diff --git a/app/agenda/page.tsx b/app/agenda/page.tsx
index fb9d9ffc..04c2fc5b 100644
--- a/app/agenda/page.tsx
+++ b/app/agenda/page.tsx
@@ -106,24 +106,16 @@ export default async function CalendarPage() {
}, 0);
return (
-
-
+
+
);
}
diff --git a/components/calendar/calendar-client.tsx b/components/calendar/calendar-client.tsx
index 5354a9d0..1533bc16 100644
--- a/components/calendar/calendar-client.tsx
+++ b/components/calendar/calendar-client.tsx
@@ -1,12 +1,12 @@
"use client";
-import { useState, useRef, useEffect, useMemo } from "react";
+import { useState, useRef, useEffect } 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, CardHeader, CardContent } from "@/components/ui/card";
+import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
@@ -435,7 +435,9 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
...cal,
events: cal.events || []
})));
- const [selectedCalendarId, setSelectedCalendarId] = useState
(undefined);
+ const [selectedCalendarId, setSelectedCalendarId] = useState(
+ initialCalendars[0]?.id || ""
+ );
const [view, setView] = useState<"dayGridMonth" | "timeGridWeek" | "timeGridDay">("dayGridMonth");
const [isEventModalOpen, setIsEventModalOpen] = useState(false);
const [isCalendarModalOpen, setIsCalendarModalOpen] = useState(false);
@@ -464,81 +466,6 @@ 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) {
@@ -625,19 +552,24 @@ 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: 'POST',
+ const response = await fetch("/api/calendars", {
+ method: calendarData.id ? "PUT" : "POST",
headers: {
- 'Content-Type': 'application/json',
+ "Content-Type": "application/json",
},
body: JSON.stringify({
...calendarData,
@@ -646,15 +578,14 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
});
if (!response.ok) {
- throw new Error('Failed to save calendar');
+ throw new Error("Failed to save calendar");
}
- const savedCalendar = await response.json();
- setCalendars(prev => [...prev, savedCalendar]);
+ await fetchCalendars();
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);
}
@@ -664,98 +595,160 @@ 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");
}
- setCalendars(prev => prev.filter(cal => cal.id !== calendarId));
- if (selectedCalendarId === calendarId) {
- setSelectedCalendarId(undefined);
- }
+ await fetchCalendars();
setIsCalendarModalOpen(false);
+
+ // If the deleted calendar was selected, select another one
+ if (selectedCalendarId === calendarId) {
+ const remainingCalendars = calendars.filter(cal => cal.id !== calendarId);
+ setSelectedCalendarId(remainingCalendars[0]?.id || "");
+ }
} 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) => {
- setSelectedEvent(null);
- setEventForm({
- title: "",
- description: null,
- start: selectInfo.startStr,
- end: selectInfo.endStr,
- allDay: selectInfo.allDay,
- location: null,
- calendarId: selectedCalendarId
+ 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
});
+
+ // 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) => {
- setSelectedEvent(clickInfo.event.extendedProps.originalEvent);
+ const event = clickInfo.event;
+ const startDate = new Date(event.start);
+ const endDate = new Date(event.end || event.start);
+
+ setSelectedEvent(event.extendedProps.originalEvent);
setEventForm({
- 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
+ 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,
});
setIsEventModalOpen(true);
};
const handleEventSubmit = async () => {
try {
- setLoading(true);
- setError(null);
+ // 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);
const eventData = {
...eventForm,
- calendarId: selectedCalendarId || calendars[0]?.id
+ 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
};
- const response = await fetch('/api/events', {
- method: selectedEvent ? 'PUT' : 'POST',
+ console.log("Submitting event with data:", eventData);
+
+ const response = await fetch("/api/events", {
+ method: selectedEvent ? "PUT" : "POST",
headers: {
- 'Content-Type': 'application/json',
+ "Content-Type": "application/json",
},
body: JSON.stringify(eventData),
});
- if (!response.ok) {
- throw new Error('Failed to save event');
- }
-
- const savedEvent = await response.json();
+ const responseData = await response.json();
+ console.log("Response from server:", responseData);
- 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
- })));
+ if (!response.ok) {
+ console.error("Error response:", responseData);
+ throw new Error(responseData.error || "Failed to save event");
}
+ // 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);
}
@@ -923,99 +916,455 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
};
return (
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
- handleViewChange("dayGridMonth")}
- >
- Mois
-
- handleViewChange("timeGridWeek")}
- >
- Semaine
-
- handleViewChange("timeGridDay")}
- >
- Jour
-
-
-
-
-
-
-
-
+
+
+ handleViewChange("dayGridMonth")}
+ >
+ Mois
+
+ handleViewChange("timeGridWeek")}
+ >
+ Semaine
+
+ handleViewChange("timeGridDay")}
+ >
+ Jour
+
+
+
+
+
+
+
+
+
+ {loading ? (
+
+
+ Chargement des événements...
+
+ ) : (
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}
selectable={true}
+ selectMirror={true}
+ dayMaxEventRows={false}
+ dayMaxEvents={false}
+ weekends={true}
select={handleDateSelect}
eventClick={handleEventClick}
- eventContent={renderEventContent}
- locale={frLocale}
- firstDay={1}
- weekends={true}
- allDaySlot={true}
- slotMinTime="08:00:00"
- slotMaxTime="20:00:00"
- expandRows={true}
- stickyHeaderDates={true}
- dayMaxEvents={true}
- eventTimeFormat={{
- hour: '2-digit',
- minute: '2-digit',
- hour12: false
- }}
+ 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 */}
+
);
}