calendar 35

This commit is contained in:
Alma 2025-04-13 17:17:43 +02:00
parent 9736b05ad4
commit f53b6556a1

View File

@ -771,7 +771,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
end: new Date(eventForm.end).toISOString(), end: new Date(eventForm.end).toISOString(),
allDay: eventForm.allDay, allDay: eventForm.allDay,
location: eventForm.location, location: eventForm.location,
calendarId: selectedCalendarId, calendarId: selectedCalendarId,
userId userId
}; };
@ -897,9 +897,9 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
// Update CalendarSelector to handle visibility // Update CalendarSelector to handle visibility
const CalendarSelector = () => ( const CalendarSelector = () => (
<div className="flex flex-wrap items-center gap-2 mb-4"> <div className="flex flex-wrap items-center gap-2 mb-4">
{calendars.map((calendar) => ( {calendars.map((calendar) => (
<div key={calendar.id} className="relative group"> <div key={calendar.id} className="relative group">
<Button <Button
variant={visibleCalendarIds.includes(calendar.id) ? "secondary" : "ghost"} variant={visibleCalendarIds.includes(calendar.id) ? "secondary" : "ghost"}
className="flex items-center gap-2 pr-8" className="flex items-center gap-2 pr-8"
onClick={() => { onClick={() => {
@ -920,9 +920,9 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
<Check className="h-4 w-4" /> <Check className="h-4 w-4" />
) : null} ) : null}
</div> </div>
</Button> </Button>
{calendar.name !== "Calendrier principal" && ( {calendar.name !== "Calendrier principal" && (
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
className="absolute right-0 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity" className="absolute right-0 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity"
@ -933,7 +933,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
}} }}
> >
<Settings className="h-4 w-4" /> <Settings className="h-4 w-4" />
</Button> </Button>
)} )}
</div> </div>
))} ))}
@ -988,110 +988,74 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
}; };
return ( return (
<div className="flex flex-col md:flex-row h-full gap-4 p-4"> <div className="space-y-4">
{/* Sidebar */} <Card className="p-4">
<div className="w-full md:w-64 space-y-4"> <div className="flex items-center justify-between mb-4">
<Card className="p-4"> <div className="flex items-center gap-4">
<div className="flex items-center justify-between mb-4"> <Button
<div className="flex items-center gap-4"> variant="outline"
<Button onClick={() => {
variant="outline" setSelectedCalendar(null);
onClick={() => { setIsCalendarModalOpen(true);
setSelectedCalendar(null); }}
setIsCalendarModalOpen(true); className="bg-white hover:bg-gray-50 text-gray-900 border-gray-200"
}} >
className="bg-white hover:bg-gray-50 text-gray-900 border-gray-200" <Plus className="mr-2 h-4 w-4" />
> <span className="font-medium">Nouveau calendrier</span>
<Plus className="mr-2 h-4 w-4" /> </Button>
<span className="font-medium">Nouveau calendrier</span>
</Button>
<Button <Button
onClick={() => { onClick={() => {
setSelectedEvent(null); setSelectedEvent(null);
setEventForm({ setEventForm({
title: "", title: "",
description: null, description: null,
start: "", start: "",
end: "", end: "",
allDay: false, allDay: false,
location: null, location: null,
calendarId: selectedCalendarId calendarId: selectedCalendarId
}); });
setIsEventModalOpen(true); setIsEventModalOpen(true);
}} }}
className="bg-primary hover:bg-primary/90 text-white" className="bg-primary hover:bg-primary/90 text-white"
> >
<Plus className="mr-2 h-4 w-4" /> <Plus className="mr-2 h-4 w-4" />
<span className="font-medium">Nouvel événement</span> <span className="font-medium">Nouvel événement</span>
</Button> </Button>
</div> </div>
<Tabs value={view} className="w-auto"> <Tabs value={view} className="w-auto">
<TabsList> <TabsList>
<TabsTrigger <TabsTrigger
value="dayGridMonth" value="dayGridMonth"
onClick={() => handleViewChange("dayGridMonth")} onClick={() => handleViewChange("dayGridMonth")}
> >
Mois Mois
</TabsTrigger> </TabsTrigger>
<TabsTrigger <TabsTrigger
value="timeGridWeek" value="timeGridWeek"
onClick={() => handleViewChange("timeGridWeek")} onClick={() => handleViewChange("timeGridWeek")}
> >
Semaine Semaine
</TabsTrigger> </TabsTrigger>
<TabsTrigger <TabsTrigger
value="timeGridDay" value="timeGridDay"
onClick={() => handleViewChange("timeGridDay")} onClick={() => handleViewChange("timeGridDay")}
> >
Jour Jour
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>
</Tabs> </Tabs>
</div> </div>
<CalendarSelector /> <CalendarSelector />
</Card>
<StatisticsPanel statistics={statistics} /> {loading ? (
<div className="h-96 flex items-center justify-center">
<Loader2 className="h-8 w-8 animate-spin text-primary" />
<span className="ml-2">Chargement des événements...</span>
</div> </div>
) : (
{/* Calendar */}
<div className="flex-1 bg-white rounded-lg shadow">
<style jsx global>{`
.fc-daygrid-day-events {
max-height: 80px;
overflow-y: auto;
margin-right: 2px;
}
.fc-daygrid-day-events::-webkit-scrollbar {
width: 4px;
}
.fc-daygrid-day-events::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 2px;
}
.fc-daygrid-day-events::-webkit-scrollbar-thumb {
background: #888;
border-radius: 2px;
}
.fc-daygrid-day-events::-webkit-scrollbar-thumb:hover {
background: #555;
}
.fc .fc-daygrid-event-harness {
margin-bottom: 2px;
}
.fc-daygrid-day-frame {
min-height: 100px !important;
height: 100px !important;
}
`}</style>
<FullCalendar <FullCalendar
ref={calendarRef} ref={calendarRef}
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]} plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
@ -1101,75 +1065,76 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend
center: "title", center: "title",
right: "", right: "",
}} }}
events={calendars events={calendars
.filter(cal => visibleCalendarIds.includes(cal.id)) .filter(cal => visibleCalendarIds.includes(cal.id))
.flatMap(cal => .flatMap(cal =>
(cal.events || []).map(event => ({ (cal.events || []).map(event => ({
id: event.id, id: event.id,
title: event.title, title: event.title,
start: new Date(event.start), start: new Date(event.start),
end: new Date(event.end), end: new Date(event.end),
allDay: event.isAllDay, allDay: event.isAllDay,
description: event.description, description: event.description,
location: event.location, location: event.location,
calendarId: event.calendarId,
backgroundColor: cal.color,
borderColor: cal.color,
textColor: '#ffffff',
extendedProps: {
location: event.location,
description: event.description,
calendarId: event.calendarId, calendarId: event.calendarId,
originalEvent: event backgroundColor: cal.color,
} borderColor: cal.color,
})) textColor: '#ffffff',
)} extendedProps: {
eventContent={(arg) => ( location: event.location,
<div className="p-1 overflow-hidden"> description: event.description,
<div className="font-semibold truncate">{arg.event.title}</div> calendarId: event.calendarId,
{!arg.event.allDay && ( originalEvent: event
<div className="text-xs opacity-90"> }
{new Date(arg.event.start).toLocaleTimeString('fr-FR', { }))
hour: '2-digit', )}
minute: '2-digit' eventContent={(arg) => (
})} <div className="p-1 overflow-hidden">
{arg.event.end && ( <div className="font-semibold truncate">{arg.event.title}</div>
<> - {new Date(arg.event.end).toLocaleTimeString('fr-FR', { {!arg.event.allDay && (
<div className="text-xs opacity-90">
{new Date(arg.event.start).toLocaleTimeString('fr-FR', {
hour: '2-digit', hour: '2-digit',
minute: '2-digit' minute: '2-digit'
})}</> })}
)} {arg.event.end && (
</div> <> - {new Date(arg.event.end).toLocaleTimeString('fr-FR', {
)} hour: '2-digit',
{arg.event.extendedProps.location && ( minute: '2-digit'
<div className="text-xs opacity-75 truncate"> })}</>
<MapPin className="inline-block w-3 h-3 mr-1" /> )}
{arg.event.extendedProps.location} </div>
</div> )}
)} {arg.event.extendedProps.location && (
</div> <div className="text-xs opacity-75 truncate">
)} <MapPin className="inline-block w-3 h-3 mr-1" />
eventClassNames="rounded-md shadow-sm hover:shadow-md transition-shadow cursor-pointer" {arg.event.extendedProps.location}
locale={frLocale} </div>
)}
</div>
)}
eventClassNames="rounded-md shadow-sm hover:shadow-md transition-shadow cursor-pointer"
locale={frLocale}
selectable={true} selectable={true}
selectMirror={true} selectMirror={true}
dayMaxEvents={false} dayMaxEvents={true}
weekends={true} weekends={true}
select={handleDateSelect} select={handleDateSelect}
eventClick={handleEventClick} eventClick={handleEventClick}
height="auto" height="auto"
aspectRatio={1.8} aspectRatio={1.8}
slotMinTime="06:00:00" slotMinTime="06:00:00"
slotMaxTime="22:00:00" slotMaxTime="22:00:00"
allDaySlot={true} allDaySlot={true}
allDayText="Toute la journée" allDayText="Toute la journée"
slotLabelFormat={{ slotLabelFormat={{
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit',
hour12: false hour12: false
}} }}
/> />
</div> )}
</Card>
{/* Calendar dialog */} {/* Calendar dialog */}
<CalendarDialog <CalendarDialog