diff --git a/src/admin/AddButton.tsx b/src/admin/AddButton.tsx index cba511a6..7feb9b4b 100644 --- a/src/admin/AddButton.tsx +++ b/src/admin/AddButton.tsx @@ -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, +) { return ( } > Add diff --git a/src/admin/AdminAppConfigurationClient.tsx b/src/admin/AdminAppConfigurationClient.tsx index b94d0e41..17db8d27 100644 --- a/src/admin/AdminAppConfigurationClient.tsx +++ b/src/admin/AdminAppConfigurationClient.tsx @@ -135,7 +135,7 @@ export default function AdminAppConfigurationClient({ renderSubStatus( type, renderEnvVars([variable]), - 'translate-y-[4.5px]', + 'translate-y-[7px]', ); const renderError = ({ @@ -534,30 +534,32 @@ export default function AdminAppConfigurationClient({ status={hasCategoryVisibility} optional > - {categoryVisibility.map((category, index) => - - {renderSubStatus( - 'checked', - <> - {index + 1} - {'.'} - {capitalize(category)} - , - )} - )} - {getHiddenDefaultCategories(categoryVisibility) - .map((category, index) => +
+ {categoryVisibility.map((category, index) => {renderSubStatus( - 'optional', - - {categoryVisibility.length + index + 1} + 'checked', + <> + {index + 1} {'.'} {capitalize(category)} - , + , )} )} - Configure photo category visibility and order + {getHiddenDefaultCategories(categoryVisibility) + .map((category, index) => + + {renderSubStatus( + 'optional', + + {categoryVisibility.length + index + 1} + {'.'} + {capitalize(category)} + , + )} + )} +
+ Configure order and visibility of categories (seen in grid sidebar and CMD-K results) by storing comma-separated values (default: {`"${DEFAULT_CATEGORY_KEYS.join(',')}"`}): diff --git a/src/admin/AdminAddAllUploads.tsx b/src/admin/AdminBatchUploadActions.tsx similarity index 90% rename from src/admin/AdminAddAllUploads.tsx rename to src/admin/AdminBatchUploadActions.tsx index f790ae5d..937910d6 100644 --- a/src/admin/AdminAddAllUploads.tsx +++ b/src/admin/AdminBatchUploadActions.tsx @@ -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> setUrlAddStatuses: Dispatch> + isDeleting: boolean + setIsDeleting: Dispatch> }) { 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 ? : { - updateAdminData?.({ uploadsCount: 0 }); - router.push(PATH_ADMIN_PHOTOS); + 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 diff --git a/src/admin/AdminUploadsClient.tsx b/src/admin/AdminUploadsClient.tsx index 89bb928e..062e4257 100644 --- a/src/admin/AdminUploadsClient.tsx +++ b/src/admin/AdminUploadsClient.tsx @@ -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(urls); - const storageUrls = useMemo(() => urls.map(({ url }) => url), [urls]); + const [isDeleting, setIsDeleting] = useState(false); + return (
{(urls.length > 1 || isAdding) && - } - +
); } diff --git a/src/admin/AdminUploadsTable.tsx b/src/admin/AdminUploadsTable.tsx index b16387a6..54a1375b 100644 --- a/src/admin/AdminUploadsTable.tsx +++ b/src/admin/AdminUploadsTable.tsx @@ -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({ } : <> - + setUrlAddStatuses?.(urlAddStatuses.filter( ({ url: urlToRemove }) => urlToRemove !== url, ))} + isLoading={isDeleting} /> } diff --git a/src/admin/DeleteButton.tsx b/src/admin/DeleteButton.tsx index df891d71..b404723e 100644 --- a/src/admin/DeleteButton.tsx +++ b/src/admin/DeleteButton.tsx @@ -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!', diff --git a/src/admin/DeleteUploadButton.tsx b/src/admin/DeleteUploadButton.tsx index 2faed481..0480512f 100644 --- a/src/admin/DeleteUploadButton.tsx +++ b/src/admin/DeleteUploadButton.tsx @@ -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) { const router = useRouter(); const [isDeleting, setIsDeleting] = useState(false); return ( { + 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}