Refactor delete photo buttons

This commit is contained in:
Sam Becker 2024-07-21 10:41:54 -05:00
parent ac10e97533
commit b71a3825db
7 changed files with 46 additions and 28 deletions

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { Photo, deleteConfirmationTextForPhoto, titleForPhoto } from '@/photo'; import { Photo, titleForPhoto } from '@/photo';
import AdminTable from './AdminTable'; import AdminTable from './AdminTable';
import { Fragment } from 'react'; import { Fragment } from 'react';
import PhotoSmall from '@/photo/PhotoSmall'; import PhotoSmall from '@/photo/PhotoSmall';
@ -9,13 +9,11 @@ import { pathForAdminPhotoEdit, pathForPhoto } from '@/site/paths';
import Link from 'next/link'; import Link from 'next/link';
import { AiOutlineEyeInvisible } from 'react-icons/ai'; import { AiOutlineEyeInvisible } from 'react-icons/ai';
import PhotoDate from '@/photo/PhotoDate'; import PhotoDate from '@/photo/PhotoDate';
import FormWithConfirm from '@/components/FormWithConfirm';
import EditButton from './EditButton'; import EditButton from './EditButton';
import DeleteButton from './DeleteButton';
import { deletePhotoFormAction } from '@/photo/actions';
import { useAppState } from '@/state/AppState'; import { useAppState } from '@/state/AppState';
import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll'; import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll';
import PhotoSyncButton from './PhotoSyncButton'; import PhotoSyncButton from './PhotoSyncButton';
import DeletePhotoButton from './DeletePhotoButton';
export default function AdminPhotosTable({ export default function AdminPhotosTable({
photos, photos,
@ -113,15 +111,10 @@ export default function AdminPhotosTable({
shouldToast shouldToast
/> />
{canDelete && {canDelete &&
<FormWithConfirm <DeletePhotoButton
action={deletePhotoFormAction} photo={photo}
confirmText={deleteConfirmationTextForPhoto(photo)} onDelete={() => revalidatePhoto?.(photo.id, true)}
onSubmit={() => revalidatePhoto?.(photo.id, true)} />}
>
<input type="hidden" name="id" value={photo.id} />
<input type="hidden" name="url" value={photo.url} />
<DeleteButton clearLocalState />
</FormWithConfirm>}
</div> </div>
</Fragment>)} </Fragment>)}
</AdminTable> </AdminTable>

View File

@ -2,7 +2,7 @@ import FormWithConfirm from '@/components/FormWithConfirm';
import { deletePhotoTagGloballyAction } from '@/photo/actions'; import { deletePhotoTagGloballyAction } from '@/photo/actions';
import AdminTable from '@/admin/AdminTable'; import AdminTable from '@/admin/AdminTable';
import { Fragment } from 'react'; import { Fragment } from 'react';
import DeleteButton from '@/admin/DeleteButton'; import DeleteFormButton from '@/admin/DeleteFormButton';
import { photoQuantityText } from '@/photo'; import { photoQuantityText } from '@/photo';
import { Tags, formatTag, sortTagsObject } from '@/tag'; import { Tags, formatTag, sortTagsObject } from '@/tag';
import EditButton from '@/admin/EditButton'; import EditButton from '@/admin/EditButton';
@ -34,7 +34,7 @@ export default function AdminTagTable({
`Are you sure you want to remove "${formatTag(tag)}" from ${photoQuantityText(count, false).toLowerCase()}?`} `Are you sure you want to remove "${formatTag(tag)}" from ${photoQuantityText(count, false).toLowerCase()}?`}
> >
<input type="hidden" name="tag" value={tag} /> <input type="hidden" name="tag" value={tag} />
<DeleteButton clearLocalState /> <DeleteFormButton clearLocalState />
</FormWithConfirm> </FormWithConfirm>
</div> </div>
</Fragment>)} </Fragment>)}

View File

@ -9,7 +9,7 @@ import { pathForAdminUploadUrl } from '@/site/paths';
import AddButton from './AddButton'; import AddButton from './AddButton';
import FormWithConfirm from '@/components/FormWithConfirm'; import FormWithConfirm from '@/components/FormWithConfirm';
import { deleteBlobPhotoAction } from '@/photo/actions'; import { deleteBlobPhotoAction } from '@/photo/actions';
import DeleteButton from './DeleteButton'; import DeleteFormButton from './DeleteFormButton';
import { UrlAddStatus } from './AdminUploadsClient'; import { UrlAddStatus } from './AdminUploadsClient';
import ResponsiveDate from '@/components/ResponsiveDate'; import ResponsiveDate from '@/components/ResponsiveDate';
@ -102,7 +102,7 @@ export default function AdminUploadsTable({
value={url} value={url}
readOnly readOnly
/> />
<DeleteButton /> <DeleteFormButton />
</FormWithConfirm> </FormWithConfirm>
</>} </>}
</span> </span>

View File

@ -6,7 +6,7 @@ import { clsx } from 'clsx/lite';
import { ComponentProps, useCallback } from 'react'; import { ComponentProps, useCallback } from 'react';
import { BiTrash } from 'react-icons/bi'; import { BiTrash } from 'react-icons/bi';
export default function DeleteButton ( export default function DeleteFormButton (
props: ComponentProps<typeof SubmitButtonWithStatus> & { props: ComponentProps<typeof SubmitButtonWithStatus> & {
clearLocalState?: boolean clearLocalState?: boolean
} }

View File

@ -0,0 +1,21 @@
'use client';
import { deleteConfirmationTextForPhoto, Photo, titleForPhoto } from '@/photo';
import DeletePhotosButton from './DeletePhotosButton';
import { ComponentProps } from 'react';
export default function DeletePhotoButton({
photo,
...rest
}: {
photo: Photo
} & ComponentProps<typeof DeletePhotosButton>) {
return (
<DeletePhotosButton
{...rest}
photoIds={[photo.id]}
confirmText={deleteConfirmationTextForPhoto(photo)}
toastText={`"${titleForPhoto(photo)}" deleted`}
/>
);
}

View File

@ -3,6 +3,7 @@
import LoaderButton from '@/components/primitives/LoaderButton'; import LoaderButton from '@/components/primitives/LoaderButton';
import { photoQuantityText } from '@/photo'; import { photoQuantityText } from '@/photo';
import { deletePhotosAction } from '@/photo/actions'; import { deletePhotosAction } from '@/photo/actions';
import { useAppState } from '@/state/AppState';
import { toastSuccess, toastWarning } from '@/toast'; import { toastSuccess, toastWarning } from '@/toast';
import { clsx } from 'clsx/lite'; import { clsx } from 'clsx/lite';
import { ComponentProps, useState } from 'react'; import { ComponentProps, useState } from 'react';
@ -11,16 +12,23 @@ import { BiTrash } from 'react-icons/bi';
export default function DeletePhotosButton({ export default function DeletePhotosButton({
photoIds = [], photoIds = [],
onDelete, onDelete,
clearLocalState = true,
className, className,
confirmText,
toastText,
...rest ...rest
}: { }: {
photoIds?: string[] photoIds?: string[]
onDelete?: () => void onDelete?: () => void
clearLocalState?: boolean
toastText?: string
} & ComponentProps<typeof LoaderButton>) { } & ComponentProps<typeof LoaderButton>) {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const photosText = photoQuantityText(photoIds.length, false); const photosText = photoQuantityText(photoIds.length, false);
const { invalidateSwr, registerAdminUpdate } = useAppState();
return ( return (
<LoaderButton <LoaderButton
{...rest} {...rest}
@ -37,12 +45,16 @@ export default function DeletePhotosButton({
)} )}
isLoading={isLoading} isLoading={isLoading}
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
confirmText={`Are you sure you want to delete ${photosText}? This action cannot be undone.`} confirmText={confirmText ?? `Are you sure you want to delete ${photosText}? This action cannot be undone.`}
onClick={() => { onClick={() => {
setIsLoading(true); setIsLoading(true);
deletePhotosAction(photoIds) deletePhotosAction(photoIds)
.then(() => { .then(() => {
toastSuccess(`${photosText} deleted`); toastSuccess(toastText ?? `${photosText} deleted`);
if (clearLocalState) {
invalidateSwr?.();
registerAdminUpdate?.();
}
onDelete?.(); onDelete?.();
}) })
.catch(() => toastWarning(`Failed to delete ${photosText}`)) .catch(() => toastWarning(`Failed to delete ${photosText}`))

View File

@ -260,14 +260,6 @@ export const deletePhotoAction = async (
} }
}); });
export const deletePhotoFormAction = async (formData: FormData) =>
runAuthenticatedAdminServerAction(() =>
deletePhotoAction(
formData.get('id') as string,
formData.get('url') as string,
)
);
export const deletePhotoTagGloballyAction = async (formData: FormData) => export const deletePhotoTagGloballyAction = async (formData: FormData) =>
runAuthenticatedAdminServerAction(async () => { runAuthenticatedAdminServerAction(async () => {
const tag = formData.get('tag') as string; const tag = formData.get('tag') as string;