From 65c32b331976db454e5bb8842b32a70d61c34972 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Sat, 7 May 2022 19:13:10 +0200 Subject: [PATCH] fix: library multiselect not accounting for published state (#5132) --- src/components/LibraryMenu.tsx | 47 +---------------- src/components/LibraryMenuItems.tsx | 79 +++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 61 deletions(-) diff --git a/src/components/LibraryMenu.tsx b/src/components/LibraryMenu.tsx index e2389836..025b893e 100644 --- a/src/components/LibraryMenu.tsx +++ b/src/components/LibraryMenu.tsx @@ -25,7 +25,6 @@ import "./LibraryMenu.scss"; import LibraryMenuItems from "./LibraryMenuItems"; import { EVENT } from "../constants"; import { KEYS } from "../keys"; -import { arrayToMap } from "../utils"; import { trackEvent } from "../analytics"; import { useAtom } from "jotai"; import { jotaiScope } from "../jotai"; @@ -225,10 +224,6 @@ export const LibraryMenu = ({ [setShowPublishLibraryDialog, setPublishLibSuccess, selectedItems, library], ); - const [lastSelectedItem, setLastSelectedItem] = useState< - LibraryItem["id"] | null - >(null); - if ( libraryItemsData.status === "loading" && !libraryItemsData.isInitialized @@ -284,47 +279,7 @@ export const LibraryMenu = ({ files={files} id={id} selectedItems={selectedItems} - onToggle={(id, event) => { - const shouldSelect = !selectedItems.includes(id); - - if (shouldSelect) { - if (event.shiftKey && lastSelectedItem) { - const rangeStart = libraryItemsData.libraryItems.findIndex( - (item) => item.id === lastSelectedItem, - ); - const rangeEnd = libraryItemsData.libraryItems.findIndex( - (item) => item.id === id, - ); - - if (rangeStart === -1 || rangeEnd === -1) { - setSelectedItems([...selectedItems, id]); - return; - } - - const selectedItemsMap = arrayToMap(selectedItems); - const nextSelectedIds = libraryItemsData.libraryItems.reduce( - (acc: LibraryItem["id"][], item, idx) => { - if ( - (idx >= rangeStart && idx <= rangeEnd) || - selectedItemsMap.has(item.id) - ) { - acc.push(item.id); - } - return acc; - }, - [], - ); - - setSelectedItems(nextSelectedIds); - } else { - setSelectedItems([...selectedItems, id]); - } - setLastSelectedItem(id); - } else { - setLastSelectedItem(null); - setSelectedItems(selectedItems.filter((_id) => _id !== id)); - } - }} + onSelectItems={(ids) => setSelectedItems(ids)} onPublish={() => setShowPublishLibraryDialog(true)} resetLibrary={resetLibrary} /> diff --git a/src/components/LibraryMenuItems.tsx b/src/components/LibraryMenuItems.tsx index 11aff36c..a97a9259 100644 --- a/src/components/LibraryMenuItems.tsx +++ b/src/components/LibraryMenuItems.tsx @@ -1,5 +1,5 @@ import { chunk } from "lodash"; -import { useCallback, useState } from "react"; +import React, { useCallback, useState } from "react"; import { importLibraryFromJSON, saveLibraryAsJSON } from "../data/json"; import Library from "../data/library"; import { ExcalidrawElement, NonDeleted } from "../element/types"; @@ -11,7 +11,7 @@ import { LibraryItem, LibraryItems, } from "../types"; -import { muteFSAbortError } from "../utils"; +import { arrayToMap, muteFSAbortError } from "../utils"; import { useDeviceType } from "./App"; import ConfirmDialog from "./ConfirmDialog"; import { exportToFileIcon, load, publishIcon, trash } from "./icons"; @@ -38,7 +38,7 @@ const LibraryMenuItems = ({ files, id, selectedItems, - onToggle, + onSelectItems, onPublish, resetLibrary, }: { @@ -55,7 +55,7 @@ const LibraryMenuItems = ({ library: Library; id: string; selectedItems: LibraryItem["id"][]; - onToggle: (id: LibraryItem["id"], event: React.MouseEvent) => void; + onSelectItems: (id: LibraryItem["id"][]) => void; onPublish: () => void; resetLibrary: () => void; }) => { @@ -192,6 +192,55 @@ const LibraryMenuItems = ({ (id) => libraryItems.find((item) => item.id === id)?.status === "published", ); + const [lastSelectedItem, setLastSelectedItem] = useState< + LibraryItem["id"] | null + >(null); + + const onItemSelectToggle = ( + id: LibraryItem["id"], + event: React.MouseEvent, + ) => { + const shouldSelect = !selectedItems.includes(id); + + const orderedItems = [...unpublishedItems, ...publishedItems]; + + if (shouldSelect) { + if (event.shiftKey && lastSelectedItem) { + const rangeStart = orderedItems.findIndex( + (item) => item.id === lastSelectedItem, + ); + const rangeEnd = orderedItems.findIndex((item) => item.id === id); + + if (rangeStart === -1 || rangeEnd === -1) { + onSelectItems([...selectedItems, id]); + return; + } + + const selectedItemsMap = arrayToMap(selectedItems); + const nextSelectedIds = orderedItems.reduce( + (acc: LibraryItem["id"][], item, idx) => { + if ( + (idx >= rangeStart && idx <= rangeEnd) || + selectedItemsMap.has(item.id) + ) { + acc.push(item.id); + } + return acc; + }, + [], + ); + + onSelectItems(nextSelectedIds); + } else { + onSelectItems([...selectedItems, id]); + } + setLastSelectedItem(id); + } else { + setLastSelectedItem(null); + onSelectItems(selectedItems.filter((_id) => _id !== id)); + } + }; + const createLibraryItemCompo = (params: { item: | LibraryItem @@ -212,9 +261,7 @@ const LibraryMenuItems = ({ onClick={params.onClick || (() => {})} id={params.item?.id || null} selected={!!params.item?.id && selectedItems.includes(params.item.id)} - onToggle={(id, event) => { - onToggle(id, event); - }} + onToggle={onItemSelectToggle} /> ); @@ -272,16 +319,12 @@ const LibraryMenuItems = ({ }); }; + const unpublishedItems = libraryItems.filter( + (item) => item.status !== "published", + ); const publishedItems = libraryItems.filter( (item) => item.status === "published", ); - const unpublishedItems = [ - // append pending library item - ...(pendingElements.length - ? [{ id: null, elements: pendingElements }] - : []), - ...libraryItems.filter((item) => item.status !== "published"), - ]; return (
@@ -310,7 +353,13 @@ const LibraryMenuItems = ({ > <>
{t("labels.personalLib")}
- {renderLibrarySection(unpublishedItems)} + {renderLibrarySection([ + // append pending library item + ...(pendingElements.length + ? [{ id: null, elements: pendingElements }] + : []), + ...unpublishedItems, + ])} <>