From 976b51ca1b998eb387546b8e314bbc74075df3d6 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Sun, 29 Jun 2025 17:30:41 +0200 Subject: [PATCH] Update planning --- ui/src/pages/planning.tsx | 751 +++++++++++++++++++++++++++----------- 1 file changed, 539 insertions(+), 212 deletions(-) diff --git a/ui/src/pages/planning.tsx b/ui/src/pages/planning.tsx index 7299bec..6cc89fb 100644 --- a/ui/src/pages/planning.tsx +++ b/ui/src/pages/planning.tsx @@ -5,102 +5,68 @@ interface Event { title: string; date: string; time: string; + endTime?: string; type: "meeting" | "task" | "reminder"; color: string; + description?: string; } +type ViewType = "month" | "week" | "day"; + export const PlanningPage = () => { const [currentDate, setCurrentDate] = useState(new Date()); const [selectedDate, setSelectedDate] = useState(new Date()); + const [currentView, setCurrentView] = useState("month"); const [events, setEvents] = useState([ { id: 1, title: "Réunion équipe", date: "2024-01-15", time: "10:00", + endTime: "11:00", type: "meeting", color: "bg-blue-500", + description: "Discussion sur les objectifs du trimestre", }, { id: 2, title: "Présentation client", date: "2024-01-16", time: "14:30", + endTime: "16:00", type: "meeting", color: "bg-red-500", + description: "Présentation du nouveau produit", }, { id: 3, title: "Révision code", date: "2024-01-17", time: "09:00", + endTime: "10:30", type: "task", color: "bg-green-500", + description: "Code review des fonctionnalités développées", + }, + { + id: 4, + title: "Appel client", + date: "2024-01-18", + time: "15:00", + endTime: "15:30", + type: "meeting", + color: "bg-purple-500", }, ]); const [isEventModalOpen, setIsEventModalOpen] = useState(false); const [newEventTitle, setNewEventTitle] = useState(""); const [newEventTime, setNewEventTime] = useState(""); + const [newEventEndTime, setNewEventEndTime] = useState(""); const [newEventType, setNewEventType] = useState< "meeting" | "task" | "reminder" >("meeting"); - - // Get calendar days for current month - const getDaysInMonth = (date: Date) => { - const year = date.getFullYear(); - const month = date.getMonth(); - const firstDay = new Date(year, month, 1); - const lastDay = new Date(year, month + 1, 0); - const daysInMonth = lastDay.getDate(); - const startingDayOfWeek = firstDay.getDay(); - - const days = []; - - // Add empty cells for days before the first day of the month - for (let i = 0; i < startingDayOfWeek; i++) { - days.push(null); - } - - // Add all days of the month - for (let day = 1; day <= daysInMonth; day++) { - days.push(new Date(year, month, day)); - } - - return days; - }; - - const formatDate = (date: Date) => { - return date.toISOString().split("T")[0]; - }; - - const getEventsForDate = (date: Date) => { - const dateString = formatDate(date); - return events.filter((event) => event.date === dateString); - }; - - const addEvent = () => { - if (newEventTitle.trim()) { - const newEvent: Event = { - id: Math.max(...events.map((e) => e.id), 0) + 1, - title: newEventTitle.trim(), - date: formatDate(selectedDate), - time: newEventTime || "09:00", - type: newEventType, - color: - newEventType === "meeting" - ? "bg-blue-500" - : newEventType === "task" - ? "bg-green-500" - : "bg-yellow-500", - }; - setEvents([...events, newEvent]); - setIsEventModalOpen(false); - setNewEventTitle(""); - setNewEventTime(""); - setNewEventType("meeting"); - } - }; + const [newEventDescription, setNewEventDescription] = useState(""); const monthNames = [ "Janvier", @@ -117,171 +83,493 @@ export const PlanningPage = () => { "Décembre", ]; - const dayNames = ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"]; + const dayNames = [ + "Dimanche", + "Lundi", + "Mardi", + "Mercredi", + "Jeudi", + "Vendredi", + "Samedi", + ]; + const dayNamesShort = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"]; - const navigateMonth = (direction: number) => { - setCurrentDate( - new Date(currentDate.getFullYear(), currentDate.getMonth() + direction, 1) - ); + const formatDate = (date: Date) => { + // Use local timezone instead of UTC to avoid timezone issues + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const day = date.getDate().toString().padStart(2, "0"); + return `${year}-${month}-${day}`; }; - return ( -
-
-
-

- Planning -

- -
+ {day} +
+ ))} +
-
- {/* Calendar */} -
- {/* Calendar Header */} -
-

- {monthNames[currentDate.getMonth()]} {currentDate.getFullYear()} -

-
- - + {day.getDate()} +
+
+ {getEventsForDate(day) + .slice(0, 3) + .map((event) => ( +
+ {event.title} +
+ ))} + {getEventsForDate(day).length > 3 && ( +
+ +{getEventsForDate(day).length - 3} autres +
+ )} +
-
+ )} +
+ ))} + + + ); - {/* Calendar Grid */} -
- {dayNames.map((day) => ( + const renderWeekView = () => ( +
+ {/* Week header */} +
+
+ {getWeekDays().map((day, index) => ( +
+
+ {dayNamesShort[day.getDay() === 0 ? 6 : day.getDay() - 1]} +
+
+ {day.getDate()} +
+
+ ))} +
+ + {/* Time slots */} +
+ {timeSlots.map((time) => ( +
+
+ {time} +
+ {getWeekDays().map((day, index) => ( +
{ + setSelectedDate(day); + setNewEventTime(time); + setIsEventModalOpen(true); + }} + > + {getEventsForDate(day) + .filter((event) => event.time.startsWith(time.split(":")[0])) + .map((event) => ( +
+
{event.title}
+
+ {event.time} - {event.endTime} +
+
+ ))} +
+ ))} +
+ ))} +
+
+ ); + + const renderDayView = () => ( +
+ {/* Day header */} +
+
+ {dayNames[currentDate.getDay()]} +
+
+ {currentDate.getDate()} +
+
+ + {/* Time slots */} +
+ {timeSlots.map((time) => ( +
{ + setNewEventTime(time); + setIsEventModalOpen(true); + }} + > +
+ {time} +
+
+ {getEventsForDate(currentDate) + .filter((event) => event.time.startsWith(time.split(":")[0])) + .map((event) => ( +
+
{event.title}
+
+ {event.time} - {event.endTime} +
+ {event.description && ( +
+ {event.description} +
+ )} +
+ ))} +
+
+ ))} +
+
+ ); + + return ( +
+
+ {/* Sidebar */} +
+
+ +
+ + {/* Mini Calendar */} +
+
+ {monthNames[currentDate.getMonth()]} {currentDate.getFullYear()} +
+
+ {dayNamesShort.map((day) => (
- {day} + {day.slice(0, 1)}
))} -
- -
{getDaysInMonth(currentDate).map((day, index) => (
day && setSelectedDate(day)} + onClick={() => { + if (day) { + setSelectedDate(day); + setIsEventModalOpen(true); + } + }} > - {day && ( - <> -
- {day.getDate()} -
-
- {getEventsForDate(day) - .slice(0, 3) - .map((event) => ( -
- {event.time} {event.title} -
- ))} - {getEventsForDate(day).length > 3 && ( -
- +{getEventsForDate(day).length - 3} autres -
- )} -
- - )} + {day ? day.getDate() : ""}
))}
+
- {/* Selected Date Events */} -
-

- Événements du{" "} - {selectedDate.toLocaleDateString("fr-FR", { - weekday: "long", - year: "numeric", - month: "long", - day: "numeric", - })} -

-
- {getEventsForDate(selectedDate).length > 0 ? ( - getEventsForDate(selectedDate).map((event) => ( -
+ {/* Header */} +
+
+
+

+ Planning +

+ +
+
- )) - ) : ( -

- Aucun événement prévu pour cette date -

- )} + + + + + +
+

+ {getViewTitle()} +

+
+ +
+
+ {(["month", "week", "day"] as ViewType[]).map((view) => ( + + ))} +
+
+ + {/* Calendar Views */} +
+ {currentView === "month" && renderMonthView()} + {currentView === "week" && renderWeekView()} + {currentView === "day" && renderDayView()} +
@@ -289,35 +577,48 @@ export const PlanningPage = () => { {isEventModalOpen && (
-

+

Nouvel événement

setNewEventTitle(e.target.value)} className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white" - placeholder="Titre de l'événement" + placeholder="Ajouter un titre" autoFocus />
-
- - setNewEventTime(e.target.value)} - className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white" - /> +
+
+ + setNewEventTime(e.target.value)} + className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white" + /> +
+
+ + setNewEventEndTime(e.target.value)} + className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white" + /> +
@@ -339,26 +640,52 @@ export const PlanningPage = () => {
-
- Date: {selectedDate.toLocaleDateString("fr-FR")} +
+ +