diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f89ebeaab..ecb848b7dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,48 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package pn-frontend + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package pn-frontend + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + + +### Bug Fixes + +* **pn-13210:** manage accessibility when closing modal ([#1451](https://github.com/pagopa/pn-frontend/issues/1451)) ([2b4981b](https://github.com/pagopa/pn-frontend/commit/2b4981bddc8f6651ac47bb2cf371f63e33962959)) +* **pn-13211:** Removed redirect when login fails ([#1445](https://github.com/pagopa/pn-frontend/issues/1445)) ([6ff0d2a](https://github.com/pagopa/pn-frontend/commit/6ff0d2aec98f161d5f23e7af49e41c31c7a7dcb7)) +* **pn-13213:** aria label for payments and statistics checkboxes ([#1450](https://github.com/pagopa/pn-frontend/issues/1450)) ([0d4d250](https://github.com/pagopa/pn-frontend/commit/0d4d25007aa3c2012c6bd3cba235cc32e8d65be1)) +* **pn-13214:** inactivity handler accessibility ([#1454](https://github.com/pagopa/pn-frontend/issues/1454)) ([7af07bd](https://github.com/pagopa/pn-frontend/commit/7af07bdc5861815ae484e0856d17f80ec3ac6096)) +* **pn-13216:** Added descriptions to radio buttons ([#1444](https://github.com/pagopa/pn-frontend/issues/1444)) ([9fb7b79](https://github.com/pagopa/pn-frontend/commit/9fb7b79a755c6850d9ec2ffbb62aff60ec88e7a1)) +* **pn-13255:** fixed aria attributes on the modal for revoking the delegation ([#1453](https://github.com/pagopa/pn-frontend/issues/1453)) ([cf2bfd9](https://github.com/pagopa/pn-frontend/commit/cf2bfd9844c412aa7f881a833c2fcaae01650355)) +* **pn-13591:** Handle Calendar for a11y ([#1448](https://github.com/pagopa/pn-frontend/issues/1448)) ([7be12df](https://github.com/pagopa/pn-frontend/commit/7be12dfb572f2eb50e3f857d78174410b1a181ac)) +* **pn-13593:** screen reader doesn't read api key value ([#1449](https://github.com/pagopa/pn-frontend/issues/1449)) ([7b11fb7](https://github.com/pagopa/pn-frontend/commit/7b11fb7ceb22d46bfd4dcea6bcbb6e1a2c3f85ae)) +* **pn-13596:** screen reader doesn't read notification status tooltip on mobile ([#1439](https://github.com/pagopa/pn-frontend/issues/1439)) ([b28f472](https://github.com/pagopa/pn-frontend/commit/b28f47258e5bd3cf4d9a2a3c95b86bfb42114ce8)) +* **pn-13598:** accessibility for the delegation tag group ([#1452](https://github.com/pagopa/pn-frontend/issues/1452)) ([a8626a2](https://github.com/pagopa/pn-frontend/commit/a8626a27ca23f9de030bc0b51d825d685bcee737)) + + +### Features + +* **pn-13215:** Screen reader doesn't read all the attachments in timeline ([#1442](https://github.com/pagopa/pn-frontend/issues/1442)) ([877bf49](https://github.com/pagopa/pn-frontend/commit/877bf49c486485f9e0ce6b04b6423a78824180e8)) +* **pn-13595:** removed automatic redirect before logout ([#1456](https://github.com/pagopa/pn-frontend/issues/1456)) ([c7d823f](https://github.com/pagopa/pn-frontend/commit/c7d823f72e9e64eeeccfcafebb0b05f4b188959c)) + + + + + ## [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 diff --git a/lerna.json b/lerna.json index af92cdeea7..d3336a0e5d 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "2.11.1", + "version": "2.12.0", "npmClient": "yarn", "useWorkspaces": true, "command": { diff --git a/packages/pn-commons/CHANGELOG.md b/packages/pn-commons/CHANGELOG.md index cc79cfc7b8..d2a0273333 100644 --- a/packages/pn-commons/CHANGELOG.md +++ b/packages/pn-commons/CHANGELOG.md @@ -3,6 +3,43 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package @pagopa-pn/pn-commons + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package @pagopa-pn/pn-commons + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + + +### Bug Fixes + +* **pn-13210:** manage accessibility when closing modal ([#1451](https://github.com/pagopa/pn-frontend/issues/1451)) ([2b4981b](https://github.com/pagopa/pn-frontend/commit/2b4981bddc8f6651ac47bb2cf371f63e33962959)) +* **pn-13213:** aria label for payments and statistics checkboxes ([#1450](https://github.com/pagopa/pn-frontend/issues/1450)) ([0d4d250](https://github.com/pagopa/pn-frontend/commit/0d4d25007aa3c2012c6bd3cba235cc32e8d65be1)) +* **pn-13214:** inactivity handler accessibility ([#1454](https://github.com/pagopa/pn-frontend/issues/1454)) ([7af07bd](https://github.com/pagopa/pn-frontend/commit/7af07bdc5861815ae484e0856d17f80ec3ac6096)) +* **pn-13591:** Handle Calendar for a11y ([#1448](https://github.com/pagopa/pn-frontend/issues/1448)) ([7be12df](https://github.com/pagopa/pn-frontend/commit/7be12dfb572f2eb50e3f857d78174410b1a181ac)) +* **pn-13596:** screen reader doesn't read notification status tooltip on mobile ([#1439](https://github.com/pagopa/pn-frontend/issues/1439)) ([b28f472](https://github.com/pagopa/pn-frontend/commit/b28f47258e5bd3cf4d9a2a3c95b86bfb42114ce8)) +* **pn-13598:** accessibility for the delegation tag group ([#1452](https://github.com/pagopa/pn-frontend/issues/1452)) ([a8626a2](https://github.com/pagopa/pn-frontend/commit/a8626a27ca23f9de030bc0b51d825d685bcee737)) + + +### Features + +* **pn-13215:** Screen reader doesn't read all the attachments in timeline ([#1442](https://github.com/pagopa/pn-frontend/issues/1442)) ([877bf49](https://github.com/pagopa/pn-frontend/commit/877bf49c486485f9e0ce6b04b6423a78824180e8)) + + + + + ## [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 diff --git a/packages/pn-commons/package.json b/packages/pn-commons/package.json index 7a8ccf4a63..c028d32e09 100644 --- a/packages/pn-commons/package.json +++ b/packages/pn-commons/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa-pn/pn-commons", - "version": "2.11.1", + "version": "2.12.0", "private": true, "main": "./src/index.ts", "dependencies": { diff --git a/packages/pn-commons/src/components/AppStatus/DowntimeLogDataSwitch.tsx b/packages/pn-commons/src/components/AppStatus/DowntimeLogDataSwitch.tsx index 22ec4990b6..cd4d6d7ab9 100644 --- a/packages/pn-commons/src/components/AppStatus/DowntimeLogDataSwitch.tsx +++ b/packages/pn-commons/src/components/AppStatus/DowntimeLogDataSwitch.tsx @@ -21,7 +21,11 @@ const FormattedDateAndTime: React.FC<{ date: string; inTwoLines?: boolean }> = ( {formatDateTime(date)} ); } - return -; + return ( + + {getLocalizedOrDefaultLabel('appStatus', 'appStatus.missed-endDate')} + + ); }; const DowntimeLogDataSwitch: React.FC<{ diff --git a/packages/pn-commons/src/components/CustomTooltip.tsx b/packages/pn-commons/src/components/CustomTooltip.tsx index c5d2ab5844..4fad610e37 100644 --- a/packages/pn-commons/src/components/CustomTooltip.tsx +++ b/packages/pn-commons/src/components/CustomTooltip.tsx @@ -17,7 +17,6 @@ const CustomTooltip: React.FC = ({ onOpen, tooltipProps, }) => { - // tooltip state const [open, setOpen] = useState(false); const handleTooltipClose = () => { if (openOnClick) { diff --git a/packages/pn-commons/src/components/Data/PnTable/PnTableBodyCell.tsx b/packages/pn-commons/src/components/Data/PnTable/PnTableBodyCell.tsx index fdd9a10eae..6fd56d4996 100644 --- a/packages/pn-commons/src/components/Data/PnTable/PnTableBodyCell.tsx +++ b/packages/pn-commons/src/components/Data/PnTable/PnTableBodyCell.tsx @@ -1,6 +1,5 @@ -import { Box, SxProps, TableCell } from '@mui/material'; +import { SxProps, TableCell } from '@mui/material'; import { ButtonNaked } from '@pagopa/mui-italia'; - import { buttonNakedInheritStyle } from '../../../utility'; export type PnTableBodyCellProps = { @@ -23,17 +22,14 @@ const PnTableBodyCell: React.FC = ({ ...cellProps!, borderBottom: 'none', }} - onClick={onClick} > - {onClick && ( - <> - {/* Even there is a onClick function on the TableCell, leave ButtonNaked below as is. - This makes spacebar key with accessibility to trigger the onClick function. - The ButtonNaked "inherits" the onClick action from the outer TableCell, so that is not necessary to replicate it. */} - {children} - + {onClick ? ( + + {children} + + ) : ( + <>{children} )} - {!onClick && {children}} ); export default PnTableBodyCell; diff --git a/packages/pn-commons/src/components/Data/PnTable/__test__/PnTableBodyCell.test.tsx b/packages/pn-commons/src/components/Data/PnTable/__test__/PnTableBodyCell.test.tsx index 93fa385e1b..f059754b6f 100644 --- a/packages/pn-commons/src/components/Data/PnTable/__test__/PnTableBodyCell.test.tsx +++ b/packages/pn-commons/src/components/Data/PnTable/__test__/PnTableBodyCell.test.tsx @@ -1,18 +1,17 @@ import { vi } from 'vitest'; -import { disableConsoleLogging, fireEvent, render } from '../../../../test-utils'; +import { disableConsoleLogging, fireEvent, render, within } from '../../../../test-utils'; import PnTableBodyCell from '../PnTableBodyCell'; describe('PnTableBodyCell', () => { disableConsoleLogging('error'); - const mockFn = vi.fn(); it('render component', () => { const { container, queryByTestId } = render( - mocke-cell-content + mocked-cell-content ); - expect(container).toHaveTextContent(/mocke-cell-content/); + expect(container).toHaveTextContent(/mocked-cell-content/); const buttons = queryByTestId('cell.button'); expect(buttons).not.toBeInTheDocument(); }); @@ -20,11 +19,12 @@ describe('PnTableBodyCell', () => { it('click cell event', () => { const { getByTestId } = render( mockFn()}> - mocke-cell-content + mocked-cell-content ); const cell = getByTestId('cell'); - fireEvent.click(cell); - expect(mockFn).toBeCalledTimes(1); + const button = within(cell).getByRole('button'); + fireEvent.click(button); + expect(mockFn).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/pn-commons/src/components/Data/SmartTable/__test__/SmartData.test.tsx b/packages/pn-commons/src/components/Data/SmartTable/__test__/SmartData.test.tsx index 31ae4c9236..db48ad869c 100644 --- a/packages/pn-commons/src/components/Data/SmartTable/__test__/SmartData.test.tsx +++ b/packages/pn-commons/src/components/Data/SmartTable/__test__/SmartData.test.tsx @@ -92,9 +92,7 @@ const RenderSmartData: React.FC<{ { const sortableColumn = smartCfg.find((cfg) => cfg.tableConfiguration.sortable); const sortToggle = within(table).getByTestId(`headerCellDesktop.sort.${sortableColumn!.id}`); fireEvent.click(sortToggle); - expect(handleSort).toBeCalledTimes(1); + expect(handleSort).toHaveBeenCalledTimes(1); const clickableColumnIdx = smartCfg.findIndex((cfg) => cfg.tableConfiguration.onClick); const rows = within(table).getAllByTestId('bodyRowDesktop'); // we can take the row we want const cells = within(rows[0]).getAllByTestId('rowCellDesktop'); - fireEvent.click(cells[clickableColumnIdx]); - expect(handleColumnClick).toBeCalledTimes(1); + const button = within(cells[clickableColumnIdx]).getByRole('button'); + fireEvent.click(button); + expect(handleColumnClick).toHaveBeenCalledTimes(1); }); it('no sort available (desktop version)', () => { @@ -193,6 +192,6 @@ describe('SmartData', () => { const action = cardActions[0]; expect(action).toHaveTextContent('Mocked action'); fireEvent.click(action); - expect(clickActionMockFn).toBeCalledTimes(1); + expect(clickActionMockFn).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/pn-commons/src/components/Data/__test__/PnTable.test.tsx b/packages/pn-commons/src/components/Data/__test__/PnTable.test.tsx index 269e38c655..edf83df93a 100644 --- a/packages/pn-commons/src/components/Data/__test__/PnTable.test.tsx +++ b/packages/pn-commons/src/components/Data/__test__/PnTable.test.tsx @@ -110,8 +110,8 @@ describe('PnTable Component', () => { const sortButton = within(firstColumn).getByRole('button'); expect(sortButton).toBeInTheDocument(); fireEvent.click(sortButton); - expect(handleSort).toBeCalledTimes(1); - expect(handleSort).toBeCalledWith({ order: 'desc', orderBy: 'column-1' }); + expect(handleSort).toHaveBeenCalledTimes(1); + expect(handleSort).toHaveBeenCalledWith({ order: 'desc', orderBy: 'column-1' }); }); it('click on a column', () => { @@ -121,8 +121,8 @@ describe('PnTable Component', () => { const firstRow = within(tableBody).getAllByTestId('table-test.body.row')[0]; const tableColumns = within(firstRow).getAllByTestId('table-test.body.row.cell'); fireEvent.click(tableColumns[2].querySelectorAll('button')[0]); - expect(handleColumnClick).toBeCalledTimes(1); - expect(handleColumnClick).toBeCalledWith(rows[0], columns[2].id); + expect(handleColumnClick).toHaveBeenCalledTimes(1); + expect(handleColumnClick).toHaveBeenCalledWith(rows[0], columns[2].id); }); it('render component - multiple PnTableBody', () => { @@ -153,7 +153,7 @@ describe('PnTable Component', () => { ) - ).toThrowError('PnTable can have only 1 child of type PnTableHeader'); + ).toThrow('PnTable can have only 1 child of type PnTableHeader'); }); it('render component - multiple PnTableHeader', () => { @@ -188,7 +188,7 @@ describe('PnTable Component', () => { ) - ).toThrowError('PnTable can have only 1 child of type PnTableHeader'); + ).toThrow('PnTable can have only 1 child of type PnTableHeader'); }); it('render component - incorrect child', () => { @@ -211,7 +211,7 @@ describe('PnTable Component', () => { Incorrect child ) - ).toThrowError( + ).toThrow( 'PnTable can have only 1 child of type PnTableHeader and 1 child of type PnTableBody' ); }); diff --git a/packages/pn-commons/src/components/Data/__test__/SmartTable.test.tsx b/packages/pn-commons/src/components/Data/__test__/SmartTable.test.tsx index fe0738f87c..c5ad3727f5 100644 --- a/packages/pn-commons/src/components/Data/__test__/SmartTable.test.tsx +++ b/packages/pn-commons/src/components/Data/__test__/SmartTable.test.tsx @@ -115,9 +115,7 @@ const RenderSmartable: React.FC<{ @@ -153,10 +151,10 @@ describe('Smart Table Component', () => { const itemsPerPageSelectorBtn = itemsPerPageSelector.querySelector('button'); fireEvent.click(itemsPerPageSelectorBtn!); const itemsPerPageList = getAllByRole('menuitem'); - fireEvent.click(itemsPerPageList[1]!); + fireEvent.click(itemsPerPageList[1]); await waitFor(() => { - expect(handleChangePagination).toBeCalledTimes(1); - expect(handleChangePagination).toBeCalledWith({ + expect(handleChangePagination).toHaveBeenCalledTimes(1); + expect(handleChangePagination).toHaveBeenCalledWith({ size: 20, page: 0, totalElements: 100, @@ -168,8 +166,8 @@ describe('Smart Table Component', () => { // the buttons are < 1 2 3 > fireEvent.click(pageButtons[2]); await waitFor(() => { - expect(handleChangePagination).toBeCalledTimes(2); - expect(handleChangePagination).toBeCalledWith({ + expect(handleChangePagination).toHaveBeenCalledTimes(2); + expect(handleChangePagination).toHaveBeenCalledWith({ size: 20, page: 1, totalElements: 100, @@ -208,9 +206,7 @@ describe('Smart Table Component', () => { @@ -227,9 +223,7 @@ describe('Smart Table Component', () => { @@ -241,7 +235,7 @@ describe('Smart Table Component', () => { ) - ).toThrowError('SmartTable can have only 1 child of type SmartBody'); + ).toThrow('SmartTable can have only 1 child of type SmartBody'); }); it('render component - multiple SmartHeader', () => { @@ -272,7 +266,7 @@ describe('Smart Table Component', () => { ) - ).toThrowError('SmartTable can have only 1 child of type SmartHeader'); + ).toThrow('SmartTable can have only 1 child of type SmartHeader'); }); it('render component - multiple SmartFilter', () => { @@ -314,7 +308,7 @@ describe('Smart Table Component', () => { ) - ).toThrowError('SmartTable can have only 1 child of type SmartFilter'); + ).toThrow('SmartTable can have only 1 child of type SmartFilter'); }); it('render component - incorrect child', () => { @@ -335,7 +329,7 @@ describe('Smart Table Component', () => { Incorrect child ) - ).toThrowError( + ).toThrow( 'SmartTable can have only 1 child of type SmartFilter, 1 child of type SmartHeader and 1 child of type SmartBody' ); }); diff --git a/packages/pn-commons/src/components/Notifications/NotificationsDataSwitch.tsx b/packages/pn-commons/src/components/Notifications/NotificationsDataSwitch.tsx index 2790fb4257..37655f339a 100644 --- a/packages/pn-commons/src/components/Notifications/NotificationsDataSwitch.tsx +++ b/packages/pn-commons/src/components/Notifications/NotificationsDataSwitch.tsx @@ -1,24 +1,42 @@ -import { Typography } from '@mui/material'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import { Box, Typography } from '@mui/material'; +import { ButtonNaked } from '@pagopa/mui-italia'; import { useIsMobile } from '../../hooks'; import { Notification, NotificationColumnData, Row } from '../../models'; import { formatDate, getNotificationStatusInfos } from '../../utility'; +import { getLocalizedOrDefaultLabel } from '../../utility/localization.utility'; import NewNotificationBadge, { isNewNotification } from './NewNotificationBadge'; import StatusTooltip from './StatusTooltip'; -const NotificationStatusChip: React.FC<{ - data: Row; -}> = ({ data }) => { +const NotificationStatusChip: React.FC<{ data: Row }> = ({ data }) => { const { label, tooltip, color } = getNotificationStatusInfos(data.notificationStatus, { recipients: data.recipients, }); return ; }; +const ActionButton: React.FC<{ + mandateId?: string; + iun: string; + handleRowClick?: (iun: string, mandateId?: string) => void; +}> = ({ mandateId, iun, handleRowClick }) => ( + handleRowClick && handleRowClick(iun, mandateId)} + aria-label={getLocalizedOrDefaultLabel('notifications', 'table.aria-action-table', undefined, { + iun, + })} + > + + +); + const NotificationsDataSwitch: React.FC<{ data: Row; type: keyof NotificationColumnData; -}> = ({ data, type }) => { + handleRowClick?: (iun: string, mandateId?: string) => void; +}> = ({ data, type, handleRowClick }) => { const isMobile = useIsMobile(); if (type === 'badge') { @@ -46,7 +64,18 @@ const NotificationsDataSwitch: React.FC<{ return <>{data.sender}; } if (type === 'subject') { - return <>{data.subject.length > 65 ? data.subject.substring(0, 65) + '...' : data.subject}; + return ( + + {data.subject} + + ); } if (type === 'iun') { return <>{data.iun}; @@ -65,6 +94,11 @@ const NotificationsDataSwitch: React.FC<{ ); } + if (type === 'action') { + return ( + + ); + } return <>; }; diff --git a/packages/pn-commons/src/components/Notifications/StatusTooltip.tsx b/packages/pn-commons/src/components/Notifications/StatusTooltip.tsx index 00193b53b3..6bef4b1403 100644 --- a/packages/pn-commons/src/components/Notifications/StatusTooltip.tsx +++ b/packages/pn-commons/src/components/Notifications/StatusTooltip.tsx @@ -33,7 +33,7 @@ const StatusTooltip = ({ cursor: 'default', }} data-testid={`statusChip-${label}`} - aria-label={isMobile ? `${label}: ${tooltip}` : undefined} + aria-label={`${label}: ${tooltip}`} /> ); diff --git a/packages/pn-commons/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx b/packages/pn-commons/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx index 8598c53171..a933c17ec6 100644 --- a/packages/pn-commons/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx +++ b/packages/pn-commons/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx @@ -1,7 +1,7 @@ import { vi } from 'vitest'; import { NotificationStatus } from '../../../models'; -import { createMatchMedia, render } from '../../../test-utils'; +import { createMatchMedia, fireEvent, render } from '../../../test-utils'; import { formatDate, getNotificationStatusInfos } from '../../../utility'; import NotificationsDataSwitch from '../NotificationsDataSwitch'; @@ -100,4 +100,15 @@ describe('NotificationsDataSwitch Component', () => { const regexp = new RegExp(`^${data.recipients.join('')}$`, 'ig'); expect(container).toHaveTextContent(regexp); }); + + it('renders component - action', () => { + const clickFn = vi.fn(); + const { getByTestId } = render( + + ); + const button = getByTestId('goToNotificationDetail'); + expect(button).toBeInTheDocument(); + fireEvent.click(button); + expect(clickFn).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/pn-commons/src/models/Notifications.ts b/packages/pn-commons/src/models/Notifications.ts index 6772e9aad2..9a4f8c27cc 100644 --- a/packages/pn-commons/src/models/Notifications.ts +++ b/packages/pn-commons/src/models/Notifications.ts @@ -31,4 +31,5 @@ export interface GetNotificationsParams { group?: string; } -export type NotificationColumnData = Notification & { badge: string }; +export type NotificationColumnData = Notification & { badge?: string; action:string } ; + diff --git a/packages/pn-data-viz/CHANGELOG.md b/packages/pn-data-viz/CHANGELOG.md index 8a38b5a085..405740a1d2 100644 --- a/packages/pn-data-viz/CHANGELOG.md +++ b/packages/pn-data-viz/CHANGELOG.md @@ -3,6 +3,33 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package @pagopa-pn/pn-data-viz + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package @pagopa-pn/pn-data-viz + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + + +### Bug Fixes + +* **pn-13213:** aria label for payments and statistics checkboxes ([#1450](https://github.com/pagopa/pn-frontend/issues/1450)) ([0d4d250](https://github.com/pagopa/pn-frontend/commit/0d4d25007aa3c2012c6bd3cba235cc32e8d65be1)) + + + + + ## [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-data-viz diff --git a/packages/pn-data-viz/package.json b/packages/pn-data-viz/package.json index 208f38bf96..4847c4a06e 100644 --- a/packages/pn-data-viz/package.json +++ b/packages/pn-data-viz/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa-pn/pn-data-viz", - "version": "2.11.1", + "version": "2.12.0", "private": true, "description": "SEND component library for data visualization", "keywords": [ diff --git a/packages/pn-pa-webapp/CHANGELOG.md b/packages/pn-pa-webapp/CHANGELOG.md index 91466f126a..bcc0e4aaa9 100644 --- a/packages/pn-pa-webapp/CHANGELOG.md +++ b/packages/pn-pa-webapp/CHANGELOG.md @@ -3,6 +3,41 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package @pagopa-pn/pn-pa-webapp + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package @pagopa-pn/pn-pa-webapp + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + + +### Bug Fixes + +* **pn-13210:** manage accessibility when closing modal ([#1451](https://github.com/pagopa/pn-frontend/issues/1451)) ([2b4981b](https://github.com/pagopa/pn-frontend/commit/2b4981bddc8f6651ac47bb2cf371f63e33962959)) +* **pn-13214:** inactivity handler accessibility ([#1454](https://github.com/pagopa/pn-frontend/issues/1454)) ([7af07bd](https://github.com/pagopa/pn-frontend/commit/7af07bdc5861815ae484e0856d17f80ec3ac6096)) +* **pn-13593:** screen reader doesn't read api key value ([#1449](https://github.com/pagopa/pn-frontend/issues/1449)) ([7b11fb7](https://github.com/pagopa/pn-frontend/commit/7b11fb7ceb22d46bfd4dcea6bcbb6e1a2c3f85ae)) +* **pn-13596:** screen reader doesn't read notification status tooltip on mobile ([#1439](https://github.com/pagopa/pn-frontend/issues/1439)) ([b28f472](https://github.com/pagopa/pn-frontend/commit/b28f47258e5bd3cf4d9a2a3c95b86bfb42114ce8)) + + +### Features + +* **pn-13595:** removed automatic redirect before logout ([#1456](https://github.com/pagopa/pn-frontend/issues/1456)) ([c7d823f](https://github.com/pagopa/pn-frontend/commit/c7d823f72e9e64eeeccfcafebb0b05f4b188959c)) + + + + + ## [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-pa-webapp diff --git a/packages/pn-pa-webapp/package.json b/packages/pn-pa-webapp/package.json index f392c6ab8d..06d6d2c76d 100644 --- a/packages/pn-pa-webapp/package.json +++ b/packages/pn-pa-webapp/package.json @@ -1,7 +1,7 @@ { "name": "@pagopa-pn/pn-pa-webapp", "description": "Backoffice di SEND per la Pubblica Amministrazione", - "version": "2.11.1", + "version": "2.12.0", "private": true, "dependencies": { "@emotion/react": "^11.11.1", diff --git a/packages/pn-pa-webapp/public/js/config.js b/packages/pn-pa-webapp/public/js/config.js index 287af7041f..58a5338318 100644 --- a/packages/pn-pa-webapp/public/js/config.js +++ b/packages/pn-pa-webapp/public/js/config.js @@ -1,4 +1,4 @@ -const regex = new RegExp('https://selfcare.((dev|test|uat|hotfix).?)notifichedigitali.it'); +const regex = new RegExp('https://selfcare\\.(((dev|test|uat|hotfix)\\.)?)notifichedigitali\\.it') const origin = window.origin; if (regex.test(origin)) { document.write(``); diff --git a/packages/pn-pa-webapp/public/locales/it/appStatus.json b/packages/pn-pa-webapp/public/locales/it/appStatus.json index 044d621e13..cee76e07c7 100644 --- a/packages/pn-pa-webapp/public/locales/it/appStatus.json +++ b/packages/pn-pa-webapp/public/locales/it/appStatus.json @@ -6,7 +6,9 @@ "ok": "Tutti i servizi di SEND sono operativi.", "not-ok": "C'è un disservizio in corso. Per maggiori dettagli, consulta la tabella qui sotto." }, - "lastCheckLegend": "Ultimo aggiornamento - {{ lastCheckTimestamp }}" + "lastCheckLegend": "Ultimo aggiornamento - {{ lastCheckTimestamp }}", + "aria-missed-endDate": "Data fine mancante, disservizio in corso", + "missed-endDate": "In corso" }, "downtimeList": { "title": "Storico dei disservizi", diff --git a/packages/pn-pa-webapp/public/locales/it/notifiche.json b/packages/pn-pa-webapp/public/locales/it/notifiche.json index 8f7fb9c352..d1c55e9d8b 100644 --- a/packages/pn-pa-webapp/public/locales/it/notifiche.json +++ b/packages/pn-pa-webapp/public/locales/it/notifiche.json @@ -37,7 +37,8 @@ "iun": "Codice IUN", "groups": "Gruppi", "status": "Stato", - "show-detail": "Vedi dettaglio" + "show-detail": "Vedi dettaglio", + "aria-action-table": "Vedi dettaglio notifica con iun : {{iun}}" }, "sort": { "title": "Ordina", @@ -382,7 +383,7 @@ "canceled": "Annullata", "canceled-tooltip": "L'ente ha annullato l'invio della notifica", "canceled-description": "L'ente ha annullato l'invio della notifica.", - "returned-to-sender":"Resa al mittente", + "returned-to-sender": "Resa al mittente", "returned-to-sender-tooltip": "Il destinatario risulta deceduto", "returned-to-sender-tooltip-multirecipient": "Tutti i destinatari risultano deceduti", "returned-to-sender-description": "Il destinatario risulta deceduto.", diff --git a/packages/pn-pa-webapp/public/locales/it/statistics.json b/packages/pn-pa-webapp/public/locales/it/statistics.json index 77c91106c7..f43947808e 100644 --- a/packages/pn-pa-webapp/public/locales/it/statistics.json +++ b/packages/pn-pa-webapp/public/locales/it/statistics.json @@ -84,7 +84,15 @@ "pec_title": "Errore di dominio PEC", "pec_description": "La notifica non è stata recapitata per dominio PEC non valido", "rejected_title": "Errore d'invio", - "rejected_description": "La notifica non è stata accettata per problemi tecnici d'invio" + "rejected_description": "La notifica non è stata accettata per problemi tecnici d'invio", + "virus_detected_title": "Rilevato virus", + "virus_detected_description": "La notifica non è stata recapitata a causa della rilevazione di un virus nella comunicazione o nei suoi allegati", + "server_pec_comunication_title": "Errore di comunicazione con il server PEC", + "server_pec_comunication_description": "La notifica non è stata recapitata a causa di un errore nella comunicazione con il server di invio PEC", + "sending_pec_title": "Errore durante l'invio della PEC", + "sending_pec_description": "La notifica non è stata recapitata a causa di un errore tecnico", + "malformed_pec_address_title": "Errore di indirizzo PEC", + "malformed_pec_address_description": "La notifica non è stata recapitata perchè l’indirizzo PEC è malformato" }, "empty": { "no_data_found": "Non ci sono dati a disposizione per l'intervallo di tempo selezionato", diff --git a/packages/pn-pa-webapp/src/__mocks__/Statistics.mock.ts b/packages/pn-pa-webapp/src/__mocks__/Statistics.mock.ts index dd0a734930..57f49851fd 100644 --- a/packages/pn-pa-webapp/src/__mocks__/Statistics.mock.ts +++ b/packages/pn-pa-webapp/src/__mocks__/Statistics.mock.ts @@ -294,6 +294,10 @@ export const parsedResponseMock: StatisticsParsedResponse = { [DigitaErrorTypes.INVALID_PEC]: { count: 4, attempts: 7 }, [DigitaErrorTypes.DELIVERY_ERROR]: { count: 4, attempts: 11 }, [DigitaErrorTypes.REJECTED]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.SENDING_PEC]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.SERVER_PEC_COMUNICATION]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.VIRUS_DETECTED]: { count: 0, attempts: 0 }, [DigitaErrorTypes.UNKNOWN]: { count: 461, attempts: 0 }, }, }, @@ -348,6 +352,10 @@ export const parsedEmptyResponseMock: StatisticsParsedResponse = { [DigitaErrorTypes.INVALID_PEC]: { count: 0, attempts: 0 }, [DigitaErrorTypes.DELIVERY_ERROR]: { count: 0, attempts: 0 }, [DigitaErrorTypes.REJECTED]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.SENDING_PEC]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.SERVER_PEC_COMUNICATION]: { count: 0, attempts: 0 }, + [DigitaErrorTypes.VIRUS_DETECTED]: { count: 0, attempts: 0 }, [DigitaErrorTypes.UNKNOWN]: { count: 0, attempts: 0 }, }, }, @@ -436,6 +444,22 @@ export const digitalErrorsEmptyDataMock = { count: 0, attempts: 0, }, + [DigitaErrorTypes.VIRUS_DETECTED]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.SERVER_PEC_COMUNICATION]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.SENDING_PEC]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: { + count: 0, + attempts: 0, + }, }, }; diff --git a/packages/pn-pa-webapp/src/__test__/config.test.js b/packages/pn-pa-webapp/src/__test__/config.test.js new file mode 100644 index 0000000000..7d94b4e1ea --- /dev/null +++ b/packages/pn-pa-webapp/src/__test__/config.test.js @@ -0,0 +1,56 @@ +import fs from 'fs'; +import { JSDOM } from 'jsdom'; +import path from 'path'; +import { vi } from 'vitest'; + +const emptyHTML = ''; +const scriptContent = fs.readFileSync(path.resolve(__dirname, '../../public/js/config.js'), 'utf8'); + +describe('config.js behavior', () => { + let dom; + let document; + + beforeAll(() => { + dom = new JSDOM(emptyHTML, { + runScripts: 'dangerously', + resources: 'usable', + }); + + document = dom.window.document; + vi.spyOn(document, 'write').mockImplementation(() => {}); + }); + + test('should add noindex meta tag when URL matches regex', async () => { + const origins = [ + 'https://selfcare.notifichedigitali.it', + 'https://selfcare.dev.notifichedigitali.it/', + 'https://selfcare.test.notifichedigitali.it/', + 'https://selfcare.uat.notifichedigitali.it/', + 'https://selfcare.hotfix.notifichedigitali.it/', + ]; + + for (const origin of origins) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).toHaveBeenCalledWith(``); + } + }); + + test('should not add noindex meta tag when URL does not match regex', async () => { + const origins = [ + 'https://selfcare.testnotifichedigitali.it', + 'https://selfcare.prod.notifichedigitali.it', + 'https://otherapp.dev.notifichedigitali.it', + 'https://selfcare.notifichedigitali-it', + 'https://selfcare-notifichedigitali.it', + ]; + + for (const origin of origins) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).not.toHaveBeenCalled(); + } + }); +}); diff --git a/packages/pn-pa-webapp/src/components/Notifications/DesktopNotifications.tsx b/packages/pn-pa-webapp/src/components/Notifications/DesktopNotifications.tsx index cdb43fcee3..e488606942 100644 --- a/packages/pn-pa-webapp/src/components/Notifications/DesktopNotifications.tsx +++ b/packages/pn-pa-webapp/src/components/Notifications/DesktopNotifications.tsx @@ -14,9 +14,9 @@ import { PnTableBodyRow, PnTableHeader, PnTableHeaderCell, - Row, Sort, } from '@pagopa-pn/pn-commons'; +import { NotificationColumnData } from '@pagopa-pn/pn-commons/src/models/Notifications'; import * as routes from '../../navigation/routes.const'; import FilterNotifications from './FilterNotifications'; @@ -25,9 +25,9 @@ import NotificationsDataSwitch from './NotificationsDataSwitch'; type Props = { notifications: Array; /** Table sort */ - sort?: Sort; + sort?: Sort; /** The function to be invoked if the user change sorting */ - onChangeSorting?: (s: Sort) => void; + onChangeSorting?: (s: Sort) => void; /** The function to be invoked if the user clicks on new notification link */ onManualSend: () => void; /** The function to be invoked if the user clicks on api keys link */ @@ -98,37 +98,37 @@ const DesktopNotifications = ({ onManualSend, onApiKeys, }: Props) => { - const navigate = useNavigate(); const filterNotificationsRef = useRef({ filtersApplied: false, cleanFilters: () => void 0 }); const { t } = useTranslation(['notifiche']); + const navigate = useNavigate(); - const columns: Array> = [ + const columns: Array> = [ { id: 'sentAt', label: t('table.date'), - cellProps: { width: '11%' }, + cellProps: { width: '10%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, { id: 'recipients', label: t('table.recipient'), - cellProps: { width: '13%' }, + cellProps: { width: '15%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, { id: 'subject', label: t('table.subject'), - cellProps: { width: '23%' }, + cellProps: { width: '19%' }, }, { id: 'iun', label: t('table.iun'), - cellProps: { width: '20%' }, + cellProps: { width: '24%' }, }, { id: 'group', label: t('table.groups'), - cellProps: { width: '15%' }, + cellProps: { width: '8%' }, }, { id: 'notificationStatus', @@ -136,6 +136,12 @@ const DesktopNotifications = ({ cellProps: { width: '18%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, + { + id: 'action', + label: '', + cellProps: { width: '6%' }, + sortable: false, + }, ]; const rows = notifications.map((n) => ({ @@ -143,22 +149,25 @@ const DesktopNotifications = ({ id: n.iun, })); - // Navigation handlers - const handleRowClick = (row: Row) => { - navigate(routes.GET_DETTAGLIO_NOTIFICA_PATH(row.iun)); - }; - const filtersApplied: boolean = filterNotificationsRef.current.filtersApplied; const showFilters = notifications?.length > 0 || filtersApplied; + const handleRowClick = (iun: string) => { + navigate(routes.GET_DETTAGLIO_NOTIFICA_PATH(iun)); + }; + return ( <> {notifications && ( <> {notifications.length > 0 ? ( - + {columns.map((column) => ( {column.label} @@ -178,13 +188,15 @@ const DesktopNotifications = ({ {columns.map((column) => ( handleRowClick(row)} cellProps={{ ...column.cellProps, - cursor: 'pointer', }} > - + ))} diff --git a/packages/pn-pa-webapp/src/components/Notifications/NotificationsDataSwitch.tsx b/packages/pn-pa-webapp/src/components/Notifications/NotificationsDataSwitch.tsx index 575f79fc1e..8e6963e09a 100644 --- a/packages/pn-pa-webapp/src/components/Notifications/NotificationsDataSwitch.tsx +++ b/packages/pn-pa-webapp/src/components/Notifications/NotificationsDataSwitch.tsx @@ -1,3 +1,6 @@ +import { useTranslation } from 'react-i18next'; + +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import { Box, Typography } from '@mui/material'; import { CustomTagGroup, @@ -8,7 +11,8 @@ import { getNotificationStatusInfos, useIsMobile, } from '@pagopa-pn/pn-commons'; -import { Tag, TagGroup } from '@pagopa/mui-italia'; +import { NotificationColumnData } from '@pagopa-pn/pn-commons/src/models/Notifications'; +import { ButtonNaked, Tag, TagGroup } from '@pagopa/mui-italia'; const NotificationStatusChip: React.FC<{ data: Row }> = ({ data }) => { const { label, tooltip, color } = getNotificationStatusInfos(data.notificationStatus, { @@ -17,10 +21,27 @@ const NotificationStatusChip: React.FC<{ data: Row }> = ({ data }) return ; }; -const NotificationsDataSwitch: React.FC<{ data: Row; type: keyof Notification }> = ({ - data, - type, +const ActionButton: React.FC<{ iun: string; handleRowClick?: (iun: string) => void }> = ({ + iun, + handleRowClick, }) => { + const { t } = useTranslation(['notifiche']); + return ( + handleRowClick && handleRowClick(iun)} + aria-label={t('table.aria-action-table', { iun })} + > + + + ); +}; + +const NotificationsDataSwitch: React.FC<{ + data: Row; + type: keyof NotificationColumnData; + handleRowClick?: (iun: string) => void; +}> = ({ data, type, handleRowClick }) => { const isMobile = useIsMobile(); if (type === 'sentAt') { @@ -41,7 +62,18 @@ const NotificationsDataSwitch: React.FC<{ data: Row; type: keyof N ); } if (type === 'subject') { - return <>{data.subject.length > 65 ? data.subject.substring(0, 65) + '...' : data.subject}; + return ( + + {data.subject} + + ); } if (type === 'iun') { return <>{data.iun}; @@ -68,6 +100,9 @@ const NotificationsDataSwitch: React.FC<{ data: Row; type: keyof N <> ); } + if (type === 'action') { + return ; + } return <>; }; diff --git a/packages/pn-pa-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx b/packages/pn-pa-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx index ca83034bf9..f0b7b29303 100644 --- a/packages/pn-pa-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx +++ b/packages/pn-pa-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx @@ -112,11 +112,11 @@ describe('DesktopNotifications Component', () => { ); }); const rows = result!.getAllByTestId('notificationsTable.body.row'); - const notificationsTableCell = within(rows[0]).getAllByRole('cell'); - fireEvent.click(notificationsTableCell[0]); + const notificationsTableCellArrow = within(rows[0]).getByTestId('goToNotificationDetail'); + fireEvent.click(notificationsTableCellArrow); await waitFor(() => { - expect(mockNavigateFn).toBeCalledTimes(1); - expect(mockNavigateFn).toBeCalledWith( + expect(mockNavigateFn).toHaveBeenCalledTimes(1); + expect(mockNavigateFn).toHaveBeenCalledWith( GET_DETTAGLIO_NOTIFICA_PATH(notificationsToFe.resultsPage[0].iun) ); }); diff --git a/packages/pn-pa-webapp/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx b/packages/pn-pa-webapp/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx index f603078f6c..5129913f07 100644 --- a/packages/pn-pa-webapp/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx +++ b/packages/pn-pa-webapp/src/components/Notifications/__test__/NotificationsDataSwitch.test.tsx @@ -4,7 +4,7 @@ import { formatDate, getNotificationStatusInfos } from '@pagopa-pn/pn-commons'; import { createMatchMedia } from '@pagopa-pn/pn-commons/src/test-utils'; import { notificationsToFe } from '../../../__mocks__/Notifications.mock'; -import { render } from '../../../__test__/test-utils'; +import { fireEvent, render } from '../../../__test__/test-utils'; import NotificationsDataSwitch from '../NotificationsDataSwitch'; vi.mock('react-i18next', () => ({ @@ -71,4 +71,15 @@ describe('NotificationsDataSwitch Component', () => { const regexp = new RegExp(`^${data.group}$`, 'ig'); expect(container).toHaveTextContent(regexp); }); + + it('renders component - action', () => { + const clickFn = vi.fn(); + const { getByTestId } = render( + + ); + const button = getByTestId('goToNotificationDetail'); + expect(button).toBeInTheDocument(); + fireEvent.click(button); + expect(clickFn).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/pn-pa-webapp/src/components/Statistics/DigitalErrorsDetailStatistics.tsx b/packages/pn-pa-webapp/src/components/Statistics/DigitalErrorsDetailStatistics.tsx index 64756ee2bf..17a64a7546 100644 --- a/packages/pn-pa-webapp/src/components/Statistics/DigitalErrorsDetailStatistics.tsx +++ b/packages/pn-pa-webapp/src/components/Statistics/DigitalErrorsDetailStatistics.tsx @@ -1,4 +1,3 @@ -/* eslint-disable functional/immutable-data */ import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -37,40 +36,61 @@ const DigitalErrorsDetailStatistics: React.FC = ({ data: sData }) => { const delivery_errors = sData[DigitaErrorTypes.DELIVERY_ERROR].count; const pec_errors = sData[DigitaErrorTypes.INVALID_PEC].count; const rejected_errors = sData[DigitaErrorTypes.REJECTED].count; - - const delivery_title = t('digital_errors_detail.delivery_title'); - const delivery_description = t('digital_errors_detail.delivery_description'); - const pec_title = t('digital_errors_detail.pec_title'); - const pec_description = t('digital_errors_detail.pec_description'); - const rejected_title = t('digital_errors_detail.rejected_title'); - const rejected_description = t('digital_errors_detail.rejected_description'); + const virus_detected_errors = sData[DigitaErrorTypes.VIRUS_DETECTED].count; + const server_pec_comunication_errors = sData[DigitaErrorTypes.SERVER_PEC_COMUNICATION].count; + const sending_pec_errors = sData[DigitaErrorTypes.SENDING_PEC].count; + const malformed_pec_address_errors = sData[DigitaErrorTypes.MALFORMED_PEC_ADDRESS].count; const data: Array = [ { - title: delivery_title, - description: delivery_description, + title: t('digital_errors_detail.delivery_title'), + description: t('digital_errors_detail.delivery_description'), value: delivery_errors, color: GraphColors.lightRed, }, { - title: pec_title, - description: pec_description, + title: t('digital_errors_detail.pec_title'), + description: t('digital_errors_detail.pec_description'), value: pec_errors, color: GraphColors.darkRed, }, { - title: rejected_title, - description: rejected_description, + title: t('digital_errors_detail.rejected_title'), + description: t('digital_errors_detail.rejected_description'), value: rejected_errors, color: GraphColors.pink, }, + { + title: t('digital_errors_detail.virus_detected_title'), + description: t('digital_errors_detail.virus_detected_description'), + value: virus_detected_errors, + color: GraphColors.lightYellow, + }, + { + title: t('digital_errors_detail.server_pec_comunication_title'), + description: t('digital_errors_detail.server_pec_comunication_description'), + value: server_pec_comunication_errors, + color: GraphColors.gold, + }, + { + title: t('digital_errors_detail.sending_pec_title'), + description: t('digital_errors_detail.sending_pec_description'), + value: sending_pec_errors, + color: GraphColors.goldenYellow, + }, + { + title: t('digital_errors_detail.malformed_pec_address_title'), + description: t('digital_errors_detail.malformed_pec_address_description'), + value: malformed_pec_address_errors, + color: GraphColors.oliveBrown, + }, ]; - const isEmpty = !data.find((item) => item.value > 0); + const isEmpty = data.every((item) => item.value === 0); - const aggregateData = [data[0], data[2], data[1]]; + const aggregateData = data.filter((item) => item.value > 0); - const color = [GraphColors.lightRed, GraphColors.pink, GraphColors.darkRed]; + const color = aggregateData.map((item) => item.color); const options: PnEChartsProps['option'] = { color, @@ -79,35 +99,39 @@ const DigitalErrorsDetailStatistics: React.FC = ({ data: sData }) => { return ( - + {t('digital_errors_detail.title')} - - {t('digital_errors_detail.description')} - - - {data.map((item) => { - const title = item.title; - const description = item.description; - const color = item.color; - const avatarSx = { - bgcolor: color, - width: 10, - height: 10, - }; - return ( - - -   - - - - ); - })} - + {!isEmpty && ( + <> + + {t('digital_errors_detail.description')} + + + {aggregateData.map((item) => { + const title = item.title; + const description = item.description; + const color = item.color; + const avatarSx = { + bgcolor: color, + width: 10, + height: 10, + }; + return ( + + +   + + + + ); + })} + + + )} - + {isEmpty ? ( ) : ( diff --git a/packages/pn-pa-webapp/src/components/Statistics/__test__/DigitalErrorsDetailStatistics.test.tsx b/packages/pn-pa-webapp/src/components/Statistics/__test__/DigitalErrorsDetailStatistics.test.tsx index da69705ea6..8ffa973a67 100644 --- a/packages/pn-pa-webapp/src/components/Statistics/__test__/DigitalErrorsDetailStatistics.test.tsx +++ b/packages/pn-pa-webapp/src/components/Statistics/__test__/DigitalErrorsDetailStatistics.test.tsx @@ -72,8 +72,6 @@ describe('DeliveryModeStatistics component tests', () => { expect(container).toHaveTextContent('digital_errors_detail.delivery_description'); expect(container).toHaveTextContent('digital_errors_detail.pec_title'); expect(container).toHaveTextContent('digital_errors_detail.pec_description'); - expect(container).toHaveTextContent('digital_errors_detail.rejected_title'); - expect(container).toHaveTextContent('digital_errors_detail.rejected_description'); const graph = getByTestId('Aggregate'); expect(graph).toBeInTheDocument(); @@ -86,12 +84,6 @@ describe('DeliveryModeStatistics component tests', () => { value: digitalErrorsDataMock.data[DigitaErrorTypes.DELIVERY_ERROR].count, color: GraphColors.lightRed, }, - { - title: 'digital_errors_detail.rejected_title', - description: 'digital_errors_detail.rejected_description', - value: digitalErrorsDataMock.data[DigitaErrorTypes.REJECTED].count, - color: GraphColors.pink, - }, { title: 'digital_errors_detail.pec_title', description: 'digital_errors_detail.pec_description', @@ -99,7 +91,7 @@ describe('DeliveryModeStatistics component tests', () => { color: GraphColors.darkRed, }, ], - options: { color: [GraphColors.lightRed, GraphColors.pink, GraphColors.darkRed] }, + options: { color: [GraphColors.lightRed, GraphColors.darkRed] }, startAngle: 180, endAngle: -180, radius: ['30%', '90%'], @@ -112,13 +104,6 @@ describe('DeliveryModeStatistics component tests', () => { ); expect(container).toHaveTextContent('digital_errors_detail.title'); - expect(container).toHaveTextContent('digital_errors_detail.description'); - expect(container).toHaveTextContent('digital_errors_detail.delivery_title'); - expect(container).toHaveTextContent('digital_errors_detail.delivery_description'); - expect(container).toHaveTextContent('digital_errors_detail.pec_title'); - expect(container).toHaveTextContent('digital_errors_detail.pec_description'); - expect(container).toHaveTextContent('digital_errors_detail.rejected_title'); - expect(container).toHaveTextContent('digital_errors_detail.rejected_description'); expect(container).toHaveTextContent('empty.no_data_found'); const emptyImg = getByTestId('empty-image'); diff --git a/packages/pn-pa-webapp/src/models/Statistics.ts b/packages/pn-pa-webapp/src/models/Statistics.ts index 34dec8306d..2745508e5c 100644 --- a/packages/pn-pa-webapp/src/models/Statistics.ts +++ b/packages/pn-pa-webapp/src/models/Statistics.ts @@ -25,8 +25,11 @@ export enum GraphColors { lightRed = '#FE6666', turquoise = '#21CDD1', azure = '#00C5CA', - pink = '#FFE0E0', + pink = '#FB9EAC', darkRed = '#761F1F', + lightYellow = '#FFE5A3', + goldenYellow = '#D9AD3C', + oliveBrown = '#614C15', } export enum CxType { @@ -49,10 +52,14 @@ export enum ResponseStatus { // EXPORT FROM pn-commons/../NotificationDetail.ts? } export enum DigitaErrorTypes { - INVALID_PEC = 'ERRORE DOMINIO PEC NON VALIDO', - DELIVERY_ERROR = 'ERRORE CONSEGNA', REJECTED = 'NON ACCETTAZIONE', - UNKNOWN = '-', + DELIVERY_ERROR = 'ERRORE CONSEGNA', + VIRUS_DETECTED = 'RILEVAZIONE VIRUS', + SERVER_PEC_COMUNICATION = 'ERRORE COMUNICAZIONE SERVER PEC', + SENDING_PEC = 'ERRORE INVIO PEC', + INVALID_PEC = 'ERRORE DOMINIO PEC NON VALIDO', + MALFORMED_PEC_ADDRESS = 'ERRORE INDIRIZZO PEC MALFORMATO', + UNKNOWN = 'NON DEFINITO', } export enum StatisticsDataTypes { @@ -161,9 +168,13 @@ export interface IAttemptsCount { } export interface IDigitalErrorsDetailStatistics { - [DigitaErrorTypes.INVALID_PEC]: IAttemptsCount; - [DigitaErrorTypes.DELIVERY_ERROR]: IAttemptsCount; [DigitaErrorTypes.REJECTED]: IAttemptsCount; + [DigitaErrorTypes.DELIVERY_ERROR]: IAttemptsCount; + [DigitaErrorTypes.VIRUS_DETECTED]: IAttemptsCount; + [DigitaErrorTypes.SERVER_PEC_COMUNICATION]: IAttemptsCount; + [DigitaErrorTypes.SENDING_PEC]: IAttemptsCount; + [DigitaErrorTypes.INVALID_PEC]: IAttemptsCount; + [DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: IAttemptsCount; [DigitaErrorTypes.UNKNOWN]: IAttemptsCount; } @@ -209,7 +220,7 @@ export const SelectedStatisticsFilter = { } as const; export type SelectedStatisticsFilterKeys = - typeof SelectedStatisticsFilter[keyof typeof SelectedStatisticsFilter]; + (typeof SelectedStatisticsFilter)[keyof typeof SelectedStatisticsFilter]; export type StatisticsFilter = { selected: SelectedStatisticsFilterKeys | null; diff --git a/packages/pn-pa-webapp/src/utility/StatisticsData/DigitalErrorsDetailStatisticsData.ts b/packages/pn-pa-webapp/src/utility/StatisticsData/DigitalErrorsDetailStatisticsData.ts index a24c4710da..cfa394833f 100644 --- a/packages/pn-pa-webapp/src/utility/StatisticsData/DigitalErrorsDetailStatisticsData.ts +++ b/packages/pn-pa-webapp/src/utility/StatisticsData/DigitalErrorsDetailStatisticsData.ts @@ -19,7 +19,7 @@ import StatisticsData from './StatisticsData'; */ export class DigitalErrorsDetailStatisticsData extends StatisticsData { data: IDigitalErrorsDetailStatistics = { - [DigitaErrorTypes.INVALID_PEC]: { + [DigitaErrorTypes.REJECTED]: { count: 0, attempts: 0, }, @@ -27,7 +27,23 @@ export class DigitalErrorsDetailStatisticsData extends StatisticsData { count: 0, attempts: 0, }, - [DigitaErrorTypes.REJECTED]: { + [DigitaErrorTypes.VIRUS_DETECTED]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.SERVER_PEC_COMUNICATION]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.SENDING_PEC]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.INVALID_PEC]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: { count: 0, attempts: 0, }, @@ -50,20 +66,28 @@ export class DigitalErrorsDetailStatisticsData extends StatisticsData { return this; } + isDigitalErrorsDetailStatistics(type: string): type is DigitaErrorTypes { + return (Object.values(DigitaErrorTypes) as Array).includes(type); + } + parseChunk(chunk: NotificationOverview | DigitalNotificationFocus): void { // parse only if chunk is a DigitalNotificationFocus if ('error_type' in chunk) { const type = chunk.error_type; - this.data[type as keyof IDigitalErrorsDetailStatistics].attempts += - +chunk.failed_attempts_count; - this.data[type as keyof IDigitalErrorsDetailStatistics].count += +chunk.notifications_count; + if (this.isDigitalErrorsDetailStatistics(type)) { + this.data[type].attempts += +chunk.failed_attempts_count; + this.data[type].count += +chunk.notifications_count; + } else { + this.data[DigitaErrorTypes.UNKNOWN].attempts += +chunk.failed_attempts_count; + this.data[DigitaErrorTypes.UNKNOWN].count += +chunk.notifications_count; + } } } resetData(): void { this.data = { - [DigitaErrorTypes.INVALID_PEC]: { + [DigitaErrorTypes.REJECTED]: { count: 0, attempts: 0, }, @@ -71,7 +95,23 @@ export class DigitalErrorsDetailStatisticsData extends StatisticsData { count: 0, attempts: 0, }, - [DigitaErrorTypes.REJECTED]: { + [DigitaErrorTypes.VIRUS_DETECTED]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.SERVER_PEC_COMUNICATION]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.SENDING_PEC]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.INVALID_PEC]: { + count: 0, + attempts: 0, + }, + [DigitaErrorTypes.MALFORMED_PEC_ADDRESS]: { count: 0, attempts: 0, }, diff --git a/packages/pn-personafisica-login/CHANGELOG.md b/packages/pn-personafisica-login/CHANGELOG.md index e3191288fc..118fbe071c 100644 --- a/packages/pn-personafisica-login/CHANGELOG.md +++ b/packages/pn-personafisica-login/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package @pagopa-pn/pn-personafisica-login + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package @pagopa-pn/pn-personafisica-login + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + + +### Bug Fixes + +* **pn-13210:** manage accessibility when closing modal ([#1451](https://github.com/pagopa/pn-frontend/issues/1451)) ([2b4981b](https://github.com/pagopa/pn-frontend/commit/2b4981bddc8f6651ac47bb2cf371f63e33962959)) +* **pn-13211:** Removed redirect when login fails ([#1445](https://github.com/pagopa/pn-frontend/issues/1445)) ([6ff0d2a](https://github.com/pagopa/pn-frontend/commit/6ff0d2aec98f161d5f23e7af49e41c31c7a7dcb7)) + + + + + ## [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-personafisica-login diff --git a/packages/pn-personafisica-login/package.json b/packages/pn-personafisica-login/package.json index 61e0a85d9f..b360778ccc 100644 --- a/packages/pn-personafisica-login/package.json +++ b/packages/pn-personafisica-login/package.json @@ -1,7 +1,7 @@ { "name": "@pagopa-pn/pn-personafisica-login", "description": "Pagina di login di SEND per il cittadino", - "version": "2.11.1", + "version": "2.12.0", "private": true, "homepage": "auth", "dependencies": { diff --git a/packages/pn-personafisica-login/public/js/redirect.js b/packages/pn-personafisica-login/public/js/redirect.js index 260d1316f1..7a656b5d63 100644 --- a/packages/pn-personafisica-login/public/js/redirect.js +++ b/packages/pn-personafisica-login/public/js/redirect.js @@ -1,4 +1,4 @@ -const regex = new RegExp('https://login.((dev|test|uat|hotfix)?.?)notifichedigitali.it'); +const regex = new RegExp('https://login\\.(((dev|test|uat|hotfix)\\.)?)notifichedigitali\\.it') const origin = window.origin; if (regex.test(origin)) { const matches = origin.match(regex); @@ -7,4 +7,4 @@ if (regex.test(origin)) { const newlogin = newloginElements.join(''); document.write(``); document.write(``); -} +} \ No newline at end of file diff --git a/packages/pn-personafisica-login/src/__test__/redirect.test.js b/packages/pn-personafisica-login/src/__test__/redirect.test.js new file mode 100644 index 0000000000..253f25b027 --- /dev/null +++ b/packages/pn-personafisica-login/src/__test__/redirect.test.js @@ -0,0 +1,76 @@ +import fs from 'fs'; +import { JSDOM } from 'jsdom'; +import path from 'path'; +import { vi } from 'vitest'; + +const emptyHTML = ''; +const scriptContent = fs.readFileSync( + path.resolve(__dirname, '../../public/js/redirect.js'), + 'utf8' +); + +describe('config.js behavior', () => { + let dom; + let document; + + beforeAll(() => { + dom = new JSDOM(emptyHTML, { + runScripts: 'dangerously', + resources: 'usable', + }); + + document = dom.window.document; + vi.spyOn(document, 'write').mockImplementation(() => {}); + }); + + test('should redirect and add noindex meta tag when URL matches regex', async () => { + const data = [ + { + origin: 'https://login.notifichedigitali.it', + redirect: 'https://cittadini.notifichedigitali.it/auth', + }, + { + origin: 'https://login.dev.notifichedigitali.it', + redirect: 'https://cittadini.dev.notifichedigitali.it/auth', + }, + { + origin: 'https://login.test.notifichedigitali.it', + redirect: 'https://cittadini.test.notifichedigitali.it/auth', + }, + { + origin: 'https://login.uat.notifichedigitali.it', + redirect: 'https://cittadini.uat.notifichedigitali.it/auth', + }, + { + origin: 'https://login.hotfix.notifichedigitali.it', + redirect: 'https://cittadini.hotfix.notifichedigitali.it/auth', + }, + ]; + + for (const { origin, redirect } of data) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).toHaveBeenNthCalledWith( + 1, + `` + ); + expect(document.write).toHaveBeenNthCalledWith(2, ``); + } + }); + + test('should not add noindex meta tag when URL does not match regex', async () => { + const origins = [ + 'https://login.testnotifichedigitali.it', + 'https://login.prod.notifichedigitali.it', + 'https://otherapp.dev.notifichedigitali.it', + ]; + + for (const origin of origins) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).not.toHaveBeenCalled(); + } + }); +}); diff --git a/packages/pn-personafisica-webapp/CHANGELOG.md b/packages/pn-personafisica-webapp/CHANGELOG.md index 696ffb393a..b7a23b39db 100644 --- a/packages/pn-personafisica-webapp/CHANGELOG.md +++ b/packages/pn-personafisica-webapp/CHANGELOG.md @@ -3,6 +3,42 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package @pagopa-pn/pn-personafisica-webapp + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package @pagopa-pn/pn-personafisica-webapp + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + + +### Bug Fixes + +* **pn-13210:** manage accessibility when closing modal ([#1451](https://github.com/pagopa/pn-frontend/issues/1451)) ([2b4981b](https://github.com/pagopa/pn-frontend/commit/2b4981bddc8f6651ac47bb2cf371f63e33962959)) +* **pn-13214:** inactivity handler accessibility ([#1454](https://github.com/pagopa/pn-frontend/issues/1454)) ([7af07bd](https://github.com/pagopa/pn-frontend/commit/7af07bdc5861815ae484e0856d17f80ec3ac6096)) +* **pn-13216:** Added descriptions to radio buttons ([#1444](https://github.com/pagopa/pn-frontend/issues/1444)) ([9fb7b79](https://github.com/pagopa/pn-frontend/commit/9fb7b79a755c6850d9ec2ffbb62aff60ec88e7a1)) +* **pn-13255:** fixed aria attributes on the modal for revoking the delegation ([#1453](https://github.com/pagopa/pn-frontend/issues/1453)) ([cf2bfd9](https://github.com/pagopa/pn-frontend/commit/cf2bfd9844c412aa7f881a833c2fcaae01650355)) +* **pn-13598:** accessibility for the delegation tag group ([#1452](https://github.com/pagopa/pn-frontend/issues/1452)) ([a8626a2](https://github.com/pagopa/pn-frontend/commit/a8626a27ca23f9de030bc0b51d825d685bcee737)) + + +### Features + +* **pn-13595:** removed automatic redirect before logout ([#1456](https://github.com/pagopa/pn-frontend/issues/1456)) ([c7d823f](https://github.com/pagopa/pn-frontend/commit/c7d823f72e9e64eeeccfcafebb0b05f4b188959c)) + + + + + ## [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-personafisica-webapp diff --git a/packages/pn-personafisica-webapp/package.json b/packages/pn-personafisica-webapp/package.json index 11d4672aa4..af6c93a531 100644 --- a/packages/pn-personafisica-webapp/package.json +++ b/packages/pn-personafisica-webapp/package.json @@ -1,7 +1,7 @@ { "name": "@pagopa-pn/pn-personafisica-webapp", "description": "SEND - Servizio Notifiche Digitali per il cittadino", - "version": "2.11.1", + "version": "2.12.0", "private": true, "dependencies": { "@emotion/react": "^11.11.1", diff --git a/packages/pn-personafisica-webapp/public/js/config.js b/packages/pn-personafisica-webapp/public/js/config.js index 346edc5237..685bf52dc5 100644 --- a/packages/pn-personafisica-webapp/public/js/config.js +++ b/packages/pn-personafisica-webapp/public/js/config.js @@ -1,4 +1,4 @@ -const regex = new RegExp('https://cittadini.((dev|test|uat|hotfix).?)notifichedigitali.it'); +const regex = new RegExp('https://cittadini\\.(((dev|test|uat|hotfix)\\.)?)notifichedigitali\\.it') const origin = window.origin; if (regex.test(origin)) { document.write(``); diff --git a/packages/pn-personafisica-webapp/public/locales/it/appStatus.json b/packages/pn-personafisica-webapp/public/locales/it/appStatus.json index 7cd3014b84..77fd6bc568 100644 --- a/packages/pn-personafisica-webapp/public/locales/it/appStatus.json +++ b/packages/pn-personafisica-webapp/public/locales/it/appStatus.json @@ -6,7 +6,9 @@ "ok": "Tutti i servizi di SEND sono operativi.", "not-ok": "C'è un disservizio in corso. Per maggiori dettagli, consulta la tabella qui sotto." }, - "lastCheckLegend": "Ultimo aggiornamento - {{ lastCheckTimestamp }}" + "lastCheckLegend": "Ultimo aggiornamento - {{ lastCheckTimestamp }}", + "aria-missed-endDate": "Data fine mancante, disservizio in corso", + "missed-endDate": "In corso" }, "downtimeList": { "title": "Storico dei disservizi", diff --git a/packages/pn-personafisica-webapp/public/locales/it/deleghe.json b/packages/pn-personafisica-webapp/public/locales/it/deleghe.json index fe71397ff4..5ff5bca601 100644 --- a/packages/pn-personafisica-webapp/public/locales/it/deleghe.json +++ b/packages/pn-personafisica-webapp/public/locales/it/deleghe.json @@ -133,4 +133,4 @@ "message": "Uno o più dei dati inseriti non sono validi" } } -} \ No newline at end of file +} diff --git a/packages/pn-personafisica-webapp/public/locales/it/notifiche.json b/packages/pn-personafisica-webapp/public/locales/it/notifiche.json index 01bd6e5fca..e3e9d3aa2e 100644 --- a/packages/pn-personafisica-webapp/public/locales/it/notifiche.json +++ b/packages/pn-personafisica-webapp/public/locales/it/notifiche.json @@ -6,7 +6,8 @@ "oggetto": "Oggetto", "iun": "Codice IUN", "status": "Stato", - "show-detail": "Vedi dettaglio" + "show-detail": "Vedi dettaglio", + "aria-action-table": "Vedi dettaglio notifica con iun : {{iun}}" }, "filters": { "iun": "Cerca per Codice IUN", @@ -398,7 +399,7 @@ "canceled": "Annullata", "canceled-tooltip": "L'ente ha annullato l'invio della notifica", "canceled-description": "L'ente ha annullato l'invio della notifica.", - "returned-to-sender":"Resa al mittente", + "returned-to-sender": "Resa al mittente", "returned-to-sender-tooltip-monorecipient": "Il destinatario risulta deceduto", "returned-to-sender-tooltip-multirecipient": "Tutti i destinatari sono deceduti", "returned-to-sender-description-monorecipient": "Il destinatario risulta deceduto.", diff --git a/packages/pn-personafisica-webapp/src/__test__/config.test.js b/packages/pn-personafisica-webapp/src/__test__/config.test.js new file mode 100644 index 0000000000..6bf08774ac --- /dev/null +++ b/packages/pn-personafisica-webapp/src/__test__/config.test.js @@ -0,0 +1,54 @@ +import fs from 'fs'; +import { JSDOM } from 'jsdom'; +import path from 'path'; +import { vi } from 'vitest'; + +const emptyHTML = ''; +const scriptContent = fs.readFileSync(path.resolve(__dirname, '../../public/js/config.js'), 'utf8'); + +describe('config.js behavior', () => { + let dom; + let document; + + beforeAll(() => { + dom = new JSDOM(emptyHTML, { + runScripts: 'dangerously', + resources: 'usable', + }); + + document = dom.window.document; + vi.spyOn(document, 'write').mockImplementation(() => {}); + }); + + test('should add noindex meta tag when URL matches regex', async () => { + const origins = [ + 'https://cittadini.notifichedigitali.it', + 'https://cittadini.dev.notifichedigitali.it/', + 'https://cittadini.test.notifichedigitali.it/', + 'https://cittadini.uat.notifichedigitali.it/', + 'https://cittadini.hotfix.notifichedigitali.it/', + ]; + + for (const origin of origins) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).toHaveBeenCalledWith(``); + } + }); + + test('should not add noindex meta tag when URL does not match regex', async () => { + const origins = [ + 'https://cittadini.testnotifichedigitali.it', + 'https://cittadini.prod.notifichedigitali.it', + 'https://otherapp.dev.notifichedigitali.it', + ]; + + for (const origin of origins) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).not.toHaveBeenCalled(); + } + }); +}); diff --git a/packages/pn-personafisica-webapp/src/components/Notifications/DesktopNotifications.tsx b/packages/pn-personafisica-webapp/src/components/Notifications/DesktopNotifications.tsx index e04f64ce13..e4034d121e 100644 --- a/packages/pn-personafisica-webapp/src/components/Notifications/DesktopNotifications.tsx +++ b/packages/pn-personafisica-webapp/src/components/Notifications/DesktopNotifications.tsx @@ -96,24 +96,24 @@ const DesktopNotifications = ({ { id: 'sentAt', label: t('table.data'), - cellProps: { width: '11%' }, + cellProps: { width: '10%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, { id: 'sender', label: t('table.mittente'), - cellProps: { width: '13%' }, + cellProps: { width: '19%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, { id: 'subject', label: t('table.oggetto'), - cellProps: { width: '23%' }, + cellProps: { width: '19%' }, }, { id: 'iun', label: t('table.iun'), - cellProps: { width: '20%' }, + cellProps: { width: '27%' }, }, { id: 'notificationStatus', @@ -121,6 +121,11 @@ const DesktopNotifications = ({ cellProps: { width: '18%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, + { + id: 'action', + label: '', + cellProps: { width: '6%' }, + }, ]; const rows: Array> = notifications.map((n) => ({ @@ -133,11 +138,11 @@ const DesktopNotifications = ({ const showFilters = notifications?.length > 0 || filtersApplied; // Navigation handlers - const handleRowClick = (row: Row) => { + const handleRowClick = (iun: string) => { if (currentDelegator) { - navigate(routes.GET_DETTAGLIO_NOTIFICA_DELEGATO_PATH(row.iun, currentDelegator.mandateId)); + navigate(routes.GET_DETTAGLIO_NOTIFICA_DELEGATO_PATH(iun, currentDelegator.mandateId)); } else { - navigate(routes.GET_DETTAGLIO_NOTIFICA_PATH(row.iun)); + navigate(routes.GET_DETTAGLIO_NOTIFICA_PATH(iun)); } }; @@ -149,7 +154,10 @@ const DesktopNotifications = ({ currentDelegator={currentDelegator} /> {rows.length ? ( - + {columns.map((column) => ( {column.label} @@ -169,13 +178,15 @@ const DesktopNotifications = ({ {columns.map((column) => ( handleRowClick(row)} cellProps={{ ...column.cellProps, - cursor: 'pointer', }} > - + ))} diff --git a/packages/pn-personafisica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx b/packages/pn-personafisica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx index d4765e0393..66a2f6778c 100644 --- a/packages/pn-personafisica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx +++ b/packages/pn-personafisica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx @@ -115,11 +115,11 @@ describe('DesktopNotifications Component', () => { result = render(); }); const rows = result.getAllByTestId('notificationsTable.body.row'); - const notificationsTableCell = within(rows[0]).getAllByRole('cell'); - fireEvent.click(notificationsTableCell[0]); + const notificationsTableCellArrow = within(rows[0]).getByTestId('goToNotificationDetail'); + fireEvent.click(notificationsTableCellArrow); await waitFor(() => { - expect(mockNavigateFn).toBeCalledTimes(1); - expect(mockNavigateFn).toBeCalledWith( + expect(mockNavigateFn).toHaveBeenCalledTimes(1); + expect(mockNavigateFn).toHaveBeenCalledWith( GET_DETTAGLIO_NOTIFICA_PATH(notificationsToFe.resultsPage[0].iun) ); }); diff --git a/packages/pn-personagiuridica-webapp/CHANGELOG.md b/packages/pn-personagiuridica-webapp/CHANGELOG.md index e51c63efda..c9a9ec94d4 100644 --- a/packages/pn-personagiuridica-webapp/CHANGELOG.md +++ b/packages/pn-personagiuridica-webapp/CHANGELOG.md @@ -3,6 +3,42 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package @pagopa-pn/pn-personagiuridica-webapp + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package @pagopa-pn/pn-personagiuridica-webapp + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + + +### Bug Fixes + +* **pn-13210:** manage accessibility when closing modal ([#1451](https://github.com/pagopa/pn-frontend/issues/1451)) ([2b4981b](https://github.com/pagopa/pn-frontend/commit/2b4981bddc8f6651ac47bb2cf371f63e33962959)) +* **pn-13214:** inactivity handler accessibility ([#1454](https://github.com/pagopa/pn-frontend/issues/1454)) ([7af07bd](https://github.com/pagopa/pn-frontend/commit/7af07bdc5861815ae484e0856d17f80ec3ac6096)) +* **pn-13216:** Added descriptions to radio buttons ([#1444](https://github.com/pagopa/pn-frontend/issues/1444)) ([9fb7b79](https://github.com/pagopa/pn-frontend/commit/9fb7b79a755c6850d9ec2ffbb62aff60ec88e7a1)) +* **pn-13255:** fixed aria attributes on the modal for revoking the delegation ([#1453](https://github.com/pagopa/pn-frontend/issues/1453)) ([cf2bfd9](https://github.com/pagopa/pn-frontend/commit/cf2bfd9844c412aa7f881a833c2fcaae01650355)) +* **pn-13598:** accessibility for the delegation tag group ([#1452](https://github.com/pagopa/pn-frontend/issues/1452)) ([a8626a2](https://github.com/pagopa/pn-frontend/commit/a8626a27ca23f9de030bc0b51d825d685bcee737)) + + +### Features + +* **pn-13595:** removed automatic redirect before logout ([#1456](https://github.com/pagopa/pn-frontend/issues/1456)) ([c7d823f](https://github.com/pagopa/pn-frontend/commit/c7d823f72e9e64eeeccfcafebb0b05f4b188959c)) + + + + + ## [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-personagiuridica-webapp diff --git a/packages/pn-personagiuridica-webapp/package.json b/packages/pn-personagiuridica-webapp/package.json index 596aefa2e3..53694e830a 100644 --- a/packages/pn-personagiuridica-webapp/package.json +++ b/packages/pn-personagiuridica-webapp/package.json @@ -1,7 +1,7 @@ { "name": "@pagopa-pn/pn-personagiuridica-webapp", "description": "SEND per la persona giuridica", - "version": "2.11.1", + "version": "2.12.0", "private": true, "dependencies": { "@emotion/react": "^11.11.1", diff --git a/packages/pn-personagiuridica-webapp/public/js/config.js b/packages/pn-personagiuridica-webapp/public/js/config.js index 4746905bf9..0666b18086 100644 --- a/packages/pn-personagiuridica-webapp/public/js/config.js +++ b/packages/pn-personagiuridica-webapp/public/js/config.js @@ -1,4 +1,4 @@ -const regex = new RegExp('https://imprese.((dev|test|uat|hotfix).?)notifichedigitali.it'); +const regex = new RegExp('https://imprese\\.(((dev|test|uat|hotfix)\\.)?)notifichedigitali\\.it') const origin = window.origin; if (regex.test(origin)) { document.write(``); diff --git a/packages/pn-personagiuridica-webapp/public/locales/it/appStatus.json b/packages/pn-personagiuridica-webapp/public/locales/it/appStatus.json index 7cd3014b84..77fd6bc568 100644 --- a/packages/pn-personagiuridica-webapp/public/locales/it/appStatus.json +++ b/packages/pn-personagiuridica-webapp/public/locales/it/appStatus.json @@ -6,7 +6,9 @@ "ok": "Tutti i servizi di SEND sono operativi.", "not-ok": "C'è un disservizio in corso. Per maggiori dettagli, consulta la tabella qui sotto." }, - "lastCheckLegend": "Ultimo aggiornamento - {{ lastCheckTimestamp }}" + "lastCheckLegend": "Ultimo aggiornamento - {{ lastCheckTimestamp }}", + "aria-missed-endDate": "Data fine mancante, disservizio in corso", + "missed-endDate": "In corso" }, "downtimeList": { "title": "Storico dei disservizi", diff --git a/packages/pn-personagiuridica-webapp/public/locales/it/deleghe.json b/packages/pn-personagiuridica-webapp/public/locales/it/deleghe.json index e6f854bcd6..57b4c20c9c 100644 --- a/packages/pn-personagiuridica-webapp/public/locales/it/deleghe.json +++ b/packages/pn-personagiuridica-webapp/public/locales/it/deleghe.json @@ -155,4 +155,4 @@ "message": "Controllalo e inseriscilo di nuovo" } } -} \ No newline at end of file +} diff --git a/packages/pn-personagiuridica-webapp/public/locales/it/notifiche.json b/packages/pn-personagiuridica-webapp/public/locales/it/notifiche.json index f840c2c4ee..ab5f274b40 100644 --- a/packages/pn-personagiuridica-webapp/public/locales/it/notifiche.json +++ b/packages/pn-personagiuridica-webapp/public/locales/it/notifiche.json @@ -12,7 +12,8 @@ "iun": "Codice IUN", "status": "Stato", "show-detail": "Vedi dettaglio", - "group-selector-title": "Menu selezione gruppo" + "group-selector-title": "Menu selezione gruppo", + "aria-action-table": "Vedi dettaglio notifica con iun : {{iun}}" }, "filters": { "iun": "Cerca per Codice IUN", @@ -402,7 +403,7 @@ "canceled": "Annullata", "canceled-tooltip": "L'ente ha annullato l'invio della notifica", "canceled-description": "L'ente ha annullato l'invio della notifica.", - "returned-to-sender":"Resa al mittente", + "returned-to-sender": "Resa al mittente", "returned-to-sender-tooltip-monorecipient": "Il destinatario risulta deceduto", "returned-to-sender-tooltip-multirecipient": "Tutti i destinatari risultano deceduti", "returned-to-sender-description-monorecipient": "Il destinatario risulta deceduto.", diff --git a/packages/pn-personagiuridica-webapp/src/__test__/config.test.js b/packages/pn-personagiuridica-webapp/src/__test__/config.test.js new file mode 100644 index 0000000000..07519f937c --- /dev/null +++ b/packages/pn-personagiuridica-webapp/src/__test__/config.test.js @@ -0,0 +1,54 @@ +import fs from 'fs'; +import { JSDOM } from 'jsdom'; +import path from 'path'; +import { vi } from 'vitest'; + +const emptyHTML = ''; +const scriptContent = fs.readFileSync(path.resolve(__dirname, '../../public/js/config.js'), 'utf8'); + +describe('config.js behavior', () => { + let dom; + let document; + + beforeAll(() => { + dom = new JSDOM(emptyHTML, { + runScripts: 'dangerously', + resources: 'usable', + }); + + document = dom.window.document; + vi.spyOn(document, 'write').mockImplementation(() => {}); + }); + + test('should add noindex meta tag when URL matches regex', async () => { + const origins = [ + 'https://imprese.notifichedigitali.it', + 'https://imprese.dev.notifichedigitali.it/', + 'https://imprese.test.notifichedigitali.it/', + 'https://imprese.uat.notifichedigitali.it/', + 'https://imprese.hotfix.notifichedigitali.it/', + ]; + + for (const origin of origins) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).toHaveBeenCalledWith(``); + } + }); + + test('should not add noindex meta tag when URL does not match regex', async () => { + const origins = [ + 'https://imprese.testnotifichedigitali.it', + 'https://imprese.prod.notifichedigitali.it', + 'https://otherapp.dev.notifichedigitali.it', + ]; + + for (const origin of origins) { + document.write.mockClear(); + dom.window.origin = origin; + dom.window.eval(scriptContent); + expect(document.write).not.toHaveBeenCalled(); + } + }); +}); diff --git a/packages/pn-personagiuridica-webapp/src/components/Notifications/DesktopNotifications.tsx b/packages/pn-personagiuridica-webapp/src/components/Notifications/DesktopNotifications.tsx index f11a42e5e4..8482312527 100644 --- a/packages/pn-personagiuridica-webapp/src/components/Notifications/DesktopNotifications.tsx +++ b/packages/pn-personagiuridica-webapp/src/components/Notifications/DesktopNotifications.tsx @@ -74,24 +74,24 @@ const DesktopNotifications = ({ { id: 'sentAt', label: t('table.data'), - cellProps: { width: '11%' }, + cellProps: { width: '10%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, { id: 'sender', label: t('table.mittente'), - cellProps: { width: '13%' }, + cellProps: { width: '19%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, { id: 'subject', label: t('table.oggetto'), - cellProps: { width: '22%' }, + cellProps: { width: '19%' }, }, { id: 'iun', label: t('table.iun'), - cellProps: { width: '20%' }, + cellProps: { width: '27%' }, }, { id: 'notificationStatus', @@ -99,6 +99,11 @@ const DesktopNotifications = ({ cellProps: { width: '18%' }, sortable: false, // TODO: will be re-enabled in PN-1124 }, + { + id: 'action', + label: '', + cellProps: { width: '6%' }, + }, ]; if (isDelegatedPage) { @@ -121,12 +126,11 @@ const DesktopNotifications = ({ const showFilters = notifications?.length > 0 || filtersApplied; - // Navigation handlers - const handleRowClick = (row: Row) => { - if (isDelegatedPage && row.mandateId) { - navigate(routes.GET_DETTAGLIO_NOTIFICA_DELEGATO_PATH(row.iun, row.mandateId)); + const handleRowClick = (iun: string, mandateId?: string) => { + if (isDelegatedPage && mandateId) { + navigate(routes.GET_DETTAGLIO_NOTIFICA_DELEGATO_PATH(iun, mandateId)); } else { - navigate(routes.GET_DETTAGLIO_NOTIFICA_PATH(row.iun)); + navigate(routes.GET_DETTAGLIO_NOTIFICA_PATH(iun)); } }; @@ -134,7 +138,10 @@ const DesktopNotifications = ({ <> {rows.length ? ( - + {columns.map((column) => ( {column.label} @@ -154,13 +162,15 @@ const DesktopNotifications = ({ {columns.map((column) => ( handleRowClick(row)} cellProps={{ ...column.cellProps, - cursor: 'pointer', }} > - + ))} diff --git a/packages/pn-personagiuridica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx b/packages/pn-personagiuridica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx index 6bed217364..0cc30cbc27 100644 --- a/packages/pn-personagiuridica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx +++ b/packages/pn-personagiuridica-webapp/src/components/Notifications/__test__/DesktopNotifications.test.tsx @@ -120,11 +120,11 @@ describe('DesktopNotifications Component', () => { result = render(); }); const rows = result!.getAllByTestId('notificationsTable.body.row'); - const notificationsTableCell = within(rows[0]).getAllByRole('cell'); - fireEvent.click(notificationsTableCell[0]); + const notificationsTableCellArrow = within(rows[0]).getByTestId('goToNotificationDetail'); + fireEvent.click(notificationsTableCellArrow); await waitFor(() => { - expect(mockNavigateFn).toBeCalledTimes(1); - expect(mockNavigateFn).toBeCalledWith( + expect(mockNavigateFn).toHaveBeenCalledTimes(1); + expect(mockNavigateFn).toHaveBeenCalledWith( GET_DETTAGLIO_NOTIFICA_PATH(notificationsToFe.resultsPage[0].iun) ); }); @@ -142,11 +142,11 @@ describe('DesktopNotifications Component', () => { ); }); const rows = result!.getAllByTestId('notificationsTable.body.row'); - const notificationsTableCell = within(rows[0]).getAllByRole('cell'); - fireEvent.click(notificationsTableCell[0]); + const notificationsTableCellArrow = within(rows[0]).getByTestId('goToNotificationDetail'); + fireEvent.click(notificationsTableCellArrow); await waitFor(() => { - expect(mockNavigateFn).toBeCalledTimes(1); - expect(mockNavigateFn).toBeCalledWith( + expect(mockNavigateFn).toHaveBeenCalledTimes(1); + expect(mockNavigateFn).toHaveBeenCalledWith( GET_DETTAGLIO_NOTIFICA_DELEGATO_PATH( notificationsToFe.resultsPage[0].iun, 'mocked-mandate-id' diff --git a/packages/pn-validator/CHANGELOG.md b/packages/pn-validator/CHANGELOG.md index c79d77de62..20c7b7143e 100644 --- a/packages/pn-validator/CHANGELOG.md +++ b/packages/pn-validator/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.12.0](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.1...v2.12.0) (2025-02-18) + +**Note:** Version bump only for package @pagopa-pn/pn-validator + + + + + +# [2.12.0-RC.1](https://github.com/pagopa/pn-frontend/compare/v2.12.0-RC.0...v2.12.0-RC.1) (2025-02-05) + +**Note:** Version bump only for package @pagopa-pn/pn-validator + + + + + +# [2.12.0-RC.0](https://github.com/pagopa/pn-frontend/compare/v2.11.1...v2.12.0-RC.0) (2025-02-04) + +**Note:** Version bump only for package @pagopa-pn/pn-validator + + + + + ## [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-validator diff --git a/packages/pn-validator/package.json b/packages/pn-validator/package.json index db534f7ae0..c89a845295 100644 --- a/packages/pn-validator/package.json +++ b/packages/pn-validator/package.json @@ -1,6 +1,6 @@ { "name": "@pagopa-pn/pn-validator", - "version": "2.11.1", + "version": "2.12.0", "private": true, "main": "./src/index.ts", "dependencies": {