import { useEffect, useState } from "preact/hooks"; type UE = { id: number; nom: string }; type UEModule = { idModule: string; idUE: number; idPromo: string; coeff: number; }; type Module = { id: string; nom: string }; type Promo = { id: string; annee: string }; export default function AdminUEs() { const [ues, setUes] = useState([]); const [ueModules, setUeModules] = useState([]); const [modules, setModules] = useState([]); const [promos, setPromos] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedUe, setSelectedUe] = useState(null); // New UE form const [newUeNom, setNewUeNom] = useState(""); const [creatingUe, setCreatingUe] = useState(false); // Add UE-module form const [addModuleId, setAddModuleId] = useState(""); const [addPromoId, setAddPromoId] = useState(""); const [addCoeff, setAddCoeff] = useState("1"); const [adding, setAdding] = useState(false); const [addError, setAddError] = useState(null); async function load() { try { const [uRes, umRes, mRes, pRes] = await Promise.all([ fetch("/notes/api/ues"), fetch("/notes/api/ue-modules"), fetch("/admin/api/modules"), fetch("/students/api/promotions"), ]); if (!uRes.ok) throw new Error("Impossible de charger les UEs"); const uesData: UE[] = await uRes.json(); setUes(uesData); if (umRes.ok) setUeModules(await umRes.json()); if (mRes.ok) setModules(await mRes.json()); if (pRes.ok) setPromos(await pRes.json()); // Keep selection in sync setSelectedUe((prev) => prev ? uesData.find((u) => u.id === prev.id) ?? null : null ); } catch (e) { setError(e instanceof Error ? e.message : "Erreur"); } finally { setLoading(false); } } useEffect(() => { load(); }, []); async function createUE() { if (!newUeNom.trim()) return; setCreatingUe(true); try { const res = await fetch("/notes/api/ues", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ nom: newUeNom.trim() }), }); if (!res.ok) throw new Error("Création échouée"); setNewUeNom(""); await load(); } catch (e) { setError(e instanceof Error ? e.message : "Erreur"); } finally { setCreatingUe(false); } } async function deleteUeModule( idModule: string, idUE: number, idPromo: string, ) { if (!confirm("Supprimer ce module de la UE ?")) return; try { const res = await fetch( `/notes/api/ue-modules/${encodeURIComponent(idModule)}/${idUE}/${ encodeURIComponent(idPromo) }`, { method: "DELETE" }, ); if (!res.ok) throw new Error("Suppression échouée"); await load(); } catch (e) { setError(e instanceof Error ? e.message : "Erreur"); } } async function addUeModule() { if (!selectedUe || !addModuleId || !addPromoId) { setAddError("Module et Promo sont requis"); return; } const coeff = parseFloat(addCoeff); if (isNaN(coeff) || coeff <= 0) { setAddError("Coefficient invalide"); return; } setAdding(true); setAddError(null); try { const res = await fetch("/notes/api/ue-modules", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ idModule: addModuleId, idUE: selectedUe.id, idPromo: addPromoId, coeff, }), }); if (!res.ok) { const body = await res.json().catch(() => ({})); throw new Error(body.error ?? "Création échouée"); } setAddModuleId(""); setAddPromoId(""); setAddCoeff("1"); await load(); } catch (e) { setAddError(e instanceof Error ? e.message : "Erreur"); } finally { setAdding(false); } } const moduleMap = Object.fromEntries(modules.map((m) => [m.id, m])); const selectedUeModules = selectedUe ? ueModules.filter((um) => um.idUE === selectedUe.id) : []; return (

Gestion des UEs

UE = Unité d'Enseignement regroupant plusieurs modules

{error &&

{error}

} {loading ?

Chargement…

: (
{/* Left panel – UE list */}

UEs existantes

setNewUeNom((e.target as HTMLInputElement).value)} onKeyDown={(e) => e.key === "Enter" && createUE()} style="min-width: 0; flex: 1" />
{ues.map((ue) => (
{ setSelectedUe(ue); setAddError(null); }} > {ue.nom}
))} {ues.length === 0 && (

Aucune UE

)}
{/* Right panel – UE detail */}
{selectedUe ? (

{selectedUe.nom}

Modules assignés (UE_Module)

{selectedUeModules.length === 0 ? ( ) : selectedUeModules.map((um) => { const mod = moduleMap[um.idModule]; return ( ); })}
Module Promo Coeff Actions
Aucun module assigné
{mod ? `${mod.id} – ${mod.nom}` : um.idModule} {um.idPromo} {um.coeff}

Ajouter un module à cette UE

{addError && (

{addError}

)}
setAddCoeff((e.target as HTMLInputElement).value)} style="min-width: 5rem; max-width: 6rem" />
) : (

Sélectionnez une UE pour voir ses modules

)}
)}
); }