diff --git a/starsky/starsky/clientapp/src/components/molecules/menu-option-archive-rename/menu-option-archive-rename.spec.tsx b/starsky/starsky/clientapp/src/components/molecules/menu-option-archive-rename/menu-option-archive-rename.spec.tsx new file mode 100644 index 0000000000..21ef6a6c8d --- /dev/null +++ b/starsky/starsky/clientapp/src/components/molecules/menu-option-archive-rename/menu-option-archive-rename.spec.tsx @@ -0,0 +1,73 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import React from "react"; +import { IArchiveProps } from "../../../interfaces/IArchiveProps"; +import * as ModalArchiveRename from "../../organisms/modal-archive-rename/modal-archive-rename"; +import { MenuOptionArchiveRename } from "./menu-option-archive-rename"; + +describe("MenuOptionArchiveRename", () => { + const mockDispatch = jest.fn(); + const mockState = { fileIndexItem: {} } as unknown as IArchiveProps; + let modalSpy = jest.spyOn(ModalArchiveRename, "default"); + + function mockModalHandleExit() { + modalSpy.mockReset(); + modalSpy = jest.spyOn(ModalArchiveRename, "default").mockImplementation((props) => { + props.handleExit(); + return

test

; + }); + } + + function mockModal() { + modalSpy.mockReset(); + modalSpy = jest.spyOn(ModalArchiveRename, "default").mockImplementation(() => { + return

test

; + }); + } + + const renderComponent = (readOnly = false) => { + return render( + + ); + }; + + it("should not show the modal initially", () => { + mockModal(); + const component = renderComponent(); + expect(screen.queryByTestId("modal-archive-rename")).not.toBeTruthy(); + expect(modalSpy).toHaveBeenCalledTimes(0); + component.unmount(); + }); + + it("should open the modal when the button is clicked", () => { + mockModal(); + const component = renderComponent(); + + fireEvent.click(screen.getByTestId("rename")); + expect(modalSpy).toHaveBeenCalledTimes(1); + + expect(screen.getByTestId("modal-archive-rename")).toBeTruthy(); + component.unmount(); + }); + + it("should close the modal when the handleExit function is called", () => { + const stateSpy = jest.spyOn(React, "useState").mockReturnValueOnce([true, jest.fn()]); + mockModalHandleExit(); + + const component = renderComponent(); + fireEvent.click(screen.getByTestId("rename")); + expect(screen.getByTestId("rename")).toBeTruthy(); + + expect(stateSpy).toHaveBeenCalledTimes(1); + expect(stateSpy).toHaveBeenCalledWith(false); + component.unmount(); + }); + + it("should not open the modal if readOnly is true", () => { + mockModal(); + + const component = renderComponent(true); + fireEvent.click(screen.getByTestId("rename")); + expect(screen.queryByTestId("modal-archive-rename")).not.toBeTruthy(); + component.unmount(); + }); +}); diff --git a/starsky/starsky/clientapp/src/components/molecules/menu-option-archive-rename/menu-option-archive-rename.tsx b/starsky/starsky/clientapp/src/components/molecules/menu-option-archive-rename/menu-option-archive-rename.tsx new file mode 100644 index 0000000000..8d086def0f --- /dev/null +++ b/starsky/starsky/clientapp/src/components/molecules/menu-option-archive-rename/menu-option-archive-rename.tsx @@ -0,0 +1,43 @@ +import { useState } from "react"; +import { ArchiveAction } from "../../../contexts/archive-context"; +import { IArchiveProps } from "../../../interfaces/IArchiveProps"; +import localization from "../../../localization/localization.json"; +import MenuOptionModal from "../../atoms/menu-option-modal/menu-option-modal"; +import ModalArchiveRename from "../../organisms/modal-archive-rename/modal-archive-rename"; + +interface IMenuOptionArchiveRenameProps { + readOnly: boolean; + state: IArchiveProps; + dispatch: React.Dispatch; +} + +export const MenuOptionArchiveRename: React.FunctionComponent = ({ + readOnly, + state, + dispatch +}) => { + const [isModalRenameFolder, setIsModalRenameFolder] = useState(false); + + return ( + <> + {isModalRenameFolder && !readOnly && state.subPath !== "/" ? ( + { + setIsModalRenameFolder(!isModalRenameFolder); + }} + isOpen={isModalRenameFolder} + /> + ) : null} + + setIsModalRenameFolder(!isModalRenameFolder)} + localization={localization.MessageRenameDir} + testName="rename" + /> + + ); +}; diff --git a/starsky/starsky/clientapp/src/components/molecules/menu-option-mkdir/menu-option-mkdir.spec.tsx b/starsky/starsky/clientapp/src/components/molecules/menu-option-mkdir/menu-option-mkdir.spec.tsx new file mode 100644 index 0000000000..da27beec8f --- /dev/null +++ b/starsky/starsky/clientapp/src/components/molecules/menu-option-mkdir/menu-option-mkdir.spec.tsx @@ -0,0 +1,75 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import React from "react"; +import { IArchiveProps } from "../../../interfaces/IArchiveProps"; +import * as ModalArchiveMkdir from "../../organisms/modal-archive-mkdir/modal-archive-mkdir"; +import { MenuOptionMkdir } from "./menu-option-mkdir"; + +describe("MenuOptionMkdir", () => { + const mockDispatch = jest.fn(); + const mockState = { fileIndexItem: {} } as unknown as IArchiveProps; + let modalSpy = jest.spyOn(ModalArchiveMkdir, "default"); + + function mockModalHandleExit() { + modalSpy.mockReset(); + modalSpy = jest.spyOn(ModalArchiveMkdir, "default").mockImplementation((props) => { + props.handleExit(); + return

test

; + }); + } + + function mockModal() { + modalSpy.mockReset(); + modalSpy = jest.spyOn(ModalArchiveMkdir, "default").mockImplementation(() => { + return

test

; + }); + } + + const renderComponent = (readOnly = false) => { + return render( + + ); + }; + + it("should not show the modal initially", () => { + mockModal(); + const component = renderComponent(); + expect(screen.queryByTestId("modal-archive-mkdir")).not.toBeTruthy(); + expect(modalSpy).toHaveBeenCalledTimes(0); + component.unmount(); + }); + + it("should open the modal when the button is clicked", () => { + mockModal(); + const component = renderComponent(); + fireEvent.click(screen.getByTestId("mkdir")); + expect(modalSpy).toHaveBeenCalledTimes(1); + + expect(screen.getByTestId("modal-archive-mkdir")).toBeTruthy(); + component.unmount(); + }); + + it("should close the modal when the handleExit function is called", () => { + const stateSpy = jest.spyOn(React, "useState").mockReturnValueOnce([true, jest.fn()]); + mockModalHandleExit(); + + const component = renderComponent(); + fireEvent.click(screen.getByTestId("mkdir")); + expect(screen.getByTestId("mkdir")).toBeTruthy(); + + // Simulate closing the modal + fireEvent.click(screen.getByTestId("mkdir")); + + expect(stateSpy).toHaveBeenCalledTimes(1); + expect(stateSpy).toHaveBeenCalledWith(false); + component.unmount(); + }); + + it("should not open the modal if readOnly is true", () => { + mockModal(); + + const component = renderComponent(true); + fireEvent.click(screen.getByTestId("mkdir")); + expect(screen.queryByTestId("modal-archive-mkdir")).not.toBeTruthy(); + component.unmount(); + }); +}); diff --git a/starsky/starsky/clientapp/src/components/molecules/menu-option-mkdir/menu-option-mkdir.tsx b/starsky/starsky/clientapp/src/components/molecules/menu-option-mkdir/menu-option-mkdir.tsx new file mode 100644 index 0000000000..b0fffe3b81 --- /dev/null +++ b/starsky/starsky/clientapp/src/components/molecules/menu-option-mkdir/menu-option-mkdir.tsx @@ -0,0 +1,42 @@ +import { useState } from "react"; +import { ArchiveAction } from "../../../contexts/archive-context"; +import { IArchiveProps } from "../../../interfaces/IArchiveProps"; +import localization from "../../../localization/localization.json"; +import MenuOptionModal from "../../atoms/menu-option-modal/menu-option-modal"; +import ModalArchiveMkdir from "../../organisms/modal-archive-mkdir/modal-archive-mkdir"; + +interface IMenuOptionMkdirProps { + readOnly: boolean; + state: IArchiveProps; + dispatch: React.Dispatch; +} + +export const MenuOptionMkdir: React.FunctionComponent = ({ + readOnly, + state, + dispatch +}) => { + const [isModalMkdirOpen, setIsModalMkdirOpen] = useState(false); + + return ( + <> + {/* Modal new directory */} + {isModalMkdirOpen && !readOnly ? ( + setIsModalMkdirOpen(!isModalMkdirOpen)} + isOpen={isModalMkdirOpen} + /> + ) : null} + + setIsModalMkdirOpen(!isModalMkdirOpen)} + localization={localization.MessageMkdir} + testName="mkdir" + /> + + ); +}; diff --git a/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx b/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx index 39596ade94..c803c98a57 100644 --- a/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx +++ b/starsky/starsky/clientapp/src/components/organisms/menu-archive/menu-archive.tsx @@ -12,8 +12,10 @@ import HamburgerMenuToggle from "../../atoms/hamburger-menu-toggle/hamburger-men import MenuOptionModal from "../../atoms/menu-option-modal/menu-option-modal"; import MoreMenu from "../../atoms/more-menu/more-menu"; import MenuSearchBar from "../../molecules/menu-inline-search/menu-inline-search"; +import { MenuOptionArchiveRename } from "../../molecules/menu-option-archive-rename/menu-option-archive-rename.tsx"; import MenuOptionDesktopEditorOpenSelectionNoSelectWarning from "../../molecules/menu-option-desktop-editor-open-selection-no-select-warning/menu-option-desktop-editor-open-selection-no-select-warning"; import MenuOptionDesktopEditorOpenSelection from "../../molecules/menu-option-desktop-editor-open-selection/menu-option-desktop-editor-open-selection"; +import { MenuOptionMkdir } from "../../molecules/menu-option-mkdir/menu-option-mkdir.tsx"; import MenuOptionMoveFolderToTrash from "../../molecules/menu-option-move-folder-to-trash/menu-option-move-folder-to-trash"; import MenuOptionMoveToTrash from "../../molecules/menu-option-move-to-trash/menu-option-move-to-trash"; import { MenuOptionSelectionAll } from "../../molecules/menu-option-selection-all/menu-option-selection-all"; @@ -21,15 +23,13 @@ import { MenuOptionSelectionUndo } from "../../molecules/menu-option-selection-u import { MenuSelectCount } from "../../molecules/menu-select-count/menu-select-count"; import { MenuSelectFurther } from "../../molecules/menu-select-further/menu-select-further"; import ModalDropAreaFilesAdded from "../../molecules/modal-drop-area-files-added/modal-drop-area-files-added"; -import ModalArchiveMkdir from "../modal-archive-mkdir/modal-archive-mkdir"; -import ModalArchiveRename from "../modal-archive-rename/modal-archive-rename"; import ModalArchiveSynchronizeManually from "../modal-archive-synchronize-manually/modal-archive-synchronize-manually"; import ModalDisplayOptions from "../modal-display-options/modal-display-options"; import ModalDownload from "../modal-download/modal-download"; import ModalPublishToggleWrapper from "../modal-publish/modal-publish-toggle-wrapper"; import NavContainer from "../nav-container/nav-container"; -import { UploadMenuItem } from "./internal/upload-menu-item"; import { SelectMenuItem } from "./internal/select-menu-item.tsx"; +import { UploadMenuItem } from "./internal/upload-menu-item"; interface IMenuArchiveProps {} @@ -48,7 +48,7 @@ const MenuArchive: React.FunctionComponent = memo(() => { const removeSidebarSelection = () => new Select(select, setSelect, state, history).removeSidebarSelection(); - // Command + A for mac os || Ctrl + A for windows + // Command + A for macOS || Ctrl + A for windows useHotKeys({ key: "a", ctrlKeyOrMetaKey: true }, allSelection, []); /* only update when the state is changed */ @@ -80,8 +80,6 @@ const MenuArchive: React.FunctionComponent = memo(() => { const [isDisplayOptionsOpen, setIsDisplayOptionsOpen] = React.useState(false); const [isSynchronizeManuallyOpen, setIsSynchronizeManuallyOpen] = React.useState(false); - const [isModalMkdirOpen, setIsModalMkdirOpen] = React.useState(false); - const [isModalRenameFolder, setIsModalRenameFolder] = React.useState(false); const [dropAreaUploadFilesList, setDropAreaUploadFilesList] = React.useState(newIFileIndexItemArray()); @@ -117,27 +115,6 @@ const MenuArchive: React.FunctionComponent = memo(() => { /> ) : null} - {/* Modal new directory */} - {isModalMkdirOpen && !readOnly ? ( - setIsModalMkdirOpen(!isModalMkdirOpen)} - isOpen={isModalMkdirOpen} - /> - ) : null} - - {isModalRenameFolder && !readOnly && state.subPath !== "/" ? ( - { - setIsModalRenameFolder(!isModalRenameFolder); - }} - isOpen={isModalRenameFolder} - /> - ) : null} - {/* Upload drop Area */} {dropAreaUploadFilesList.length !== 0 ? ( = memo(() => { {/* default more menu */} {!select ? ( - setIsModalMkdirOpen(!isModalMkdirOpen)} - localization={localization.MessageMkdir} - testName="mkdir" - /> + = memo(() => { /> ) : null} - setIsModalRenameFolder(!isModalRenameFolder)} - localization={localization.MessageRenameDir} - testName="rename" - /> + void; state: IArchiveProps; dispatch: React.Dispatch; }