Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into feature/rework_con…
Browse files Browse the repository at this point in the history
…tacts
  • Loading branch information
AndreaCimini90 committed Feb 11, 2025
2 parents 7c3a4c8 + fa34990 commit 405269a
Show file tree
Hide file tree
Showing 79 changed files with 838 additions and 528 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [2.11.1](https://github.com/pagopa/pn-frontend/compare/v2.11.0...v2.11.1) (2025-01-31)

**Note:** Version bump only for package pn-frontend





# [2.11.0](https://github.com/pagopa/pn-frontend/compare/v2.11.0-RC.2...v2.11.0) (2025-01-20)

**Note:** Version bump only for package pn-frontend
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
"version": "2.11.0",
"version": "2.11.1",
"npmClient": "yarn",
"useWorkspaces": true,
"command": {
Expand Down
8 changes: 8 additions & 0 deletions packages/pn-commons/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [2.11.1](https://github.com/pagopa/pn-frontend/compare/v2.11.0...v2.11.1) (2025-01-31)

**Note:** Version bump only for package @pagopa-pn/pn-commons





# [2.11.0](https://github.com/pagopa/pn-frontend/compare/v2.11.0-RC.2...v2.11.0) (2025-01-20)

**Note:** Version bump only for package @pagopa-pn/pn-commons
Expand Down
6 changes: 3 additions & 3 deletions packages/pn-commons/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pagopa-pn/pn-commons",
"version": "2.11.0",
"version": "2.11.1",
"private": true,
"main": "./src/index.ts",
"dependencies": {
Expand Down Expand Up @@ -63,7 +63,7 @@
"@typescript-eslint/eslint-plugin": "^6.7.3",
"@typescript-eslint/parser": "^6.7.3",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "^1.3.1",
"@vitest/coverage-v8": "^1.6.1",
"css-mediaquery": "^0.1.2",
"eslint": "7.11.0",
"eslint-config-prettier": "^8.10.0",
Expand All @@ -76,7 +76,7 @@
"prettier": "^2.8.8",
"sonarqube-scanner": "^3.3.0",
"vite": "^5.1.4",
"vitest": "1.3.1",
"vitest": "^1.6.1",
"vitest-sonar-reporter": "^2.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ReactElement, ReactNode, Ref, forwardRef, useImperativeHandle } from 'react';

import CloseIcon from '@mui/icons-material/Close';
import { Dialog, DialogTitle, Grid, Slide, Typography } from '@mui/material';
import { Dialog, DialogTitle, Grid, IconButton, Slide, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import { TransitionProps } from '@mui/material/transitions';

import { getLocalizedOrDefaultLabel } from '../../utility/localization.utility';
import { useCustomMobileDialogContext } from './CustomMobileDialog.context';

type Props = {
Expand Down Expand Up @@ -82,17 +83,19 @@ const CustomMobileDialogContent = forwardRef<{ toggleOpen: () => void }, Props>(
</Typography>
</Grid>
<Grid item xs={6} textAlign="right">
<CloseIcon
<IconButton
edge="end"
onClick={handleClose}
sx={{
position: 'relative',
right: 0,
top: 4,
color: 'action.active',
width: '32px',
height: '32px',
}}
/>
aria-label={getLocalizedOrDefaultLabel('common', 'button.close')}
>
<CloseIcon
sx={{
color: 'action.active',
width: '32px',
height: '32px',
}}
/>
</IconButton>
</Grid>
</Grid>
</DialogTitle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ const TagIndicator: React.FC<{
arrayChildren: Array<JSX.Element>;
visibleItems: number;
dataTestId: string;
}> = ({ boxProps, arrayChildren, visibleItems, dataTestId }) => (
<Box {...boxProps} sx={{ cursor: 'pointer', display: 'inline-block' }} data-testid={dataTestId}>
<Tag value={`+${arrayChildren.length - visibleItems}`} />
ariaLabel?: string;
}> = ({ boxProps, arrayChildren, visibleItems, dataTestId, ariaLabel }) => (
<Box
{...boxProps}
sx={{ cursor: 'pointer', display: 'inline-block' }}
data-testid={dataTestId}
aria-label={ariaLabel || undefined}
>
<Tag value={`+${arrayChildren.length - visibleItems}`} aria-hidden={!!ariaLabel} />
</Box>
);

Expand All @@ -50,14 +56,18 @@ const CustomTagGroup: React.FC<CustomTagGroupProps> = ({
onOpen={onOpen}
tooltipContent={<>{arrayChildren.slice(visibleItems).map((c) => c)}</>}
>
<div>
<Box sx={{ width: 'fit-content' }}>
<TagIndicator
boxProps={{ role: 'button' }}
arrayChildren={arrayChildren}
visibleItems={visibleItems as number}
dataTestId="custom-tooltip-indicator"
ariaLabel={arrayChildren
.slice(visibleItems)
.map((c) => c.props?.children?.props?.value) // <Box><Tag value={v}></Tag></Box>
.filter(Boolean)
.join(',')}
/>
</div>
</Box>
</CustomTooltip>
)}
{disableTooltip && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { vi } from 'vitest';

import { Box } from '@mui/material';
import { Tag } from '@pagopa/mui-italia';

import { fireEvent, render, screen, waitFor } from '../../../test-utils';
import CustomTagGroup from '../CustomTagGroup';

describe('CustomTagGroup component', () => {
const tagsArray = ['mock-tag-1', 'mock-tag-2', 'mock-tag-3', 'mock-tag-4'];
const tags = tagsArray.map((v, i) => <Box key={i}>{v}</Box>);
const tags = tagsArray.map((v, i) => (
<Box key={i}>
<Tag value={v}></Tag>
</Box>
));
const mockCallbackFn = vi.fn();

beforeEach(() => {
Expand Down Expand Up @@ -57,4 +62,15 @@ describe('CustomTagGroup component', () => {
expect(tooltip).not.toBeInTheDocument();
expect(mockCallbackFn).toBeCalledTimes(0);
});

it('renders component with limited 1 tags with aria-label', () => {
const { getByTestId } = render(
<CustomTagGroup visibleItems={2} disableTooltip={false}>
{tags}
</CustomTagGroup>
);
const tooltipIndicator = getByTestId('custom-tooltip-indicator');
expect(tooltipIndicator).toBeInTheDocument();
expect(tooltipIndicator).toHaveAttribute('aria-label', 'mock-tag-3,mock-tag-4');
});
});
41 changes: 16 additions & 25 deletions packages/pn-commons/src/components/CustomTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { cloneElement, useState } from 'react';

import { Box, SxProps } from '@mui/material';
import ClickAwayListener from '@mui/material/ClickAwayListener';
// ReactNode, cloneElement
import Tooltip, { TooltipProps } from '@mui/material/Tooltip';

type Props = {
tooltipContent: any;
openOnClick: boolean;
sx?: SxProps;
onOpen?: () => void;
children: JSX.Element;
tooltipProps?: Partial<TooltipProps>;
Expand All @@ -18,7 +14,6 @@ const CustomTooltip: React.FC<Props> = ({
openOnClick,
tooltipContent,
children,
sx,
onOpen,
tooltipProps,
}) => {
Expand All @@ -37,27 +32,23 @@ const CustomTooltip: React.FC<Props> = ({
};

return (
<ClickAwayListener onClickAway={handleTooltipClose}>
<Box sx={sx}>
<Tooltip
arrow
leaveTouchDelay={5000}
title={tooltipContent}
onClose={handleTooltipClose}
open={openOnClick ? open : undefined}
disableFocusListener={openOnClick}
disableHoverListener={openOnClick}
disableTouchListener={openOnClick}
enterTouchDelay={0}
onOpen={onOpen}
{...tooltipProps}
>
{openOnClick ? cloneElement(children, {
<Tooltip
arrow
leaveTouchDelay={5000}
title={tooltipContent}
onClose={handleTooltipClose}
open={openOnClick ? open : undefined}
disableHoverListener={openOnClick}
enterTouchDelay={0}
onOpen={onOpen}
{...tooltipProps}
>
{openOnClick
? cloneElement(children, {
onClick: handleTooltipOpen,
}) : children}
</Tooltip>
</Box>
</ClickAwayListener>
})
: children}
</Tooltip>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ const PnTableHeaderCell = <T,>({
direction={sort.orderBy === columnId ? sort.order : 'asc'}
onClick={sortHandler(columnId)}
data-testid={testId ? `${testId}.sort.${columnId.toString()}` : null}
sx={{
'&:focus-visible': {
borderRadius: '2px',
outlineOffset: '4px',
outline: '2px solid currentColor'
}
}}
>
{children}
{sort.orderBy === columnId && (
Expand Down
70 changes: 50 additions & 20 deletions packages/pn-commons/src/components/InactivityHandler.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Fragment, useEffect, useState } from 'react';
import { useEffect, useState } from 'react';

import { Button, DialogContentText, DialogTitle } from '@mui/material';

import { getLocalizedOrDefaultLabel } from '../utility/localization.utility';
import PnDialog from './PnDialog/PnDialog';
import PnDialogActions from './PnDialog/PnDialogActions';
import PnDialogContent from './PnDialog/PnDialogContent';

type Props = {
/** Inactivity timer (in milliseconds), if 0 the inactivity timer is disabled */
Expand All @@ -8,43 +15,66 @@ type Props = {
children?: React.ReactNode;
};

const InactivityHandler: React.FC<Props> = ({ inactivityTimer, children, onTimerExpired }) => {
const InactivityHandler: React.FC<Props> = ({ inactivityTimer, onTimerExpired, children }) => {
const [initTimeout, setInitTimeout] = useState(true);

const [openModal, setOpenModal] = useState(false);
const resetTimer = () => setInitTimeout(!initTimeout);

const initListeners = () => {
window.addEventListener('mousemove', resetTimer);
window.addEventListener('scroll', resetTimer);
window.addEventListener('keydown', resetTimer);
};

const cleanUpListeners = () => {
window.removeEventListener('mousemove', resetTimer);
window.removeEventListener('scroll', resetTimer);
window.removeEventListener('keydown', resetTimer);
};

// init timer
useEffect(() => {
if (inactivityTimer) {
// init listeners
initListeners();
// this is the timer after wich the inactivity modal is shown
const inactivityWarningTimer = inactivityTimer - 30 * 1000;
// init timer
const timer = setTimeout(() => {
cleanUpListeners();
onTimerExpired();
}, inactivityTimer);

const warningTimer = setTimeout(() => {
setOpenModal(true);
}, inactivityWarningTimer);

// cleanup function
return () => {
setOpenModal(false);
clearTimeout(timer);
cleanUpListeners();
clearTimeout(warningTimer);
};
}
return () => {};
}, [initTimeout]);

return <Fragment>{children}</Fragment>;
return (
<>
<PnDialog
open={openModal}
aria-labelledby="inactivity-dialog-title"
aria-describedby="inactivity-dialog-description"
data-testid="inactivity-modal"
>
<DialogTitle id="inactivity-dialog-title">
{getLocalizedOrDefaultLabel('common', 'inactivity.title')}
</DialogTitle>
<PnDialogContent>
<DialogContentText id="inactivity-dialog-description">
{getLocalizedOrDefaultLabel('common', 'inactivity.body')}
</DialogContentText>
</PnDialogContent>
<PnDialogActions>
<Button
fullWidth
color="primary"
variant="outlined"
data-testid="inactivity-button"
onClick={resetTimer}
>
{getLocalizedOrDefaultLabel('common', 'inactivity.action')}
</Button>
</PnDialogActions>
</PnDialog>
{children}
</>
);
};

export default InactivityHandler;
Loading

0 comments on commit 405269a

Please sign in to comment.