Create /admin/recipes page
This commit is contained in:
parent
3d57de3997
commit
2c35587f5d
@ -1,16 +1,16 @@
|
||||
import AdminTagTable from '@/admin/AdminTagTable';
|
||||
import AdminRecipeTable from '@/admin/AdminRecipeTable';
|
||||
import SiteGrid from '@/components/SiteGrid';
|
||||
import { getUniqueTagsHiddenCached } from '@/photo/cache';
|
||||
import { getUniqueRecipesCached } from '@/photo/cache';
|
||||
|
||||
export default async function AdminTagsPage() {
|
||||
const tags = await getUniqueTagsHiddenCached().catch(() => []);
|
||||
const recipes = await getUniqueRecipesCached().catch(() => []);
|
||||
|
||||
return (
|
||||
<SiteGrid
|
||||
contentMain={
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<AdminTagTable {...{ tags }} />
|
||||
<AdminRecipeTable {...{ recipes }} />
|
||||
</div>
|
||||
</div>}
|
||||
/>
|
||||
|
||||
35
src/admin/AdminRecipeBadge.tsx
Normal file
35
src/admin/AdminRecipeBadge.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import { photoLabelForCount } from '@/photo';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import Badge from '@/components/Badge';
|
||||
import PhotoRecipe from '@/recipe/PhotoRecipe';
|
||||
|
||||
export default function AdminRecipeBadge({
|
||||
recipe,
|
||||
count,
|
||||
hideBadge,
|
||||
}: {
|
||||
recipe: string,
|
||||
count: number,
|
||||
hideBadge?: boolean,
|
||||
}) {
|
||||
const renderBadgeContent = () =>
|
||||
<div className={clsx(
|
||||
'inline-flex items-center gap-2',
|
||||
'translate-y-[1px]',
|
||||
)}>
|
||||
<PhotoRecipe {...{ recipe }} />
|
||||
<div className="text-dim uppercase">
|
||||
<span>{count}</span>
|
||||
<span className="hidden xs:inline-block">
|
||||
|
||||
{photoLabelForCount(count)}
|
||||
</span>
|
||||
</div>
|
||||
</div>;
|
||||
|
||||
return (
|
||||
hideBadge
|
||||
? renderBadgeContent()
|
||||
: <Badge className="py-[3px]!">{renderBadgeContent()}</Badge>
|
||||
);
|
||||
}
|
||||
43
src/admin/AdminRecipeTable.tsx
Normal file
43
src/admin/AdminRecipeTable.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import FormWithConfirm from '@/components/FormWithConfirm';
|
||||
import { deletePhotoTagGloballyAction } from '@/photo/actions';
|
||||
import AdminTable from '@/admin/AdminTable';
|
||||
import { Fragment } from 'react';
|
||||
import DeleteFormButton from '@/admin/DeleteFormButton';
|
||||
import { photoQuantityText } from '@/photo';
|
||||
import EditButton from '@/admin/EditButton';
|
||||
import { pathForAdminRecipeEdit } from '@/app/paths';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { formatRecipe, Recipes, sortRecipesWithCount } from '@/recipe';
|
||||
import AdminRecipeBadge from './AdminRecipeBadge';
|
||||
|
||||
export default function AdminRecipeTable({
|
||||
recipes,
|
||||
}: {
|
||||
recipes: Recipes
|
||||
}) {
|
||||
return (
|
||||
<AdminTable>
|
||||
{sortRecipesWithCount(recipes).map(({ recipe, count }) =>
|
||||
<Fragment key={recipe}>
|
||||
<div className="pr-2 col-span-2">
|
||||
<AdminRecipeBadge {...{ recipe, count }} />
|
||||
</div>
|
||||
<div className={clsx(
|
||||
'flex flex-nowrap',
|
||||
'gap-2 sm:gap-3 items-center',
|
||||
)}>
|
||||
<EditButton path={pathForAdminRecipeEdit(recipe)} />
|
||||
<FormWithConfirm
|
||||
action={deletePhotoTagGloballyAction}
|
||||
confirmText={
|
||||
// eslint-disable-next-line max-len
|
||||
`Are you sure you want to remove "${formatRecipe(recipe)}" from ${photoQuantityText(count, false).toLowerCase()}?`}
|
||||
>
|
||||
<input type="hidden" name="recipe" value={recipe} />
|
||||
<DeleteFormButton clearLocalState />
|
||||
</FormWithConfirm>
|
||||
</div>
|
||||
</Fragment>)}
|
||||
</AdminTable>
|
||||
);
|
||||
}
|
||||
@ -100,6 +100,9 @@ export const pathForAdminPhotoEdit = (photo: PhotoOrPhotoId) =>
|
||||
export const pathForAdminTagEdit = (tag: string) =>
|
||||
`${PATH_ADMIN_TAGS}/${tag}/${EDIT}`;
|
||||
|
||||
export const pathForAdminRecipeEdit = (recipe: string) =>
|
||||
`${PATH_ADMIN_RECIPES}/${recipe}/${EDIT}`;
|
||||
|
||||
type PhotoOrPhotoId = Photo | string;
|
||||
|
||||
const getPhotoId = (photoOrPhotoId: PhotoOrPhotoId) =>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user