Refine states for batch upload actions

This commit is contained in:
Sam Becker 2025-03-07 21:33:33 -06:00
parent 021e107cad
commit 0070e0d03e
7 changed files with 81 additions and 47 deletions

View File

@ -1,14 +1,12 @@
import { BiImageAdd } from 'react-icons/bi';
import PathLoaderButton from '@/components/primitives/PathLoaderButton';
export default function AddButton({
path,
}: {
path: string,
}) {
import { ComponentProps } from 'react';
export default function AddButton(
props: ComponentProps<typeof PathLoaderButton>,
) {
return (
<PathLoaderButton
path={path}
{...props}
icon={<BiImageAdd size={18} className="translate-x-[1px]" />}
>
Add

View File

@ -135,7 +135,7 @@ export default function AdminAppConfigurationClient({
renderSubStatus(
type,
renderEnvVars([variable]),
'translate-y-[4.5px]',
'translate-y-[7px]',
);
const renderError = ({
@ -534,6 +534,7 @@ export default function AdminAppConfigurationClient({
status={hasCategoryVisibility}
optional
>
<div className="my-1">
{categoryVisibility.map((category, index) =>
<Fragment key={category}>
{renderSubStatus(
@ -557,7 +558,8 @@ export default function AdminAppConfigurationClient({
</span>,
)}
</Fragment>)}
Configure photo category visibility and order
</div>
Configure order and visibility of categories
(seen in grid sidebar and CMD-K results)
by storing comma-separated values
(default: {`"${DEFAULT_CATEGORY_KEYS.join(',')}"`}):

View File

@ -24,18 +24,22 @@ import { useAppState } from '@/state/AppState';
const UPLOAD_BATCH_SIZE = 4;
export default function AdminAddAllUploads({
export default function AdminBatchUploadActions({
storageUrls,
uniqueTags,
isAdding,
setIsAdding,
setUrlAddStatuses,
isDeleting,
setIsDeleting,
}: {
storageUrls: string[]
uniqueTags?: Tags
isAdding: boolean
setIsAdding: (isAdding: boolean) => void
setIsAdding: Dispatch<SetStateAction<boolean>>
setUrlAddStatuses: Dispatch<SetStateAction<UrlAddStatus[]>>
isDeleting: boolean
setIsDeleting: Dispatch<SetStateAction<boolean>>
}) {
const { updateAdminData } = useAppState();
@ -141,7 +145,11 @@ export default function AdminAddAllUploads({
className="w-full justify-center"
progress={addingProgress}
isLoading={isAdding}
disabled={Boolean(tagErrorMessage) || isAddingComplete}
disabled={
Boolean(tagErrorMessage) ||
isAddingComplete ||
isDeleting
}
icon={isAddingComplete
? <BiCheckCircle size={18} className="translate-x-[1px]" />
: <BiImageAdd
@ -187,13 +195,19 @@ export default function AdminAddAllUploads({
</ProgressButton>
<DeleteUploadButton
urls={storageUrls}
onDelete={() => {
onDeleteStart={() => setIsDeleting(true)}
onDelete={didFail => {
if (!didFail) {
updateAdminData?.({ uploadsCount: 0 });
router.push(PATH_ADMIN_PHOTOS);
} else {
setIsDeleting(false);
}
}}
className="w-full flex justify-center"
shouldRedirectToAdminPhotos
hideTextOnMobile={false}
disabled={isAdding}
>
Delete All Uploads
</DeleteUploadButton>

View File

@ -1,7 +1,7 @@
'use client';
import { StorageListResponse } from '@/platforms/storage';
import AdminAddAllUploads from './AdminAddAllUploads';
import AdminBatchUploadActions from './AdminBatchUploadActions';
import { useMemo, useState } from 'react';
import { Tags } from '@/tag';
import AdminUploadsTable from './AdminUploadsTable';
@ -23,20 +23,28 @@ export default function AdminUploadsClient({
}) {
const [isAdding, setIsAdding] = useState(false);
const [urlAddStatuses, setUrlAddStatuses] = useState<UrlAddStatus[]>(urls);
const storageUrls = useMemo(() => urls.map(({ url }) => url), [urls]);
const [isDeleting, setIsDeleting] = useState(false);
return (
<div className="space-y-4">
{(urls.length > 1 || isAdding) &&
<AdminAddAllUploads {...{
<AdminBatchUploadActions {...{
storageUrls,
uniqueTags,
isAdding,
setIsAdding,
setUrlAddStatuses,
isDeleting,
setIsDeleting,
}} />}
<AdminUploadsTable {...{ isAdding, urlAddStatuses, setUrlAddStatuses }} />
<AdminUploadsTable {...{
isAdding,
urlAddStatuses,
setUrlAddStatuses,
isDeleting,
}} />
</div>
);
}

View File

@ -15,10 +15,12 @@ export default function AdminUploadsTable({
isAdding,
urlAddStatuses,
setUrlAddStatuses,
isDeleting,
}: {
isAdding?: boolean
urlAddStatuses: UrlAddStatus[]
setUrlAddStatuses?: (urlAddStatuses: UrlAddStatus[]) => void
isDeleting?: boolean
}) {
const isComplete = urlAddStatuses.every(({ status }) => status === 'added');
@ -85,13 +87,17 @@ export default function AdminUploadsTable({
</span>}
</>
: <>
<AddButton path={pathForAdminUploadUrl(url)} />
<AddButton
path={pathForAdminUploadUrl(url)}
disabled={isDeleting}
/>
<DeleteBlobButton
urls={[url]}
shouldRedirectToAdminPhotos={urlAddStatuses.length <= 1}
onDelete={() => setUrlAddStatuses?.(urlAddStatuses.filter(
({ url: urlToRemove }) => urlToRemove !== url,
))}
isLoading={isDeleting}
/>
</>}
</span>

View File

@ -16,6 +16,7 @@ export default function DeleteButton({
className={clsx(
'text-red-500! dark:text-red-500!',
'active:bg-red-100/50! dark:active:bg-red-950/50!',
'disabled:text-red-500/60! dark:disabled:text-red-500/60!',
'disabled:bg-red-100/50! dark:disabled:bg-red-950/50!',
'border-red-200! hover:border-red-300!',
'dark:border-red-900/75! dark:hover:border-red-900!',

View File

@ -4,34 +4,36 @@ import { deleteUploadsAction } from '@/photo/actions';
import DeleteButton from './DeleteButton';
import { useRouter } from 'next/navigation';
import { PATH_ADMIN_PHOTOS } from '@/app/paths';
import { ReactNode, useState } from 'react';
import { ComponentProps, useState } from 'react';
import LoaderButton from '@/components/primitives/LoaderButton';
export default function DeleteUploadButton({
urls,
shouldRedirectToAdminPhotos,
onDeleteStart,
onDelete,
hideTextOnMobile,
children,
className,
isLoading,
...props
}: {
urls: string[]
shouldRedirectToAdminPhotos?: boolean
onDelete?: () => void
hideTextOnMobile?: boolean
children?: ReactNode
className?: string
}) {
onDeleteStart?: () => void
onDelete?: (didFail?: boolean) => void
} & ComponentProps<typeof LoaderButton>) {
const router = useRouter();
const [isDeleting, setIsDeleting] = useState(false);
return (
<DeleteButton
className={className}
{...props}
confirmText={urls.length === 1
? 'Are you sure you want to delete this upload?'
: `Are you sure you want to delete all ${urls.length} uploads?`}
onClick={() => {
onDeleteStart?.();
setIsDeleting(true);
deleteUploadsAction(urls)
.then(() => {
@ -42,9 +44,12 @@ export default function DeleteUploadButton({
setIsDeleting(false);
}
})
.catch(() => setIsDeleting(false));
.catch(() => {
setIsDeleting(false);
onDelete?.(true);
});
}}
isLoading={isDeleting}
isLoading={isLoading ?? isDeleting}
hideTextOnMobile={hideTextOnMobile}
>
{children}