From 8c51fae1a76d68caa05ddd18c522e4ca6fbb0619 Mon Sep 17 00:00:00 2001 From: alma Date: Wed, 14 Jan 2026 11:23:16 +0100 Subject: [PATCH] Vision Refactor --- app/vision/page.tsx | 435 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 407 insertions(+), 28 deletions(-) diff --git a/app/vision/page.tsx b/app/vision/page.tsx index 2b0fe10..ce0a84a 100644 --- a/app/vision/page.tsx +++ b/app/vision/page.tsx @@ -4,9 +4,14 @@ import { useState, useEffect } from "react"; import { useSession } from "next-auth/react"; import { redirect } from "next/navigation"; import { ResponsiveIframe } from "@/app/components/responsive-iframe"; -import { Users, FolderKanban, Video, ArrowLeft, Loader2 } from "lucide-react"; +import { Users, FolderKanban, Video, ArrowLeft, Loader2, Calendar, Clock, Plus, X } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useToast } from "@/components/ui/use-toast"; +import { Calendar as CalendarComponent } from "@/components/ui/calendar"; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Badge } from "@/components/ui/badge"; interface Group { id: string; @@ -20,6 +25,16 @@ interface Mission { logoUrl?: string | null; } +interface ScheduledMeeting { + id: string; + type: "group" | "mission"; + entityId: string; + entityName: string; + date: string; // ISO date string + time: string; // HH:mm format + title?: string; +} + type ConferenceType = "group" | "mission" | null; export default function VisionPage() { @@ -34,6 +49,25 @@ export default function VisionPage() { name: string; } | null>(null); const [jitsiUrl, setJitsiUrl] = useState(null); + const [scheduledMeetings, setScheduledMeetings] = useState([]); + const [showCalendar, setShowCalendar] = useState(false); + const [showMeetingDialog, setShowMeetingDialog] = useState(false); + const [selectedDate, setSelectedDate] = useState(new Date()); + const [meetingForm, setMeetingForm] = useState<{ + type: "group" | "mission" | ""; + entityId: string; + entityName: string; + date: string; + time: string; + title: string; + }>({ + type: "", + entityId: "", + entityName: "", + date: "", + time: "", + title: "", + }); // Redirect if not authenticated useEffect(() => { @@ -42,6 +76,27 @@ export default function VisionPage() { } }, [status]); + // Load scheduled meetings from localStorage + useEffect(() => { + if (status === "authenticated" && session?.user?.id) { + const stored = localStorage.getItem(`meetings_${session.user.id}`); + if (stored) { + try { + setScheduledMeetings(JSON.parse(stored)); + } catch (e) { + console.error("Error loading meetings:", e); + } + } + } + }, [session, status]); + + // Save scheduled meetings to localStorage + useEffect(() => { + if (status === "authenticated" && session?.user?.id && scheduledMeetings.length >= 0) { + localStorage.setItem(`meetings_${session.user.id}`, JSON.stringify(scheduledMeetings)); + } + }, [scheduledMeetings, session, status]); + // Fetch user groups and missions useEffect(() => { const fetchData = async () => { @@ -119,6 +174,84 @@ export default function VisionPage() { setJitsiUrl(null); }; + // Get today's meetings + const getTodayMeetings = (): ScheduledMeeting[] => { + const today = new Date(); + const todayStr = today.toISOString().split('T')[0]; + return scheduledMeetings.filter(meeting => meeting.date === todayStr); + }; + + // Get meetings for a specific date + const getMeetingsForDate = (date: Date): ScheduledMeeting[] => { + const dateStr = date.toISOString().split('T')[0]; + return scheduledMeetings.filter(meeting => meeting.date === dateStr); + }; + + // Handle open meeting dialog + const handleOpenMeetingDialog = (type: "group" | "mission", id: string, name: string) => { + setMeetingForm({ + type, + entityId: id, + entityName: name, + date: selectedDate ? selectedDate.toISOString().split('T')[0] : new Date().toISOString().split('T')[0], + time: "", + title: "", + }); + setShowMeetingDialog(true); + }; + + // Handle save meeting + const handleSaveMeeting = () => { + if (!meetingForm.type || !meetingForm.entityId || !meetingForm.date || !meetingForm.time) { + toast({ + title: "Erreur", + description: "Veuillez remplir tous les champs requis", + variant: "destructive", + }); + return; + } + + const newMeeting: ScheduledMeeting = { + id: `${Date.now()}-${Math.random()}`, + type: meetingForm.type, + entityId: meetingForm.entityId, + entityName: meetingForm.entityName, + date: meetingForm.date, + time: meetingForm.time, + title: meetingForm.title || `${meetingForm.type === "group" ? "Groupe" : "Mission"}: ${meetingForm.entityName}`, + }; + + setScheduledMeetings([...scheduledMeetings, newMeeting]); + setShowMeetingDialog(false); + setMeetingForm({ + type: "", + entityId: "", + entityName: "", + date: "", + time: "", + title: "", + }); + toast({ + title: "Succès", + description: "Réunion planifiée avec succès", + }); + }; + + // Handle delete meeting + const handleDeleteMeeting = (meetingId: string) => { + setScheduledMeetings(scheduledMeetings.filter(m => m.id !== meetingId)); + toast({ + title: "Succès", + description: "Réunion supprimée", + }); + }; + + // Format date for display + const formatDate = (dateStr: string): string => { + const date = new Date(dateStr); + return date.toLocaleDateString('fr-FR', { weekday: 'long', day: 'numeric', month: 'long' }); + }; + // Show loading state if (status === "loading" || loading) { return ( @@ -165,12 +298,14 @@ export default function VisionPage() { } // Show list of groups and missions + const todayMeetings = getTodayMeetings(); + return ( -
-
+
+
{/* Header */} -
+

Espaces de réunion

@@ -179,6 +314,150 @@ export default function VisionPage() {

+ {/* Today's Meetings Section */} + {todayMeetings.length > 0 && ( +
+
+
+ +

+ Réunions du jour ({todayMeetings.length}) +

+
+
+
+ {todayMeetings.map((meeting) => ( +
+
+
+ +
+
+

+ {meeting.title || `${meeting.type === "group" ? "Groupe" : "Mission"}: ${meeting.entityName}`} +

+

+ {meeting.time} - {formatDate(meeting.date)} +

+
+
+
+ + +
+
+ ))} +
+
+ )} + + {/* Calendar Section */} +
+
+
+
+ +

+ Calendrier des réunions +

+
+ +
+ + {showCalendar && ( +
+
+ { + if (!date) return false; + return getMeetingsForDate(date).length > 0; + }, + }} + modifiersClassNames={{ + hasMeeting: "bg-blue-100 text-blue-900 font-semibold", + }} + /> +
+
+ {selectedDate && ( +
+

+ Réunions du {selectedDate.toLocaleDateString('fr-FR', { weekday: 'long', day: 'numeric', month: 'long' })} +

+ {getMeetingsForDate(selectedDate).length === 0 ? ( +

Aucune réunion planifiée

+ ) : ( +
+ {getMeetingsForDate(selectedDate).map((meeting) => ( +
+
+

+ {meeting.title || `${meeting.type === "group" ? "Groupe" : "Mission"}: ${meeting.entityName}`} +

+

{meeting.time}

+
+
+ + +
+
+ ))} +
+ )} +
+ )} +
+
+ )} +
+
+ {/* Groups Section */}
@@ -215,18 +494,32 @@ export default function VisionPage() {

- +
+ + +
))} @@ -280,18 +573,32 @@ export default function VisionPage() {
- +
+ + +
))} @@ -300,6 +607,78 @@ export default function VisionPage() { + + {/* Meeting Dialog */} + + + + Planifier une réunion + +
+
+ + setMeetingForm({ ...meetingForm, title: e.target.value })} + placeholder={`Réunion ${meetingForm.type === "group" ? "du groupe" : "de la mission"}`} + className="mt-1" + /> +
+
+ + setMeetingForm({ ...meetingForm, date: e.target.value })} + className="mt-1" + required + /> +
+
+ + setMeetingForm({ ...meetingForm, time: e.target.value })} + className="mt-1" + required + /> +
+
+

+ {meetingForm.type === "group" ? "Groupe" : "Mission"}: {meetingForm.entityName} +

+
+
+ + + + +
+
); }