From a89546c54e21b6de40c6a79db8bd7507cda799d1 Mon Sep 17 00:00:00 2001 From: Nathan Lamy Date: Tue, 19 Aug 2025 19:32:03 +0200 Subject: [PATCH] feat: add last sync and health --- app/components/home/index.tsx | 235 ++++++++++++++++++--------------- app/components/sync-status.tsx | 31 +++-- app/layout.tsx | 8 +- app/lib/api.ts | 8 +- app/routes/colles.tsx | 6 - app/routes/home.tsx | 14 +- app/routes/settings.tsx | 14 +- 7 files changed, 170 insertions(+), 146 deletions(-) diff --git a/app/components/home/index.tsx b/app/components/home/index.tsx index b5a014b..69dd8c1 100644 --- a/app/components/home/index.tsx +++ b/app/components/home/index.tsx @@ -24,6 +24,9 @@ import Error from "~/components/error"; import { useSearchParams } from "react-router"; import { useColles, type User } from "~/lib/api"; import TabContent from "~/components/home/tab-content"; +import { MainLayout } from "~/layout"; +import { forceReload } from "~/lib/utils"; +import { SyncButton } from "../sync-status"; export default function Home({ user }: { user: User }) { // Handle query parameters @@ -62,8 +65,15 @@ export default function Home({ user }: { user: User }) { }; // Fetch colles from API - const { studentColles, classColles, favoriteColles, error, isLoading } = - useColles(startDate); + const { + studentColles, + classColles, + favoriteColles, + healthyUntil, + lastSync, + error, + isLoading, + } = useColles(startDate); // Error handling (after all hooks) if (error) @@ -143,106 +153,116 @@ export default function Home({ user }: { user: User }) { }; return ( -
- {/* Tabs */} - - - - - Vous - - {/* + +

+ Khollisé - {user.className} ⚔️ +

+ + + } + > +
+ {/* Tabs */} + + + + + Vous + + {/* Favoris */} - - - Classe - - - + + + Classe + + + - {/* Week Navigation */} -
-
- -
- + {/* Week Navigation */} +
+
+ +
+ +
+
-
+ + {/* Filter component */} +
+ + + + +
-
- {/* Filter component */} -
- + {/* Your Colles Tab */} + {activeTab === "you" && ( + + )} - - - -
- - {/* Your Colles Tab */} - {activeTab === "you" && ( - - )} - - {/* Favorites Tab + {/* Favorites Tab {activeTab === "favorites" && ( )} */} - {/* Class Colles Tab */} - {activeTab === "class" && ( - - )} + {/* Class Colles Tab */} + {activeTab === "class" && ( + + )} - {/* Bottom Navigation for Mobile */} - -
+ {/* Bottom Navigation for Mobile */} + +
+ ); } diff --git a/app/components/sync-status.tsx b/app/components/sync-status.tsx index ccb15c3..12b20e9 100644 --- a/app/components/sync-status.tsx +++ b/app/components/sync-status.tsx @@ -8,10 +8,18 @@ import { import { Cloud, CloudOff, Wifi, WifiOff } from "lucide-react"; import { cn } from "~/lib/utils"; -export function SyncButton() { - const [isSync, setIsSync] = useState(true); +export function SyncButton({ + healthyUntil, + lastSync, +}: { + healthyUntil: Date; + lastSync: Date; +}) { + const healthyUntilDate = new Date(healthyUntil) || new Date(0); + const lastSyncDate = new Date(lastSync) || new Date(0); + // Determine if the sync is healthy based on the healthyUntil date + const isSync = healthyUntilDate > new Date(); const [isOpen, setIsOpen] = useState(false); - const lastSync = new Date(); // TODO: Replace with actual last sync date const getIcon = () => { if (isSync) return ; @@ -28,11 +36,12 @@ export function SyncButton() { const now = new Date(); const diff = now.getTime() - date.getTime(); + const seconds = Math.floor(diff / 1000); const minutes = Math.floor(diff / 60000); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); - if (minutes < 1) return "A l'instant"; + if (minutes < 1) return `il y a ${seconds}s`; if (minutes < 60) return `il y a ${minutes}m`; if (hours < 24) return `il y a ${hours}h`; return `il y a ${days}j`; @@ -61,26 +70,26 @@ export function SyncButton() { ) : ( )} - - Status - + Status
- {isSync ? "Connecté" : "Erreur"} + {isSync ? "Connecté" : "Hors ligne"}
- Dernière mis à jour : - {formatLastSync(lastSync)} + + Dernière mis à jour : + + {formatLastSync(lastSyncDate)}
{/* TODO: diff --git a/app/layout.tsx b/app/layout.tsx index 0145bcc..6f1243d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -51,18 +51,18 @@ export function AuthLayout({ export function MainLayout({ children, - page + header }: { children: React.ReactNode; - page: React.ReactNode; + header: React.ReactNode; }) { return (
- {children} + {header}
- {page} + {children}
); } diff --git a/app/lib/api.ts b/app/lib/api.ts index f01fbc2..5631b68 100644 --- a/app/lib/api.ts +++ b/app/lib/api.ts @@ -189,6 +189,8 @@ interface CollePayload { classColles: Colle[]; studentColles: Colle[]; favoriteColles: Colle[]; + healthyUntil: Date; + lastSync: Date; } export const useColles = (startDate: DateTime) => { @@ -206,7 +208,9 @@ export const useColles = (startDate: DateTime) => { gcTime: 0, } : { - staleTime: 0, + staleTime: Duration.fromObject({ + hours: 1, // 1 hour + }).toMillis(), gcTime: Duration.fromObject({ days: 3, // 3 days }).toMillis(), @@ -222,6 +226,8 @@ export const useColles = (startDate: DateTime) => { classColles: [], studentColles: [], favoriteColles: [], + healthyUntil: new Date(0), + lastSync: new Date(0), }, data || {} ) as CollePayload; diff --git a/app/routes/colles.tsx b/app/routes/colles.tsx index 7b77c48..fe1c804 100644 --- a/app/routes/colles.tsx +++ b/app/routes/colles.tsx @@ -16,13 +16,11 @@ import { ChevronUp, ChevronDown, MapPinHouse, - Users, RefreshCw, Share2, ExternalLink, } from "lucide-react"; import { Separator } from "~/components/ui/separator"; -import UserDropdown from "~/components/user-dropdown"; import ColleDetailsSkeleton from "~/components/details/skeleton-details"; import AttachmentItem from "~/components/details/attachment"; import Error from "~/components/error"; @@ -134,9 +132,6 @@ export default function ColleDetailPage() { Retour -
- -
-
diff --git a/app/routes/home.tsx b/app/routes/home.tsx index ef89e05..ab082d8 100644 --- a/app/routes/home.tsx +++ b/app/routes/home.tsx @@ -2,14 +2,11 @@ import { Navigate } from "react-router"; import Error from "~/components/error"; import HomePage from "~/components/home"; import Loader from "~/components/loader"; -import { SyncButton } from "~/components/sync-status"; -import { MainLayout } from "~/layout"; import { AUTH_ERROR, useUser } from "~/lib/api"; -import { forceReload } from "~/lib/utils"; export default function Home() { const { user, isLoading, error } = useUser(); - + if (isLoading) { return ; } @@ -20,12 +17,5 @@ export default function Home() { return ; } - return ( - }> -

- Khollisé - {user.className} ⚔️ -

- -
- ); + return ; } diff --git a/app/routes/settings.tsx b/app/routes/settings.tsx index 4024041..558de36 100644 --- a/app/routes/settings.tsx +++ b/app/routes/settings.tsx @@ -8,7 +8,7 @@ import { forceReload } from "~/lib/utils"; export default function Home() { const { user, isLoading, error } = useUser(); - + if (isLoading) { return ; } @@ -20,10 +20,14 @@ export default function Home() { } return ( - }> -

- Khollisé - {user.className} ⚔️ -

+ + Khollisé - {user.className} ⚔️ + + } + > + ); }