import { useEffect, useState } from 'react'; const API_BASE = import.meta.env.VITE_API_BASE_URL || ''; interface CachedPrompt { prompt_id: string; created_at: string; updated_at: string; metadata: { script: string; style: string; model: string; segments_count: number; }; segments_count: number; } export function SavedPromptsLibrary({ onClose, onReuse }: { onClose: () => void; onReuse: (payload: any) => void; }) { const [prompts, setPrompts] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [editingPromptId, setEditingPromptId] = useState(null); const [editingPayloadJson, setEditingPayloadJson] = useState(''); const [editError, setEditError] = useState(null); const [saving, setSaving] = useState(false); const [validating, setValidating] = useState(false); const [validationResult, setValidationResult] = useState<{ valid: boolean; schema_errors?: string[]; ai_checked?: boolean; ai_valid?: boolean; ai_warnings?: string[]; ai_suggestions?: string[]; } | null>(null); useEffect(() => { loadSavedPrompts(); }, []); const loadSavedPrompts = async () => { try { setLoading(true); setError(null); const response = await fetch(`${API_BASE}/api/cached-prompts?limit=50`); if (!response.ok) throw new Error('Failed to load prompts'); const data = await response.json(); const list: CachedPrompt[] = data.prompts || []; // Deduplicate: same script + same segment count = same prompt; keep most recent const seen = new Map(); const key = (p: CachedPrompt) => { const script = (p.metadata?.script || '').trim().slice(0, 300); return `${script}|${p.segments_count ?? p.metadata?.segments_count ?? 0}`; }; for (const p of list) { const k = key(p); const existing = seen.get(k); if (!existing || new Date(p.updated_at) > new Date(existing.updated_at)) { seen.set(k, p); } } setPrompts(Array.from(seen.values())); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load prompts'); } finally { setLoading(false); } }; const handleReuse = async (promptId: string) => { try { const response = await fetch(`${API_BASE}/api/use-cached-prompt/${promptId}`, { method: 'POST' }); if (!response.ok) throw new Error('Failed to load prompt'); const { payload } = await response.json(); onReuse(payload); onClose(); } catch (err) { alert(err instanceof Error ? err.message : 'Failed to reuse prompt'); } }; const handleDelete = async (promptId: string) => { if (!confirm('Delete this saved prompt?')) return; try { await fetch(`${API_BASE}/api/cached-prompts/${promptId}`, { method: 'DELETE' }); loadSavedPrompts(); // Refresh list } catch (err) { alert('Failed to delete prompt'); } }; const handleEdit = async (promptId: string) => { setEditError(null); try { const response = await fetch(`${API_BASE}/api/cached-prompts/${promptId}`); if (!response.ok) throw new Error('Failed to load prompt'); const entry = await response.json(); const payload = entry.payload ?? { segments: entry.segments ?? [] }; setEditingPayloadJson(JSON.stringify(payload, null, 2)); setEditingPromptId(promptId); } catch (err) { setEditError(err instanceof Error ? err.message : 'Failed to load prompt'); } }; const validatePayload = (): { valid: boolean; payload?: any; error?: string } => { try { const parsed = JSON.parse(editingPayloadJson); if (!parsed || typeof parsed !== 'object') return { valid: false, error: 'Payload must be an object' }; if (!Array.isArray(parsed.segments)) return { valid: false, error: 'Payload must have a "segments" array' }; return { valid: true, payload: parsed }; } catch { return { valid: false, error: 'Invalid JSON' }; } }; const handleValidateWithAi = async () => { const { valid, payload, error } = validatePayload(); if (!valid || !payload) { setEditError(error ?? 'Invalid payload'); setValidationResult(null); return; } setEditError(null); setValidationResult(null); setValidating(true); try { const response = await fetch(`${API_BASE}/api/validate-payload`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ payload, use_ai: true }), }); const data = await response.json().catch(() => ({})); if (!response.ok) throw new Error(data.detail || response.statusText || 'Validation failed'); setValidationResult({ valid: data.valid, schema_errors: data.schema_errors, ai_checked: data.ai_checked, ai_valid: data.ai_valid, ai_warnings: data.ai_warnings, ai_suggestions: data.ai_suggestions, }); } catch (err) { setEditError(err instanceof Error ? err.message : 'Validation request failed'); } finally { setValidating(false); } }; const handleSaveEdit = async () => { const { valid, payload, error } = validatePayload(); if (!valid || !payload || !editingPromptId) { setEditError(error ?? 'Invalid payload'); return; } setEditError(null); setSaving(true); try { const response = await fetch(`${API_BASE}/api/cached-prompts/${editingPromptId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!response.ok) { const errData = await response.json().catch(() => ({})); throw new Error(errData.detail || response.statusText || 'Failed to update'); } setEditingPromptId(null); setEditingPayloadJson(''); loadSavedPrompts(); } catch (err) { setEditError(err instanceof Error ? err.message : 'Failed to save'); } finally { setSaving(false); } }; const closeEditModal = () => { setEditingPromptId(null); setEditingPayloadJson(''); setEditError(null); setValidationResult(null); }; return (
{/* Header */}

💾 My Saved Prompts

{/* Content */}
{loading ? (
) : error ? (

{error}

) : prompts.length === 0 ? (
📭

No saved prompts yet

Generate some prompts to see them here

) : (
{prompts.map((prompt) => (
{/* Header */}
{new Date(prompt.created_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })} {prompt.segments_count} segments
{/* Content Preview */}

{(prompt.metadata?.script || '').slice(0, 120)} {(prompt.metadata?.script || '').length > 120 ? '…' : ''}

{prompt.metadata?.style || '—'}
{/* Actions */}
))}
)}
{/* Footer */}
{/* Edit modal - dark chrome to match app; light body so JSON is readable */} {editingPromptId && (

✏️ Edit saved prompt

{editError && (

{editError}

)} {validationResult && (
{!validationResult.valid && validationResult.schema_errors && validationResult.schema_errors.length > 0 && (

Schema issues:

    {validationResult.schema_errors.map((e, i) => (
  • {e}
  • ))}
)} {validationResult.ai_checked && ( <> {validationResult.ai_warnings && validationResult.ai_warnings.length > 0 && (

AI review warnings:

    {validationResult.ai_warnings.map((w, i) => (
  • {w}
  • ))}
)} {validationResult.ai_suggestions && validationResult.ai_suggestions.length > 0 && (

Suggestions:

    {validationResult.ai_suggestions.map((s, i) => (
  • {s}
  • ))}
)} {validationResult.valid && (!validationResult.ai_warnings?.length) && (!validationResult.ai_suggestions?.length) && validationResult.ai_valid !== false && (

✓ Schema and AI review passed.

)} )}
)}

Edit the JSON below. Keep the segments array structure. Use "Validate with AI" to check schema and content.