Add delete functionality to multi-select
This commit is contained in:
parent
6ccb1533d2
commit
50024bd115
@ -6,7 +6,6 @@ import SiteGrid from '@/components/SiteGrid';
|
||||
import { useAppState } from '@/state/AppState';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { IoCloseSharp } from 'react-icons/io5';
|
||||
import DeleteButton from './DeleteButton';
|
||||
import { useState } from 'react';
|
||||
import { Tags } from '@/tag';
|
||||
import { usePathname } from 'next/navigation';
|
||||
@ -14,6 +13,7 @@ import { PATH_GRID_INFERRED } from '@/site/paths';
|
||||
import PhotoTagFieldset from './PhotoTagFieldset';
|
||||
import { tagMultiplePhotosAction } from '@/photo/actions';
|
||||
import { toastSuccess } from '@/toast';
|
||||
import DeletePhotosButton from './DeletePhotosButton';
|
||||
|
||||
export default function AdminBatchEditPanelClient({
|
||||
uniqueTags,
|
||||
@ -96,7 +96,11 @@ export default function AdminBatchEditPanelClient({
|
||||
>
|
||||
Tag ...
|
||||
</LoaderButton>
|
||||
<DeleteButton disabled={isLoading} />
|
||||
<DeletePhotosButton
|
||||
photoIds={selectedPhotoIds}
|
||||
disabled={isLoading}
|
||||
onDelete={resetForm}
|
||||
/>
|
||||
</>}
|
||||
<LoaderButton
|
||||
icon={<IoCloseSharp size={20} className="translate-y-[-1.5px]" />}
|
||||
|
||||
53
src/admin/DeletePhotosButton.tsx
Normal file
53
src/admin/DeletePhotosButton.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
'use client';
|
||||
|
||||
import LoaderButton from '@/components/primitives/LoaderButton';
|
||||
import { photoQuantityText } from '@/photo';
|
||||
import { deletePhotosAction } from '@/photo/actions';
|
||||
import { toastSuccess, toastWarning } from '@/toast';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import { ComponentProps, useState } from 'react';
|
||||
import { BiTrash } from 'react-icons/bi';
|
||||
|
||||
export default function DeletePhotosButton({
|
||||
photoIds = [],
|
||||
onDelete,
|
||||
className,
|
||||
...rest
|
||||
}: {
|
||||
photoIds?: string[]
|
||||
onDelete?: () => void
|
||||
} & ComponentProps<typeof LoaderButton>) {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const photosText = photoQuantityText(photoIds.length, false);
|
||||
|
||||
return (
|
||||
<LoaderButton
|
||||
{...rest}
|
||||
title="Delete"
|
||||
icon={<BiTrash size={16} />}
|
||||
spinnerColor="text"
|
||||
className={clsx(
|
||||
'!text-red-500 dark:!text-red-600',
|
||||
'active:!bg-red-100/50 active:dark:!bg-red-950/50',
|
||||
'disabled:!bg-red-100/50 disabled:dark:!bg-red-950/50',
|
||||
'!border-red-200 hover:!border-red-300',
|
||||
'dark:!border-red-900/75 dark:hover:!border-red-900',
|
||||
className,
|
||||
)}
|
||||
isLoading={isLoading}
|
||||
// eslint-disable-next-line max-len
|
||||
confirmText={`Are you sure you want to delete ${photosText}? This action cannot be undone.`}
|
||||
onClick={() => {
|
||||
setIsLoading(true);
|
||||
deletePhotosAction(photoIds)
|
||||
.then(() => {
|
||||
toastSuccess(`${photosText} deleted`);
|
||||
onDelete?.();
|
||||
})
|
||||
.catch(() => toastWarning(`Failed to delete ${photosText}`))
|
||||
.finally(() => setIsLoading(false));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -59,7 +59,7 @@ export default function LoaderButton(props: {
|
||||
>
|
||||
{(icon || isLoading) &&
|
||||
<span className={clsx(
|
||||
'min-w-[1.25rem] max-h-4 overflow-hidden',
|
||||
'min-w-[1.25rem] max-h-5 overflow-hidden',
|
||||
styleAs === 'button' ? 'translate-y-[-0.5px]' : 'translate-y-[0.5px]',
|
||||
'inline-flex justify-center shrink-0',
|
||||
)}>
|
||||
@ -67,9 +67,7 @@ export default function LoaderButton(props: {
|
||||
? <Spinner
|
||||
size={14}
|
||||
color={spinnerColor}
|
||||
className={styleAs === 'button'
|
||||
? 'translate-y-[2px]'
|
||||
: 'translate-y-[0.5px]'}
|
||||
className="translate-y-[0.5px]"
|
||||
/>
|
||||
: icon}
|
||||
</span>}
|
||||
|
||||
@ -236,6 +236,17 @@ export const toggleFavoritePhotoAction = async (
|
||||
}
|
||||
});
|
||||
|
||||
export const deletePhotosAction = async (photoIds: string[]) =>
|
||||
runAuthenticatedAdminServerAction(async () => {
|
||||
for (const photoId of photoIds) {
|
||||
const photo = await getPhoto(photoId);
|
||||
if (photo) {
|
||||
await deletePhoto(photoId).then(() => deleteFile(photo.url));
|
||||
}
|
||||
}
|
||||
revalidateAllKeysAndPaths();
|
||||
});
|
||||
|
||||
export const deletePhotoAction = async (
|
||||
photoId: string,
|
||||
photoUrl: string,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user