diff --git a/app/agenda/page.tsx b/app/agenda/page.tsx
index 04c2fc5b..fb9d9ffc 100644
--- a/app/agenda/page.tsx
+++ b/app/agenda/page.tsx
@@ -106,16 +106,24 @@ export default async function CalendarPage() {
}, 0);
return (
-
-
+
);
}
diff --git a/components/calendar/calendar-client.tsx b/components/calendar/calendar-client.tsx
index 1533bc16..5354a9d0 100644
--- a/components/calendar/calendar-client.tsx
+++ b/components/calendar/calendar-client.tsx
@@ -1,12 +1,12 @@
"use client";
-import { useState, useRef, useEffect } from "react";
+import { useState, useRef, useEffect, useMemo } from "react";
import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import interactionPlugin from "@fullcalendar/interaction";
import frLocale from "@fullcalendar/core/locales/fr";
-import { Card } from "@/components/ui/card";
+import { Card, CardHeader, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
@@ -435,9 +435,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
...cal,
events: cal.events || []
})));
- const [selectedCalendarId, setSelectedCalendarId] = useState
(
- initialCalendars[0]?.id || ""
- );
+ const [selectedCalendarId, setSelectedCalendarId] = useState(undefined);
const [view, setView] = useState<"dayGridMonth" | "timeGridWeek" | "timeGridDay">("dayGridMonth");
const [isEventModalOpen, setIsEventModalOpen] = useState(false);
const [isCalendarModalOpen, setIsCalendarModalOpen] = useState(false);
@@ -466,6 +464,81 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
const [visibleCalendarIds, setVisibleCalendarIds] = useState([]);
+ // Calculate events based on visible calendars
+ const events = useMemo(() => {
+ return calendars
+ .filter(cal => visibleCalendarIds.includes(cal.id))
+ .flatMap(cal =>
+ (cal.events || []).map(event => ({
+ id: event.id,
+ title: event.title,
+ start: new Date(event.start),
+ end: new Date(event.end),
+ allDay: event.isAllDay,
+ description: event.description,
+ location: event.location,
+ calendarId: event.calendarId,
+ backgroundColor: `${cal.color}dd`,
+ borderColor: cal.color,
+ textColor: '#ffffff',
+ extendedProps: {
+ calendarName: cal.name,
+ location: event.location,
+ description: event.description,
+ calendarId: event.calendarId,
+ originalEvent: event,
+ color: cal.color
+ }
+ }))
+ );
+ }, [calendars, visibleCalendarIds]);
+
+ // Event content renderer
+ const renderEventContent = (arg: any) => {
+ return (
+
+
+
+
+
+ {!arg.event.allDay && (
+
+ {new Date(arg.event.start).toLocaleTimeString('fr-FR', {
+ hour: '2-digit',
+ minute: '2-digit'
+ })}
+
+ )}
+
+ {arg.event.title}
+
+
+
+
+
+
+
{arg.event.title}
+ {!arg.event.allDay && (
+
+ {new Date(arg.event.start).toLocaleTimeString('fr-FR', {
+ hour: '2-digit',
+ minute: '2-digit'
+ })}
+
+ )}
+
+
+
+
+ );
+ };
+
// Update useEffect to initialize visible calendars and fetch events
useEffect(() => {
if (calendars.length > 0) {
@@ -552,24 +625,19 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
}
};
- const calendarRef = useRef(null);
+ const calendarRef = useRef(null);
const handleCalendarSelect = (calendarId: string) => {
- console.log("Calendar selected:", calendarId);
setSelectedCalendarId(calendarId);
- setEventForm(prev => ({
- ...prev,
- calendarId: calendarId
- }));
};
const handleCalendarSave = async (calendarData: Partial) => {
try {
setLoading(true);
- const response = await fetch("/api/calendars", {
- method: calendarData.id ? "PUT" : "POST",
+ const response = await fetch('/api/calendars', {
+ method: 'POST',
headers: {
- "Content-Type": "application/json",
+ 'Content-Type': 'application/json',
},
body: JSON.stringify({
...calendarData,
@@ -578,14 +646,15 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
});
if (!response.ok) {
- throw new Error("Failed to save calendar");
+ throw new Error('Failed to save calendar');
}
- await fetchCalendars();
+ const savedCalendar = await response.json();
+ setCalendars(prev => [...prev, savedCalendar]);
setIsCalendarModalOpen(false);
} catch (error) {
- console.error("Error saving calendar:", error);
- setError(error instanceof Error ? error.message : "Failed to save calendar");
+ console.error('Error saving calendar:', error);
+ setError(error instanceof Error ? error.message : 'Failed to save calendar');
} finally {
setLoading(false);
}
@@ -595,160 +664,98 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
try {
setLoading(true);
const response = await fetch(`/api/calendars/${calendarId}`, {
- method: "DELETE",
+ method: 'DELETE',
});
if (!response.ok) {
- throw new Error("Failed to delete calendar");
+ throw new Error('Failed to delete calendar');
}
- await fetchCalendars();
- setIsCalendarModalOpen(false);
-
- // If the deleted calendar was selected, select another one
+ setCalendars(prev => prev.filter(cal => cal.id !== calendarId));
if (selectedCalendarId === calendarId) {
- const remainingCalendars = calendars.filter(cal => cal.id !== calendarId);
- setSelectedCalendarId(remainingCalendars[0]?.id || "");
+ setSelectedCalendarId(undefined);
}
+ setIsCalendarModalOpen(false);
} catch (error) {
- console.error("Error deleting calendar:", error);
- setError(error instanceof Error ? error.message : "Failed to delete calendar");
+ console.error('Error deleting calendar:', error);
+ setError(error instanceof Error ? error.message : 'Failed to delete calendar');
} finally {
setLoading(false);
}
};
const handleDateSelect = (selectInfo: any) => {
- const startDate = new Date(selectInfo.start);
- const endDate = new Date(selectInfo.end);
-
- console.log("Date select handler - Current state:", {
- calendars: calendars.map(c => ({ id: c.id, name: c.name })),
- selectedCalendarId,
- availableCalendars: calendars.length
+ setSelectedEvent(null);
+ setEventForm({
+ title: "",
+ description: null,
+ start: selectInfo.startStr,
+ end: selectInfo.endStr,
+ allDay: selectInfo.allDay,
+ location: null,
+ calendarId: selectedCalendarId
});
-
- // If no calendar is selected, use the first available calendar
- if (!selectedCalendarId && calendars.length > 0) {
- const firstCalendar = calendars[0];
- console.log("No calendar selected, selecting first calendar:", firstCalendar);
- setSelectedCalendarId(firstCalendar.id);
-
- setEventForm({
- title: "",
- description: null,
- start: startDate.toISOString(),
- end: endDate.toISOString(),
- allDay: selectInfo.allDay,
- location: null,
- calendarId: firstCalendar.id
- });
- } else {
- setEventForm({
- title: "",
- description: null,
- start: startDate.toISOString(),
- end: endDate.toISOString(),
- allDay: selectInfo.allDay,
- location: null,
- calendarId: selectedCalendarId
- });
- }
-
setIsEventModalOpen(true);
};
const handleEventClick = (clickInfo: any) => {
- const event = clickInfo.event;
- const startDate = new Date(event.start);
- const endDate = new Date(event.end || event.start);
-
- setSelectedEvent(event.extendedProps.originalEvent);
+ setSelectedEvent(clickInfo.event.extendedProps.originalEvent);
setEventForm({
- title: event.title,
- description: event.extendedProps.description,
- start: startDate.toISOString().slice(0, 16),
- end: endDate.toISOString().slice(0, 16),
- allDay: event.isAllDay,
- location: event.extendedProps.location,
- calendarId: event.extendedProps.calendarId,
+ title: clickInfo.event.title,
+ description: clickInfo.event.extendedProps.description,
+ start: clickInfo.event.startStr,
+ end: clickInfo.event.endStr,
+ allDay: clickInfo.event.allDay,
+ location: clickInfo.event.extendedProps.location,
+ calendarId: clickInfo.event.extendedProps.calendarId
});
setIsEventModalOpen(true);
};
const handleEventSubmit = async () => {
try {
- // Validate required fields including calendar
- if (!eventForm.title || !eventForm.start || !eventForm.end || !eventForm.calendarId) {
- console.log("Form validation failed:", {
- title: eventForm.title,
- start: eventForm.start,
- end: eventForm.end,
- calendarId: eventForm.calendarId
- });
- setError("Veuillez remplir tous les champs obligatoires et sélectionner un calendrier");
- return;
- }
-
setLoading(true);
+ setError(null);
+
const eventData = {
...eventForm,
- start: new Date(eventForm.start).toISOString(),
- end: new Date(eventForm.end).toISOString(),
- userId,
- ...(selectedEvent ? { id: selectedEvent.id } : {}), // Include ID for updates
- allDay: eventForm.allDay // Use allDay instead of isAllDay
+ calendarId: selectedCalendarId || calendars[0]?.id
};
- console.log("Submitting event with data:", eventData);
-
- const response = await fetch("/api/events", {
- method: selectedEvent ? "PUT" : "POST",
+ const response = await fetch('/api/events', {
+ method: selectedEvent ? 'PUT' : 'POST',
headers: {
- "Content-Type": "application/json",
+ 'Content-Type': 'application/json',
},
body: JSON.stringify(eventData),
});
- const responseData = await response.json();
- console.log("Response from server:", responseData);
-
if (!response.ok) {
- console.error("Error response:", responseData);
- throw new Error(responseData.error || "Failed to save event");
+ throw new Error('Failed to save event');
+ }
+
+ const savedEvent = await response.json();
+
+ if (selectedEvent) {
+ setCalendars(prev => prev.map(cal => ({
+ ...cal,
+ events: cal.events.map(ev =>
+ ev.id === selectedEvent.id ? savedEvent : ev
+ )
+ })));
+ } else {
+ setCalendars(prev => prev.map(cal => ({
+ ...cal,
+ events: cal.id === eventData.calendarId
+ ? [...cal.events, savedEvent]
+ : cal.events
+ })));
}
- // Reset form and close modal first
setIsEventModalOpen(false);
- setEventForm({
- title: "",
- description: null,
- start: "",
- end: "",
- allDay: false,
- location: null,
- calendarId: selectedCalendarId
- });
- setSelectedEvent(null);
- setError(null);
-
- // Update calendars state with the new event
- const updatedCalendars = calendars.map(cal => {
- if (cal.id === eventData.calendarId) {
- return {
- ...cal,
- events: [...cal.events, responseData]
- };
- }
- return cal;
- });
- setCalendars(updatedCalendars);
-
- // Fetch fresh data to ensure all calendars are up to date
- await fetchCalendars();
} catch (error) {
- console.error("Error saving event:", error);
- setError(error instanceof Error ? error.message : "Failed to save event");
+ console.error('Error saving event:', error);
+ setError(error instanceof Error ? error.message : 'Failed to save event');
} finally {
setLoading(false);
}
@@ -916,455 +923,99 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
};
return (
-
-
-
-
-
-
-
-
-
-
- handleViewChange("dayGridMonth")}
- >
- Mois
-
- handleViewChange("timeGridWeek")}
- >
- Semaine
-
- handleViewChange("timeGridDay")}
- >
- Jour
-
-
-
-
-
-
-
-
-
- {loading ? (
-
-
-
Chargement des événements...
+
+
+
+
+
+
+
- ) : (
+
+
+
+ handleViewChange("dayGridMonth")}
+ >
+ Mois
+
+ handleViewChange("timeGridWeek")}
+ >
+ Semaine
+
+ handleViewChange("timeGridDay")}
+ >
+ Jour
+
+
+
+
+
+
+
+
visibleCalendarIds.includes(cal.id))
- .flatMap(cal =>
- (cal.events || []).map(event => ({
- id: event.id,
- title: event.title,
- start: new Date(event.start),
- end: new Date(event.end),
- allDay: event.isAllDay,
- description: event.description,
- location: event.location,
- calendarId: event.calendarId,
- backgroundColor: `${cal.color}dd`,
- borderColor: cal.color,
- textColor: '#ffffff',
- extendedProps: {
- calendarName: cal.name,
- location: event.location,
- description: event.description,
- calendarId: event.calendarId,
- originalEvent: event,
- color: cal.color
- }
- }))
- )}
- eventContent={(arg) => {
- return (
-
-
-
-
-
- {!arg.event.allDay && (
-
- {new Date(arg.event.start).toLocaleTimeString('fr-FR', {
- hour: '2-digit',
- minute: '2-digit'
- })}
-
- )}
-
- {arg.event.title}
-
-
-
-
-
-
-
{arg.event.title}
- {!arg.event.allDay && (
-
- {new Date(arg.event.start).toLocaleTimeString('fr-FR', {
- hour: '2-digit',
- minute: '2-digit'
- })}
-
- )}
-
-
-
-
- );
- }}
- eventClassNames="rounded-md overflow-hidden"
- dayCellContent={(arg) => {
- return (
-
- {arg.dayNumberText}
-
- );
- }}
- locale={frLocale}
+ initialView="dayGridMonth"
+ headerToolbar={false}
+ height="100%"
+ events={events}
selectable={true}
- selectMirror={true}
- dayMaxEventRows={false}
- dayMaxEvents={false}
- weekends={true}
select={handleDateSelect}
eventClick={handleEventClick}
- height="auto"
- aspectRatio={1.8}
- slotMinTime="06:00:00"
- slotMaxTime="22:00:00"
- allDaySlot={true}
- allDayText=""
- views={{
- timeGridWeek: {
- allDayText: "",
- dayHeaderFormat: { weekday: 'long', day: 'numeric', month: 'numeric' }
- },
- timeGridDay: {
- allDayText: "",
- dayHeaderFormat: { weekday: 'long', day: 'numeric', month: 'numeric' }
- }
- }}
- slotLabelFormat={{
- hour: '2-digit',
- minute: '2-digit',
- hour12: false
- }}
- />
- )}
-
-
- {/* Calendar dialog */}
- setIsCalendarModalOpen(false)}
- onSave={handleCalendarSave}
- onDelete={handleCalendarDelete}
- initialData={selectedCalendar || undefined}
- />
-
- {/* Event dialog */}
-
+
+
);
}