1 import { useCallback, useMemo, useState } from 'react';
3 import { isPhotoGroup } from '../../../../store/_photos';
4 import type { PhotoGroup } from '../../../../store/_photos/interface';
6 type SelectionItem = { linkId: string };
7 type SelectionGroup = PhotoGroup;
9 export const getGroupLinkIds = <T extends SelectionItem>(data: (T | SelectionGroup)[], groupIndex: number) => {
10 if (!isPhotoGroup(data[groupIndex])) {
14 const items: string[] = [];
16 for (let i = groupIndex + 1; i < data.length; i++) {
17 const current = data[i];
19 if (isPhotoGroup(current)) {
23 items.push(current.linkId);
29 type HandleSelectionArgs = {
31 isMultiSelect?: boolean;
34 export const usePhotosSelection = <T extends SelectionItem>(
35 data: (T | SelectionGroup)[],
36 photoLinkIdToIndexMap: Record<string, number>
38 const [selection, setSelection] = useState<Record<string, boolean>>({});
39 const [lastIndex, setLastIndex] = useState<number | undefined>();
41 const setSelected = useCallback(
42 (isSelected: boolean, ...linkIds: string[]) => {
43 setSelection((state) => {
44 let newState = { ...state };
46 linkIds.forEach((linkId) => {
48 newState[linkId] = true;
50 delete newState[linkId];
60 const clearSelection = useCallback(() => {
62 setLastIndex(undefined);
65 const handleSelection = useCallback(
66 (index: number, { isSelected, isMultiSelect }: HandleSelectionArgs) => {
67 const item = data[index];
69 if (isPhotoGroup(item)) {
70 const groupLinkIds = getGroupLinkIds(data, index);
71 setSelected(isSelected, ...groupLinkIds);
72 const lastIndexLinkId = groupLinkIds.shift();
73 setLastIndex(lastIndexLinkId ? photoLinkIdToIndexMap[lastIndexLinkId] : undefined);
75 if (isMultiSelect && lastIndex !== undefined) {
76 const startIndex = lastIndex < index ? lastIndex : index;
77 const endIndex = lastIndex < index ? index : lastIndex;
80 data.slice(startIndex, endIndex + 1).filter((item) => !isPhotoGroup(item)) as T[]
81 ).map((item) => item.linkId);
84 setSelected(true, ...items);
89 setSelected(isSelected, item.linkId);
92 [data, setSelected, photoLinkIdToIndexMap, lastIndex]
95 const selectedItems = useMemo(
97 Object.keys(selection).reduce<T[]>((acc, linkId) => {
98 const item = data[photoLinkIdToIndexMap[linkId]];
99 if (item && !isPhotoGroup(item)) {
105 [selection, data, photoLinkIdToIndexMap]
108 const isGroupSelected = useCallback(
109 (groupIndex: number) => {
110 let linkIds = getGroupLinkIds(data, groupIndex);
111 let selectedCount = 0;
113 for (let linkId of linkIds) {
114 if (selection[linkId]) {
116 } else if (selectedCount > 0) {
121 if (selectedCount === 0) {
125 return selectedCount === linkIds.length || 'some';
130 const isItemSelected = useCallback((linkId: string) => !!selection[linkId], [selection]);