Start batch editing from the current page (#303)
* Batch edit from the current page * Redirect to grid when batch editing a page without grid * Always clear selected ids on path change * Only clear ids when selecting * Use data-photo-grid to find grid * Update batch edit from command K * Not mount batch edit panel when not needed * Not clear selecting state when go to /grid * Use search param to force batch editing
This commit is contained in:
parent
784c641174
commit
91f99508f7
@ -57,20 +57,24 @@ export default function AdminAppMenu({
|
||||
clearAuthStateAndRedirectIfNecessary,
|
||||
} = useAppState();
|
||||
|
||||
const isSelecting = selectedPhotoIds !== undefined;
|
||||
|
||||
useEffect(() => {
|
||||
if (pathname !== PATH_GRID_INFERRED) {
|
||||
if (isSelecting) {
|
||||
setSelectedPhotoIds?.(undefined);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname, setSelectedPhotoIds]);
|
||||
|
||||
const appText = useAppText();
|
||||
|
||||
const isSelecting = selectedPhotoIds !== undefined;
|
||||
|
||||
const isAltPressed = useIsKeyBeingPressed('alt');
|
||||
|
||||
const showAppInsightsLink = photosCountTotal > 0 && !isAltPressed;
|
||||
|
||||
const currentPageHasGrid = () =>
|
||||
document.querySelector('[data-photo-grid]') !== null;
|
||||
|
||||
const sectionUpload: MoreMenuSection = useMemo(() => ({ items: [{
|
||||
label: appText.admin.uploadPhotos,
|
||||
icon: <IconUpload
|
||||
@ -165,8 +169,8 @@ export default function AdminAppMenu({
|
||||
size={16}
|
||||
className="translate-x-[-0.5px] translate-y-[0.5px]"
|
||||
/>,
|
||||
...pathname !== PATH_GRID_INFERRED && {
|
||||
href: PATH_GRID_INFERRED,
|
||||
...!currentPageHasGrid() && {
|
||||
href: `${PATH_GRID_INFERRED}?batch=true`,
|
||||
},
|
||||
action: () => {
|
||||
if (isSelecting) {
|
||||
@ -192,7 +196,6 @@ export default function AdminAppMenu({
|
||||
|
||||
return { items };
|
||||
}, [
|
||||
pathname,
|
||||
appText,
|
||||
isSelecting,
|
||||
photosCountNeedSync,
|
||||
|
||||
@ -8,8 +8,6 @@ import { clsx } from 'clsx/lite';
|
||||
import { IoCloseSharp } from 'react-icons/io5';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { TAG_FAVS, Tags } from '@/tag';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { PATH_GRID_INFERRED } from '@/app/path';
|
||||
import PhotoTagFieldset from './PhotoTagFieldset';
|
||||
import { tagMultiplePhotosAction } from '@/photo/actions';
|
||||
import { toastSuccess } from '@/toast';
|
||||
@ -28,8 +26,6 @@ export default function AdminBatchEditPanelClient({
|
||||
}) {
|
||||
const refNote = useRef<HTMLDivElement>(null);
|
||||
|
||||
const pathname = usePathname();
|
||||
|
||||
const {
|
||||
isUserSignedIn,
|
||||
selectedPhotoIds,
|
||||
@ -156,7 +152,7 @@ export default function AdminBatchEditPanelClient({
|
||||
|
||||
const shouldShowPanel =
|
||||
isUserSignedIn &&
|
||||
pathname === PATH_GRID_INFERRED &&
|
||||
document.querySelector('[data-photo-grid]') !== null &&
|
||||
selectedPhotoIds !== undefined;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -644,12 +644,18 @@ export default function CommandKClient({
|
||||
? appText.admin.batchEdit
|
||||
: appText.admin.batchExitEdit,
|
||||
annotation: <IconLock narrow />,
|
||||
path: selectedPhotoIds === undefined
|
||||
? PATH_GRID_INFERRED
|
||||
: undefined,
|
||||
action: selectedPhotoIds === undefined
|
||||
? () => setSelectedPhotoIds?.([])
|
||||
: () => setSelectedPhotoIds?.(undefined),
|
||||
action: () => {
|
||||
if (selectedPhotoIds === undefined) {
|
||||
const hasGrid = document.querySelector('[data-photo-grid]') !== null;
|
||||
if (!hasGrid) {
|
||||
router.push(`${PATH_GRID_INFERRED}?batch=true`);
|
||||
return;
|
||||
}
|
||||
setSelectedPhotoIds?.([]);
|
||||
} else {
|
||||
setSelectedPhotoIds?.(undefined);
|
||||
}
|
||||
},
|
||||
}, {
|
||||
label: <span className="flex items-center gap-3">
|
||||
{appText.admin.appInsights}
|
||||
|
||||
@ -8,7 +8,8 @@ import AnimateItems from '@/components/AnimateItems';
|
||||
import { GRID_ASPECT_RATIO } from '@/app/config';
|
||||
import { useAppState } from '@/app/AppState';
|
||||
import SelectTileOverlay from '@/components/SelectTileOverlay';
|
||||
import { ReactNode } from 'react';
|
||||
import { ReactNode, useEffect } from 'react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { GRID_GAP_CLASSNAME } from '@/components';
|
||||
|
||||
export default function PhotoGrid({
|
||||
@ -21,7 +22,6 @@ export default function PhotoGrid({
|
||||
staggerOnFirstLoadOnly = true,
|
||||
additionalTile,
|
||||
small,
|
||||
canSelect,
|
||||
onLastPhotoVisible,
|
||||
onAnimationComplete,
|
||||
...categories
|
||||
@ -35,7 +35,6 @@ export default function PhotoGrid({
|
||||
staggerOnFirstLoadOnly?: boolean
|
||||
additionalTile?: ReactNode
|
||||
small?: boolean
|
||||
canSelect?: boolean
|
||||
onLastPhotoVisible?: () => void
|
||||
onAnimationComplete?: () => void
|
||||
} & PhotoSetCategory) {
|
||||
@ -46,7 +45,22 @@ export default function PhotoGrid({
|
||||
isGridHighDensity,
|
||||
} = useAppState();
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
|
||||
// Check for batch editing parameter on mount
|
||||
useEffect(() => {
|
||||
if (searchParams.get('batch') === 'true') {
|
||||
setSelectedPhotoIds?.([]);
|
||||
// Clean up the URL parameter
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.delete('batch');
|
||||
router.replace(url.pathname + url.search);
|
||||
}
|
||||
}, [searchParams, setSelectedPhotoIds, router]);
|
||||
|
||||
return (
|
||||
<div data-photo-grid>
|
||||
<AnimateItems
|
||||
className={clsx(
|
||||
'grid',
|
||||
@ -96,7 +110,7 @@ export default function PhotoGrid({
|
||||
: undefined,
|
||||
}}
|
||||
/>
|
||||
{isUserSignedIn && canSelect && selectedPhotoIds !== undefined &&
|
||||
{isUserSignedIn && selectedPhotoIds !== undefined &&
|
||||
<SelectTileOverlay
|
||||
isSelected={isSelected}
|
||||
onSelectChange={() => setSelectedPhotoIds?.(isSelected
|
||||
@ -109,5 +123,6 @@ export default function PhotoGrid({
|
||||
itemKeys={photos.map(photo => photo.id)
|
||||
.concat(additionalTile ? ['more'] : [])}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -19,7 +19,6 @@ export default function PhotoGridContainer({
|
||||
animateOnFirstLoadOnly,
|
||||
header,
|
||||
sidebar,
|
||||
canSelect,
|
||||
...categories
|
||||
}: {
|
||||
cacheKey: string
|
||||
@ -34,7 +33,6 @@ export default function PhotoGridContainer({
|
||||
shouldAnimateDynamicItems,
|
||||
setShouldAnimateDynamicItems,
|
||||
] = useState(false);
|
||||
|
||||
const onAnimationComplete = useCallback(() =>
|
||||
setShouldAnimateDynamicItems(true), []);
|
||||
|
||||
@ -55,7 +53,6 @@ export default function PhotoGridContainer({
|
||||
...categories,
|
||||
animateOnFirstLoadOnly,
|
||||
onAnimationComplete,
|
||||
canSelect,
|
||||
}} />
|
||||
{count > photos.length &&
|
||||
<PhotoGridInfinite {...{
|
||||
@ -67,7 +64,6 @@ export default function PhotoGridContainer({
|
||||
...categories,
|
||||
canStart: shouldAnimateDynamicItems,
|
||||
animateOnFirstLoadOnly,
|
||||
canSelect,
|
||||
}} />}
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
@ -14,7 +14,6 @@ export default function PhotoGridInfinite({
|
||||
excludeFromFeeds,
|
||||
canStart,
|
||||
animateOnFirstLoadOnly,
|
||||
canSelect,
|
||||
...categories
|
||||
}: {
|
||||
cacheKey: string
|
||||
@ -40,7 +39,6 @@ export default function PhotoGridInfinite({
|
||||
canStart,
|
||||
onLastPhotoVisible,
|
||||
animateOnFirstLoadOnly,
|
||||
canSelect,
|
||||
}} />}
|
||||
</InfinitePhotoScroll>
|
||||
);
|
||||
|
||||
@ -60,7 +60,6 @@ export default function PhotoGridPageClient({
|
||||
}} />
|
||||
</MaskedScroll>
|
||||
}
|
||||
canSelect
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user