Add hide/unhide to admin photo menu
This commit is contained in:
parent
489f48523b
commit
b6d5f2ebb2
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -56,6 +56,7 @@
|
|||||||
"trpc",
|
"trpc",
|
||||||
"Turbopack",
|
"Turbopack",
|
||||||
"Unfavoriting",
|
"Unfavoriting",
|
||||||
|
"Unhiding",
|
||||||
"unnest",
|
"unnest",
|
||||||
"upstash",
|
"upstash",
|
||||||
"UsKSGcbt",
|
"UsKSGcbt",
|
||||||
|
|||||||
@ -1,18 +1,24 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ComponentProps, useMemo } from 'react';
|
import { ComponentProps, useMemo } from 'react';
|
||||||
import { pathForAdminPhotoEdit, pathForPhoto } from '@/app/paths';
|
import {
|
||||||
|
getPathComponents,
|
||||||
|
PATH_ROOT,
|
||||||
|
pathForAdminPhotoEdit,
|
||||||
|
pathForTag,
|
||||||
|
} from '@/app/paths';
|
||||||
import {
|
import {
|
||||||
deletePhotoAction,
|
deletePhotoAction,
|
||||||
syncPhotoAction,
|
syncPhotoAction,
|
||||||
toggleFavoritePhotoAction,
|
toggleFavoritePhotoAction,
|
||||||
|
toggleHidePhotoAction,
|
||||||
} from '@/photo/actions';
|
} from '@/photo/actions';
|
||||||
import {
|
import {
|
||||||
Photo,
|
Photo,
|
||||||
deleteConfirmationTextForPhoto,
|
deleteConfirmationTextForPhoto,
|
||||||
downloadFileNameForPhoto,
|
downloadFileNameForPhoto,
|
||||||
} from '@/photo';
|
} from '@/photo';
|
||||||
import { isPathFavs, isPhotoFav } from '@/tag';
|
import { isPathFavs, isPhotoFav, TAG_HIDDEN } from '@/tag';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { BiTrash } from 'react-icons/bi';
|
import { BiTrash } from 'react-icons/bi';
|
||||||
import MoreMenu from '@/components/more/MoreMenu';
|
import MoreMenu from '@/components/more/MoreMenu';
|
||||||
@ -27,6 +33,7 @@ import IconEdit from '@/components/icons/IconEdit';
|
|||||||
import { photoNeedsToBeSynced } from '@/photo/sync';
|
import { photoNeedsToBeSynced } from '@/photo/sync';
|
||||||
import { KEY_COMMANDS } from '@/photo/key-commands';
|
import { KEY_COMMANDS } from '@/photo/key-commands';
|
||||||
import { useAppText } from '@/i18n/state/client';
|
import { useAppText } from '@/i18n/state/client';
|
||||||
|
import IconHidden from '@/components/icons/IconHidden';
|
||||||
|
|
||||||
export default function AdminPhotoMenu({
|
export default function AdminPhotoMenu({
|
||||||
photo,
|
photo,
|
||||||
@ -44,10 +51,18 @@ export default function AdminPhotoMenu({
|
|||||||
|
|
||||||
const appText = useAppText();
|
const appText = useAppText();
|
||||||
|
|
||||||
const isFav = isPhotoFav(photo);
|
|
||||||
const path = usePathname();
|
const path = usePathname();
|
||||||
|
const pathComponents = getPathComponents(path);
|
||||||
|
const isOnPhotoDetail = pathComponents.photoId === photo.id;
|
||||||
|
const isFav = isPhotoFav(photo);
|
||||||
const shouldRedirectFav = isPathFavs(path) && isFav;
|
const shouldRedirectFav = isPathFavs(path) && isFav;
|
||||||
const shouldRedirectDelete = pathForPhoto({ photo: photo.id }) === path;
|
const shouldRedirectDelete = isOnPhotoDetail;
|
||||||
|
const redirectPathOnHideToggle = isOnPhotoDetail
|
||||||
|
? photo.hidden
|
||||||
|
? pathForTag(TAG_HIDDEN)
|
||||||
|
: PATH_ROOT
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
|
||||||
const sectionMain = useMemo(() => {
|
const sectionMain = useMemo(() => {
|
||||||
const items: ComponentProps<typeof MoreMenuItem>[] = [{
|
const items: ComponentProps<typeof MoreMenuItem>[] = [{
|
||||||
@ -78,6 +93,22 @@ export default function AdminPhotoMenu({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
items.push({
|
||||||
|
label: photo.hidden ? appText.admin.unhide : appText.admin.hide,
|
||||||
|
icon: <IconHidden
|
||||||
|
size={16}
|
||||||
|
className="translate-x-[-1px] translate-y-[1px]"
|
||||||
|
visible={photo.hidden}
|
||||||
|
/>,
|
||||||
|
action: () => toggleHidePhotoAction(
|
||||||
|
photo.id,
|
||||||
|
redirectPathOnHideToggle,
|
||||||
|
)
|
||||||
|
.then(() => revalidatePhoto?.(photo.id)),
|
||||||
|
...showKeyCommands && {
|
||||||
|
keyCommand: KEY_COMMANDS.toggleHide,
|
||||||
|
},
|
||||||
|
});
|
||||||
items.push({
|
items.push({
|
||||||
label: appText.admin.download,
|
label: appText.admin.download,
|
||||||
icon: <MdOutlineFileDownload
|
icon: <MdOutlineFileDownload
|
||||||
@ -115,6 +146,7 @@ export default function AdminPhotoMenu({
|
|||||||
includeFavorite,
|
includeFavorite,
|
||||||
isFav,
|
isFav,
|
||||||
shouldRedirectFav,
|
shouldRedirectFav,
|
||||||
|
redirectPathOnHideToggle,
|
||||||
revalidatePhoto,
|
revalidatePhoto,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -87,6 +87,8 @@ const TEXT = {
|
|||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
favorite: 'Favorite',
|
favorite: 'Favorite',
|
||||||
unfavorite: 'Unfavorite',
|
unfavorite: 'Unfavorite',
|
||||||
|
hide: 'Hide',
|
||||||
|
unhide: 'Unhide',
|
||||||
download: 'Download',
|
download: 'Download',
|
||||||
sync: 'Sync',
|
sync: 'Sync',
|
||||||
delete: 'Delete',
|
delete: 'Delete',
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import {
|
|||||||
deletePhotoAction,
|
deletePhotoAction,
|
||||||
syncPhotoAction,
|
syncPhotoAction,
|
||||||
toggleFavoritePhotoAction,
|
toggleFavoritePhotoAction,
|
||||||
|
toggleHidePhotoAction,
|
||||||
} from './actions';
|
} from './actions';
|
||||||
import { isPhotoFav } from '@/tag';
|
import { isPhotoFav } from '@/tag';
|
||||||
import Tooltip from '@/components/Tooltip';
|
import Tooltip from '@/components/Tooltip';
|
||||||
@ -66,6 +67,10 @@ export default function PhotoPrevNextActions({
|
|||||||
if (photo?.id) { return toggleFavoritePhotoAction(photo.id); }
|
if (photo?.id) { return toggleFavoritePhotoAction(photo.id); }
|
||||||
}, [photo?.id]);
|
}, [photo?.id]);
|
||||||
|
|
||||||
|
const toggleHidden = useCallback(() => {
|
||||||
|
if (photo?.id) { return toggleHidePhotoAction(photo.id); }
|
||||||
|
}, [photo?.id]);
|
||||||
|
|
||||||
const navigateToPhotoEdit = useNavigateOrRunActionWithToast({
|
const navigateToPhotoEdit = useNavigateOrRunActionWithToast({
|
||||||
pathOrAction: photo ? pathForAdminPhotoEdit(photo) : undefined,
|
pathOrAction: photo ? pathForAdminPhotoEdit(photo) : undefined,
|
||||||
toastMessage: `Editing ${photoTitle} ...`,
|
toastMessage: `Editing ${photoTitle} ...`,
|
||||||
@ -81,6 +86,16 @@ export default function PhotoPrevNextActions({
|
|||||||
toastMessage: `Unfavoriting ${photoTitle} ...`,
|
toastMessage: `Unfavoriting ${photoTitle} ...`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const hidePhoto = useNavigateOrRunActionWithToast({
|
||||||
|
pathOrAction: toggleHidden,
|
||||||
|
toastMessage: `Hiding ${photoTitle} ...`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const unhidePhoto = useNavigateOrRunActionWithToast({
|
||||||
|
pathOrAction: toggleHidden,
|
||||||
|
toastMessage: `Unhiding ${photoTitle} ...`,
|
||||||
|
});
|
||||||
|
|
||||||
const syncPhoto = useNavigateOrRunActionWithToast({
|
const syncPhoto = useNavigateOrRunActionWithToast({
|
||||||
pathOrAction: useCallback(() => {
|
pathOrAction: useCallback(() => {
|
||||||
if (photo?.id) { return syncPhotoAction(photo.id); }
|
if (photo?.id) { return syncPhotoAction(photo.id); }
|
||||||
@ -153,6 +168,15 @@ export default function PhotoPrevNextActions({
|
|||||||
unfavoritePhoto();
|
unfavoritePhoto();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KEY_COMMANDS.toggleHide:
|
||||||
|
if (isUserSignedIn && photo) {
|
||||||
|
if (photo.hidden) {
|
||||||
|
unhidePhoto();
|
||||||
|
} else {
|
||||||
|
hidePhoto();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case KEY_COMMANDS.download:
|
case KEY_COMMANDS.download:
|
||||||
if (
|
if (
|
||||||
(isUserSignedIn || ALLOW_PUBLIC_DOWNLOADS) &&
|
(isUserSignedIn || ALLOW_PUBLIC_DOWNLOADS) &&
|
||||||
@ -182,6 +206,8 @@ export default function PhotoPrevNextActions({
|
|||||||
photo,
|
photo,
|
||||||
favoritePhoto,
|
favoritePhoto,
|
||||||
unfavoritePhoto,
|
unfavoritePhoto,
|
||||||
|
hidePhoto,
|
||||||
|
unhidePhoto,
|
||||||
downloadUrl,
|
downloadUrl,
|
||||||
downloadFileName,
|
downloadFileName,
|
||||||
syncPhoto,
|
syncPhoto,
|
||||||
|
|||||||
@ -265,6 +265,20 @@ export const toggleFavoritePhotoAction = async (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const toggleHidePhotoAction = async (
|
||||||
|
photoId: string,
|
||||||
|
redirectPath?: string,
|
||||||
|
) =>
|
||||||
|
runAuthenticatedAdminServerAction(async () => {
|
||||||
|
const photo = await getPhoto(photoId, true);
|
||||||
|
if (photo) {
|
||||||
|
photo.hidden = !photo.hidden;
|
||||||
|
await updatePhoto(convertPhotoToPhotoDbInsert(photo));
|
||||||
|
revalidateAllKeysAndPaths();
|
||||||
|
}
|
||||||
|
if (redirectPath) { redirect(redirectPath); }
|
||||||
|
});
|
||||||
|
|
||||||
export const deletePhotosAction = async (photoIds: string[]) =>
|
export const deletePhotosAction = async (photoIds: string[]) =>
|
||||||
runAuthenticatedAdminServerAction(async () => {
|
runAuthenticatedAdminServerAction(async () => {
|
||||||
for (const photoId of photoIds) {
|
for (const photoId of photoIds) {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export const KEY_COMMANDS = {
|
|||||||
edit: 'E',
|
edit: 'E',
|
||||||
favorite: 'P',
|
favorite: 'P',
|
||||||
unfavorite: 'X',
|
unfavorite: 'X',
|
||||||
|
toggleHide: 'H',
|
||||||
download: 'D',
|
download: 'D',
|
||||||
sync: 'S',
|
sync: 'S',
|
||||||
search: ['⌘', 'K'],
|
search: ['⌘', 'K'],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user