import React, { useCallback, useEffect, useState } from 'react'; import { useAppStateContext } from '../../context/user.data.context'; import { listPromptTemplates, createPromptTemplate, updatePromptTemplate, deletePromptTemplate, improvePrompt, } from '../../service/content-generator/content-generator.service'; import type { PromptTemplate } from '../../service/content-generator/content-generator.interface'; import { EMPTY_PROMPT_TEMPLATE_DRAFT, toPromptTemplateDraft, toTemplatePayload, type PromptTemplateDraft, } from './PromptTemplateDraft'; const TONES = [ { value: 'professional', label: 'Professional' }, { value: 'friendly', label: 'Friendly' }, { value: 'luxury', label: 'Luxury' }, { value: 'technical', label: 'Technical' }, { value: 'custom', label: 'Custom…' }, ]; const LANGUAGES = [ { value: 'en', label: 'English' }, { value: 'ro', label: 'Romanian' }, { value: 'de', label: 'German' }, { value: 'fr', label: 'French' }, { value: 'es', label: 'Spanish' }, { value: 'it', label: 'Italian' }, { value: 'nl', label: 'Dutch' }, { value: 'pt', label: 'Portuguese' }, { value: 'pl', label: 'Polish' }, { value: 'el', label: 'Greek' }, { value: 'tr', label: 'Turkish' }, { value: 'hu', label: 'Hungarian' }, { value: 'cs', label: 'Czech' }, { value: 'sv', label: 'Swedish' }, { value: 'da', label: 'Danish' }, { value: 'fi', label: 'Finnish' }, { value: 'no', label: 'Norwegian' }, { value: 'bg', label: 'Bulgarian' }, { value: 'hr', label: 'Croatian' }, { value: 'ar', label: 'Arabic' }, ]; const PROMPT_FIELDS: { key: keyof Pick< PromptTemplateDraft, 'titles_prompt' | 'descriptions_prompt' | 'tags_prompt' | 'faq_prompt' >; label: string; placeholder: string; fieldName: string; maxLength: number; }[] = [ { key: 'titles_prompt', label: 'Titles', placeholder: 'e.g., Always start with the brand name, max 70 characters…', fieldName: 'titles', maxLength: 1500, }, { key: 'descriptions_prompt', label: 'Descriptions', placeholder: 'e.g., Include a benefits section, use bullet points, max 200 words…', fieldName: 'descriptions', maxLength: 4500, }, { key: 'tags_prompt', label: 'Tags', placeholder: 'e.g., Include seasonal tags, max 8 tags, comma-separated…', fieldName: 'tags', maxLength: 1500, }, { key: 'faq_prompt', label: 'FAQ', placeholder: 'e.g., Focus on shipping and returns questions, 3-5 Q&A pairs…', fieldName: 'faq', maxLength: 1500, }, ]; interface ConfirmModalProps { open: boolean; message: string; onConfirm: () => void; onCancel: () => void; busy?: boolean; } const ConfirmModal = ({ open, message, onConfirm, onCancel, busy, }: ConfirmModalProps): JSX.Element | null => { if (!open) return null; return (

{message}

); }; const PAGE_SIZE = 10; const PromptTemplates = (): JSX.Element => { const { clientId } = useAppStateContext(); const [view, setView] = useState<'list' | 'form'>('list'); const [templates, setTemplates] = useState([]); const [loading, setLoading] = useState(false); const [listError, setListError] = useState(null); const [nextCursor, setNextCursor] = useState(null); const [prevCursors, setPrevCursors] = useState([]); const [draft, setDraft] = useState( EMPTY_PROMPT_TEMPLATE_DRAFT ); const [saving, setSaving] = useState(false); const [formError, setFormError] = useState(null); const [deleteId, setDeleteId] = useState(null); const [deleteTemplateName, setDeleteTemplateName] = useState(''); const [deleteBusy, setDeleteBusy] = useState(false); const [improvingField, setImprovingField] = useState(null); const fetchPage = useCallback( async (cursor?: string | null) => { if (!clientId) return; setLoading(true); setListError(null); try { const res = await listPromptTemplates(clientId, cursor); if (res?.data) { setTemplates(res.data.templates); setNextCursor(res.data.next_cursor); } else { setListError(res?.error || 'Failed to load templates.'); } } catch { setListError('Failed to load templates.'); } finally { setLoading(false); } }, [clientId] ); useEffect(() => { fetchPage(null); }, [fetchPage]); const handleNext = () => { if (!nextCursor) return; setPrevCursors(prev => [...prev, /* current offset */ '']); fetchPage(nextCursor); }; const handlePrev = () => { const cursors = [...prevCursors]; cursors.pop(); setPrevCursors(cursors); fetchPage(cursors[cursors.length - 1] ?? null); }; const openCreate = () => { setDraft(EMPTY_PROMPT_TEMPLATE_DRAFT); setFormError(null); setView('form'); }; const openEdit = (template: PromptTemplate) => { setDraft(toPromptTemplateDraft(template)); setFormError(null); setView('form'); }; const handleSave = async () => { if (!clientId) return; if (!draft.name.trim()) { setFormError('Template name is required.'); return; } setSaving(true); setFormError(null); try { const payload = toTemplatePayload(draft); const res = draft.template_id ? await updatePromptTemplate(draft.template_id, payload, clientId) : await createPromptTemplate(payload, clientId); if (res?.error || res?.errors) { setFormError( (res.error || String(res.errors) || 'Failed to save template.') as string ); return; } setView('list'); fetchPage(null); setPrevCursors([]); } catch { setFormError('Failed to save template.'); } finally { setSaving(false); } }; const handleDelete = async () => { if (!clientId || !deleteId) return; setDeleteBusy(true); try { await deletePromptTemplate(deleteId, clientId); setDeleteId(null); fetchPage(null); setPrevCursors([]); } catch { /* ignore */ } finally { setDeleteBusy(false); } }; const handleImproveField = async ( fieldKey: keyof Pick< PromptTemplateDraft, 'titles_prompt' | 'descriptions_prompt' | 'tags_prompt' | 'faq_prompt' >, fieldName: string ) => { if (!clientId) return; const current = draft[fieldKey]; if (!current.trim()) return; setImprovingField(fieldKey); try { const res = await improvePrompt( current, fieldName, draft.language, clientId ); const improved = res?.data?.improved_prompt; if (improved) { setDraft(prev => ({ ...prev, [fieldKey]: improved })); } } catch { /* ignore */ } finally { setImprovingField(null); } }; if (view === 'form') { return (

{draft.template_id ? 'Edit Template' : 'New Template'}

setDraft(prev => ({ ...prev, name: e.target.value })) } placeholder="e.g., Electronics – English" className="block w-full rounded-md border-gray-300 px-3 py-2 text-sm focus:border-gray-900 focus:outline-none focus:ring-1 focus:ring-gray-900" />
setDraft(prev => ({ ...prev, description: e.target.value })) } placeholder="Short description for your reference" className="block w-full rounded-md border-gray-300 px-3 py-2 text-sm focus:border-gray-900 focus:outline-none focus:ring-1 focus:ring-gray-900" />
{draft.tone === 'custom' && (