Rearchitect client-side EXIF syncing
This commit is contained in:
parent
dc3f5b2f9b
commit
ac5f709c3d
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user