Add server actions to get/override EXIF data
This commit is contained in:
parent
bf78ced898
commit
8bb5c2990b
@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { LegacyRef } from 'react';
|
||||
// @ts-ignore
|
||||
import { useFormStatus } from 'react-dom';
|
||||
import Spinner from './Spinner';
|
||||
import { cc } from '@/utility/css';
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { HTMLProps } from 'react';
|
||||
// @ts-ignore
|
||||
import { useFormStatus } from 'react-dom';
|
||||
import Spinner from './Spinner';
|
||||
import { cc } from '@/utility/css';
|
||||
|
||||
@ -5,26 +5,40 @@ import { Photo } from '.';
|
||||
import { PATH_ADMIN_PHOTOS } from '@/site/paths';
|
||||
import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
|
||||
import { BiRefresh } from 'react-icons/bi';
|
||||
import { convertPhotoToFormData } from './form';
|
||||
import { PhotoFormData, convertPhotoToFormData } from './form';
|
||||
import PhotoForm from './PhotoForm';
|
||||
import { useFormState } from 'react-dom';
|
||||
import { getExifDataAction } from './actions';
|
||||
|
||||
export default function PhotoEditPageClient({
|
||||
photo,
|
||||
}: {
|
||||
photo: Photo
|
||||
}) {
|
||||
const [updatedExifData, action] = useFormState<Partial<PhotoFormData>>(
|
||||
getExifDataAction,
|
||||
{ url: photo.url},
|
||||
);
|
||||
|
||||
return (
|
||||
<AdminChildPage
|
||||
backPath={PATH_ADMIN_PHOTOS}
|
||||
backLabel="Photos"
|
||||
breadcrumb={photo.title || photo.id}
|
||||
accessory={<SubmitButtonWithStatus icon={<BiRefresh size={18} />}>
|
||||
Refresh EXIF
|
||||
</SubmitButtonWithStatus>}
|
||||
accessory={
|
||||
<form action={action}>
|
||||
<input name="photoUrl" value={photo.url} hidden readOnly />
|
||||
<SubmitButtonWithStatus
|
||||
icon={<BiRefresh size={18} className="translate-y-[-1.5px]" />}
|
||||
>
|
||||
Refresh EXIF
|
||||
</SubmitButtonWithStatus>
|
||||
</form>}
|
||||
>
|
||||
<PhotoForm
|
||||
type="edit"
|
||||
initialPhotoForm={convertPhotoToFormData(photo)}
|
||||
updatedExifData={updatedExifData}
|
||||
/>
|
||||
</AdminChildPage>
|
||||
);
|
||||
|
||||
@ -23,16 +23,26 @@ const THUMBNAIL_HEIGHT = 200;
|
||||
|
||||
export default function PhotoForm({
|
||||
initialPhotoForm,
|
||||
updatedExifData,
|
||||
type = 'create',
|
||||
debugBlur,
|
||||
}: {
|
||||
initialPhotoForm: Partial<PhotoFormData>
|
||||
updatedExifData?: Partial<PhotoFormData>
|
||||
type?: 'create' | 'edit'
|
||||
debugBlur?: boolean
|
||||
}) {
|
||||
const [formData, setFormData] =
|
||||
useState<Partial<PhotoFormData>>(initialPhotoForm);
|
||||
|
||||
useEffect(() => {
|
||||
// Update form when EXIF data is refreshed by parent
|
||||
setFormData(currentForm => ({
|
||||
...currentForm,
|
||||
...updatedExifData,
|
||||
}));
|
||||
}, [updatedExifData]);
|
||||
|
||||
// Generate local date strings when
|
||||
// none can be harvested from EXIF
|
||||
useEffect(() => {
|
||||
|
||||
@ -6,8 +6,14 @@ import {
|
||||
sqlDeletePhotoTagGlobally,
|
||||
sqlUpdatePhoto,
|
||||
sqlRenamePhotoTagGlobally,
|
||||
getPhoto,
|
||||
} from '@/services/postgres';
|
||||
import { convertFormDataToPhoto } from './form';
|
||||
import {
|
||||
PhotoFormData,
|
||||
convertFormDataToPhotoDbInsert,
|
||||
convertPhotoFormDataToPhotoDbInsert,
|
||||
convertPhotoToFormData,
|
||||
} from './form';
|
||||
import { redirect } from 'next/navigation';
|
||||
import {
|
||||
convertUploadToPhoto,
|
||||
@ -20,9 +26,10 @@ import {
|
||||
revalidatePhotosKey,
|
||||
} from '@/cache';
|
||||
import { PATH_ADMIN_PHOTOS, PATH_ADMIN_TAGS } from '@/site/paths';
|
||||
import { extractFormDataFromUploadPath } from './server';
|
||||
|
||||
export async function createPhotoAction(formData: FormData) {
|
||||
const photo = convertFormDataToPhoto(formData, true);
|
||||
const photo = convertFormDataToPhotoDbInsert(formData, true);
|
||||
|
||||
const updatedUrl = await convertUploadToPhoto(photo.url, photo.id);
|
||||
|
||||
@ -36,7 +43,7 @@ export async function createPhotoAction(formData: FormData) {
|
||||
}
|
||||
|
||||
export async function updatePhotoAction(formData: FormData) {
|
||||
const photo = convertFormDataToPhoto(formData);
|
||||
const photo = convertFormDataToPhotoDbInsert(formData);
|
||||
|
||||
await sqlUpdatePhoto(photo);
|
||||
|
||||
@ -84,7 +91,40 @@ export async function deleteBlobPhotoAction(formData: FormData) {
|
||||
if (formData.get('redirectToPhotos') === 'true') {
|
||||
redirect(PATH_ADMIN_PHOTOS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function getExifDataAction(
|
||||
photoFormPrevious: Partial<PhotoFormData>,
|
||||
): Promise<Partial<PhotoFormData>> {
|
||||
const { url } = photoFormPrevious;
|
||||
if (url) {
|
||||
const { photoForm } = await extractFormDataFromUploadPath(url);
|
||||
if (photoForm) {
|
||||
return photoForm;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
export async function syncPhotoExifDataAction(formData: FormData) {
|
||||
const photoId = formData.get('photoId') as string;
|
||||
if (photoId) {
|
||||
const photo = await getPhoto(photoId);
|
||||
if (photo) {
|
||||
const {
|
||||
photoForm: photoFormExif,
|
||||
} = await extractFormDataFromUploadPath(photo.url);
|
||||
if (photoFormExif) {
|
||||
const photoFormDbInsert = convertPhotoFormDataToPhotoDbInsert({
|
||||
...convertPhotoToFormData(photo),
|
||||
...photoFormExif,
|
||||
});
|
||||
await sqlUpdatePhoto(photoFormDbInsert);
|
||||
revalidatePhotosKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncCacheAction() {
|
||||
revalidateAllKeysAndPaths();
|
||||
|
||||
@ -123,7 +123,7 @@ export const convertExifToFormData = (
|
||||
: undefined,
|
||||
});
|
||||
|
||||
export const convertFormDataToPhoto = (
|
||||
export const convertFormDataToPhotoDbInsert = (
|
||||
formData: FormData,
|
||||
generateId?: boolean,
|
||||
): PhotoDbInsert => {
|
||||
@ -178,3 +178,20 @@ export const convertFormDataToPhoto = (
|
||||
hidden: photoForm.hidden === 'true',
|
||||
};
|
||||
};
|
||||
|
||||
const convertPhotoFormDataToFormData = (
|
||||
photoFormData: PhotoFormData,
|
||||
) => {
|
||||
const formData = new FormData();
|
||||
for (const key in photoFormData) {
|
||||
formData.append(key, photoFormData[key as keyof PhotoFormData]);
|
||||
}
|
||||
return formData;
|
||||
};
|
||||
|
||||
export const convertPhotoFormDataToPhotoDbInsert = (
|
||||
photoFormData: PhotoFormData,
|
||||
) => {
|
||||
const formData = convertPhotoFormDataToFormData(photoFormData);
|
||||
return convertFormDataToPhotoDbInsert(formData);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user