import { redirect } from "next/navigation";
import type { CSSProperties } from "react";
import { and, desc, eq } from "drizzle-orm";
import { auth } from "@/auth";
import { db } from "@/db";
import { meetingRegistrations, meetings } from "@/db/schema";
import { can } from "@/lib/rbac";
import {
confirmMeetingRegistration,
deleteMeetingRegistration,
updateMeetingRegistration,
} from "../actions";
export const dynamic = "force-dynamic";
function formatDate(date: Date) {
return new Intl.DateTimeFormat("fr-FR", { day: "numeric", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit" }).format(date);
}
export default async function InscriptionsPage({ searchParams }: { searchParams: Promise<{ meeting?: string }> }) {
const session = await auth();
if (!can(session?.user.role, "manageMeetings")) redirect("/backend");
const { meeting: meetingParam } = await searchParams;
const selectedMeetingId = Number(meetingParam) || null;
const [meetingRows, registrationRows] = await Promise.all([
db.select({ id: meetings.id, title: meetings.title, startsAt: meetings.startsAt }).from(meetings).orderBy(desc(meetings.startsAt)),
db
.select({
id: meetingRegistrations.id,
meetingId: meetingRegistrations.meetingId,
meetingTitle: meetings.title,
meetingStartsAt: meetings.startsAt,
attendeeName: meetingRegistrations.attendeeName,
attendeeCompany: meetingRegistrations.attendeeCompany,
attendeeEmail: meetingRegistrations.attendeeEmail,
attendeePhone: meetingRegistrations.attendeePhone,
status: meetingRegistrations.status,
imageConsent: meetingRegistrations.imageConsent,
createdAt: meetingRegistrations.createdAt,
})
.from(meetingRegistrations)
.innerJoin(meetings, eq(meetings.id, meetingRegistrations.meetingId))
.where(selectedMeetingId ? and(eq(meetingRegistrations.meetingId, selectedMeetingId)) : undefined)
.orderBy(desc(meetings.startsAt), desc(meetingRegistrations.createdAt)),
]);
return (
Participants
{registrationRows.length} inscription{registrationRows.length > 1 ? "s" : ""} affichée{registrationRows.length > 1 ? "s" : ""}
{registrationRows.map((registration) => (
{registration.attendeeName}
{registration.meetingTitle} · {formatDate(registration.meetingStartsAt)}
{registration.status === "confirmed" ? "Confirmée" : "En attente"}
{registration.imageConsent ? "Image autorisée" : "Image refusée"}
{registration.status !== "confirmed" && (
)}
))}
{registrationRows.length === 0 &&
Aucune inscription pour cette sélection.
}
);
}
const sectionLabel: CSSProperties = { fontSize: 12.5, letterSpacing: "0.08em", textTransform: "uppercase", color: "#9a8d72", fontWeight: 800 };
const cardStyle: CSSProperties = { background: "#fff", border: "1px solid #e6dcc6", borderRadius: 8, padding: 20 };
const badgeBase: CSSProperties = { display: "inline-block", borderRadius: 999, padding: "5px 10px", fontSize: 11.5, fontWeight: 800 };
const confirmedBadge: CSSProperties = { ...badgeBase, background: "#e6f4ec", color: "#1f8a5b" };
const pendingBadge: CSSProperties = { ...badgeBase, background: "#fbeede", color: "#9a6638" };
const consentBadge: CSSProperties = { ...badgeBase, background: "#eaf0f6", color: "#2C6FB3" };
const refusalBadge: CSSProperties = { ...badgeBase, background: "#fbe9e6", color: "#d8472b" };
const primaryButton: CSSProperties = { border: "none", background: "#13324F", color: "#fff", borderRadius: 8, padding: "11px 16px", fontWeight: 800, cursor: "pointer" };
const secondaryButton: CSSProperties = { border: "1px solid #d8cdb4", background: "#fff", color: "#6f6450", borderRadius: 8, padding: "11px 16px", fontWeight: 800, cursor: "pointer" };
const confirmButton: CSSProperties = { border: "none", background: "#1f8a5b", color: "#fff", borderRadius: 8, padding: "9px 14px", fontWeight: 800, cursor: "pointer" };
const dangerButton: CSSProperties = { border: "1px solid #e0c3bb", background: "#fff", color: "#d8472b", borderRadius: 8, padding: "8px 13px", fontWeight: 800, cursor: "pointer" };
const emptyStyle: CSSProperties = { background: "#fff", border: "1px solid #e6dcc6", borderRadius: 8, padding: 28, color: "#8c8068", textAlign: "center" };