From 477d7c088e1577b7a73c1a660f0b1c68b4f22f8d Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 25 Mar 2025 10:08:48 -0500 Subject: [PATCH] Refine admin photo menu placement/appearance --- src/admin/AdminPhotoMenu.tsx | 139 ++++++++++++++++++++++++++--- src/admin/AdminPhotoMenuClient.tsx | 131 --------------------------- src/components/more/MoreMenu.tsx | 5 +- src/photo/PhotoLarge.tsx | 29 +++--- 4 files changed, 150 insertions(+), 154 deletions(-) delete mode 100644 src/admin/AdminPhotoMenuClient.tsx diff --git a/src/admin/AdminPhotoMenu.tsx b/src/admin/AdminPhotoMenu.tsx index 441520ab..7ce6a06b 100644 --- a/src/admin/AdminPhotoMenu.tsx +++ b/src/admin/AdminPhotoMenu.tsx @@ -1,12 +1,131 @@ -import { authCachedSafe } from '@/auth/cache'; -import AdminPhotoMenuClient from './AdminPhotoMenuClient'; -import { ComponentProps } from 'react'; +'use client'; -export default async function AdminPhotoMenu( - props: ComponentProps, -) { - const session = await authCachedSafe(); - return Boolean(session?.user?.email) - ? - : null; +import { ComponentProps, useMemo } from 'react'; +import { pathForAdminPhotoEdit, pathForPhoto } from '@/app/paths'; +import { + deletePhotoAction, + syncPhotoAction, + toggleFavoritePhotoAction, +} from '@/photo/actions'; +import { + Photo, + deleteConfirmationTextForPhoto, + downloadFileNameForPhoto, +} from '@/photo'; +import { isPathFavs, isPhotoFav } from '@/tag'; +import { usePathname } from 'next/navigation'; +import { BiTrash } from 'react-icons/bi'; +import MoreMenu from '@/components/more/MoreMenu'; +import { useAppState } from '@/state/AppState'; +import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll'; +import { MdOutlineFileDownload } from 'react-icons/md'; +import MoreMenuItem from '@/components/more/MoreMenuItem'; +import IconGrSync from '@/components/icons/IconGrSync'; +import { isPhotoOutdated } from '@/photo/outdated'; +import InsightsIndicatorDot from './insights/InsightsIndicatorDot'; +import IconFavs from '@/components/icons/IconFavs'; +import IconEdit from '@/components/icons/IconEdit'; + +export default function AdminPhotoMenu({ + photo, + revalidatePhoto, + includeFavorite = true, + ...props +}: Omit, 'items'> & { + photo: Photo + revalidatePhoto?: RevalidatePhoto + includeFavorite?: boolean +}) { + const { isUserSignedIn, registerAdminUpdate } = useAppState(); + + const isFav = isPhotoFav(photo); + const path = usePathname(); + const shouldRedirectFav = isPathFavs(path) && isFav; + const shouldRedirectDelete = pathForPhoto({ photo: photo.id }) === path; + + const items = useMemo(() => { + const items: ComponentProps[] = [{ + label: 'Edit', + icon: , + href: pathForAdminPhotoEdit(photo.id), + }]; + if (includeFavorite) { + items.push({ + label: isFav ? 'Unfavorite' : 'Favorite', + icon: , + action: () => toggleFavoritePhotoAction( + photo.id, + shouldRedirectFav, + ).then(() => revalidatePhoto?.(photo.id)), + }); + } + items.push({ + label: 'Download', + icon: , + href: photo.url, + hrefDownloadName: downloadFileNameForPhoto(photo), + }); + items.push({ + label: 'Sync', + labelComplex: + Sync + {isPhotoOutdated(photo) && + } + , + icon: , + action: () => syncPhotoAction(photo.id) + .then(() => revalidatePhoto?.(photo.id)), + }); + items.push({ + label: 'Delete', + icon: , + className: 'text-error *:hover:text-error', + action: () => { + if (confirm(deleteConfirmationTextForPhoto(photo))) { + return deletePhotoAction( + photo.id, + photo.url, + shouldRedirectDelete, + ).then(() => { + revalidatePhoto?.(photo.id, true); + registerAdminUpdate?.(); + }); + } + }, + }); + return items; + }, [ + photo, + includeFavorite, + isFav, + shouldRedirectFav, + revalidatePhoto, + shouldRedirectDelete, + registerAdminUpdate, + ]); + + return ( + isUserSignedIn + ? + : null + ); } diff --git a/src/admin/AdminPhotoMenuClient.tsx b/src/admin/AdminPhotoMenuClient.tsx deleted file mode 100644 index 8e85d036..00000000 --- a/src/admin/AdminPhotoMenuClient.tsx +++ /dev/null @@ -1,131 +0,0 @@ -'use client'; - -import { ComponentProps, useMemo } from 'react'; -import { pathForAdminPhotoEdit, pathForPhoto } from '@/app/paths'; -import { - deletePhotoAction, - syncPhotoAction, - toggleFavoritePhotoAction, -} from '@/photo/actions'; -import { - Photo, - deleteConfirmationTextForPhoto, - downloadFileNameForPhoto, -} from '@/photo'; -import { isPathFavs, isPhotoFav } from '@/tag'; -import { usePathname } from 'next/navigation'; -import { BiTrash } from 'react-icons/bi'; -import MoreMenu from '@/components/more/MoreMenu'; -import { useAppState } from '@/state/AppState'; -import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll'; -import { MdOutlineFileDownload } from 'react-icons/md'; -import MoreMenuItem from '@/components/more/MoreMenuItem'; -import IconGrSync from '@/components/icons/IconGrSync'; -import { isPhotoOutdated } from '@/photo/outdated'; -import InsightsIndicatorDot from './insights/InsightsIndicatorDot'; -import IconFavs from '@/components/icons/IconFavs'; -import IconEdit from '@/components/icons/IconEdit'; - -export default function AdminPhotoMenuClient({ - photo, - revalidatePhoto, - includeFavorite = true, - ...props -}: Omit, 'items'> & { - photo: Photo - revalidatePhoto?: RevalidatePhoto - includeFavorite?: boolean -}) { - const { isUserSignedIn, registerAdminUpdate } = useAppState(); - - const isFav = isPhotoFav(photo); - const path = usePathname(); - const shouldRedirectFav = isPathFavs(path) && isFav; - const shouldRedirectDelete = pathForPhoto({ photo: photo.id }) === path; - - const items = useMemo(() => { - const items: ComponentProps[] = [{ - label: 'Edit', - icon: , - href: pathForAdminPhotoEdit(photo.id), - }]; - if (includeFavorite) { - items.push({ - label: isFav ? 'Unfavorite' : 'Favorite', - icon: , - action: () => toggleFavoritePhotoAction( - photo.id, - shouldRedirectFav, - ).then(() => revalidatePhoto?.(photo.id)), - }); - } - items.push({ - label: 'Download', - icon: , - href: photo.url, - hrefDownloadName: downloadFileNameForPhoto(photo), - }); - items.push({ - label: 'Sync', - labelComplex: - Sync - {isPhotoOutdated(photo) && - } - , - icon: , - action: () => syncPhotoAction(photo.id) - .then(() => revalidatePhoto?.(photo.id)), - }); - items.push({ - label: 'Delete', - icon: , - className: 'text-error *:hover:text-error', - action: () => { - if (confirm(deleteConfirmationTextForPhoto(photo))) { - return deletePhotoAction( - photo.id, - photo.url, - shouldRedirectDelete, - ).then(() => { - revalidatePhoto?.(photo.id, true); - registerAdminUpdate?.(); - }); - } - }, - }); - return items; - }, [ - photo, - includeFavorite, - isFav, - shouldRedirectFav, - revalidatePhoto, - shouldRedirectDelete, - registerAdminUpdate, - ]); - - return ( - isUserSignedIn - ? - : null - ); -} diff --git a/src/components/more/MoreMenu.tsx b/src/components/more/MoreMenu.tsx index e921e844..99978bae 100644 --- a/src/components/more/MoreMenu.tsx +++ b/src/components/more/MoreMenu.tsx @@ -46,10 +46,11 @@ export default function MoreMenu({