Vercel/src/photo/PhotoEditPageClient.tsx
Sam Becker 1e66815a3d
Albums (#315)
* Make /db top-level module

* Create Album type

* Pin pnpm version

* Generalize query modules

* Finalize album postgres data type

* Remove temp albums prop

* Create basic album primitives

* Fix temporary album bugs

* Add albums to sidebar

* Disambiguate string date utilities

* Localize album language

* Add album join option to core photo queries

* Tweak album icon placement

* Add album photo detail page

* Refine Album data model

* Display album subhead when available

* Generate album og images

* Finalize album share modal

* Add albums to sitemap

* Statically pre-render albums

* Display tags on albums

* Add albums to cmd-k menu

* Handle album tag overflow

* Stop truncating album subheads

* Create core admin album views

* Make albums editable

* Create/edit albums on photo save, add delete album
2025-09-16 21:47:22 -05:00

104 lines
2.7 KiB
TypeScript

'use client';
import AdminChildPage from '@/components/AdminChildPage';
import { Photo } from '.';
import { PATH_ADMIN_PHOTOS } from '@/app/path';
import {
PhotoFormData,
convertPhotoToFormData,
} from './form';
import PhotoForm from './form/PhotoForm';
import { Tags } from '@/tag';
import AiButton from './ai/AiButton';
import usePhotoFormParent from './form/usePhotoFormParent';
import ExifCaptureButton from '@/admin/ExifCaptureButton';
import { useState } from 'react';
import { Recipes } from '@/recipe';
import { Films } from '@/film';
import { StorageListResponse } from '@/platforms/storage';
import { Albums } from '@/album';
export default function PhotoEditPageClient({
photo,
photoStorageUrls,
photoAlbumTitles,
albums,
uniqueTags,
uniqueRecipes,
uniqueFilms,
hasAiTextGeneration,
imageThumbnailBase64,
blurData,
}: {
photo: Photo
photoStorageUrls?: StorageListResponse
photoAlbumTitles: string[]
albums: Albums
uniqueTags: Tags
uniqueRecipes: Recipes
uniqueFilms: Films
hasAiTextGeneration: boolean
imageThumbnailBase64: string
blurData: string
}) {
const photoForm = convertPhotoToFormData(photo);
const {
pending,
setIsPending,
updatedTitle,
setUpdatedTitle,
shouldConfirmAiTextGeneration,
setShouldConfirmAiTextGeneration,
aiContent,
} = usePhotoFormParent({
photoForm,
imageThumbnailBase64,
});
const [updatedExifData, setUpdatedExifData] =
useState<Partial<PhotoFormData>>();
return (
<AdminChildPage
backPath={PATH_ADMIN_PHOTOS}
backLabel="Photos"
breadcrumb={pending && updatedTitle
? updatedTitle
: photo.title || photo.id}
breadcrumbEllipsis
accessory={
<div className="flex gap-2">
{hasAiTextGeneration &&
<AiButton {...{
aiContent,
shouldConfirm: shouldConfirmAiTextGeneration,
tooltip: 'Generate AI text for all fields',
}} />}
<ExifCaptureButton
photoUrl={photo.url}
onSync={setUpdatedExifData}
/>
</div>}
isLoading={pending}
>
<PhotoForm
type="edit"
initialPhotoForm={photoForm}
photoStorageUrls={photoStorageUrls}
updatedExifData={updatedExifData}
updatedBlurData={blurData}
photoAlbumTitles={photoAlbumTitles}
albums={albums}
uniqueTags={uniqueTags}
uniqueRecipes={uniqueRecipes}
uniqueFilms={uniqueFilms}
aiContent={hasAiTextGeneration ? aiContent : undefined}
onTitleChange={setUpdatedTitle}
onFormStatusChange={setIsPending}
onFormDataChange={setShouldConfirmAiTextGeneration}
/>
</AdminChildPage>
);
};