diff --git a/packages/pn-commons/src/components/ApiError/__test__/ApiErrorWrapper.test.tsx b/packages/pn-commons/src/components/ApiError/__test__/ApiErrorWrapper.test.tsx index 1a79755dec..29c085db3c 100644 --- a/packages/pn-commons/src/components/ApiError/__test__/ApiErrorWrapper.test.tsx +++ b/packages/pn-commons/src/components/ApiError/__test__/ApiErrorWrapper.test.tsx @@ -16,6 +16,7 @@ vi.mock('../../../hooks', () => ({ describe('ApiErrorWrapper', () => { const original = window.location; const reloadText = 'Ricarica'; + const user = userEvent.setup(); beforeAll(() => { Object.defineProperty(window, 'location', { @@ -67,7 +68,7 @@ describe('ApiErrorWrapper', () => { const reloadItemComponent = screen.getByText(reloadText); expect(reloadItemComponent).toBeInTheDocument(); - await userEvent.click(reloadItemComponent); + await user.click(reloadItemComponent); await waitFor(() => { expect(reloadActionMock).toHaveBeenCalled(); @@ -83,7 +84,7 @@ describe('ApiErrorWrapper', () => { const reloadItemComponent = screen.getByText(reloadText); expect(reloadItemComponent).toBeInTheDocument(); - await userEvent.click(reloadItemComponent); + await user.click(reloadItemComponent); await waitFor(() => { expect(window.location.reload).toHaveBeenCalled(); diff --git a/packages/pn-commons/src/components/CodeModal/__test__/CodeInput.test.tsx b/packages/pn-commons/src/components/CodeModal/__test__/CodeInput.test.tsx index 22b2a185e8..fe58883811 100644 --- a/packages/pn-commons/src/components/CodeModal/__test__/CodeInput.test.tsx +++ b/packages/pn-commons/src/components/CodeModal/__test__/CodeInput.test.tsx @@ -8,6 +8,8 @@ import CodeInput from '../CodeInput'; const handleChangeMock = vi.fn(); describe('CodeInput Component', () => { + const user = userEvent.setup(); + afterEach(() => { vi.clearAllMocks(); }); @@ -82,7 +84,7 @@ describe('CodeInput Component', () => { await waitFor(() => { expect(handleChangeMock).toBeCalledTimes(2); // check focus on next elem - expect(codeInputs[3]).toBe(document.activeElement); + expect(codeInputs[3]).toHaveFocus(); }); // change the value of the input and check that it is updated correctly // set the cursor position to the end @@ -90,20 +92,32 @@ describe('CodeInput Component', () => { (codeInputs[2] as HTMLInputElement).setSelectionRange(1, 1); // when we try to edit an input, we insert a second value and after, based on cursor position, we change the value // we must use userEvent because the keyboard event must trigger also the change event (fireEvent doesn't do that) - await userEvent.keyboard('4'); + await user.keyboard('4'); + // next element will be focused + await waitFor(() => { + expect(codeInputs[3]).toHaveFocus(); + }); await waitFor(() => { expect(codeInputs[2]).toHaveValue('4'); }); // move the cursor at the start of the input and try to edit again act(() => (codeInputs[2] as HTMLInputElement).focus()); (codeInputs[2] as HTMLInputElement).setSelectionRange(0, 0); - await userEvent.keyboard('3'); + await user.keyboard('3'); + // next element will be focused + await waitFor(() => { + expect(codeInputs[3]).toHaveFocus(); + }); await waitFor(() => { expect(codeInputs[2]).toHaveValue('3'); }); // delete the value act(() => (codeInputs[2] as HTMLInputElement).focus()); - await userEvent.keyboard('{Backspace}'); + await user.keyboard('{Backspace}'); + // previous element will be focused + await waitFor(() => { + expect(codeInputs[1]).toHaveFocus(); + }); await waitFor(() => { expect(codeInputs[2]).toHaveValue(''); }); @@ -120,52 +134,52 @@ describe('CodeInput Component', () => { // press enter fireEvent.keyDown(codeInputs[0], { key: 'Enter', code: 'Enter' }); await waitFor(() => { - expect(codeInputs[1]).toBe(document.activeElement); + expect(codeInputs[1]).toHaveFocus(); }); // press tab fireEvent.keyDown(codeInputs[1], { key: 'Tab', code: 'Tab' }); await waitFor(() => { - expect(codeInputs[2]).toBe(document.activeElement); + expect(codeInputs[2]).toHaveFocus(); }); // press arrow right fireEvent.keyDown(codeInputs[2], { key: 'ArrowRight', code: 'ArrowRight' }); await waitFor(() => { - expect(codeInputs[3]).toBe(document.activeElement); + expect(codeInputs[3]).toHaveFocus(); }); // press delete fireEvent.keyDown(codeInputs[3], { key: 'Delete', code: 'Delete' }); await waitFor(() => { - expect(codeInputs[4]).toBe(document.activeElement); + expect(codeInputs[4]).toHaveFocus(); }); // press the same value of the input // we reach the end, so we have to lost the focus fireEvent.keyDown(codeInputs[4], { key: '1', code: 'Digit1' }); await waitFor(() => { - expect(document.body).toBe(document.activeElement); + expect(document.body).toHaveFocus(); }); // focus on last input and moove back act(() => (codeInputs[4] as HTMLInputElement).focus()); // press backspace fireEvent.keyDown(codeInputs[4], { key: 'Backspace', code: 'Backspace' }); await waitFor(() => { - expect(codeInputs[3]).toBe(document.activeElement); + expect(codeInputs[3]).toHaveFocus(); }); // press arrow left fireEvent.keyDown(codeInputs[3], { key: 'ArrowLeft', code: 'ArrowLeft' }); await waitFor(() => { - expect(codeInputs[2]).toBe(document.activeElement); + expect(codeInputs[2]).toHaveFocus(); }); // press tab and shift key fireEvent.keyDown(codeInputs[2], { key: 'Tab', code: 'Tab', shiftKey: true }); await waitFor(() => { - expect(codeInputs[1]).toBe(document.activeElement); + expect(codeInputs[1]).toHaveFocus(); }); // focus on first element and try to go back act(() => (codeInputs[0] as HTMLInputElement).focus()); fireEvent.keyDown(codeInputs[0], { key: 'Backspace', code: 'Backspace' }); // nothing happens await waitFor(() => { - expect(codeInputs[0]).toBe(document.activeElement); + expect(codeInputs[0]).toHaveFocus(); }); }); }); diff --git a/packages/pn-commons/src/components/PnDialog/PnDialog.tsx b/packages/pn-commons/src/components/PnDialog/PnDialog.tsx index eb0530ae0d..ecb1df33f7 100644 --- a/packages/pn-commons/src/components/PnDialog/PnDialog.tsx +++ b/packages/pn-commons/src/components/PnDialog/PnDialog.tsx @@ -1,4 +1,4 @@ -import { Children, cloneElement, isValidElement, useMemo } from 'react'; +import { Children, cloneElement, isValidElement } from 'react'; import { Dialog, DialogProps, DialogTitle } from '@mui/material'; @@ -8,9 +8,8 @@ import PnDialogActions from './PnDialogActions'; import PnDialogContent from './PnDialogContent'; const PnDialog: React.FC = (props) => { - const isMobile = useIsMobile(); - const paddingSize = useMemo(() => (isMobile ? 3 : 4), [isMobile]); - + const isMobile = useIsMobile('sm'); + const paddingSize = isMobile ? 3 : 4; const title: ReactComponent = Children.toArray(props.children).find( (child) => isValidElement(child) && child.type === DialogTitle ); @@ -26,11 +25,10 @@ const PnDialog: React.FC = (props) => { (child) => isValidElement(child) && child.type === PnDialogContent ); - const paddingTop = isMobile ? 3 : 4; const enrichedContent = isValidElement(content) ? cloneElement(content, { ...content.props, - sx: { pt: title ? 0 : paddingTop, ...content.props.sx }, + sx: { pt: title ? 0 : paddingSize, ...content.props.sx }, }) : content; diff --git a/packages/pn-commons/src/components/PnDialog/PnDialogActions.tsx b/packages/pn-commons/src/components/PnDialog/PnDialogActions.tsx index b8588a82e4..713412cf95 100644 --- a/packages/pn-commons/src/components/PnDialog/PnDialogActions.tsx +++ b/packages/pn-commons/src/components/PnDialog/PnDialogActions.tsx @@ -1,4 +1,4 @@ -import { Children, cloneElement, isValidElement, useMemo } from 'react'; +import { Children, cloneElement, isValidElement } from 'react'; import { Button, DialogActions, DialogActionsProps } from '@mui/material'; @@ -6,10 +6,7 @@ import { useIsMobile } from '../../hooks'; import { ReactComponent } from '../../models/PnDialog'; const PnDialogActions: React.FC = (props) => { - const isMobile = useIsMobile(); - const paddingSize = useMemo(() => (isMobile ? 3 : 4), [isMobile]); - const gapSize = useMemo(() => (isMobile ? 0 : 1), [isMobile]); - + const isMobile = useIsMobile('sm'); const buttons: Array | undefined = Children.toArray(props.children).filter( (child) => isValidElement(child) && child.type === Button ); @@ -19,7 +16,10 @@ const PnDialogActions: React.FC = (props) => { ? cloneElement(button, { ...button.props, fullWidth: isMobile, - sx: { marginBottom: isMobile && index > 0 ? 2 : 0, ...button.props.sx }, + sx: { + marginBottom: index > 0 && isMobile ? 2 : 0, + ...button.props.sx, + }, }) : button ); @@ -31,9 +31,9 @@ const PnDialogActions: React.FC = (props) => { {...props} sx={{ flexDirection: isMobile ? 'column-reverse' : 'row', - p: paddingSize, + p: isMobile ? 3 : 4, pt: 0, - gap: gapSize, + gap: isMobile ? 0 : 1, ...props.sx, }} > diff --git a/packages/pn-commons/src/components/PnDialog/PnDialogContent.tsx b/packages/pn-commons/src/components/PnDialog/PnDialogContent.tsx index bfe82036ae..4708956809 100644 --- a/packages/pn-commons/src/components/PnDialog/PnDialogContent.tsx +++ b/packages/pn-commons/src/components/PnDialog/PnDialogContent.tsx @@ -1,4 +1,4 @@ -import { Children, cloneElement, isValidElement, useMemo } from 'react'; +import { Children, cloneElement, isValidElement } from 'react'; import { DialogContent, DialogContentProps, DialogContentText } from '@mui/material'; @@ -6,9 +6,7 @@ import { useIsMobile } from '../../hooks'; import { ReactComponent } from '../../models/PnDialog'; const PnDialogContent: React.FC = (props) => { - const isMobile = useIsMobile(); - const paddingSize = useMemo(() => (isMobile ? 3 : 4), [isMobile]); - + const isMobile = useIsMobile('sm'); const subtitle: ReactComponent = Children.toArray(props.children).find( (child) => isValidElement(child) && child.type === DialogContentText ); @@ -28,7 +26,7 @@ const PnDialogContent: React.FC = (props) => { {subtitle && enrichedSubTitle} {othersChildren} diff --git a/packages/pn-commons/src/components/PnDialog/__test__/PnDialog.test.tsx b/packages/pn-commons/src/components/PnDialog/__test__/PnDialog.test.tsx index b43fc40e81..190e409d7c 100644 --- a/packages/pn-commons/src/components/PnDialog/__test__/PnDialog.test.tsx +++ b/packages/pn-commons/src/components/PnDialog/__test__/PnDialog.test.tsx @@ -26,7 +26,7 @@ describe('PnDialog Component', () => { }); it('renders component - mobile', () => { - window.matchMedia = createMatchMedia(800); + window.matchMedia = createMatchMedia(500); const { queryByTestId } = render( Title diff --git a/packages/pn-commons/src/components/PnDialog/__test__/PnDialogActions.test.tsx b/packages/pn-commons/src/components/PnDialog/__test__/PnDialogActions.test.tsx index 7b4536bcd6..cefb46a00b 100644 --- a/packages/pn-commons/src/components/PnDialog/__test__/PnDialogActions.test.tsx +++ b/packages/pn-commons/src/components/PnDialog/__test__/PnDialogActions.test.tsx @@ -26,7 +26,7 @@ describe('PnDialogActions Component', () => { }); it('renders component - mobile', () => { - window.matchMedia = createMatchMedia(800); + window.matchMedia = createMatchMedia(500); const { queryByTestId, queryAllByTestId } = render( @@ -41,8 +41,9 @@ describe('PnDialogActions Component', () => { const buttons = queryAllByTestId('button'); expect(buttons).toHaveLength(2); buttons.forEach((button, index) => { - expect(button).toHaveClass('MuiButton-fullWidth'); - expect(button).toHaveStyle(index === 0 ? 'margin-bottom: 0' : 'margin-bottom: 16px'); + expect(button).toHaveStyle( + index === 0 ? 'margin-bottom: 0' : 'margin-bottom: 16px; width: 100%' + ); }); }); }); diff --git a/packages/pn-commons/src/hooks/useIsMobile.ts b/packages/pn-commons/src/hooks/useIsMobile.ts index 87f96bde76..da4b4e49fc 100644 --- a/packages/pn-commons/src/hooks/useIsMobile.ts +++ b/packages/pn-commons/src/hooks/useIsMobile.ts @@ -1,10 +1,10 @@ -import { useTheme } from '@mui/material'; +import { Breakpoint, useTheme } from '@mui/material'; import useMediaQuery from '@mui/material/useMediaQuery'; /** * Checks if we are on a mobile device */ -export const useIsMobile = () => { +export const useIsMobile = (breakpoint: Breakpoint | number = 'lg') => { const theme = useTheme(); - return useMediaQuery(theme.breakpoints.down('lg')); + return useMediaQuery(theme.breakpoints.down(breakpoint)); }; diff --git a/packages/pn-pa-webapp/src/components/Notifications/NotificationRecipientsDetail.tsx b/packages/pn-pa-webapp/src/components/Notifications/NotificationRecipientsDetail.tsx index 29b3ec76c3..f2284d9e51 100644 --- a/packages/pn-pa-webapp/src/components/Notifications/NotificationRecipientsDetail.tsx +++ b/packages/pn-pa-webapp/src/components/Notifications/NotificationRecipientsDetail.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; -import { Box, Button, DialogTitle, Grid, Typography } from '@mui/material'; import { useTranslation } from 'react-i18next'; + +import { Box, Button, DialogTitle, Grid, Typography } from '@mui/material'; import { CollapsedList, NotificationDetailRecipient,