import { useEffect, useState } from "preact/hooks"; type Student = { numEtud: number; nom: string; prenom: string; idPromo: string; }; type Promo = { id: string; annee: string }; type Module = { id: string; nom: string }; type Mobilite = { id: number; duree: number; status: string }; type Stage = { id: number; duree: number }; type Props = { numEtud: number }; function anneeLabel(idPromo: string): string { const m = idPromo.match(/^(\d+)A/); if (!m) return ""; const n = m[1]; if (n === "3") return "3ème année"; if (n === "4") return "4ème année"; if (n === "5") return "5ème année"; return `${n}ème année`; } export default function EditStudents({ numEtud }: Props) { const [student, setStudent] = useState(null); const [promos, setPromos] = useState([]); const [_modules, setModules] = useState([]); const [mobWeeks, setMobWeeks] = useState(0); const [stageWeeks, setStageWeeks] = useState(0); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [saveMsg, setSaveMsg] = useState(null); const [saving, setSaving] = useState(false); // Edit form state const [nom, setNom] = useState(""); const [prenom, setPrenom] = useState(""); const [idPromo, setIdPromo] = useState(""); useEffect(() => { async function load() { try { const [sRes, pRes, mRes, mobRes, stRes] = await Promise.all([ fetch(`/students/api/students/${numEtud}`), fetch("/students/api/promotions"), fetch("/notes/api/modules"), fetch(`/mobility/api/mobilites?numEtud=${numEtud}`), fetch(`/stages/api/stages?numEtud=${numEtud}`), ]); if (!sRes.ok) throw new Error("Élève introuvable"); const s: Student = await sRes.json(); setStudent(s); setNom(s.nom); setPrenom(s.prenom); setIdPromo(s.idPromo); if (pRes.ok) setPromos(await pRes.json()); if (mRes.ok) setModules(await mRes.json()); if (mobRes.ok) { const mobs: Mobilite[] = await mobRes.json(); setMobWeeks( mobs.filter((m) => m.status === "validated").reduce( (s, m) => s + m.duree, 0, ), ); } if (stRes.ok) { const stages: Stage[] = await stRes.json(); setStageWeeks(stages.reduce((s, st) => s + st.duree, 0)); } } catch (e) { setError(e instanceof Error ? e.message : "Erreur"); } finally { setLoading(false); } } load(); }, [numEtud]); async function saveInfos() { if (!student) return; setSaving(true); setSaveMsg(null); try { const res = await fetch(`/students/api/students/${numEtud}`, { method: "PUT", headers: { "content-type": "application/json" }, body: JSON.stringify({ nom: nom.trim(), prenom: prenom.trim(), idPromo, }), }); if (!res.ok) throw new Error("Modification échouée"); const updated: Student = await res.json(); setStudent(updated); setSaveMsg("Informations enregistrées."); } catch (e) { setError(e instanceof Error ? e.message : "Erreur"); } finally { setSaving(false); } } async function deleteStudent() { if (!confirm(`Supprimer définitivement l'élève #${numEtud} ?`)) return; try { const res = await fetch(`/students/api/students/${numEtud}`, { method: "DELETE", }); if (!res.ok) throw new Error("Suppression échouée"); globalThis.location.href = "/students/consult"; } catch (e) { setError(e instanceof Error ? e.message : "Erreur"); } } if (loading) { return (

Chargement…

); } if (error && !student) { return (

{error}

); } if (!student) return null; return (
← Retour à la liste

Édition – {student.prenom} {student.nom}

{/* Info bar */}
{student.numEtud} {student.idPromo} {anneeLabel(student.idPromo)}
{error &&

{error}

} {saveMsg && (

{saveMsg}

)} {/* Section 1: Informations générales */}

Informations générales

setNom((e.target as HTMLInputElement).value)} />
setPrenom((e.target as HTMLInputElement).value)} />
{/* Section 2: Notes */}

Notes

Récap complet des notes et moyennes Voir les notes
{/* Section 3: Mobilités */}

Mobilités

= 12 ? "#22c55e" : "#dc2626", }} > {mobWeeks}/12 semaines validées Consulter
{/* Section 4: Stages */}

Stages

= 40 ? "#22c55e" : "#dc2626", }} > {stageWeeks}/40 semaines Consulter
); }