From 105fb531be6cfcd13cfad5f4d8c46c76c8bb54ba Mon Sep 17 00:00:00 2001 From: kim Date: Tue, 10 Dec 2024 15:34:52 +0100 Subject: [PATCH 1/2] feat: add new folder button --- src/components/item/FolderContent.tsx | 32 ++++++-- .../item/form/folder/FolderCreateForm.tsx | 3 +- .../item/form/folder/NewFolderButton.tsx | 73 +++++++++++++++++++ src/components/main/NewItemModal.tsx | 2 +- src/components/pages/home/HomeScreen.tsx | 12 ++- src/langs/constants.ts | 1 + src/langs/en.json | 3 +- src/langs/fr.json | 3 +- 8 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 src/components/item/form/folder/NewFolderButton.tsx diff --git a/src/components/item/FolderContent.tsx b/src/components/item/FolderContent.tsx index cdc5a8055..9686fb5ea 100644 --- a/src/components/item/FolderContent.tsx +++ b/src/components/item/FolderContent.tsx @@ -1,7 +1,14 @@ import { useEffect } from 'react'; import { useOutletContext } from 'react-router-dom'; -import { Alert, Box, Stack, Typography } from '@mui/material'; +import { + Alert, + Box, + Stack, + Typography, + useMediaQuery, + useTheme, +} from '@mui/material'; import { PackedItem, @@ -43,6 +50,7 @@ import { useSorting } from '../table/useSorting'; import FolderDescription from './FolderDescription'; import FolderToolbar from './FolderSelectionToolbar'; import { useItemSearch } from './ItemSearch'; +import { NewFolderButton } from './form/folder/NewFolderButton'; import ModeButton from './header/ModeButton'; type Props = { @@ -132,6 +140,8 @@ const Content = ({ * Helper component to render typed folder items */ const FolderContent = ({ item }: { item: PackedItem }): JSX.Element => { + const theme = useTheme(); + const isMd = useMediaQuery(theme.breakpoints.up('md')); const { t: translateEnums } = useEnumsTranslation(); const { itemTypes } = useFilterItemsContext(); const { t: translateBuilder } = useBuilderTranslation(); @@ -185,12 +195,20 @@ const FolderContent = ({ item }: { item: PackedItem }): JSX.Element => { > {itemSearch.input} {canWrite && ( - + <> + + + )} diff --git a/src/components/item/form/folder/FolderCreateForm.tsx b/src/components/item/form/folder/FolderCreateForm.tsx index b9e8a781c..c46516ea4 100644 --- a/src/components/item/form/folder/FolderCreateForm.tsx +++ b/src/components/item/form/folder/FolderCreateForm.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; +import { useParams } from 'react-router'; import { Box, @@ -40,10 +41,10 @@ type FolderCreateFormProps = { export function FolderCreateForm({ onClose, - parentId, geolocation, previousItemId, }: FolderCreateFormProps): JSX.Element { + const { itemId: parentId } = useParams(); const { t: translateBuilder } = useBuilderTranslation(); const { t: translateCommon } = useCommonTranslation(); const methods = useForm(); diff --git a/src/components/item/form/folder/NewFolderButton.tsx b/src/components/item/form/folder/NewFolderButton.tsx new file mode 100644 index 000000000..b528d3438 --- /dev/null +++ b/src/components/item/form/folder/NewFolderButton.tsx @@ -0,0 +1,73 @@ +import { ButtonProps, Dialog, IconButton, useTheme } from '@mui/material'; + +import { DiscriminatedItem, ItemGeolocation } from '@graasp/sdk'; +import { Button } from '@graasp/ui'; + +import { FolderPlus } from 'lucide-react'; + +import useModalStatus from '@/components/hooks/useModalStatus'; +import { useBuilderTranslation } from '@/config/i18n'; +import { BUILDER } from '@/langs/constants'; + +import { FolderCreateForm } from './FolderCreateForm'; + +type Props = { + previousItemId?: DiscriminatedItem['id']; + parentId?: DiscriminatedItem['id']; + geolocation?: Pick; + size?: ButtonProps['size']; + type?: 'button' | 'icon'; +}; + +export const NewFolderButton = ({ + previousItemId, + parentId, + geolocation, + size = 'medium', + type = 'button', +}: Props): JSX.Element => { + const { t: translateBuilder } = useBuilderTranslation(); + const theme = useTheme(); + const { isOpen, openModal, closeModal } = useModalStatus(); + + const handleClickOpen = () => { + openModal(); + }; + + return ( + <> + {type === 'icon' ? ( + + + + ) : ( + + )} + + + + + ); +}; diff --git a/src/components/main/NewItemModal.tsx b/src/components/main/NewItemModal.tsx index 996ab0d78..d6fcc77d5 100644 --- a/src/components/main/NewItemModal.tsx +++ b/src/components/main/NewItemModal.tsx @@ -53,7 +53,7 @@ const NewItemModal = ({ const { t: translateCommon } = useCommonTranslation(); const [selectedItemType, setSelectedItemType] = useState( - ItemType.FOLDER, + ItemType.LOCAL_FILE, ); const { itemId: parentId } = useParams(); diff --git a/src/components/pages/home/HomeScreen.tsx b/src/components/pages/home/HomeScreen.tsx index 4c858b336..e1ce20c61 100644 --- a/src/components/pages/home/HomeScreen.tsx +++ b/src/components/pages/home/HomeScreen.tsx @@ -8,10 +8,13 @@ import { Button as MuiButton, Stack, Typography, + useMediaQuery, + useTheme, } from '@mui/material'; import { Button } from '@graasp/ui'; +import { NewFolderButton } from '@/components/item/form/folder/NewFolderButton'; import LoadingScreen from '@/components/layout/LoadingScreen'; import { SelectionContextProvider, @@ -211,6 +214,8 @@ const HomeScreenContent = ({ searchText }: { searchText: string }) => { const HomeScreen = (): JSX.Element => { const { t: translateBuilder } = useBuilderTranslation(); const { data: currentMember } = hooks.useCurrentMember(); + const theme = useTheme(); + const isMd = useMediaQuery(theme.breakpoints.up('md')); const itemSearch = useItemSearch(); @@ -226,7 +231,12 @@ const HomeScreen = (): JSX.Element => { spacing={1} > {itemSearch.input} - + + } > diff --git a/src/langs/constants.ts b/src/langs/constants.ts index dfa7b9cdb..5017c3607 100644 --- a/src/langs/constants.ts +++ b/src/langs/constants.ts @@ -613,4 +613,5 @@ export const BUILDER = { DELETE_GUESTS_MODAL_DELETE_BUTTON: 'DELETE_GUESTS_MODAL_DELETE_BUTTON', DELETE_GUESTS_MODAL_CONTENT: 'DELETE_GUESTS_MODAL_CONTENT', DELETE_ITEM_LOGIN_SCHEMA_ALERT_TEXT: 'DELETE_ITEM_LOGIN_SCHEMA_ALERT_TEXT', + CREATE_FOLDER_BUTTON_TEXT: 'CREATE_FOLDER_BUTTON_TEXT', }; diff --git a/src/langs/en.json b/src/langs/en.json index 1da5f316a..c09db7cd6 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -510,5 +510,6 @@ "DELETE_GUESTS_MODAL_TITLE_other": "Confirm deletion of {{count}} disabled reader(s)", "DELETE_GUESTS_MODAL_CONTENT": "I confirm deleting <1>permanently the following readers and their data:", "DELETE_GUESTS_MODAL_DELETE_BUTTON": "Delete permanently", - "ADD_TAG_OPTION_BUTTON_TEXT": "Add {{value}}" + "ADD_TAG_OPTION_BUTTON_TEXT": "Add {{value}}", + "CREATE_FOLDER_BUTTON_TEXT": "Create Folder" } diff --git a/src/langs/fr.json b/src/langs/fr.json index 91ec5ccce..c6f3c5a48 100644 --- a/src/langs/fr.json +++ b/src/langs/fr.json @@ -503,5 +503,6 @@ "TRASH_COUNT_other": "Il y a {{count}} éléments dans la poubelle.", "ITEM_NAME_CANNOT_BE_EMPTY": "L'élément a besoin d'un nom.", "LINK_INVALID_MESSAGE": "Le lien est invalide.", - "DOCUMENT_EMPTY_MESSAGE": "Le contenu ne peut pas être vide." + "DOCUMENT_EMPTY_MESSAGE": "Le contenu ne peut pas être vide.", + "CREATE_FOLDER_BUTTON_TEXT": "Nouveau Dossier" } From 621f22d6ae445d0d7abd168e72743cb870fed29b Mon Sep 17 00:00:00 2001 From: kim Date: Wed, 11 Dec 2024 10:57:11 +0100 Subject: [PATCH 2/2] test: add tests --- cypress/e2e/map/map.cy.ts | 30 +++++++++++++++++++ cypress/support/createUtils.ts | 4 ++- .../item/form/folder/NewFolderButton.tsx | 4 ++- src/config/selectors.ts | 3 +- 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 cypress/e2e/map/map.cy.ts diff --git a/cypress/e2e/map/map.cy.ts b/cypress/e2e/map/map.cy.ts new file mode 100644 index 000000000..a15cfae49 --- /dev/null +++ b/cypress/e2e/map/map.cy.ts @@ -0,0 +1,30 @@ +// /map is used by the mobile application to display the map and have access to its feature +import { MAP_ITEMS_PATH } from '@/config/paths'; +import { + CREATE_ITEM_FOLDER_ID, + FOLDER_FORM_DESCRIPTION_ID, + buildMapViewId, +} from '@/config/selectors'; + +describe('Map', () => { + it('open create folder modal on Home', () => { + cy.setUpApi(); + cy.visit(`${MAP_ITEMS_PATH}?enableGeolocation=false`); + + // home id + cy.get(`#${buildMapViewId(undefined)}`).should('be.visible'); + + // select a country + cy.get(`#${buildMapViewId(undefined)} input`).click(); + cy.get(`#${buildMapViewId(undefined)} [role="presentation"]`).click(); + + // open location button + cy.get(`#${buildMapViewId(undefined)}`).click(); + cy.get(`#${buildMapViewId(undefined)} img[role="button"]`).click(); + cy.get(`[data-testid="AddLocationAltIcon"]`).click(); + + // open folder form + cy.get(`#${CREATE_ITEM_FOLDER_ID}`).click(); + cy.get(`#${FOLDER_FORM_DESCRIPTION_ID}`).should('be.visible'); + }); +}); diff --git a/cypress/support/createUtils.ts b/cypress/support/createUtils.ts index f8f14f545..6e9f71085 100644 --- a/cypress/support/createUtils.ts +++ b/cypress/support/createUtils.ts @@ -6,6 +6,7 @@ import { } from '@graasp/sdk'; import { + ADD_FOLDER_BUTTON_CY, CREATE_ITEM_APP_ID, CREATE_ITEM_BUTTON_ID, CREATE_ITEM_CLOSE_BUTTON_ID, @@ -16,6 +17,7 @@ import { DASHBOARD_UPLOADER_ID, H5P_DASHBOARD_UPLOADER_ID, ZIP_DASHBOARD_UPLOADER_ID, + buildDataCyWrapper, } from '../../src/config/selectors'; import { InternalItemType } from '../../src/config/types'; import { ZIPInternalItem } from '../fixtures/files'; @@ -43,7 +45,7 @@ export const createFolder = ( payload: { name?: string; description?: string }, options?: { confirm?: boolean }, ): void => { - cy.get(`#${CREATE_ITEM_BUTTON_ID}`).click({ force: true }); + cy.get(buildDataCyWrapper(ADD_FOLDER_BUTTON_CY)).click({ force: true }); cy.fillFolderModal(payload, options); }; diff --git a/src/components/item/form/folder/NewFolderButton.tsx b/src/components/item/form/folder/NewFolderButton.tsx index b528d3438..4f2d6d818 100644 --- a/src/components/item/form/folder/NewFolderButton.tsx +++ b/src/components/item/form/folder/NewFolderButton.tsx @@ -7,6 +7,7 @@ import { FolderPlus } from 'lucide-react'; import useModalStatus from '@/components/hooks/useModalStatus'; import { useBuilderTranslation } from '@/config/i18n'; +import { ADD_FOLDER_BUTTON_CY } from '@/config/selectors'; import { BUILDER } from '@/langs/constants'; import { FolderCreateForm } from './FolderCreateForm'; @@ -50,9 +51,10 @@ export const NewFolderButton = ({ ) : (