Rearchitect client-side EXIF syncing

This commit is contained in:
Sam Becker 2024-07-07 13:01:06 -05:00
parent dc3f5b2f9b
commit ac5f709c3d
3 changed files with 40 additions and 57 deletions

View File

@ -1,37 +1,39 @@
import FormWithConfirm from '@/components/FormWithConfirm';
'use client';
import LoaderButton from '@/components/primitives/LoaderButton';
import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
import { getExifDataAction } from '@/photo/actions';
import { PhotoFormData } from '@/photo/form';
import IconGrSync from '@/site/IconGrSync';
import { clsx } from 'clsx/lite';
import { ComponentProps } from 'react';
import { ComponentProps, useState } from 'react';
export default function ExifSyncButton({
action,
label,
onFormSubmit,
photoUrl,
className,
onSync,
}: {
action: (formData: FormData) => void
label?: string
photoUrl?: string
photoUrl: string
onSync?: (data: Partial<PhotoFormData>) => void
} & ComponentProps<typeof SubmitButtonWithStatus>) {
const [isLoading, setIsLoading] = useState(false);
return (
<FormWithConfirm
action={action}
className={className}
<LoaderButton
title="Update photo from original file"
isLoading={isLoading}
onClick={() => {
setIsLoading(true);
getExifDataAction(photoUrl)
.then(onSync)
.finally(() => setIsLoading(false));
}}
icon={<IconGrSync
className={clsx(
'translate-y-[0.5px] translate-x-[0.5px]',
'sm:translate-x-[-0.5px]',
)} />}
>
<input name="photoUrl" value={photoUrl} hidden readOnly />
<SubmitButtonWithStatus
title="Update photo from original file"
icon={<IconGrSync
className={clsx(
'translate-y-[0.5px] translate-x-[0.5px]',
label && 'sm:translate-x-[-0.5px]',
)} />}
onFormSubmit={onFormSubmit}
>
{label}
</SubmitButtonWithStatus>
</FormWithConfirm>
EXIF
</LoaderButton>
);
}

View File

@ -3,18 +3,13 @@
import AdminChildPage from '@/components/AdminChildPage';
import { Photo } from '.';
import { PATH_ADMIN_PHOTOS } from '@/site/paths';
import {
PhotoFormData,
convertPhotoToFormData,
} from './form';
import { PhotoFormData, convertPhotoToFormData } from './form';
import PhotoForm from './form/PhotoForm';
import { useFormState } from 'react-dom';
import { areSimpleObjectsEqual } from '@/utility/object';
import { getExifDataAction } from './actions';
import { Tags } from '@/tag';
import AiButton from './ai/AiButton';
import usePhotoFormParent from './form/usePhotoFormParent';
import ExifSyncButton from '@/admin/ExifSyncButton';
import { useState } from 'react';
export default function PhotoEditPageClient({
photo,
@ -29,18 +24,6 @@ export default function PhotoEditPageClient({
imageThumbnailBase64: string
blurData: string
}) {
const seedExifData = { url: photo.url };
const [updatedExifData, action] = useFormState<Partial<PhotoFormData>>(
getExifDataAction,
seedExifData,
);
const hasExifDataBeenFound = !areSimpleObjectsEqual(
updatedExifData,
seedExifData,
);
const photoForm = convertPhotoToFormData(photo);
const {
@ -56,6 +39,9 @@ export default function PhotoEditPageClient({
imageThumbnailBase64,
});
const [updatedExifData, setUpdatedExifData] =
useState<Partial<PhotoFormData>>();
return (
<AdminChildPage
backPath={PATH_ADMIN_PHOTOS}
@ -69,9 +55,8 @@ export default function PhotoEditPageClient({
{hasAiTextGeneration &&
<AiButton {...{ aiContent, shouldConfirm: hasTextContent }} />}
<ExifSyncButton
action={action}
label="EXIF"
photoUrl={photo.url}
onSync={setUpdatedExifData}
/>
</div>}
isLoading={pending}
@ -79,9 +64,7 @@ export default function PhotoEditPageClient({
<PhotoForm
type="edit"
initialPhotoForm={photoForm}
updatedExifData={hasExifDataBeenFound
? updatedExifData
: undefined}
updatedExifData={updatedExifData}
updatedBlurData={blurData}
uniqueTags={uniqueTags}
aiContent={hasAiTextGeneration ? aiContent : undefined}

View File

@ -280,17 +280,15 @@ export const deleteBlobPhotoAction = async (formData: FormData) =>
// Accessed from admin photo edit page
// will not update blur data
export const getExifDataAction = async (
photoFormPrevious: Partial<PhotoFormData>,
url: string,
): Promise<Partial<PhotoFormData>> =>
runAuthenticatedAdminServerAction(async () => {
const { url } = photoFormPrevious;
if (url) {
const { photoFormExif } = await extractImageDataFromBlobPath(url);
if (photoFormExif) {
return photoFormExif;
}
const { photoFormExif } = await extractImageDataFromBlobPath(url);
if (photoFormExif) {
return photoFormExif;
} else {
return {};
}
return {};
});
// Accessed from admin photo table, will: