diff --git a/src/admin/AdminNav.tsx b/src/admin/AdminNav.tsx index ecc00562..2185390f 100644 --- a/src/admin/AdminNav.tsx +++ b/src/admin/AdminNav.tsx @@ -16,7 +16,7 @@ export default async function AdminNav() { countPhotos, countUploads, countTags, - mostRecentUpdate, + mostRecentPhotoUpdateTime, ] = await Promise.all([ getPhotosCountIncludingHiddenCached().catch(() => 0), getStorageUploadUrlsNoStore() @@ -53,6 +53,6 @@ export default async function AdminNav() { if (countTags > 0) { items.push(navItemTags); } return ( - + ); } diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 58348a5e..69709277 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -12,31 +12,43 @@ import { clsx } from 'clsx/lite'; import { differenceInMinutes } from 'date-fns'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { BiCog } from 'react-icons/bi'; import { FaRegClock } from 'react-icons/fa'; -const RECENCY_THRESHOLD = 5; +const areTimesRecent = (dates: Date[]) => dates + .some(date => differenceInMinutes(new Date(), date) < 5); export default function AdminNavClient({ items, - mostRecentUpdate, + mostRecentPhotoUpdateTime, }: { items: { label: string, href: string, count: number, }[] - mostRecentUpdate?: Date + mostRecentPhotoUpdateTime?: Date }) { const pathname = usePathname(); - const { adminUpdates = [] } = useAppState(); + const { adminUpdateTimes = [] } = useAppState(); - const shouldShowBanner = useMemo(() => - ((mostRecentUpdate ? [mostRecentUpdate] : []).concat(adminUpdates)) - .some(date => differenceInMinutes(new Date(), date) < RECENCY_THRESHOLD) - , [mostRecentUpdate, adminUpdates]); + const updateTimes = useMemo(() => + (mostRecentPhotoUpdateTime ? [mostRecentPhotoUpdateTime] : []) + .concat(adminUpdateTimes) + , [mostRecentPhotoUpdateTime, adminUpdateTimes]); + + const [shouldShowBanner, setShouldShowBanner] = + useState(areTimesRecent(updateTimes)); + + useEffect(() => { + // Check every 10 seconds if update times are recent + const timeout = setTimeout(() => + setShouldShowBanner(areTimesRecent(updateTimes)) + , 10_000); + return () => clearTimeout(timeout); + }, [updateTimes]); return ( { revalidatePhoto?.(photo.id, true); - addAdminUpdate?.(); + registerAdminUpdate?.(); }); } }, diff --git a/src/admin/DeleteButton.tsx b/src/admin/DeleteButton.tsx index 7128c24f..7c570903 100644 --- a/src/admin/DeleteButton.tsx +++ b/src/admin/DeleteButton.tsx @@ -17,15 +17,15 @@ export default function DeleteButton ( ...rest } = props; - const { invalidateSwr, addAdminUpdate } = useAppState(); + const { invalidateSwr, registerAdminUpdate } = useAppState(); const onFormSubmit = useCallback(() => { onFormSubmitProps?.(); if (clearLocalState) { invalidateSwr?.(); - addAdminUpdate?.(); + registerAdminUpdate?.(); } - }, [onFormSubmitProps, clearLocalState, invalidateSwr, addAdminUpdate]); + }, [onFormSubmitProps, clearLocalState, invalidateSwr, registerAdminUpdate]); return > isCommandKOpen?: boolean setIsCommandKOpen?: Dispatch> - adminUpdates?: Date[] - addAdminUpdate?: () => void + adminUpdateTimes?: Date[] + registerAdminUpdate?: () => void shouldShowBaselineGrid?: boolean setShouldShowBaselineGrid?: Dispatch> clearNextPhotoAnimation?: () => void diff --git a/src/state/AppStateProvider.tsx b/src/state/AppStateProvider.tsx index becd004b..ac4ecf5b 100644 --- a/src/state/AppStateProvider.tsx +++ b/src/state/AppStateProvider.tsx @@ -26,7 +26,7 @@ export default function AppStateProvider({ useState(true); const [isCommandKOpen, setIsCommandKOpen] = useState(false); - const [adminUpdates, setAdminUpdates] = useState([]); + const [adminUpdateTimes, setAdminUpdateTimes] = useState([]); const [shouldShowBaselineGrid, setShouldShowBaselineGrid] = useState(false); @@ -35,8 +35,8 @@ export default function AppStateProvider({ const { data } = useSWR('getCurrentUser', getCurrentUser); useEffect(() => setUserEmail(data?.email ?? undefined), [data]); - const addAdminUpdate = useCallback(() => - setAdminUpdates(updates => [...updates, new Date()]) + const registerAdminUpdate = useCallback(() => + setAdminUpdateTimes(updates => [...updates, new Date()]) , []); useEffect(() => { @@ -60,8 +60,8 @@ export default function AppStateProvider({ setShouldRespondToKeyboardCommands, isCommandKOpen, setIsCommandKOpen, - adminUpdates, - addAdminUpdate, + adminUpdateTimes, + registerAdminUpdate, shouldShowBaselineGrid, setShouldShowBaselineGrid, clearNextPhotoAnimation: () => setNextPhotoAnimation?.(undefined),