diff --git a/app/api/admin/events/[id]/route.ts b/app/api/admin/events/[id]/route.ts index edd6864..586736e 100644 --- a/app/api/admin/events/[id]/route.ts +++ b/app/api/admin/events/[id]/route.ts @@ -1,7 +1,7 @@ import { NextResponse } from "next/server"; import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; -import { Role, EventType, EventStatus } from "@/prisma/generated/prisma/client"; +import { Role, EventType } from "@/prisma/generated/prisma/client"; export async function PUT( request: Request, @@ -16,7 +16,8 @@ export async function PUT( const { id } = await params; const body = await request.json(); - const { date, name, description, type, status, room, time, maxPlaces } = body; + const { date, name, description, type, room, time, maxPlaces } = body; + // Le statut est ignoré s'il est fourni, il sera calculé automatiquement // Vérifier que l'événement existe const existingEvent = await prisma.event.findUnique({ @@ -35,7 +36,6 @@ export async function PUT( name?: string; description?: string; type?: EventType; - status?: EventStatus; room?: string | null; time?: string | null; maxPlaces?: number | null; @@ -62,18 +62,11 @@ export async function PUT( } updateData.type = type as EventType; } - if (status !== undefined) { - if (!Object.values(EventStatus).includes(status)) { - return NextResponse.json( - { error: "Statut d'événement invalide" }, - { status: 400 } - ); - } - updateData.status = status as EventStatus; - } + // Le statut est toujours calculé automatiquement, on ignore s'il est fourni if (room !== undefined) updateData.room = room || null; if (time !== undefined) updateData.time = time || null; - if (maxPlaces !== undefined) updateData.maxPlaces = maxPlaces ? parseInt(maxPlaces) : null; + if (maxPlaces !== undefined) + updateData.maxPlaces = maxPlaces ? parseInt(maxPlaces) : null; const event = await prisma.event.update({ where: { id }, @@ -128,4 +121,3 @@ export async function DELETE( ); } } - diff --git a/app/api/admin/events/route.ts b/app/api/admin/events/route.ts index 05ae0e0..9828e34 100644 --- a/app/api/admin/events/route.ts +++ b/app/api/admin/events/route.ts @@ -1,7 +1,8 @@ import { NextResponse } from "next/server"; import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; -import { Role, EventType, EventStatus } from "@/prisma/generated/prisma/client"; +import { Role, EventType } from "@/prisma/generated/prisma/client"; +import { calculateEventStatus } from "@/lib/eventStatus"; export async function GET() { try { @@ -15,18 +16,7 @@ export async function GET() { orderBy: { date: "desc", }, - select: { - id: true, - date: true, - name: true, - description: true, - type: true, - status: true, - room: true, - time: true, - maxPlaces: true, - createdAt: true, - updatedAt: true, + include: { _count: { select: { registrations: true, @@ -36,13 +26,14 @@ export async function GET() { }); // Transformer les données pour inclure le nombre d'inscriptions + // Le statut est calculé automatiquement en fonction de la date const eventsWithCount = events.map((event) => ({ id: event.id, date: event.date.toISOString(), name: event.name, description: event.description, type: event.type, - status: event.status, + status: calculateEventStatus(event.date), room: event.room, time: event.time, maxPlaces: event.maxPlaces, @@ -70,15 +61,24 @@ export async function POST(request: Request) { } const body = await request.json(); - const { date, name, description, type, status, room, time, maxPlaces } = body; + const { date, name, description, type, room, time, maxPlaces } = body; - if (!date || !name || !description || !type || !status) { + if (!date || !name || !description || !type) { return NextResponse.json( { error: "Tous les champs sont requis" }, { status: 400 } ); } + // Convertir la date string en Date object + const eventDate = new Date(date); + if (isNaN(eventDate.getTime())) { + return NextResponse.json( + { error: "Format de date invalide" }, + { status: 400 } + ); + } + // Valider les enums if (!Object.values(EventType).includes(type)) { return NextResponse.json( @@ -87,20 +87,12 @@ export async function POST(request: Request) { ); } - if (!Object.values(EventStatus).includes(status)) { - return NextResponse.json( - { error: "Statut d'événement invalide" }, - { status: 400 } - ); - } - const event = await prisma.event.create({ data: { date: eventDate, name, description, type: type as EventType, - status: status as EventStatus, room: room || null, time: time || null, maxPlaces: maxPlaces ? parseInt(maxPlaces) : null, @@ -116,4 +108,3 @@ export async function POST(request: Request) { ); } } - diff --git a/app/events/page.tsx b/app/events/page.tsx index 6a44c79..824e88d 100644 --- a/app/events/page.tsx +++ b/app/events/page.tsx @@ -3,6 +3,7 @@ import EventsPageSection from "@/components/EventsPageSection"; import { prisma } from "@/lib/prisma"; import { getBackgroundImage } from "@/lib/preferences"; import { auth } from "@/lib/auth"; +import { calculateEventStatus } from "@/lib/eventStatus"; export default async function EventsPage() { const events = await prisma.event.findMany({ @@ -26,7 +27,9 @@ export default async function EventsPage() { const initialRegistrations: Record = {}; if (session?.user?.id) { - const upcomingEvents = events.filter((e) => e.status === "UPCOMING"); + const upcomingEvents = events.filter( + (e) => calculateEventStatus(e.date) === "UPCOMING" + ); const eventIds = upcomingEvents.map((e) => e.id); if (eventIds.length > 0) { diff --git a/components/EventManagement.tsx b/components/EventManagement.tsx index 3a5fd78..8876a00 100644 --- a/components/EventManagement.tsx +++ b/components/EventManagement.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useEffect } from "react"; +import { calculateEventStatus } from "@/lib/eventStatus"; interface Event { id: string; @@ -22,7 +23,6 @@ interface EventFormData { name: string; description: string; type: "SUMMIT" | "LAUNCH" | "FESTIVAL" | "COMPETITION" | "CODE_KATA"; - status: "UPCOMING" | "LIVE" | "PAST"; room?: string; time?: string; maxPlaces?: number; @@ -35,8 +35,6 @@ const eventTypes: Event["type"][] = [ "COMPETITION", "CODE_KATA", ]; -const eventStatuses: Event["status"][] = ["UPCOMING", "LIVE", "PAST"]; - const getEventTypeLabel = (type: Event["type"]) => { switch (type) { case "SUMMIT": @@ -78,7 +76,6 @@ export default function EventManagement() { name: "", description: "", type: "SUMMIT", - status: "UPCOMING", room: "", time: "", maxPlaces: undefined, @@ -110,7 +107,6 @@ export default function EventManagement() { name: "", description: "", type: "SUMMIT", - status: "UPCOMING", room: "", time: "", maxPlaces: undefined, @@ -125,7 +121,6 @@ export default function EventManagement() { name: event.name, description: event.description, type: event.type, - status: event.status, room: event.room || "", time: event.time || "", maxPlaces: event.maxPlaces || undefined, @@ -163,7 +158,6 @@ export default function EventManagement() { name: "", description: "", type: "SUMMIT", - status: "UPCOMING", room: "", time: "", maxPlaces: undefined, @@ -210,7 +204,6 @@ export default function EventManagement() { name: "", description: "", type: "SUMMIT", - status: "UPCOMING", room: "", time: "", maxPlaces: undefined, @@ -300,27 +293,6 @@ export default function EventManagement() { ))} -
- - -
@@ -411,15 +383,16 @@ export default function EventManagement() { {getEventTypeLabel(event.type)} { + const status = calculateEventStatus(event.date); + return status === "UPCOMING" ? "bg-green-900/50 border border-green-500/50 text-green-400" - : event.status === "LIVE" + : status === "LIVE" ? "bg-yellow-900/50 border border-yellow-500/50 text-yellow-400" - : "bg-gray-900/50 border border-gray-500/50 text-gray-400" - }`} + : "bg-gray-900/50 border border-gray-500/50 text-gray-400"; + })()}`} > - {getStatusLabel(event.status)} + {getStatusLabel(calculateEventStatus(event.date))}

diff --git a/components/EventsPageSection.tsx b/components/EventsPageSection.tsx index 202b2e0..98b656e 100644 --- a/components/EventsPageSection.tsx +++ b/components/EventsPageSection.tsx @@ -3,6 +3,7 @@ import { useState, useEffect, useMemo, useRef } from "react"; import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; +import { calculateEventStatus } from "@/lib/eventStatus"; interface Event { id: string; @@ -10,7 +11,6 @@ interface Event { name: string; description: string; type: "SUMMIT" | "LAUNCH" | "FESTIVAL" | "COMPETITION" | "CODE_KATA"; - status: "UPCOMING" | "LIVE" | "PAST"; room?: string | null; time?: string | null; maxPlaces?: number | null; @@ -56,7 +56,7 @@ const getEventTypeLabel = (type: Event["type"]) => { } }; -const getStatusBadge = (status: Event["status"]) => { +const getStatusBadge = (status: "UPCOMING" | "LIVE" | "PAST") => { switch (status) { case "UPCOMING": return ( @@ -93,6 +93,9 @@ export default function EventsPageSection({ const [currentMonth, setCurrentMonth] = useState(new Date()); const [selectedEvent, setSelectedEvent] = useState(null); + // Helper function pour obtenir le statut d'un événement + const getEventStatus = (event: Event) => calculateEventStatus(event.date); + // Déterminer si on a des données initiales valides const hasInitialData = useMemo( () => Object.keys(initialRegistrations).length > 0, @@ -103,8 +106,12 @@ export default function EventsPageSection({ const hasUsedInitialData = useRef(hasInitialData); // Séparer et trier les événements (du plus récent au plus ancien) + // Le statut est calculé automatiquement en fonction de la date const upcomingEvents = events - .filter((e) => e.status === "UPCOMING" || e.status === "LIVE") + .filter((e) => { + const status = calculateEventStatus(e.date); + return status === "UPCOMING" || status === "LIVE"; + }) .sort((a, b) => { // Trier par date décroissante (du plus récent au plus ancien) const dateA = typeof a.date === "string" ? new Date(a.date) : a.date; @@ -112,7 +119,7 @@ export default function EventsPageSection({ return dateB.getTime() - dateA.getTime(); }); const pastEvents = events - .filter((e) => e.status === "PAST") + .filter((e) => calculateEventStatus(e.date) === "PAST") .sort((a, b) => { // Trier par date décroissante (du plus récent au plus ancien) const dateA = typeof a.date === "string" ? new Date(a.date) : a.date; @@ -168,7 +175,9 @@ export default function EventsPageSection({ // Charger les inscriptions depuis l'API seulement si on n'a pas de données initiales const checkRegistrations = async () => { - const upcomingOnlyEvents = events.filter((e) => e.status === "UPCOMING"); + const upcomingOnlyEvents = events.filter( + (e) => getEventStatus(e) === "UPCOMING" + ); const registrationChecks = upcomingOnlyEvents.map(async (event) => { try { const response = await fetch(`/api/events/${event.id}/register`); @@ -298,9 +307,11 @@ export default function EventsPageSection({ const hasEvents = dayEvents.length > 0; // Déterminer la couleur principale selon le type d'événement - const hasUpcoming = dayEvents.some((e) => e.status === "UPCOMING"); - const hasLive = dayEvents.some((e) => e.status === "LIVE"); - const hasPast = dayEvents.some((e) => e.status === "PAST"); + const hasUpcoming = dayEvents.some( + (e) => getEventStatus(e) === "UPCOMING" + ); + const hasLive = dayEvents.some((e) => getEventStatus(e) === "LIVE"); + const hasPast = dayEvents.some((e) => getEventStatus(e) === "PAST"); let eventBorderColor = ""; let eventBgColor = ""; @@ -347,19 +358,22 @@ export default function EventsPageSection({

{hasEvents && (
- {dayEvents.slice(0, 3).map((event) => ( -
- ))} + {dayEvents.slice(0, 3).map((event) => { + const status = getEventStatus(event); + return ( +
+ ); + })} {dayEvents.length > 3 && (
)} @@ -393,7 +407,7 @@ export default function EventsPageSection({
{/* Status Badge */}
- {getStatusBadge(event.status)} + {getStatusBadge(getEventStatus(event))} {getEventTypeLabel(event.type)} @@ -457,7 +471,7 @@ export default function EventsPageSection({ )} {/* Action Button */} - {event.status === "UPCOMING" && ( + {getEventStatus(event) === "UPCOMING" && ( <> {registrations[event.id] ? ( )} - {event.status === "PAST" && ( + {getEventStatus(event) === "PAST" && ( @@ -662,7 +676,9 @@ export default function EventsPageSection({
- {getStatusBadge(selectedEvent.status)} + {getStatusBadge( + selectedEvent ? getEventStatus(selectedEvent) : "UPCOMING" + )} {getEventTypeLabel(selectedEvent.type)} @@ -759,47 +775,48 @@ export default function EventsPageSection({
{/* Action Button */} - {selectedEvent.status === "UPCOMING" && ( -
- {registrations[selectedEvent.id] ? ( - - ) : ( - - )} -
- )} - {selectedEvent.status === "LIVE" && ( + {selectedEvent && + getEventStatus(selectedEvent) === "UPCOMING" && ( +
+ {registrations[selectedEvent.id] ? ( + + ) : ( + + )} +
+ )} + {selectedEvent && getEventStatus(selectedEvent) === "LIVE" && (
)} - {selectedEvent.status === "PAST" && ( + {selectedEvent && getEventStatus(selectedEvent) === "PAST" && (