Skip to content

Commit

Permalink
feat(pn-13453): Domicile Banner and Validating PEC Banner (#1475)
Browse files Browse the repository at this point in the history
  • Loading branch information
mflauti authored Feb 24, 2025
1 parent 3fb7248 commit 30cbd6d
Show file tree
Hide file tree
Showing 23 changed files with 429 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"pec-validation-banner": {
"title": "La PEC è in validazione",
"dod-enabled-message": "Fino al termine del processo, la Piattaforma SEND rimane attiva come domicilio digitale.",
"dod-disabled-message": "Fino al termine del processo non sarà possibile modificare i recapiti a valore legale."
"dod-disabled-message": "Fino al termine del processo non sarà possibile modificare i recapiti a valore legale.",
"parties-list": "La piattaforma SEND resterà il tuo domicilio digitale per {{list}} fino al completamento della validazione."
},
"pec-description": "Quando un ente ti invia una notifica SEND, ricevi l’avviso a valore legale sulla PEC che hai scelto.",
"link-pec-placeholder": "La tua PEC",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ const EmailContactItem: React.FC = () => {
actions={getActions()}
expanded={isEmailActive}
data-testid="emailContact"
slotProps={{ Card: { id: 'emailContactSection' } }}
>
{!isEmailActive && (
<Typography variant="body1" fontSize={{ xs: '14px', lg: '16px' }} mb={3}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ const IOContact: React.FC = () => {
color="primary"
fullWidth={isMobile}
sx={{ mt: 3 }}
id="ioContactButton"
>
{t('io-contact.enable', { ns: 'recapiti' })}
</Button>
Expand Down Expand Up @@ -208,6 +209,7 @@ const IOContact: React.FC = () => {
: undefined
}
expanded={isAppIOEnabled}
slotProps={{ Card: { id: 'ioContactSection' } }}
>
<Stack direction="row" alignItems="center" data-testid="ioContact">
<Avatar variant="rounded" sx={{ bgcolor: '#0B3EE3', width: '36px', height: '36px' }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ const LegalContacts = () => {
)
.unwrap()
.then(() => {
if (channelType === ChannelType.SERCQ_SEND) {
sessionStorage.removeItem('domicileBannerClosed');
}
PFEventStrategyFactory.triggerEvent(
PFEventsType[`SEND_REMOVE_${channelType}_SUCCESS`],
'default'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ const SercqSendContactWizard: React.FC<Props> = ({ goToNextStep, setShowPecWizar
dispatch(createOrUpdateAddress(digitalAddressParams))
.unwrap()
.then(() => {
sessionStorage.removeItem('domicileBannerClosed');
PFEventStrategyFactory.triggerEvent(PFEventsType.SEND_ADD_SERCQ_SEND_UX_SUCCESS, 'default');
// show success message
dispatch(
Expand All @@ -150,7 +151,6 @@ const SercqSendContactWizard: React.FC<Props> = ({ goToNextStep, setShowPecWizar
message: t(`legal-contacts.sercq_send-added-successfully`, { ns: 'recapiti' }),
})
);

goToNextStep && goToNextStep();
})
.catch(() => {});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { useTranslation } from 'react-i18next';

import { Alert, Typography } from '@mui/material';

import { contactsSelectors } from '../../redux/contact/reducers';
import { useAppSelector } from '../../redux/hooks';

const ValidatingPecBanner: React.FC = () => {
const { t } = useTranslation(['recapiti']);
const {
defaultPECAddress,
defaultSERCQ_SENDAddress,
specialPECAddresses,
specialSERCQ_SENDAddresses,
} = useAppSelector(contactsSelectors.selectAddresses);

const isValidatingDefaultPec = defaultPECAddress?.pecValid === false;

const isDefaultSercqSendActive = !!defaultSERCQ_SENDAddress;

const validatingSpecialPecList: Array<string> = specialPECAddresses
.filter(
(pecAddr) =>
pecAddr.pecValid === false &&
(isDefaultSercqSendActive ||
specialSERCQ_SENDAddresses.some((sercqAddr) => sercqAddr.senderId === pecAddr.senderId))
)
.map((addr) => addr.senderName ?? addr.senderId);

// eslint-disable-next-line functional/no-let
let bannerMessage = '';

if (!isValidatingDefaultPec && validatingSpecialPecList.length === 0) {
return <></>;
}

if (isValidatingDefaultPec) {
if (isDefaultSercqSendActive) {
bannerMessage = 'dod-enabled-message';
} else {
bannerMessage = 'dod-disabled-message';
}
} else {
bannerMessage = 'parties-list';
}

return (
<Alert data-testid="PecVerificationAlert" severity="warning" sx={{ my: { xs: 2, lg: 4 } }}>
<Typography variant="inherit" sx={{ fontWeight: '600' }}>
{t('legal-contacts.pec-validation-banner.title')}
</Typography>
<Typography variant="inherit">
{t(`legal-contacts.pec-validation-banner.${bannerMessage}`, {
list: validatingSpecialPecList.join(', '),
})}
</Typography>
</Alert>
);
};

export default ValidatingPecBanner;
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { SERCQ_SEND_VALUE } from '@pagopa-pn/pn-commons';

import { digitalAddresses } from '../../../__mocks__/Contacts.mock';
import { render, within } from '../../../__test__/test-utils';
import { AddressType, ChannelType } from '../../../models/contacts';
import ValidatingPecBanner from '../ValidatingPecBanner';

const sercqAddr = {
addressType: AddressType.LEGAL,
senderId: 'default',
channelType: ChannelType.SERCQ_SEND,
value: SERCQ_SEND_VALUE,
codeValid: true,
};

const validatingDefaultPecNoSercq = digitalAddresses.map((addr) =>
addr.senderId === 'default' && addr.addressType === AddressType.LEGAL
? { ...addr, pecValid: false }
: addr
);

const validatingDefaultPecSercq = [...validatingDefaultPecNoSercq, sercqAddr];

const validatingPartyPecNoSercq = digitalAddresses.map((addr) =>
addr.senderId === 'comune-milano' ? { ...addr, pecValid: false } : addr
);

const validatingPartyPecSercq = [...validatingPartyPecNoSercq, sercqAddr];

const validatingDefaultAndPartyPecSercq = validatingPartyPecSercq.map((addr) =>
addr.senderId === 'default' && addr.channelType === ChannelType.PEC
? { ...addr, pecValid: false }
: addr
);

describe('ValidatingPecBanner component', () => {
it('shows the component while validating default PEC - SERCQ SEND not enabled', () => {
const { getByTestId, getByText } = render(<ValidatingPecBanner />, {
preloadedState: { contactsState: { digitalAddresses: validatingDefaultPecNoSercq } },
});

const alert = getByTestId('PecVerificationAlert');
const icon = within(alert).getByTestId('ReportProblemOutlinedIcon');
expect(icon).toBeInTheDocument();
getByText('legal-contacts.pec-validation-banner.title');
getByText('legal-contacts.pec-validation-banner.dod-disabled-message');
});

it('shows the component while validating default PEC - SERCQ SEND previously enabled', () => {
const { getByTestId, getByText } = render(<ValidatingPecBanner />, {
preloadedState: { contactsState: { digitalAddresses: validatingDefaultPecSercq } },
});

const alert = getByTestId('PecVerificationAlert');
const icon = within(alert).getByTestId('ReportProblemOutlinedIcon');
expect(icon).toBeInTheDocument();
getByText('legal-contacts.pec-validation-banner.title');
getByText('legal-contacts.pec-validation-banner.dod-enabled-message');
});

it("shows the component while validating a party's PEC - default SERCQ SEND enabled", () => {
const { getByTestId, getByText } = render(<ValidatingPecBanner />, {
preloadedState: { contactsState: { digitalAddresses: validatingPartyPecSercq } },
});

const alert = getByTestId('PecVerificationAlert');
const icon = within(alert).getByTestId('ReportProblemOutlinedIcon');
expect(icon).toBeInTheDocument();
getByText('legal-contacts.pec-validation-banner.title');
getByText('legal-contacts.pec-validation-banner.parties-list');
});

it("shows the component while validating default and party's PEC - default SERCQ SEND enabled", () => {
const { getByTestId, getByText } = render(<ValidatingPecBanner />, {
preloadedState: { contactsState: { digitalAddresses: validatingDefaultAndPartyPecSercq } },
});

const alert = getByTestId('PecVerificationAlert');
const icon = within(alert).getByTestId('ReportProblemOutlinedIcon');
expect(icon).toBeInTheDocument();
getByText('legal-contacts.pec-validation-banner.title');
getByText('legal-contacts.pec-validation-banner.dod-enabled-message');
});

it("doesn't show the component if there is no validating PEC", () => {
const { queryByTestId, queryByText } = render(<ValidatingPecBanner />, {
preloadedState: { contactsState: { digitalAddresses } },
});

expect(queryByTestId('PecVerificationAlert')).not.toBeInTheDocument();
expect(queryByTestId('ReportProblemOutlinedIcon')).not.toBeInTheDocument();
const bannerTitle = queryByText('legal-contacts.pec-validation-banner.title');
const bannerMessage = queryByText('legal-contacts.pec-validation-banner.dod-enabled-message');

expect(bannerTitle).not.toBeInTheDocument();
expect(bannerMessage).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import { ButtonNaked } from '@pagopa/mui-italia';

import { PFEventsType } from '../../models/PFEventsType';
import {
AddressType,
ChannelType,
ContactOperation,
ContactSource,
IOAllowedValues,
} from '../../models/contacts';
import * as routes from '../../navigation/routes.const';
import { setExternalEvent } from '../../redux/contact/reducers';
import { contactsSelectors, setExternalEvent } from '../../redux/contact/reducers';
import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { closeDomicileBanner } from '../../redux/sidemenu/reducers';
import { RootState } from '../../redux/store';
Expand Down Expand Up @@ -108,43 +107,44 @@ const DomicileBanner: React.FC<Props> = ({ source }) => {
const dispatch = useAppDispatch();
const open = useAppSelector((state: RootState) => state.generalInfoState.domicileBannerOpened);
const { IS_DOD_ENABLED } = getConfiguration();
const { defaultPECAddress, defaultSERCQ_SENDAddress, defaultAPPIOAddress, courtesyAddresses } =
useAppSelector(contactsSelectors.selectAddresses);

const digitalAddresses = useAppSelector(
(state: RootState) => state.contactsState.digitalAddresses
);
const hasAppIODisabled = defaultAPPIOAddress?.value === IOAllowedValues.DISABLED;

const hasSercqSend = digitalAddresses.find((addr) => addr.channelType === ChannelType.SERCQ_SEND);
const hasAppIODisabled = digitalAddresses.find(
(addr) => addr.channelType === ChannelType.IOMSG && addr.value === IOAllowedValues.DISABLED
const hasCourtesyAddresses = courtesyAddresses.some(
(addr) => addr.value !== IOAllowedValues.DISABLED
);

const hasCourtesyAddresses =
digitalAddresses.filter(
(addr) => addr.addressType === AddressType.COURTESY && addr.value !== IOAllowedValues.DISABLED
).length > 0;
const domicileBannerData: DomicileBannerData | null = getDomicileData(
source,
!!hasSercqSend,
hasCourtesyAddresses,
!!hasAppIODisabled,
IS_DOD_ENABLED
);
const domicileBannerData: DomicileBannerData | null = defaultPECAddress
? null
: getDomicileData(
source,
!!defaultSERCQ_SENDAddress,
hasCourtesyAddresses,
hasAppIODisabled,
IS_DOD_ENABLED
);

const handleClose = () => {
dispatch(closeDomicileBanner());
// sessionStorage.setItem('domicileBannerClosed', 'true');
sessionStorage.setItem('domicileBannerClosed', 'true');
};

const handleClick = (destination?: ChannelType, operation?: ContactOperation) => {
if (destination && operation) {
if (destination === ChannelType.SERCQ_SEND && operation === ContactOperation.ADD) {
navigate(routes.DIGITAL_DOMICILE_ACTIVATION);
} else {
navigate(routes.RECAPITI);
}
dispatch(setExternalEvent({ destination, source, operation }));
}
PFEventStrategyFactory.triggerEvent(PFEventsType.SEND_VIEW_CONTACT_DETAILS, { source });
navigate(routes.RECAPITI);
};

return open && domicileBannerData ? (
<Box mb={5}>
<Box my={4}>
<Alert
severity={domicileBannerData.severity}
variant="outlined"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('DomicileBanner component', () => {
const button = getByText('domicile-banner.no-sercq-cta');
fireEvent.click(button);
expect(mockNavigateFn).toHaveBeenCalledTimes(1);
expect(mockNavigateFn).toHaveBeenCalledWith(routes.RECAPITI);
expect(mockNavigateFn).toHaveBeenCalledWith(routes.DIGITAL_DOMICILE_ACTIVATION);
expect(testStore.getState().contactsState.event).toStrictEqual({
destination: ChannelType.SERCQ_SEND,
source: ContactSource.HOME_NOTIFICHE,
Expand Down
Loading

0 comments on commit 30cbd6d

Please sign in to comment.