diff --git a/src/components/item/FolderContent.tsx b/src/components/item/FolderContent.tsx index d0fa2a453..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'; @@ -49,6 +52,8 @@ type Props = { canWrite?: boolean; }; +const CONTAINER_ID = 'items-container-id'; + const Content = ({ item, searchText, @@ -60,7 +65,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 +78,26 @@ 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..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,9 +14,35 @@ 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, -} = {}): 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..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'; @@ -29,6 +32,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 +57,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..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'; @@ -46,6 +49,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 +80,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 +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 = ; @@ -182,7 +187,7 @@ const HomeScreenContent = ({ searchText }: { searchText: string }) => { )} - + {content} {data && isFetching && (