112 lines
3.8 KiB
TypeScript
112 lines
3.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
|
|
export default function AdminCertificates({ certificates }: any) {
|
|
const router = useRouter();
|
|
const [filter, setFilter] = useState("PENDING");
|
|
const [viewing, setViewing] = useState<any>(null);
|
|
|
|
const filtered = certificates.filter((c: any) =>
|
|
filter === "ALL" ? true : c.status === filter
|
|
);
|
|
|
|
async function updateStatus(id: string, status: string) {
|
|
const res = await fetch("/api/certificates", {
|
|
method: "PATCH",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ id, status }),
|
|
});
|
|
if (res.ok) {
|
|
setViewing(null);
|
|
router.refresh();
|
|
}
|
|
}
|
|
|
|
const pendingCount = certificates.filter((c: any) => c.status === "PENDING").length;
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<h2 className="text-lg font-bold">
|
|
📄 Certificats médical
|
|
{pendingCount > 0 && (
|
|
<span className="ml-2 rounded-full bg-amber-500 px-2 py-0.5 text-xs text-black">
|
|
{pendingCount} en attente
|
|
</span>
|
|
)}
|
|
</h2>
|
|
|
|
<div className="flex gap-2">
|
|
{(["PENDING", "VALIDATED", "REJECTED", "ALL"] as const).map((f) => (
|
|
<button
|
|
key={f}
|
|
onClick={() => setFilter(f)}
|
|
className={`rounded-xl px-3 py-2 text-sm ${
|
|
filter === f ? "bg-primary-600 text-white" : "bg-white/5 text-white/60"
|
|
}`}
|
|
>
|
|
{f === "PENDING" ? "⏳ En attente" : f === "VALIDATED" ? "✓ Validés" : f === "REJECTED" ? "✗ Rejetés" : "Tous"}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
{filtered.length === 0 && (
|
|
<p className="card text-center text-sm text-white/50">Aucun certificat ici.</p>
|
|
)}
|
|
{filtered.map((c: any) => (
|
|
<div key={c.id} className="card">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="font-semibold">{c.user.name}</p>
|
|
<p className="text-xs text-white/50">{c.user.email}</p>
|
|
<p className="mt-1 text-xs text-white/40">
|
|
Reçu le {new Date(c.createdAt).toLocaleDateString("fr-FR")}
|
|
</p>
|
|
</div>
|
|
<StatusBadge status={c.status} />
|
|
</div>
|
|
<div className="mt-3 flex gap-2">
|
|
<a
|
|
href={c.fileUrl}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="btn-secondary flex-1 !py-2 text-sm"
|
|
>
|
|
👁️ Voir le fichier
|
|
</a>
|
|
{c.status === "PENDING" && (
|
|
<>
|
|
<button
|
|
onClick={() => updateStatus(c.id, "VALIDATED")}
|
|
className="rounded-xl bg-emerald-600 px-4 py-2 text-sm font-semibold text-white hover:bg-emerald-700"
|
|
>
|
|
✓ Valider
|
|
</button>
|
|
<button
|
|
onClick={() => updateStatus(c.id, "REJECTED")}
|
|
className="btn-danger"
|
|
>
|
|
✗
|
|
</button>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function StatusBadge({ status }: { status: string }) {
|
|
switch (status) {
|
|
case "VALIDATED":
|
|
return <span className="rounded-full bg-emerald-500/20 px-3 py-1 text-xs font-semibold text-emerald-300">✓ Validé</span>;
|
|
case "REJECTED":
|
|
return <span className="rounded-full bg-red-500/20 px-3 py-1 text-xs font-semibold text-red-300">✗ Rejeté</span>;
|
|
default:
|
|
return <span className="rounded-full bg-amber-500/20 px-3 py-1 text-xs font-semibold text-amber-300">⏳ En attente</span>;
|
|
}
|
|
} |