"use client"; // Annonces : création avec aperçu Markdown, liste avec épingle, activation et suppression. import { useState } from "react"; import { Megaphone, Pin, PinOff, Power, Trash2 } from "lucide-react"; import { PageHeader } from "@/components/app-shell"; import { Markdown } from "@/components/chat/markdown"; import { Badge, Button, Card, EmptyState, Input, Label, Modal, Skeleton, Spinner, Tabs, Textarea } from "@/components/ui"; import { ErrorBanner, SuccessFlash, Toggle, fmtDate, postJson, useFetchJson } from "./shared"; type Announcement = { id: number; title: string; body: string; course_code: string | null; pinned: number; active: number; created_by: number | null; created_at: string; }; const COURSE_OPTIONS = [ { value: "", label: "Tous les cours" }, { value: "IMM1003", label: "IMM1003" }, { value: "IMM1033", label: "IMM1033" }, ]; export function AdminAnnouncements() { const { data, error, loading, reload } = useFetchJson<{ announcements: Announcement[] }>("/api/admin/announcements"); // Formulaire de création const [title, setTitle] = useState(""); const [body, setBody] = useState(""); const [courseCode, setCourseCode] = useState(""); const [pinned, setPinned] = useState(false); const [editTab, setEditTab] = useState("write"); const [creating, setCreating] = useState(false); const [formError, setFormError] = useState(null); const [flash, setFlash] = useState(null); // Actions sur la liste const [actionError, setActionError] = useState(null); const [busyId, setBusyId] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); const [deleting, setDeleting] = useState(false); async function create() { if (!title.trim() || !body.trim()) { setFormError("Le titre et le corps de l'annonce sont requis."); return; } setCreating(true); setFormError(null); try { await postJson("/api/admin/announcements", { action: "create", title: title.trim(), body: body.trim(), courseCode: courseCode === "" ? null : courseCode, pinned, }); setTitle(""); setBody(""); setCourseCode(""); setPinned(false); setEditTab("write"); setFlash("Annonce publiée."); setTimeout(() => setFlash(null), 3500); await reload(); } catch (e) { setFormError(e instanceof Error ? e.message : "La publication a échoué."); } finally { setCreating(false); } } async function update(id: number, patch: { active?: boolean; pinned?: boolean }) { setBusyId(id); setActionError(null); try { await postJson("/api/admin/announcements", { action: "update", id, ...patch }); await reload(); } catch (e) { setActionError(e instanceof Error ? e.message : "L'action a échoué."); } finally { setBusyId(null); } } async function remove() { if (!deleteTarget) return; setDeleting(true); setActionError(null); try { await postJson("/api/admin/announcements", { action: "delete", id: deleteTarget.id }); setDeleteTarget(null); await reload(); } catch (e) { setActionError(e instanceof Error ? e.message : "La suppression a échoué."); } finally { setDeleting(false); } } return (
{flash &&
} {/* Création */}

Nouvelle annonce

setTitle(e.target.value)} maxLength={200} placeholder="Ex. : Report de la remise du travail 2" />
{editTab === "write" ? (