Add recipe query param, sync menu item

This commit is contained in:
Sam Becker 2025-02-23 12:59:52 -06:00
parent 1b92b42b78
commit 4ff7473a00
4 changed files with 38 additions and 9 deletions

View File

@ -2,7 +2,11 @@
import { ComponentProps, useMemo } from 'react';
import { pathForAdminPhotoEdit, pathForPhoto } from '@/app/paths';
import { deletePhotoAction, toggleFavoritePhotoAction } from '@/photo/actions';
import {
deletePhotoAction,
syncPhotoAction,
toggleFavoritePhotoAction,
} from '@/photo/actions';
import { FaRegEdit, FaRegStar, FaStar } from 'react-icons/fa';
import {
Photo,
@ -17,6 +21,7 @@ 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 '@/app/IconGrSync';
export default function AdminPhotoMenuClient({
photo,
@ -65,17 +70,24 @@ export default function AdminPhotoMenuClient({
label: 'Download',
icon: <MdOutlineFileDownload
size={17}
className="translate-x-[-1.5px] translate-y-[-0.5px]"
className="translate-x-[-1px] translate-y-[-0.5px]"
/>,
href: photo.url,
hrefDownloadName: downloadFileNameForPhoto(photo),
});
items.push({
label: 'Sync',
icon: <IconGrSync className="translate-x-[-1px]" />,
action: () => syncPhotoAction(photo.id)
.then(() => revalidatePhoto?.(photo.id)),
});
items.push({
label: 'Delete',
icon: <BiTrash
size={15}
className="translate-x-[-1.5px]"
className="translate-x-[-1px]"
/>,
className: 'text-error',
action: () => {
if (confirm(deleteConfirmationTextForPhoto(photo))) {
return deletePhotoAction(

View File

@ -33,6 +33,10 @@ const PATH_CAMERA_DYNAMIC = `${PREFIX_CAMERA}/[make]/[model]`;
const PATH_FILM_SIMULATION_DYNAMIC = `${PREFIX_FILM_SIMULATION}/[simulation]`;
const PATH_FOCAL_LENGTH_DYNAMIC = `${PREFIX_FOCAL_LENGTH}/[focal]`;
// Search params
export const SEARCH_PARAM_SHOW = 'show';
export const SEARCH_PARAM_SHOW_RECIPE = 'recipe';
// Admin paths
export const PATH_ADMIN_PHOTOS = `${PATH_ADMIN}/photos`;
export const PATH_ADMIN_OUTDATED = `${PATH_ADMIN}/outdated`;
@ -78,7 +82,9 @@ export const PATHS_TO_CACHE = [
...PATHS_ADMIN,
];
type PhotoPathParams = { photo: PhotoOrPhotoId } & PhotoSetCategory;
type PhotoPathParams = { photo: PhotoOrPhotoId } & PhotoSetCategory & {
showRecipe?: boolean
};
// Absolute paths
export const ABSOLUTE_PATH_FOR_HOME_IMAGE = `${BASE_URL}/home-image`;
@ -103,6 +109,7 @@ export const pathForPhoto = ({
camera,
simulation,
focal,
showRecipe,
}: PhotoPathParams) =>
typeof photo !== 'string' && photo.hidden
? `${pathForTag(TAG_HIDDEN)}/${getPhotoId(photo)}`
@ -114,7 +121,9 @@ export const pathForPhoto = ({
? `${pathForFilmSimulation(simulation)}/${getPhotoId(photo)}`
: focal
? `${pathForFocalLength(focal)}/${getPhotoId(photo)}`
: `${PREFIX_PHOTO}/${getPhotoId(photo)}`;
: `${PREFIX_PHOTO}/${getPhotoId(photo)}` + (showRecipe
? `?${SEARCH_PARAM_SHOW}=${SEARCH_PARAM_SHOW_RECIPE}`
: '');
export const pathForTag = (tag: string) =>
`${PREFIX_TAG}/${tag}`;

View File

@ -12,6 +12,7 @@ export default function MoreMenuItem({
icon,
href,
hrefDownloadName,
className,
action,
shouldPreventDefault = true,
}: {
@ -19,6 +20,7 @@ export default function MoreMenuItem({
icon?: ReactNode
href?: string
hrefDownloadName?: string
className?: string
action?: () => Promise<void> | void
shouldPreventDefault?: boolean
}) {
@ -43,6 +45,7 @@ export default function MoreMenuItem({
isLoading
? 'cursor-not-allowed opacity-50'
: 'cursor-pointer',
className,
)}
onClick={async e => {
if (shouldPreventDefault) { e.preventDefault(); }

View File

@ -15,6 +15,8 @@ import Link from 'next/link';
import {
pathForFocalLength,
pathForPhoto,
SEARCH_PARAM_SHOW,
SEARCH_PARAM_SHOW_RECIPE,
} from '@/app/paths';
import PhotoTags from '@/tag/PhotoTags';
import ShareButton from '@/share/ShareButton';
@ -43,6 +45,7 @@ import ZoomControls, { ZoomControlsRef } from '@/components/image/ZoomControls';
import PhotoRecipe from './PhotoRecipe';
import { TbChecklist } from 'react-icons/tb';
import { IoCloseSharp } from 'react-icons/io5';
import { useSearchParams } from 'next/navigation';
export default function PhotoLarge({
photo,
@ -91,7 +94,10 @@ export default function PhotoLarge({
const zoomControlsRef = useRef<ZoomControlsRef>(null);
const [shouldShowRecipe, setShouldShowRecipe] = useState(false);
const params = useSearchParams();
const showRecipeInitially =
params.get(SEARCH_PARAM_SHOW) === SEARCH_PARAM_SHOW_RECIPE;
const [shouldShowRecipe, setShouldShowRecipe] = useState(showRecipeInitially);
const recipeButtonRef = useRef<HTMLButtonElement>(null);
const {
@ -333,9 +339,8 @@ export default function PhotoLarge({
// Prevent collision with admin button
!hasNonDateContent && isUserSignedIn && 'md:pr-7',
)}
// 'createdAt' is a naive datetime which
// does not require a timezone and will not
// cause server/client time mismatches
// 'createdAt' is a naive datetime which does not require
// a timezone and will not cause server/client mismatch
timezone={null}
hideTime={!SHOW_TAKEN_AT_TIME}
/>