From 8a516de691ef6432b27265799700a28aaafda230 Mon Sep 17 00:00:00 2001 From: Cristhian Zanforlin Lousa Date: Tue, 3 Dec 2024 17:18:37 -0300 Subject: [PATCH] refactor: Split folderSidebarComponent into modular components (#5000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ (index.tsx): Refactor SideBarFoldersButtonsComponent to improve code readability and maintainability. Add new functionalities such as drag and drop, folder hovering effects, and folder actions like upload, download, add, update, and delete. Update folder state management and handle loading states for various folder operations. * ✨ (add-folder-button.tsx): Add a new component for adding folders to the sidebar ✨ (folder-select-item.tsx): Add a new component for displaying folder select items in the sidebar ✨ (header-buttons.tsx): Add a new component for displaying header buttons in the sidebar ✨ (input-edit-folder-name.tsx): Add a new component for editing folder names in the sidebar ✨ (select-options.tsx): Add a new component for displaying select options in the sidebar ✨ (upload-folder-button.tsx): Add a new component for uploading folders to the sidebar ✨ (handle-select-change.ts): Add a new helper function for handling select changes in the sidebar 🔧 (index.tsx): Refactor sidebar folder buttons component to use new components and helpers for better organization and functionality --- .../components/add-folder-button.tsx | 27 ++ .../components/folder-select-item.tsx | 14 + .../components/header-buttons.tsx | 35 +++ .../components/input-edit-folder-name.tsx | 67 ++++ .../components/select-options.tsx | 80 +++++ .../components/upload-folder-button.tsx | 18 ++ .../helpers/handle-select-change.ts | 21 ++ .../components/sideBarFolderButtons/index.tsx | 296 +++++------------- 8 files changed, 337 insertions(+), 221 deletions(-) create mode 100644 src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/add-folder-button.tsx create mode 100644 src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/folder-select-item.tsx create mode 100644 src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx create mode 100644 src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/input-edit-folder-name.tsx create mode 100644 src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx create mode 100644 src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/upload-folder-button.tsx create mode 100644 src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/helpers/handle-select-change.ts diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/add-folder-button.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/add-folder-button.tsx new file mode 100644 index 000000000..ac4de9567 --- /dev/null +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/add-folder-button.tsx @@ -0,0 +1,27 @@ +import IconComponent from "@/components/common/genericIconComponent"; +import ShadTooltip from "@/components/common/shadTooltipComponent"; +import { Button } from "@/components/ui/button"; + +export const AddFolderButton = ({ + onClick, + disabled, + loading, +}: { + onClick: () => void; + disabled: boolean; + loading: boolean; +}) => ( + + + +); diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/folder-select-item.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/folder-select-item.tsx new file mode 100644 index 000000000..33afc8211 --- /dev/null +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/folder-select-item.tsx @@ -0,0 +1,14 @@ +import IconComponent from "@/components/common/genericIconComponent"; +import { cn } from "@/utils/utils"; + +export const FolderSelectItem = ({ name, iconName }) => ( +
+ + {name} +
+); diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx new file mode 100644 index 000000000..56c9b23bd --- /dev/null +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/header-buttons.tsx @@ -0,0 +1,35 @@ +import IconComponent from "@/components/common/genericIconComponent"; +import { SidebarTrigger } from "@/components/ui/sidebar"; +import { AddFolderButton } from "./add-folder-button"; +import { UploadFolderButton } from "./upload-folder-button"; + +export const HeaderButtons = ({ + handleUploadFlowsToFolder, + isUpdatingFolder, + isPending, + addNewFolder, +}: { + handleUploadFlowsToFolder: () => void; + isUpdatingFolder: boolean; + isPending: boolean; + addNewFolder: () => void; +}) => ( +
+ + + + +
Folders
+
+ + +
+
+); diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/input-edit-folder-name.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/input-edit-folder-name.tsx new file mode 100644 index 000000000..86ed361c4 --- /dev/null +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/input-edit-folder-name.tsx @@ -0,0 +1,67 @@ +import { Input } from "@/components/ui/input"; +import { FolderType } from "@/pages/MainPage/entities"; + +export const InputEditFolderName = ({ + handleEditFolderName, + item, + refInput, + handleKeyDownFn, + handleKeyDown, + handleEditNameFolder, + editFolderName, + foldersNames, +}: { + handleEditFolderName: ( + e: React.ChangeEvent, + folderName: string, + ) => void; + item: FolderType; + refInput: React.RefObject; + handleKeyDownFn: ( + e: React.KeyboardEvent, + folder: FolderType, + ) => void; + handleKeyDown: ( + e: React.KeyboardEvent, + key: string, + folderName: string, + ) => void; + handleEditNameFolder: (item: FolderType) => void; + editFolderName: { name: string; edit: boolean }; + foldersNames: Record; +}) => { + return ( + <> + { + handleEditFolderName(e, item.name); + }} + maxLength={38} + ref={refInput} + onKeyDown={(e) => { + handleKeyDownFn(e, item); + handleKeyDown(e, e.key, ""); + }} + autoFocus={true} + onBlur={(e) => { + // fixes autofocus problem where cursor isn't present + if (e.relatedTarget?.id === `options-trigger-${item.name}`) { + refInput.current?.focus(); + return; + } + + if (refInput.current?.value !== item.name) { + handleEditNameFolder(item); + } else { + editFolderName.edit = false; + } + refInput.current?.blur(); + }} + value={foldersNames[item.name]} + id={`input-folder-${item.name}`} + data-testid={`input-folder`} + /> + + ); +}; diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx new file mode 100644 index 000000000..676576655 --- /dev/null +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/select-options.tsx @@ -0,0 +1,80 @@ +import IconComponent from "@/components/common/genericIconComponent"; +import ShadTooltip from "@/components/common/shadTooltipComponent"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, +} from "@/components/ui/select-custom"; +import { FolderType } from "@/pages/MainPage/entities"; +import { cn } from "@/utils/utils"; +import { handleSelectChange } from "../helpers/handle-select-change"; +import { FolderSelectItem } from "./folder-select-item"; + +export const SelectOptions = ({ + item, + index, + handleDeleteFolder, + handleDownloadFolder, + handleSelectFolderToRename, + checkPathName, +}: { + item: FolderType; + index: number; + handleDeleteFolder: ((folder: FolderType) => void) | undefined; + handleDownloadFolder: (folderId: string) => void; + handleSelectFolderToRename: (folder: FolderType) => void; + checkPathName: (folderId: string) => boolean; +}) => { + return ( + <> + + + ); +}; diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/upload-folder-button.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/upload-folder-button.tsx new file mode 100644 index 000000000..61a1a354e --- /dev/null +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/components/upload-folder-button.tsx @@ -0,0 +1,18 @@ +import IconComponent from "@/components/common/genericIconComponent"; +import ShadTooltip from "@/components/common/shadTooltipComponent"; +import { Button } from "@/components/ui/button"; + +export const UploadFolderButton = ({ onClick, disabled }) => ( + + + +); diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/helpers/handle-select-change.ts b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/helpers/handle-select-change.ts new file mode 100644 index 000000000..cbc06e781 --- /dev/null +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/helpers/handle-select-change.ts @@ -0,0 +1,21 @@ +import { FolderType } from "@/pages/MainPage/entities"; + +export const handleSelectChange = ( + option: string, + folder: FolderType, + handleDeleteFolder: ((folder: FolderType) => void) | undefined, + handleDownloadFolder: (folderId: string) => void, + handleSelectFolderToRename: (folder: FolderType) => void, +) => { + switch (option) { + case "delete": + handleDeleteFolder!(folder); + break; + case "download": + handleDownloadFolder(folder.id!); + break; + case "rename": + handleSelectFolderToRename(folder); + break; + } +}; diff --git a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/index.tsx b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/index.tsx index 0fc2a2466..a863e70e2 100644 --- a/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/index.tsx +++ b/src/frontend/src/components/core/folderSidebarComponent/components/sideBarFolderButtons/index.tsx @@ -1,10 +1,3 @@ -import ShadTooltip from "@/components/common/shadTooltipComponent"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, -} from "@/components/ui/select-custom"; import { Sidebar, SidebarContent, @@ -14,7 +7,6 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, - SidebarTrigger, } from "@/components/ui/sidebar"; import { usePatchFolders, @@ -37,11 +29,11 @@ import useFlowsManagerStore from "../../../../../stores/flowsManagerStore"; import { useFolderStore } from "../../../../../stores/foldersStore"; import { handleKeyDown } from "../../../../../utils/reactflowUtils"; import { cn } from "../../../../../utils/utils"; -import IconComponent from "../../../../common/genericIconComponent"; -import { Button } from "../../../../ui/button"; -import { Input } from "../../../../ui/input"; import useFileDrop from "../../hooks/use-on-file-drop"; import { SidebarFolderSkeleton } from "../sidebarFolderSkeleton"; +import { HeaderButtons } from "./components/header-buttons"; +import { InputEditFolderName } from "./components/input-edit-folder-name"; +import { SelectOptions } from "./components/select-options"; type SideBarFoldersButtonsComponentProps = { handleChangeFolder?: (id: string) => void; @@ -54,37 +46,68 @@ const SideBarFoldersButtonsComponent = ({ const location = useLocation(); const pathname = location.pathname; const folders = useFolderStore((state) => state.folders); - - const isFetchingFolders = !!useIsFetching({ - queryKey: ["useGetFolders"], - exact: false, - }); const loading = !folders; const refInput = useRef(null); - const [foldersNames, setFoldersNames] = useState({}); - const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); - const [editFolders, setEditFolderName] = useState( - folders.map((obj) => ({ name: obj.name, edit: false })) ?? [], - ); + const currentFolder = pathname.split("/"); const urlWithoutPath = pathname.split("/").length < (ENABLE_CUSTOM_PARAM ? 5 : 4); - const myCollectionId = useFolderStore((state) => state.myCollectionId); + const checkPathName = (itemId: string) => { if (urlWithoutPath && itemId === myCollectionId) { return true; } return currentFolder.includes(itemId); }; - const folderId = useParams().folderId ?? myCollectionId ?? ""; + const setErrorData = useAlertStore((state) => state.setErrorData); const setSuccessData = useAlertStore((state) => state.setSuccessData); - const uploadFlow = useUploadFlow(); + const isMobile = useIsMobile({ maxWidth: 1024 }); + const folderIdDragging = useFolderStore((state) => state.folderIdDragging); + const myCollectionId = useFolderStore((state) => state.myCollectionId); + const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); + + const folderId = useParams().folderId ?? myCollectionId ?? ""; const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop(folderId); + const uploadFlow = useUploadFlow(); + const [foldersNames, setFoldersNames] = useState({}); + const [editFolders, setEditFolderName] = useState( + folders.map((obj) => ({ name: obj.name, edit: false })) ?? [], + ); + const isFetchingFolders = !!useIsFetching({ + queryKey: ["useGetFolders"], + exact: false, + }); + + const { mutate: mutateDownloadFolder } = useGetDownloadFolders({}); + const { mutate: mutateAddFolder, isPending } = usePostFolders(); + const { mutate: mutateUpdateFolder } = usePatchFolders(); const { mutate } = usePostUploadFolders(); + const checkHoveringFolder = (folderId: string) => { + if (folderId === folderIdDragging) { + return "bg-accent text-accent-foreground"; + } + }; + + const isFetchingFolder = !!useIsFetching({ + queryKey: ["useGetFolder"], + exact: false, + }); + + const isDeletingFolder = !!useIsMutating({ + mutationKey: ["useDeleteFolders"], + }); + + const isUpdatingFolder = + isFetchingFolders || + isFetchingFolder || + isPending || + loading || + isDeletingFolder; + const handleUploadFlowsToFolder = () => { createFileUpload().then((files: File[]) => { if (files?.length === 0) { @@ -125,8 +148,6 @@ const SideBarFoldersButtonsComponent = ({ }); }; - const { mutate: mutateDownloadFolder } = useGetDownloadFolders({}); - const handleDownloadFolder = (id: string) => { mutateDownloadFolder( { @@ -166,9 +187,6 @@ const SideBarFoldersButtonsComponent = ({ ); }; - const { mutate: mutateAddFolder, isPending } = usePostFolders(); - const { mutate: mutateUpdateFolder } = usePatchFolders(); - function addNewFolder() { mutateAddFolder( { @@ -257,86 +275,6 @@ const SideBarFoldersButtonsComponent = ({ } }; - const isFetchingFolder = !!useIsFetching({ - queryKey: ["useGetFolder"], - exact: false, - }); - - const isDeletingFolder = !!useIsMutating({ - mutationKey: ["useDeleteFolders"], - }); - - const isUpdatingFolder = - isFetchingFolders || - isFetchingFolder || - isPending || - loading || - isDeletingFolder; - - const HeaderButtons = () => ( -
- - - - -
Folders
-
- - -
-
- ); - - const AddFolderButton = ({ onClick, disabled, loading }) => ( - - - - ); - - const UploadFolderButton = ({ onClick, disabled }) => ( - - - - ); - - const FolderSelectItem = ({ name, iconName }) => ( -
- - {name} -
- ); - const handleDoubleClick = (event, item) => { if (item.name === "My Projects") { return; @@ -395,29 +333,18 @@ const SideBarFoldersButtonsComponent = ({ } }; - const handleSelectChange = (option, folder) => { - switch (option) { - case "delete": - handleDeleteFolder!(folder); - break; - case "download": - handleDownloadFolder(folder.id!); - break; - case "rename": - handleSelectFolderToRename(folder); - break; - } - }; - - const isMobile = useIsMobile({ maxWidth: 1024 }); - return ( - + @@ -440,7 +367,10 @@ const SideBarFoldersButtonsComponent = ({ data-testid={`sidebar-nav-${item.name}`} isActive={checkPathName(item.id!)} onClick={() => handleChangeFolder!(item.id!)} - className="group/menu-button" + className={cn( + "group/menu-button", + checkHoveringFolder(item.id!), + )} >
{ @@ -450,38 +380,15 @@ const SideBarFoldersButtonsComponent = ({ >
{editFolderName?.edit && !isUpdatingFolder ? ( - { - handleEditFolderName(e, item.name); - }} - maxLength={38} - ref={refInput} - onKeyDown={(e) => { - handleKeyDownFn(e, item); - handleKeyDown(e, e.key, ""); - }} - autoFocus={true} - onBlur={(e) => { - // fixes autofocus problem where cursor isn't present - if ( - e.relatedTarget?.id === - `options-trigger-${item.name}` - ) { - refInput.current?.focus(); - return; - } - - if (refInput.current?.value !== item.name) { - handleEditNameFolder(item); - } else { - editFolderName.edit = false; - } - refInput.current?.blur(); - }} - value={foldersNames[item.name]} - id={`input-folder-${item.name}`} - data-testid={`input-folder`} + ) : ( @@ -489,69 +396,16 @@ const SideBarFoldersButtonsComponent = ({ )}
- + checkPathName={checkPathName} + />