/** * Prompt Detail Page (Story 19.10) * * Route: /prompts/:id * * Features: * - Version history timeline * - Content viewer * - Side-by-side diff between versions * - Per-version analytics charts */ import React, { useState, useMemo } from 'react'; import { Link, useParams } from 'react-router-dom'; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, } from 'recharts'; import { useApi } from '../hooks/useApi'; import { getPrompt, getPromptAnalytics, getPromptDiff, createPromptVersion, deletePrompt, } from '../api/prompts'; import type { PromptTemplate, PromptVersion, PromptVersionAnalytics, PromptDiffResponse, } from '../api/prompts'; // ─── Helpers ──────────────────────────────────────────────────── function formatDate(iso: string): string { try { return new Date(iso).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } catch { return iso; } } function formatCost(usd: number): string { if (usd < 0.01) return `$${usd.toFixed(4)}`; if (usd < 1) return `$${usd.toFixed(3)}`; return `$${usd.toFixed(2)}`; } // ─── Diff Viewer ──────────────────────────────────────────────── function DiffViewer({ diff }: { diff: string }) { const lines = diff.split('\n'); return (
      {lines.map((line, i) => {
        let cls = 'text-gray-700';
        if (line.startsWith('+') && !line.startsWith('+++')) cls = 'text-green-700 bg-green-50';
        else if (line.startsWith('-') && !line.startsWith('---')) cls = 'text-red-700 bg-red-50';
        else if (line.startsWith('@@')) cls = 'text-blue-600';
        return (
          
{line}
); })}
); } // ─── New Version Modal ────────────────────────────────────────── function NewVersionModal({ templateId, currentContent, onClose, onCreated, }: { templateId: string; currentContent: string; onClose: () => void; onCreated: () => void; }) { const [content, setContent] = useState(currentContent); const [changelog, setChangelog] = useState(''); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!content.trim()) return; setSaving(true); setError(''); try { await createPromptVersion(templateId, { content, changelog }); onCreated(); onClose(); } catch (err: any) { setError(err?.message || 'Failed to create version'); } finally { setSaving(false); } }; return (
e.stopPropagation()}>

Create New Version