From b2240cb880d63e81dee410123fcc1aa2f184f8ff Mon Sep 17 00:00:00 2001 From: Alma Date: Sun, 13 Apr 2025 13:56:43 +0200 Subject: [PATCH] calendar 9 --- components/calendar/calendar-client.tsx | 437 ++++++++++++++++++------ 1 file changed, 332 insertions(+), 105 deletions(-) diff --git a/components/calendar/calendar-client.tsx b/components/calendar/calendar-client.tsx index c29215b0..36cf1e09 100644 --- a/components/calendar/calendar-client.tsx +++ b/components/calendar/calendar-client.tsx @@ -9,12 +9,35 @@ import frLocale from "@fullcalendar/core/locales/fr"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Loader2, Plus, Calendar as CalendarIcon, Check, X } from "lucide-react"; +import { + Loader2, + Plus, + Calendar as CalendarIcon, + Check, + X, + User, + Clock, + BarChart2, + Settings, + ChevronRight, + ChevronLeft, + Bell, + Users, + MapPin, + Tag, + ChevronDown, + ChevronUp +} from "lucide-react"; import { Calendar, Event } from "@prisma/client"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Badge } from "@/components/ui/badge"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Separator } from "@/components/ui/separator"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; // Predefined professional color palette const colorPalette = [ @@ -35,6 +58,11 @@ const colorPalette = [ interface CalendarClientProps { initialCalendars: (Calendar & { events: Event[] })[]; userId: string; + userProfile: { + name: string; + email: string; + avatar?: string; + }; } interface EventFormData { @@ -233,7 +261,136 @@ function CalendarDialog({ open, onClose, onSave, initialData }: CalendarDialogPr ); } -export function CalendarClient({ initialCalendars, userId }: CalendarClientProps) { +function StatisticsPanel({ statistics }: { + statistics: { + totalEvents: number; + upcomingEvents: number; + completedEvents: number; + meetingHours: number; + }; +}) { + return ( +
+ +
+
+ +
+
+

Total Événements

+

{statistics.totalEvents}

+
+
+
+ +
+
+ +
+
+

Heures de Réunion

+

{statistics.meetingHours}h

+
+
+
+ +
+
+ +
+
+

Prochains Événements

+

{statistics.upcomingEvents}

+
+
+
+ +
+
+ +
+
+

Événements Terminés

+

{statistics.completedEvents}

+
+
+
+
+ ); +} + +function EventPreview({ event, calendar }: { event: Event; calendar: Calendar }) { + const [isExpanded, setIsExpanded] = useState(false); + + return ( + +
+
+

{event.title}

+
+ + + {new Date(event.start).toLocaleDateString('fr-FR', { + weekday: 'long', + day: 'numeric', + month: 'long', + hour: '2-digit', + minute: '2-digit' + })} + +
+
+
+
+ +
+
+ + {isExpanded && ( +
+ {event.description && ( +

{event.description}

+ )} + +
+ {event.location && ( +
+ + {event.location} +
+ )} + {event.calendarId && ( +
+ + {calendar.name} +
+ )} +
+ +
+ + +
+
+ )} + + ); +} + +export function CalendarClient({ initialCalendars, userId, userProfile }: CalendarClientProps) { const [calendars, setCalendars] = useState(initialCalendars); const [selectedCalendarId, setSelectedCalendarId] = useState( initialCalendars[0]?.id || "" @@ -254,6 +411,29 @@ export function CalendarClient({ initialCalendars, userId }: CalendarClientProps location: null, }); + const [selectedEventPreview, setSelectedEventPreview] = useState(null); + const [statistics, setStatistics] = useState({ + totalEvents: initialCalendars.reduce((acc, cal) => acc + cal.events.length, 0), + upcomingEvents: initialCalendars.reduce((acc, cal) => + acc + cal.events.filter(e => new Date(e.start) > new Date()).length, 0 + ), + completedEvents: initialCalendars.reduce((acc, cal) => + acc + cal.events.filter(e => new Date(e.end) < new Date()).length, 0 + ), + meetingHours: initialCalendars.reduce((acc, cal) => + acc + cal.events.reduce((hours, e) => { + const duration = (new Date(e.end).getTime() - new Date(e.start).getTime()) / (1000 * 60 * 60); + return hours + duration; + }, 0) + , 0) + }); + + const upcomingEvents = initialCalendars + .flatMap(cal => cal.events) + .filter(event => new Date(event.start) > new Date()) + .sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime()) + .slice(0, 5); + const calendarRef = useRef(null); const handleCalendarSave = async (calendarData: Partial) => { @@ -412,114 +592,161 @@ export function CalendarClient({ initialCalendars, userId }: CalendarClientProps return (
- {error && ( -
- {error} -
- )} - - {/* Calendar management */} -
-
- {calendars.map((calendar) => ( - - ))} - -
- -
+ - {/* View selector */} - - - handleViewChange("dayGridMonth")} - > - Mois - - handleViewChange("timeGridWeek")} - > - Semaine - - handleViewChange("timeGridDay")} - > - Jour - - +
+
+ +
+
+ + +
- {/* Calendar display */} - - {loading ? ( -
- - Chargement des événements... + + + handleViewChange("dayGridMonth")} + > + Mois + + handleViewChange("timeGridWeek")} + > + Semaine + + handleViewChange("timeGridDay")} + > + Jour + + +
- ) : ( - - cal.events.map(event => ({ - id: event.id, - title: event.title, - start: event.start, - end: event.end, - allDay: event.isAllDay, - description: event.description, - location: event.location, - calendarId: event.calendarId, - originalEvent: event, - backgroundColor: cal.color, - })) - )} - locale={frLocale} - selectable={true} - selectMirror={true} - dayMaxEvents={true} - weekends={true} - select={handleDateSelect} - eventClick={handleEventClick} - height="auto" - aspectRatio={1.8} + + {loading ? ( +
+ + Chargement des événements... +
+ ) : ( + + cal.events.map(event => ({ + id: event.id, + title: event.title, + start: event.start, + end: event.end, + allDay: event.isAllDay, + description: event.description, + location: event.location, + calendarId: event.calendarId, + originalEvent: event, + backgroundColor: cal.color, + textColor: '#ffffff', + borderColor: cal.color, + })) + )} + locale={frLocale} + selectable={true} + selectMirror={true} + dayMaxEvents={true} + weekends={true} + select={handleDateSelect} + eventClick={(clickInfo) => { + handleEventClick(clickInfo); + setSelectedEventPreview(clickInfo.event.extendedProps.originalEvent); + }} + height="auto" + aspectRatio={1.8} + /> + )} +
+
+ +
+ {selectedEventPreview ? ( + c.id === selectedEventPreview.calendarId)!} /> + ) : ( + +
+

Mini-calendrier

+ + cal.events.map(event => ({ + id: event.id, + title: event.title, + start: event.start, + end: event.end, + backgroundColor: cal.color, + })) + )} + locale={frLocale} + /> +
+
)} - - + + +

Calendriers

+
+ {calendars.map((calendar) => ( + + ))} +
+
+
+
{/* Calendar dialog */}