// @deno-types="https://cdn.sheetjs.com/xlsx-0.20.3/package/types/index.d.ts" import * as XLSX from "https://cdn.sheetjs.com/xlsx-0.20.3/package/xlsx.mjs"; import { useRef } from "preact/hooks"; import { useSignal } from "@preact/signals"; import ImportResultPopup, { type ImportDetail, type ImportResult, } from "$root/defaults/ImportResultPopup.tsx"; export default function UploadStudents() { const file = useSignal(null); const dragging = useSignal(false); const uploading = useSignal(false); const error = useSignal(null); const importResult = useSignal(null); const inputRef = useRef(null); function pickFile(f: File) { if (!f.name.match(/\.xlsx?$/i)) { error.value = "Fichier invalide — format attendu : .xlsx"; return; } file.value = f; error.value = null; importResult.value = null; } function onDragOver(e: DragEvent) { e.preventDefault(); dragging.value = true; } function onDragLeave() { dragging.value = false; } function onDrop(e: DragEvent) { e.preventDefault(); dragging.value = false; const f = e.dataTransfer?.files?.[0]; if (f) pickFile(f); } function onInputChange(e: Event) { const f = (e.target as HTMLInputElement).files?.[0]; if (f) pickFile(f); } async function doImport() { if (!file.value) return; uploading.value = true; error.value = null; importResult.value = null; try { const arrayBuffer = await file.value.arrayBuffer(); const workbook = XLSX.read(arrayBuffer, { type: "array" }); let added = 0; let errors = 0; const details: ImportDetail[] = []; for (const sheetName of workbook.SheetNames) { const sheet = workbook.Sheets[sheetName]; const rows = XLSX.utils.sheet_to_json<{ nom: string; prenom: string; numEtud: number; idPromo: string; }>(sheet, { header: ["nom", "prenom", "numEtud", "idPromo"], range: 2, }); for (const row of rows) { const res = await fetch("/students/api/students", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(row), }); if (res.ok) { added++; details.push({ type: "change", message: `${row.numEtud} : ${row.nom} ${row.prenom} -> ${row.idPromo}`, }); } else { errors++; const body = await res.json().catch(() => ({})); details.push({ type: "error", message: `${row.numEtud} : ${body.error ?? "Erreur creation"}`, }); } } } importResult.value = { added, modified: 0, ignored: 0, errors, details, }; } catch { error.value = "Erreur lors de la lecture du fichier."; } finally { uploading.value = false; } } function downloadTemplate() { globalThis.open("/templates/modele_etudiants.xlsx", "_blank"); } return (
inputRef.current?.click()} > {file.value ? {file.value.name} : ( <> Glisser le fichier .xlsx ici ou cliquer pour parcourir )}
{error.value &&

{error.value}

} {importResult.value && ( (importResult.value = null)} /> )}

Format : Nom | Prenom |{" "} Numero-etudiant | Promotion

); }