diff --git a/frontend/src/pages/GenerateCalendar.tsx b/frontend/src/pages/GenerateCalendar.tsx index ff88184..34b8473 100644 --- a/frontend/src/pages/GenerateCalendar.tsx +++ b/frontend/src/pages/GenerateCalendar.tsx @@ -1,6 +1,247 @@ /** - * Pagina Genera Calendario (stub — completata nel Task 2c) + * Pagina Genera Calendario. + * + * Flusso: + * 1. Utente compila form (obiettivo + settimane) + * 2. Submit chiama POST /api/generate/bulk → ritorna {job_id} (202 Accepted) + * 3. Mostra ProgressIndicator con polling ogni 2s su job_id + * 4. Quando il job completa → navigate a /risultati/:jobId + * + * Il pulsante Genera è disabilitato se API key non configurata. */ + +import { AlertTriangle, Loader2 } from 'lucide-react' +import { useState } from 'react' +import { Link, useNavigate } from 'react-router-dom' +import { useGenerateCalendar, useSettings, useSettingsStatus } from '../api/hooks' +import { ProgressIndicator } from '../components/ProgressIndicator' +import type { CalendarRequest } from '../types' + export function GenerateCalendar() { - return
Genera Calendario — in costruzione
+ const navigate = useNavigate() + const { data: status } = useSettingsStatus() + const { data: settings } = useSettings() + const generateMutation = useGenerateCalendar() + + const apiKeyOk = status?.api_key_configured ?? false + + // Stato del form + const [obiettivo, setObiettivo] = useState('') + const [settimane, setSettimane] = useState(2) + const [brandName, setBrandName] = useState('') + const [tono, setTono] = useState('') + const [customNicchie, setCustomNicchie] = useState(false) + + // Job ID quando la generazione parte + const [jobId, setJobId] = useState(null) + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault() + if (!apiKeyOk || !obiettivo.trim()) return + + const req: CalendarRequest = { + obiettivo_campagna: obiettivo.trim(), + settimane, + frequenza_post: settings?.frequenza_post ?? 3, + nicchie: customNicchie ? settings?.nicchie_attive : undefined, + } + + try { + const res = await generateMutation.mutateAsync(req) + setJobId(res.job_id) + } catch { + // Errore gestito da generateMutation.error + } + } + + function handleComplete(completedJobId: string) { + navigate(`/risultati/${completedJobId}`) + } + + // --------------------------------------------------------------------------- + // Se il job è stato avviato: mostra progress indicator + // --------------------------------------------------------------------------- + + if (jobId) { + return ( +
+
+

Generazione in corso

+

+ Claude sta generando i 13 caroselli Instagram. Ci vorranno alcuni minuti. +

+
+ +
+ +
+ +

+ Non chiudere questa pagina. Job ID: {jobId} +

+
+ ) + } + + // --------------------------------------------------------------------------- + // Form generazione + // --------------------------------------------------------------------------- + + return ( +
+
+

Genera Calendario

+

+ Genera 13 caroselli Instagram strategici basati sul framework Persuasion Nurturing e Schwartz. +

+
+ + {/* Banner API key mancante */} + {!apiKeyOk && ( +
+ +
+

API key Claude non configurata

+

+ + Configura la tua API key nelle Impostazioni + {' '} + per abilitare la generazione. +

+
+
+ )} + +
+ + {/* Obiettivo campagna */} +
+ +