From b9630421a6db614510dc9037cba8f220ca4bf14b Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Nov 2025 14:30:33 +0000 Subject: [PATCH] =?UTF-8?q?Feature:=20Am=C3=A9lioration=20de=20l'interface?= =?UTF-8?q?=20avec=20date/heure=20et=20alertes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modifications majeures de l'interface : - Ajout de la date et l'heure en temps réel dans le header - Alerte rouge dans le header 30 minutes avant un rendez-vous - Réorganisation du layout en 3 colonnes : * Calendrier à gauche (300px, sticky) * Notes au milieu (responsive) * Todo et RSS à droite (380px, sticky) - Badge rouge "Dans moins de 30 min" sur les événements proches - Amélioration de la compacité des cartes de notes - Synchronisation optimisée de l'affichage du calendrier --- src/pages/Index.tsx | 247 +++++++++++++++++++++++++++++--------------- 1 file changed, 162 insertions(+), 85 deletions(-) diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 1de355b..c7e2a39 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -54,6 +54,8 @@ const Index = () => { const [noteTags, setNoteTags] = useState([]); const [openRouterModels, setOpenRouterModels] = useState([]); const [loadingModels, setLoadingModels] = useState(false); + const [currentDateTime, setCurrentDateTime] = useState(new Date()); + const [upcomingAlert, setUpcomingAlert] = useState(null); const [calendarAuthStatus, setCalendarAuthStatus] = useState<{ isAuthenticated: boolean; isExpired: boolean; @@ -79,6 +81,33 @@ const Index = () => { // Debounce timer for auto-save const saveTimerRef = useRef(null); + // Update current date/time every second + useEffect(() => { + const timer = setInterval(() => { + setCurrentDateTime(new Date()); + }, 1000); + return () => clearInterval(timer); + }, []); + + // Check for upcoming events every minute + useEffect(() => { + const checkUpcomingEvents = () => { + const now = new Date(); + const thirtyMinutesFromNow = new Date(now.getTime() + 30 * 60 * 1000); + + const upcomingEvent = calendarEvents.find(event => { + const eventStart = new Date(event.start_time); + return eventStart > now && eventStart <= thirtyMinutesFromNow; + }); + + setUpcomingAlert(upcomingEvent || null); + }; + + checkUpcomingEvents(); + const timer = setInterval(checkUpcomingEvents, 60000); // Check every minute + return () => clearInterval(timer); + }, [calendarEvents]); + useEffect(() => { const userFromAuth = AuthService.getUser(); if (userFromAuth) { @@ -565,13 +594,55 @@ const Index = () => {
{/* Top Navigation */}
+ {/* Alert bar for upcoming events */} + {upcomingAlert && ( +
+
+ + + Rendez-vous dans moins de 30 minutes : {upcomingAlert.title} + + + à {new Date(upcomingAlert.start_time).toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })} + +
+ +
+ )} +
-
-
- +
+
+
+ +
+ NoteFlow +
+
+
+ {currentDateTime.toLocaleDateString('fr-FR', { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric' + })} +
+
+ {currentDateTime.toLocaleTimeString('fr-FR', { + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + })} +
- NoteFlow
@@ -616,9 +687,84 @@ const Index = () => { {/* Main Content */}
- {/* Two Column Layout: Notes Left | Boxes Right */} -
- {/* Left Column: Notes or Open Note */} + {/* Three Column Layout: Calendar Left | Notes Middle | Todo/RSS Right */} +
+ {/* Left Column: Calendar */} +
+ + +
+ + + Rendez-vous + + +
+
+ +
+ {calendarEvents.length > 0 ? ( + calendarEvents.map(event => { + const startDate = new Date(event.start_time); + const endDate = new Date(event.end_time); + const isToday = startDate.toDateString() === new Date().toDateString(); + const isSoon = startDate.getTime() - new Date().getTime() < 30 * 60 * 1000 && startDate > new Date(); + + return ( +
event.html_link && window.open(event.html_link, '_blank')} + > +
+
+

{event.title}

+

+ {isToday ? "Aujourd'hui" : startDate.toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit' })} à {startDate.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })} +

+ {event.location && ( +

+ 📍 {event.location} +

+ )} + {isSoon && ( + Dans moins de 30 min + )} +
+ +
+
+ ); + }) + ) : ( +

+ Aucun rendez-vous à venir +
+ +

+ )} +
+
+
+
+ + {/* Middle Column: Notes or Open Note */}
{!openNote ? ( <> @@ -654,23 +800,23 @@ const Index = () => {
- {/* Notes Grid - 2 columns */} -
+ {/* Notes Grid - 1 column for better visibility */} +
{filteredNotes.length > 0 ? ( filteredNotes.map(note => ( handleOpenNote(note)} > - -

+ +

{note.title || "Sans titre"}

-

+

{note.content ? note.content.replace(/<[^>]*>/g, '') : "Note vide"}

-
+
{note.todos && note.todos.length > 0 && ( @@ -703,7 +849,7 @@ const Index = () => { )) ) : ( -
+

{searchQuery ? "Aucune note trouvée" : "Aucune note"} @@ -1029,7 +1175,7 @@ const Index = () => {

{/* Right Column: Todos & RSS Boxes stacked */} -
+
{/* Todos Box */} @@ -1171,75 +1317,6 @@ const Index = () => { - {/* Calendar Box */} - - -
- - - Rendez-vous - - -
-
- -
- {calendarEvents.length > 0 ? ( - calendarEvents.map(event => { - const startDate = new Date(event.start_time); - const endDate = new Date(event.end_time); - const isToday = startDate.toDateString() === new Date().toDateString(); - - return ( -
event.html_link && window.open(event.html_link, '_blank')} - > -
-
-

{event.title}

-

- {isToday ? "Aujourd'hui" : startDate.toLocaleDateString('fr-FR')} à {startDate.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })} -

- {event.location && ( -

- 📍 {event.location} -

- )} -
- -
-
- ); - }) - ) : ( -

- Aucun rendez-vous à venir -
- -

- )} -
-
-