fix: selection is unified across the tool

Signed-off-by: Varun Raj <varun@skcript.com>
This commit is contained in:
Varun Raj
2025-08-23 17:24:00 +05:30
parent 0ea429578e
commit 53fa52cfd7
4 changed files with 44 additions and 16 deletions
+38 -12
View File
@@ -1,12 +1,13 @@
import "yet-another-react-lightbox/styles.css";
import { IAsset } from '@/types/asset';
import React, { useEffect, useMemo, useState } from 'react'
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react'
import Lightbox from 'yet-another-react-lightbox';
import { Gallery } from "react-grid-gallery";
import LazyGridImage from "../ui/lazy-grid-image";
import Download from "yet-another-react-lightbox/plugins/download";
import Video from "yet-another-react-lightbox/plugins/video";
import { usePhotoSelectionContext } from '@/contexts/PhotoSelectionContext';
interface AssetGridProps {
@@ -16,10 +17,31 @@ interface AssetGridProps {
onSelectionChange?: (ids: string[]) => void;
}
export default function AssetGrid({ assets, isInternal = true, selectable = false, onSelectionChange }: AssetGridProps) {
interface AssetGridRef {
getSelectedIds: () => string[];
selectAll: () => void;
unselectAll: () => void;
}
const AssetGrid = forwardRef<AssetGridRef, AssetGridProps>(({ assets, isInternal = true, selectable = false, onSelectionChange }, ref) => {
const [index, setIndex] = useState(-1);
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const [lastSelectedIndex, setLastSelectedIndex] = useState(-1);
// Use context for selection state
const { selectedIds, updateContext } = usePhotoSelectionContext();
useImperativeHandle(ref, () => ({
getSelectedIds: () => selectedIds,
selectAll: () => {
const allIds = assets.map((asset) => asset.id);
updateContext({ selectedIds: allIds });
onSelectionChange?.(allIds);
},
unselectAll: () => {
updateContext({ selectedIds: [] });
onSelectionChange?.([]);
},
}), [assets, selectedIds, updateContext]);
const handleClick = (index: number, asset: IAsset, event: React.MouseEvent<HTMLElement>) => {
@@ -35,8 +57,9 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals
event.stopPropagation();
const isPresent = selectedIds.includes(asset.id);
if (isPresent) {
setSelectedIds(selectedIds.filter((id) => id !== asset.id));
onSelectionChange?.(selectedIds.filter((id) => id !== asset.id));
const newSelectedIds = selectedIds.filter((id) => id !== asset.id);
updateContext({ selectedIds: newSelectedIds });
onSelectionChange?.(newSelectedIds);
} else {
const clickedIndex = images.findIndex((image) => {
return image.id === asset.id;
@@ -44,14 +67,15 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals
if (event.shiftKey) {
const startIndex = Math.min(clickedIndex, lastSelectedIndex);
const endIndex = Math.max(clickedIndex, lastSelectedIndex);
const newSelectedIds = images.slice(startIndex, endIndex + 1).map((image) => image.id);
const allSelectedIds = [...selectedIds, ...newSelectedIds];
const rangeSelectedIds = images.slice(startIndex, endIndex + 1).map((image) => image.id);
const allSelectedIds = [...selectedIds, ...rangeSelectedIds];
const uniqueSelectedIds = [...new Set(allSelectedIds)];
setSelectedIds(uniqueSelectedIds);
updateContext({ selectedIds: uniqueSelectedIds });
onSelectionChange?.(uniqueSelectedIds);
} else {
setSelectedIds([...selectedIds, asset.id]);
onSelectionChange?.([...selectedIds, asset.id]);
const newSelectedIds = [...selectedIds, asset.id];
updateContext({ selectedIds: newSelectedIds });
onSelectionChange?.(newSelectedIds);
}
setLastSelectedIndex(clickedIndex);
}
@@ -93,7 +117,7 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals
const handleEsc = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setSelectedIds([]);
updateContext({ selectedIds: [] });
onSelectionChange?.([]);
}
};
@@ -122,4 +146,6 @@ export default function AssetGrid({ assets, isInternal = true, selectable = fals
/>
</div>
);
}
})
AssetGrid.displayName = "AssetGrid";
export default AssetGrid;
+1 -1
View File
@@ -73,7 +73,7 @@ export const getAssetGeoHeatmap = async (filters: IHeatMapParams) => {
}
export const deleteAssets = async (ids: string[]) => {
return API.delete(UPDATE_ASSETS_PATH, { ids });
return API.delete(UPDATE_ASSETS_PATH, { ids, force: true });
}
export interface IEmptyVideosParams {
+4 -3
View File
@@ -150,6 +150,7 @@ export default function PotentialAlbums() {
{contextState.selectedIds.length} Selected
</p>
<div className="flex items-center gap-2">
{contextState.selectedIds.length === contextState.assets.length ? (
<Button
variant={"outline"}
size={"sm"}
@@ -161,8 +162,8 @@ export default function PotentialAlbums() {
>
Unselect all
</Button>
<Button
) : (
<Button
variant={"outline"}
size={"sm"}
onClick={() =>
@@ -170,10 +171,10 @@ export default function PotentialAlbums() {
selectedIds: contextState.assets.map((a) => a.id),
})
}
>
Select all
</Button>
)}
<AlbumSelectorDialog onSelected={handleSelect} onSubmit={handleCreate} />
<AssetOffsetDialog assets={selectedAssets} onComplete={handleOffsetComplete} />
<div className="h-[10px] w-[1px] bg-zinc-500 dark:bg-zinc-600"></div>
+1
View File
@@ -22,6 +22,7 @@ export default function EmptyVideosPage() {
const [assets, setAssets] = useState<IAsset[]>([])
const [loading, setLoading] = useState(false)
const [errorMessage, setErrorMessage] = useState('')
// Initialize filters from URL params or defaults
const getInitialFilters = () => {