From 4766945b5398fc0313f8ab9e5cdc71c211570fed Mon Sep 17 00:00:00 2001 From: kim Date: Tue, 24 Sep 2024 15:26:28 +0200 Subject: [PATCH 1/2] fix: define container for drag selection --- src/components/item/FolderContent.tsx | 48 +++++++------ src/components/main/list/ItemsTable.tsx | 11 ++- src/components/main/list/SelectionContext.tsx | 6 +- src/components/main/list/useDragSelection.tsx | 13 +++- src/components/pages/PageWrapper.tsx | 25 +++++-- src/components/pages/RecycledItemsScreen.tsx | 67 +++++++++++-------- src/components/pages/home/HomeScreen.tsx | 16 +++-- 7 files changed, 122 insertions(+), 64 deletions(-) diff --git a/src/components/item/FolderContent.tsx b/src/components/item/FolderContent.tsx index d0fa2a453..23a082687 100644 --- a/src/components/item/FolderContent.tsx +++ b/src/components/item/FolderContent.tsx @@ -49,6 +49,8 @@ type Props = { canWrite?: boolean; }; +const CONTAINER_ID = 'items-container-id'; + const Content = ({ item, searchText, @@ -60,7 +62,7 @@ const Content = ({ const { itemTypes } = useFilterItemsContext(); const { selectedIds, clearSelection, toggleSelection } = useSelectionContext(); - const DragSelection = useDragSelection(); + const DragSelection = useDragSelection({ containerId: CONTAINER_ID }); if (mode === ItemLayoutMode.Map) { return ( @@ -73,24 +75,32 @@ const Content = ({ if (items?.length) { return ( <> - - {Boolean(canWrite && !searchText && !itemTypes?.length) && ( - - - - )} + + + {Boolean(canWrite && !searchText && !itemTypes?.length) && ( + + + + )} + {DragSelection} ); diff --git a/src/components/main/list/ItemsTable.tsx b/src/components/main/list/ItemsTable.tsx index a00ea3749..a27cbbb04 100644 --- a/src/components/main/list/ItemsTable.tsx +++ b/src/components/main/list/ItemsTable.tsx @@ -105,11 +105,16 @@ const ItemsTable = ({ return; } + // silent error, happens when you want to cancel the operation + if (movedItem.id === targetItem.id) { + console.error('cannot move target into itself'); + return; + } + // cannot move item into itself, or target cannot be part of selection if moving selection if ( - movedItem.id === targetItem.id || - (selectedIds.includes(movedItem?.id) && - selectedIds.includes(targetItem.id)) + selectedIds.includes(movedItem?.id) && + selectedIds.includes(targetItem.id) ) { toast.error(translateMessage(FAILURE_MESSAGES.INVALID_MOVE_TARGET)); return; diff --git a/src/components/main/list/SelectionContext.tsx b/src/components/main/list/SelectionContext.tsx index 4101847a5..7f0da2947 100644 --- a/src/components/main/list/SelectionContext.tsx +++ b/src/components/main/list/SelectionContext.tsx @@ -7,6 +7,8 @@ import { useState, } from 'react'; +import { Stack } from '@mui/material'; + type SelectionContextValue = { selectedIds: string[]; toggleSelection: (id: string) => void; @@ -74,7 +76,9 @@ export const SelectionContextProvider = ({ return ( -
{children}
+ + {children} +
); }; diff --git a/src/components/main/list/useDragSelection.tsx b/src/components/main/list/useDragSelection.tsx index dea70fbc7..b75c12876 100644 --- a/src/components/main/list/useDragSelection.tsx +++ b/src/components/main/list/useDragSelection.tsx @@ -14,7 +14,11 @@ import { useSelectionContext } from './SelectionContext'; export const useDragSelection = ({ elementClass = ITEM_CARD_CLASS, -} = {}): JSX.Element => { + containerId, +}: { + containerId: string; + elementClass?: string; +}): JSX.Element => { const { addToSelection, clearSelection } = useSelectionContext(); const [boundingBox, setBoundingBox] = useState { - // does not trigger drag selection if mousedown on card if (e instanceof HTMLElement || e instanceof SVGElement) { + // does not trigger if click is outside of container + if (!e.closest(`#${containerId}`)) { + return false; + } + + // does not trigger drag selection if mousedown on card return !e?.closest(`.${elementClass}`); } return true; diff --git a/src/components/pages/PageWrapper.tsx b/src/components/pages/PageWrapper.tsx index 39d0e1bb4..fb3eee150 100644 --- a/src/components/pages/PageWrapper.tsx +++ b/src/components/pages/PageWrapper.tsx @@ -19,14 +19,25 @@ const PageWrapper = ({ {title} - - - - {title} - - {options} + + + + + {title} + + {options} + + {children} - {children} ); diff --git a/src/components/pages/RecycledItemsScreen.tsx b/src/components/pages/RecycledItemsScreen.tsx index a212266d4..99c88a5f1 100644 --- a/src/components/pages/RecycledItemsScreen.tsx +++ b/src/components/pages/RecycledItemsScreen.tsx @@ -29,6 +29,8 @@ import { useSorting, useTranslatedSortingOptions } from '../table/useSorting'; import PageWrapper from './PageWrapper'; import RecycleBinToolbar from './recycleBin/RecycleBinSelectionToolbar'; +const CONTAINER_ID = 'recycle-items-container'; + const RecycledItemsScreenContent = ({ searchText, }: { @@ -52,14 +54,14 @@ const RecycledItemsScreenContent = ({ ?.sort(sortFn); const { selectedIds, toggleSelection } = useSelectionContext(); - const DragSelection = useDragSelection(); + const DragSelection = useDragSelection({ containerId: CONTAINER_ID }); // render this when there is data from the query if (recycledItems?.length) { const hasSelection = selectedIds.length && filteredData?.length; return ( <> - + )} - { - // render the filtered data and when it is empty display that nothing matches the search - filteredData?.length ? ( - filteredData.map((item) => ( - toggleSelection(item.id)} - isSelected={selectedIds.includes(item.id)} - showThumbnail={false} - allowNavigation={false} - footer={ - - - - - } - /> - )) - ) : ( - - {translateBuilder(BUILDER.TRASH_NO_ITEM_SEARCH, { - search: searchText, - })} - - ) - } + + { + // render the filtered data and when it is empty display that nothing matches the search + filteredData?.length ? ( + filteredData.map((item) => ( + toggleSelection(item.id)} + isSelected={selectedIds.includes(item.id)} + showThumbnail={false} + allowNavigation={false} + footer={ + + + + + } + /> + )) + ) : ( + + {translateBuilder(BUILDER.TRASH_NO_ITEM_SEARCH, { + search: searchText, + })} + + ) + } + {DragSelection} diff --git a/src/components/pages/home/HomeScreen.tsx b/src/components/pages/home/HomeScreen.tsx index 64fd7b315..0f76f3332 100644 --- a/src/components/pages/home/HomeScreen.tsx +++ b/src/components/pages/home/HomeScreen.tsx @@ -46,6 +46,8 @@ import NoItemFilters from '../NoItemFilters'; import PageWrapper from '../PageWrapper'; import HomeSelectionToolbar from './HomeSelectionToolbar'; +const CONTAINER_ID = 'home-items-container'; + const HomeScreenContent = ({ searchText }: { searchText: string }) => { const { t: translateBuilder } = useBuilderTranslation(); const { t: translateEnums } = useEnumsTranslation(); @@ -75,7 +77,7 @@ const HomeScreenContent = ({ searchText }: { searchText: string }) => { { pageSize: ITEM_PAGE_SIZE }, ); - const DragSelection = useDragSelection(); + const DragSelection = useDragSelection({ containerId: CONTAINER_ID }); const onShowOnlyMeChange: ShowOnlyMeChangeType = (checked) => { setShowOnlyMe(checked); @@ -105,7 +107,13 @@ const HomeScreenContent = ({ searchText }: { searchText: string }) => { ? data.pages.map(({ data: d }) => d.length).reduce((a, b) => a + b, 0) : 0; content = ( - <> + { )} - + ); } else if (itemTypes.length || searchText) { content = ; @@ -182,7 +190,7 @@ const HomeScreenContent = ({ searchText }: { searchText: string }) => { )} - + {content} {data && isFetching && ( From 8ac8fed126fc6ec0abad7c9fa95ce24b52db125e Mon Sep 17 00:00:00 2001 From: kim Date: Fri, 27 Sep 2024 09:47:02 +0200 Subject: [PATCH 2/2] refactor: apply PR requested changes --- src/components/item/FolderContent.tsx | 15 +++++------ src/components/main/list/useDragSelection.tsx | 26 ++++++++++++++++++- src/components/pages/RecycledItemsScreen.tsx | 16 +++++------- src/components/pages/home/HomeScreen.tsx | 15 +++++------ 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/components/item/FolderContent.tsx b/src/components/item/FolderContent.tsx index 23a082687..975814933 100644 --- a/src/components/item/FolderContent.tsx +++ b/src/components/item/FolderContent.tsx @@ -29,7 +29,10 @@ import { SelectionContextProvider, useSelectionContext, } from '../main/list/SelectionContext'; -import { useDragSelection } from '../main/list/useDragSelection'; +import { + DragContainerStack, + useDragSelection, +} from '../main/list/useDragSelection'; import { DesktopMap } from '../map/DesktopMap'; import NoItemFilters from '../pages/NoItemFilters'; import { OutletType } from '../pages/item/type'; @@ -75,13 +78,7 @@ const Content = ({ if (items?.length) { return ( <> - + )} - + {DragSelection} ); diff --git a/src/components/main/list/useDragSelection.tsx b/src/components/main/list/useDragSelection.tsx index b75c12876..f7b7ee989 100644 --- a/src/components/main/list/useDragSelection.tsx +++ b/src/components/main/list/useDragSelection.tsx @@ -1,4 +1,6 @@ -import { useState } from 'react'; +import { ReactNode, useState } from 'react'; + +import { Stack } from '@mui/material'; import { PRIMARY_COLOR } from '@graasp/ui'; @@ -12,6 +14,28 @@ import { ITEM_CARD_CLASS } from '@/config/selectors'; import { useSelectionContext } from './SelectionContext'; +export const DragContainerStack = ({ + gap, + id, + children, +}: { + gap?: number; + id: string; + children: ReactNode; +}): JSX.Element => ( + + {children} + +); + export const useDragSelection = ({ elementClass = ITEM_CARD_CLASS, containerId, diff --git a/src/components/pages/RecycledItemsScreen.tsx b/src/components/pages/RecycledItemsScreen.tsx index 99c88a5f1..0e219fbaa 100644 --- a/src/components/pages/RecycledItemsScreen.tsx +++ b/src/components/pages/RecycledItemsScreen.tsx @@ -21,7 +21,10 @@ import { SelectionContextProvider, useSelectionContext, } from '../main/list/SelectionContext'; -import { useDragSelection } from '../main/list/useDragSelection'; +import { + DragContainerStack, + useDragSelection, +} from '../main/list/useDragSelection'; import ItemCard from '../table/ItemCard'; import SortingSelect from '../table/SortingSelect'; import { SortingOptions } from '../table/types'; @@ -93,14 +96,7 @@ const RecycledItemsScreenContent = ({ )} - + { // render the filtered data and when it is empty display that nothing matches the search filteredData?.length ? ( @@ -127,7 +123,7 @@ const RecycledItemsScreenContent = ({ ) } - + {DragSelection} diff --git a/src/components/pages/home/HomeScreen.tsx b/src/components/pages/home/HomeScreen.tsx index 0f76f3332..4c858b336 100644 --- a/src/components/pages/home/HomeScreen.tsx +++ b/src/components/pages/home/HomeScreen.tsx @@ -17,7 +17,10 @@ import { SelectionContextProvider, useSelectionContext, } from '@/components/main/list/SelectionContext'; -import { useDragSelection } from '@/components/main/list/useDragSelection'; +import { + DragContainerStack, + useDragSelection, +} from '@/components/main/list/useDragSelection'; import { ITEM_PAGE_SIZE } from '@/config/constants'; import { ShowOnlyMeChangeType } from '@/config/types'; import { ItemLayoutMode, Ordering } from '@/enums'; @@ -107,13 +110,7 @@ const HomeScreenContent = ({ searchText }: { searchText: string }) => { ? data.pages.map(({ data: d }) => d.length).reduce((a, b) => a + b, 0) : 0; content = ( - + { )} - + ); } else if (itemTypes.length || searchText) { content = ;