Create admin recipe detail page

This commit is contained in:
Sam Becker 2025-03-12 18:11:16 -05:00
parent 2c35587f5d
commit 769d6b64bb
4 changed files with 92 additions and 18 deletions

View File

@ -1,31 +1,31 @@
import AdminChildPage from '@/components/AdminChildPage';
import { redirect } from 'next/navigation';
import { getPhotosCached } from '@/photo/cache';
import TagForm from '@/tag/TagForm';
import { PATH_ADMIN, PATH_ADMIN_TAGS, pathForTag } from '@/app/paths';
import { PATH_ADMIN, PATH_ADMIN_TAGS, pathForRecipe } from '@/app/paths';
import PhotoLightbox from '@/photo/PhotoLightbox';
import { getPhotosMeta } from '@/photo/db/query';
import AdminTagBadge from '@/admin/AdminTagBadge';
import AdminRecipeBadge from '@/admin/AdminRecipeBadge';
import AdminRecipeForm from '@/admin/AdminRecipeForm';
const MAX_PHOTO_TO_SHOW = 6;
interface Props {
params: Promise<{ tag: string }>
params: Promise<{ recipe: string }>
}
export default async function PhotoPageEdit({
export default async function RecipePageEdit({
params,
}: Props) {
const { tag: tagFromParams } = await params;
const { recipe: recipeFromParams } = await params;
const tag = decodeURIComponent(tagFromParams);
const recipe = decodeURIComponent(recipeFromParams);
const [
{ count },
photos,
] = await Promise.all([
getPhotosMeta({ tag }),
getPhotosCached({ tag, limit: MAX_PHOTO_TO_SHOW }),
getPhotosMeta({ recipe }),
getPhotosCached({ recipe, limit: MAX_PHOTO_TO_SHOW }),
]);
if (count === 0) { redirect(PATH_ADMIN); }
@ -34,15 +34,15 @@ export default async function PhotoPageEdit({
<AdminChildPage
backPath={PATH_ADMIN_TAGS}
backLabel="Tags"
breadcrumb={<AdminTagBadge {...{ tag, count, hideBadge: true }} />}
breadcrumb={<AdminRecipeBadge {...{ recipe, count, hideBadge: true }} />}
>
<TagForm {...{ tag, photos }}>
<AdminRecipeForm {...{ recipe, photos }}>
<PhotoLightbox
{...{ count, photos, tag }}
{...{ count, photos, recipe }}
maxPhotosToShow={MAX_PHOTO_TO_SHOW}
moreLink={pathForTag(tag)}
moreLink={pathForRecipe(recipe)}
/>
</TagForm>
</AdminRecipeForm>
</AdminChildPage>
);
};

View File

@ -1,7 +1,7 @@
import AdminChildPage from '@/components/AdminChildPage';
import { redirect } from 'next/navigation';
import { getPhotosCached } from '@/photo/cache';
import TagForm from '@/tag/TagForm';
import AdminTagForm from '@/admin/AdminTagForm';
import { PATH_ADMIN, PATH_ADMIN_TAGS, pathForTag } from '@/app/paths';
import PhotoLightbox from '@/photo/PhotoLightbox';
import { getPhotosMeta } from '@/photo/db/query';
@ -36,13 +36,13 @@ export default async function PhotoPageEdit({
backLabel="Tags"
breadcrumb={<AdminTagBadge {...{ tag, count, hideBadge: true }} />}
>
<TagForm {...{ tag, photos }}>
<AdminTagForm {...{ tag, photos }}>
<PhotoLightbox
{...{ count, photos, tag }}
maxPhotosToShow={MAX_PHOTO_TO_SHOW}
moreLink={pathForTag(tag)}
/>
</TagForm>
</AdminTagForm>
</AdminChildPage>
);
};

View File

@ -0,0 +1,74 @@
'use client';
import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
import Link from 'next/link';
import { PATH_ADMIN_RECIPES } from '@/app/paths';
import FieldSetWithStatus from '@/components/FieldSetWithStatus';
import { ReactNode, useMemo, useState } from 'react';
import { renamePhotoTagGloballyAction } from '@/photo/actions';
import { parameterize } from '@/utility/string';
import { useAppState } from '@/state/AppState';
export default function AdminRecipeForm({
recipe,
children,
}: {
recipe: string
children?: ReactNode
}) {
const { invalidateSwr } = useAppState();
const [updatedRecipeRaw, setUpdatedRecipeRaw] = useState(recipe);
const updatedRecipe = useMemo(() =>
parameterize(updatedRecipeRaw)
, [updatedRecipeRaw]);
const isFormValid = (
updatedRecipe &&
updatedRecipe !== recipe
);
return (
<form
action={renamePhotoTagGloballyAction}
className="space-y-8"
>
<FieldSetWithStatus
id="updatedTagRaw"
label="New Tag Name"
value={updatedRecipeRaw}
onChange={setUpdatedRecipeRaw}
/>
{/* Form data: tag to be replaced */}
<input
name="recipe"
value={recipe}
hidden
readOnly
/>
{/* Form data: updated tag */}
<input
name="updatedRecipe"
value={updatedRecipe}
hidden
readOnly
/>
{children}
<div className="flex gap-3">
<Link
className="button"
href={PATH_ADMIN_RECIPES}
>
Cancel
</Link>
<SubmitButtonWithStatus
disabled={!isFormValid}
onFormSubmit={invalidateSwr}
>
Update
</SubmitButtonWithStatus>
</div>
</form>
);
}

View File

@ -9,7 +9,7 @@ import { renamePhotoTagGloballyAction } from '@/photo/actions';
import { parameterize } from '@/utility/string';
import { useAppState } from '@/state/AppState';
export default function TagForm({
export default function AdminTagForm({
tag,
children,
}: {