"use client"; import { useState, useEffect, useCallback } from "react"; interface Module { id: string; title: string; description: string | null; week_number: number; order_index: number; content_type: "video" | "pdf" | "text" | "quiz" | null; content_url: string | null; duration_minutes: number | null; is_published: boolean; created_at: string; } type FormData = { title: string; description: string; week_number: number; order_index: number; content_type: "video" | "pdf" | "text" | "quiz" | ""; content_url: string; duration_minutes: number | ""; is_published: boolean; }; const emptyForm: FormData = { title: "", description: "", week_number: 1, order_index: 0, content_type: "video", content_url: "", duration_minutes: "", is_published: false, }; export default function AdminCoursPage() { const [modules, setModules] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); // Vue : "list" ou "form" const [view, setView] = useState<"list" | "form">("list"); const [editingId, setEditingId] = useState(null); const [form, setForm] = useState(emptyForm); const [deleteConfirm, setDeleteConfirm] = useState(null); const fetchModules = useCallback(async () => { setLoading(true); try { const res = await fetch("/api/admin/modules"); const data = await res.json(); if (!res.ok) throw new Error(data.error); setModules(data.modules); } catch (err) { setError(err instanceof Error ? err.message : "Erreur de chargement"); } finally { setLoading(false); } }, []); useEffect(() => { fetchModules(); }, [fetchModules]); // Auto-clear success message useEffect(() => { if (success) { const t = setTimeout(() => setSuccess(null), 3000); return () => clearTimeout(t); } }, [success]); const openNew = () => { // Calculer automatiquement le prochain order_index const maxOrder = modules.reduce((max, m) => Math.max(max, m.order_index), -1); setForm({ ...emptyForm, order_index: maxOrder + 1 }); setEditingId(null); setView("form"); setError(null); }; const openEdit = (mod: Module) => { setForm({ title: mod.title, description: mod.description || "", week_number: mod.week_number, order_index: mod.order_index, content_type: mod.content_type || "", content_url: mod.content_url || "", duration_minutes: mod.duration_minutes ?? "", is_published: mod.is_published, }); setEditingId(mod.id); setView("form"); setError(null); }; const handleSave = async () => { if (!form.title.trim()) { setError("Le titre est obligatoire."); return; } setSaving(true); setError(null); try { const payload = { title: form.title.trim(), description: form.description.trim() || null, week_number: form.week_number, order_index: form.order_index, content_type: form.content_type || null, content_url: form.content_url.trim() || null, duration_minutes: form.duration_minutes === "" ? null : Number(form.duration_minutes), is_published: form.is_published, }; let res: Response; if (editingId) { res = await fetch(`/api/admin/modules/${editingId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); } else { res = await fetch("/api/admin/modules", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); } const data = await res.json(); if (!res.ok) throw new Error(data.error); setSuccess(editingId ? "Cours mis à jour !" : "Cours créé !"); setView("list"); await fetchModules(); } catch (err) { setError(err instanceof Error ? err.message : "Erreur"); } finally { setSaving(false); } }; const handleDelete = async (id: string) => { try { const res = await fetch(`/api/admin/modules/${id}`, { method: "DELETE" }); const data = await res.json(); if (!res.ok) throw new Error(data.error); setSuccess("Cours supprimé !"); setDeleteConfirm(null); await fetchModules(); } catch (err) { setError(err instanceof Error ? err.message : "Erreur"); } }; const handleTogglePublish = async (mod: Module) => { try { const res = await fetch(`/api/admin/modules/${mod.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ is_published: !mod.is_published }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error); await fetchModules(); } catch (err) { setError(err instanceof Error ? err.message : "Erreur"); } }; const contentTypeLabels: Record = { video: "Vidéo", pdf: "PDF", text: "Texte", quiz: "Quiz", }; // Grouper par semaine pour l'affichage liste const modulesByWeek = modules.reduce( (acc, mod) => { const w = mod.week_number; if (!acc[w]) acc[w] = []; acc[w].push(mod); return acc; }, {} as Record ); if (loading) { return (
); } // ========== FORMULAIRE ========== if (view === "form") { return (

{editingId ? "Modifier le cours" : "Nouveau cours"}

{error && (

{error}

)}
{/* Titre */}
setForm({ ...form, title: e.target.value })} placeholder="Ex : Introduction au TikTok Shop" className="w-full px-4 py-3 bg-dark-lighter border border-dark-border rounded-xl text-white placeholder-white/30 text-sm focus:outline-none focus:border-primary" />
{/* Description */}