Finalize batch select core behavior

This commit is contained in:
Sam Becker 2025-09-07 12:18:51 -05:00
parent 1f499e697e
commit db5f9ceb3a
5 changed files with 31 additions and 37 deletions

View File

@ -31,7 +31,6 @@ export default function AdminBatchEditPanelClient({
isSelectingPhotos, isSelectingPhotos,
stopSelectingPhotos, stopSelectingPhotos,
selectedPhotoIds, selectedPhotoIds,
setSelectedPhotoIds,
isPerformingSelectEdit, isPerformingSelectEdit,
setIsPerformingSelectEdit, setIsPerformingSelectEdit,
} = useSelectPhotosState(); } = useSelectPhotosState();
@ -42,12 +41,6 @@ export default function AdminBatchEditPanelClient({
const [tagErrorMessage, setTagErrorMessage] = useState(''); const [tagErrorMessage, setTagErrorMessage] = useState('');
const isInTagMode = tags !== undefined; const isInTagMode = tags !== undefined;
const resetForm = () => {
setSelectedPhotoIds?.([]);
setTags(undefined);
setTagErrorMessage('');
};
const photosText = photoQuantityText( const photosText = photoQuantityText(
selectedPhotoIds?.length ?? 0, selectedPhotoIds?.length ?? 0,
appText, appText,
@ -99,7 +92,7 @@ export default function AdminBatchEditPanelClient({
) )
.then(() => { .then(() => {
toastSuccess(`${photosText} tagged`); toastSuccess(`${photosText} tagged`);
resetForm(); stopSelectingPhotos?.();
}) })
.finally(() => setIsPerformingSelectEdit?.(false)); .finally(() => setIsPerformingSelectEdit?.(false));
}} }}
@ -119,7 +112,7 @@ export default function AdminBatchEditPanelClient({
photoIds={selectedPhotoIds} photoIds={selectedPhotoIds}
disabled={isFormDisabled} disabled={isFormDisabled}
onClick={() => setIsPerformingSelectEdit?.(true)} onClick={() => setIsPerformingSelectEdit?.(true)}
onDelete={resetForm} onDelete={stopSelectingPhotos}
onFinish={() => setIsPerformingSelectEdit?.(false)} onFinish={() => setIsPerformingSelectEdit?.(false)}
/> />
<LoaderButton <LoaderButton
@ -134,7 +127,7 @@ export default function AdminBatchEditPanelClient({
) )
.then(() => { .then(() => {
toastSuccess(`${photosText} favorited`); toastSuccess(`${photosText} favorited`);
resetForm(); stopSelectingPhotos?.();
}) })
.finally(() => setIsPerformingSelectEdit?.(false)); .finally(() => setIsPerformingSelectEdit?.(false));
}} }}

View File

@ -6,6 +6,7 @@ import { PARAM_SELECT, PATH_GRID_INFERRED } from '@/app/path';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { useAppState } from '@/app/AppState'; import { useAppState } from '@/app/AppState';
import useClientSearchParams from '@/utility/useClientSearchParams'; import useClientSearchParams from '@/utility/useClientSearchParams';
import { pushPathWithEvent } from '@/utility/url';
export const DATA_KEY_PHOTO_GRID = 'data-photo-grid'; export const DATA_KEY_PHOTO_GRID = 'data-photo-grid';
@ -21,7 +22,11 @@ export default function SelectPhotosProvider({
const searchParamsSelect = useClientSearchParams(PARAM_SELECT); const searchParamsSelect = useClientSearchParams(PARAM_SELECT);
const [canCurrentPageSelectPhotos, setCanCurrentPageSelectPhotos] = const [canCurrentPageSelectPhotos, setCanCurrentPageSelectPhotos] =
useState(true); useState(false);
const [selectedPhotoIds, setSelectedPhotoIds] =
useState<string[]>([]);
const [isPerformingSelectEdit, setIsPerformingSelectEdit] =
useState(false);
useEffect(() => { useEffect(() => {
setCanCurrentPageSelectPhotos(document setCanCurrentPageSelectPhotos(document
@ -33,32 +38,23 @@ export default function SelectPhotosProvider({
searchParamsSelect === 'true' searchParamsSelect === 'true'
, [isUserSignedIn, searchParamsSelect]); , [isUserSignedIn, searchParamsSelect]);
const startSelectingPhotos = useCallback(() => { const startSelectingPhotos = useCallback(() =>
window.history.pushState( pushPathWithEvent(canCurrentPageSelectPhotos
null, ? `${pathname}?${PARAM_SELECT}=true`
'', // Redirect to grid if current view does not support photo selection
canCurrentPageSelectPhotos : `${PATH_GRID_INFERRED}?${PARAM_SELECT}=true`)
? `${pathname}?${PARAM_SELECT}=true` , [canCurrentPageSelectPhotos, pathname]);
: `${PATH_GRID_INFERRED}?batch=true`,
);
dispatchEvent(new Event('pushstate'));
}, [canCurrentPageSelectPhotos, pathname]);
const stopSelectingPhotos = useCallback(() => { const stopSelectingPhotos = useCallback(() =>
window.history.pushState(null, '', pathname); pushPathWithEvent(pathname)
dispatchEvent(new Event('pushstate')); , [pathname]);
}, [pathname]);
useEffect(() => { useEffect(() => {
if (!isSelectingPhotos) { setSelectedPhotoIds([]); } if (!isSelectingPhotos) {
setSelectedPhotoIds([]);
}
}, [isSelectingPhotos]); }, [isSelectingPhotos]);
const [selectedPhotoIds, setSelectedPhotoIds] =
useState<string[]>([]);
const [isPerformingSelectEdit, setIsPerformingSelectEdit] =
useState(false);
return ( return (
<SelectPhotosContext.Provider value={{ <SelectPhotosContext.Provider value={{
canCurrentPageSelectPhotos, canCurrentPageSelectPhotos,

View File

@ -185,7 +185,6 @@ export default function CommandKClient({
isSelectingPhotos, isSelectingPhotos,
startSelectingPhotos, startSelectingPhotos,
stopSelectingPhotos, stopSelectingPhotos,
selectedPhotoIds,
} = useSelectPhotosState(); } = useSelectPhotosState();
const { const {
@ -646,9 +645,9 @@ export default function CommandKClient({
}); });
} }
adminSection.items.push({ adminSection.items.push({
label: selectedPhotoIds === undefined label: isSelectingPhotos
? appText.admin.batchEdit ? appText.admin.batchExitEdit
: appText.admin.batchExitEdit, : appText.admin.batchEdit,
annotation: <IconLock narrow />, annotation: <IconLock narrow />,
action: () => { action: () => {
if (!isSelectingPhotos) { if (!isSelectingPhotos) {

View File

@ -88,7 +88,7 @@ export default function PhotoGrid({
className={clsx( className={clsx(
'flex w-full h-full', 'flex w-full h-full',
// Prevent photo navigation when selecting // Prevent photo navigation when selecting
selectedPhotoIds?.length !== undefined && 'pointer-events-none', isSelectingPhotos && 'pointer-events-none',
)} )}
{...{ {...{
photo, photo,

View File

@ -41,3 +41,9 @@ export const downloadFileFromBrowser = async (
document.body.removeChild(link); document.body.removeChild(link);
window.URL.revokeObjectURL(downloadUrl); window.URL.revokeObjectURL(downloadUrl);
}; };
// Necessary for useClientSearchParams to see window.location changes
export const pushPathWithEvent = (pathname: string) => {
window.history.pushState(null, '', pathname);
dispatchEvent(new Event('pushstate'));
};