Initial commit: JuanitoSport - Muay Thai & Yog4Fight PWA
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
"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>;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user