From 639ab06420e8a7ad0c9f0acebfef12a2d9a77dba Mon Sep 17 00:00:00 2001 From: Samuele Varianti <128470180+svariant@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:23:02 +0200 Subject: [PATCH 01/73] [VAS-418] feat: Align tos page with design (#579) --- src/components/TOS/TOSWall.tsx | 61 ++++++++++++++++------------------ src/locale/it.json | 5 ++- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/components/TOS/TOSWall.tsx b/src/components/TOS/TOSWall.tsx index 6cc80a308..e5482cfaf 100644 --- a/src/components/TOS/TOSWall.tsx +++ b/src/components/TOS/TOSWall.tsx @@ -1,40 +1,37 @@ -import {Trans, useTranslation} from 'react-i18next'; -import {Box, Typography, Link} from '@mui/material'; -import {TOSAgreement} from '@pagopa/mui-italia'; -import {Link as RouterLink} from 'react-router-dom'; +import { Trans, useTranslation } from 'react-i18next'; +import { Box, Link } from '@mui/material'; +import { TOSAgreement } from '@pagopa/mui-italia'; +import { Link as RouterLink } from 'react-router-dom'; interface TOSWallProps { - acceptTOS: () => void; - detailRoute: string; + acceptTOS: () => void; + detailRoute: string; } -const TOSWall = ({acceptTOS, detailRoute}: TOSWallProps) => { - const {t} = useTranslation(); - return ( - - acceptTOS()} +const TOSWall = ({ acceptTOS, detailRoute }: TOSWallProps) => { + const { t } = useTranslation(); + return ( + + + {t('tos.termsDescription')} + - - - Entrando dichiari di aver letto e accettato l’Informativa Privacy e i Termini e - condizioni d’uso di PagoPA - - Accedi - - - - - - ); + Accedi + + + } + onConfirm={() => acceptTOS()} + > + + ); }; export default TOSWall; diff --git a/src/locale/it.json b/src/locale/it.json index 5214c632f..85fe9b55d 100644 --- a/src/locale/it.json +++ b/src/locale/it.json @@ -1490,9 +1490,8 @@ "backButton": "Esci" }, "tos": { - "title": "pagoPA", - "description": "Prima di entrare, leggi e accetta l’Informativa Privacy e i Termini e condizioni d’uso. Potrai consultarli di nuovo quando vuoi: li trovi sempre in fondo alla pagina.", - "termsDescription": "Entrando dichiari di aver letto e accettato l’<1>Informativa Privacy e i <1>Termini e condizioni d’uso di PagoPA" + "title": "Pagamenti pagoPA", + "termsDescription": "Accedendo, accetti i <1>Termini e condizioni d’uso del servizio e confermi di avere letto l’<1>Informativa Privacy. " }, "general": { "noDataLabel": "Nessun risultato", From e839dafa851b3436c8c0296132eae1349fd26e5a Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Mon, 24 Jun 2024 14:23:21 +0000 Subject: [PATCH 02/73] Bump to version 1.26.0-1-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 543ef7bde..30b5826c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.0", + "version": "1.26.0-1-next", "homepage": "ui", "private": true, "scripts": { From 11830e509d47302fdce7c7aaf0825911bc57d3d9 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Mon, 24 Jun 2024 16:27:31 +0200 Subject: [PATCH 03/73] merge --- .github/workflows/ci_code_review.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/ci_code_review.yml b/.github/workflows/ci_code_review.yml index 92770b29e..312ae18e8 100644 --- a/.github/workflows/ci_code_review.yml +++ b/.github/workflows/ci_code_review.yml @@ -112,6 +112,7 @@ jobs: app_location: "/out" # App source code path relative to repository root skip_app_build: true skip_api_build: true + skip_deploy_on_missing_secrets: true # smoke_test: @@ -229,3 +230,18 @@ jobs: with: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} action: "close" + + delete-branch: + name: delete branch when closed + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.action == 'closed' + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Delete branch + run: | + echo "Deleting branch ${{head_ref}}" + git push origin --delete "${{head_ref}}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 3fb8c45ec288c6bfad3ee89b8d9d4448ff23d878 Mon Sep 17 00:00:00 2001 From: Alessio Cialini <63233981+alessio-cialini@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:42:34 +0200 Subject: [PATCH 04/73] fix: PaymentNoticesDetailPage.tsx posteAuth (#577) --- src/pages/notices/detail/PaymentNoticesDetailPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/notices/detail/PaymentNoticesDetailPage.tsx b/src/pages/notices/detail/PaymentNoticesDetailPage.tsx index 2f86ea08c..5a7a51666 100644 --- a/src/pages/notices/detail/PaymentNoticesDetailPage.tsx +++ b/src/pages/notices/detail/PaymentNoticesDetailPage.tsx @@ -154,7 +154,7 @@ const PaymentNoticesDetailPage = ({ {t('addEditInstitutionsDataPage.addForm.fields.posteAuth')} - {data?.posteAccountNumber} + {data?.posteAuth} From cf7c06b76c51b1eb381ee21d92f5cb1852ce3f5a Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Mon, 24 Jun 2024 14:42:52 +0000 Subject: [PATCH 05/73] Bump to version 1.26.0-2-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 30b5826c7..10cb4f7ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.0-1-next", + "version": "1.26.0-2-next", "homepage": "ui", "private": true, "scripts": { From 80762b8d1c77b035c9ec4984397d35a29c80a429 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Mon, 24 Jun 2024 17:34:08 +0200 Subject: [PATCH 06/73] fix github.head_ref in the action --- .github/workflows/ci_code_review.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_code_review.yml b/.github/workflows/ci_code_review.yml index 312ae18e8..afca1d9a2 100644 --- a/.github/workflows/ci_code_review.yml +++ b/.github/workflows/ci_code_review.yml @@ -241,7 +241,7 @@ jobs: - name: Delete branch run: | - echo "Deleting branch ${{head_ref}}" - git push origin --delete "${{head_ref}}" + echo "Deleting branch ${{github.head_ref}}" + git push origin --delete "${{github.head_ref}}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From b667c10a8fc86761d4360d542f8f00e2715762ba Mon Sep 17 00:00:00 2001 From: gioelemella <128155546+gioelemella@users.noreply.github.com> Date: Tue, 25 Jun 2024 10:42:14 +0200 Subject: [PATCH 07/73] feat: Review channel flow (#573) * [VAS-998] feat: introducing ops review from channel * [VAS-998] feat: Updated ops review modal management for channels * [VAS-997] changed channels page structured and integrated new getChannels API * [VAS-997] updated tests * [VAS-998] feat: Updated addEdit, details and tests * [VAS-998] feat: Updated tests, introduced common header to avoid duplicates * [VAS-998] feat: temporary rollback test * [VAS-998] feat: Update GetChannelAlert.test.tsx * [VAS-998] feat: Update ci_code_review.yml * [VAS-998] feat: Updated GetChannelAlert.test.tsx * [VAS-997] fix after merge with VAS-998 * fix client after merge * [VAS-997] fix: Width row station name * [VAS-997] fix: Improve createdBy/modifiedBy station detail * [VAS-997] fix: Handle change page channels table * [VAS-997] feat: Add alert channels details * [VAS-997] chore: Refactor detail button station detail * [VAS-997] feat: Refactor ChannelDetail component & improve UI * [VAS-997] feat: New translations * [VAS-997] fix: Refactor & format + fix translations * [VAS-997] feat: Delete unused component * [VAS-997] fix: Wrapper status chip translation for operators * [VAS-997] chore: Clean code * fixed client * [VAS-997] fixed unit tests * [VAS-997] add unit tests * [VAS-997] improve tests * [VAS-997] improve coverage --------- Co-authored-by: Alessio Cialini Co-authored-by: svariant Co-authored-by: Samuele Varianti <128470180+svariant@users.noreply.github.com> Co-authored-by: Jacopo Carlini --- .github/workflows/ci_code_review.yml | 2 +- package.json | 2 +- src/api/BackofficeClient.ts | 77 +- src/components/StatusChip.tsx | 2 +- src/locale/it.json | 46 +- .../addEditChannel/AddEditChannelForm.tsx | 1463 +++++++++-------- .../addEditChannel/AddEditChannelPage.tsx | 259 +-- .../__tests__/AddEditChannelForm.test.tsx | 110 +- .../__tests__/AddEditChannelPage.test.tsx | 57 +- .../channels/detail/ChannelDetailPage.tsx | 104 +- .../detail/__tests__/ChannelDetails.test.tsx | 224 ++- .../__tests__/ChannelDetailsWrap.test.tsx | 42 - .../detail/__tests__/DetailButton.test.tsx | 61 +- .../detail/__tests__/GetChannelAlert.test.tsx | 109 ++ .../detail/components/ChannelDetails.tsx | 734 ++++----- .../detail/components/ChannelDetailsWrap.tsx | 198 --- .../detail/components/DetailButtons.tsx | 339 ++-- .../detail/components/GetChannelAlert.tsx | 61 + src/pages/channels/list/ChannelsPage.tsx | 137 +- src/pages/channels/list/ChannelsTable.tsx | 220 +-- .../channels/list/ChannelsTableColumns.tsx | 290 ++-- .../channels/list/ChannelsTableSearchBar.tsx | 45 - .../list/__tests__/ChannelsPage.test.tsx | 30 + .../list/__tests__/ChannelsTable.test.tsx | 91 +- .../__tests__/ChannelsTableSearchBar.test.tsx | 26 - .../detail/components/StationDetails.tsx | 37 +- src/pages/stations/list/StationsTable.tsx | 156 +- .../stations/list/StationsTableColumns.tsx | 2 +- .../stations/list/StationsTableSearchBar.tsx | 46 - .../list/__tests__/StationsTable.test.tsx | 27 +- .../__tests__/StationsTableColumns.test.tsx | 2 +- src/services/__mocks__/channelService.ts | 775 +++++---- src/services/__mocks__/stationService.ts | 8 + src/services/__tests__/channelService.test.ts | 704 ++++---- src/services/channelService.ts | 401 +++-- 35 files changed, 3674 insertions(+), 3213 deletions(-) delete mode 100644 src/pages/channels/detail/__tests__/ChannelDetailsWrap.test.tsx create mode 100644 src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx delete mode 100644 src/pages/channels/detail/components/ChannelDetailsWrap.tsx create mode 100644 src/pages/channels/detail/components/GetChannelAlert.tsx delete mode 100644 src/pages/channels/list/ChannelsTableSearchBar.tsx delete mode 100644 src/pages/channels/list/__tests__/ChannelsTableSearchBar.test.tsx delete mode 100644 src/pages/stations/list/StationsTableSearchBar.tsx diff --git a/.github/workflows/ci_code_review.yml b/.github/workflows/ci_code_review.yml index afca1d9a2..eace04e46 100644 --- a/.github/workflows/ci_code_review.yml +++ b/.github/workflows/ci_code_review.yml @@ -218,7 +218,7 @@ jobs: with: args: > -Dsonar.coverage.exclusions=**/utils/**,**/__mocks__/**,**/__tests__/**,**/api/**,**/e2e/** - + -Dsonar.cpd.exclusions=**/__mocks__/**,**/__tests__/** close_pull_request_job: if: github.event_name == 'pull_request' && github.event.action == 'closed' runs-on: ubuntu-latest diff --git a/package.json b/package.json index 10cb4f7ff..8ac3fc829 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "clean:api-portal": "rimraf src/api/generated/portal && rimraf openApi/generated", "generate:api-portal": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/main/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-next": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/next/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", - "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/next/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", + "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1002-update-get-channels-api/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-local": "npm run generate:client", "generate:client": "jq 'walk(if type == \"object\" and has(\"parameters\") then .parameters |= map(select(.name != \"X-Request-Id\")) else . end)' ./openApi/portal-api-docs.json > ./openApi/portal-api-docs.json.temp && mv ./openApi/portal-api-docs.json.temp ./openApi/portal-api-docs.json && yarn run clean:api-portal && mkdirp openApi/generated && gen-api-models --api-spec openApi/portal-api-docs.json --out-dir src/api/generated/portal --no-strict --request-types --response-decoders --client && node openApi/scripts/api-portal_fixPostGen.js" }, diff --git a/src/api/BackofficeClient.ts b/src/api/BackofficeClient.ts index 25b92b1fe..fe63643fb 100644 --- a/src/api/BackofficeClient.ts +++ b/src/api/BackofficeClient.ts @@ -39,7 +39,6 @@ import { } from './generated/portal/ChannelDetailsDto'; import { ChannelDetailsResource } from './generated/portal/ChannelDetailsResource'; import { ChannelPspListResource } from './generated/portal/ChannelPspListResource'; -import { ChannelsResource } from './generated/portal/ChannelsResource'; import { CreditorInstitutionContactsResource } from './generated/portal/CreditorInstitutionContactsResource'; import { CreditorInstitutionDetailsResource } from './generated/portal/CreditorInstitutionDetailsResource'; import { CreditorInstitutionDto } from './generated/portal/CreditorInstitutionDto'; @@ -206,7 +205,6 @@ const channelBody = (channel: ChannelDetailsDto) => ({ rt_push: false, serv_plugin: undefined, service: channel.service, - status: StatusEnum.TO_CHECK_UPDATE, target_host: channel.target_host, target_path: channel.target_path, target_port: channel.target_port, @@ -380,8 +378,26 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - getChannels: async (page: number): Promise => { - const result = await backofficeClient.getChannels({ page }); + getChannels: async ({ + status, + channelCode, + brokerCode, + limit, + page, + }: { + status: ConfigurationStatus; + channelCode: string; + brokerCode: string; + limit?: number; + page: number; + }): Promise => { + const result = await backofficeClient.getChannels({ + status: String(status), + brokerCode, + channelCode, + limit, + page, + }); return extractResponse(result, 200, onRedirectToLogin); }, @@ -437,7 +453,7 @@ export const BackofficeApi = { createChannel: async (channel: ChannelDetailsDto): Promise => { const channelBody2Send = channelBody(channel); const result = await backofficeClient.createChannel({ - body: { ...channelBody2Send, status: StatusEnum.APPROVED }, + body: channelBody2Send, }); return extractResponse(result, 201, onRedirectToLogin); }, @@ -461,7 +477,6 @@ export const BackofficeApi = { target_port: channel.target_port, payment_types: channel.payment_types, validationUrl, - status: StatusEnum.TO_CHECK, }, }); return extractResponse(result, 201, onRedirectToLogin); @@ -474,32 +489,23 @@ export const BackofficeApi = { const channelBody2Send = channelBody(channel); const result = await backofficeClient.updateChannel({ 'channel-code': code, - body: { ...channelBody2Send, status: StatusEnum.APPROVED }, + body: channelBody2Send, }); return extractResponse(result, 200, onRedirectToLogin); }, - updateWrapperChannelDetailsToCheck: async ( - channel: ChannelDetailsDto, - validationUrl: string - ): Promise => { - const channelBody2Send = channelBody(channel); - const result = await backofficeClient.updateWrapperChannelDetails({ - body: { - ...channelBody2Send, - status: StatusEnum.APPROVED, - validationUrl, - }, - }); - return extractResponse(result, 200, onRedirectToLogin); - }, - - updateWrapperChannelDetailsToCheckUpdate: async ( - channel: ChannelDetailsDto, - validationUrl: string - ): Promise => { + updateWrapperChannelDetailsToCheck: async ({ + channelCode, + channel, + validationUrl, + }: { + channelCode: string; + channel: ChannelDetailsDto; + validationUrl: string; + }): Promise => { const channelBody2Send = channelBody(channel); const result = await backofficeClient.updateWrapperChannelDetails({ + 'channel-code': channelCode, body: { ...channelBody2Send, validationUrl, @@ -1480,4 +1486,23 @@ export const BackofficeApi = { }); return extractResponse(result, 200, onRedirectToLogin); }, + + updateWrapperChannelWithOperatorReview: async ({ + channelCode, + brokerPspCode, + note, + }: { + channelCode: string; + brokerPspCode: string; + note: string; + }): Promise => { + const result = await backofficeClient.updateWrapperChannelWithOperatorReview({ + 'channel-code': channelCode, + brokerPspCode, + body: { + note, + }, + }); + return extractResponse(result, 200, onRedirectToLogin); + }, }; diff --git a/src/components/StatusChip.tsx b/src/components/StatusChip.tsx index 733bf4de1..8687f81bf 100644 --- a/src/components/StatusChip.tsx +++ b/src/components/StatusChip.tsx @@ -14,7 +14,7 @@ export const StatusChip = ({status, size = 'regular'}: Props) => { return status ? ( ", "messageStation": "Un operatore PagoPA revisionerà le informazioni inserite nella stazione prima di approvare. Riceverai una notifica a revisione completata.
", "messageChannelOperation": "L’ente riceverà una notifica di conferma attivazione del canale.", - "channelConfiguration": "Configurazione canale" + "channelConfiguration": "Configurazione canale", + "channelValidate": "Conferma validazione canale", + "messageChannelOperationValidate": "Il canale passerà in stato attivo, e l'ente potrà utilizzarlo per attivare i suoi servizi" } }, "validationMessage": { @@ -319,14 +327,20 @@ "subtitle": "Dopo la modifica sarà richiesta una nuova revisione del canale." }, "channelDetailPage": { + "subtitle":{ + "waiting": "Ecco i dettagli del canale inviato in revisione.", + "approved": "Ecco i dettagli della canale." + }, "channels": "Canali", - "edit": "Modifica", "deleteRequired": "Richiedi eliminazione", "correctionRequired": "Richiedi correzione", + "requestEdit": "Richiedi modifiche", + "approveAndValidate": "Approva e valida", "configure": "Configura", "duplicate": "Duplica", "disable": "Disabilita", "createdOn": "Creato il", + "lastModified": "Ultima modifica operata da", "alertWarning": "Canale in attesa di revisione da parte di un operatore PagoPA.", "detail": "dettaglio", "state": "Stato", @@ -370,7 +384,21 @@ "timeoutB": "Timeout B", "timeoutC": "Timeout C", "pspNotify": "PSP Notify Payment", - "stamp": "Marca da bollo" + "stamp": "Marca da bollo", + "alert": { + "toCheckMessage": "Verifica le informazioni inserite dall’ente e approva o richiedi modifiche al canale.", + "toFixTitle": "Modifiche richieste", + "toFixMessage": "Canale in attesa di correzione da parte dell’ente.", + "waitingForRevision": "Il canale è in attesa di approvazione da parte di un nostro operatore. Riceverai una mail a procedura completata." + }, + "modal": { + "title": "Cosa c'è che non va?", + "subtitle": "il tuo commento sarà condiviso con l'ente", + "placeholder": "Descrivi l'anomalia", + "helperText": "Scrivi massimo 200 caratteri", + "successMessage": "Richiesta di modifiche inviata con successo", + "error": "Errore riscontrato in fase di invia richiesta di modifiche" + } }, "channelPSPList": { "title": "Gestisci PSP", @@ -1549,7 +1577,9 @@ "maintenancePageText": "Il portale è in manutenzione", "rejectedFile": "Tipo di file non supportato", "noOptions": "Nessun elemento", - "loading": "Caricamento..." + "loading": "Caricamento...", + "fromLower": "da", + "atLower": "il" }, "ANY": "Tutti" } diff --git a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx index 26896523f..f291eb69e 100644 --- a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx +++ b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx @@ -1,758 +1,769 @@ /* eslint-disable sonarjs/cognitive-complexity */ /* eslint-disable complexity */ -import {useEffect, useState} from 'react'; -import {useHistory} from 'react-router'; +import { useEffect, useState } from 'react'; +import { useHistory } from 'react-router'; import { - Box, - Button, - FormControl, - Grid, - InputLabel, - MenuItem, - Paper, - Select, - Stack, - TextField, - Typography, + Box, + Button, + FormControl, + Grid, + InputLabel, + MenuItem, + Paper, + Select, + Stack, + TextField, + Typography, } from '@mui/material'; -import {FormikProps, useFormik} from 'formik'; -import {Trans, useTranslation} from 'react-i18next'; -import {ButtonNaked, theme} from '@pagopa/mui-italia'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; +import { FormikProps, useFormik } from 'formik'; +import { Trans, useTranslation } from 'react-i18next'; +import { ButtonNaked, theme } from '@pagopa/mui-italia'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; import { - Badge as BadgeIcon, - CreditCard as CreditCardIcon, - MenuBook as MenuBookIcon, - RemoveCircleOutline, + Add, + Badge as BadgeIcon, + CreditCard as CreditCardIcon, + MenuBook as MenuBookIcon, + RemoveCircleOutline, } from '@mui/icons-material'; -import {generatePath} from 'react-router-dom'; +import { generatePath } from 'react-router-dom'; import ROUTES from '../../../routes'; import { - createChannel, - createWrapperChannelDetails, - updateChannel, - updateWrapperChannelDetailsToCheck, - updateWrapperChannelDetailsToCheckUpdate, + createChannel, + createWrapperChannelDetails, + updateChannel, + updateWrapperChannelDetailsToCheck, } from '../../../services/channelService'; -import {PaymentTypes} from '../../../api/generated/portal/PaymentTypes'; -import {Party} from '../../../model/Party'; -import {LOADING_TASK_CHANNEL_ADD_EDIT, LOADING_TASK_PAYMENT_TYPE} from '../../../utils/constants'; -import {sortPaymentType} from '../../../model/PaymentType'; -import {isValidURL} from '../../components/commonFunctions'; -import {ChannelDetailsResource, ProtocolEnum,} from '../../../api/generated/portal/ChannelDetailsResource'; -import {WrapperStatusEnum} from '../../../api/generated/portal/WrapperChannelDetailsResource'; -import {ChannelOnCreation, FormAction} from '../../../model/Channel'; -import {ENV} from '../../../utils/env'; +import { PaymentTypes } from '../../../api/generated/portal/PaymentTypes'; +import { Party } from '../../../model/Party'; +import { LOADING_TASK_CHANNEL_ADD_EDIT, LOADING_TASK_PAYMENT_TYPE } from '../../../utils/constants'; +import { sortPaymentType } from '../../../model/PaymentType'; +import { isValidURL } from '../../components/commonFunctions'; +import { + ChannelDetailsResource, + ProtocolEnum, +} from '../../../api/generated/portal/ChannelDetailsResource'; +import { WrapperStatusEnum } from '../../../api/generated/portal/WrapperChannelDetailsResource'; +import { ChannelOnCreation, FormAction } from '../../../model/Channel'; +import { ENV } from '../../../utils/env'; import ConfirmModal from '../../components/ConfirmModal'; -import {getPaymentTypes} from '../../../services/configurationService'; -import {useUserRole} from "../../../hooks/useUserRole"; +import { getPaymentTypes } from '../../../services/configurationService'; +import { useUserRole } from '../../../hooks/useUserRole'; import AddEditChannelFormSectionTitle from './AddEditChannelFormSectionTitle'; import AddEditChannelValidationForm from './components/AddEditChannelValidationForm'; type Props = { - selectedParty: Party; - channelDetail?: ChannelDetailsResource; - channelCode: string; - formAction: string; + selectedParty: Party; + channelDetail?: ChannelDetailsResource; + channelCode: string; + formAction: string; }; -const AddEditChannelForm = ({selectedParty, channelCode, channelDetail, formAction}: Props) => { - const {t} = useTranslation(); - const history = useHistory(); - const addError = useErrorDispatcher(); - - const setLoading = useLoading(LOADING_TASK_CHANNEL_ADD_EDIT); - const setLoadingPayment = useLoading(LOADING_TASK_PAYMENT_TYPE); - const [showConfirmModal, setShowConfirmModal] = useState(false); - const [paymentOptions, setPaymentOptions] = useState({payment_types: []}); - const {userIsPagopaOperator} = useUserRole(); - - const forwarder01 = - ENV.ENV === 'PROD' - ? 'https://api.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward' - : 'https://api.uat.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward'; - - const initialFormData = ( - channelCode: string, - channelDetail?: ChannelDetailsResource, - selectedParty?: Party - ): ChannelOnCreation => { - if (channelDetail) { - return { - broker_description: channelDetail.broker_description ?? '', - broker_psp_code: channelDetail.broker_psp_code ?? '', - card_chart: false, - channel_code: channelDetail.channel_code, - digital_stamp_brand: channelDetail.digital_stamp_brand ?? false, - flag_io: channelDetail.flag_io ?? false, - ip: channelDetail.ip ?? '', - newConnection: - `${channelDetail.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://'}${ - channelDetail.ip - }${channelDetail.service}` === forwarder01 - ? forwarder01 - : '', - new_password: channelDetail.new_password ?? '', - nmp_service: channelDetail.nmp_service ?? '', - on_us: channelDetail.on_us ?? false, - password: channelDetail.password ?? '', - payment_model: channelDetail.payment_model ?? undefined, - payment_types: channelDetail.payment_types ? [...channelDetail.payment_types] : [''], - port: channelDetail.port ?? 0, - primitive_version: channelDetail.primitive_version ?? undefined, - protocol: channelDetail.protocol ?? undefined, - proxyUnion: channelDetail.proxy_host !== undefined && channelDetail.proxy_host !== null && - channelDetail.proxy_host !== '' && channelDetail.proxy_port !== undefined && channelDetail.proxy_port !== null ? - `${channelDetail.proxy_host}:${channelDetail.proxy_port}` : - '', - proxy_host: channelDetail.proxy_host ?? '', - proxy_port: channelDetail.proxy_port ?? undefined, - proxy_enabled: channelDetail.proxy_enabled ?? false, - recovery: channelDetail.recovery ?? false, - rt_push: channelDetail.rt_push ?? false, - serv_plugin: channelDetail.serv_plugin ?? '', - service: channelDetail.service ?? '', - target_host: channelDetail.target_host ?? '', - target_path: channelDetail.target_path ?? '', - target_port: channelDetail.target_port ?? undefined, - targetUnion: - channelDetail.target_host !== '' - ? `${channelDetail.target_host}:${channelDetail.target_port}${channelDetail.target_path}` - : `${channelDetail.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://'}${ - channelDetail.ip - }:${channelDetail.port}${channelDetail.service}`, - thread_number: channelDetail.thread_number ?? 0, - timeout_a: channelDetail.timeout_a ?? 0, - timeout_b: channelDetail.timeout_b ?? 0, - timeout_c: channelDetail.timeout_c ?? 0, - validationUrl: '' - }; - } else { - return { - broker_description: selectedParty?.description ?? '', - broker_psp_code: selectedParty?.fiscalCode ?? '', - channel_code: channelCode, - digital_stamp_brand: false, - flag_io: false, - ip: '', - newConnection: '', - password: '', - payment_model: undefined, - payment_types: [''], - primitive_version: undefined, - protocol: undefined, - proxyUnion: '', - proxy_host: '', - proxy_port: undefined, - proxy_enabled: false, - target_host: '', - target_path: '', - target_port: undefined, - targetUnion: '', - timeout_a: 0, - timeout_b: 0, - timeout_c: 0, - validationUrl: '' - }; - } - }; - - const validate = (values: Partial) => - Object.fromEntries( - Object.entries({ - ...{ - broker_psp_code: !values.broker_psp_code - ? t('addEditChannelPage.validationMessage.requiredField') - : undefined, - broker_description: !values.broker_description - ? t('addEditChannelPage.validationMessage.requiredField') - : undefined, - channel_code: !values.channel_code - ? t('addEditChannelPage.validationMessage.requiredField') - : undefined, - targetUnion: !values.targetUnion - ? t('addEditChannelPage.validationMessage.requiredField') - : !isValidURL(values.targetUnion) - ? t('addEditChannelPage.validationMessage.urlNotValid') - : undefined, - payment_types: values.payment_types?.includes('') - ? t('addEditChannelPage.validationMessage.requiredField') - : undefined, - }, - ...(userIsPagopaOperator && { - primitive_version: !values.primitive_version - ? t('addEditChannelPage.validationMessage.requiredField') - : validatePrimitiveVersion(values.primitive_version) - ? t('addEditStationPage.validation.overVersion') - : undefined, - password: !values.password - ? t('addEditChannelPage.validationMessage.requiredField') - : undefined, - - proxy_host: !values.proxy_host ? t('addEditChannelPage.requiredField') : undefined, - }), - }).filter(([_key, value]) => value) - ); - - const formik = useFormik({ - initialValues: initialFormData(channelCode, channelDetail, selectedParty), - validate, - onSubmit: () => { - setShowConfirmModal(true); +const componentPath = 'addEditChannelPage.addForm'; +const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAction }: Props) => { + const { t } = useTranslation(); + const history = useHistory(); + const addError = useErrorDispatcher(); + + const setLoading = useLoading(LOADING_TASK_CHANNEL_ADD_EDIT); + const setLoadingPayment = useLoading(LOADING_TASK_PAYMENT_TYPE); + const [showConfirmModal, setShowConfirmModal] = useState(false); + const [paymentOptions, setPaymentOptions] = useState({ payment_types: [] }); + const { userIsPagopaOperator } = useUserRole(); + + const forwarder01 = + ENV.ENV === 'PROD' + ? 'https://api.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward' + : 'https://api.uat.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward'; + + const initialFormData = ( + channelCode: string, + channelDetail?: ChannelDetailsResource, + selectedParty?: Party + ): ChannelOnCreation => { + if (channelDetail) { + return { + broker_description: channelDetail.broker_description ?? '', + broker_psp_code: channelDetail.broker_psp_code ?? '', + card_chart: false, + channel_code: channelDetail.channel_code, + digital_stamp_brand: channelDetail.digital_stamp_brand ?? false, + flag_io: channelDetail.flag_io ?? false, + ip: channelDetail.ip ?? '', + newConnection: + `${channelDetail.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://'}${ + channelDetail.ip + }${channelDetail.service}` === forwarder01 + ? forwarder01 + : '', + new_password: channelDetail.new_password ?? '', + nmp_service: channelDetail.nmp_service ?? '', + on_us: channelDetail.on_us ?? false, + password: channelDetail.password ?? '', + payment_model: channelDetail.payment_model ?? undefined, + payment_types: channelDetail.payment_types ? [...channelDetail.payment_types] : [''], + port: channelDetail.port ?? 0, + primitive_version: channelDetail.primitive_version ?? undefined, + protocol: channelDetail.protocol ?? undefined, + proxyUnion: + channelDetail.proxy_host !== undefined && + channelDetail.proxy_host !== null && + channelDetail.proxy_host !== '' && + channelDetail.proxy_port !== undefined && + channelDetail.proxy_port !== null + ? `${channelDetail.proxy_host}:${channelDetail.proxy_port}` + : '', + proxy_host: channelDetail.proxy_host ?? '', + proxy_port: channelDetail.proxy_port ?? undefined, + proxy_enabled: channelDetail.proxy_enabled ?? false, + recovery: channelDetail.recovery ?? false, + rt_push: channelDetail.rt_push ?? false, + serv_plugin: channelDetail.serv_plugin ?? '', + service: channelDetail.service ?? '', + target_host: channelDetail.target_host ?? '', + target_path: channelDetail.target_path ?? '', + target_port: channelDetail.target_port ?? undefined, + targetUnion: + channelDetail.target_host !== '' + ? `${channelDetail.target_host}:${channelDetail.target_port}${channelDetail.target_path}` + : `${channelDetail.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://'}${ + channelDetail.ip + }:${channelDetail.port}${channelDetail.service}`, + thread_number: channelDetail.thread_number ?? 0, + timeout_a: channelDetail.timeout_a ?? 0, + timeout_b: channelDetail.timeout_b ?? 0, + timeout_c: channelDetail.timeout_c ?? 0, + validationUrl: '', + }; + } else { + return { + broker_description: selectedParty?.description ?? '', + broker_psp_code: selectedParty?.fiscalCode ?? '', + channel_code: channelCode, + digital_stamp_brand: false, + flag_io: false, + ip: '', + newConnection: '', + password: '', + payment_model: undefined, + payment_types: [''], + primitive_version: undefined, + protocol: undefined, + proxyUnion: '', + proxy_host: '', + proxy_port: undefined, + proxy_enabled: false, + target_host: '', + target_path: '', + target_port: undefined, + targetUnion: '', + timeout_a: 0, + timeout_b: 0, + timeout_c: 0, + validationUrl: '', + }; + } + }; + + const validate = (values: Partial) => + Object.fromEntries( + Object.entries({ + ...{ + broker_psp_code: !values.broker_psp_code + ? t('addEditChannelPage.validationMessage.requiredField') + : undefined, + broker_description: !values.broker_description + ? t('addEditChannelPage.validationMessage.requiredField') + : undefined, + channel_code: !values.channel_code + ? t('addEditChannelPage.validationMessage.requiredField') + : undefined, + targetUnion: !values.targetUnion + ? t('addEditChannelPage.validationMessage.requiredField') + : !isValidURL(values.targetUnion) + ? t('addEditChannelPage.validationMessage.urlNotValid') + : undefined, + payment_types: values.payment_types?.includes('') + ? t('addEditChannelPage.validationMessage.requiredField') + : undefined, }, - enableReinitialize: true, - validateOnMount: true, - }); - - - const [isNewConnectivity, setIsNewConnectivity] = useState(!!formik.values.newConnection); - - - useEffect(() => { - splitTarget(formik.values); - }, [formik.values.targetUnion]); - - useEffect(() => { - splitProxy(formik.values); - if (formik.values.proxy_host !== '' && formik.values.proxy_port !== 0) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - formik.setValues({...formik.values, proxy_enabled: true}); - } - }, [formik.values.proxyUnion]); - - useEffect(() => { - if (paymentOptions?.payment_types?.length === 0) { - setLoadingPayment(true); - getPaymentTypes() - .then((results) => { - if (results) { - setPaymentOptions(results); - } - }) - .catch((reason) => { - addError({ - id: 'GET_PAYMENT_TYPES', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while getting payment types`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('addEditChannelPage.addForm.errorMessagePaymentTypesDesc'), - component: 'Toast', - }); - }) - .finally(() => setLoadingPayment(false)); - } - }, []); - - const splitURL = (targetURL: string) => { - try { - const url = new URL(targetURL); - return { - protocolSplit: url.protocol, - hostSplit: url.hostname, - portSplit: - Number(url.port) !== 0 && Number(url.port) !== 80 - ? Number(url.port) - : url.protocol === 'https:' - ? 443 - : 80, - pathSplit: url.pathname + url.search + url.hash, - }; - } catch (e) { - console.error(e); - } - return { - protocolSplit: '', - hostSplit: '', - portSplit: 0, - pathSplit: '', - }; - }; - - const splitTarget = (values: ChannelOnCreation) => { - const normalizedTargetUnion = formik.values.targetUnion.trim(); // Normalizza il valore rimuovendo spazi iniziali e finali - - if (normalizedTargetUnion && normalizedTargetUnion !== '') { - const splitTargetUnion = splitURL(formik.values.targetUnion); - - if (splitTargetUnion) { - const {protocolSplit, hostSplit, pathSplit, portSplit} = splitTargetUnion; - - // eslint-disable-next-line functional/immutable-data - values.target_host = `${protocolSplit ? protocolSplit + '//' : ''}${hostSplit}`; - - // eslint-disable-next-line functional/immutable-data - values.target_path = pathSplit; - - // eslint-disable-next-line functional/immutable-data - values.target_port = portSplit !== 0 ? portSplit : protocolSplit === 'https:' ? 443 : 80; - } - } - }; - - const splitProxy = (values: ChannelOnCreation) => { - if (formik.values.proxyUnion && formik.values.proxyUnion !== '') { - if (!formik.values.proxyUnion.startsWith("http")) { - // eslint-disable-next-line functional/immutable-data - formik.values.proxyUnion = "http://".concat(formik.values.proxyUnion); - } - const splitProxyUnion = splitURL(formik.values.proxyUnion); - if (splitProxyUnion) { - const {protocolSplit, hostSplit, portSplit} = splitProxyUnion; - - // eslint-disable-next-line functional/immutable-data - values.proxy_host = `${hostSplit}`; - // eslint-disable-next-line functional/immutable-data - values.proxy_port = portSplit; - } - } - }; - - const splitNewConnection = (values: ChannelOnCreation) => { - const splitUrl = - formik.values.newConnection.trim() !== '' && isNewConnectivity - ? splitURL(formik.values.newConnection) - : splitURL(formik.values.targetUnion); - - if (splitUrl) { - const {protocolSplit, hostSplit, pathSplit, portSplit} = splitUrl; - // eslint-disable-next-line functional/immutable-data - values.protocol = protocolSplit === 'https:' ? ProtocolEnum.HTTPS : ProtocolEnum.HTTP; - // eslint-disable-next-line functional/immutable-data - values.ip = hostSplit; - // eslint-disable-next-line functional/immutable-data - values.port = portSplit !== 0 ? portSplit : protocolSplit === 'https:' ? 443 : 80; - // eslint-disable-next-line functional/immutable-data - values.service = pathSplit; - // eslint-disable-next-line functional/immutable-data - values.nmp_service = pathSplit; - } - }; - - const inputGroupStyle = { - borderRadius: 1, - border: 1, - borderColor: theme.palette.divider, - p: 3, - mb: 3, - }; - - const validatePrimitiveVersion = (primitive_version: number | undefined) => { - if (primitive_version) { - return primitive_version > 0 && primitive_version <= 2 ? false : true; - } - return false; - }; - - const enableSubmit = (values: ChannelOnCreation) => { - const baseConditions = - values.broker_psp_code !== '' && - values.broker_description !== '' && - values.channel_code !== '' && - values.targetUnion !== '' && - values.payment_types?.toString() !== ''; - - if (baseConditions) { - if (!userIsPagopaOperator) { - return true; - } else { - if ( - values.primitive_version?.toString() !== '' && - values.password !== '' && - values.proxyUnion !== '' - ) { - if (userIsPagopaOperator && values.payment_types && values.payment_types.length > 0) { - for (const paymentType of values.payment_types) { - if (paymentType === '') { - return false; - } - } - } - return true; - } - } - } - - return false; - }; + ...(userIsPagopaOperator && { + primitive_version: !values.primitive_version + ? t('addEditChannelPage.validationMessage.requiredField') + : validatePrimitiveVersion(values.primitive_version) + ? t('addEditStationPage.validation.overVersion') + : undefined, + password: !values.password + ? t('addEditChannelPage.validationMessage.requiredField') + : undefined, + + proxy_host: !values.proxy_host ? t('addEditChannelPage.requiredField') : undefined, + }), + }).filter(([_key, value]) => value) + ); - const addPaymentMethod = async () => { - if (userIsPagopaOperator && formik.values.payment_types) { - const newArr = [...formik.values.payment_types, '']; - await formik.setFieldValue('payment_types', newArr); - } + const formik = useFormik({ + initialValues: initialFormData(channelCode, channelDetail, selectedParty), + validate, + onSubmit: () => { + setShowConfirmModal(true); + }, + enableReinitialize: true, + validateOnMount: true, + }); + + const [isNewConnectivity, setIsNewConnectivity] = useState(!!formik.values.newConnection); + + useEffect(() => { + splitTarget(formik.values); + }, [formik.values.targetUnion]); + + useEffect(() => { + splitProxy(formik.values); + if (formik.values.proxy_host !== '' && formik.values.proxy_port !== 0) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + formik.setValues({ ...formik.values, proxy_enabled: true }); + } + }, [formik.values.proxyUnion]); + + useEffect(() => { + if (paymentOptions?.payment_types?.length === 0) { + setLoadingPayment(true); + getPaymentTypes() + .then((results) => { + if (results) { + setPaymentOptions(results); + } + }) + .catch((reason) => { + addError({ + id: 'GET_PAYMENT_TYPES', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while getting payment types`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t(`${componentPath}.errorMessagePaymentTypesDesc`), + component: 'Toast', + }); + }) + .finally(() => setLoadingPayment(false)); + } + }, []); + + const splitURL = (targetURL: string) => { + try { + const url = new URL(targetURL); + return { + protocolSplit: url.protocol, + hostSplit: url.hostname, + portSplit: + Number(url.port) !== 0 && Number(url.port) !== 80 + ? Number(url.port) + : url.protocol === 'https:' + ? 443 + : 80, + pathSplit: url.pathname + url.search + url.hash, + }; + } catch (e) { + console.error(e); + } + return { + protocolSplit: '', + hostSplit: '', + portSplit: 0, + pathSplit: '', }; - - const deletePaymentMethod = async (index: number) => { - if (userIsPagopaOperator && formik.values.payment_types) { - const newArr = [...formik.values.payment_types]; - if (index > -1 && index < formik.values.payment_types.length) { - // eslint-disable-next-line functional/immutable-data - newArr.splice(index, 1); + }; + + const splitTarget = (values: ChannelOnCreation) => { + const normalizedTargetUnion = formik.values.targetUnion.trim(); // Normalizza il valore rimuovendo spazi iniziali e finali + + if (normalizedTargetUnion && normalizedTargetUnion !== '') { + const splitTargetUnion = splitURL(formik.values.targetUnion); + + if (splitTargetUnion) { + const { protocolSplit, hostSplit, pathSplit, portSplit } = splitTargetUnion; + + // eslint-disable-next-line functional/immutable-data + values.target_host = `${protocolSplit ? protocolSplit + '//' : ''}${hostSplit}`; + + // eslint-disable-next-line functional/immutable-data + values.target_path = pathSplit; + + // eslint-disable-next-line functional/immutable-data + values.target_port = portSplit !== 0 ? portSplit : protocolSplit === 'https:' ? 443 : 80; + } + } + }; + + const splitProxy = (values: ChannelOnCreation) => { + if (formik.values.proxyUnion && formik.values.proxyUnion !== '') { + if (!formik.values.proxyUnion.startsWith('http')) { + // eslint-disable-next-line functional/immutable-data + formik.values.proxyUnion = 'http://'.concat(formik.values.proxyUnion); + } + const splitProxyUnion = splitURL(formik.values.proxyUnion); + if (splitProxyUnion) { + const { protocolSplit, hostSplit, portSplit } = splitProxyUnion; + + // eslint-disable-next-line functional/immutable-data + values.proxy_host = `${hostSplit}`; + // eslint-disable-next-line functional/immutable-data + values.proxy_port = portSplit; + } + } + }; + + const splitNewConnection = (values: ChannelOnCreation) => { + const splitUrl = + formik.values.newConnection.trim() !== '' && isNewConnectivity + ? splitURL(formik.values.newConnection) + : splitURL(formik.values.targetUnion); + + if (splitUrl) { + const { protocolSplit, hostSplit, pathSplit, portSplit } = splitUrl; + // eslint-disable-next-line functional/immutable-data + values.protocol = protocolSplit === 'https:' ? ProtocolEnum.HTTPS : ProtocolEnum.HTTP; + // eslint-disable-next-line functional/immutable-data + values.ip = hostSplit; + // eslint-disable-next-line functional/immutable-data + values.port = portSplit !== 0 ? portSplit : protocolSplit === 'https:' ? 443 : 80; + // eslint-disable-next-line functional/immutable-data + values.service = pathSplit; + // eslint-disable-next-line functional/immutable-data + values.nmp_service = pathSplit; + } + }; + + const inputGroupStyle = { + borderRadius: 1, + border: 1, + borderColor: theme.palette.divider, + p: 3, + mb: 3, + }; + + const validatePrimitiveVersion = (primitive_version: number | undefined) => { + if (primitive_version) { + return primitive_version > 0 && primitive_version <= 2 ? false : true; + } + return false; + }; + + const enableSubmit = (values: ChannelOnCreation) => { + const baseConditions = + values.broker_psp_code !== '' && + values.broker_description !== '' && + values.channel_code !== '' && + values.targetUnion !== '' && + values.payment_types?.toString() !== ''; + + if (baseConditions) { + if (!userIsPagopaOperator) { + return true; + } else { + if ( + values.primitive_version?.toString() !== '' && + values.password !== '' && + values.proxyUnion !== '' + ) { + if (userIsPagopaOperator && values.payment_types && values.payment_types.length > 0) { + for (const paymentType of values.payment_types) { + if (paymentType === '') { + return false; + } } - await formik.setFieldValue('payment_types', newArr); + } + return true; } - }; - - const redirect = () => { + } + } + + return false; + }; + + const addPaymentMethod = async () => { + if (userIsPagopaOperator && formik.values.payment_types) { + const newArr = [...formik.values.payment_types, '']; + await formik.setFieldValue('payment_types', newArr); + } + }; + + const deletePaymentMethod = async (index: number) => { + if (userIsPagopaOperator && formik.values.payment_types) { + const newArr = [...formik.values.payment_types]; + if (index > -1 && index < formik.values.payment_types.length) { + // eslint-disable-next-line functional/immutable-data + newArr.splice(index, 1); + } + await formik.setFieldValue('payment_types', newArr); + } + }; + + const redirect = () => { + if (userIsPagopaOperator) { + history.push(generatePath(ROUTES.CHANNEL_DETAIL, { channelId: formik.values.channel_code })); + } else { + history.push(ROUTES.CHANNELS); + } + }; + + const submit = async (values: ChannelOnCreation) => { + setShowConfirmModal(false); + setLoading(true); + + splitNewConnection(formik.values); + splitProxy(formik.values); + + try { + const validationUrl = `${window.location.origin}${generatePath(ROUTES.CHANNEL_DETAIL, { + channelId: formik.values.channel_code, + })}`; + + if (formAction === FormAction.Create || formAction === FormAction.Duplicate) { + await createWrapperChannelDetails(values as any, validationUrl); + redirect(); + } + + if (formAction === FormAction.Edit) { if (userIsPagopaOperator) { - history.push(generatePath(ROUTES.CHANNEL_DETAIL, {channelId: formik.values.channel_code})); + if ( + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK || + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX + ) { + await createChannel(values); + } else if ( + channelDetail?.wrapperStatus === WrapperStatusEnum.APPROVED || + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE || + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX_UPDATE + ) { + await updateChannel(channelCode, values); + } else { + throw new Error('Wrong channel wrapper status'); + } } else { - history.push(ROUTES.CHANNELS); + await updateWrapperChannelDetailsToCheck({channelCode, channel: values, validationUrl}); } - }; - - const submit = async (values: ChannelOnCreation) => { - setShowConfirmModal(false); - setLoading(true); - - splitNewConnection(formik.values); - splitProxy(formik.values); - - try { - const validationUrl = `${window.location.origin}${generatePath(ROUTES.CHANNEL_DETAIL, { - channelId: formik.values.channel_code, - })}`; - - if (formAction === FormAction.Create || formAction === FormAction.Duplicate) { - await createWrapperChannelDetails(values as any, validationUrl); - redirect(); - } - - if (formAction === FormAction.Edit) { - switch (channelDetail?.wrapperStatus) { - case WrapperStatusEnum.TO_CHECK: - if (userIsPagopaOperator) { - await createChannel(values); - } else { - await updateWrapperChannelDetailsToCheck(values, validationUrl); + redirect(); + } + } catch (reason) { + addError({ + id: 'ADDEDIT_CHANNEL', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while adding/editing channel`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t(`${componentPath}.errorMessageDesc`), + component: 'Toast', + }); + } finally { + setLoading(false); + } + }; + + const handleChangeNumberOnly = ( + e: React.ChangeEvent, + field: string, + formik: FormikProps + ) => { + const regex = /^[0-9\b]+$/; + if (e.target.value === '' || regex.test(e.target.value)) { + formik.setFieldValue(field, e.target.value); + } + }; + + const openConfirmModal = () => { + if (formik.isValid) { + setShowConfirmModal(true); + } else { + setShowConfirmModal(false); + } + }; + + return ( + <> + + + + + {t('channelDetailPage.channelConfiguration')} + + + + + {t('channelDetailPage.channelConfiguration')} + + + + + + + } + isRequired + > + + + + + + + + + + + + + + + } + isRequired + > + + + formik.handleChange(e)} + error={formik.touched.targetUnion && Boolean(formik.errors.targetUnion)} + helperText={formik.touched.targetUnion && formik.errors.targetUnion} + inputProps={{ + 'data-testid': 'target-union-test', + }} + required + /> + + + + + } + isRequired + > + + {formik.values.payment_types?.map((_pT, i) => ( + + {i > 0 && userIsPagopaOperator ? ( + + deletePaymentMethod(i)} + id={`remove_PaymentMethod${i}`} + data-testid="remove-payment-method" + /> + + ) : null} + 0 && userIsPagopaOperator ? 5 : 6} key={`item${i}`}> + + + {t(`${componentPath}.fields.paymentType`)} + + + + + {userIsPagopaOperator && i === 0 && ( - - {t('channelDetailPage.channelConfiguration')} - + addPaymentMethod()} + sx={{ color: 'primary.main', mr: '20px' }} + endIcon={} + weight="default" + data-testid="add-payment-test" + > + {t(`${componentPath}.fields.addPayment`)} + + )} - - - - } - isRequired - > - - - - - - - - - - - - - - - } - isRequired - > - - - formik.handleChange(e)} - error={formik.touched.targetUnion && Boolean(formik.errors.targetUnion)} - helperText={formik.touched.targetUnion && formik.errors.targetUnion} - inputProps={{ - 'data-testid': 'target-union-test', - }} - required - /> - - - - - } - isRequired - > - - {formik.values.payment_types?.map((_pT, i) => ( - - {i > 0 && userIsPagopaOperator ? ( - - deletePaymentMethod(i)} - id={`remove_PaymentMethod${i}`} - data-testid="remove-payment-method" - /> - - ) : null} - 0 && userIsPagopaOperator ? 5 : 6} key={`item${i}`}> - - - {t('addEditChannelPage.addForm.fields.paymentType')} - - - - - {userIsPagopaOperator && ( - - {i === 0 && ( - - addPaymentMethod()} - sx={{color: 'primary.main', mr: '20px'}} - weight="default" - data-testid="add-payment-test" - > - {t('addEditChannelPage.addForm.fields.addPayment')} - - - )} - - )} - - ))} - - - - - - {formAction === FormAction.Edit && userIsPagopaOperator ? ( - - ) : null} - - - - - - - - - - - - Un operatore PagoPA revisionerà le informazioni inserite nel canale prima di - approvare. Riceverai una notifica a revisione completata. -
- - ) - } - openConfirmModal={showConfirmModal} - onConfirmLabel={userIsPagopaOperator ? t('general.confirm') : t('general.send')} - onCloseLabel={t('general.turnBack')} - handleCloseConfirmModal={() => setShowConfirmModal(false)} - handleConfrimSubmit={async () => { - await submit(formik.values); - setShowConfirmModal(false); - }} - /> - - ); + ))} + + + + + + {formAction === FormAction.Edit && userIsPagopaOperator ? ( + + ) : null} + + + + + + + + + + + + Un operatore PagoPA revisionerà le informazioni inserite nel canale prima di + approvare. Riceverai una notifica a revisione completata. +
+ + ) + } + openConfirmModal={showConfirmModal} + onConfirmLabel={userIsPagopaOperator ? t('general.confirm') : t('general.send')} + onCloseLabel={t('general.turnBack')} + handleCloseConfirmModal={() => setShowConfirmModal(false)} + handleConfrimSubmit={async () => { + await submit(formik.values); + setShowConfirmModal(false); + }} + /> + + ); }; export default AddEditChannelForm; diff --git a/src/pages/channels/addEditChannel/AddEditChannelPage.tsx b/src/pages/channels/addEditChannel/AddEditChannelPage.tsx index a960eab24..9e1eb4633 100644 --- a/src/pages/channels/addEditChannel/AddEditChannelPage.tsx +++ b/src/pages/channels/addEditChannel/AddEditChannelPage.tsx @@ -1,136 +1,143 @@ -import {ArrowBack} from '@mui/icons-material'; -import {Breadcrumbs, Grid, Stack, Typography} from '@mui/material'; -import {ButtonNaked} from '@pagopa/mui-italia'; -import {TitleBox, useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useHistory, useParams} from 'react-router'; -import {ChannelDetailsResource} from '../../../api/generated/portal/ChannelDetailsResource'; -import {FormAction} from '../../../model/Channel'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; +import { ArrowBack } from '@mui/icons-material'; +import { Breadcrumbs, Grid, Stack, Typography } from '@mui/material'; +import { ButtonNaked } from '@pagopa/mui-italia'; +import { TitleBox, useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useHistory, useParams } from 'react-router'; +import { ChannelDetailsResource } from '../../../api/generated/portal/ChannelDetailsResource'; +import { WrapperStatusEnum } from '../../../api/generated/portal/WrapperChannelDetailsResource'; +import { FormAction } from '../../../model/Channel'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; -import {getChannelCode, getChannelDetail} from '../../../services/channelService'; -import {LOADING_TASK_CHANNEL_ADD_EDIT} from '../../../utils/constants'; -import {useUserRole} from "../../../hooks/useUserRole"; +import { getChannelCode, getChannelDetail } from '../../../services/channelService'; +import { LOADING_TASK_CHANNEL_ADD_EDIT } from '../../../utils/constants'; +import { useUserRole } from '../../../hooks/useUserRole'; import AddEditChannelForm from './AddEditChannelForm'; const AddEditChannelPage = () => { - const {t} = useTranslation(); - const history = useHistory(); - const addError = useErrorDispatcher(); - const setLoading = useLoading(LOADING_TASK_CHANNEL_ADD_EDIT); - const {channelId, actionId} = useParams<{ channelId: string; actionId: string }>(); - const formAction = actionId ?? FormAction.Create; - const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const {userIsPagopaOperator} = useUserRole(); - const [channelDetail, setChannelDetail] = useState(); - const [channelCode, setChannelCode] = useState(''); - const pspTaxCode = selectedParty?.fiscalCode ? selectedParty.fiscalCode : ''; + const { t } = useTranslation(); + const history = useHistory(); + const addError = useErrorDispatcher(); + const setLoading = useLoading(LOADING_TASK_CHANNEL_ADD_EDIT); + const { channelId, actionId } = useParams<{ channelId: string; actionId: string }>(); + const formAction = actionId ?? FormAction.Create; + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); + const { userIsPagopaOperator } = useUserRole(); + const [channelDetail, setChannelDetail] = useState(); + const [channelCode, setChannelCode] = useState(''); + const pspTaxCode = selectedParty?.fiscalCode ? selectedParty.fiscalCode : ''; - const goBack = () => history.push(ROUTES.CHANNELS); + const goBack = () => history.push(ROUTES.CHANNELS); - useEffect(() => { - if (formAction === FormAction.Edit) { - setLoading(true); - getChannelDetail(channelId) - .then((response) => { - setChannelDetail(response); - setChannelCode(response.channel_code ?? ''); - }) - .catch((reason) => { - addError({ - id: 'GET_CHANNEL_DETAILS', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while getting channel details`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('addEditChannelPage.addForm.errorMessageChannelDetailsDesc'), - component: 'Toast', - }); - }) - .finally(() => { - setLoading(false); - }); - } else { - setLoading(true); - getChannelCode(pspTaxCode) - .then((result) => { - setChannelCode(result.channel_code ?? ''); - }) - .catch((reason) => { - addError({ - id: 'GET_CHANNEL_CODE', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while getting payment types`, - toNotify: true, - displayableTitle: t('addEditChannelPage.addForm.errorMessageChannelCodeTypesTitle'), - displayableDescription: t( - 'addEditChannelPage.addForm.errorMessageChannelCodeTypesDesc' - ), - component: 'Toast', - }); - }) - .finally(() => setLoading(false)); - } - }, [selectedParty]); + useEffect(() => { + if (formAction === FormAction.Edit) { + setLoading(true); + getChannelDetail(channelId) + .then((response) => { + setChannelDetail(response); + setChannelCode(response.channel_code ?? ''); + }) + .catch((reason) => { + addError({ + id: 'GET_CHANNEL_DETAILS', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while getting channel details`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('addEditChannelPage.addForm.errorMessageChannelDetailsDesc'), + component: 'Toast', + }); + }) + .finally(() => { + setLoading(false); + }); + } else { + setLoading(true); + getChannelCode(pspTaxCode) + .then((result) => { + setChannelCode(result.channel_code ?? ''); + }) + .catch((reason) => { + addError({ + id: 'GET_CHANNEL_CODE', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while getting payment types`, + toNotify: true, + displayableTitle: t('addEditChannelPage.addForm.errorMessageChannelCodeTypesTitle'), + displayableDescription: t( + 'addEditChannelPage.addForm.errorMessageChannelCodeTypesDesc' + ), + component: 'Toast', + }); + }) + .finally(() => setLoading(false)); + } + }, [selectedParty]); - return ( - - - - } - sx={{color: 'primary.main', mr: '20px'}} - weight="default" - > - {t('general.exit')} - - - {t('general.Channels')} - {formAction === FormAction.Edit && ( - {channelId} - )} - - {userIsPagopaOperator - ? t(`addEditChannelPage.config.titleConfiguration`) - : t(`addEditChannelPage.${formAction}.breadcrumb`)} - - - - - {selectedParty && ( - - )} - - - ); + return ( + + + + } + sx={{ color: 'primary.main', mr: '20px' }} + weight="default" + > + {t('general.exit')} + + + {t('general.Channels')} + {formAction === FormAction.Edit && ( + {channelId} + )} + + {userIsPagopaOperator + ? channelDetail?.wrapperStatus !== WrapperStatusEnum.APPROVED + ? t('addEditChannelPage.config.titleValidate') + : t(`addEditChannelPage.config.titleConfiguration`) + : t(`addEditChannelPage.${formAction}.breadcrumb`)} + + + + + {selectedParty && ( + + )} + + + ); }; export default AddEditChannelPage; diff --git a/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx b/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx index dfeb2e4ed..5c35225bc 100644 --- a/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx +++ b/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx @@ -13,8 +13,9 @@ import {pspAdminSignedDirect, pspOperatorSignedDirect,} from '../../../../servic import {BackofficeApi} from '../../../../api/BackofficeClient'; import {Party} from '../../../../model/Party'; import {isValidURL} from '../../../components/commonFunctions'; -import {ChannelDetailsResource} from '../../../../api/generated/portal/ChannelDetailsResource'; +import {ChannelDetailsResource, WrapperStatusEnum} from '../../../../api/generated/portal/ChannelDetailsResource'; import {ROLE} from "../../../../model/RolePermission"; + import * as useUserRole from "../../../../hooks/useUserRole" // import { wait } from '@testing-library/user-event/dist/types/utils'; @@ -38,8 +39,25 @@ const channelDetail: ChannelDetailsResource = { target_path: '/govpay/api/pagopa/PagamentiTelematiciCCPservice', target_port: 443, target_host: 'www.lab.link.it', + proxy_enabled: false, + proxy_host: 'string', + proxy_password: 'string', + proxy_port: 0, + proxy_username: 'string', + ip: 'ip', + service: 'service', payment_types: ['PPAY'], }; +const channelDetailApproved: ChannelDetailsResource = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `${pspOperatorSignedDirect.fiscalCode}_01`, + target_path: '/govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 443, + target_host: 'www.lab.link.it', + payment_types: ['PPAY'], + wrapperStatus: WrapperStatusEnum.APPROVED +}; describe('', (injectedHistory?: ReturnType) => { const history = injectedHistory ? injectedHistory : createMemoryHistory(); @@ -401,4 +419,94 @@ describe('', (injectedHistory?: ReturnType ); }); + + test('Test of AddEditChannelValidationForm case chackbox select-new-connection-test flag true on config', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: true, + }); + (isValidURL as jest.Mock).mockReturnValue(true); + + const {getByTestId, getByText} = render( + + + + + + + + ); + + const primitiveVersion = getByTestId('primitive-version-test') as HTMLInputElement; + const password = getByTestId('password-test') as HTMLInputElement; + const proxyUnion = getByTestId('proxy-union-test') as HTMLInputElement; + const timeoutA = getByTestId('timeout-a-test') as HTMLInputElement; + const timeoutB = getByTestId('timeout-b-test') as HTMLInputElement; + const timeoutC = getByTestId('timeout-c-test') as HTMLInputElement; + const continueBtn = getByText('addEditChannelPage.addForm.continueButton'); + const backButton = getByTestId('back-btn-test') as HTMLButtonElement; + const selectNewConnection = screen.getByTestId('select-new-connection-test'); + const newConnection = getByTestId('new-connection-channel') as HTMLInputElement; + + fireEvent.click(selectNewConnection); + + fireEvent.change(newConnection, { + target: {value: 'https://api.uat.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward'}, + }); + + fireEvent.click(selectNewConnection); + + expect(newConnection.value).toBe(''); + + fireEvent.change(primitiveVersion, {target: {value: undefined}}); + fireEvent.change(primitiveVersion, {target: {value: 1}}); + + fireEvent.change(password, {target: {value: 1}}); + + fireEvent.change(proxyUnion, { + target: {value: 'https://10.101.1.95:8080'}, + }); + + fireEvent.change(timeoutA, {target: {value: 10}}); + + fireEvent.change(timeoutB, {target: {value: 20}}); + + fireEvent.change(timeoutC, {target: {value: 30}}); + + fireEvent.click(continueBtn); + + const confirmBtn = screen.queryByText( + (_content, element) => + element?.tagName.toLowerCase() === 'button' && + element.textContent === 'addEditChannelPage.confirmModal.confirmButtonOpe' + ) as HTMLButtonElement; + + const cancelBtn = screen.queryByText( + (_content, element) => + element?.tagName.toLowerCase() === 'button' && + element.textContent === 'addEditChannelPage.confirmModal.cancelButton' + ) as HTMLButtonElement; + + if (cancelBtn) { + fireEvent.click(cancelBtn); + } + + fireEvent.click(continueBtn); + + if (confirmBtn) { + fireEvent.click(confirmBtn); + } + + fireEvent.click(backButton); + }); + }); diff --git a/src/pages/channels/addEditChannel/__tests__/AddEditChannelPage.test.tsx b/src/pages/channels/addEditChannel/__tests__/AddEditChannelPage.test.tsx index f51f6b803..a4616fe9c 100644 --- a/src/pages/channels/addEditChannel/__tests__/AddEditChannelPage.test.tsx +++ b/src/pages/channels/addEditChannel/__tests__/AddEditChannelPage.test.tsx @@ -8,9 +8,11 @@ import AddEditChannelPage from '../AddEditChannelPage'; import {createMemoryHistory} from 'history'; import {Provider} from 'react-redux'; import ROUTES from '../../../../routes'; +import * as useUserRole from '../../../../hooks/useUserRole'; +import {ROLE} from '../../../../model/RolePermission'; import {FormAction} from '../../../../model/Channel'; import {mockedIban} from '../../../../services/__mocks__/ibanService'; -import {mockedChannel} from '../../../../services/__mocks__/channelService'; +import {mockedChannel, mockedChannelDetail} from '../../../../services/__mocks__/channelService'; let getChannelDetailMocked: jest.SpyInstance; let getChannelCodeMocked: jest.SpyInstance; @@ -36,6 +38,42 @@ describe('', () => { const history = createMemoryHistory(); test('render component AddEditChannelPage formAction Edit', () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: true, + userIsEcAdmin: false, + userIsPspDirectAdmin: true, + userIsPagopaOperator: false, + userIsAdmin: false + }); + getChannelDetailMocked.mockReturnValueOnce(Promise.resolve(mockedChannelDetail(mockedChannel.channel_code!))); + + render( + + + + + + + + + + ); + + expect(getChannelDetailMocked).toBeCalled(); + }); + + test('render component AddEditChannelPage formAction Edit Operator', () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: false + }); + getChannelDetailMocked.mockReturnValueOnce(Promise.resolve(mockedChannelDetail(mockedChannel.channel_code!))); + render( @@ -52,6 +90,14 @@ describe('', () => { }); test('render component AddEditChannelPage formAction Edit with fetch error', () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: true, + userIsEcAdmin: false, + userIsPspDirectAdmin: true, + userIsPagopaOperator: false, + userIsAdmin: false + }); const mockError = new Error('Fetch error'); getChannelDetailMocked.mockRejectedValueOnce(mockError); @@ -71,6 +117,14 @@ describe('', () => { }); test('render component AddEditChannelPage formAction Createwith fetch error', () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: true, + userIsEcAdmin: false, + userIsPspDirectAdmin: true, + userIsPagopaOperator: false, + userIsAdmin: false + }); const mockError = new Error('Fetch error'); getChannelCodeMocked.mockRejectedValueOnce(mockError); @@ -88,4 +142,5 @@ describe('', () => { expect(getChannelCodeMocked).toBeCalled(); }); + }); diff --git a/src/pages/channels/detail/ChannelDetailPage.tsx b/src/pages/channels/detail/ChannelDetailPage.tsx index 88af5cbeb..4a8a85c1c 100644 --- a/src/pages/channels/detail/ChannelDetailPage.tsx +++ b/src/pages/channels/detail/ChannelDetailPage.tsx @@ -1,67 +1,55 @@ /* eslint-disable complexity */ -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useHistory, useParams} from 'react-router'; -import ROUTES from '../../../routes'; -import {getChannelDetail, getChannelPSPs} from '../../../services/channelService'; -import {LOADING_TASK_CHANNEL_DETAIL} from '../../../utils/constants'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; -import {ChannelDetailsResource} from '../../../api/generated/portal/ChannelDetailsResource'; -import {useUserRole} from "../../../hooks/useUserRole"; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router'; +import { getChannelDetail, getChannelPSPs } from '../../../services/channelService'; +import { LOADING_TASK_CHANNEL_DETAIL } from '../../../utils/constants'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; +import { ChannelDetailsResource } from '../../../api/generated/portal/ChannelDetailsResource'; import ChannelDetails from './components/ChannelDetails'; -import ChannelDetailsWrap from './components/ChannelDetailsWrap'; const ChannelDetailPage = () => { - const {t} = useTranslation(); - const history = useHistory(); - const setLoading = useLoading(LOADING_TASK_CHANNEL_DETAIL); - const [channelDetail, setChannelDetail] = useState({} as any); - const [PSPAssociatedNumber, setPSPAssociatedNumber] = useState(0); - const addError = useErrorDispatcher(); - const {channelId} = useParams<{ channelId: string }>(); - const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const {userIsPagopaOperator} = useUserRole(); - const goBack = () => history.push(ROUTES.CHANNELS); + const { t } = useTranslation(); - useEffect(() => { - setLoading(true); - Promise.all([getChannelDetail(channelId), getChannelPSPs(channelId, "", 0)]) - .then(([channelDetailResponse, channelPSPList]) => { - setChannelDetail(channelDetailResponse); - setPSPAssociatedNumber(channelPSPList?.page_info?.total_items ?? 0); - }) - .catch((reason) => { - addError({ - id: 'GET_CHANNEL_DETAILS', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while getting channel details`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('addEditChannelPage.addForm.errorMessageChannelDetailsDesc'), - component: 'Toast', - }); - }) - .finally(() => setLoading(false)); - }, [selectedParty]); + const setLoading = useLoading(LOADING_TASK_CHANNEL_DETAIL); + const [channelDetail, setChannelDetail] = useState({} as any); + const [PSPAssociatedNumber, setPSPAssociatedNumber] = useState(0); + const addError = useErrorDispatcher(); + const { channelId } = useParams<{ channelId: string }>(); + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - return userIsPagopaOperator ? ( - - ) : ( - - ); + useEffect(() => { + setLoading(true); + Promise.all([getChannelDetail(channelId), getChannelPSPs(channelId, '', 0)]) + .then(([channelDetailResponse, channelPSPList]) => { + setChannelDetail(channelDetailResponse); + setPSPAssociatedNumber(channelPSPList?.page_info?.total_items ?? 0); + }) + .catch((reason) => { + addError({ + id: 'GET_CHANNEL_DETAILS', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while getting channel details`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('addEditChannelPage.addForm.errorMessageChannelDetailsDesc'), + component: 'Toast', + }); + }) + .finally(() => setLoading(false)); + }, [selectedParty]); + + return ( + + ); }; export default ChannelDetailPage; diff --git a/src/pages/channels/detail/__tests__/ChannelDetails.test.tsx b/src/pages/channels/detail/__tests__/ChannelDetails.test.tsx index 4f269391c..3aa062eee 100644 --- a/src/pages/channels/detail/__tests__/ChannelDetails.test.tsx +++ b/src/pages/channels/detail/__tests__/ChannelDetails.test.tsx @@ -1,98 +1,164 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, screen, render, fireEvent} from '@testing-library/react'; +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { cleanup, screen, render, fireEvent } from '@testing-library/react'; import React from 'react'; -import {MemoryRouter, Route} from 'react-router-dom'; -import {store} from '../../../../redux/store'; -import {Provider} from 'react-redux'; +import { MemoryRouter, Route } from 'react-router-dom'; +import { store } from '../../../../redux/store'; +import { Provider } from 'react-redux'; import ChannelDetails from '../components/ChannelDetails'; -import {StatusEnum} from '../../../../api/generated/portal/ChannelDetailsDto'; -import {mockedPaymentTypes} from '../../../../services/__mocks__/configurationService'; +import { StatusEnum } from '../../../../api/generated/portal/ChannelDetailsDto'; +import { mockedPaymentTypes } from '../../../../services/__mocks__/configurationService'; +import * as useUserRole from '../../../../hooks/useUserRole'; +import { ROLE } from '../../../../model/RolePermission'; beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); - jest.resetModules(); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); + jest.resetModules(); }); afterEach(cleanup); const passwordFieldValue = 'randomValue'; describe('', () => { - const channelId = 'XPAY_03_ONUS'; - const channelDetail = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `${channelId}`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), - status: StatusEnum.TO_CHECK, - password: passwordFieldValue, - }; - test('render component ChannelDetails with channelDetail', async () => { - render( - - - - - - - - - - ); + const channelId = 'XPAY_03_ONUS'; + const channelDetail = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `${channelId}`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + proxy_host: ' proxy.link.it', + payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), + status: StatusEnum.TO_CHECK, + password: passwordFieldValue, + }; + const channelDetailToFix = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `${channelId}`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + proxy_host: ' proxy.link.it', + payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), + status: StatusEnum.TO_FIX, + password: passwordFieldValue, + note: 'note', + }; + test('render component ChannelDetails with channelDetail', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: true, + }); + render( + + + + + + + + + + ); + + const passwordField = screen.getByTestId('password-value-test') as HTMLElement; + expect(passwordField.innerHTML).toBe('XXXXXXXXXXXXXX'); - const passwordField = screen.getByTestId('password-value-test') as HTMLElement; - expect(passwordField.innerHTML).toBe('XXXXXXXXXXXXXX'); + const showPasswordButton = screen.getByTestId('show-psw-test') as HTMLElement; - const showPasswordButton = screen.getByTestId('show-psw-test') as HTMLElement; + fireEvent.click(showPasswordButton); - fireEvent.click(showPasswordButton); + expect(passwordField.innerHTML).toBe(passwordFieldValue); + }); - expect(passwordField.innerHTML).toBe(passwordFieldValue); + test('render component ChannelDetails with channelDetail TO_FIX', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: true, }); + render( + + + + + + + + + + ); - test('render component ChannelDetails with empty channelDetail', async () => { - render( - - - - - - - - - - ); + const passwordField = screen.getByTestId('password-value-test') as HTMLElement; + expect(passwordField.innerHTML).toBe('XXXXXXXXXXXXXX'); - let noPassword = false; - try { - screen.getByTestId('password-value-test'); - } catch (_) { - noPassword = true; - } - expect(noPassword).toBeTruthy(); + const showPasswordButton = screen.getByTestId('show-psw-test') as HTMLElement; + + fireEvent.click(showPasswordButton); + + expect(passwordField.innerHTML).toBe(passwordFieldValue); + }); + + test('render component ChannelDetails with empty channelDetail', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.EC_DIRECT_ADMIN, + userIsPspAdmin: false, + userIsEcAdmin: true, + userIsPspDirectAdmin: false, + userIsPagopaOperator: false, + userIsAdmin: true, }); + render( + + + + + + + + + + ); + + let noPassword = false; + try { + screen.getByTestId('password-value-test'); + } catch (_) { + noPassword = true; + } + expect(noPassword).toBeTruthy(); + }); }); diff --git a/src/pages/channels/detail/__tests__/ChannelDetailsWrap.test.tsx b/src/pages/channels/detail/__tests__/ChannelDetailsWrap.test.tsx deleted file mode 100644 index dc4dae8df..000000000 --- a/src/pages/channels/detail/__tests__/ChannelDetailsWrap.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import {render} from '@testing-library/react'; -import {MemoryRouter, Route, Router} from 'react-router-dom'; -import {Provider} from 'react-redux'; -import ChannelDetailsWrap from '../components/ChannelDetailsWrap'; -import {mockedPaymentTypes} from '../../../../services/__mocks__/configurationService'; -import {StatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsDto'; -import {store} from '../../../../redux/store'; -import {theme} from '@pagopa/mui-italia'; -import {ThemeProvider} from '@mui/system'; - -describe('', () => { - test('render component ChannelDetailsWrap', async () => { - const channelId = 'XPAY_03_ONUS'; - const channelDetailWrapper = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `${channelId}`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), - status: StatusEnum.TO_CHECK, - }; - render( - - - - - - - - - - ); - }); -}); diff --git a/src/pages/channels/detail/__tests__/DetailButton.test.tsx b/src/pages/channels/detail/__tests__/DetailButton.test.tsx index a81fcf286..0c34ec7ba 100644 --- a/src/pages/channels/detail/__tests__/DetailButton.test.tsx +++ b/src/pages/channels/detail/__tests__/DetailButton.test.tsx @@ -1,10 +1,13 @@ import React from 'react'; -import {render} from '@testing-library/react'; +import { fireEvent, render, screen, waitFor} from '@testing-library/react'; import {MemoryRouter, Route, Router} from 'react-router-dom'; import {Provider} from 'react-redux'; import {mockedPaymentTypes} from '../../../../services/__mocks__/configurationService'; import {StatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsDto'; +import {WrapperStatusEnum,} from '../../../../api/generated/portal/ChannelDetailsResource'; +import {ROLE} from '../../../../model/RolePermission'; import {store} from '../../../../redux/store'; +import * as useUserRole from '../../../../hooks/useUserRole'; import {theme} from '@pagopa/mui-italia'; import {ThemeProvider} from '@mui/system'; import DetailButtons from '../components/DetailButtons'; @@ -34,4 +37,60 @@ describe('', () => { ); }); + + test('render component DetailButtons should contain modal', async () => { + + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: true, + }); + + const channelId = 'XPAY_03_ONUS'; + const channelDetailWrapper = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `${channelId}`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), + status: StatusEnum.TO_CHECK, + wrapperStatus: WrapperStatusEnum.TO_CHECK + }; + render( + + + + + + + + + + ); + + expect(screen.queryByTestId('request-edit-button')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('request-edit-button')); + + await waitFor(() => { + expect(screen.queryByTestId('confirm-and-send-button')).toBeInTheDocument(); + }); + const confirmButton = screen.getByTestId('confirm-and-send-button'); + + expect(confirmButton).toBeDisabled(); + + fireEvent.change(screen.getByTestId('requestInput'), {target: {value: 'note'}}); + + await waitFor(() => { + expect(confirmButton).toBeEnabled(); + }); + + fireEvent.click(confirmButton); + + }); }); diff --git a/src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx b/src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx new file mode 100644 index 000000000..40bc19545 --- /dev/null +++ b/src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx @@ -0,0 +1,109 @@ +import {ThemeProvider} from '@mui/system'; +import {theme} from '@pagopa/mui-italia'; +import {cleanup, render} from '@testing-library/react'; +import React from 'react'; +import {MemoryRouter, Route} from 'react-router-dom'; +import {store} from '../../../../redux/store'; +import * as useUserRole from '../../../../hooks/useUserRole'; +import {ROLE} from '../../../../model/RolePermission'; +import GetChannelAlert from '../components/GetChannelAlert'; +import {StatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsDto'; +import {WrapperStatusEnum,} from '../../../../api/generated/portal/ChannelDetailsResource'; +import {Provider} from 'react-redux'; + +beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(() => { + }); + jest.spyOn(console, 'warn').mockImplementation(() => { + }); + jest.resetModules(); +}); +afterEach(cleanup); + +describe('', () => { + const channelId = 'XPAY_03_ONUS'; + test('render component ChannelDetailPage on APPROVED', async () => { + const channelDetail = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `$test`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + status: StatusEnum.APPROVED, + wrapperStatus: WrapperStatusEnum.APPROVED + }; + render( + + + + + + + + + + ); + }); + + test('render component ChannelDetailPage on TO_FIX', async () => { + const channelDetail = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `$test`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + status: StatusEnum.TO_FIX, + wrapperStatus: WrapperStatusEnum.TO_FIX + }; + render( + + + + + + + + + + ); + }); + + test('render component ChannelDetailPage on TO_CHECK', async () => { + + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: true, + }); + + const channelDetail = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `$test`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + status: StatusEnum.TO_CHECK, + wrapperStatus: WrapperStatusEnum.TO_CHECK + }; + render( + + + + + + + + + + ); + }); + +}); + + diff --git a/src/pages/channels/detail/components/ChannelDetails.tsx b/src/pages/channels/detail/components/ChannelDetails.tsx index defb2ae31..32c8260ac 100644 --- a/src/pages/channels/detail/components/ChannelDetails.tsx +++ b/src/pages/channels/detail/components/ChannelDetails.tsx @@ -1,397 +1,377 @@ /* eslint-disable complexity */ -import {ManageAccounts, VisibilityOff} from '@mui/icons-material'; -import {Alert, Chip, Divider, Grid, IconButton, Paper, Typography} from '@mui/material'; -import {Box} from '@mui/system'; -import {ButtonNaked} from '@pagopa/mui-italia'; -import {TitleBox} from '@pagopa/selfcare-common-frontend'; -import {generatePath, Link} from 'react-router-dom'; -import {useTranslation} from 'react-i18next'; -import {useState} from 'react'; +import { ArrowBack, VisibilityOff } from '@mui/icons-material'; +import { Breadcrumbs, Chip, Divider, Grid, IconButton, Paper, Typography } from '@mui/material'; +import { Box, Stack } from '@mui/system'; +import { useHistory } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { useState } from 'react'; import VisibilityIcon from '@mui/icons-material/Visibility'; +import { ButtonNaked } from '@pagopa/mui-italia'; +import { StatusChip } from '../../../../components/StatusChip'; import ROUTES from '../../../../routes'; -import {ChannelDetailsResource} from '../../../../api/generated/portal/ChannelDetailsResource'; -import {ProtocolEnum, WrapperStatusEnum,} from '../../../../api/generated/portal/WrapperChannelDetailsResource'; -import {StatusChip} from '../../../../components/StatusChip'; -import {ENV} from '../../../../utils/env'; -import {useUserRole} from "../../../../hooks/useUserRole"; +import { + ChannelDetailsResource, + WrapperStatusEnum, +} from '../../../../api/generated/portal/ChannelDetailsResource'; +import { ProtocolEnum } from '../../../../api/generated/portal/WrapperChannelDetailsResource'; +import { ENV } from '../../../../utils/env'; +import { useUserRole } from '../../../../hooks/useUserRole'; import DetailButtons from './DetailButtons'; +import GetChannelAlert from './GetChannelAlert'; type Props = { - channelDetail: ChannelDetailsResource; - channelId: string; - goBack: () => void; - PSPAssociatedNumber: number; + channelDetail: ChannelDetailsResource; + setChannelDetail: (value: any) => void; + channelId: string; + PSPAssociatedNumber: number; }; -// eslint-disable-next-line sonarjs/cognitive-complexity -const ChannelDetails = ({channelDetail, channelId, goBack, PSPAssociatedNumber}: Props) => { - const {t} = useTranslation(); - const {userIsPagopaOperator} = useUserRole(); - const targetPath = (!channelDetail.target_path?.startsWith("/") ? "/" : "").concat(channelDetail.target_path !== undefined ? channelDetail.target_path : ""); - const targetValue = `${channelDetail.target_host}:${channelDetail.target_port}${targetPath}`; +const ChannelDetails = ({ + channelDetail, + setChannelDetail, + channelId, + PSPAssociatedNumber, + // eslint-disable-next-line sonarjs/cognitive-complexity +}: Props) => { + const history = useHistory(); + const goBack = () => history.push(ROUTES.CHANNELS); + const { t } = useTranslation(); + const { userIsPagopaOperator } = useUserRole(); + const targetPath = (!channelDetail.target_path?.startsWith('/') ? '/' : '').concat( + channelDetail.target_path !== undefined ? channelDetail.target_path : '' + ); + const targetValue = `${channelDetail.target_host}:${channelDetail.target_port}${targetPath}`; - const [showPassword, setShowPassword] = useState(false); - const hidePassword = 'XXXXXXXXXXXXXX'; - const showOrHidePassword = (password?: string) => { - if (showPassword) { - return password; - } - return hidePassword; - }; + const [showPassword, setShowPassword] = useState(false); + const hidePassword = 'XXXXXXXXXXXXXX'; + const showOrHidePassword = (password?: string) => { + if (showPassword) { + return password; + } + return hidePassword; + }; - const forwarder01 = - ENV.ENV === 'prod' - ? 'https://api.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward' - : 'https://api.uat.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward'; + const forwarder01 = + ENV.ENV === 'prod' + ? 'https://api.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward' + : 'https://api.uat.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward'; - const newConnectionValue = `${ - channelDetail.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://' - }${channelDetail.ip}${channelDetail.service}`; + const newConnectionValue = `${ + channelDetail.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://' + }${channelDetail.ip}${channelDetail.service}`; - return ( - - - - - - - {t('channelDetailPage.createdOn')}{' '} - - {`${channelDetail.createdAt?.toLocaleDateString('en-GB')} da ${ - channelDetail.createdBy - }`} - - - - - - - {userIsPagopaOperator && - (channelDetail.wrapperStatus === WrapperStatusEnum.TO_CHECK || - channelDetail.wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE) ? ( - - - {t('channelDetailPage.alertWarning')} - - - ) : null} - + return ( + + + } + sx={{ color: 'primary.main', mr: '20px' }} + weight="default" + data-testid="back-button-test" + > + {t('general.back')} + + + + {channelId} + + + + + {t( + `channelDetailPage.subtitle.${channelDetail?.wrapperStatus === WrapperStatusEnum.APPROVED ? 'approved' : 'waiting'}` + )} + - - - - {t('channelDetailPage.state')} - - - - - - - {t('channelDetailPage.channelConfiguration')} - - {t('channelDetailPage.institutionInfo')} - + - - - - - {t('channelDetailPage.registry')} - - - {t('channelDetailPage.pspBrokerCode')} - - - - {channelDetail.broker_psp_code} - - - - {t('channelDetailPage.companyName')} - - - - {channelDetail.broker_description} - - - - {t('channelDetailPage.idChannel')} - - - - {channelDetail.channel_code} - - - - {t('channelDetailPage.target')} - - - {t('channelDetailPage.endPoint')} - - - - {targetValue} - - - - {t('channelDetailPage.paymentType')} - - - {channelDetail.payment_types && channelDetail.payment_types.length > 0 - ? channelDetail.payment_types.map((e, i) => ( - // eslint-disable-next-line react/jsx-key - - - - )) - : ''} - - - {t('channelDetailPage.associatedPsp')} - - - } - size="medium" - > - {t('channelDetailPage.changeHistory')} - - - - {t('channelDetailPage.associated')} - - - - {PSPAssociatedNumber} - - - {/* TODO: get from channelDetail when will be available */} - - {t('channelDetailPage.changes')} - - - {t('channelDetailPage.lastChange')} - - - - {channelDetail.modifiedAt?.toLocaleDateString('en-GB') ?? '-'} - - - - {t('channelDetailPage.operatedBy')} - - - - {channelDetail.modifiedBy ?? '-'} - - - - - - + + + + + {t('channelDetailPage.channelConfiguration')} + + + + {t('channelDetailPage.registry')} + + + {t('channelDetailPage.pspBrokerCode')} + + + + {channelDetail.broker_psp_code} + + + + {t('channelDetailPage.companyName')} + + + + {channelDetail.broker_description} + + + + {t('channelDetailPage.idChannel')} + + + + {channelDetail.channel_code} + + + + {t('channelDetailPage.target')} + + + {t('channelDetailPage.endPoint')} + + + + {targetValue} + + + + {t('channelDetailPage.paymentType')} + + {channelDetail.payment_types && channelDetail.payment_types.length > 0 + ? channelDetail.payment_types.map((e, i) => ( + + + + )) + : ''} - - - - - {t('channelDetailValidationPage.title')} - - - - - {t('channelDetailValidationPage.subtitle')} - - - - + <> + {!userIsPagopaOperator && ( + <> + + + {t('channelDetailPage.associatedPsp')} + + + + {t('channelDetailPage.associated')} + + + + {PSPAssociatedNumber} + + + + )} + + + - - - - - - {t('channelDetailValidationPage.registry')} - - - - - {t('channelDetailValidationPage.primitiveVersion')} - - - - - {channelDetail?.primitive_version ?? '-'} - - - - - {t('channelDetailValidationPage.password')} - - - - {channelDetail?.password ? ( - <> - - {showOrHidePassword(channelDetail?.password)} - - { - setShowPassword(!showPassword); - }} - data-testid="show-psw-test" - > - {showPassword ? ( - - ) : ( - - )} - - - ) : ( - '-' - )} - - - - {t('channelDetailValidationPage.connection')} - - - - - {t('channelDetailValidationPage.newConnection')} - - - - - {forwarder01 === newConnectionValue - ? t('channelDetailValidationPage.forwarder01') - : targetValue} - - - - - {t('channelDetailValidationPage.proxy')} - - - - - {t('channelDetailValidationPage.proxyAddress')} - - - - - {channelDetail?.proxy_host && channelDetail?.proxy_port - ? `${channelDetail?.proxy_host}:${channelDetail?.proxy_port}` - : '-'} - - - - - {t('channelDetailValidationPage.otherInfo')} - - - - - {t('channelDetailValidationPage.timeoutA')} - - - - - {channelDetail?.timeout_a ?? '-'} - - - - - {t('channelDetailValidationPage.timeoutB')} - - - - - {channelDetail?.timeout_b ?? '-'} - - - - - {t('channelDetailValidationPage.timeoutC')} - - - - - {channelDetail?.timeout_c ?? '-'} - - - - - {t('channelDetailValidationPage.pspNotify')} - - - - - {channelDetail?.flag_io - ? t('channelDetailValidationPage.enabled') - : t('channelDetailValidationPage.disabled')} - - - - {t('channelDetailValidationPage.stamp')} - - - - {channelDetail?.digital_stamp_brand - ? t('channelDetailValidationPage.enabled') - : t('channelDetailValidationPage.disabled')} - - - - - - + {userIsPagopaOperator && channelDetail?.proxy_host && ( + + + + {t('channelDetailValidationPage.title')} + + + + {t('channelDetailValidationPage.subtitle')} + + + + + {t('channelDetailValidationPage.registry')} + + + + + {t('channelDetailValidationPage.primitiveVersion')} + + + + + {channelDetail?.primitive_version ?? '-'} + + + + {t('channelDetailValidationPage.password')} + + + {channelDetail?.password ? ( + <> + + {showOrHidePassword(channelDetail?.password)} + + { + setShowPassword(!showPassword); + }} + data-testid="show-psw-test" + > + {showPassword ? ( + + ) : ( + + )} + + + ) : ( + '-' + )} + + + + {t('channelDetailValidationPage.connection')} + + + + + {t('channelDetailValidationPage.newConnection')} + + + + + {forwarder01 === newConnectionValue + ? t('channelDetailValidationPage.forwarder01') + : targetValue} + + + + {t('channelDetailValidationPage.proxy')} + + + + {t('channelDetailValidationPage.proxyAddress')} + + + + + {channelDetail?.proxy_host && channelDetail?.proxy_port + ? `${channelDetail?.proxy_host}:${channelDetail?.proxy_port}` + : '-'} + + + + + {t('channelDetailValidationPage.otherInfo')} + + + + {t('channelDetailValidationPage.timeoutA')} + + + + {channelDetail?.timeout_a ?? '-'} + + + + {t('channelDetailValidationPage.timeoutB')} + + + + {channelDetail?.timeout_b ?? '-'} + + + + {t('channelDetailValidationPage.timeoutC')} + + + + {channelDetail?.timeout_c ?? '-'} + + + + + {t('channelDetailValidationPage.pspNotify')} + + + + + {channelDetail?.flag_io + ? t('channelDetailValidationPage.enabled') + : t('channelDetailValidationPage.disabled')} + + + + {t('channelDetailValidationPage.stamp')} + + + + {channelDetail?.digital_stamp_brand + ? t('channelDetailValidationPage.enabled') + : t('channelDetailValidationPage.disabled')} + + - - ); + + )} + + {t('channelDetailPage.createdOn')}{' '} + + {`${channelDetail?.createdAt?.toLocaleDateString('en-GB') ?? '-'}`} + {' '} + {t('general.fromLower')}{' '} + + {channelDetail?.createdBy} + + {'.'} + {channelDetail?.modifiedBy && ( +
+ {t('channelDetailPage.lastModified')}{' '} + + {channelDetail?.modifiedBy} + + {channelDetail?.modifiedAt && ( + <> + {' '} + {t('general.atLower')}{' '} + + {`${channelDetail?.modifiedAt?.toLocaleDateString('en-GB')}`} + + + )} + {'.'} +
+ )} +
+ +
+
+ ); }; export default ChannelDetails; diff --git a/src/pages/channels/detail/components/ChannelDetailsWrap.tsx b/src/pages/channels/detail/components/ChannelDetailsWrap.tsx deleted file mode 100644 index de93739aa..000000000 --- a/src/pages/channels/detail/components/ChannelDetailsWrap.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import {ArrowBack, ManageAccounts} from '@mui/icons-material'; -import {Grid, Stack, Breadcrumbs, Typography, Paper, Chip, Divider} from '@mui/material'; -import {Box} from '@mui/system'; -import {ButtonNaked} from '@pagopa/mui-italia'; -import {TitleBox} from '@pagopa/selfcare-common-frontend'; -import {Link, generatePath} from 'react-router-dom'; -import {useTranslation} from 'react-i18next'; -import {useState} from 'react'; -import ROUTES from '../../../../routes'; -import {ChannelDetailsResource} from '../../../../api/generated/portal/ChannelDetailsResource'; -import {WrapperStatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsResource'; -import {StatusChip} from '../../../../components/StatusChip'; -import DetailButtons from './DetailButtons'; - -type Props = { - channelDetWrap?: ChannelDetailsResource; - channelId: string; - goBack: () => void; - PSPAssociatedNumber: number; -}; - -// eslint-disable-next-line sonarjs/cognitive-complexity -const ChannelDetailsWrap = ({channelDetWrap, channelId, goBack, PSPAssociatedNumber}: Props) => { - const {t} = useTranslation(); - - return channelDetWrap ? ( - - - - } - sx={{color: 'primary.main', mr: '20px'}} - weight="default" - > - {t('general.exit')} - - - {t('general.Channels')} - - {t('channelDetailPage.detail')} {channelId} - - - - - - - - {t('channelDetailPage.createdOn')}{' '} - - {channelDetWrap.createdAt?.toLocaleDateString('en-GB') ?? '-'} - - - - - - - - - - - - {t('channelDetailPage.state')} - - - - - - - {t('channelDetailPage.channelConfiguration')} - - - - - - - - {t('channelDetailPage.registry')} - - - {t('channelDetailPage.pspBrokerCode')} - - - - {channelDetWrap.broker_psp_code} - - - - {t('channelDetailPage.companyName')} - - - - {channelDetWrap.broker_description} - - - - {t('channelDetailPage.idChannel')} - - - - {channelDetWrap.channel_code} - - - - {t('channelDetailPage.target')} - - - {t('channelDetailPage.endPoint')} - - - - {`${channelDetWrap.target_host}:${channelDetWrap.target_port}${(!channelDetWrap.target_path?.startsWith("/") ? "/" : "")}${channelDetWrap.target_path}`} - - - - - {t('channelDetailPage.paymentType')} - - - {channelDetWrap.payment_types && channelDetWrap.payment_types.length > 0 - ? // eslint-disable-next-line sonarjs/no-identical-functions - channelDetWrap.payment_types.map((e, i) => ( - // eslint-disable-next-line react/jsx-key - - - - )) - : ''} - - - {t('channelDetailPage.associatedPsp')} - - - } - size="medium" - > - {t('channelDetailPage.managePsp')} - - - - {t('channelDetailPage.associated')} - - - - {PSPAssociatedNumber} - - - - {t('channelDetailPage.changes')} - - - {t('channelDetailPage.lastChange')} - - - - {channelDetWrap.modifiedAt?.toLocaleDateString('en-GB') ?? '-'} - - - - {t('channelDetailPage.operatedBy')} - - - - {channelDetWrap.modifiedBy} - - - - - - - - - ) : ( - <> - ); -}; - -export default ChannelDetailsWrap; diff --git a/src/pages/channels/detail/components/DetailButtons.tsx b/src/pages/channels/detail/components/DetailButtons.tsx index efc242bd7..b45b0657b 100644 --- a/src/pages/channels/detail/components/DetailButtons.tsx +++ b/src/pages/channels/detail/components/DetailButtons.tsx @@ -1,121 +1,238 @@ -import {Button, Stack} from '@mui/material'; -import {generatePath, Link, useParams} from 'react-router-dom'; -import {useTranslation} from 'react-i18next'; -import {FormAction} from '../../../../model/Channel'; +import { useErrorDispatcher, useLoading, useUserNotify } from '@pagopa/selfcare-common-frontend'; +import { Button, Stack, Typography, TextField } from '@mui/material'; +import { Box } from '@mui/system'; +import { ContentCopy, Delete, Edit, ManageAccounts } from '@mui/icons-material'; +import { generatePath, Link, useParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { useState } from 'react'; +import { FormAction } from '../../../../model/Channel'; import ROUTES from '../../../../routes'; -import {ChannelDetailsResource, WrapperStatusEnum,} from '../../../../api/generated/portal/ChannelDetailsResource'; -import {useUserRole} from "../../../../hooks/useUserRole"; +import { + ChannelDetailsResource, + WrapperStatusEnum, +} from '../../../../api/generated/portal/ChannelDetailsResource'; +import { useUserRole } from '../../../../hooks/useUserRole'; +import { LOADING_TASK_CHANNEL_DETAIL } from '../../../../utils/constants'; +import { updateWrapperChannelWithOperatorReview } from '../../../../services/channelService'; +import GenericModal from '../../../../components/Form/GenericModal'; -type Props = { - channelDetails?: ChannelDetailsResource; - goBack: () => void; +const ModalContent = ({ + setShowModal, + channelDetails, + setChannelDetails, +}: { + setShowModal: (value: boolean) => void; +} & Props) => { + const { t } = useTranslation(); + + const addError = useErrorDispatcher(); + const setLoading = useLoading(LOADING_TASK_CHANNEL_DETAIL); + const addNotify = useUserNotify(); + + const [input, setInput] = useState(channelDetails?.note ?? ''); + + const sendEditRequest = () => { + setLoading(true); + updateWrapperChannelWithOperatorReview({ + channelCode: channelDetails?.channel_code ?? '', + brokerPspCode: channelDetails?.broker_psp_code ?? '', + note: input, + }) + .then((data: ChannelDetailsResource) => { + setChannelDetails(data); + addNotify({ + id: 'ADDEDIT_INSTITUTION_DATA_SAVE', + title: '', + message: t('channelDetailValidationPage.modal.successMessage'), + component: 'Toast', + }); + }) + .catch((reason) => + addError({ + id: 'PUT_CHANNEL_DETAILS_REQUEST_EDIT', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while getting updating the channel with operator's note`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('channelDetailValidationPage.modal.error'), + component: 'Toast', + }) + ) + .finally(() => { + setShowModal(false); + setLoading(false); + }); + }; + return ( + <> + {t('channelDetailValidationPage.modal.title')} + + {t('channelDetailValidationPage.modal.subtitle')} + + setInput(e.target.value)} + helperText={t('channelDetailValidationPage.modal.helperText')} + inputProps={{ + 'data-testid': 'requestInput', + maxLength: 200, + }} + /> + + + + + + ); }; -const DetailButtons = ({channelDetails, goBack}: Props) => { - const {channelId} = useParams<{ channelId: string }>(); - const {userIsPagopaOperator} = useUserRole(); - const {t} = useTranslation(); +function Buttons({ + channelDetails, + setShowModal, +}: { + channelDetails?: ChannelDetailsResource; + setShowModal: (value: boolean) => void; +}) { + const { userIsPagopaOperator } = useUserRole(); + const { t } = useTranslation(); + const { channelId } = useParams<{ channelId: string }>(); + if (userIsPagopaOperator) { return ( - - {/* - - */} - - {userIsPagopaOperator && channelDetails?.wrapperStatus === WrapperStatusEnum.APPROVED ? ( - <> - - - ) : userIsPagopaOperator && channelDetails?.wrapperStatus !== WrapperStatusEnum.APPROVED ? ( - <> - - - - ) : channelDetails?.wrapperStatus === WrapperStatusEnum.APPROVED ? ( - <> - - - - - ) : ( - <> - - - )} - + <> + {(channelDetails?.wrapperStatus === WrapperStatusEnum.TO_CHECK || + channelDetails?.wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE) && ( + + )} + + + ); + } else { + return ( + <> + + {channelDetails?.wrapperStatus === WrapperStatusEnum.APPROVED && ( + <> + + + + )} + + ); + } +} + +type Props = { + channelDetails?: ChannelDetailsResource; + setChannelDetails: (value: any) => void; + goBack: () => void; +}; + +const DetailButtons = ({ channelDetails, setChannelDetails, goBack }: Props) => { + const [showModal, setShowModal] = useState(false); + + return ( + <> + + + + {showModal && ( + ( + + )} + /> + )} + + ); }; export default DetailButtons; diff --git a/src/pages/channels/detail/components/GetChannelAlert.tsx b/src/pages/channels/detail/components/GetChannelAlert.tsx new file mode 100644 index 000000000..45b9eb8f2 --- /dev/null +++ b/src/pages/channels/detail/components/GetChannelAlert.tsx @@ -0,0 +1,61 @@ +import { Alert, Typography } from '@mui/material'; +import { Box } from '@mui/system'; +import { useTranslation } from 'react-i18next'; +import { ChannelDetailsResource } from '../../../../api/generated/portal/ChannelDetailsResource'; +import { WrapperStatusEnum } from '../../../../api/generated/portal/WrapperChannelDetailsResource'; +import { useUserRole } from '../../../../hooks/useUserRole'; + +type Props = { + channelDetail: ChannelDetailsResource; +}; + +// eslint-disable-next-line sonarjs/cognitive-complexity +export default function GetChannelAlert({ channelDetail }: Props) { + const { t } = useTranslation(); + const { userIsPagopaOperator } = useUserRole(); + + if (channelDetail?.wrapperStatus !== WrapperStatusEnum.APPROVED) { + const isToBeValidated = + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK || + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE; + const isToBeFixed = + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX || + channelDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX_UPDATE; + + const userHasToTakeAction = + (isToBeValidated && userIsPagopaOperator) || (isToBeFixed && !userIsPagopaOperator); + return ( + <> + + + {userIsPagopaOperator ? ( + + {t( + `channelDetailValidationPage.alert.${ + isToBeValidated ? 'toCheckMessage' : 'toFixMessage' + }` + )} + + ) : isToBeFixed && channelDetail?.note?.trim() ? ( + <> + + {t('channelDetailValidationPage.alert.toFixTitle')} + + {channelDetail.note} + + ) : ( + isToBeValidated && ( + {t('channelDetailValidationPage.alert.waitingForRevision')} + ) + )} + + + + ); + } + return null; +} diff --git a/src/pages/channels/list/ChannelsPage.tsx b/src/pages/channels/list/ChannelsPage.tsx index 1bf6e9adf..da6e79d51 100644 --- a/src/pages/channels/list/ChannelsPage.tsx +++ b/src/pages/channels/list/ChannelsPage.tsx @@ -1,59 +1,98 @@ -import {Alert, Box, Grid} from '@mui/material'; -import {TitleBox} from '@pagopa/selfcare-common-frontend'; -import {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useHistory} from 'react-router'; +import { Alert, Button } from '@mui/material'; +import { TitleBox } from '@pagopa/selfcare-common-frontend'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router'; +import { Link } from 'react-router-dom'; import SideMenuLayout from '../../../components/SideMenu/SideMenuLayout'; +import TableSearchBar from '../../../components/Table/TableSearchBar'; +import { useUserRole } from '../../../hooks/useUserRole'; +import { ConfigurationStatus } from '../../../model/Station'; +import ROUTES from '../../../routes'; import ChannelsTable from './ChannelsTable'; -import ChannelsTableSearchBar from './ChannelsTableSearchBar'; export const clearLocationState = () => { - window.history.replaceState({}, document.title); + window.history.replaceState({}, document.title); }; +const componentPath = 'channelsPage'; const Channels = () => { - const {t} = useTranslation(); - const history = useHistory(); - - const [channelCodeInput, setChannelCodeInput] = useState(''); - const [channelCodeFilter, setChannelCodeFilter] = useState(''); - - useEffect(() => { - const setSearchValue = setTimeout(() => { - setChannelCodeFilter(channelCodeInput); - }, 500); - - return () => clearTimeout(setSearchValue); - }, [channelCodeInput]); - - useEffect(() => { - window.addEventListener('beforeunload', clearLocationState); - return () => { - window.removeEventListener('beforeunload', clearLocationState); - }; - }, []); - - return ( - - - {history.location.state && (history.location.state as any).alertSuccessMessage && ( - - {(history.location.state as any).alertSuccessMessage} - - )} - - - - ); + const { t } = useTranslation(); + const history = useHistory(); + const { userIsPagopaOperator } = useUserRole(); + + const [channelCodeInput, setChannelCodeInput] = useState(''); + const [channelCodeFilter, setChannelCodeFilter] = useState(''); + const [tabFilter, setTabFilter] = useState(userIsPagopaOperator ? 1 : 0); + + const tabList = [ + { + label: t(`${componentPath}.search.tabActive`), + 'data-testid': 'active', + value: ConfigurationStatus.ACTIVE, + }, + { + label: t(`${componentPath}.search.tabToBeValidated`), + 'data-testid': 'toBeValidated', + value: ConfigurationStatus.TO_BE_VALIDATED, + }, + ]; + + useEffect(() => { + const setSearchValue = setTimeout(() => { + setChannelCodeFilter(channelCodeInput); + }, 500); + + return () => clearTimeout(setSearchValue); + }, [channelCodeInput]); + + useEffect(() => { + window.addEventListener('beforeunload', clearLocationState); + return () => { + window.removeEventListener('beforeunload', clearLocationState); + }; + }, []); + + return ( + + + {history.location.state && (history.location.state as any).alertSuccessMessage && ( + + {(history.location.state as any).alertSuccessMessage} + + )} + + + {t(`${componentPath}.search.createButton`)} + + ) + } + setActiveTab={setTabFilter} + activeTab={tabFilter} + listTabFilter={tabList} + /> + + + + ); }; export default Channels; diff --git a/src/pages/channels/list/ChannelsTable.tsx b/src/pages/channels/list/ChannelsTable.tsx index 684649a87..78fe9ea60 100644 --- a/src/pages/channels/list/ChannelsTable.tsx +++ b/src/pages/channels/list/ChannelsTable.tsx @@ -1,152 +1,100 @@ -import {Box, Pagination} from '@mui/material'; -import {GridColDef, GridSortModel} from '@mui/x-data-grid'; -import React, {ChangeEvent, useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useLoading} from '@pagopa/selfcare-common-frontend'; -import {useHistory} from 'react-router'; -import {generatePath} from 'react-router-dom'; -import {handleErrors} from '@pagopa/selfcare-common-frontend/services/errorService'; -import TableEmptyState from '../../../components/Table/TableEmptyState'; -import {useUserRole} from '../../../hooks/useUserRole'; -import {LOADING_TASK_CHANNELS_LIST} from '../../../utils/constants'; +import { Box } from '@mui/material'; +import { GridColDef } from '@mui/x-data-grid'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router'; +import { generatePath } from 'react-router-dom'; +import { WrapperChannelsResource } from '../../../api/generated/portal/WrapperChannelsResource'; +import TableDataGrid from '../../../components/Table/TableDataGrid'; +import { useUserRole } from '../../../hooks/useUserRole'; +import { ConfigurationStatus } from '../../../model/Station'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; -import {getChannelsMerged} from '../../../services/channelService'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; -import {WrapperChannelsResource} from '../../../api/generated/portal/WrapperChannelsResource'; -import {useAppSelector} from '../../../redux/hooks'; -import {CustomDataGrid} from '../../../components/Table/TableDataGrid'; -import {buildColumnDefs} from './ChannelsTableColumns'; +import { getChannels } from '../../../services/channelService'; +import { LOADING_TASK_CHANNELS_LIST } from '../../../utils/constants'; +import { buildColumnDefs } from './ChannelsTableColumns'; const rowHeight = 64; const headerHeight = 56; const emptyChannelsResource: WrapperChannelsResource = { - channels: [], - page_info: {}, + channels: [], + page_info: {}, }; const componentPath = 'channelsPage'; -export default function ChannelsTable({channelCodeFilter}: { channelCodeFilter: string }) { - const {t} = useTranslation(); - const history = useHistory(); - const {userIsPagopaOperator} = useUserRole(); - const partySelected = useAppSelector(partiesSelectors.selectPartySelected); +export default function ChannelsTable({ + channelCodeFilter, + statusFilter, +}: Readonly<{ channelCodeFilter: string; statusFilter: ConfigurationStatus }>) { + const { t } = useTranslation(); + const history = useHistory(); + const { userIsPagopaOperator } = useUserRole(); + const addError = useErrorDispatcher(); + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const onRowClick = (channelIdRow: string) => { - history.push(generatePath(`${ROUTES.CHANNEL_DETAIL}`, {channelId: channelIdRow})); - }; + const onRowClick = (channelIdRow: string) => { + history.push(generatePath(`${ROUTES.CHANNEL_DETAIL}`, { channelId: channelIdRow })); + }; - const columns: Array = buildColumnDefs(t, onRowClick); - const setLoadingOverlay = useLoading(LOADING_TASK_CHANNELS_LIST); + const columns: Array = buildColumnDefs(t, onRowClick); + const setLoadingOverlay = useLoading(LOADING_TASK_CHANNELS_LIST); - const [channels, setChannels] = useState(emptyChannelsResource); - const [page, setPage] = useState(0); - const [pagePaginator, setPagePaginator] = useState(0); - const [channelCodeSort, setChannelCodeSort] = useState(undefined); + const [channels, setChannels] = useState(emptyChannelsResource); + const [page, setPage] = useState(0); + const [pageLimit, setPageLimit] = useState(10); - const brokerCode = typeof partySelected !== 'undefined' ? partySelected.fiscalCode : ''; + const brokerCode = typeof selectedParty !== 'undefined' ? selectedParty.fiscalCode : ''; - useEffect(() => { - fetchChannels(page); - }, [page, brokerCode, channelCodeSort]); + useEffect(() => { + fetchChannels(0); + }, [statusFilter, brokerCode, channelCodeFilter, pageLimit]); - useEffect(() => { - setPagePaginator(0); - fetchChannels(0); - }, [channelCodeFilter]); + const fetchChannels = (pageParam: number) => { + if (brokerCode) { + setLoadingOverlay(true); + if(pageParam){ + setPage(pageParam); + } + getChannels({ + status: statusFilter, + channelCode: channelCodeFilter, + brokerCode, + limit: pageLimit, + page: pageParam ?? page, + }) + .then((r) => { + setChannels(r); + }) + .catch((reason) => { + addError({ + id: `FETCH_CHANNELS_ERROR`, + blocking: false, + error: reason, + techDescription: `An error occurred while fetching channels`, + toNotify: true, + }); + setChannels(emptyChannelsResource); + }) + .finally(() => setLoadingOverlay(false)); + } + }; - const fetchChannels = (pageParam: number) => { - if (brokerCode) { - setLoadingOverlay(true); - getChannelsMerged( - pageParam, - brokerCode, - channelCodeFilter, - 10, - channelCodeSort ?? channelCodeSort - ) - .then((r) => { - setChannels(r); - }) - .catch((reason) => { - handleErrors([ - { - id: `FETCH_CHANNELS_ERROR`, - blocking: false, - error: reason, - techDescription: `An error occurred while fetching channels`, - toNotify: true, - }, - ]); - setChannels(emptyChannelsResource); - }) - .finally(() => setLoadingOverlay(false)); - } - }; - - const handleSortModelChange = (sortModel: GridSortModel) => { - setChannelCodeSort( - sortModel.find((column) => column.field === 'channel_code')?.sort?.toUpperCase() - ); - }; - - return ( - - {channels?.channels?.length === 0 ? ( - - ) : ( - ( - , value: number) => { - setPage(value - 1); - setPagePaginator(value - 1); - }} - /> - ), - }} - componentsProps={{ - basePopper: { - sx: { - '& .MuiDataGrid-menuList': { - boxShadow: `0px 0px 45px rgba(0, 0, 0, 0.1)`, - }, - }, - }, - }} - getRowId={(r) => r.channel_code} - headerHeight={headerHeight} - hideFooterSelectedRowCount={true} - paginationMode="server" - rowCount={channels.channels!.length} - rowHeight={rowHeight} - rows={channels.channels as any} - sortingMode="server" - onSortModelChange={handleSortModelChange} - /> - )} - - ); + return ( + + fetchChannels(newPage)} + pageLimit={pageLimit} + setPageLimit={setPageLimit} + getRowId={(r) => r.channel_code} + /> + + ); } diff --git a/src/pages/channels/list/ChannelsTableColumns.tsx b/src/pages/channels/list/ChannelsTableColumns.tsx index 0ebe6ed9c..c99518c61 100644 --- a/src/pages/channels/list/ChannelsTableColumns.tsx +++ b/src/pages/channels/list/ChannelsTableColumns.tsx @@ -1,156 +1,154 @@ -import {GridColDef, GridRenderCellParams} from '@mui/x-data-grid'; -import {TFunction} from 'react-i18next'; -import {generatePath} from 'react-router'; -import {FormAction} from '../../../model/Channel'; -import ROUTES from '../../../routes'; +import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid'; +import { TFunction } from 'react-i18next'; +import { generatePath } from 'react-router'; +import { StatusEnum } from '../../../api/generated/portal/ChannelDetailsDto'; +import { StatusChip } from '../../../components/StatusChip'; import GridLinkAction from '../../../components/Table/GridLinkAction'; -import {StatusChip} from '../../../components/StatusChip'; -import {StatusEnum} from '../../../api/generated/portal/ChannelDetailsDto'; -import {renderCell, showCustomHeader} from '../../../components/Table/TableUtils'; +import { renderCell, showCustomHeader } from '../../../components/Table/TableUtils'; +import { FormAction } from '../../../model/Channel'; +import ROUTES from '../../../routes'; export function buildColumnDefs( - t: TFunction<'translation', undefined>, - _onRowClick: (channelId: string) => void + t: TFunction<'translation', undefined>, + _onRowClick: (channelId: string) => void ) { - return [ - { - field: 'channel_code', - cellClassName: 'justifyContentBold', - headerName: t('channelsPage.channelsTableColumns.headerFields.name'), - align: 'left', - headerAlign: 'left', - width: 404, - editable: false, - disableColumnMenu: true, - renderHeader: showCustomHeader, - renderCell: (params: any) => - renderCell({ - value: params.row.channel_code, - mainCell: true, - color: params.row.status === 'SUSPENDED' ? 'text.disabled' : undefined, - }), - sortable: true, - flex: 4, - }, - { - field: 'createdAt', - cellClassName: 'justifyContentNormal', - headerName: t('channelsPage.channelsTableColumns.headerFields.creationDate'), - align: 'left', - headerAlign: 'left', - width: 404, - editable: false, - disableColumnMenu: true, - renderHeader: showCustomHeader, - renderCell: (params) => - renderCell({ - value: params.row.createdAt?.toLocaleDateString('en-GB'), - color: params.row.status === 'SUSPENDED' ? 'text.disabled' : undefined, - }), - sortable: false, - flex: 4, - }, - { - field: 'modifiedAt', - cellClassName: 'justifyContentNormal', - headerName: t('channelsPage.channelsTableColumns.headerFields.lastEditDate'), - align: 'left', - headerAlign: 'left', - width: 404, - editable: false, - disableColumnMenu: true, - renderHeader: showCustomHeader, - renderCell: (params) => - renderCell({ - value: params.row.modifiedAt?.toLocaleDateString('en-GB'), - color: params.row.status === 'SUSPENDED' ? 'text.disabled' : undefined, - }), - sortable: false, - flex: 4, - }, - { - field: 'enabled', - cellClassName: 'justifyContentNormal', - headerName: t('channelsPage.channelsTableColumns.headerFields.status'), - align: 'left', - headerAlign: 'left', - width: 404, - editable: false, - disableColumnMenu: true, - renderHeader: showCustomHeader, - renderCell: (params) => showStatus(params), - sortable: false, - flex: 4, - }, - { - field: 'actions', - cellClassName: 'justifyContentNormalRight', - type: 'actions', - headerName: '', - align: 'center', - hideSortIcons: true, - disableColumnMenu: true, - editable: false, + return [ + { + field: 'channel_code', + cellClassName: 'justifyContentBold', + headerName: t('channelsPage.channelsTableColumns.headerFields.name'), + align: 'left', + headerAlign: 'left', + width: 404, + editable: false, + disableColumnMenu: true, + renderHeader: showCustomHeader, + renderCell: (params: any) => + renderCell({ + value: params.row.channel_code, + mainCell: true, + color: params.row.status === 'SUSPENDED' ? 'text.disabled' : undefined, + }), + sortable: true, + flex: 4, + }, + { + field: 'createdAt', + cellClassName: 'justifyContentNormal', + headerName: t('channelsPage.channelsTableColumns.headerFields.creationDate'), + align: 'left', + headerAlign: 'left', + width: 404, + editable: false, + disableColumnMenu: true, + renderHeader: showCustomHeader, + renderCell: (params) => + renderCell({ + value: params.row.createdAt?.toLocaleDateString('en-GB'), + color: params.row.status === 'SUSPENDED' ? 'text.disabled' : undefined, + }), + sortable: false, + flex: 4, + }, + { + field: 'modifiedAt', + cellClassName: 'justifyContentNormal', + headerName: t('channelsPage.channelsTableColumns.headerFields.lastEditDate'), + align: 'left', + headerAlign: 'left', + width: 404, + editable: false, + disableColumnMenu: true, + renderHeader: showCustomHeader, + renderCell: (params) => + renderCell({ + value: params.row.modifiedAt?.toLocaleDateString('en-GB'), + color: params.row.status === 'SUSPENDED' ? 'text.disabled' : undefined, + }), + sortable: false, + flex: 4, + }, + { + field: 'enabled', + cellClassName: 'justifyContentNormal', + headerName: t('channelsPage.channelsTableColumns.headerFields.status'), + align: 'left', + headerAlign: 'left', + width: 404, + editable: false, + disableColumnMenu: true, + renderHeader: showCustomHeader, + renderCell: (params) => showStatus(params), + sortable: false, + flex: 4, + }, + { + field: 'actions', + cellClassName: 'justifyContentNormalRight', + type: 'actions', + headerName: '', + align: 'center', + hideSortIcons: true, + disableColumnMenu: true, + editable: false, - getActions: (params: any) => { - const manageChannelAction = ( - - ); - const editChannelAction = ( - - ); - const duplicateChannelAction = ( - - ); - const manageChannelPSPAction = ( - - ); + getActions: (params: any) => { + const manageChannelAction = ( + + ); + const editChannelAction = ( + + ); + const duplicateChannelAction = ( + + ); + const manageChannelPSPAction = ( + + ); - if (params.row.wrapperStatus === StatusEnum.APPROVED) { - return [manageChannelAction, manageChannelPSPAction, duplicateChannelAction]; - } else { - return [manageChannelAction, editChannelAction]; - } - }, - sortable: false, - flex: 1, - }, - ] as Array; + if (params.row.wrapperStatus === StatusEnum.APPROVED) { + return [manageChannelAction, manageChannelPSPAction, duplicateChannelAction]; + } else { + return [manageChannelAction, editChannelAction]; + } + }, + sortable: false, + flex: 1, + }, + ] as Array; } export function showStatus(params: GridRenderCellParams) { - return renderCell({ - value: ( - - ), - overrideStyle: { - textAlign: 'left', - }, - }); + return renderCell({ + value: , + overrideStyle: { + textAlign: 'left', + }, + }); } diff --git a/src/pages/channels/list/ChannelsTableSearchBar.tsx b/src/pages/channels/list/ChannelsTableSearchBar.tsx deleted file mode 100644 index 22a58ec78..000000000 --- a/src/pages/channels/list/ChannelsTableSearchBar.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import {Box, Button, InputAdornment, TextField} from '@mui/material'; -import {GridSearchIcon} from '@mui/x-data-grid'; -import {useTranslation} from 'react-i18next'; -import {Link} from 'react-router-dom'; -import ROUTES from '../../../routes'; -import {useUserRole} from "../../../hooks/useUserRole"; - -type Props = { - channelCodeInput: string; - setChannelCodeInput: (stationCode: string) => void; -}; - -export default function ChannelsTableSearchBar({channelCodeInput, setChannelCodeInput}: Props) { - const {t} = useTranslation(); - const {userIsPagopaOperator} = useUserRole(); - - return ( - - - - - ), - sx: {height: 48}, - }} - value={channelCodeInput} - onChange={(event) => setChannelCodeInput(event.target.value)} - fullWidth - placeholder={t('channelsPage.searchPlaceholder')} - /> - - - ); -} diff --git a/src/pages/channels/list/__tests__/ChannelsPage.test.tsx b/src/pages/channels/list/__tests__/ChannelsPage.test.tsx index 3658008c7..3e02e4741 100644 --- a/src/pages/channels/list/__tests__/ChannelsPage.test.tsx +++ b/src/pages/channels/list/__tests__/ChannelsPage.test.tsx @@ -7,6 +7,8 @@ import {store} from '../../../../redux/store'; import ChannelsPage, {clearLocationState} from '../ChannelsPage'; import {createMemoryHistory} from 'history'; import {Provider} from 'react-redux'; +import * as useUserRole from '../../../../hooks/useUserRole'; +import {ROLE} from '../../../../model/RolePermission'; beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(() => { @@ -35,7 +37,35 @@ describe('', () => { expect(screen.getByTestId('alert-test')).toBeInTheDocument(); }); + test('render component ChannelsPage operator', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: false + }); + render( + + + + + + + + ); + }); + it('should replace the current state of window history', () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: false + }); render( diff --git a/src/pages/channels/list/__tests__/ChannelsTable.test.tsx b/src/pages/channels/list/__tests__/ChannelsTable.test.tsx index 062ca6bbb..f65291ebf 100644 --- a/src/pages/channels/list/__tests__/ChannelsTable.test.tsx +++ b/src/pages/channels/list/__tests__/ChannelsTable.test.tsx @@ -1,66 +1,65 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, render, waitFor, screen} from '@testing-library/react'; +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { cleanup, render, screen, waitFor } from '@testing-library/react'; +import { createMemoryHistory } from 'history'; import React from 'react'; -import {Router} from 'react-router-dom'; -import {store} from '../../../../redux/store'; -import ChannelsTable from '../ChannelsTable'; -import {createMemoryHistory} from 'history'; -import {Provider} from 'react-redux'; -import {pspAdminSignedDirect} from '../../../../services/__mocks__/partyService'; -import {partiesActions} from '../../../../redux/slices/partiesSlice'; -import {useAppDispatch} from '../../../../redux/hooks'; +import { Provider } from 'react-redux'; +import { Router } from 'react-router-dom'; +import { ConfigurationStatus } from '../../../../model/Station'; +import { useAppDispatch } from '../../../../redux/hooks'; +import { partiesActions } from '../../../../redux/slices/partiesSlice'; +import { store } from '../../../../redux/store'; +import { mockedChannels } from '../../../../services/__mocks__/channelService'; +import { pspAdminSignedDirect } from '../../../../services/__mocks__/partyService'; import * as ChannelService from '../../../../services/channelService'; -import {mockedChannelsMerged} from '../../../../services/__mocks__/channelService'; +import ChannelsTable from '../ChannelsTable'; const mockGetChannelsMerged = jest.spyOn(ChannelService, 'getChannelsMerged'); beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); }); afterEach(cleanup); const Component = () => { - const history = createMemoryHistory(); - const dispatch = useAppDispatch(); - dispatch(partiesActions.setPartySelected(pspAdminSignedDirect)); + const history = createMemoryHistory(); + const dispatch = useAppDispatch(); + dispatch(partiesActions.setPartySelected(pspAdminSignedDirect)); - return ( - - - - - - ); + return ( + + + + + + ); }; describe('', () => { - test('render component ChannelsTable', async () => { - mockGetChannelsMerged.mockReturnValue(Promise.resolve(mockedChannelsMerged)); - render( - - - - ); + test('render component ChannelsTable', async () => { + mockGetChannelsMerged.mockReturnValue(Promise.resolve(mockedChannels)); + render( + + + + ); - await waitFor(() => { - expect(screen.queryByTestId('empty-state-table')).not.toBeInTheDocument(); - }); + await waitFor(() => { + expect(screen.queryByTestId('empty-state-table')).not.toBeInTheDocument(); }); - test('render component ChannelsTable error getChannelsMerged', async () => { - mockGetChannelsMerged.mockRejectedValue('error'); - render( - - - - ); + }); + test('render component ChannelsTable error getChannelsMerged', async () => { + mockGetChannelsMerged.mockRejectedValue('error'); + render( + + + + ); - await waitFor(() => { - expect(screen.queryByTestId('empty-state-table')).toBeInTheDocument(); - }); + await waitFor(() => { + expect(screen.queryByTestId('empty-state-table')).toBeInTheDocument(); }); + }); }); diff --git a/src/pages/channels/list/__tests__/ChannelsTableSearchBar.test.tsx b/src/pages/channels/list/__tests__/ChannelsTableSearchBar.test.tsx deleted file mode 100644 index 5a323d869..000000000 --- a/src/pages/channels/list/__tests__/ChannelsTableSearchBar.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import {render} from '@testing-library/react'; -import ChannelsTableSearchBar from '../ChannelsTableSearchBar'; -import {Router} from 'react-router-dom'; -import {createMemoryHistory} from 'history'; -import {Provider} from 'react-redux'; -import {store} from "../../../../redux/store"; -import {featureFlagsActions} from "../../../../redux/slices/featureFlagsSlice"; - -test('render component ChannelsTableSearchBar', async () => { - const history = createMemoryHistory(); - const flags = { - flags: {['isOperator']: false} - }; - await store.dispatch(featureFlagsActions.setFeatureFlags(flags)); - render( - - - - - - ); -}); - -describe('', () => { -}); diff --git a/src/pages/stations/detail/components/StationDetails.tsx b/src/pages/stations/detail/components/StationDetails.tsx index 9d97fe4b1..564adc425 100644 --- a/src/pages/stations/detail/components/StationDetails.tsx +++ b/src/pages/stations/detail/components/StationDetails.tsx @@ -452,12 +452,37 @@ Props) => { )} - {t('channelDetailPage.createdOn')}{' '} - - {`${stationDetail?.createdAt?.toLocaleDateString('en-GB')} da ${ - stationDetail?.createdBy - }`} - + {stationDetail?.createdBy && ( + <> + {t('channelDetailPage.createdOn')}{' '} + + {`${stationDetail?.createdAt?.toLocaleDateString('en-GB') ?? '-'}`} + {' '} + {t('general.fromLower')}{' '} + + {stationDetail?.createdBy} + + {'.'} + + )} + {stationDetail?.modifiedBy && ( +
+ {t('channelDetailPage.lastModified')}{' '} + + {stationDetail?.modifiedBy} + + {stationDetail?.modifiedAt && ( + <> + {' '} + {t('general.atLower')}{' '} + + {`${stationDetail?.modifiedAt?.toLocaleDateString('en-GB')}`} + + + )} + {'.'} +
+ )}
{stationDetail && ( diff --git a/src/pages/stations/list/StationsTable.tsx b/src/pages/stations/list/StationsTable.tsx index 052a8abb9..0c66261e3 100644 --- a/src/pages/stations/list/StationsTable.tsx +++ b/src/pages/stations/list/StationsTable.tsx @@ -1,94 +1,94 @@ -import {Box} from '@mui/material'; -import {GridColDef} from '@mui/x-data-grid'; -import React, {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {WrapperStationsResource} from '../../../api/generated/portal/WrapperStationsResource'; -import {getStations} from '../../../services/stationService'; -import {LOADING_TASK_RETRIEVE_STATIONS} from '../../../utils/constants'; -import {useUserRole} from '../../../hooks/useUserRole'; -import {ConfigurationStatus} from '../../../model/Station'; +import { Box } from '@mui/material'; +import { GridColDef } from '@mui/x-data-grid'; +import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { WrapperStationsResource } from '../../../api/generated/portal/WrapperStationsResource'; +import { getStations } from '../../../services/stationService'; +import { LOADING_TASK_RETRIEVE_STATIONS } from '../../../utils/constants'; +import { useUserRole } from '../../../hooks/useUserRole'; +import { ConfigurationStatus } from '../../../model/Station'; import ROUTES from '../../../routes'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import TableDataGrid from '../../../components/Table/TableDataGrid'; -import {buildColumnDefs} from './StationsTableColumns'; +import { buildColumnDefs } from './StationsTableColumns'; const emptyStationsResource: WrapperStationsResource = { - stationsList: [], - pageInfo: {}, + stationsList: [], + pageInfo: {}, }; const componentPath = 'stationsPage'; export default function StationsTable({ - stationCode, - statusFilter, - }: Readonly<{ stationCode: string; statusFilter: ConfigurationStatus }>) { - const {t} = useTranslation(); - const {userIsPagopaOperator} = useUserRole(); - const columns: Array = buildColumnDefs(t, userIsPagopaOperator); - const addError = useErrorDispatcher(); - const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const setLoading = useLoading(LOADING_TASK_RETRIEVE_STATIONS); - const [stations, setStations] = useState(emptyStationsResource); + stationCode, + statusFilter, +}: Readonly<{ stationCode: string; statusFilter: ConfigurationStatus }>) { + const { t } = useTranslation(); + const { userIsPagopaOperator } = useUserRole(); + const columns: Array = buildColumnDefs(t, userIsPagopaOperator); + const addError = useErrorDispatcher(); + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); + const setLoading = useLoading(LOADING_TASK_RETRIEVE_STATIONS); + const [stations, setStations] = useState(emptyStationsResource); - const [page, setPage] = useState(0); - const [pageLimit, setPageLimit] = useState(10); + const [page, setPage] = useState(0); + const [pageLimit, setPageLimit] = useState(10); - const brokerCode = typeof selectedParty !== 'undefined' ? selectedParty.fiscalCode : ''; + const brokerCode = typeof selectedParty !== 'undefined' ? selectedParty.fiscalCode : ''; - function handleGetStations(newPage?: number) { - if (brokerCode) { - if (newPage !== undefined) { - setPage(newPage); - } - setLoading(true); - getStations({ - page: newPage ?? page, - brokerCode, - stationCode, - status: statusFilter, - limit: pageLimit, - }) - .then((res) => { - setStations(res); - }) - .catch((reason) => { - addError({ - id: 'RETRIEVE_STATIONS_ERROR', - blocking: false, - error: reason, - techDescription: `An error occurred while retrieving stations`, - toNotify: true, - }); - setStations(emptyStationsResource); - }) - .finally(() => setLoading(false)); - } + function handleGetStations(newPage?: number) { + if (brokerCode) { + if (newPage !== undefined) { + setPage(newPage); + } + setLoading(true); + getStations({ + page: newPage ?? page, + brokerCode, + stationCode, + status: statusFilter, + limit: pageLimit, + }) + .then((res) => { + setStations(res); + }) + .catch((reason) => { + addError({ + id: 'RETRIEVE_STATIONS_ERROR', + blocking: false, + error: reason, + techDescription: `An error occurred while retrieving stations`, + toNotify: true, + }); + setStations(emptyStationsResource); + }) + .finally(() => setLoading(false)); } + } - function handleChangePage(newPage: number) { - handleGetStations(newPage); - } + function handleChangePage(newPage: number) { + handleGetStations(newPage); + } - useEffect(() => { - handleGetStations(0); - }, [stationCode, brokerCode, statusFilter, pageLimit]); + useEffect(() => { + handleGetStations(0); + }, [stationCode, brokerCode, statusFilter, pageLimit]); - return ( - - handleChangePage(newPage)} - pageLimit={pageLimit} - setPageLimit={setPageLimit} - getRowId={(r) => r.stationCode} - /> - - ); + return ( + + handleChangePage(newPage)} + pageLimit={pageLimit} + setPageLimit={setPageLimit} + getRowId={(r) => r.stationCode} + /> + + ); } diff --git a/src/pages/stations/list/StationsTableColumns.tsx b/src/pages/stations/list/StationsTableColumns.tsx index 3782ef6b9..e715f2ebb 100644 --- a/src/pages/stations/list/StationsTableColumns.tsx +++ b/src/pages/stations/list/StationsTableColumns.tsx @@ -19,7 +19,7 @@ export function buildColumnDefs( headerName: t('stationsPage.stationsTableColumns.headerFields.name'), align: 'left', headerAlign: 'left', - minWidth: userIsPagopaOperator ? 900 : 485, + minWidth: userIsPagopaOperator ? 700 : 485, editable: false, disableColumnMenu: true, renderHeader: showCustomHeader, diff --git a/src/pages/stations/list/StationsTableSearchBar.tsx b/src/pages/stations/list/StationsTableSearchBar.tsx deleted file mode 100644 index 19637c696..000000000 --- a/src/pages/stations/list/StationsTableSearchBar.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import {Box, Button, InputAdornment, TextField} from '@mui/material'; -import {GridSearchIcon} from '@mui/x-data-grid'; -import {useTranslation} from 'react-i18next'; -import {Link} from 'react-router-dom'; -import ROUTES from '../../../routes'; -import {useUserRole} from "../../../hooks/useUserRole"; - -type Props = { - stationCodeInput: string; - setStationCodeInput: (stationCode: string) => void; -}; - -export default function StationsTableSearchBar({stationCodeInput, setStationCodeInput}: Props) { - const {t} = useTranslation(); - const {userIsPagopaOperator} = useUserRole(); - - return ( - - - - - ), - sx: {height: 48}, - }} - value={stationCodeInput} - onChange={(event) => setStationCodeInput(event.target.value)} - fullWidth - placeholder={t('stationsPage.searchPlaceholder')} - /> - - - ); -} diff --git a/src/pages/stations/list/__tests__/StationsTable.test.tsx b/src/pages/stations/list/__tests__/StationsTable.test.tsx index 308f1b96f..ba28a5105 100644 --- a/src/pages/stations/list/__tests__/StationsTable.test.tsx +++ b/src/pages/stations/list/__tests__/StationsTable.test.tsx @@ -1,16 +1,17 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, render, waitFor, screen} from '@testing-library/react'; +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { cleanup, render, screen, waitFor } from '@testing-library/react'; +import { createMemoryHistory } from 'history'; import React from 'react'; -import {Router} from 'react-router-dom'; -import {createMemoryHistory} from 'history'; -import {Provider} from 'react-redux'; -import {useAppDispatch} from '../../../../redux/hooks'; -import {partiesActions} from '../../../../redux/slices/partiesSlice'; -import {store} from '../../../../redux/store'; +import { Provider } from 'react-redux'; +import { Router } from 'react-router-dom'; +import { ConfigurationStatus } from '../../../../model/Station'; +import { useAppDispatch } from '../../../../redux/hooks'; +import { partiesActions } from '../../../../redux/slices/partiesSlice'; +import { store } from '../../../../redux/store'; +import { pspAdminSignedDirect } from '../../../../services/__mocks__/partyService'; +import { mockedStations } from '../../../../services/__mocks__/stationService'; import * as StationService from '../../../../services/stationService'; -import {pspAdminSignedDirect} from '../../../../services/__mocks__/partyService'; -import {mockedStationsMerged2} from '../../../../services/__mocks__/stationService'; import StationsTable from '../StationsTable'; const mockGetStationsMerged = jest.spyOn(StationService, 'getStationsMerged'); @@ -32,7 +33,7 @@ const Component = () => { return ( - + ); @@ -40,7 +41,7 @@ const Component = () => { describe('', () => { test('render component StationTable', async () => { - mockGetStationsMerged.mockReturnValueOnce(Promise.resolve(mockedStationsMerged2)); + mockGetStationsMerged.mockReturnValueOnce(Promise.resolve(mockedStations)); render( diff --git a/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx b/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx index cfed2806e..3322b0bb2 100644 --- a/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx +++ b/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx @@ -185,7 +185,7 @@ describe('', () => { headerName: 'Station Name', align: 'left', headerAlign: 'left', - minWidth: 900, + minWidth: 700, editable: false, disableColumnMenu: true, renderHeader: expect.any(Function), diff --git a/src/services/__mocks__/channelService.ts b/src/services/__mocks__/channelService.ts index 9d6f37e92..7398df01a 100644 --- a/src/services/__mocks__/channelService.ts +++ b/src/services/__mocks__/channelService.ts @@ -1,425 +1,480 @@ -import {ChannelCodeResource} from '../../api/generated/portal/ChannelCodeResource'; -import {ChannelDetailsDto, ProtocolEnum} from '../../api/generated/portal/ChannelDetailsDto'; -import {ChannelDetailsResource} from '../../api/generated/portal/ChannelDetailsResource'; -import {ChannelPspListResource} from '../../api/generated/portal/ChannelPspListResource'; -import {ChannelsResource} from '../../api/generated/portal/ChannelsResource'; -import {PspChannelPaymentTypes} from '../../api/generated/portal/PspChannelPaymentTypes'; -import {PspChannelPaymentTypesResource} from '../../api/generated/portal/PspChannelPaymentTypesResource'; -import {PspChannelsResource} from '../../api/generated/portal/PspChannelsResource'; -import {WrapperStatusEnum} from '../../api/generated/portal/WrapperChannelResource'; -import {WrapperChannelsResource} from '../../api/generated/portal/WrapperChannelsResource'; +import { ChannelCodeResource } from '../../api/generated/portal/ChannelCodeResource'; +import { ChannelDetailsDto, ProtocolEnum } from '../../api/generated/portal/ChannelDetailsDto'; +import { ChannelDetailsResource } from '../../api/generated/portal/ChannelDetailsResource'; +import { ChannelPspListResource } from '../../api/generated/portal/ChannelPspListResource'; +import { PspChannelPaymentTypes } from '../../api/generated/portal/PspChannelPaymentTypes'; +import { PspChannelPaymentTypesResource } from '../../api/generated/portal/PspChannelPaymentTypesResource'; +import { PspChannelsResource } from '../../api/generated/portal/PspChannelsResource'; +import { WfespPluginConfs } from '../../api/generated/portal/WfespPluginConfs'; import { - StatusEnum, - WrapperChannelDetailsDto, + StatusEnum, + WrapperChannelDetailsDto, } from '../../api/generated/portal/WrapperChannelDetailsDto'; -import {WrapperEntities} from '../../api/generated/portal/WrapperEntities'; -import {ChannelOnCreation} from '../../model/Channel'; -import {WfespPluginConfs} from '../../api/generated/portal/WfespPluginConfs'; -import {Delegation} from '../../api/generated/portal/Delegation'; -import {mockedPaymentTypes} from './configurationService'; -import {channelWrapperMockedGet} from './institutionsService'; +import { WrapperStatusEnum } from '../../api/generated/portal/WrapperChannelResource'; +import { WrapperChannelsResource } from '../../api/generated/portal/WrapperChannelsResource'; +import { WrapperEntities } from '../../api/generated/portal/WrapperEntities'; +import { ChannelOnCreation } from '../../model/Channel'; +import { mockedPaymentTypes } from './configurationService'; +import { channelWrapperMockedGet } from './institutionsService'; -export const mockedChannels: ChannelsResource = { - channels: [ - { - channel_code: 'XPAY_03_ONUS', - enabled: true, - broker_description: 'Intermediario XPAY', - }, - { - channel_code: 'XPAY_03', - enabled: true, - broker_description: 'Intermediario XPAY', - }, - { - channel_code: 'WFESP_07_tot', - enabled: true, - broker_description: 'Intermediario per test WFESP', - }, - { - channel_code: 'WFESP_07_salvo', - enabled: false, - broker_description: 'Intermediario per test WFESP', - }, - { - channel_code: 'WFESP_07_ila', - enabled: true, - broker_description: 'Intermediario per test WFESP', - }, - ], - page_info: { - page: 0, - limit: 50, - items_found: 50, - total_pages: 8, +export const mockedChannels: WrapperChannelsResource = { + channels: [ + { + channel_code: 'XPAY_03_ONUS', + enabled: true, + broker_description: 'Intermediario XPAY', + wrapperStatus: WrapperStatusEnum.APPROVED, }, + { + channel_code: 'XPAY_03', + enabled: true, + broker_description: 'Intermediario XPAY', + wrapperStatus: WrapperStatusEnum.APPROVED, + }, + { + channel_code: 'WFESP_07_tot', + enabled: true, + broker_description: 'Intermediario per test WFESP', + wrapperStatus: WrapperStatusEnum.APPROVED, + }, + { + channel_code: 'WFESP_07_salvo', + enabled: false, + broker_description: 'Intermediario per test WFESP', + wrapperStatus: WrapperStatusEnum.APPROVED, + }, + { + channel_code: 'WFESP_07_ila', + enabled: true, + broker_description: 'Intermediario per test WFESP', + wrapperStatus: WrapperStatusEnum.APPROVED, + }, + ], + page_info: { + page: 0, + limit: 50, + items_found: 50, + total_pages: 8, + }, }; export const mockedPSPChannels: PspChannelsResource = { - channels: [ - { - channel_code: 'XPAY_03_ONUS', - enabled: true, - payment_types: [], - }, - { - channel_code: '97735020584_01', - enabled: false, - payment_types: [], - }, - { - channel_code: 'WFESP_07_tot', - enabled: true, - payment_types: [], - }, - ], + channels: [ + { + channel_code: 'XPAY_03_ONUS', + enabled: true, + payment_types: [], + }, + { + channel_code: '97735020584_01', + enabled: false, + payment_types: [], + }, + { + channel_code: 'WFESP_07_tot', + enabled: true, + payment_types: [], + }, + ], }; export const channelEnabled = (channel: PspChannelsResource) => { - const newList: PspChannelsResource = { - channels: channel.channels.filter((e) => e.enabled === false), - }; - return newList; + const newList: PspChannelsResource = { + channels: channel.channels.filter((e) => e.enabled === false), + }; + return newList; }; - export const mockedWfespPlugIn: WfespPluginConfs = { - wfesp_plugin_confs: [ - { - pag_const_string_profile: '', - pag_soap_rule_profile: '', - pag_rpt_xpath_profile: '', - id_bean: 'defaultForwardProcessor', - id_serv_plugin: 'test2', - }, - { - pag_const_string_profile: '', - pag_soap_rule_profile: '', - pag_rpt_xpath_profile: '', - id_bean: 'defaultForwardProcessor', - id_serv_plugin: 'wpl02', - }, - { - pag_const_string_profile: '', - pag_soap_rule_profile: - 'profilo=$identificativoIntermediarioPA$~$identificativoStazioneIntermediarioPA$', - pag_rpt_xpath_profile: '', - id_bean: 'defaultForwardProcessor', - id_serv_plugin: 'idPsp1', - }, - { - pag_const_string_profile: '', - pag_soap_rule_profile: '', - pag_rpt_xpath_profile: '', - id_bean: 'myBankForwardProcessor', - id_serv_plugin: 'wpl04', - }, - { - pag_const_string_profile: '', - pag_soap_rule_profile: '', - pag_rpt_xpath_profile: '', - id_bean: 'defaultForwardProcessor', - id_serv_plugin: 'wpl06', - }, - { - pag_const_string_profile: '', - pag_soap_rule_profile: '', - pag_rpt_xpath_profile: '', - id_bean: 'defaultForwardProcessor', - id_serv_plugin: 'wpl05', - }, - { - pag_const_string_profile: '', - pag_soap_rule_profile: '', - pag_rpt_xpath_profile: '', - id_bean: 'defaultForwardProcessor', - id_serv_plugin: 'wpl03', - }, - { - pag_const_string_profile: '', - pag_soap_rule_profile: 'IDVS=$buyerBank$', - pag_rpt_xpath_profile: '', - id_bean: 'defaultForwardProcessor', - id_serv_plugin: 'wpl07', - }, - ], + wfesp_plugin_confs: [ + { + pag_const_string_profile: '', + pag_soap_rule_profile: '', + pag_rpt_xpath_profile: '', + id_bean: 'defaultForwardProcessor', + id_serv_plugin: 'test2', + }, + { + pag_const_string_profile: '', + pag_soap_rule_profile: '', + pag_rpt_xpath_profile: '', + id_bean: 'defaultForwardProcessor', + id_serv_plugin: 'wpl02', + }, + { + pag_const_string_profile: '', + pag_soap_rule_profile: + 'profilo=$identificativoIntermediarioPA$~$identificativoStazioneIntermediarioPA$', + pag_rpt_xpath_profile: '', + id_bean: 'defaultForwardProcessor', + id_serv_plugin: 'idPsp1', + }, + { + pag_const_string_profile: '', + pag_soap_rule_profile: '', + pag_rpt_xpath_profile: '', + id_bean: 'myBankForwardProcessor', + id_serv_plugin: 'wpl04', + }, + { + pag_const_string_profile: '', + pag_soap_rule_profile: '', + pag_rpt_xpath_profile: '', + id_bean: 'defaultForwardProcessor', + id_serv_plugin: 'wpl06', + }, + { + pag_const_string_profile: '', + pag_soap_rule_profile: '', + pag_rpt_xpath_profile: '', + id_bean: 'defaultForwardProcessor', + id_serv_plugin: 'wpl05', + }, + { + pag_const_string_profile: '', + pag_soap_rule_profile: '', + pag_rpt_xpath_profile: '', + id_bean: 'defaultForwardProcessor', + id_serv_plugin: 'wpl03', + }, + { + pag_const_string_profile: '', + pag_soap_rule_profile: 'IDVS=$buyerBank$', + pag_rpt_xpath_profile: '', + id_bean: 'defaultForwardProcessor', + id_serv_plugin: 'wpl07', + }, + ], }; // @ts-ignore export const mockedChannel: ChannelDetailsDto = { - agid: false, - broker_description: 'string', - broker_psp_code: 'string', - card_chart: false, - channel_code: 'string', - digital_stamp_brand: false, - enabled: true, - flag_io: false, - ip: 'string', - new_fault_code: false, - new_password: 'string', - note: 'string', - nmp_service: 'string', - on_us: false, - password: 'string', - payment_model: undefined, - payment_types: mockedPaymentTypes?.payment_types?.map((e) => e.payment_type ?? "") ?? [], - port: 0, - primitive_version: 1, - protocol: ProtocolEnum.HTTPS, - proxy_enabled: false, - proxy_host: 'string', - proxy_password: 'string', - proxy_port: 0, - proxy_username: 'string', - recovery: false, - rt_push: false, - serv_plugin: 'string', - service: 'string', - status: StatusEnum.APPROVED, - target_host: 'string', - target_path: 'string', - target_port: 3000, - thread_number: 3, - timeout_a: 1000, - timeout_b: 2000, - timeout_c: 3000, + agid: false, + broker_description: 'string', + broker_psp_code: 'string', + card_chart: false, + channel_code: 'string', + digital_stamp_brand: false, + enabled: true, + flag_io: false, + ip: 'string', + new_fault_code: false, + new_password: 'string', + note: 'string', + nmp_service: 'string', + on_us: false, + password: 'string', + payment_model: undefined, + payment_types: mockedPaymentTypes?.payment_types?.map((e) => e.payment_type ?? '') ?? [], + port: 0, + primitive_version: 1, + protocol: ProtocolEnum.HTTPS, + proxy_enabled: false, + proxy_host: 'string', + proxy_password: 'string', + proxy_port: 0, + proxy_username: 'string', + recovery: false, + rt_push: false, + serv_plugin: 'string', + service: 'string', + status: StatusEnum.APPROVED, + target_host: 'string', + target_path: 'string', + target_port: 3000, + thread_number: 3, + timeout_a: 1000, + timeout_b: 2000, + timeout_c: 3000, }; // @ts-ignore export const mockedWrapperChannel: WrapperChannelDetailsDto = { - broker_psp_code: 'broker_psp_code', - broker_description: 'broker_description', - channel_code: 'id_channel', - target_path: 'target_path', - target_port: 8081, - target_host: 'target_host', - payment_types: mockedPaymentTypes?.payment_types?.map((e) => `${e.description ?? ""} - ${e.payment_type ?? ""}`) ?? [], - status: StatusEnum.TO_CHECK, + broker_psp_code: 'broker_psp_code', + broker_description: 'broker_description', + channel_code: 'id_channel', + target_path: 'target_path', + target_port: 8081, + target_host: 'target_host', + payment_types: + mockedPaymentTypes?.payment_types?.map( + (e) => `${e.description ?? ''} - ${e.payment_type ?? ''}` + ) ?? [], + status: StatusEnum.TO_CHECK, }; export const mockedChannelsMerged: WrapperChannelsResource = { - page_info: { - page: 0, - limit: 10, - items_found: 5, - total_pages: 1, - total_items: 5 + page_info: { + page: 0, + limit: 10, + items_found: 5, + total_pages: 1, + total_items: 5, + }, + channels: [ + { + channel_code: '97735020584_01', + createdAt: new Date('2023-05-04T17:52:33.993Z'), + wrapperStatus: WrapperStatusEnum.APPROVED, + modifiedAt: new Date(), }, - channels: [ - { - channel_code: '97735020584_01', - createdAt: new Date('2023-05-04T17:52:33.993Z'), - wrapperStatus: WrapperStatusEnum.APPROVED, - modifiedAt: new Date(), - }, - { - channel_code: '97735020584_02', - createdAt: new Date('2023-05-04T17:52:33.993Z'), - wrapperStatus: WrapperStatusEnum.TO_CHECK, - modifiedAt: new Date(), - }, - { - channel_code: '97735020584_03', - createdAt: new Date('2023-05-04T17:52:33.993Z'), - wrapperStatus: WrapperStatusEnum.TO_CHECK_UPDATE, - modifiedAt: new Date(), - }, - { - channel_code: '97735020584_04', - createdAt: new Date('2023-05-04T17:52:33.993Z'), - wrapperStatus: WrapperStatusEnum.TO_FIX, - modifiedAt: new Date(), - }, - { - channel_code: '97735020584_05', - createdAt: new Date('2023-05-04T17:52:33.993Z'), - wrapperStatus: WrapperStatusEnum.TO_FIX_UPDATE, - modifiedAt: new Date(), - }, - ], + { + channel_code: '97735020584_02', + createdAt: new Date('2023-05-04T17:52:33.993Z'), + wrapperStatus: WrapperStatusEnum.TO_CHECK, + modifiedAt: new Date(), + }, + { + channel_code: '97735020584_03', + createdAt: new Date('2023-05-04T17:52:33.993Z'), + wrapperStatus: WrapperStatusEnum.TO_CHECK_UPDATE, + modifiedAt: new Date(), + }, + { + channel_code: '97735020584_04', + createdAt: new Date('2023-05-04T17:52:33.993Z'), + wrapperStatus: WrapperStatusEnum.TO_FIX, + modifiedAt: new Date(), + }, + { + channel_code: '97735020584_05', + createdAt: new Date('2023-05-04T17:52:33.993Z'), + wrapperStatus: WrapperStatusEnum.TO_FIX_UPDATE, + modifiedAt: new Date(), + }, + ], }; export const mockedChannelDetail = (channelId: string): ChannelDetailsResource => ({ - agid: true, - broker_description: 'broker_description', - broker_psp_code: 'broker_psp_code', - card_chart: true, - channel_code: channelId, - digital_stamp_brand: true, - enabled: false, - flag_io: true, - ip: 'ip', - new_fault_code: true, - new_password: 'new_password', - nmp_service: 'npm_service', - on_us: true, - password: 'password', - payment_model: undefined, - payment_types: mockedPaymentTypes?.payment_types?.map((e) => e.payment_type ?? "") ?? [], - port: 8080, - primitive_version: 1, - protocol: ProtocolEnum.HTTPS, - proxy_enabled: true, - proxy_host: 'proxy_host', - proxy_password: 'proxy_password', - proxy_port: 8080, - proxy_username: 'proxy_username', - recovery: true, - rt_push: true, - serv_plugin: 'serv_plugin', - service: 'service', - target_host: 'target_host', - target_path: 'target_path', - target_port: 8080, - thread_number: 1, - timeout_a: 1000, - timeout_b: 2000, - timeout_c: 3000, + agid: true, + broker_description: 'broker_description', + broker_psp_code: 'broker_psp_code', + card_chart: true, + channel_code: channelId, + digital_stamp_brand: true, + enabled: false, + flag_io: true, + ip: 'ip', + new_fault_code: true, + new_password: 'new_password', + nmp_service: 'npm_service', + on_us: true, + password: 'password', + payment_model: undefined, + payment_types: mockedPaymentTypes?.payment_types?.map((e) => e.payment_type ?? '') ?? [], + port: 8080, + primitive_version: 1, + protocol: ProtocolEnum.HTTPS, + proxy_enabled: true, + proxy_host: 'proxy_host', + proxy_password: 'proxy_password', + proxy_port: 8080, + proxy_username: 'proxy_username', + recovery: true, + rt_push: true, + serv_plugin: 'serv_plugin', + service: 'service', + target_host: 'target_host', + target_path: 'target_path', + target_port: 8080, + thread_number: 1, + timeout_a: 1000, + timeout_b: 2000, + timeout_c: 3000, +}); + +export const mockedChannelDetailWithNote = ( + channelId: string, + note: string +): ChannelDetailsResource => ({ + agid: true, + broker_description: 'broker_description', + broker_psp_code: 'broker_psp_code', + card_chart: true, + channel_code: channelId, + digital_stamp_brand: true, + enabled: false, + flag_io: true, + ip: 'ip', + new_fault_code: true, + new_password: 'new_password', + nmp_service: 'npm_service', + on_us: true, + password: 'password', + payment_model: undefined, + payment_types: mockedPaymentTypes?.payment_types?.map((e) => e.payment_type ?? '') ?? [], + port: 8080, + primitive_version: 1, + protocol: ProtocolEnum.HTTPS, + proxy_enabled: true, + proxy_host: 'proxy_host', + proxy_password: 'proxy_password', + proxy_port: 8080, + proxy_username: 'proxy_username', + recovery: true, + rt_push: true, + serv_plugin: 'serv_plugin', + service: 'service', + target_host: 'target_host', + target_path: 'target_path', + target_port: 8080, + thread_number: 1, + timeout_a: 1000, + timeout_b: 2000, + timeout_c: 3000, + note: note, }); export const mockedChannelPSPs: ChannelPspListResource = { - payment_service_providers: [ - { - psp_code: '14847241001', - business_name: 'PSP S.p.A.', - enabled: true, - payment_types: ['MYBK'], - tax_code: 'AAAAAAAA78AAAAA3' - }, - { - psp_code: '14847241002', - business_name: 'PSP2 S.p.A.', - enabled: true, - payment_types: ['PPAY'], + payment_service_providers: [ + { + psp_code: '14847241001', + business_name: 'PSP S.p.A.', + enabled: true, + payment_types: ['MYBK'], + tax_code: 'AAAAAAAA78AAAAA3', + }, + { + psp_code: '14847241002', + business_name: 'PSP2 S.p.A.', + enabled: true, + payment_types: ['PPAY'], - tax_code: 'AAAAAAAA78AAAAA4' - }, - { - psp_code: '14847241003', - business_name: 'PSP3 S.p.A.', - enabled: false, - payment_types: ['STP'], - tax_code: 'AAAAAAAA78AAAAA5' - }, - { - psp_code: '14847241004', - business_name: 'PSP4 S.p.A.', - enabled: false, - payment_types: ['STP'], - tax_code: 'AAAAAAAA78AAAAA6' - }, - { - psp_code: '14847241005', - business_name: 'PSP5 S.p.A.', - enabled: true, - payment_types: ['STP'], - tax_code: 'AAAAAAAA78AAAAA7' - }, - ], - page_info: { - page: 0, - limit: 5, - items_found: 8, - total_pages: 2, + tax_code: 'AAAAAAAA78AAAAA4', + }, + { + psp_code: '14847241003', + business_name: 'PSP3 S.p.A.', + enabled: false, + payment_types: ['STP'], + tax_code: 'AAAAAAAA78AAAAA5', }, + { + psp_code: '14847241004', + business_name: 'PSP4 S.p.A.', + enabled: false, + payment_types: ['STP'], + tax_code: 'AAAAAAAA78AAAAA6', + }, + { + psp_code: '14847241005', + business_name: 'PSP5 S.p.A.', + enabled: true, + payment_types: ['STP'], + tax_code: 'AAAAAAAA78AAAAA7', + }, + ], + page_info: { + page: 0, + limit: 5, + items_found: 8, + total_pages: 2, + }, }; export const mockedChannelPSPsPage2: ChannelPspListResource = { - payment_service_providers: [ - { - psp_code: '14847241006', - business_name: 'PSP6 S.p.A.', - enabled: true, - payment_types: ['MYBK'], - tax_code: 'AAAAAAAA78AAAAA8' - }, - { - psp_code: '14847241007', - business_name: 'PSP7 S.p.A.', - enabled: true, - payment_types: ['PPAY'], - tax_code: 'AAAAAAAA78AAAAA9' - }, - { - psp_code: '14847241008', - business_name: 'PSP8 S.p.A.', - enabled: true, - payment_types: ['STP'], - tax_code: 'AAAAAAAA78AAAAA2' - }, - ], - page_info: { - page: 1, - limit: 5, - items_found: 8, - total_pages: 2, + payment_service_providers: [ + { + psp_code: '14847241006', + business_name: 'PSP6 S.p.A.', + enabled: true, + payment_types: ['MYBK'], + tax_code: 'AAAAAAAA78AAAAA8', + }, + { + psp_code: '14847241007', + business_name: 'PSP7 S.p.A.', + enabled: true, + payment_types: ['PPAY'], + tax_code: 'AAAAAAAA78AAAAA9', + }, + { + psp_code: '14847241008', + business_name: 'PSP8 S.p.A.', + enabled: true, + payment_types: ['STP'], + tax_code: 'AAAAAAAA78AAAAA2', }, + ], + page_info: { + page: 1, + limit: 5, + items_found: 8, + total_pages: 2, + }, }; export const channelCode: ChannelCodeResource = { - channel_code: '1231231231', + channel_code: '1231231231', }; -export const getChannels = (_page: number): Promise => - new Promise((resolve) => resolve(mockedChannels)); +export const getChannels = (_page: number): Promise => + Promise.resolve(mockedChannels); export const getChannelsMerged = ( - _page: number, - _brokerCode: string, - _stationcode?: string, - _limit?: number, - _sorting?: string -): Promise => new Promise((resolve) => resolve(mockedChannelsMerged)); + _page: number, + _brokerCode: string, + _stationcode?: string, + _limit?: number, + _sorting?: string +): Promise => Promise.resolve(mockedChannelsMerged); export const getChannelCode = (_taxCode: string): Promise => - new Promise((resolve) => resolve(channelCode)); + Promise.resolve(channelCode); export const getChannelDetail = (channelcode: string): Promise => - new Promise((resolve) => resolve(mockedChannelDetail(channelcode))); + Promise.resolve(mockedChannelDetail(channelcode)); export const getPSPChannels = (_taxCode: string): Promise => - new Promise((resolve) => resolve(channelEnabled(mockedPSPChannels))); + Promise.resolve(channelEnabled(mockedPSPChannels)); export const createChannel = (_channel: ChannelOnCreation): Promise => - new Promise((resolve) => { - // @ts-ignore - resolve(mockedChannel); - }); + new Promise((resolve) => { + // @ts-ignore + resolve(mockedChannel); + }); export const updateChannel = ( - _code: string, - _channel: ChannelOnCreation + _code: string, + _channel: ChannelOnCreation ): Promise => - new Promise((resolve) => { - // @ts-ignore - resolve(mockedChannel); - }); + new Promise((resolve) => { + // @ts-ignore + resolve(mockedChannel); + }); export const getChannelPSPs = (page: number): Promise => - new Promise((resolve) => resolve(page === 0 ? mockedChannelPSPs : mockedChannelPSPsPage2)); + Promise.resolve(page === 0 ? mockedChannelPSPs : mockedChannelPSPsPage2); -export const mockedPaymentTypesResource: PspChannelPaymentTypesResource = {payment_types: ['ptype_test']}; +export const mockedPaymentTypesResource: PspChannelPaymentTypesResource = { + payment_types: ['ptype_test'], +}; export const associatePSPtoChannel = ( - _channelcode: string, - _pspcode: string, - _payment_type: PspChannelPaymentTypes -): Promise => - new Promise((resolve) => resolve(mockedPaymentTypesResource)); + _channelcode: string, + _pspcode: string, + _payment_type: PspChannelPaymentTypes +): Promise => Promise.resolve(mockedPaymentTypesResource); -export const dissociatePSPfromChannel = (_channelcode: string, _pspTaxCode: string): Promise => - new Promise((resolve) => resolve()); +export const dissociatePSPfromChannel = ( + _channelcode: string, + _pspTaxCode: string +): Promise => new Promise((resolve) => resolve()); export const createWrapperChannel = ( - _channel: WrapperChannelDetailsDto, - _validationUrl: string -): Promise => new Promise((resolve) => resolve(mockedWrapperChannel)); + _channel: WrapperChannelDetailsDto, + _validationUrl: string +): Promise => Promise.resolve(mockedWrapperChannel); export const updateWrapperChannel = ( - _channel: ChannelDetailsDto, - _validationUrl: string -): Promise => new Promise((resolve) => resolve(mockedWrapperChannel)); + _channel: ChannelDetailsDto, + _validationUrl: string +): Promise => Promise.resolve(mockedWrapperChannel); export const getWrapperChannel = (pspCode: string): Promise => - new Promise((resolve) => resolve(channelWrapperMockedGet(pspCode))); + Promise.resolve(channelWrapperMockedGet(pspCode)); + +export const getWfespPlugins = (): Promise => Promise.resolve(mockedWfespPlugIn); -export const getWfespPlugins = (): Promise => - new Promise((resolve) => resolve(mockedWfespPlugIn)); +export const updateWrapperChannelWithOperatorReview = ( + channelcode: string, + note: string +): Promise => + new Promise((resolve) => resolve(mockedChannelDetailWithNote(channelcode, note))); diff --git a/src/services/__mocks__/stationService.ts b/src/services/__mocks__/stationService.ts index a532b65ab..7668fd572 100644 --- a/src/services/__mocks__/stationService.ts +++ b/src/services/__mocks__/stationService.ts @@ -78,6 +78,14 @@ export const mockedFullStation: StationDetailResource = { targetHost: '1www', targetPort: 11, targetPath: 'www', + targetHostPof: 'hostPof', + targetPathPof: 'pathPof', + targetPortPof: 456, + isConnectionSync: true, + proxyEnabled: false, + proxyHost: 'proxyHost', + proxyPort: 888, + proxyUsername: 'username', primitiveVersion: 1, }; diff --git a/src/services/__tests__/channelService.test.ts b/src/services/__tests__/channelService.test.ts index 7bf4a6ef9..00321ba51 100644 --- a/src/services/__tests__/channelService.test.ts +++ b/src/services/__tests__/channelService.test.ts @@ -1,337 +1,391 @@ +import { BackofficeApi } from '../../api/BackofficeClient.ts'; +import { Redirect_protocolEnum } from '../../api/generated/portal/WrapperChannelDetailsDto.ts'; +import { WrapperChannelDetailsResource } from '../../api/generated/portal/WrapperChannelDetailsResource.ts'; +import { ConfigurationStatus } from '../../model/Station.tsx'; +import { channelCode } from '../__mocks__/channelService'; import { - channelEnabled, - mockedChannel, - mockedChannelDetail, - mockedChannelPSPs, - mockedChannelPSPsPage2, - mockedChannels, - mockedChannelsMerged, - mockedPSPChannels, - mockedPaymentTypesResource, - mockedWfespPlugIn, - mockedWrapperChannel, + channelEnabled, + mockedChannel, + mockedChannelDetail, + mockedChannelDetailWithNote, + mockedChannelPSPs, + mockedChannelPSPsPage2, + mockedChannels, + mockedChannelsMerged, + mockedPSPChannels, + mockedPaymentTypesResource, + mockedWfespPlugIn, + mockedWrapperChannel, } from '../__mocks__/channelService.ts'; +import { channelWrapperMockedGet } from '../__mocks__/institutionsService.ts'; import { - associatePSPtoChannel, - createChannel, - createWrapperChannelDetails, - dissociatePSPfromChannel, - getChannelCode, - getChannelDetail, - getChannelPSPs, - getChannels, - getChannelsIdAssociatedToPSP, - getChannelsMerged, - getPSPChannels, - getWfespPlugins, - getWrapperEntities, - updateChannel, - updateWrapperChannelDetailsByOpt, - updateWrapperChannelDetailsToCheck, - updateWrapperChannelDetailsToCheckUpdate, + associatePSPtoChannel, + createChannel, + createWrapperChannelDetails, + dissociatePSPfromChannel, + getChannelCode, + getChannelDetail, + getChannelPSPs, + getChannels, + getChannelsIdAssociatedToPSP, + getChannelsMerged, + getPSPChannels, + getWfespPlugins, + getWrapperEntities, + updateChannel, + updateWrapperChannelDetailsByOpt, + updateWrapperChannelDetailsToCheck, + updateWrapperChannelWithOperatorReview, } from '../channelService.ts'; -import {channelCode} from '../__mocks__/channelService'; -import {channelWrapperMockedGet} from '../__mocks__/institutionsService.ts'; -import {Redirect_protocolEnum} from '../../api/generated/portal/WrapperChannelDetailsDto.ts'; -import {BackofficeApi} from '../../api/BackofficeClient.ts'; -import {WrapperChannelDetailsResource} from '../../api/generated/portal/WrapperChannelDetailsResource.ts'; describe('ChannelService test mocked', () => { - test('Test getChannels', async () => { - const response = await getChannels(0); - expect(response).toMatchObject(mockedChannels); - }); - test('Test getChannelsMerged', async () => { - const response = await getChannelsMerged(0, 'brokerCode'); - expect(response).toMatchObject(mockedChannelsMerged); - }); - test('Test getChannelDetail', async () => { - const response = await getChannelDetail('channelId'); - expect(response).toMatchObject(mockedChannelDetail('channelId')); - }); - test('Test getPSPChannels', async () => { - const response = await getPSPChannels('pspTaxCode'); - expect(response).toMatchObject(channelEnabled(mockedPSPChannels)); - }); - test('Test getChannelsIdAssociatedToPSP', async () => { - const response = await getChannelsIdAssociatedToPSP(0, 'brokerCode'); - expect(response).toMatchObject(mockedChannelsMerged!.channels!.map((el) => el!.channel_code)); - }); - test('Test getWfespPlugins', async () => { - const response = await getWfespPlugins(); - expect(response).toMatchObject(mockedWfespPlugIn); - }); - test('Test createChannel', async () => { - const response = await createChannel({ - validationUrl: '', - targetUnion: '', - newConnection: '', - proxyUnion: '', - }); - expect(response).toMatchObject(mockedChannel); - }); - test('Test updateChannel', async () => { - const response = await updateChannel('channelCode', { - validationUrl: '', - targetUnion: '', - newConnection: '', - proxyUnion: '', - }); - expect(response).toMatchObject(mockedChannel); - }); - test('Test getChannelCode', async () => { - const response = await getChannelCode('pspCode'); - expect(response).toMatchObject(channelCode); - }); - test('Test getChannelPSPs page 0', async () => { - const response = await getChannelPSPs('channelCode', 'pspName', 0); - expect(response).toMatchObject(mockedChannelPSPs); - }); - test('Test getChannelPSPs page 1', async () => { - const response = await getChannelPSPs('channelCode', 'pspName', 1); - expect(response).toMatchObject(mockedChannelPSPsPage2); - }); - test('Test associatePSPtoChannel', async () => { - const response = await associatePSPtoChannel('channelCode', 'taxCode', { - payment_types: [], - }); - expect(response).toMatchObject(mockedPaymentTypesResource); - }); - test('Test dissociatePSPfromChannel', async () => { - expect(dissociatePSPfromChannel('channelCode', 'pspTaxCode')).resolves.not.toThrow(); - }); - test('Test getWrapperEntities', async () => { - const response = await getWrapperEntities('pspCode'); - expect(response).toMatchObject(channelWrapperMockedGet('pspCode')); - }); - test('Test createWrapperChannelDetails', async () => { - const response = await createWrapperChannelDetails( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - ); - expect(response).toMatchObject(mockedWrapperChannel); - }); - test('Test updateWrapperChannelDetailsToCheck', async () => { - const response = await updateWrapperChannelDetailsToCheck( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - ); - expect(response).toMatchObject(mockedWrapperChannel); - }); - test('Test updateWrapperChannelDetailsToCheckUpdate', async () => { - const response = await updateWrapperChannelDetailsToCheckUpdate( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - ); - expect(response).toMatchObject(mockedWrapperChannel); - }); - test('Test updateWrapperChannelDetailsByOpt', async () => { - const response = await updateWrapperChannelDetailsByOpt( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - ); - expect(response).toMatchObject(mockedWrapperChannel); - }); + test('Test getChannels', async () => { + const response = await getChannels({ + status: ConfigurationStatus.ACTIVE, + channelCode: 'channelId', + brokerCode: 'brokerCode', + limit: 10, + page: 0, + }); + expect(response).toMatchObject(mockedChannels); + }); + test('Test getChannelsMerged', async () => { + const response = await getChannelsMerged(0, 'brokerCode'); + expect(response).toMatchObject(mockedChannelsMerged); + }); + test('Test getChannelDetail', async () => { + const response = await getChannelDetail('channelId'); + expect(response).toMatchObject(mockedChannelDetail('channelId')); + }); + test('Test getPSPChannels', async () => { + const response = await getPSPChannels('pspTaxCode'); + expect(response).toMatchObject(channelEnabled(mockedPSPChannels)); + }); + test('Test getChannelsIdAssociatedToPSP', async () => { + const response = await getChannelsIdAssociatedToPSP(0, 'brokerCode'); + expect(response).toMatchObject(mockedChannelsMerged!.channels!.map((el) => el!.channel_code)); + }); + test('Test getWfespPlugins', async () => { + const response = await getWfespPlugins(); + expect(response).toMatchObject(mockedWfespPlugIn); + }); + test('Test createChannel', async () => { + const response = await createChannel({ + validationUrl: '', + targetUnion: '', + newConnection: '', + proxyUnion: '', + }); + expect(response).toMatchObject(mockedChannel); + }); + test('Test updateChannel', async () => { + const response = await updateChannel('channelCode', { + validationUrl: '', + targetUnion: '', + newConnection: '', + proxyUnion: '', + }); + expect(response).toMatchObject(mockedChannel); + }); + test('Test getChannelCode', async () => { + const response = await getChannelCode('pspCode'); + expect(response).toMatchObject(channelCode); + }); + test('Test getChannelPSPs page 0', async () => { + const response = await getChannelPSPs('channelCode', 'pspName', 0); + expect(response).toMatchObject(mockedChannelPSPs); + }); + test('Test getChannelPSPs page 1', async () => { + const response = await getChannelPSPs('channelCode', 'pspName', 1); + expect(response).toMatchObject(mockedChannelPSPsPage2); + }); + test('Test associatePSPtoChannel', async () => { + const response = await associatePSPtoChannel('channelCode', 'taxCode', { + payment_types: [], + }); + expect(response).toMatchObject(mockedPaymentTypesResource); + }); + test('Test dissociatePSPfromChannel', async () => { + expect(dissociatePSPfromChannel('channelCode', 'pspTaxCode')).resolves.not.toThrow(); + }); + test('Test getWrapperEntities', async () => { + const response = await getWrapperEntities('pspCode'); + expect(response).toMatchObject(channelWrapperMockedGet('pspCode')); + }); + test('Test createWrapperChannelDetails', async () => { + const response = await createWrapperChannelDetails( + { + broker_description: '', + broker_psp_code: '', + channel_code: '', + payment_types: [], + redirect_protocol: Redirect_protocolEnum.HTTPS, + target_host: '', + target_path: '', + target_port: 0, + validationUrl: '', + }, + 'validationUrl' + ); + expect(response).toMatchObject(mockedWrapperChannel); + }); + test('Test updateWrapperChannelDetailsToCheck', async () => { + const response = await updateWrapperChannelDetailsToCheck({ + channelCode: 'channelCode', + channel: { + broker_description: '', + broker_psp_code: '', + channel_code: '', + payment_types: [], + redirect_protocol: Redirect_protocolEnum.HTTPS, + target_host: '', + target_path: '', + target_port: 0, + validationUrl: '', + }, + validationUrl: 'validationUrl', + }); + expect(response).toMatchObject(mockedWrapperChannel); + }); + test('Test updateWrapperChannelDetailsByOpt', async () => { + const response = await updateWrapperChannelDetailsByOpt( + { + broker_description: '', + broker_psp_code: '', + channel_code: '', + payment_types: [], + redirect_protocol: Redirect_protocolEnum.HTTPS, + target_host: '', + target_path: '', + target_port: 0, + validationUrl: '', + }, + 'validationUrl' + ); + expect(response).toMatchObject(mockedWrapperChannel); + }); + test('Test updateWrapperChannelWithOperatorReview', async () => { + const response = await updateWrapperChannelWithOperatorReview({ + channelCode: 'channelCode', + brokerPspCode: 'brokerPspCode', + note: 'note', + }); + expect(response).toMatchObject(mockedChannelDetailWithNote('channelCode', 'note')); + }); }); describe('ChannelService test client', () => { - const OLD_ENV = process.env; - beforeEach(() => { - jest.resetModules(); - process.env = {...OLD_ENV, REACT_APP_API_MOCK_BACKOFFICE: "false"}; - }); + const OLD_ENV = process.env; + beforeEach(() => { + jest.resetModules(); + process.env = { ...OLD_ENV, REACT_APP_API_MOCK_BACKOFFICE: 'false' }; + }); - afterAll(() => { - process.env = OLD_ENV; - }); + afterAll(() => { + process.env = OLD_ENV; + }); - test('Test getChannels', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getChannels").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(getChannels(0)).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getChannelsMerged', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getChannelsMerged").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(getChannelsMerged(0, 'brokerCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getChannelDetail', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getChannelDetail").mockReturnValue(new Promise((resolve) => resolve(mockedChannelDetail("channelCode")))); - expect(getChannelDetail('channelId')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getPSPChannels', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getPSPChannels").mockReturnValue(new Promise((resolve) => resolve(channelEnabled(mockedPSPChannels)))); - expect(getPSPChannels('pspTaxCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getChannelsIdAssociatedToPSP', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getChannelsMerged").mockReturnValue(new Promise((resolve) => resolve(mockedChannelsMerged))); - expect(getChannelsIdAssociatedToPSP(0, 'brokerCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getWfespPlugins', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getWfespPlugins").mockReturnValue(new Promise((resolve) => resolve(mockedWfespPlugIn))); - expect(getWfespPlugins()).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test createChannel', async () => { - const spyOn = jest.spyOn(BackofficeApi, "createChannel").mockReturnValue(new Promise((resolve) => resolve(mockedChannel as WrapperChannelDetailsResource))); - expect(createChannel({ - validationUrl: '', - targetUnion: '', - newConnection: '', - proxyUnion: '', - })).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateChannel', async () => { - const spyOn = jest.spyOn(BackofficeApi, "updateChannel").mockReturnValue(new Promise((resolve) => resolve(mockedChannel as WrapperChannelDetailsResource))); - expect(updateChannel('channelCode', { - validationUrl: '', - targetUnion: '', - newConnection: '', - proxyUnion: '', - })).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getChannelCode', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getChannelCode").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(getChannelCode('pspCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getChannelPSPs', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getChannelPSPs").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(getChannelPSPs('channelCode', 'pspName', 0)).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test associatePSPtoChannel', async () => { - const spyOn = jest.spyOn(BackofficeApi, "associatePSPtoChannel").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(associatePSPtoChannel('channelCode', 'taxCode', { - payment_types: [], - })).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test dissociatePSPfromChannel', async () => { - const spyOn = jest.spyOn(BackofficeApi, "dissociatePSPfromChannel").mockReturnValue(new Promise((resolve) => resolve())); - expect(dissociatePSPfromChannel('channelCode', 'pspTaxCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getWrapperEntities', async () => { - const spyOn = jest.spyOn(BackofficeApi, "getWrapperEntities").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(getWrapperEntities('pspCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test createWrapperChannelDetails', async () => { - const spyOn = jest.spyOn(BackofficeApi, "createWrapperChannelDetails").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(createWrapperChannelDetails( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - )).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateWrapperChannelDetailsToCheck', async () => { - const spyOn = jest.spyOn(BackofficeApi, "updateWrapperChannelDetailsToCheck").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(updateWrapperChannelDetailsToCheck( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - )).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateWrapperChannelDetailsToCheckUpdate', async () => { - const spyOn = jest.spyOn(BackofficeApi, "updateWrapperChannelDetailsToCheckUpdate").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(updateWrapperChannelDetailsToCheckUpdate( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - )).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateWrapperChannelDetailsByOpt', async () => { - const spyOn = jest.spyOn(BackofficeApi, "updateWrapperChannelDetailsByOpt").mockReturnValue(new Promise((resolve) => resolve({}))); - expect(updateWrapperChannelDetailsByOpt( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - )).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); + test('Test getChannels', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getChannels') + .mockReturnValue(Promise.resolve(mockedChannels)); + expect( + getChannels({ + status: ConfigurationStatus.ACTIVE, + channelCode: 'channelId', + brokerCode: 'brokerCode', + limit: 10, + page: 0, + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getChannelsMerged', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getChannelsMerged') + .mockReturnValue(Promise.resolve(mockedChannelsMerged)); + expect(getChannelsMerged(0, 'brokerCode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getChannelDetail', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getChannelDetail') + .mockReturnValue(new Promise((resolve) => resolve(mockedChannelDetail('channelCode')))); + expect(getChannelDetail('channelId')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getPSPChannels', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getPSPChannels') + .mockReturnValue(new Promise((resolve) => resolve(channelEnabled(mockedPSPChannels)))); + expect(getPSPChannels('pspTaxCode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getChannelsIdAssociatedToPSP', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getChannelsMerged') + .mockReturnValue(new Promise((resolve) => resolve(mockedChannelsMerged))); + expect(getChannelsIdAssociatedToPSP(0, 'brokerCode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getWfespPlugins', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getWfespPlugins') + .mockReturnValue(new Promise((resolve) => resolve(mockedWfespPlugIn))); + expect(getWfespPlugins()).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test createChannel', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'createChannel') + .mockReturnValue( + new Promise((resolve) => resolve(mockedChannel as WrapperChannelDetailsResource)) + ); + expect( + createChannel({ + validationUrl: '', + targetUnion: '', + newConnection: '', + proxyUnion: '', + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test updateChannel', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'updateChannel') + .mockReturnValue( + new Promise((resolve) => resolve(mockedChannel as WrapperChannelDetailsResource)) + ); + expect( + updateChannel('channelCode', { + validationUrl: '', + targetUnion: '', + newConnection: '', + proxyUnion: '', + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getChannelCode', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getChannelCode') + .mockReturnValue(new Promise((resolve) => resolve({}))); + expect(getChannelCode('pspCode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getChannelPSPs', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getChannelPSPs') + .mockReturnValue(new Promise((resolve) => resolve({}))); + expect(getChannelPSPs('channelCode', 'pspName', 0)).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test associatePSPtoChannel', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'associatePSPtoChannel') + .mockReturnValue(Promise.resolve(mockedPaymentTypesResource)); + expect( + associatePSPtoChannel('channelCode', 'taxCode', { + payment_types: [], + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test dissociatePSPfromChannel', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'dissociatePSPfromChannel') + .mockReturnValue(new Promise((resolve) => resolve())); + expect(dissociatePSPfromChannel('channelCode', 'pspTaxCode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getWrapperEntities', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getWrapperEntities') + .mockReturnValue(new Promise((resolve) => resolve({}))); + expect(getWrapperEntities('pspCode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test createWrapperChannelDetails', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'createWrapperChannelDetails') + .mockReturnValue(new Promise((resolve) => resolve({}))); + expect( + createWrapperChannelDetails( + { + broker_description: '', + broker_psp_code: '', + channel_code: '', + payment_types: [], + redirect_protocol: Redirect_protocolEnum.HTTPS, + target_host: '', + target_path: '', + target_port: 0, + validationUrl: '', + }, + 'validationUrl' + ) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test updateWrapperChannelDetailsToCheck', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'updateWrapperChannelDetailsToCheck') + .mockReturnValue(new Promise((resolve) => resolve({}))); + expect( + updateWrapperChannelDetailsToCheck({ + channelCode: 'channelCode', + channel: { + broker_description: '', + broker_psp_code: '', + channel_code: '', + payment_types: [], + redirect_protocol: Redirect_protocolEnum.HTTPS, + target_host: '', + target_path: '', + target_port: 0, + validationUrl: '', + }, + validationUrl: 'validationUrl', + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test updateWrapperChannelDetailsByOpt', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'updateWrapperChannelDetailsByOpt') + .mockReturnValue(new Promise((resolve) => resolve({}))); + expect( + updateWrapperChannelDetailsByOpt( + { + broker_description: '', + broker_psp_code: '', + channel_code: '', + payment_types: [], + redirect_protocol: Redirect_protocolEnum.HTTPS, + target_host: '', + target_path: '', + target_port: 0, + validationUrl: '', + }, + 'validationUrl' + ) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test updateWrapperChannelWithOperatorReview', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'updateWrapperChannelWithOperatorReview') + .mockReturnValue( + new Promise((resolve) => resolve(mockedChannelDetailWithNote('channelCode', 'note'))) + ); + expect( + updateWrapperChannelWithOperatorReview({ + channelCode: 'channelCode', + brokerPspCode: 'brokerPspCode', + note: 'note', + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); }); diff --git a/src/services/channelService.ts b/src/services/channelService.ts index 1e18c2765..a889ad641 100644 --- a/src/services/channelService.ts +++ b/src/services/channelService.ts @@ -1,233 +1,278 @@ -import {ChannelCodeResource} from '../api/generated/portal/ChannelCodeResource'; -import {ChannelDetailsDto} from '../api/generated/portal/ChannelDetailsDto'; -import {ChannelDetailsResource} from '../api/generated/portal/ChannelDetailsResource'; -import {ChannelPspListResource} from '../api/generated/portal/ChannelPspListResource'; -import {ChannelsResource} from '../api/generated/portal/ChannelsResource'; -import {PspChannelPaymentTypes} from '../api/generated/portal/PspChannelPaymentTypes'; -import {PspChannelPaymentTypesResource} from '../api/generated/portal/PspChannelPaymentTypesResource'; -import {PspChannelsResource} from '../api/generated/portal/PspChannelsResource'; -import {WrapperChannelsResource} from '../api/generated/portal/WrapperChannelsResource'; -import {WrapperChannelDetailsDto} from '../api/generated/portal/WrapperChannelDetailsDto'; -import {BackofficeApi} from '../api/BackofficeClient'; -import {WfespPluginConfs} from '../api/generated/portal/WfespPluginConfs'; -import {ChannelOnCreation} from '../model/Channel'; -import {WrapperEntities} from '../api/generated/portal/WrapperEntities'; +import { BackofficeApi } from '../api/BackofficeClient'; +import { ChannelCodeResource } from '../api/generated/portal/ChannelCodeResource'; +import { ChannelDetailsDto } from '../api/generated/portal/ChannelDetailsDto'; +import { ChannelDetailsResource } from '../api/generated/portal/ChannelDetailsResource'; +import { ChannelPspListResource } from '../api/generated/portal/ChannelPspListResource'; +import { PspChannelPaymentTypes } from '../api/generated/portal/PspChannelPaymentTypes'; +import { PspChannelPaymentTypesResource } from '../api/generated/portal/PspChannelPaymentTypesResource'; +import { PspChannelsResource } from '../api/generated/portal/PspChannelsResource'; +import { WfespPluginConfs } from '../api/generated/portal/WfespPluginConfs'; +import { WrapperChannelDetailsDto } from '../api/generated/portal/WrapperChannelDetailsDto'; +import { WrapperChannelsResource } from '../api/generated/portal/WrapperChannelsResource'; +import { WrapperEntities } from '../api/generated/portal/WrapperEntities'; +import { ChannelOnCreation } from '../model/Channel'; +import { ConfigurationStatus } from '../model/Station'; import { - getChannels as getChannelsMocked, - getChannelsMerged as getChannelsMergedMocked, - getPSPChannels as getPSPChannelsMocked, - createChannel as createChannelMocked, - updateChannel as updateChannelMocked, - getChannelDetail as getChannelDetailMocked, - getChannelPSPs as getChannelPSPsMocked, - getChannelCode as getChannelCodeMocked, - associatePSPtoChannel as associatePSPtoChannelMocked, - dissociatePSPfromChannel as dissociatePSPfromChannelMocked, - getWrapperChannel, - createWrapperChannel, - updateWrapperChannel, - getWfespPlugins as mockedGetWfespPlugins, + associatePSPtoChannel as associatePSPtoChannelMocked, + createChannel as createChannelMocked, + createWrapperChannel, + dissociatePSPfromChannel as dissociatePSPfromChannelMocked, + getChannelCode as getChannelCodeMocked, + getChannelDetail as getChannelDetailMocked, + getChannelPSPs as getChannelPSPsMocked, + getChannelsMerged as getChannelsMergedMocked, + getChannels as getChannelsMocked, + getPSPChannels as getPSPChannelsMocked, + getWrapperChannel, + getWfespPlugins as mockedGetWfespPlugins, + updateChannel as updateChannelMocked, + updateWrapperChannel, + updateWrapperChannelWithOperatorReview as updateWrapperChannelWithOperatorReviewMocked, } from './__mocks__/channelService'; // /channels endpoint -export const getChannels = (page: number): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelsMocked(page); - } else { - return BackofficeApi.getChannels(page).then((resources) => resources); - } +export const getChannels = ({ + status, + channelCode, + brokerCode, + limit, + page, +}: { + status: ConfigurationStatus; + channelCode: string; + brokerCode: string; + limit?: number; + page: number; +}): Promise => { + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getChannelsMocked(page); + } else { + return BackofficeApi.getChannels({ status, brokerCode, channelCode, limit, page }).then( + (resources) => resources + ); + } }; export const getChannelsMerged = ( - page: number, - brokerCode: string, - channelcodefilter?: string, - limit?: number, - sorting?: string + page: number, + brokerCode: string, + channelcodefilter?: string, + limit?: number, + sorting?: string ): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelsMergedMocked(page, brokerCode, channelcodefilter, limit, sorting); - } else { - return BackofficeApi.getChannelsMerged(page, brokerCode, channelcodefilter, limit, sorting).then( - (resources) => resources - ); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getChannelsMergedMocked(page, brokerCode, channelcodefilter, limit, sorting); + } else { + return BackofficeApi.getChannelsMerged( + page, + brokerCode, + channelcodefilter, + limit, + sorting + ).then((resources) => resources); + } }; export const getChannelDetail = (channelcode: string): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelDetailMocked(channelcode); - } else { - return BackofficeApi.getChannelDetail(channelcode).then((resources) => resources); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getChannelDetailMocked(channelcode); + } else { + return BackofficeApi.getChannelDetail(channelcode).then((resources) => resources); + } }; export const getPSPChannels = (taxCode: string): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getPSPChannelsMocked(taxCode); - } else { - return BackofficeApi.getPSPChannels(taxCode).then((resources) => resources); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getPSPChannelsMocked(taxCode); + } else { + return BackofficeApi.getPSPChannels(taxCode).then((resources) => resources); + } }; export const getChannelsIdAssociatedToPSP = ( - page: number, - brokerCode: string, - channelcodefilter?: string, - limit?: number, - sorting?: string + page: number, + brokerCode: string, + channelcodefilter?: string, + limit?: number, + sorting?: string ): Promise> => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelsMergedMocked(page, brokerCode, channelcodefilter, limit, sorting).then( - (resources) => - resources.channels!.map((e) => (e.channel_code !== undefined ? e.channel_code : '')) - ); - } else { - return BackofficeApi.getChannelsMerged(page, brokerCode, channelcodefilter, limit, sorting).then( - (resources) => - resources.channels!.map((e) => (e.channel_code !== undefined ? e.channel_code : '')) - ); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getChannelsMergedMocked(page, brokerCode, channelcodefilter, limit, sorting).then( + (resources) => + resources.channels!.map((e) => (e.channel_code !== undefined ? e.channel_code : '')) + ); + } else { + return BackofficeApi.getChannelsMerged( + page, + brokerCode, + channelcodefilter, + limit, + sorting + ).then((resources) => + resources.channels!.map((e) => (e.channel_code !== undefined ? e.channel_code : '')) + ); + } }; export const getWfespPlugins = (): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return mockedGetWfespPlugins(); - } else { - return BackofficeApi.getWfespPlugins().then((resources) => resources); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return mockedGetWfespPlugins(); + } else { + return BackofficeApi.getWfespPlugins().then((resources) => resources); + } }; export const createChannel = (channel: ChannelOnCreation): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return createChannelMocked(channel); - } else { - return BackofficeApi.createChannel(channel).then((resources) => resources); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return createChannelMocked(channel); + } else { + return BackofficeApi.createChannel(channel).then((resources) => resources); + } }; export const updateChannel = ( - code: string, - channel: ChannelOnCreation + code: string, + channel: ChannelOnCreation ): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateChannelMocked(code, channel); - } else { - return BackofficeApi.updateChannel(code, channel).then((resources) => resources); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return updateChannelMocked(code, channel); + } else { + return BackofficeApi.updateChannel(code, channel).then((resources) => resources); + } }; export const getChannelCode = (taxCode: string): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelCodeMocked(taxCode); - } else { - return BackofficeApi.getChannelCode(taxCode).then((resources) => resources); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getChannelCodeMocked(taxCode); + } else { + return BackofficeApi.getChannelCode(taxCode).then((resources) => resources); + } }; export const getChannelPSPs = ( - channelcode: string, - pspName: string, - page: number, - limit?: number + channelcode: string, + pspName: string, + page: number, + limit?: number ): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelPSPsMocked(page); - } else { - return BackofficeApi.getChannelPSPs(channelcode, pspName, page, limit).then((resources) => resources); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getChannelPSPsMocked(page); + } else { + return BackofficeApi.getChannelPSPs(channelcode, pspName, page, limit).then( + (resources) => resources + ); + } }; export const associatePSPtoChannel = ( - channelcode: string, - taxcode: string, - payment_type: PspChannelPaymentTypes + channelcode: string, + taxcode: string, + payment_type: PspChannelPaymentTypes ): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return associatePSPtoChannelMocked(channelcode, taxcode, payment_type); - } else { - return BackofficeApi.associatePSPtoChannel(channelcode, taxcode, payment_type).then( - (resources) => resources - ); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return associatePSPtoChannelMocked(channelcode, taxcode, payment_type); + } else { + return BackofficeApi.associatePSPtoChannel(channelcode, taxcode, payment_type).then( + (resources) => resources + ); + } }; -export const dissociatePSPfromChannel = (channelcode: string, pspTaxCode: string): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return dissociatePSPfromChannelMocked(channelcode, pspTaxCode); - } else { - return BackofficeApi.dissociatePSPfromChannel(channelcode, pspTaxCode).then((resources) => resources); - } +export const dissociatePSPfromChannel = ( + channelcode: string, + pspTaxCode: string +): Promise => { + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return dissociatePSPfromChannelMocked(channelcode, pspTaxCode); + } else { + return BackofficeApi.dissociatePSPfromChannel(channelcode, pspTaxCode).then( + (resources) => resources + ); + } }; export const getWrapperEntities = (pspCode: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getWrapperChannel(pspCode); - } else { - return BackofficeApi.getWrapperEntities(pspCode).then((resources) => resources); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getWrapperChannel(pspCode); + } else { + return BackofficeApi.getWrapperEntities(pspCode).then((resources) => resources); + } }; export const createWrapperChannelDetails = ( - channel: WrapperChannelDetailsDto, - validationUrl: string + channel: WrapperChannelDetailsDto, + validationUrl: string ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return createWrapperChannel(channel, validationUrl); - } else { - return BackofficeApi.createWrapperChannelDetails(channel, validationUrl).then( - (resources) => resources - ); - } -}; - -export const updateWrapperChannelDetailsToCheck = ( - channel: ChannelDetailsDto, - validationUrl: string -): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateWrapperChannel(channel, validationUrl); - } else { - return BackofficeApi.updateWrapperChannelDetailsToCheck(channel, validationUrl).then( - (resources) => resources - ); - } -}; - -export const updateWrapperChannelDetailsToCheckUpdate = ( - channel: ChannelDetailsDto, - validationUrl: string -): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateWrapperChannel(channel, validationUrl); - } else { - return BackofficeApi.updateWrapperChannelDetailsToCheckUpdate(channel, validationUrl).then( - (resources) => resources - ); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return createWrapperChannel(channel, validationUrl); + } else { + return BackofficeApi.createWrapperChannelDetails(channel, validationUrl).then( + (resources) => resources + ); + } +}; + +export const updateWrapperChannelDetailsToCheck = ({ + channelCode, + channel, + validationUrl, +}: { + channelCode: string; + channel: ChannelDetailsDto; + validationUrl: string; +}): Promise => { + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return updateWrapperChannel(channel, validationUrl); + } else { + return BackofficeApi.updateWrapperChannelDetailsToCheck({ + channelCode, + channel, + validationUrl, + }).then((resources) => resources); + } }; export const updateWrapperChannelDetailsByOpt = ( - channel: ChannelDetailsDto, - validationUrl: string + channel: ChannelDetailsDto, + validationUrl: string ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateWrapperChannel(channel, validationUrl); - } else { - return BackofficeApi.updateWrapperChannelDetailsByOpt(channel, validationUrl).then( - (resources) => resources - ); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return updateWrapperChannel(channel, validationUrl); + } else { + return BackofficeApi.updateWrapperChannelDetailsByOpt(channel, validationUrl).then( + (resources) => resources + ); + } +}; + +export const updateWrapperChannelWithOperatorReview = ({ + channelCode, + brokerPspCode, + note, +}: { + channelCode: string; + brokerPspCode: string; + note: string; +}): Promise => { + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return updateWrapperChannelWithOperatorReviewMocked(channelCode, note); + } else { + return BackofficeApi.updateWrapperChannelWithOperatorReview({ + channelCode, + brokerPspCode, + note, + }).then((resources) => resources); + } }; From 305195dc8ffcb41b60813ac14bf91eda8947f317 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Tue, 25 Jun 2024 08:42:33 +0000 Subject: [PATCH 08/73] Bump to version 1.26.0-3-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ac3fc829..5aeabb12c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.0-2-next", + "version": "1.26.0-3-next", "homepage": "ui", "private": true, "scripts": { From 8cdb6297d5f781bf048436691947cbfaf1955ee0 Mon Sep 17 00:00:00 2001 From: gioelemella <128155546+gioelemella@users.noreply.github.com> Date: Tue, 25 Jun 2024 17:02:45 +0200 Subject: [PATCH 09/73] [VAS-1123] feat: Remove unused Station and Channel API (#574) * [VAS-998] feat: introducing ops review from channel * [VAS-998] feat: Updated ops review modal management for channels * [VAS-997] changed channels page structured and integrated new getChannels API * [VAS-997] updated tests * [VAS-998] feat: Updated addEdit, details and tests * [VAS-998] feat: Updated tests, introduced common header to avoid duplicates * [VAS-998] feat: temporary rollback test * [VAS-998] feat: Update GetChannelAlert.test.tsx * [VAS-998] feat: Update ci_code_review.yml * [VAS-998] feat: Updated GetChannelAlert.test.tsx * [VAS-997] fix after merge with VAS-998 * fix client after merge * [VAS-1123] replace old merged API with new get Stations and Channels * [VAS-1123] fixed tests * [VAS-1123] fix after merge * [VAS-1123] fix test after merge * [VAS-1123] removed useless file and added tests * improve coverage * improve for coverage --------- Co-authored-by: Alessio Cialini Co-authored-by: Samuele Varianti <128470180+svariant@users.noreply.github.com> --- package.json | 2 +- src/api/BackofficeClient.ts | 72 +- .../addEditChannel/AddEditChannelForm.tsx | 4 +- .../__tests__/AddEditChannelForm.test.tsx | 67 +- .../AddEditChannelValidationForm.tsx | 6 +- .../channels/detail/ChannelDetailPage.tsx | 1 + .../__tests__/ChannelDetailHeader.test.tsx | 51 ++ .../detail/components/ChannelDetails.tsx | 2 + .../detail/components/DetailButtons.tsx | 1 + .../list/__tests__/ChannelsTable.test.tsx | 6 +- .../AddEditCommissionBundleForm.tsx | 67 +- .../AddEditCommissionBundleForm.test.tsx | 2 +- .../dashboard/nodeSignIn/NodeSignInECForm.tsx | 714 +++++++++--------- .../nodeSignIn/NodeSignInPSPForm.tsx | 55 +- .../dashboard/nodeSignIn/NodeSignInPTForm.tsx | 503 ++++++------ .../__tests__/NodeSignInECForm.test.tsx | 676 +++++++++-------- .../__tests__/NodeSignInPSPForm.test.tsx | 225 ++++-- .../__tests__/NodeSignInPTForm.test.tsx | 28 +- .../list/__tests__/StationsTable.test.tsx | 6 +- src/services/__mocks__/stationService.ts | 1 - src/services/__tests__/channelService.test.ts | 83 +- src/services/__tests__/stationService.test.ts | 27 +- src/services/channelService.ts | 74 +- src/services/stationService.ts | 353 +++++---- 24 files changed, 1544 insertions(+), 1482 deletions(-) create mode 100644 src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx diff --git a/package.json b/package.json index 5aeabb12c..82303b314 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "clean:api-portal": "rimraf src/api/generated/portal && rimraf openApi/generated", "generate:api-portal": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/main/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-next": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/next/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", - "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1002-update-get-channels-api/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", + "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1122-remove-unused-api-station-channels/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-local": "npm run generate:client", "generate:client": "jq 'walk(if type == \"object\" and has(\"parameters\") then .parameters |= map(select(.name != \"X-Request-Id\")) else . end)' ./openApi/portal-api-docs.json > ./openApi/portal-api-docs.json.temp && mv ./openApi/portal-api-docs.json.temp ./openApi/portal-api-docs.json && yarn run clean:api-portal && mkdirp openApi/generated && gen-api-models --api-spec openApi/portal-api-docs.json --out-dir src/api/generated/portal --no-strict --request-types --response-decoders --client && node openApi/scripts/api-portal_fixPostGen.js" }, diff --git a/src/api/BackofficeClient.ts b/src/api/BackofficeClient.ts index fe63643fb..05a6fd15a 100644 --- a/src/api/BackofficeClient.ts +++ b/src/api/BackofficeClient.ts @@ -3,8 +3,8 @@ import { appStateActions } from '@pagopa/selfcare-common-frontend/redux/slices/a import { storageTokenOps } from '@pagopa/selfcare-common-frontend/utils/storage'; import { ReactNode } from 'react'; import { - BundleCISubscriptionsMethodParams, BundleCISubscriptionsBodyRequest, + BundleCISubscriptionsMethodParams, BundleCiSubscriptionsDetailMethodParams, SubscriptionStateType, } from '../model/CommissionBundle'; @@ -18,6 +18,7 @@ import { ConfigurationStatus, StationOnCreation } from '../model/Station'; import { store } from '../redux/store'; import { extractResponse } from '../utils/client-utils'; import { ENV } from '../utils/env'; +import { WithDefaultsT as WithCustomDefaultsT, createClient as createCustomClient } from './custom/client'; import { AvailableCodes } from './generated/portal/AvailableCodes'; import { BrokerAndEcDetailsResource } from './generated/portal/BrokerAndEcDetailsResource'; import { BrokerDto } from './generated/portal/BrokerDto'; @@ -30,6 +31,10 @@ import { BundleCreateResponse } from './generated/portal/BundleCreateResponse'; import { BundleRequest } from './generated/portal/BundleRequest'; import { CIBrokerDelegationPage } from './generated/portal/CIBrokerDelegationPage'; import { CIBrokerStationPage } from './generated/portal/CIBrokerStationPage'; +import { CIBundleAttributeResource } from './generated/portal/CIBundleAttributeResource'; +import { CIBundleId } from './generated/portal/CIBundleId'; +import { CIBundleSubscriptionsDetail } from './generated/portal/CIBundleSubscriptionsDetail'; +import { CIBundleSubscriptionsResource } from './generated/portal/CIBundleSubscriptionsResource'; import { CIBundlesResource } from './generated/portal/CIBundlesResource'; import { ChannelCodeResource } from './generated/portal/ChannelCodeResource'; import { @@ -54,6 +59,7 @@ import { Ibans } from './generated/portal/Ibans'; import { Institution } from './generated/portal/Institution'; import { InstitutionApiKeysResource } from './generated/portal/InstitutionApiKeysResource'; import { InstitutionDetailResource } from './generated/portal/InstitutionDetailResource'; +import { InstitutionUploadData } from './generated/portal/InstitutionUploadData'; import { MaintenanceMessage } from './generated/portal/MaintenanceMessage'; import { PSPBundleResource } from './generated/portal/PSPBundleResource'; import { PSPBundlesResource } from './generated/portal/PSPBundlesResource'; @@ -66,8 +72,6 @@ import { ProductResource } from './generated/portal/ProductResource'; import { PspChannelPaymentTypes } from './generated/portal/PspChannelPaymentTypes'; import { PspChannelPaymentTypesResource } from './generated/portal/PspChannelPaymentTypesResource'; import { PspChannelsResource } from './generated/portal/PspChannelsResource'; -import { CIBundleSubscriptionsDetail } from './generated/portal/CIBundleSubscriptionsDetail'; -import { CIBundleSubscriptionsResource } from './generated/portal/CIBundleSubscriptionsResource'; import { PublicBundleRequest } from './generated/portal/PublicBundleRequest'; import { StationCodeResource } from './generated/portal/StationCodeResource'; import { StationDetailResource } from './generated/portal/StationDetailResource'; @@ -93,11 +97,6 @@ import { WrapperEntities } from './generated/portal/WrapperEntities'; import { WrapperStationDetailsDto } from './generated/portal/WrapperStationDetailsDto'; import { WrapperStationsResource } from './generated/portal/WrapperStationsResource'; import { WithDefaultsT, createClient } from './generated/portal/client'; -import { InstitutionUploadData } from './generated/portal/InstitutionUploadData'; -import { createClient as createCustomClient } from './custom/client'; -import { WithDefaultsT as WithCustomDefaultsT } from './custom/client'; -import { CIBundleId } from './generated/portal/CIBundleId'; -import { CIBundleAttributeResource } from './generated/portal/CIBundleAttributeResource'; // eslint-disable-next-line functional/immutable-data, @typescript-eslint/no-var-requires window.Buffer = window.Buffer || require('buffer').Buffer; @@ -386,10 +385,10 @@ export const BackofficeApi = { page, }: { status: ConfigurationStatus; - channelCode: string; + channelCode?: string; brokerCode: string; limit?: number; - page: number; + page?: number; }): Promise => { const result = await backofficeClient.getChannels({ status: String(status), @@ -401,23 +400,6 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - getChannelsMerged: async ( - page: number, - brokerCode: string, - channelcodefilter?: string, - limit?: number, - sorting?: string - ): Promise => { - const result = await backofficeClient.getAllChannelsMerged({ - limit, - channelcodefilter, - brokerCode, - page, - sorting, - }); - return extractResponse(result, 200, onRedirectToLogin); - }, - // retrive of channel detail before on db and then on the node getChannelDetail: async (channelcode: string): Promise => { const result = await backofficeClient.getChannelDetail({ 'channel-code': channelcode }); @@ -494,7 +476,7 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - updateWrapperChannelDetailsToCheck: async ({ + updateWrapperChannelDetails: async ({ channelCode, channel, validationUrl, @@ -514,21 +496,6 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - updateWrapperChannelDetailsByOpt: async ( - channel: ChannelDetailsDto, - validationUrl: string - ): Promise => { - const channelBody2Send = channelBody(channel); - const result = await backofficeClient.updateWrapperChannelDetailsByOpt({ - body: { - ...channelBody2Send, - status: StatusEnum.APPROVED, - validationUrl, - }, - }); - return extractResponse(result, 200, onRedirectToLogin); - }, - getPaymentTypes: async (): Promise => { const result = await backofficeClient.getPaymentTypes({}); return extractResponse(result, 200, onRedirectToLogin); @@ -591,7 +558,7 @@ export const BackofficeApi = { stationCode, limit, }: { - page: number; + page?: number; brokerCode: string; status: ConfigurationStatus; stationCode?: string; @@ -607,23 +574,6 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - getStationsMerged: async ( - page: number, - brokerCode: string, - stationcodefilter?: string, - limit?: number, - sorting?: string - ): Promise => { - const result = await backofficeClient.getAllStationsMerged({ - limit, - stationcodefilter, - brokerCode, - page, - sorting, - }); - return extractResponse(result, 200, onRedirectToLogin); - }, - getStationCode: async (ecCode: string): Promise => { const result = await backofficeClient.getStationCode({ 'ec-code': ecCode }); return extractResponse(result, 200, onRedirectToLogin); diff --git a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx index f291eb69e..c757e510d 100644 --- a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx +++ b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx @@ -32,7 +32,7 @@ import { createChannel, createWrapperChannelDetails, updateChannel, - updateWrapperChannelDetailsToCheck, + updateWrapperChannelDetails, } from '../../../services/channelService'; import { PaymentTypes } from '../../../api/generated/portal/PaymentTypes'; import { Party } from '../../../model/Party'; @@ -443,7 +443,7 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct throw new Error('Wrong channel wrapper status'); } } else { - await updateWrapperChannelDetailsToCheck({channelCode, channel: values, validationUrl}); + await updateWrapperChannelDetails({channelCode, channel: values, validationUrl}); } redirect(); } diff --git a/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx b/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx index 5c35225bc..18290371d 100644 --- a/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx +++ b/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx @@ -66,7 +66,7 @@ describe('', (injectedHistory?: ReturnType = [pspOperatorSignedDirect]; - test('Test rendering AddEditChannelForm', async () => { + test('Test rendering AddEditChannelForm Operator', async () => { jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ userRole: ROLE.PAGOPA_OPERATOR, userIsPspAdmin: false, @@ -131,6 +131,71 @@ describe('', (injectedHistory?: ReturnType { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: true, + userIsEcAdmin: false, + userIsPspDirectAdmin: true, + userIsPagopaOperator: false, + userIsAdmin: true, + }); + render( + + + + + + + + ); + const businessName = screen.getByTestId('business-name-test') as HTMLInputElement; + const pspBrokerCode = screen.getByTestId('psp-brokercode-test') as HTMLInputElement; + const channelCode = screen.getByTestId('channel-code-test') as HTMLInputElement; + const targetUnion = screen.getByTestId('target-union-test') as HTMLInputElement; + const paymentType = screen.getByTestId('payment-type-test') as HTMLSelectElement; + const continueBtn = screen.getByText( + 'addEditChannelPage.addForm.continueButton' + ) as HTMLButtonElement; + + expect(businessName.value).toBe(pspOperatorSignedDirect.description); + expect(pspBrokerCode.value).toBe(pspOperatorSignedDirect.fiscalCode); + expect(channelCode.value).toBe(`${pspOperatorSignedDirect.fiscalCode}_01`); + + fireEvent.click(businessName); + fireEvent.change(businessName, {target: {value: 'businessName'}}); + expect(businessName.value).toBe('businessName'); + + fireEvent.click(pspBrokerCode); + fireEvent.change(pspBrokerCode, {target: {value: 'pspBrokerCode'}}); + expect(pspBrokerCode.value).toBe('pspBrokerCode'); + + fireEvent.click(channelCode); + fireEvent.change(channelCode, {target: {value: 'channelCode'}}); + expect(channelCode.value).toBe('channelCode'); + + fireEvent.click(targetUnion); + fireEvent.change(targetUnion, {target: {value: 'https://www.testTarget.it/path'}}); + expect(targetUnion.value).toBe('https://www.testTarget.it/path'); + + fireEvent.click(paymentType); + fireEvent.change(paymentType, {target: {value: 'Option 1'}}); + + fireEvent.click(continueBtn); + + const confirmBtn = screen.queryByTestId('confirm-button-test') as HTMLButtonElement; + const cancelBtn = screen.queryByTestId('cancel-button-test') as HTMLButtonElement; + + userEvent.click(cancelBtn); + fireEvent.click(continueBtn); + + userEvent.click(confirmBtn); + }); + test('test catch case api getPaymentTypes', async () => { jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ userRole: ROLE.PAGOPA_OPERATOR, diff --git a/src/pages/channels/addEditChannel/components/AddEditChannelValidationForm.tsx b/src/pages/channels/addEditChannel/components/AddEditChannelValidationForm.tsx index 60cce5f5f..b1a5c2a55 100644 --- a/src/pages/channels/addEditChannel/components/AddEditChannelValidationForm.tsx +++ b/src/pages/channels/addEditChannel/components/AddEditChannelValidationForm.tsx @@ -16,7 +16,7 @@ import { } from '@mui/material'; import {theme} from '@pagopa/mui-italia'; import {FormikProps} from 'formik'; -import {Badge as BadgeIcon, MenuBook as MenuBookIcon} from '@mui/icons-material'; +import {Badge as BadgeIcon, Info, MenuBook as MenuBookIcon} from '@mui/icons-material'; import {Dispatch, SetStateAction, useEffect, useState} from 'react'; import AddEditChannelFormSectionTitle from '../AddEditChannelFormSectionTitle'; import {ChannelOnCreation} from '../../../../model/Channel'; @@ -257,7 +257,7 @@ const AddEditChannelValidationForm = ({ } + icon={} > @@ -317,7 +317,7 @@ const AddEditChannelValidationForm = ({ /> - + { }; export default ChannelDetailPage; + diff --git a/src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx b/src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx new file mode 100644 index 000000000..5a295da4b --- /dev/null +++ b/src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx @@ -0,0 +1,51 @@ +import {ThemeProvider} from '@mui/system'; +import {theme} from '@pagopa/mui-italia'; +import {cleanup, screen, render, fireEvent} from '@testing-library/react'; +import React from 'react'; +import {MemoryRouter, Route} from 'react-router-dom'; +import {store} from '../../../../redux/store'; +import ChannelDetailHeader from '../components/GetChannelAlert'; +import {StatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsDto'; +import {WrapperStatusEnum,} from '../../../../api/generated/portal/ChannelDetailsResource'; +import {Provider} from 'react-redux'; + + +beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(() => { + }); + jest.spyOn(console, 'warn').mockImplementation(() => { + }); + jest.resetModules(); +}); +afterEach(cleanup); + +describe('', () => { + const channelId = 'XPAY_03_ONUS'; + test('render component ChannelDetailHeader', async () => { + const channelDetail = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `$test`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + status: StatusEnum.TO_CHECK, + wrapperStatus: WrapperStatusEnum.APPROVED + }; + render( + + + + + + + + + + ); + + }); + +}); + + diff --git a/src/pages/channels/detail/components/ChannelDetails.tsx b/src/pages/channels/detail/components/ChannelDetails.tsx index 32c8260ac..2956b6d8a 100644 --- a/src/pages/channels/detail/components/ChannelDetails.tsx +++ b/src/pages/channels/detail/components/ChannelDetails.tsx @@ -19,6 +19,7 @@ import { useUserRole } from '../../../../hooks/useUserRole'; import DetailButtons from './DetailButtons'; import GetChannelAlert from './GetChannelAlert'; + type Props = { channelDetail: ChannelDetailsResource; setChannelDetail: (value: any) => void; @@ -375,3 +376,4 @@ const ChannelDetails = ({ }; export default ChannelDetails; + diff --git a/src/pages/channels/detail/components/DetailButtons.tsx b/src/pages/channels/detail/components/DetailButtons.tsx index b45b0657b..4126e4ce6 100644 --- a/src/pages/channels/detail/components/DetailButtons.tsx +++ b/src/pages/channels/detail/components/DetailButtons.tsx @@ -236,3 +236,4 @@ const DetailButtons = ({ channelDetails, setChannelDetails, goBack }: Props) => }; export default DetailButtons; + diff --git a/src/pages/channels/list/__tests__/ChannelsTable.test.tsx b/src/pages/channels/list/__tests__/ChannelsTable.test.tsx index f65291ebf..c1335d408 100644 --- a/src/pages/channels/list/__tests__/ChannelsTable.test.tsx +++ b/src/pages/channels/list/__tests__/ChannelsTable.test.tsx @@ -14,7 +14,7 @@ import { pspAdminSignedDirect } from '../../../../services/__mocks__/partyServic import * as ChannelService from '../../../../services/channelService'; import ChannelsTable from '../ChannelsTable'; -const mockGetChannelsMerged = jest.spyOn(ChannelService, 'getChannelsMerged'); +const mockGetChannels = jest.spyOn(ChannelService, 'getChannels'); beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(() => {}); @@ -39,7 +39,7 @@ const Component = () => { describe('', () => { test('render component ChannelsTable', async () => { - mockGetChannelsMerged.mockReturnValue(Promise.resolve(mockedChannels)); + mockGetChannels.mockReturnValue(Promise.resolve(mockedChannels)); render( @@ -51,7 +51,7 @@ describe('', () => { }); }); test('render component ChannelsTable error getChannelsMerged', async () => { - mockGetChannelsMerged.mockRejectedValue('error'); + mockGetChannels.mockRejectedValue('error'); render( diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx index 00d968f6f..4821d7db5 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx @@ -1,10 +1,10 @@ /* eslint-disable functional/no-let */ /* eslint-disable complexity */ /* eslint-disable sonarjs/cognitive-complexity */ -import {theme} from '@pagopa/mui-italia'; -import {FormikProps} from 'formik'; -import React, {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; +import { MenuBook } from '@mui/icons-material'; +import BookmarkAddIcon from '@mui/icons-material/BookmarkAdd'; +import DateRangeIcon from '@mui/icons-material/DateRange'; +import EuroIcon from '@mui/icons-material/Euro'; import { Autocomplete, Box, @@ -22,33 +22,34 @@ import { TextFieldProps, Typography, } from '@mui/material'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {MenuBook} from '@mui/icons-material'; -import EuroIcon from '@mui/icons-material/Euro'; -import BookmarkAddIcon from '@mui/icons-material/BookmarkAdd'; -import DateRangeIcon from '@mui/icons-material/DateRange'; -import {AdapterDateFns} from '@mui/x-date-pickers/AdapterDateFns'; -import {NumericFormat} from 'react-number-format'; -import {DesktopDatePicker, LocalizationProvider} from '@mui/x-date-pickers'; -import {LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS, LOADING_TASK_GET_CHANNELS_IDS,} from '../../../../utils/constants'; -import {Party} from '../../../../model/Party'; -import {sortPaymentType} from '../../../../model/PaymentType'; +import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import { theme } from '@pagopa/mui-italia'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { FormikProps } from 'formik'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { NumericFormat } from 'react-number-format'; +import { BundleRequest } from '../../../../api/generated/portal/BundleRequest'; +import { Delegation } from '../../../../api/generated/portal/Delegation'; +import { TypeEnum } from '../../../../api/generated/portal/PSPBundleResource'; +import { PaymentTypes } from '../../../../api/generated/portal/PaymentTypes'; +import { Touchpoints } from '../../../../api/generated/portal/Touchpoints'; import FormSectionTitle from '../../../../components/Form/FormSectionTitle'; -import {useAppSelector} from '../../../../redux/hooks'; -import {partiesSelectors} from '../../../../redux/slices/partiesSlice'; -import {PaymentTypes} from '../../../../api/generated/portal/PaymentTypes'; -import {BundleRequest} from '../../../../api/generated/portal/BundleRequest'; -import {Touchpoints} from '../../../../api/generated/portal/Touchpoints'; -import {getChannelsIdAssociatedToPSP} from '../../../../services/channelService'; -import {getPaymentTypes} from '../../../../services/configurationService'; -import {getTouchpoints} from '../../../../services/bundleService'; -import {getBrokerDelegation} from '../../../../services/institutionService'; -import {Delegation} from '../../../../api/generated/portal/Delegation'; -import {addCurrentPSP} from '../../../../utils/channel-utils'; -import {useFlagValue} from '../../../../hooks/useFeatureFlags'; -import {useUserRole} from "../../../../hooks/useUserRole"; -import {TypeEnum} from '../../../../api/generated/portal/PSPBundleResource'; -import {useOrganizationType} from "../../../../hooks/useOrganizationType"; +import { useFlagValue } from '../../../../hooks/useFeatureFlags'; +import { useOrganizationType } from "../../../../hooks/useOrganizationType"; +import { useUserRole } from "../../../../hooks/useUserRole"; +import { Party } from '../../../../model/Party'; +import { sortPaymentType } from '../../../../model/PaymentType'; +import { ConfigurationStatus } from '../../../../model/Station'; +import { useAppSelector } from '../../../../redux/hooks'; +import { partiesSelectors } from '../../../../redux/slices/partiesSlice'; +import { getTouchpoints } from '../../../../services/bundleService'; +import { getChannels } from '../../../../services/channelService'; +import { getPaymentTypes } from '../../../../services/configurationService'; +import { getBrokerDelegation } from '../../../../services/institutionService'; +import { addCurrentPSP } from '../../../../utils/channel-utils'; +import { LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS, LOADING_TASK_GET_CHANNELS_IDS, } from '../../../../utils/constants'; type Props = { formik: FormikProps; @@ -82,10 +83,10 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { const getChannelsByBrokerCode = (selectedBrokerCode: string) => { setLoadingChannels(true); - getChannelsIdAssociatedToPSP(0, selectedBrokerCode) + getChannels({status: ConfigurationStatus.ACTIVE, brokerCode: selectedBrokerCode}) .then((data) => { - if (data && data.length > 0) { - setChannelsId(data); + if (data?.channels && data.channels.length > 0) { + setChannelsId(data.channels.map(ch => ch.channel_code)); } else { setChannelsId([]); addError({ diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx index b04b5292a..b56b0c023 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx @@ -87,7 +87,7 @@ describe('', () => { ); spyOnGetChannelService = jest.spyOn( require('../../../../../services/channelService'), - 'getChannelsIdAssociatedToPSP' + 'getChannels' ); spyOnErrorHook = jest .spyOn(useErrorDispatcher, 'useErrorDispatcher') diff --git a/src/pages/dashboard/nodeSignIn/NodeSignInECForm.tsx b/src/pages/dashboard/nodeSignIn/NodeSignInECForm.tsx index cb167970e..a9dbfae10 100644 --- a/src/pages/dashboard/nodeSignIn/NodeSignInECForm.tsx +++ b/src/pages/dashboard/nodeSignIn/NodeSignInECForm.tsx @@ -1,396 +1,402 @@ /* eslint-disable sonarjs/cognitive-complexity */ /* eslint-disable complexity */ -import {Badge as BadgeIcon} from '@mui/icons-material'; -import {Box, Button, Grid, Paper, Stack, TextField} from '@mui/material'; -import {theme} from '@pagopa/mui-italia'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {FormikProps, useFormik} from 'formik'; -import {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useHistory} from 'react-router'; -import {BrokerAndEcDetailsResource} from '../../../api/generated/portal/BrokerAndEcDetailsResource'; -import {CreditorInstitutionAddressDto} from '../../../api/generated/portal/CreditorInstitutionAddressDto'; +import { Badge as BadgeIcon } from '@mui/icons-material'; +import { Box, Button, Grid, Paper, Stack, TextField } from '@mui/material'; +import { theme } from '@pagopa/mui-italia'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { FormikProps, useFormik } from 'formik'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router'; +import { BrokerAndEcDetailsResource } from '../../../api/generated/portal/BrokerAndEcDetailsResource'; +import { CreditorInstitutionAddressDto } from '../../../api/generated/portal/CreditorInstitutionAddressDto'; import FormSectionTitle from '../../../components/Form/FormSectionTitle'; -import {useSigninData} from '../../../hooks/useSigninData'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; +import { useOrganizationType } from '../../../hooks/useOrganizationType'; +import { useSigninData } from '../../../hooks/useSigninData'; +import { ConfigurationStatus } from '../../../model/Station'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; -import {deleteCIBroker} from '../../../services/brokerService'; +import { deleteCIBroker } from '../../../services/brokerService'; import { createECAndBroker, - createEcBroker, createECIndirect, + createEcBroker, updateCreditorInstitution, } from '../../../services/nodeService'; -import {getStationsMerged} from '../../../services/stationService'; -import {LOADING_TASK_NODE_SIGN_IN_EC} from '../../../utils/constants'; -import {useOrganizationType} from "../../../hooks/useOrganizationType"; +import { getStations } from '../../../services/stationService'; +import { LOADING_TASK_NODE_SIGN_IN_EC } from '../../../utils/constants'; import CommonRadioGroup from './components/CommonRadioGroup'; - type Props = { - goBack: () => void; - signInData: BrokerAndEcDetailsResource; + goBack: () => void; + signInData: BrokerAndEcDetailsResource; }; -const NodeSignInCIForm = ({goBack, signInData}: Props) => { - const {t} = useTranslation(); - const {orgIsEcBrokerSigned, orgIsEcSigned} = useOrganizationType(); - const history = useHistory(); - const addError = useErrorDispatcher(); - const setLoading = useLoading(LOADING_TASK_NODE_SIGN_IN_EC); - const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const updateSigninData = useSigninData(); - const [intermediaryAvailableValue, setIntermediaryAvailableValue] = useState(false); - const ciDirect = signInData && orgIsEcBrokerSigned && orgIsEcSigned; - const [hasCIStations, setHasCIStations] = useState(true); - - useEffect(() => { - if (ciDirect) { - setIntermediaryAvailableValue(true); - } else { - setIntermediaryAvailableValue(false); - } +const NodeSignInCIForm = ({ goBack, signInData }: Props) => { + const { t } = useTranslation(); + const { orgIsEcBrokerSigned, orgIsEcSigned } = useOrganizationType(); + const history = useHistory(); + const addError = useErrorDispatcher(); + const setLoading = useLoading(LOADING_TASK_NODE_SIGN_IN_EC); + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); + const updateSigninData = useSigninData(); + const [intermediaryAvailableValue, setIntermediaryAvailableValue] = useState(false); + const ciDirect = signInData && orgIsEcBrokerSigned && orgIsEcSigned; + const [hasCIStations, setHasCIStations] = useState(true); - setLoading(true); - const brokerCode = selectedParty?.fiscalCode ?? ''; + useEffect(() => { + if (ciDirect) { + setIntermediaryAvailableValue(true); + } else { + setIntermediaryAvailableValue(false); + } - getStationsMerged(0, brokerCode, undefined, 1) - .then((stations) => { - setHasCIStations( - stations?.pageInfo?.items_found !== undefined && stations.pageInfo.items_found > 0 - ); - }) - .catch((reason) => { - addError({ - id: 'RETRIEVE_STATIONS_ERROR', - blocking: false, - error: reason, - techDescription: `An error occurred while retrieving ci stations`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('nodeSignInPage.error.retrieveStationsErrorMessage'), - component: 'Toast', - }); - }) - .finally(() => setLoading(false)); - }, [selectedParty]); + setLoading(true); + const brokerCode = selectedParty?.fiscalCode ?? ''; - const initialFormData = (ecDetails: BrokerAndEcDetailsResource) => - ecDetails - ? { - city: ecDetails?.creditorInstitutionDetailsResource?.address?.city ?? '', - countryCode: ecDetails?.creditorInstitutionDetailsResource?.address?.countryCode ?? '', - location: ecDetails?.creditorInstitutionDetailsResource?.address?.location ?? '', - taxDomicile: ecDetails?.creditorInstitutionDetailsResource?.address?.taxDomicile ?? '', - zipCode: ecDetails?.creditorInstitutionDetailsResource?.address?.zipCode ?? '', - } - : { - city: '', - countryCode: '', - location: '', - taxDomicile: '', - zipCode: '', - }; - - const validate = (values: CreditorInstitutionAddressDto) => - Object.fromEntries( - Object.entries({ - location: !values.location - ? t('nodeSignInPage.form.ecFields.validation.required') - : undefined, - city: !values.city ? t('nodeSignInPage.form.ecFields.validation.required') : undefined, - countryCode: !values.countryCode - ? t('nodeSignInPage.form.ecFields.validation.required') - : values.countryCode.length < 2 - ? t('nodeSignInPage.form.ecFields.validation.countryCode') - : undefined, - zipCode: !values.zipCode - ? t('nodeSignInPage.form.ecFields.validation.required') - : values.zipCode.length < 5 - ? t('nodeSignInPage.form.ecFields.validation.zipCode') - : undefined, - taxDomicile: !values.taxDomicile - ? t('nodeSignInPage.form.ecFields.validation.required') - : undefined, - }).filter(([_key, value]) => (typeof value !== 'undefined' ? value : '')) + Promise.all([ + getStations({ status: ConfigurationStatus.ACTIVE, brokerCode, page: 0, limit: 1}), + getStations({ status: ConfigurationStatus.TO_BE_VALIDATED, brokerCode, page: 0, limit: 1}), + ]) + .then(([activeStations, toBeActivatedStations]) => { + setHasCIStations( + (activeStations?.pageInfo?.total_items !== undefined && + activeStations.pageInfo.total_items > 0) || + (toBeActivatedStations?.pageInfo?.total_items !== undefined && + toBeActivatedStations.pageInfo.total_items > 0) ); + }) + .catch((reason) => { + addError({ + id: 'RETRIEVE_STATIONS_ERROR', + blocking: false, + error: reason, + techDescription: `An error occurred while retrieving ci stations`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('nodeSignInPage.error.retrieveStationsErrorMessage'), + component: 'Toast', + }); + }) + .finally(() => setLoading(false)); + }, [selectedParty]); - const submit = async () => { - setLoading(true); - - const commonPayload = { - address: {...formik.values}, - businessName: selectedParty?.description ?? '', - creditorInstitutionCode: selectedParty?.fiscalCode ?? '', - enabled: true, - pspPayment: false, - reportingFtp: false, - reportingZip: false, + const initialFormData = (ecDetails: BrokerAndEcDetailsResource) => + ecDetails + ? { + city: ecDetails?.creditorInstitutionDetailsResource?.address?.city ?? '', + countryCode: ecDetails?.creditorInstitutionDetailsResource?.address?.countryCode ?? '', + location: ecDetails?.creditorInstitutionDetailsResource?.address?.location ?? '', + taxDomicile: ecDetails?.creditorInstitutionDetailsResource?.address?.taxDomicile ?? '', + zipCode: ecDetails?.creditorInstitutionDetailsResource?.address?.zipCode ?? '', + } + : { + city: '', + countryCode: '', + location: '', + taxDomicile: '', + zipCode: '', }; - if (orgIsEcSigned && selectedParty) { - try { - if (!orgIsEcBrokerSigned && intermediaryAvailableValue) { - await createEcBroker({ - broker_code: selectedParty.fiscalCode, - description: selectedParty.description, - }); - } + const validate = (values: CreditorInstitutionAddressDto) => + Object.fromEntries( + Object.entries({ + location: !values.location + ? t('nodeSignInPage.form.ecFields.validation.required') + : undefined, + city: !values.city ? t('nodeSignInPage.form.ecFields.validation.required') : undefined, + countryCode: !values.countryCode + ? t('nodeSignInPage.form.ecFields.validation.required') + : values.countryCode.length < 2 + ? t('nodeSignInPage.form.ecFields.validation.countryCode') + : undefined, + zipCode: !values.zipCode + ? t('nodeSignInPage.form.ecFields.validation.required') + : values.zipCode.length < 5 + ? t('nodeSignInPage.form.ecFields.validation.zipCode') + : undefined, + taxDomicile: !values.taxDomicile + ? t('nodeSignInPage.form.ecFields.validation.required') + : undefined, + }).filter(([_key, value]) => (typeof value !== 'undefined' ? value : '')) + ); - if (!hasCIStations && ciDirect && !intermediaryAvailableValue) { - await deleteCIBroker(selectedParty.fiscalCode); - } + const submit = async () => { + setLoading(true); - await updateCreditorInstitution(selectedParty.fiscalCode, commonPayload); + const commonPayload = { + address: { ...formik.values }, + businessName: selectedParty?.description ?? '', + creditorInstitutionCode: selectedParty?.fiscalCode ?? '', + enabled: true, + pspPayment: false, + reportingFtp: false, + reportingZip: false, + }; - await updateSigninData(selectedParty); - } catch (reason) { - addError({ - id: 'NODE_SIGNIN_EC_UPDATE', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while updating Ec data at the node`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('nodeSignInPage.form.ecUpdateErrorMessageDesc'), - component: 'Toast', - }); - } finally { - setLoading(false); - history.push(ROUTES.HOME, { - alertSuccessMessage: t('nodeSignInPage.form.seccesMessagePut'), - }); - } + if (orgIsEcSigned && selectedParty) { + try { + if (!orgIsEcBrokerSigned && intermediaryAvailableValue) { + await createEcBroker({ + broker_code: selectedParty.fiscalCode, + description: selectedParty.description, + }); } - if (!orgIsEcSigned && selectedParty) { - try { - if (intermediaryAvailableValue) { - await createECAndBroker(commonPayload); - } else { - await createECIndirect(commonPayload); - } - - await updateSigninData(selectedParty); - } catch (reason) { - addError({ - id: 'NODE_SIGNIN_EC_CREATE', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while registration EC at the node`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('nodeSignInPage.form.ecErrorMessageDesc'), - component: 'Toast', - }); - } finally { - setLoading(false); - history.push(ROUTES.HOME, { - alertSuccessMessage: t('nodeSignInPage.form.successMessage'), - }); - } + if (!hasCIStations && ciDirect && !intermediaryAvailableValue) { + await deleteCIBroker(selectedParty.fiscalCode); } - }; - const formik = useFormik({ - initialValues: initialFormData(signInData), - validate, - onSubmit: async () => { - await submit(); - }, - validateOnMount: true, - validateOnChange: true, - enableReinitialize: true, - }); + await updateCreditorInstitution(selectedParty.fiscalCode, commonPayload); - const handleChangeNumberOnly = ( - e: React.ChangeEvent, - field: string, - formik: FormikProps - ) => { - const regex = /^[0-9\b]+$/; - if (e.target.value === '' || regex.test(e.target.value)) { - formik.setFieldValue(field, e.target.value); - } - }; + await updateSigninData(selectedParty); + } catch (reason) { + addError({ + id: 'NODE_SIGNIN_EC_UPDATE', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while updating Ec data at the node`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('nodeSignInPage.form.ecUpdateErrorMessageDesc'), + component: 'Toast', + }); + } finally { + setLoading(false); + history.push(ROUTES.HOME, { + alertSuccessMessage: t('nodeSignInPage.form.seccesMessagePut'), + }); + } + } - const handleChangeLetterOnly = ( - e: React.ChangeEvent, - field: string, - formik: FormikProps - ) => { - const regex = /^[A-Za-z]+$/; - if (e.target.value === '' || regex.test(e.target.value)) { - formik.setFieldValue(field, e.target.value); + if (!orgIsEcSigned && selectedParty) { + try { + if (intermediaryAvailableValue) { + await createECAndBroker(commonPayload); + } else { + await createECIndirect(commonPayload); } - }; - const enebledSubmit = (values: CreditorInstitutionAddressDto) => - !!( - values.location !== '' && - values.city !== '' && - values.countryCode !== '' && - values.zipCode !== '' && - values.taxDomicile !== '' && - intermediaryAvailableValue !== undefined - ); + await updateSigninData(selectedParty); + } catch (reason) { + addError({ + id: 'NODE_SIGNIN_EC_CREATE', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while registration EC at the node`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('nodeSignInPage.form.ecErrorMessageDesc'), + component: 'Toast', + }); + } finally { + setLoading(false); + history.push(ROUTES.HOME, { + alertSuccessMessage: t('nodeSignInPage.form.successMessage'), + }); + } + } + }; - return ( -
- - - } - isRequired - > - - - formik.handleChange(e)} - error={formik.touched.location && Boolean(formik.errors.location)} - helperText={formik.touched.location && formik.errors.location} - inputProps={{'data-testid': 'address-test'}} - /> - - - formik.handleChange(e)} - error={formik.touched.city && Boolean(formik.errors.city)} - helperText={formik.touched.city && formik.errors.city} - inputProps={{'data-testid': 'city-test'}} - /> - - - handleChangeLetterOnly(e, 'countryCode', formik)} - error={formik.touched.countryCode && Boolean(formik.errors.countryCode)} - helperText={formik.touched.countryCode && formik.errors.countryCode} - /> - - - handleChangeNumberOnly(e, 'zipCode', formik)} - error={formik.touched.zipCode && Boolean(formik.errors.zipCode)} - helperText={formik.touched.zipCode && formik.errors.zipCode} - aria-errormessage="è possibile inserire solamente caratteri numerici" - /> - - - formik.handleChange(e)} - error={formik.touched.taxDomicile && Boolean(formik.errors.taxDomicile)} - helperText={formik.touched.taxDomicile && formik.errors.taxDomicile} - inputProps={{'data-testid': 'fiscal-domicile-test'}} - disabled={ - signInData?.creditorInstitutionDetailsResource?.address?.taxDomicile - ? true - : false - } - /> - - - + const formik = useFormik({ + initialValues: initialFormData(signInData), + validate, + onSubmit: async () => { + await submit(); + }, + validateOnMount: true, + validateOnChange: true, + enableReinitialize: true, + }); - - - - + const handleChangeNumberOnly = ( + e: React.ChangeEvent, + field: string, + formik: FormikProps + ) => { + const regex = /^[0-9\b]+$/; + if (e.target.value === '' || regex.test(e.target.value)) { + formik.setFieldValue(field, e.target.value); + } + }; - - - - - - - - - + const handleChangeLetterOnly = ( + e: React.ChangeEvent, + field: string, + formik: FormikProps + ) => { + const regex = /^[A-Za-z]+$/; + if (e.target.value === '' || regex.test(e.target.value)) { + formik.setFieldValue(field, e.target.value); + } + }; + + const enebledSubmit = (values: CreditorInstitutionAddressDto) => + !!( + values.location !== '' && + values.city !== '' && + values.countryCode !== '' && + values.zipCode !== '' && + values.taxDomicile !== '' && + intermediaryAvailableValue !== undefined ); + + return ( +
+ + + } + isRequired + > + + + formik.handleChange(e)} + error={formik.touched.location && Boolean(formik.errors.location)} + helperText={formik.touched.location && formik.errors.location} + inputProps={{ 'data-testid': 'address-test' }} + /> + + + formik.handleChange(e)} + error={formik.touched.city && Boolean(formik.errors.city)} + helperText={formik.touched.city && formik.errors.city} + inputProps={{ 'data-testid': 'city-test' }} + /> + + + handleChangeLetterOnly(e, 'countryCode', formik)} + error={formik.touched.countryCode && Boolean(formik.errors.countryCode)} + helperText={formik.touched.countryCode && formik.errors.countryCode} + /> + + + handleChangeNumberOnly(e, 'zipCode', formik)} + error={formik.touched.zipCode && Boolean(formik.errors.zipCode)} + helperText={formik.touched.zipCode && formik.errors.zipCode} + aria-errormessage="è possibile inserire solamente caratteri numerici" + /> + + + formik.handleChange(e)} + error={formik.touched.taxDomicile && Boolean(formik.errors.taxDomicile)} + helperText={formik.touched.taxDomicile && formik.errors.taxDomicile} + inputProps={{ 'data-testid': 'fiscal-domicile-test' }} + disabled={ + signInData?.creditorInstitutionDetailsResource?.address?.taxDomicile + ? true + : false + } + /> + + + + + + + + + + + + + + + + + +
+ ); }; export const inputGroupStyle = { - borderRadius: 1, - border: 1, - borderColor: theme.palette.divider, - p: 3, - mb: 3, + borderRadius: 1, + border: 1, + borderColor: theme.palette.divider, + p: 3, + mb: 3, }; export default NodeSignInCIForm; diff --git a/src/pages/dashboard/nodeSignIn/NodeSignInPSPForm.tsx b/src/pages/dashboard/nodeSignIn/NodeSignInPSPForm.tsx index 2cd2c04f3..a5bbc876b 100644 --- a/src/pages/dashboard/nodeSignIn/NodeSignInPSPForm.tsx +++ b/src/pages/dashboard/nodeSignIn/NodeSignInPSPForm.tsx @@ -1,24 +1,25 @@ -import {Badge as BadgeIcon, BookmarkAdd as BookmarkAddIcon} from '@mui/icons-material'; -import {Box, Button, FormControlLabel, Grid, Paper, Radio, RadioGroup, Stack, TextField,} from '@mui/material'; -import {theme} from '@pagopa/mui-italia'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {FormikProps, useFormik} from 'formik'; -import {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useHistory} from 'react-router'; -import {BrokerOrPspDetailsResource} from '../../../api/generated/portal/BrokerOrPspDetailsResource'; +import { Badge as BadgeIcon, BookmarkAdd as BookmarkAddIcon } from '@mui/icons-material'; +import { Box, Button, FormControlLabel, Grid, Paper, Radio, RadioGroup, Stack, TextField, } from '@mui/material'; +import { theme } from '@pagopa/mui-italia'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { FormikProps, useFormik } from 'formik'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router'; +import { BrokerOrPspDetailsResource } from '../../../api/generated/portal/BrokerOrPspDetailsResource'; import FormSectionTitle from '../../../components/Form/FormSectionTitle'; -import {useSigninData} from '../../../hooks/useSigninData'; -import {NodeOnSignInPSP} from '../../../model/Node'; -import {Party} from '../../../model/Party'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; +import { useOrganizationType } from "../../../hooks/useOrganizationType"; +import { useSigninData } from '../../../hooks/useSigninData'; +import { NodeOnSignInPSP } from '../../../model/Node'; +import { Party } from '../../../model/Party'; +import { ConfigurationStatus } from '../../../model/Station'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; -import {getChannelsMerged} from '../../../services/channelService'; -import {createPspBroker, createPSPDirect, createPSPIndirect, updatePSPInfo,} from '../../../services/nodeService'; -import {deletePSPBroker} from '../../../services/pspBrokerService'; -import {LOADING_TASK_CHANNEL_ADD_EDIT} from '../../../utils/constants'; -import {useOrganizationType} from "../../../hooks/useOrganizationType"; +import { getChannels } from '../../../services/channelService'; +import { createPSPDirect, createPSPIndirect, createPspBroker, updatePSPInfo, } from '../../../services/nodeService'; +import { deletePSPBroker } from '../../../services/pspBrokerService'; +import { LOADING_TASK_CHANNEL_ADD_EDIT } from '../../../utils/constants'; import CommonRadioGroup from './components/CommonRadioGroup'; type Props = { @@ -49,11 +50,17 @@ const NodeSignInPSPForm = ({goBack, signInData}: Props) => { setLoading(true); const brokerCode = selectedParty?.fiscalCode ?? ''; - getChannelsMerged(0, brokerCode, undefined, 1) - .then((channels) => { - setHasPSPChannels( - channels?.page_info?.items_found !== undefined && channels.page_info.items_found > 0 - ); + Promise.all([ + getChannels({ status: ConfigurationStatus.ACTIVE, brokerCode, page: 0, limit: 1}), + getChannels({ status: ConfigurationStatus.TO_BE_VALIDATED, brokerCode, page: 0, limit: 1}), + ]) + .then(([activeChannels, toBeActivatedChannels]) => { + setHasPSPChannels( + (activeChannels?.page_info?.total_items !== undefined && + activeChannels.page_info.total_items > 0) || + (toBeActivatedChannels?.page_info?.total_items !== undefined && + toBeActivatedChannels.page_info.total_items > 0) + ); }) .catch((reason) => { addError({ diff --git a/src/pages/dashboard/nodeSignIn/NodeSignInPTForm.tsx b/src/pages/dashboard/nodeSignIn/NodeSignInPTForm.tsx index 61af6a5f1..6d81a4270 100644 --- a/src/pages/dashboard/nodeSignIn/NodeSignInPTForm.tsx +++ b/src/pages/dashboard/nodeSignIn/NodeSignInPTForm.tsx @@ -1,268 +1,287 @@ -import {Badge as BadgeIcon, CompareArrows as CompareArrowsIcon} from '@mui/icons-material'; -import {Box, Button, Checkbox, FormControlLabel, Grid, Paper, Stack, TextField,} from '@mui/material'; -import {theme} from '@pagopa/mui-italia'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {useFormik} from 'formik'; -import {useEffect, useState} from 'react'; -import {useTranslation} from 'react-i18next'; -import {useHistory} from 'react-router'; +import { Badge as BadgeIcon, CompareArrows as CompareArrowsIcon } from '@mui/icons-material'; +import { + Box, + Button, + Checkbox, + FormControlLabel, + Grid, + Paper, + Stack, + TextField, +} from '@mui/material'; +import { theme } from '@pagopa/mui-italia'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { useFormik } from 'formik'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router'; import FormSectionTitle from '../../../components/Form/FormSectionTitle'; -import {useSigninData} from '../../../hooks/useSigninData'; -import {NodeOnSignInPT, PTResource} from '../../../model/Node'; -import {Party} from '../../../model/Party'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; +import { useOrganizationType } from '../../../hooks/useOrganizationType'; +import { useSigninData } from '../../../hooks/useSigninData'; +import { NodeOnSignInPT, PTResource } from '../../../model/Node'; +import { Party } from '../../../model/Party'; +import { ConfigurationStatus } from '../../../model/Station'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; -import {deleteCIBroker} from '../../../services/brokerService'; -import {getChannelsMerged} from '../../../services/channelService'; -import {createEcBroker, createPspBroker} from '../../../services/nodeService'; -import {deletePSPBroker} from '../../../services/pspBrokerService'; -import {getStationsMerged} from '../../../services/stationService'; -import {LOADING_TASK_NODE_SIGN_IN_EC} from '../../../utils/constants'; -import {useOrganizationType} from "../../../hooks/useOrganizationType"; +import { deleteCIBroker } from '../../../services/brokerService'; +import { getChannels } from '../../../services/channelService'; +import { createEcBroker, createPspBroker } from '../../../services/nodeService'; +import { deletePSPBroker } from '../../../services/pspBrokerService'; +import { getStations } from '../../../services/stationService'; +import { LOADING_TASK_NODE_SIGN_IN_EC } from '../../../utils/constants'; type Props = { - goBack: () => void; - signInData: PTResource; + goBack: () => void; + signInData: PTResource; }; -const NodeSignInPTForm = ({goBack, signInData}: Props) => { - const {t} = useTranslation(); - const history = useHistory(); - const addError = useErrorDispatcher(); - const setLoading = useLoading(LOADING_TASK_NODE_SIGN_IN_EC); - const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const updateSigninData = useSigninData(); - const {orgInfo, orgIsPspDirect, orgIsEcDirect, orgIsPspBrokerSigned, orgIsEcBrokerSigned} = useOrganizationType(); +const NodeSignInPTForm = ({ goBack, signInData }: Props) => { + const { t } = useTranslation(); + const history = useHistory(); + const addError = useErrorDispatcher(); + const setLoading = useLoading(LOADING_TASK_NODE_SIGN_IN_EC); + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); + const updateSigninData = useSigninData(); + const { orgInfo, orgIsPspDirect, orgIsEcDirect, orgIsPspBrokerSigned, orgIsEcBrokerSigned } = + useOrganizationType(); - const [isPartnerPSPChecked, setIsPartnerPSPChecked] = useState(orgIsPspBrokerSigned); - const [isPartnerCIChecked, setIsPartnerCIChecked] = useState(orgIsEcBrokerSigned); - const [hasCIStations, setHasCIStations] = useState(true); - const [hasPSPChannels, setHasPSPChannels] = useState(true); + const [isPartnerPSPChecked, setIsPartnerPSPChecked] = useState(orgIsPspBrokerSigned); + const [isPartnerCIChecked, setIsPartnerCIChecked] = useState(orgIsEcBrokerSigned); + const [hasCIStations, setHasCIStations] = useState(true); + const [hasPSPChannels, setHasPSPChannels] = useState(true); - useEffect(() => { - if (selectedParty) { - setLoading(true); - const brokerCode = selectedParty?.fiscalCode ?? ''; + useEffect(() => { + if (selectedParty) { + setLoading(true); + const brokerCode = selectedParty?.fiscalCode ?? ''; - Promise.all([ - getStationsMerged(0, brokerCode, undefined, 1), - getChannelsMerged(0, brokerCode, undefined, 1), - ]) - .then(([stations, channels]) => { - setHasCIStations( - stations?.pageInfo?.items_found !== undefined && stations.pageInfo.items_found > 0 - ); - setHasPSPChannels( - channels?.page_info?.items_found !== undefined && channels.page_info.items_found > 0 - ); - }) - .catch((reason) => { - addError({ - id: 'RETRIEVE_STATIONS_CHANNEL_ERROR', - blocking: false, - error: reason, - techDescription: `An error occurred while retrieving partner stations and channels`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t( - 'nodeSignInPage.error.retrieveChannelsAndStationsErrorMessage' - ), - component: 'Toast', - }); - }) - .finally(() => setLoading(false)); + Promise.all([ + getStations({ status: ConfigurationStatus.ACTIVE, brokerCode, page: 0, limit: 1}), + getStations({ status: ConfigurationStatus.TO_BE_VALIDATED, brokerCode, page: 0, limit: 1}), + getChannels({ status: ConfigurationStatus.ACTIVE, brokerCode, page: 0, limit: 1}), + getChannels({ status: ConfigurationStatus.TO_BE_VALIDATED, brokerCode, page: 0, limit: 1}), + ]) + .then(([activeStations, toBeActivatedStations, activeChannels, toBeActivatedChannels]) => { + setHasCIStations( + (activeStations?.pageInfo?.total_items !== undefined && + activeStations.pageInfo.total_items > 0) || + (toBeActivatedStations?.pageInfo?.total_items !== undefined && + toBeActivatedStations.pageInfo.total_items > 0) + ); + setHasPSPChannels( + (activeChannels?.page_info?.total_items !== undefined && + activeChannels.page_info.total_items > 0) || + (toBeActivatedChannels?.page_info?.total_items !== undefined && + toBeActivatedChannels.page_info.total_items > 0) + ); + }) + .catch((reason) => { + addError({ + id: 'RETRIEVE_STATIONS_CHANNEL_ERROR', + blocking: false, + error: reason, + techDescription: `An error occurred while retrieving partner stations and channels`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t( + 'nodeSignInPage.error.retrieveChannelsAndStationsErrorMessage' + ), + component: 'Toast', + }); + }) + .finally(() => setLoading(false)); - setIsPartnerPSPChecked(orgIsPspBrokerSigned); - setIsPartnerCIChecked(orgIsEcBrokerSigned); - } - }, [selectedParty, signInData]); - - const initialFormData = (selectedParty?: Party) => ({ - name: selectedParty?.fiscalCode ?? '', - businessName: selectedParty?.description ?? '', - }); + setIsPartnerPSPChecked(orgIsPspBrokerSigned); + setIsPartnerCIChecked(orgIsEcBrokerSigned); + } + }, [selectedParty, signInData]); - // eslint-disable-next-line complexity, sonarjs/cognitive-complexity - const submit = async () => { - setLoading(true); - if (selectedParty) { - try { - if (isPartnerPSPChecked && !orgIsPspBrokerSigned) { - await createPspBroker({ - broker_psp_code: selectedParty.fiscalCode, - description: selectedParty.description, - enabled: true, - extended_fault_bean: true, - }); - } - if (isPartnerCIChecked && !orgIsEcBrokerSigned) { - await createEcBroker({ - broker_code: selectedParty.fiscalCode, - description: selectedParty.description, - }); - } + const initialFormData = (selectedParty?: Party) => ({ + name: selectedParty?.fiscalCode ?? '', + businessName: selectedParty?.description ?? '', + }); - if (!hasPSPChannels && orgIsPspBrokerSigned && !isPartnerPSPChecked) { - await deletePSPBroker(selectedParty.fiscalCode); - } - if (!hasCIStations && orgIsEcBrokerSigned && !isPartnerCIChecked) { - await deleteCIBroker(selectedParty.fiscalCode); - } + // eslint-disable-next-line complexity, sonarjs/cognitive-complexity + const submit = async () => { + setLoading(true); + if (selectedParty) { + try { + if (isPartnerPSPChecked && !orgIsPspBrokerSigned) { + await createPspBroker({ + broker_psp_code: selectedParty.fiscalCode, + description: selectedParty.description, + enabled: true, + extended_fault_bean: true, + }); + } + if (isPartnerCIChecked && !orgIsEcBrokerSigned) { + await createEcBroker({ + broker_code: selectedParty.fiscalCode, + description: selectedParty.description, + }); + } - await updateSigninData(selectedParty); - } catch (reason) { - addError({ - id: 'NODE_SIGNIN_CREATE_PT', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while creating pt`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('nodeSignInPage.form.ptErrorMessageDesc'), - component: 'Toast', - }); - } finally { - setLoading(false); - history.push(ROUTES.HOME, { - alertSuccessMessage: t('nodeSignInPage.form.successMessage'), - }); - } + if (!hasPSPChannels && orgIsPspBrokerSigned && !isPartnerPSPChecked) { + await deletePSPBroker(selectedParty.fiscalCode); + } + if (!hasCIStations && orgIsEcBrokerSigned && !isPartnerCIChecked) { + await deleteCIBroker(selectedParty.fiscalCode); } - }; - const disabledSubmit = () => - isPartnerPSPChecked === orgIsPspBrokerSigned && isPartnerCIChecked === orgIsEcBrokerSigned; + await updateSigninData(selectedParty); + } catch (reason) { + addError({ + id: 'NODE_SIGNIN_CREATE_PT', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while creating pt`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('nodeSignInPage.form.ptErrorMessageDesc'), + component: 'Toast', + }); + } finally { + setLoading(false); + history.push(ROUTES.HOME, { + alertSuccessMessage: t('nodeSignInPage.form.successMessage'), + }); + } + } + }; + + const disabledSubmit = () => + isPartnerPSPChecked === orgIsPspBrokerSigned && isPartnerCIChecked === orgIsEcBrokerSigned; - const formik = useFormik({ - initialValues: initialFormData(selectedParty), - onSubmit: async () => { - await submit(); - }, - validateOnMount: true, - validateOnChange: true, - enableReinitialize: true, - }); + const formik = useFormik({ + initialValues: initialFormData(selectedParty), + onSubmit: async () => { + await submit(); + }, + validateOnMount: true, + validateOnChange: true, + enableReinitialize: true, + }); - return ( -
- - - } - isRequired - > - - - formik.handleChange(e)} - error={formik.touched.name && Boolean(formik.errors.name)} - helperText={formik.touched.name && formik.errors.name} - inputProps={{'data-testid': 'name-test'}} - disabled - /> - - - formik.handleChange(e)} - error={formik.touched.businessName && Boolean(formik.errors.businessName)} - helperText={formik.touched.businessName && formik.errors.businessName} - inputProps={{'data-testid': 'businessName-test'}} - disabled - /> - - - + return ( + + + + } + isRequired + > + + + formik.handleChange(e)} + error={formik.touched.name && Boolean(formik.errors.name)} + helperText={formik.touched.name && formik.errors.name} + inputProps={{ 'data-testid': 'name-test' }} + disabled + /> + + + formik.handleChange(e)} + error={formik.touched.businessName && Boolean(formik.errors.businessName)} + helperText={formik.touched.businessName && formik.errors.businessName} + inputProps={{ 'data-testid': 'businessName-test' }} + disabled + /> + + + - - } - isRequired - > + + } + isRequired + > - - setIsPartnerPSPChecked(event.target.checked)} - disabled={hasPSPChannels} - data-testid="psp-checkbox-test" - /> - } - /> - setIsPartnerCIChecked(event.target.checked)} - disabled={hasCIStations} - data-testid="ec-checkbox-test" - /> - } - /> - - - + + setIsPartnerPSPChecked(event.target.checked)} + disabled={hasPSPChannels} + data-testid="psp-checkbox-test" + /> + } + /> + setIsPartnerCIChecked(event.target.checked)} + disabled={hasCIStations} + data-testid="ec-checkbox-test" + /> + } + /> + + + - - - - - - - - -
- ); + + + + + + + + + + ); }; export const inputGroupStyle = { - borderRadius: 1, - border: 1, - borderColor: theme.palette.divider, - p: 3, - mb: 3, + borderRadius: 1, + border: 1, + borderColor: theme.palette.divider, + p: 3, + mb: 3, }; export default NodeSignInPTForm; diff --git a/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInECForm.test.tsx b/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInECForm.test.tsx index b93c6a002..4b25e457d 100644 --- a/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInECForm.test.tsx +++ b/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInECForm.test.tsx @@ -1,411 +1,449 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react'; -import {createMemoryHistory} from 'history'; +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { createMemoryHistory } from 'history'; import React from 'react'; -import {Provider} from 'react-redux'; -import {Router} from 'react-router-dom'; -import {createStore} from '../../../../redux/store'; +import { Provider } from 'react-redux'; +import { Router } from 'react-router-dom'; +import { createStore } from '../../../../redux/store'; import NodeSignInECForm from '../NodeSignInECForm'; -import {BrokerAndEcDetailsResource} from '../../../../api/generated/portal/BrokerAndEcDetailsResource'; +import { BrokerAndEcDetailsResource } from '../../../../api/generated/portal/BrokerAndEcDetailsResource'; import { - brokerAndEcDetailsResource_ECAndBroker, - brokerAndEcDetailsResource_ECOnly, + brokerAndEcDetailsResource_ECAndBroker, + brokerAndEcDetailsResource_ECOnly, } from '../../../../services/__mocks__/nodeService'; import { - ecAdminSignedDirect, - ecAdminSignedUndirect, - ecAdminUnsigned, + ecAdminSignedDirect, + ecAdminSignedUndirect, + ecAdminUnsigned, } from '../../../../services/__mocks__/partyService'; +import { mockedStations } from '../../../../services/__mocks__/stationService'; const renderApp = ( - signInData: BrokerAndEcDetailsResource, - injectedStore?: ReturnType, - injectedHistory?: ReturnType + signInData: BrokerAndEcDetailsResource, + injectedStore?: ReturnType, + injectedHistory?: ReturnType ) => { - const store = injectedStore ? injectedStore : createStore(); - const history = injectedHistory ? injectedHistory : createMemoryHistory(); - render( - - - - - - - - ); - return {store, history}; + const store = injectedStore ? injectedStore : createStore(); + const history = injectedHistory ? injectedHistory : createMemoryHistory(); + render( + + + + + + + + ); + return { store, history }; }; const setupForm = () => { - const address = screen.getByTestId('address-test') as HTMLInputElement; - const city = screen.getByTestId('city-test') as HTMLInputElement; - const province = screen.getByTestId('province-test') as HTMLSelectElement; - const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; - const fiscalDomicile = screen.getByTestId('fiscal-domicile-test') as HTMLInputElement; + const address = screen.getByTestId('address-test') as HTMLInputElement; + const city = screen.getByTestId('city-test') as HTMLInputElement; + const province = screen.getByTestId('province-test') as HTMLSelectElement; + const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; + const fiscalDomicile = screen.getByTestId('fiscal-domicile-test') as HTMLInputElement; - fireEvent.change(address, {target: {value: 'Via Calindri 21'}}); - expect(address.value).toBe('Via Calindri 21'); + fireEvent.change(address, { target: { value: 'Via Calindri 21' } }); + expect(address.value).toBe('Via Calindri 21'); - fireEvent.change(city, {target: {value: 'Milano'}}); - expect(city.value).toBe('Milano'); + fireEvent.change(city, { target: { value: 'Milano' } }); + expect(city.value).toBe('Milano'); - fireEvent.change(province, {target: {value: 'MI'}}); - expect(province.value).toBe('MI'); + fireEvent.change(province, { target: { value: 'MI' } }); + expect(province.value).toBe('MI'); - fireEvent.change(CAP, {target: {value: '11111'}}); - expect(CAP.value).toBe('11111'); + fireEvent.change(CAP, { target: { value: '11111' } }); + expect(CAP.value).toBe('11111'); - fireEvent.change(fiscalDomicile, {target: {value: 'Via Calindri 21'}}); - expect(fiscalDomicile.value).toBe('Via Calindri 21'); + fireEvent.change(fiscalDomicile, { target: { value: 'Via Calindri 21' } }); + expect(fiscalDomicile.value).toBe('Via Calindri 21'); }; let spyOnCreateECAndBroker: jest.SpyInstance; let spyOnCreateEcIndirect: jest.SpyInstance; let spyOnUpdateCreditorInstitution: jest.SpyInstance; let SpyOnCreateEcBroker: jest.SpyInstance; +let SpyOnGetStations: jest.SpyInstance; beforeEach(() => { - spyOnCreateECAndBroker = jest.spyOn( - require('../../../../services/nodeService'), - 'createECAndBroker' + spyOnCreateECAndBroker = jest.spyOn( + require('../../../../services/nodeService'), + 'createECAndBroker' + ); + spyOnCreateEcIndirect = jest.spyOn( + require('../../../../services/nodeService'), + 'createECIndirect' + ); + spyOnUpdateCreditorInstitution = jest.spyOn( + require('../../../../services/nodeService'), + 'updateCreditorInstitution' + ); + SpyOnCreateEcBroker = jest.spyOn(require('../../../../services/nodeService'), 'createEcBroker'); + SpyOnGetStations = jest.spyOn(require('../../../../services/stationService'), 'getStations'); + + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); +}); + +afterEach(cleanup); + +describe('NodeSignInECForm', () => { + const dispatchAdminUsignedAndSignInDataEmpty = async (store: any) => { + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: ecAdminUnsigned, + }) ); - spyOnCreateEcIndirect = jest.spyOn( - require('../../../../services/nodeService'), - 'createECIndirect' + + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: {}, + }) ); - spyOnUpdateCreditorInstitution = jest.spyOn( - require('../../../../services/nodeService'), - 'updateCreditorInstitution' + }; + + const dispatchAdminSignedIndirectAndEcDetailsOnly = async (store: any) => { + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: ecAdminSignedUndirect, + }) ); - SpyOnCreateEcBroker = jest.spyOn(require('../../../../services/nodeService'), 'createEcBroker'); - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); -}); + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: brokerAndEcDetailsResource_ECOnly, + }) + ); + }; + + const dispatchAdminSignedInDirectAndFullEcDetails = async (store: any) => { + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: ecAdminSignedDirect, + }) + ); -afterEach(cleanup); + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: brokerAndEcDetailsResource_ECAndBroker, + }) + ); + }; -describe('NodeSignInECForm', () => { - const dispatchAdminUsignedAndSignInDataEmpty = async (store: any) => { - await waitFor(() => - store.dispatch({ - type: 'parties/setPartySelected', - payload: ecAdminUnsigned, - }) - ); - - await waitFor(() => - store.dispatch({ - type: 'parties/setSigninData', - payload: {}, - }) - ); - }; - - const dispatchAdminSignedIndirectAndEcDetailsOnly = async (store: any) => { - await waitFor(() => - store.dispatch({ - type: 'parties/setPartySelected', - payload: ecAdminSignedUndirect, - }) - ); - - await waitFor(() => - store.dispatch({ - type: 'parties/setSigninData', - payload: brokerAndEcDetailsResource_ECOnly, - }) - ); - }; - - const dispatchAdminSignedInDirectAndFullEcDetails = async (store: any) => { - await waitFor(() => - store.dispatch({ - type: 'parties/setPartySelected', - payload: ecAdminSignedDirect, - }) - ); - - await waitFor(() => - store.dispatch({ - type: 'parties/setSigninData', - payload: brokerAndEcDetailsResource_ECAndBroker, - }) - ); - }; - - test('Test rendering NodeSignInECForm with intermediary true and Sumbit a direct ec', async () => { - const {store} = renderApp({}); - - dispatchAdminUsignedAndSignInDataEmpty(store); - - setupForm(); - - const intermediaryTrue = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=true]') as HTMLInputElement; - - fireEvent.click(intermediaryTrue); - - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); - - await waitFor(() => { - expect(spyOnCreateECAndBroker).toHaveBeenCalled(); - }); + test('Test rendering NodeSignInECForm with intermediary true and Sumbit a direct ec', async () => { + const { store } = renderApp({}); + + dispatchAdminUsignedAndSignInDataEmpty(store); + + setupForm(); + + const intermediaryTrue = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=true]') as HTMLInputElement; + + fireEvent.click(intermediaryTrue); + + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); + + await waitFor(() => { + expect(spyOnCreateECAndBroker).toHaveBeenCalled(); }); + }); - test('Test rendering NodeSignInECForm with intermediary false and Sumbit an inderiect ec', async () => { - const ecDetailsDispatched = {}; + test('Test rendering NodeSignInECForm with intermediary false and Sumbit an inderiect ec', async () => { + const ecDetailsDispatched = {}; - const {store} = renderApp(ecDetailsDispatched); + const { store } = renderApp(ecDetailsDispatched); - dispatchAdminUsignedAndSignInDataEmpty(store); + dispatchAdminUsignedAndSignInDataEmpty(store); - setupForm(); + setupForm(); - const intermediaryFalse = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=false]') as HTMLInputElement; + const intermediaryFalse = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=false]') as HTMLInputElement; - fireEvent.click(intermediaryFalse); + fireEvent.click(intermediaryFalse); - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); - await waitFor(() => expect(spyOnCreateEcIndirect).toHaveBeenCalled()); - }); + await waitFor(() => expect(spyOnCreateEcIndirect).toHaveBeenCalled()); + }); - test('Test rendering NodeSignInECForm and BackBtn click', async () => { - renderApp({}); - const backBtn = await screen.findByTestId('back-button-test'); - fireEvent.click(backBtn); - }); + test('Test rendering NodeSignInECForm and BackBtn click', async () => { + renderApp({}); + const backBtn = await screen.findByTestId('back-button-test'); + fireEvent.click(backBtn); + }); - test('Test rendering NodeSignInECForm with intermediary true and create ecBroker', async () => { - const {store} = renderApp(brokerAndEcDetailsResource_ECOnly); + test('Test rendering NodeSignInECForm with intermediary true and create ecBroker', async () => { + const { store } = renderApp(brokerAndEcDetailsResource_ECOnly); - await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); + await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); - const intermediaryTrue = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=true]') as HTMLInputElement; + const intermediaryTrue = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=true]') as HTMLInputElement; - fireEvent.click(intermediaryTrue); + fireEvent.click(intermediaryTrue); - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); - await waitFor(() => { - expect(SpyOnCreateEcBroker).toHaveBeenCalled(); - }); + await waitFor(() => { + expect(SpyOnCreateEcBroker).toHaveBeenCalled(); }); + }); - test('Test rendering NodeSignInECForm in case of updating the form with an ec direct', async () => { - const {store} = renderApp(brokerAndEcDetailsResource_ECAndBroker); - - dispatchAdminSignedInDirectAndFullEcDetails(store); - - const address = screen.getByTestId('address-test') as HTMLInputElement; - const city = screen.getByTestId('city-test') as HTMLInputElement; - const province = screen.getByTestId('province-test') as HTMLSelectElement; - const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; - const fiscalDomicile = screen.getByTestId('fiscal-domicile-test') as HTMLInputElement; - - expect(address.value).toBe( - brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.location! - ); - expect(city.value).toBe( - brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.city! - ); - expect(province.value).toBe( - brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.countryCode! - ); - expect(CAP.value).toBe( - brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.zipCode! - ); - expect(fiscalDomicile.value).toBe( - brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.taxDomicile! - ); - - fireEvent.change(address, {target: {value: 'Via Roma 11'}}); - expect(address.value).toBe('Via Roma 11'); - - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); - - await waitFor(() => { - expect(spyOnUpdateCreditorInstitution).toHaveBeenCalled(); - }); - }); + test('Test rendering NodeSignInECForm in case of updating the form with an ec direct', async () => { + const { store } = renderApp(brokerAndEcDetailsResource_ECAndBroker); + + dispatchAdminSignedInDirectAndFullEcDetails(store); + + const address = screen.getByTestId('address-test') as HTMLInputElement; + const city = screen.getByTestId('city-test') as HTMLInputElement; + const province = screen.getByTestId('province-test') as HTMLSelectElement; + const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; + const fiscalDomicile = screen.getByTestId('fiscal-domicile-test') as HTMLInputElement; + + expect(address.value).toBe( + brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.location! + ); + expect(city.value).toBe( + brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.city! + ); + expect(province.value).toBe( + brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address! + .countryCode! + ); + expect(CAP.value).toBe( + brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address!.zipCode! + ); + expect(fiscalDomicile.value).toBe( + brokerAndEcDetailsResource_ECAndBroker!.creditorInstitutionDetailsResource!.address! + .taxDomicile! + ); + + fireEvent.change(address, { target: { value: 'Via Roma 11' } }); + expect(address.value).toBe('Via Roma 11'); + + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); - test('Test rendering NodeSignInECForm in case of updating the form with an ec indirect', async () => { - const {store} = renderApp(brokerAndEcDetailsResource_ECOnly); - - await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); - - const address = screen.getByTestId('address-test') as HTMLInputElement; - const city = screen.getByTestId('city-test') as HTMLInputElement; - const province = screen.getByTestId('province-test') as HTMLSelectElement; - const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; - const fiscalDomicile = screen.getByTestId('fiscal-domicile-test') as HTMLInputElement; - const intermediaryTrue = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=true]') as HTMLInputElement; - const intermediaryFalse = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=false]') as HTMLInputElement; - - expect(address.value).toBe( - brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.location! - ); - expect(city.value).toBe( - brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.city! - ); - expect(province.value).toBe( - brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.countryCode! - ); - expect(CAP.value).toBe( - brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.zipCode! - ); - expect(fiscalDomicile.value).toBe( - brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.taxDomicile! - ); - - expect(intermediaryFalse.checked).toBe(true); - - fireEvent.change(address, {target: {value: 'Via Roma 11'}}); - expect(address.value).toBe('Via Roma 11'); - - expect(intermediaryTrue.checked).toBe(false); - fireEvent.click(intermediaryTrue); - expect(intermediaryTrue.checked).toBe(true); - - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); - - await waitFor(() => expect(SpyOnCreateEcBroker).toHaveBeenCalled()); - await waitFor(() => expect(spyOnUpdateCreditorInstitution).toHaveBeenCalled()); + await waitFor(() => { + expect(spyOnUpdateCreditorInstitution).toHaveBeenCalled(); }); + }); - test('Test NodeSignInECForm function falsy conditions', async () => { - const {store} = renderApp({}); + test('Test rendering NodeSignInECForm in case of updating the form with an ec indirect', async () => { + const { store } = renderApp(brokerAndEcDetailsResource_ECOnly); - await waitFor(() => - store.dispatch({ - type: 'parties/setPartySelected', - payload: { - ...ecAdminUnsigned, - description: undefined, - fiscalCode: undefined, - }, - }) - ); + await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); - await waitFor(() => - store.dispatch({ - type: 'parties/setSigninData', - payload: undefined, - }) - ); + const address = screen.getByTestId('address-test') as HTMLInputElement; + const city = screen.getByTestId('city-test') as HTMLInputElement; + const province = screen.getByTestId('province-test') as HTMLSelectElement; + const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; + const fiscalDomicile = screen.getByTestId('fiscal-domicile-test') as HTMLInputElement; + const intermediaryTrue = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=true]') as HTMLInputElement; + const intermediaryFalse = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=false]') as HTMLInputElement; + + expect(address.value).toBe( + brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.location! + ); + expect(city.value).toBe( + brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.city! + ); + expect(province.value).toBe( + brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.countryCode! + ); + expect(CAP.value).toBe( + brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.zipCode! + ); + expect(fiscalDomicile.value).toBe( + brokerAndEcDetailsResource_ECOnly!.creditorInstitutionDetailsResource!.address!.taxDomicile! + ); - setupForm(); + expect(intermediaryFalse.checked).toBe(true); - const province = screen.getByTestId('province-test') as HTMLSelectElement; - const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; - const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.change(address, { target: { value: 'Via Roma 11' } }); + expect(address.value).toBe('Via Roma 11'); - fireEvent.change(province, {target: {value: 'M'}}); - expect(province.value).toBe('M'); + expect(intermediaryTrue.checked).toBe(false); + fireEvent.click(intermediaryTrue); + expect(intermediaryTrue.checked).toBe(true); - fireEvent.change(province, {target: {value: '12'}}); - expect(province.value).toBe('M'); + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); - fireEvent.change(CAP, {target: {value: '1111'}}); - expect(CAP.value).toBe('1111'); + await waitFor(() => expect(SpyOnCreateEcBroker).toHaveBeenCalled()); + await waitFor(() => expect(spyOnUpdateCreditorInstitution).toHaveBeenCalled()); + }); - fireEvent.change(CAP, {target: {value: 'AAAAA'}}); - expect(CAP.value).toBe('1111'); + test('Test NodeSignInECForm function falsy conditions', async () => { + const { store } = renderApp({}); - fireEvent.click(confirmBtn); + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: { + ...ecAdminUnsigned, + description: undefined, + fiscalCode: undefined, + }, + }) + ); - setupForm(); + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: undefined, + }) + ); - fireEvent.click(confirmBtn); - }); + setupForm(); - test('Test error response of createECAndBroker', async () => { - const {store} = renderApp({}); + const province = screen.getByTestId('province-test') as HTMLSelectElement; + const CAP = screen.getByTestId('CAP-test') as HTMLInputElement; + const confirmBtn = await screen.findByTestId('continue-button-test'); - dispatchAdminUsignedAndSignInDataEmpty(store); + fireEvent.change(province, { target: { value: 'M' } }); + expect(province.value).toBe('M'); - setupForm(); + fireEvent.change(province, { target: { value: '12' } }); + expect(province.value).toBe('M'); - const intermediaryTrue = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=true]') as HTMLInputElement; + fireEvent.change(CAP, { target: { value: '1111' } }); + expect(CAP.value).toBe('1111'); - fireEvent.click(intermediaryTrue); + fireEvent.change(CAP, { target: { value: 'AAAAA' } }); + expect(CAP.value).toBe('1111'); - spyOnCreateECAndBroker.mockRejectedValue(() => { - throw new Error('Error in createECAndBroker'); - }); + fireEvent.click(confirmBtn); - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); + setupForm(); + + fireEvent.click(confirmBtn); + }); + + test('Test error response of createECAndBroker', async () => { + const { store } = renderApp({}); + + dispatchAdminUsignedAndSignInDataEmpty(store); + + setupForm(); + + const intermediaryTrue = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=true]') as HTMLInputElement; + + fireEvent.click(intermediaryTrue); + + spyOnCreateECAndBroker.mockRejectedValue(() => { + throw new Error('Error in createECAndBroker'); }); - test('Test error response of createECIndirect', async () => { - const {store} = renderApp({}); + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); + }); - dispatchAdminUsignedAndSignInDataEmpty(store); + test('Test error response of createECIndirect', async () => { + const { store } = renderApp({}); - setupForm(); + dispatchAdminUsignedAndSignInDataEmpty(store); - spyOnCreateEcIndirect.mockRejectedValue(() => { - throw new Error('Error in createECIndirect'); - }); + setupForm(); - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); + spyOnCreateEcIndirect.mockRejectedValue(() => { + throw new Error('Error in createECIndirect'); }); - test('Test error response of updateCreditorInstitution with intermediary true', async () => { - const {store} = renderApp(brokerAndEcDetailsResource_ECAndBroker); + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); + }); - dispatchAdminSignedInDirectAndFullEcDetails(store); + test('Test error response of updateCreditorInstitution with intermediary true', async () => { + const { store } = renderApp(brokerAndEcDetailsResource_ECAndBroker); - const address = screen.getByTestId('address-test') as HTMLInputElement; + dispatchAdminSignedInDirectAndFullEcDetails(store); - fireEvent.change(address, {target: {value: 'Via Roma 11'}}); - expect(address.value).toBe('Via Roma 11'); + const address = screen.getByTestId('address-test') as HTMLInputElement; - spyOnUpdateCreditorInstitution.mockRejectedValue(() => { - throw new Error('Error in updateCreditorInstitution'); - }); + fireEvent.change(address, { target: { value: 'Via Roma 11' } }); + expect(address.value).toBe('Via Roma 11'); - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); + spyOnUpdateCreditorInstitution.mockRejectedValue(() => { + throw new Error('Error in updateCreditorInstitution'); }); - test('Test error response of updateCreditorInstitution with intermediary false', async () => { - const {store} = renderApp(brokerAndEcDetailsResource_ECOnly); + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); + }); - await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); + test('Test error response of updateCreditorInstitution with intermediary false', async () => { + const { store } = renderApp(brokerAndEcDetailsResource_ECOnly); - const address = screen.getByTestId('address-test') as HTMLInputElement; + await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); - fireEvent.change(address, {target: {value: 'Via Roma 11'}}); - expect(address.value).toBe('Via Roma 11'); + const address = screen.getByTestId('address-test') as HTMLInputElement; - spyOnUpdateCreditorInstitution.mockRejectedValue(() => { - throw new Error('Error in updateCreditorInstitution'); - }); + fireEvent.change(address, { target: { value: 'Via Roma 11' } }); + expect(address.value).toBe('Via Roma 11'); - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); + spyOnUpdateCreditorInstitution.mockRejectedValue(() => { + throw new Error('Error in updateCreditorInstitution'); }); + + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); + }); + + test('Test getStations for intermediaryAvailable true', async () => { + SpyOnGetStations.mockReturnValue(mockedStations); + const { store } = renderApp(brokerAndEcDetailsResource_ECOnly); + await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); + + const address = screen.getByTestId('address-test') as HTMLInputElement; + expect(address).toBeInTheDocument(); + }); + + test('Test getStations for intermediaryAvailable false', async () => { + SpyOnGetStations.mockReturnValue({ + pageInfo: { + page: 0, + limit: 50, + items_found: 0, + total_pages: 0, + }, + stationsList: [], + }); + const { store } = renderApp(brokerAndEcDetailsResource_ECOnly); + await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); + + const address = screen.getByTestId('address-test') as HTMLInputElement; + expect(address).toBeInTheDocument(); + }); + + test('Test getStations error', async () => { + SpyOnGetStations.mockRejectedValue('error'); + const { store } = renderApp(brokerAndEcDetailsResource_ECOnly); + await waitFor(() => dispatchAdminSignedIndirectAndEcDetailsOnly(store)); + + const address = screen.getByTestId('address-test') as HTMLInputElement; + expect(address).toBeInTheDocument(); + }); }); diff --git a/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPSPForm.test.tsx b/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPSPForm.test.tsx index 1d1013999..f22f0a03e 100644 --- a/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPSPForm.test.tsx +++ b/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPSPForm.test.tsx @@ -17,6 +17,7 @@ import { pspAdminUnsigned, } from '../../../../services/__mocks__/partyService'; import {BrokerOrPspDetailsResource} from '../../../../api/generated/portal/BrokerOrPspDetailsResource'; +import { mockedChannels } from '../../../../services/__mocks__/channelService'; let createPSPDirectMocked: jest.SpyInstance; let createPSPIndirectMocked: jest.SpyInstance; @@ -24,6 +25,7 @@ let useSigninDataMocked: jest.SpyInstance; let updatePSPInfoMocked: jest.SpyInstance; let getBrokerAndPspDetailsMocked: jest.SpyInstance; let createPspBroker: jest.SpyInstance; +let spyOnGetChannels: jest.SpyInstance; jest.mock('../../../../decorators/withSelectedParty'); @@ -93,6 +95,7 @@ beforeEach(() => { 'getBrokerAndPspDetails' ); createPspBroker = jest.spyOn(require('../../../../services/nodeService'), 'createPspBroker'); + spyOnGetChannels = jest.spyOn(require('../../../../services/channelService'), 'getChannels'); jest.spyOn(console, 'error').mockImplementation(() => { }); @@ -240,86 +243,158 @@ describe('NodeSignInPSPForm', () => { const confirmBtn = await screen.findByTestId('continue-button-test'); fireEvent.click(confirmBtn); }); -}); - -test('Test rendering NodeSignInPSPForm in case of updating the form with a psp direct', async () => { - const {store} = renderApp(brokerOrPspDetailsResource_PSPAndBroker); - - await waitFor(() => - store.dispatch({ - type: 'parties/setSigninData', - payload: brokerOrPspDetailsResource_PSPAndBroker, - }) - ); - - await waitFor(() => - store.dispatch({ - type: 'parties/setPartySelected', - payload: pspAdminSignedDirect, - }) - ); - const bicCode = screen.getByTestId('bicCode-test') as HTMLInputElement; - expect(bicCode.value).toBe( - brokerOrPspDetailsResource_PSPAndBroker.paymentServiceProviderDetailsResource?.bic - ); - - fireEvent.change(bicCode, {target: {value: '12345'}}); - expect(bicCode.value).toBe('12345'); - - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); - - await waitFor(() => { - expect(updatePSPInfoMocked).toHaveBeenCalled(); + test('Test rendering NodeSignInPSPForm in case of updating the form with a psp direct', async () => { + const {store} = renderApp(brokerOrPspDetailsResource_PSPAndBroker); + + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: brokerOrPspDetailsResource_PSPAndBroker, + }) + ); + + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: pspAdminSignedDirect, + }) + ); + const bicCode = screen.getByTestId('bicCode-test') as HTMLInputElement; + + expect(bicCode.value).toBe( + brokerOrPspDetailsResource_PSPAndBroker.paymentServiceProviderDetailsResource?.bic + ); + + fireEvent.change(bicCode, {target: {value: '12345'}}); + expect(bicCode.value).toBe('12345'); + + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); + + await waitFor(() => { + expect(updatePSPInfoMocked).toHaveBeenCalled(); + }); }); -}); - -test('Test rendering NodeSignInPSPForm in case of updating the form with a psp indirect', async () => { - const {store} = renderApp(brokerOrPspDetailsResource_PSPOnly); - - await waitFor(() => - store.dispatch({ - type: 'parties/setSigninData', - payload: brokerOrPspDetailsResource_PSPOnly, - }) - ); - - await waitFor(() => - store.dispatch({ - type: 'parties/setPartySelected', - payload: pspAdminSignedUndirect, - }) - ); - const bicCode = screen.getByTestId('bicCode-test') as HTMLInputElement; - const intermediaryFalse = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=false]') as HTMLInputElement; - const intermediaryTrue = screen - .getByTestId('intermediary-available-test') - .querySelector('[value=true]') as HTMLInputElement; - - expect(bicCode.value).toBe( - brokerOrPspDetailsResource_PSPOnly.paymentServiceProviderDetailsResource?.bic - ); - expect(intermediaryFalse.checked).toBe(true); - - fireEvent.change(bicCode, {target: {value: '12345'}}); - expect(bicCode.value).toBe('12345'); - - expect(intermediaryTrue.checked).toBe(false); - fireEvent.click(intermediaryTrue); - expect(intermediaryTrue.checked).toBe(true); - - const confirmBtn = await screen.findByTestId('continue-button-test'); - fireEvent.click(confirmBtn); - - await waitFor(() => expect(createPspBroker).toHaveBeenCalledTimes(1)); - await waitFor(() => { - expect(updatePSPInfoMocked).toHaveBeenCalled(); + + test('Test rendering NodeSignInPSPForm in case of updating the form with a psp indirect', async () => { + const {store} = renderApp(brokerOrPspDetailsResource_PSPOnly); + + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: brokerOrPspDetailsResource_PSPOnly, + }) + ); + + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: pspAdminSignedUndirect, + }) + ); + const bicCode = screen.getByTestId('bicCode-test') as HTMLInputElement; + const intermediaryFalse = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=false]') as HTMLInputElement; + const intermediaryTrue = screen + .getByTestId('intermediary-available-test') + .querySelector('[value=true]') as HTMLInputElement; + + expect(bicCode.value).toBe( + brokerOrPspDetailsResource_PSPOnly.paymentServiceProviderDetailsResource?.bic + ); + expect(intermediaryFalse.checked).toBe(true); + + fireEvent.change(bicCode, {target: {value: '12345'}}); + expect(bicCode.value).toBe('12345'); + + expect(intermediaryTrue.checked).toBe(false); + fireEvent.click(intermediaryTrue); + expect(intermediaryTrue.checked).toBe(true); + + const confirmBtn = await screen.findByTestId('continue-button-test'); + fireEvent.click(confirmBtn); + + await waitFor(() => expect(createPspBroker).toHaveBeenCalledTimes(1)); + await waitFor(() => { + expect(updatePSPInfoMocked).toHaveBeenCalled(); + }); + }); + + test('Test getChannels for intermediaryAvailable true', async () => { + spyOnGetChannels.mockReturnValue(mockedChannels); + const {store} = renderApp(brokerOrPspDetailsResource_PSPOnly); + + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: brokerOrPspDetailsResource_PSPOnly, + }) + ); + + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: pspAdminSignedUndirect, + }) + ); + const bicCode = screen.getByTestId('bicCode-test') as HTMLInputElement; + expect(bicCode).toBeInTheDocument(); + }); + + test('Test getChannels for intermediaryAvailable false', async () => { + spyOnGetChannels.mockReturnValue({ + channels: [], + page_info: { + page: 0, + limit: 50, + items_found: 0, + total_pages: 0, + }, + }); + const {store} = renderApp(brokerOrPspDetailsResource_PSPOnly); + + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: brokerOrPspDetailsResource_PSPOnly, + }) + ); + + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: pspAdminSignedUndirect, + }) + ); + const bicCode = screen.getByTestId('bicCode-test') as HTMLInputElement; + expect(bicCode).toBeInTheDocument(); + }); + + test('Test getChannels error', async () => { + spyOnGetChannels.mockRejectedValue('error'); + const {store} = renderApp(brokerOrPspDetailsResource_PSPOnly); + + await waitFor(() => + store.dispatch({ + type: 'parties/setSigninData', + payload: brokerOrPspDetailsResource_PSPOnly, + }) + ); + + await waitFor(() => + store.dispatch({ + type: 'parties/setPartySelected', + payload: pspAdminSignedUndirect, + }) + ); + const bicCode = screen.getByTestId('bicCode-test') as HTMLInputElement; + expect(bicCode).toBeInTheDocument(); }); }); + const pspPartySelected = { partyId: '26a0aabf-ce6a-4dfa-af4e-d4f744a8b944', externalId: '15376371009', diff --git a/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPTForm.test.tsx b/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPTForm.test.tsx index dd5b9eda4..e512177b6 100644 --- a/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPTForm.test.tsx +++ b/src/pages/dashboard/nodeSignIn/__tests__/NodeSignInPTForm.test.tsx @@ -20,8 +20,8 @@ let spyOnCreateBrokerPsp: jest.SpyInstance; let spyOnCreateEcBroker: jest.SpyInstance; let spyOnGetPSPBrokerDetails: jest.SpyInstance; let spyOnGetBrokerAndEcDetails: jest.SpyInstance; -let spyOnGetStationsMerged: jest.SpyInstance; -let spyOnGetChannelsMerged: jest.SpyInstance; +let spyOnGetStations: jest.SpyInstance; +let spyOnGetChannels: jest.SpyInstance; beforeEach(() => { spyOnCreateBrokerPsp = jest.spyOn(require('../../../../services/nodeService'), 'createPspBroker'); @@ -34,13 +34,13 @@ beforeEach(() => { require('../../../../services/nodeService'), 'getBrokerAndEcDetails' ); - spyOnGetStationsMerged = jest.spyOn( + spyOnGetStations = jest.spyOn( require("../../../../services/stationService"), - "getStationsMerged" + "getStations" ); - spyOnGetChannelsMerged = jest.spyOn( + spyOnGetChannels = jest.spyOn( require("../../../../services/channelService"), - "getChannelsMerged" + "getChannels" ); jest.spyOn(console, 'error').mockImplementation(() => { }); @@ -564,8 +564,8 @@ describe('', () => { orgIsPspSigned: false }); - spyOnGetStationsMerged.mockReturnValueOnce(Promise.resolve({})); - spyOnGetChannelsMerged.mockReturnValueOnce(Promise.resolve({})); + spyOnGetStations.mockReturnValueOnce(Promise.resolve({})); + spyOnGetChannels.mockReturnValueOnce(Promise.resolve({})); const {store, pspCheckbox, ecCheckbox} = renderApp({}); await waitFor(() => store.dispatch({ @@ -599,8 +599,8 @@ describe('', () => { orgIsPspSigned: false }); - spyOnGetStationsMerged.mockReturnValueOnce(Promise.resolve(mockedStationsMerged2)); - spyOnGetChannelsMerged.mockReturnValueOnce(Promise.resolve(mockedChannelsMerged)); + spyOnGetStations.mockReturnValueOnce(Promise.resolve(mockedStationsMerged2)); + spyOnGetChannels.mockReturnValueOnce(Promise.resolve(mockedChannelsMerged)); const {store, pspCheckbox, ecCheckbox} = renderApp({}); await waitFor(() => store.dispatch({ @@ -635,8 +635,8 @@ describe('', () => { orgIsPspSigned: false }); - spyOnGetStationsMerged.mockReturnValueOnce(Promise.resolve(mockedStationsMerged2)); - spyOnGetChannelsMerged.mockReturnValueOnce(Promise.resolve({})); + spyOnGetStations.mockReturnValueOnce(Promise.resolve(mockedStationsMerged2)); + spyOnGetChannels.mockReturnValueOnce(Promise.resolve({})); const {store, pspCheckbox, ecCheckbox} = renderApp({}); await waitFor(() => store.dispatch({ @@ -671,8 +671,8 @@ describe('', () => { orgIsPspSigned: false }); - spyOnGetStationsMerged.mockReturnValueOnce(Promise.resolve({})); - spyOnGetChannelsMerged.mockReturnValueOnce(Promise.resolve(mockedChannelsMerged)); + spyOnGetStations.mockReturnValueOnce(Promise.resolve({})); + spyOnGetChannels.mockReturnValueOnce(Promise.resolve(mockedChannelsMerged)); const {store, pspCheckbox, ecCheckbox} = renderApp({}); await waitFor(() => store.dispatch({ diff --git a/src/pages/stations/list/__tests__/StationsTable.test.tsx b/src/pages/stations/list/__tests__/StationsTable.test.tsx index ba28a5105..af6bf22aa 100644 --- a/src/pages/stations/list/__tests__/StationsTable.test.tsx +++ b/src/pages/stations/list/__tests__/StationsTable.test.tsx @@ -14,7 +14,7 @@ import { mockedStations } from '../../../../services/__mocks__/stationService'; import * as StationService from '../../../../services/stationService'; import StationsTable from '../StationsTable'; -const mockGetStationsMerged = jest.spyOn(StationService, 'getStationsMerged'); +const mockGetStations = jest.spyOn(StationService, 'getStations'); beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(() => { @@ -41,7 +41,7 @@ const Component = () => { describe('', () => { test('render component StationTable', async () => { - mockGetStationsMerged.mockReturnValueOnce(Promise.resolve(mockedStations)); + mockGetStations.mockReturnValueOnce(Promise.resolve(mockedStations)); render( @@ -53,7 +53,7 @@ describe('', () => { }); }); test('render component StationTable error getStationMerged', async () => { - mockGetStationsMerged.mockRejectedValueOnce('error'); + mockGetStations.mockRejectedValueOnce('error'); render( diff --git a/src/services/__mocks__/stationService.ts b/src/services/__mocks__/stationService.ts index 7668fd572..3d18247c9 100644 --- a/src/services/__mocks__/stationService.ts +++ b/src/services/__mocks__/stationService.ts @@ -81,7 +81,6 @@ export const mockedFullStation: StationDetailResource = { targetHostPof: 'hostPof', targetPathPof: 'pathPof', targetPortPof: 456, - isConnectionSync: true, proxyEnabled: false, proxyHost: 'proxyHost', proxyPort: 888, diff --git a/src/services/__tests__/channelService.test.ts b/src/services/__tests__/channelService.test.ts index 00321ba51..5210932d1 100644 --- a/src/services/__tests__/channelService.test.ts +++ b/src/services/__tests__/channelService.test.ts @@ -11,7 +11,6 @@ import { mockedChannelPSPs, mockedChannelPSPsPage2, mockedChannels, - mockedChannelsMerged, mockedPSPChannels, mockedPaymentTypesResource, mockedWfespPlugIn, @@ -27,14 +26,11 @@ import { getChannelDetail, getChannelPSPs, getChannels, - getChannelsIdAssociatedToPSP, - getChannelsMerged, getPSPChannels, getWfespPlugins, getWrapperEntities, updateChannel, - updateWrapperChannelDetailsByOpt, - updateWrapperChannelDetailsToCheck, + updateWrapperChannelDetails, updateWrapperChannelWithOperatorReview, } from '../channelService.ts'; @@ -49,10 +45,6 @@ describe('ChannelService test mocked', () => { }); expect(response).toMatchObject(mockedChannels); }); - test('Test getChannelsMerged', async () => { - const response = await getChannelsMerged(0, 'brokerCode'); - expect(response).toMatchObject(mockedChannelsMerged); - }); test('Test getChannelDetail', async () => { const response = await getChannelDetail('channelId'); expect(response).toMatchObject(mockedChannelDetail('channelId')); @@ -61,10 +53,6 @@ describe('ChannelService test mocked', () => { const response = await getPSPChannels('pspTaxCode'); expect(response).toMatchObject(channelEnabled(mockedPSPChannels)); }); - test('Test getChannelsIdAssociatedToPSP', async () => { - const response = await getChannelsIdAssociatedToPSP(0, 'brokerCode'); - expect(response).toMatchObject(mockedChannelsMerged!.channels!.map((el) => el!.channel_code)); - }); test('Test getWfespPlugins', async () => { const response = await getWfespPlugins(); expect(response).toMatchObject(mockedWfespPlugIn); @@ -129,8 +117,8 @@ describe('ChannelService test mocked', () => { ); expect(response).toMatchObject(mockedWrapperChannel); }); - test('Test updateWrapperChannelDetailsToCheck', async () => { - const response = await updateWrapperChannelDetailsToCheck({ + test('Test updateWrapperChannelDetails', async () => { + const response = await updateWrapperChannelDetails({ channelCode: 'channelCode', channel: { broker_description: '', @@ -147,23 +135,6 @@ describe('ChannelService test mocked', () => { }); expect(response).toMatchObject(mockedWrapperChannel); }); - test('Test updateWrapperChannelDetailsByOpt', async () => { - const response = await updateWrapperChannelDetailsByOpt( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - ); - expect(response).toMatchObject(mockedWrapperChannel); - }); test('Test updateWrapperChannelWithOperatorReview', async () => { const response = await updateWrapperChannelWithOperatorReview({ channelCode: 'channelCode', @@ -200,13 +171,6 @@ describe('ChannelService test client', () => { ).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); - test('Test getChannelsMerged', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getChannelsMerged') - .mockReturnValue(Promise.resolve(mockedChannelsMerged)); - expect(getChannelsMerged(0, 'brokerCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); test('Test getChannelDetail', async () => { const spyOn = jest .spyOn(BackofficeApi, 'getChannelDetail') @@ -221,13 +185,6 @@ describe('ChannelService test client', () => { expect(getPSPChannels('pspTaxCode')).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); - test('Test getChannelsIdAssociatedToPSP', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getChannelsMerged') - .mockReturnValue(new Promise((resolve) => resolve(mockedChannelsMerged))); - expect(getChannelsIdAssociatedToPSP(0, 'brokerCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); test('Test getWfespPlugins', async () => { const spyOn = jest .spyOn(BackofficeApi, 'getWfespPlugins') @@ -284,7 +241,7 @@ describe('ChannelService test client', () => { test('Test associatePSPtoChannel', async () => { const spyOn = jest .spyOn(BackofficeApi, 'associatePSPtoChannel') - .mockReturnValue(Promise.resolve(mockedPaymentTypesResource)); + .mockReturnValue(new Promise((resolve) => resolve(mockedPaymentTypesResource))); expect( associatePSPtoChannel('channelCode', 'taxCode', { payment_types: [], @@ -328,13 +285,13 @@ describe('ChannelService test client', () => { ).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); - test('Test updateWrapperChannelDetailsToCheck', async () => { + test('Test updateWrapperChannelDetails', async () => { const spyOn = jest - .spyOn(BackofficeApi, 'updateWrapperChannelDetailsToCheck') - .mockReturnValue(new Promise((resolve) => resolve({}))); + .spyOn(BackofficeApi, 'updateWrapperChannelDetails') + .mockReturnValue(Promise.resolve({})); expect( - updateWrapperChannelDetailsToCheck({ - channelCode: 'channelCode', + updateWrapperChannelDetails({ + channelCode: 'channel_code', channel: { broker_description: '', broker_psp_code: '', @@ -351,28 +308,6 @@ describe('ChannelService test client', () => { ).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); - test('Test updateWrapperChannelDetailsByOpt', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'updateWrapperChannelDetailsByOpt') - .mockReturnValue(new Promise((resolve) => resolve({}))); - expect( - updateWrapperChannelDetailsByOpt( - { - broker_description: '', - broker_psp_code: '', - channel_code: '', - payment_types: [], - redirect_protocol: Redirect_protocolEnum.HTTPS, - target_host: '', - target_path: '', - target_port: 0, - validationUrl: '', - }, - 'validationUrl' - ) - ).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); test('Test updateWrapperChannelWithOperatorReview', async () => { const spyOn = jest .spyOn(BackofficeApi, 'updateWrapperChannelWithOperatorReview') diff --git a/src/services/__tests__/stationService.test.ts b/src/services/__tests__/stationService.test.ts index 9914cf93b..b518a97d3 100644 --- a/src/services/__tests__/stationService.test.ts +++ b/src/services/__tests__/stationService.test.ts @@ -1,6 +1,6 @@ -import {BackofficeApi} from '../../api/BackofficeClient'; -import {TestStationTypeEnum} from '../../api/generated/portal/StationTestDto'; -import {ConfigurationStatus} from '../../model/Station'; +import { BackofficeApi } from '../../api/BackofficeClient'; +import { TestStationTypeEnum } from '../../api/generated/portal/StationTestDto'; +import { ConfigurationStatus } from '../../model/Station'; import { mockedCreatedStation, mockedCreditorInstitutionStationDTO, @@ -12,11 +12,10 @@ import { mockedStationDetailsDTO, mockedStationECs, mockedStations, - mockedStationsMerged2, mockedWrapperStation, stationTestErrorMocked, stationTestMocked, - stationWrapperMockedGet, + stationWrapperMockedGet } from '../__mocks__/stationService'; import { associateEcToStation, @@ -31,13 +30,12 @@ import { getStationCodeV2, getStationDetail, getStations, - getStationsMerged, getWrapperStation, testStation, updateStation, - updateWrapperStationWithOperatorReview, updateWrapperStationToCheck, updateWrapperStationToCheckUpdate, + updateWrapperStationWithOperatorReview, } from '../stationService'; describe('StationService test mocked', () => { @@ -55,10 +53,6 @@ describe('StationService test mocked', () => { }); expect(response).toMatchObject(mockedStations); }); - test('Test getStationsMerged', async () => { - const response = await getStationsMerged(0, 'brokerCode'); - expect(response).toMatchObject(mockedStationsMerged2); - }); test('Test getStation', async () => { const response = await getStation('stationId'); expect(response).toMatchObject(mockedFullStation); @@ -120,7 +114,7 @@ describe('StationService test mocked', () => { expect(response).toMatchObject(mockedFullStation); }); test('Test getCreditorInstitutionSegregationcodes', async () => { - const response = await getCreditorInstitutionSegregationCodes('ecCode'); + const response = await getCreditorInstitutionSegregationCodes('ecCode', 'targetCICode'); expect(response).toMatchObject(mockedSegregationCodeList); }); test('Test testStation', async () => { @@ -178,13 +172,6 @@ describe('StationService test', () => { ).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); - test('Test getStationsMerged', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getStationsMerged') - .mockReturnValue(new Promise((resolve) => resolve(mockedStationsMerged2))); - expect(getStationsMerged(0, 'brokerCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); test('Test getStation', async () => { const spyOn = jest .spyOn(BackofficeApi, 'getStation') @@ -295,7 +282,7 @@ describe('StationService test', () => { const spyOn = jest .spyOn(BackofficeApi, 'getCreditorInstitutionSegregationCodes') .mockReturnValue(new Promise((resolve) => resolve(mockedSegregationCodeList))); - expect(getCreditorInstitutionSegregationCodes('ecCode')).resolves.not.toThrow(); + expect(getCreditorInstitutionSegregationCodes('ecCode', 'targetCICode')).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); test('Test testStation', async () => { diff --git a/src/services/channelService.ts b/src/services/channelService.ts index a889ad641..39cd4905d 100644 --- a/src/services/channelService.ts +++ b/src/services/channelService.ts @@ -21,14 +21,13 @@ import { getChannelCode as getChannelCodeMocked, getChannelDetail as getChannelDetailMocked, getChannelPSPs as getChannelPSPsMocked, - getChannelsMerged as getChannelsMergedMocked, getChannels as getChannelsMocked, getPSPChannels as getPSPChannelsMocked, getWrapperChannel, getWfespPlugins as mockedGetWfespPlugins, updateChannel as updateChannelMocked, updateWrapperChannel, - updateWrapperChannelWithOperatorReview as updateWrapperChannelWithOperatorReviewMocked, + updateWrapperChannelWithOperatorReview as updateWrapperChannelWithOperatorReviewMocked } from './__mocks__/channelService'; // /channels endpoint @@ -41,14 +40,14 @@ export const getChannels = ({ page, }: { status: ConfigurationStatus; - channelCode: string; + channelCode?: string; brokerCode: string; limit?: number; - page: number; + page?: number; }): Promise => { /* istanbul ignore if */ if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelsMocked(page); + return getChannelsMocked(page ?? 0); } else { return BackofficeApi.getChannels({ status, brokerCode, channelCode, limit, page }).then( (resources) => resources @@ -56,27 +55,6 @@ export const getChannels = ({ } }; -export const getChannelsMerged = ( - page: number, - brokerCode: string, - channelcodefilter?: string, - limit?: number, - sorting?: string -): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelsMergedMocked(page, brokerCode, channelcodefilter, limit, sorting); - } else { - return BackofficeApi.getChannelsMerged( - page, - brokerCode, - channelcodefilter, - limit, - sorting - ).then((resources) => resources); - } -}; - export const getChannelDetail = (channelcode: string): Promise => { /* istanbul ignore if */ if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { @@ -95,31 +73,6 @@ export const getPSPChannels = (taxCode: string): Promise => } }; -export const getChannelsIdAssociatedToPSP = ( - page: number, - brokerCode: string, - channelcodefilter?: string, - limit?: number, - sorting?: string -): Promise> => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelsMergedMocked(page, brokerCode, channelcodefilter, limit, sorting).then( - (resources) => - resources.channels!.map((e) => (e.channel_code !== undefined ? e.channel_code : '')) - ); - } else { - return BackofficeApi.getChannelsMerged( - page, - brokerCode, - channelcodefilter, - limit, - sorting - ).then((resources) => - resources.channels!.map((e) => (e.channel_code !== undefined ? e.channel_code : '')) - ); - } -}; - export const getWfespPlugins = (): Promise => { if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { return mockedGetWfespPlugins(); @@ -224,7 +177,7 @@ export const createWrapperChannelDetails = ( } }; -export const updateWrapperChannelDetailsToCheck = ({ +export const updateWrapperChannelDetails = ({ channelCode, channel, validationUrl, @@ -236,22 +189,7 @@ export const updateWrapperChannelDetailsToCheck = ({ if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { return updateWrapperChannel(channel, validationUrl); } else { - return BackofficeApi.updateWrapperChannelDetailsToCheck({ - channelCode, - channel, - validationUrl, - }).then((resources) => resources); - } -}; - -export const updateWrapperChannelDetailsByOpt = ( - channel: ChannelDetailsDto, - validationUrl: string -): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateWrapperChannel(channel, validationUrl); - } else { - return BackofficeApi.updateWrapperChannelDetailsByOpt(channel, validationUrl).then( + return BackofficeApi.updateWrapperChannelDetails({ channelCode, channel, validationUrl }).then( (resources) => resources ); } diff --git a/src/services/stationService.ts b/src/services/stationService.ts index f99033714..f5d1eedf8 100644 --- a/src/services/stationService.ts +++ b/src/services/stationService.ts @@ -1,19 +1,19 @@ -import {BackofficeApi} from '../api/BackofficeClient'; -import {AvailableCodes} from '../api/generated/portal/AvailableCodes'; -import {CreditorInstitutionStationDto} from '../api/generated/portal/CreditorInstitutionStationDto'; -import {CreditorInstitutionStationEditResource} from '../api/generated/portal/CreditorInstitutionStationEditResource'; -import {CreditorInstitutionsResource} from '../api/generated/portal/CreditorInstitutionsResource'; -import {Delegation} from '../api/generated/portal/Delegation'; -import {ProblemJson} from '../api/generated/portal/ProblemJson'; -import {StationCodeResource} from '../api/generated/portal/StationCodeResource'; -import {StationDetailResource} from '../api/generated/portal/StationDetailResource'; -import {StationDetailsDto} from '../api/generated/portal/StationDetailsDto'; -import {TestStationTypeEnum} from '../api/generated/portal/StationTestDto'; -import {TestStationResource} from '../api/generated/portal/TestStationResource'; -import {WrapperEntities} from '../api/generated/portal/WrapperEntities'; -import {WrapperStationDetailsDto} from '../api/generated/portal/WrapperStationDetailsDto'; -import {WrapperStationsResource} from '../api/generated/portal/WrapperStationsResource'; -import {ConfigurationStatus, StationOnCreation} from '../model/Station'; +import { BackofficeApi } from '../api/BackofficeClient'; +import { AvailableCodes } from '../api/generated/portal/AvailableCodes'; +import { CreditorInstitutionStationDto } from '../api/generated/portal/CreditorInstitutionStationDto'; +import { CreditorInstitutionStationEditResource } from '../api/generated/portal/CreditorInstitutionStationEditResource'; +import { CreditorInstitutionsResource } from '../api/generated/portal/CreditorInstitutionsResource'; +import { Delegation } from '../api/generated/portal/Delegation'; +import { ProblemJson } from '../api/generated/portal/ProblemJson'; +import { StationCodeResource } from '../api/generated/portal/StationCodeResource'; +import { StationDetailResource } from '../api/generated/portal/StationDetailResource'; +import { StationDetailsDto } from '../api/generated/portal/StationDetailsDto'; +import { TestStationTypeEnum } from '../api/generated/portal/StationTestDto'; +import { TestStationResource } from '../api/generated/portal/TestStationResource'; +import { WrapperEntities } from '../api/generated/portal/WrapperEntities'; +import { WrapperStationDetailsDto } from '../api/generated/portal/WrapperStationDetailsDto'; +import { WrapperStationsResource } from '../api/generated/portal/WrapperStationsResource'; +import { ConfigurationStatus, StationOnCreation } from '../model/Station'; import { updateStation as UpdateStationMocked, associateEcToStation as associateEcToStationMocked, @@ -27,235 +27,222 @@ import { getStationCodeV2Mocked, getStationDetail as getStationDetailMock, getWrapperStation as getStationWrap, - getStationsMerged as getStationsMergedMocked, getStations as getStationsMocked, testStation as testStationMocked, updateWrapperStation as updateStationWrap, - updateWrapperStationByOpt as updateStationWrapByOpt, + updateWrapperStationByOpt as updateStationWrapByOpt } from '../services/__mocks__/stationService'; export const createStation = (station: StationOnCreation): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return createStationMocked(station); - } - return BackofficeApi.createStation(station).then((resources) => resources); + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return createStationMocked(station); + } + return BackofficeApi.createStation(station).then((resources) => resources); }; export const getStations = ({ - page, - brokerCode, - status, - stationCode, - limit, - }: { - page: number; - brokerCode: string; - status: ConfigurationStatus; - stationCode?: string; - limit?: number; + page, + brokerCode, + status, + stationCode, + limit, +}: { + page?: number; + brokerCode: string; + status: ConfigurationStatus; + stationCode?: string; + limit?: number; }): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationsMocked(0); - } - return BackofficeApi.getStations({ - page, - brokerCode, - status, - stationCode, - limit, - }).then((resource) => resource); -}; - -export const getStationsMerged = ( - page: number, - brokerCode: string, - stationcode?: string, - limit?: number, - sorting?: string -): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationsMergedMocked(page, brokerCode, stationcode, limit, sorting); - } - return BackofficeApi.getStationsMerged(page, brokerCode, stationcode, limit, sorting).then( - (resource) => resource - ); + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getStationsMocked(0); + } + return BackofficeApi.getStations({ + page, + brokerCode, + status, + stationCode, + limit, + }).then((resource) => resource); }; export const getStation = (stationId: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationDetail(stationId); - } - return BackofficeApi.getStation(stationId).then((resource) => resource); + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getStationDetail(stationId); + } + return BackofficeApi.getStation(stationId).then((resource) => resource); }; export const getStationCode = (code: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationCodeMocked(code); - } - return BackofficeApi.getStationCode(code).then((resource) => resource); + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getStationCodeMocked(code); + } + return BackofficeApi.getStationCode(code).then((resource) => resource); }; export const getStationCodeV2 = (code: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationCodeV2Mocked(code); - } - return BackofficeApi.getStationCodeV2(code).then((resource) => resource); + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getStationCodeV2Mocked(code); + } + return BackofficeApi.getStationCodeV2(code).then((resource) => resource); }; export const getECListByStationCode = ( - stationcode: string, - ciName: string | undefined, - page: number, - limit?: number + stationcode: string, + ciName: string | undefined, + page: number, + limit?: number ): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getECListByStationCodeMocked(stationcode, page, limit); - } else { - return BackofficeApi.getECListByStationCode(stationcode, ciName, page, limit).then( - (resources) => resources - ); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getECListByStationCodeMocked(stationcode, page, limit); + } else { + return BackofficeApi.getECListByStationCode(stationcode, ciName, page, limit).then( + (resources) => resources + ); + } }; export const dissociateECfromStation = (ecCode: string, stationCode: string): Promise => { - /* istanbul ignore if */ - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return dissociateECfromStationMocked(ecCode, stationCode); - } else { - return BackofficeApi.dissociateECfromStation(ecCode, stationCode).then( - (resources) => resources - ); - } + /* istanbul ignore if */ + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return dissociateECfromStationMocked(ecCode, stationCode); + } else { + return BackofficeApi.dissociateECfromStation(ecCode, stationCode).then( + (resources) => resources + ); + } }; export const associateEcToStation = ( - code: string, - station: CreditorInstitutionStationDto + code: string, + station: CreditorInstitutionStationDto ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return associateEcToStationMocked(code, station); - } - return BackofficeApi.associateEcToStation(code, station).then((resource) => resource); + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return associateEcToStationMocked(code, station); + } + return BackofficeApi.associateEcToStation(code, station).then((resource) => resource); }; export const getStationAvailableEC = ( - institutionId?: string, - brokerId?: string + institutionId?: string, + brokerId?: string ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationAvailableECMocked(); - } else { - return BackofficeApi.getStationAvailableEc(institutionId!).then((resource) => resource); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getStationAvailableECMocked(); + } else { + return BackofficeApi.getStationAvailableEc(institutionId!).then((resource) => resource); + } }; export const createWrapperStation = ( - station: WrapperStationDetailsDto + station: WrapperStationDetailsDto ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return createStationWrap(station); - } - return BackofficeApi.createWrapperStation(station).then((resources) => resources); + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return createStationWrap(station); + } + return BackofficeApi.createWrapperStation(station).then((resources) => resources); }; export const getWrapperStation = (ecCode: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationWrap(ecCode); - } else { - return BackofficeApi.getWrapperEntitiesStation(ecCode).then((resources) => resources); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getStationWrap(ecCode); + } else { + return BackofficeApi.getWrapperEntitiesStation(ecCode).then((resources) => resources); + } }; export const updateWrapperStationToCheck = ( - station: StationDetailsDto + station: StationDetailsDto ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateStationWrap(station); - } else { - return BackofficeApi.updateWrapperStationToCheck(station.stationCode, station).then( - (resources) => resources - ); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return updateStationWrap(station); + } else { + return BackofficeApi.updateWrapperStationToCheck(station.stationCode, station).then( + (resources) => resources + ); + } }; export const updateWrapperStationToCheckUpdate = ( - station: StationDetailsDto + station: StationDetailsDto ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateStationWrap(station); - } else { - return BackofficeApi.updateWrapperStationToCheckUpdate(station.stationCode, station).then( - (resources) => resources - ); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return updateStationWrap(station); + } else { + return BackofficeApi.updateWrapperStationToCheckUpdate(station.stationCode, station).then( + (resources) => resources + ); + } }; export const updateWrapperStationWithOperatorReview = ({ - stationCode, - ciTaxCode, - note, - }: { - stationCode: string; - ciTaxCode: string; - note: string; + stationCode, + ciTaxCode, + note, +}: { + stationCode: string; + ciTaxCode: string; + note: string; }): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateStationWrapByOpt(); - } else { - return BackofficeApi.updateWrapperStationWithOperatorReview({ - stationCode, - ciTaxCode, - note, - }).then((resources) => resources); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return updateStationWrapByOpt(); + } else { + return BackofficeApi.updateWrapperStationWithOperatorReview({ + stationCode, + ciTaxCode, + note, + }).then((resources) => resources); + } }; export const updateStation = ( - station: StationDetailsDto, - stationCode: string + station: StationDetailsDto, + stationCode: string ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return UpdateStationMocked(station, stationCode); - } else { - return BackofficeApi.updateStation(station, stationCode).then((resources) => resources); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return UpdateStationMocked(station, stationCode); + } else { + return BackofficeApi.updateStation(station, stationCode).then((resources) => resources); + } }; export const getStationDetail = (stationId: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationDetailMock(stationId); - } else { - return BackofficeApi.getStationDetail(stationId).then((resource) => resource); - } -}; - -export const getCreditorInstitutionSegregationCodes = (ecCode: string, targetCITaxCode: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getCreditorInstitutionSegregationcodesMocked(ecCode, targetCITaxCode); - } else { - return BackofficeApi.getCreditorInstitutionSegregationCodes(ecCode, targetCITaxCode).then( - (resource) => resource - ); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getStationDetailMock(stationId); + } else { + return BackofficeApi.getStationDetail(stationId).then((resource) => resource); + } +}; + +export const getCreditorInstitutionSegregationCodes = ( + ecCode: string, + targetCITaxCode: string +): Promise => { + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return getCreditorInstitutionSegregationcodesMocked(ecCode, targetCITaxCode); + } else { + return BackofficeApi.getCreditorInstitutionSegregationCodes(ecCode, targetCITaxCode).then( + (resource) => resource + ); + } }; export const testStation = ( - hostProtocol: string, - hostUrl: string, - hostPort: number, - hostPath: string, - testStationType: TestStationTypeEnum + hostProtocol: string, + hostUrl: string, + hostPort: number, + hostPath: string, + testStationType: TestStationTypeEnum ): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return testStationMocked(hostUrl, hostPort, hostPath); - } else { - return BackofficeApi.testStation( - hostProtocol, - hostUrl, - hostPort, - hostPath, - testStationType - ).then((resource) => resource); - } + if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { + return testStationMocked(hostUrl, hostPort, hostPath); + } else { + return BackofficeApi.testStation( + hostProtocol, + hostUrl, + hostPort, + hostPath, + testStationType + ).then((resource) => resource); + } }; From b23b17abf686646c8250f5e1e352b3789ae9cc67 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Tue, 25 Jun 2024 15:03:03 +0000 Subject: [PATCH 10/73] Bump to version 1.26.0-4-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 82303b314..1a554009b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.0-3-next", + "version": "1.26.0-4-next", "homepage": "ui", "private": true, "scripts": { From 1012f3c094aeeef2964a9d38d91d521870fb8728 Mon Sep 17 00:00:00 2001 From: Samuele Varianti <128470180+svariant@users.noreply.github.com> Date: Wed, 26 Jun 2024 11:30:01 +0200 Subject: [PATCH 11/73] [VAS-1104] feat: New bundle status for available but expired bundles (#580) * [VAS-1104] feat: New bundle status for available but expired bundles * [VAS-1104] feat: Add alert bundle expired * [VAS-1104] chore: BE openapi * [VAS-1104] feat: Changes after UI designer advice * [VAS-1104] chore: Fix unit tests --- package.json | 2 +- src/locale/it.json | 6 +- .../detail/CommissionBundleDetailPage.tsx | 24 +- .../CommissionBundleDetailPage.test.tsx | 1081 +++++++++-------- .../CommissionBundleDetailConfiguration.tsx | 1 + .../CommissionBundleDetailTaxonomies.tsx | 3 +- .../list/CommissionBundlesTableColumns.tsx | 11 +- .../CommissionBundlesTableColumns.test.tsx | 6 +- 8 files changed, 585 insertions(+), 549 deletions(-) diff --git a/package.json b/package.json index 1a554009b..e98fe76cb 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "clean:api-portal": "rimraf src/api/generated/portal && rimraf openApi/generated", "generate:api-portal": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/main/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-next": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/next/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", - "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1122-remove-unused-api-station-channels/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", + "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1104-new-bundle-status/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-local": "npm run generate:client", "generate:client": "jq 'walk(if type == \"object\" and has(\"parameters\") then .parameters |= map(select(.name != \"X-Request-Id\")) else . end)' ./openApi/portal-api-docs.json > ./openApi/portal-api-docs.json.temp && mv ./openApi/portal-api-docs.json.temp ./openApi/portal-api-docs.json && yarn run clean:api-portal && mkdirp openApi/generated && gen-api-models --api-spec openApi/portal-api-docs.json --out-dir src/api/generated/portal --no-strict --request-types --response-decoders --client && node openApi/scripts/api-portal_fixPostGen.js" }, diff --git a/src/locale/it.json b/src/locale/it.json index c106beb04..801d18511 100644 --- a/src/locale/it.json +++ b/src/locale/it.json @@ -1049,7 +1049,11 @@ "commissions": "Commissione a carico", "alert": { "expiredTaxonomies": "Alcuni servizi di incasso non sono più validi.", - "onRemoval": "Il pacchetto sarà disattivato e non più visibile a partire da domani." + "onRemoval": "Il pacchetto sarà disattivato e non più visibile a partire da domani.", + "availableExpired": { + "title": "Pacchetto in scadenza", + "message": "Non è più possibile attivare questo pacchetto perché in scadenza." + } }, "error": { "deleteBundlePsp": "Errore durante l'eliminazione del pacchetto", diff --git a/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx b/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx index f20eb4097..3a2030c36 100644 --- a/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx +++ b/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx @@ -47,6 +47,16 @@ function RenderAlert({ bundleDetail }: Readonly<{ bundleDetail: BundleResource } ); } + if ((bundleDetail as CIBundleResource)?.ciBundleStatus === CiBundleStatusEnum.AVAILABLE_EXPIRED) { + return ( + + + {t('commissionBundlesPage.commissionBundleDetail.alert.availableExpired.title')} + + {t('commissionBundlesPage.commissionBundleDetail.alert.availableExpired.message')} + + ); + } // eslint-disable-next-line functional/no-let let expiredFound = false; (bundleDetail?.bundleTaxonomies as Array)?.forEach((el: PSPBundleTaxonomy) => { @@ -75,7 +85,7 @@ const BundleActionButtons = ({ setShowConfirmModal: (arg: BundleDetailsActionTypes | null) => void; bundleDetail: BundleResource; bundleId: string; -// eslint-disable-next-line sonarjs/cognitive-complexity + // eslint-disable-next-line sonarjs/cognitive-complexity }) => { const { t } = useTranslation(); const { orgInfo } = useOrganizationType(); @@ -108,11 +118,10 @@ const BundleActionButtons = ({ ); } if (orgInfo.types.isEc) { + const bundleStatus = (bundleDetail as CIBundleResource).ciBundleStatus; if ( - (bundleDetail as CIBundleResource).ciBundleStatus === CiBundleStatusEnum.AVAILABLE && - // TODO remove after VAS-1104 - !(bundleDetail?.validityDateTo && - datesAreOnSameDay(new Date(), bundleDetail?.validityDateTo)) + bundleStatus === CiBundleStatusEnum.AVAILABLE || + bundleStatus === CiBundleStatusEnum.AVAILABLE_EXPIRED ) { return ( <> @@ -131,13 +140,14 @@ const BundleActionButtons = ({ to={ROUTES.COMMISSION_BUNDLES_ACTIVATE} variant="contained" data-testid="activate-button" + disabled={bundleStatus === CiBundleStatusEnum.AVAILABLE_EXPIRED} > {t('general.activate')} ); } - if ((bundleDetail as CIBundleResource).ciBundleStatus === CiBundleStatusEnum.ENABLED) { + if (bundleStatus === CiBundleStatusEnum.ENABLED) { return ( ); } - if ((bundleDetail as CIBundleResource).ciBundleStatus === CiBundleStatusEnum.REQUESTED) { + if (bundleStatus === CiBundleStatusEnum.REQUESTED) { return ( - - - - - - - L’ente riceverà una notifica di conferma attivazione della stazione. -
- - ) : ( - - Un operatore PagoPA revisionerà le informazioni inserite nella stazione prima di - approvare. Riceverai una notifica a revisione completata. -
-
+ onClick={() => validateRtEndpoint()} + sx={{ color: 'primary.main' }} + weight="default" + data-testid="test-rt-endpoint-test" + endIcon={} + > + {t(`${componentPath}.testStation`)} + ) - } - openConfirmModal={showConfirmModal} - onConfirmLabel={userIsPagopaOperator ? t('general.confirm') : t('general.send')} - onCloseLabel={t('general.turnBack')} - handleCloseConfirmModal={() => setShowConfirmModal(false)} - handleConfrimSubmit={async () => { - await submit(formik.values); - setShowConfirmModal(false); - }} - /> - - ); + )} +
+
+ + + + {testRedirectResult !== undefined && + testRedirectResult.testResult === TestResultEnum.SUCCESS ? ( + + ) : ( + '' + )} + + ), + }} + /> + + + {validatingRedirect ? ( + + ) : ( + isTesting && ( + + ) + )} + + +
+ + + } + /> + + + + {testPofResult !== undefined && + testPofResult.testResult === TestResultEnum.SUCCESS && ( + + )} + + ), + }} + /> + + + {validatingPof ? ( + + ) : ( + isTesting && ( + validatePofEndpoint()} + sx={{ color: 'primary.main' }} + weight="default" + data-testid="test-pof-endpoint-test" + endIcon={} + > + {t(`${componentPath}.testStation`)} + + ) + )} + + + + + + + {t(`${componentPath}.fields.primitiveVersion`)} + + + + + + + + )} + + + {userIsPagopaOperator && formAction !== StationFormAction.Create ? ( + + ) : ( + <> + )} + + + + + + + + + + L’ente riceverà una notifica di conferma attivazione della stazione. +
+ + ) : ( + + Un operatore PagoPA revisionerà le informazioni inserite nella stazione prima di + approvare. Riceverai una notifica a revisione completata. +
+
+ ) + } + openConfirmModal={showConfirmModal} + onConfirmLabel={userIsPagopaOperator ? t('general.confirm') : t('general.send')} + onCloseLabel={t('general.turnBack')} + handleCloseConfirmModal={() => setShowConfirmModal(false)} + handleConfrimSubmit={async () => { + await submit(formik.values); + setShowConfirmModal(false); + }} + /> + + ); }; export default AddEditStationForm; diff --git a/yarn.lock b/yarn.lock index 4922313f0..c772ab529 100644 --- a/yarn.lock +++ b/yarn.lock @@ -51,15 +51,7 @@ call-me-maybe "^1.0.1" z-schema "^5.0.1" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2", "@babel/code-frame@^7.8.3": - version "7.24.2" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== - dependencies: - "@babel/highlight" "^7.24.2" - picocolors "^1.0.0" - -"@babel/code-frame@^7.24.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.24.7", "@babel/code-frame@^7.8.3": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== @@ -72,21 +64,21 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== -"@babel/core@7.24.4", "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz" - integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== +"@babel/core@7.24.7", "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" + integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.4" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.4" - "@babel/parser" "^7.24.4" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.24.7" + "@babel/helper-compilation-targets" "^7.24.7" + "@babel/helper-module-transforms" "^7.24.7" + "@babel/helpers" "^7.24.7" + "@babel/parser" "^7.24.7" + "@babel/template" "^7.24.7" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -102,17 +94,7 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.24.1", "@babel/generator@^7.24.4", "@babel/generator@^7.7.2": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz" - integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw== - dependencies: - "@babel/types" "^7.24.0" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" - -"@babel/generator@^7.24.7": +"@babel/generator@^7.24.7", "@babel/generator@^7.7.2": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== @@ -151,7 +133,7 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6", "@babel/helper-compilation-targets@^7.24.7": +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== @@ -289,13 +271,6 @@ "@babel/template" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - "@babel/helper-hoist-variables@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" @@ -332,13 +307,6 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - "@babel/helper-module-imports@^7.22.5": version "7.22.5" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz" @@ -354,17 +322,6 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" - "@babel/helper-module-transforms@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" @@ -440,13 +397,6 @@ "@babel/helper-member-expression-to-functions" "^7.24.7" "@babel/helper-optimise-call-expression" "^7.24.7" -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - "@babel/helper-simple-access@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" @@ -498,21 +448,11 @@ dependencies: "@babel/types" "^7.24.7" -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - "@babel/helper-string-parser@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" @@ -533,24 +473,13 @@ "@babel/traverse" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/helpers@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz" - integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== - dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" - -"@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== +"@babel/helpers@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" + integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" "@babel/highlight@^7.24.7": version "7.24.7" @@ -562,12 +491,7 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz" - integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== - -"@babel/parser@^7.24.7": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== @@ -1479,16 +1403,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.16.7", "@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - -"@babel/template@^7.24.7": +"@babel/template@^7.16.7", "@babel/template@^7.22.15", "@babel/template@^7.24.7", "@babel/template@^7.3.3": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== @@ -1497,23 +1412,7 @@ "@babel/parser" "^7.24.7" "@babel/types" "^7.24.7" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.24.1", "@babel/traverse@^7.7.2": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz" - integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== - dependencies: - "@babel/code-frame" "^7.24.1" - "@babel/generator" "^7.24.1" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.1" - "@babel/types" "^7.24.0" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/traverse@^7.24.7": +"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.24.7", "@babel/traverse@^7.7.2": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== @@ -1529,16 +1428,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.18.2", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.24.7": +"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.17.12", "@babel/types@^7.18.2", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== @@ -2342,13 +2232,13 @@ react-is "^18.2.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.15.14": - version "5.15.14" - resolved "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.15.14.tgz" - integrity sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw== +"@mui/private-theming@^5.15.20": + version "5.15.20" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.20.tgz#028c4e3c717a13691ac2c8c98e29aa819d89001a" + integrity sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g== dependencies: "@babel/runtime" "^7.23.9" - "@mui/utils" "^5.15.14" + "@mui/utils" "^5.15.20" prop-types "^15.8.1" "@mui/styled-engine@^5.15.14": @@ -2361,16 +2251,16 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.15.15", "@mui/system@^5.8.1": - version "5.15.15" - resolved "https://registry.npmjs.org/@mui/system/-/system-5.15.15.tgz" - integrity sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ== +"@mui/system@^5.15.15", "@mui/system@^5.15.20", "@mui/system@^5.8.1": + version "5.15.20" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.20.tgz#f1933aabc4c10f8580c7a951ca3b88542ef0f76b" + integrity sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA== dependencies: "@babel/runtime" "^7.23.9" - "@mui/private-theming" "^5.15.14" + "@mui/private-theming" "^5.15.20" "@mui/styled-engine" "^5.15.14" "@mui/types" "^7.2.14" - "@mui/utils" "^5.15.14" + "@mui/utils" "^5.15.20" clsx "^2.1.0" csstype "^3.1.3" prop-types "^15.8.1" @@ -2380,10 +2270,10 @@ resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz" integrity sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ== -"@mui/utils@^5.10.3", "@mui/utils@^5.13.7", "@mui/utils@^5.14.16", "@mui/utils@^5.15.14", "@mui/utils@^5.6.1": - version "5.15.14" - resolved "https://registry.npmjs.org/@mui/utils/-/utils-5.15.14.tgz" - integrity sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA== +"@mui/utils@^5.10.3", "@mui/utils@^5.13.7", "@mui/utils@^5.14.16", "@mui/utils@^5.15.14", "@mui/utils@^5.15.20", "@mui/utils@^5.6.1": + version "5.15.20" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.20.tgz#92778d749ce5ded1598639b4e684aaedb1146e08" + integrity sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A== dependencies: "@babel/runtime" "^7.23.9" "@types/prop-types" "^15.7.11" @@ -2615,13 +2505,6 @@ node-fetch "^2.6.0" validator "^13.7.0" -"@playwright/test@^1.44.1": - version "1.44.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.44.1.tgz#cc874ec31342479ad99838040e99b5f604299bcb" - integrity sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q== - dependencies: - playwright "1.44.1" - "@pmmmwh/react-refresh-webpack-plugin@^0.5.3": version "0.5.7" resolved "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz" @@ -4008,15 +3891,16 @@ array-flatten@^2.1.2: resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz" integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== -array-includes@^3.1.4, array-includes@^3.1.5, array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== +array-includes@^3.1.4, array-includes@^3.1.7, array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^2.1.0: @@ -4035,6 +3919,18 @@ array.prototype.filter@^1.0.3: es-array-method-boxes-properly "^1.0.0" is-string "^1.0.7" +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + array.prototype.findlastindex@^1.2.3: version "1.2.4" resolved "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz" @@ -4056,7 +3952,7 @@ array.prototype.flat@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.0, array.prototype.flatmap@^1.3.2: +array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -4066,6 +3962,27 @@ array.prototype.flatmap@^1.3.0, array.prototype.flatmap@^1.3.2: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" +array.prototype.toreversed@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz#b989a6bf35c4c5051e1dc0325151bf8088954eba" + integrity sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + arraybuffer.prototype.slice@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz" @@ -5465,14 +5382,6 @@ define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - defined@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz" @@ -5809,7 +5718,7 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.3.4" -es-abstract@^1.19.1, es-abstract@^1.19.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0: +es-abstract@^1.19.1, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: version "1.23.3" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz" integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== @@ -5878,6 +5787,26 @@ es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-iterator-helpers@^1.0.19: + version "1.0.19" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + iterator.prototype "^1.1.2" + safe-array-concat "^1.1.2" + es-module-lexer@^0.9.0: version "0.9.3" resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz" @@ -6079,25 +6008,29 @@ eslint-plugin-react-hooks@^4.6.0: resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz" integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== -eslint-plugin-react@^7.26.1, eslint-plugin-react@^7.27.1: - version "7.30.0" - resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.30.0.tgz" - integrity sha512-RgwH7hjW48BleKsYyHK5vUAvxtE9SMPDKmcPRQgtRCYaZA0XQPt5FSkrU3nhz5ifzMZcA8opwmRJ2cmOO8tr5A== +eslint-plugin-react@^7.27.1, eslint-plugin-react@^7.34.3: + version "7.34.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz#9965f27bd1250a787b5d4cfcc765e5a5d58dcb7b" + integrity sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA== dependencies: - array-includes "^3.1.5" - array.prototype.flatmap "^1.3.0" + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.2" + array.prototype.toreversed "^1.1.2" + array.prototype.tosorted "^1.1.4" doctrine "^2.1.0" + es-iterator-helpers "^1.0.19" estraverse "^5.3.0" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.5" - object.fromentries "^2.0.5" - object.hasown "^1.1.1" - object.values "^1.1.5" + object.entries "^1.1.8" + object.fromentries "^2.0.8" + object.hasown "^1.1.4" + object.values "^1.2.0" prop-types "^15.8.1" - resolve "^2.0.0-next.3" - semver "^6.3.0" - string.prototype.matchall "^4.0.7" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.11" eslint-plugin-sonarjs@^0.13.0: version "0.13.0" @@ -6736,7 +6669,7 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@2.3.2, fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -6756,7 +6689,7 @@ function-bind@^1.1.1, function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.6: +function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: version "1.1.6" resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz" integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== @@ -6781,7 +6714,7 @@ get-caller-file@^2.0.5: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: +get-intrinsic@^1.0.2: version "1.1.1" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -7320,15 +7253,6 @@ ini@^1.3.5: resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz" @@ -7388,6 +7312,13 @@ is-arrayish@^0.2.1: resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" @@ -7425,7 +7356,7 @@ is-callable@^1.2.7: resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.2.0: +is-core-module@^2.13.0, is-core-module@^2.13.1: version "2.13.1" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== @@ -7439,7 +7370,7 @@ is-data-view@^1.0.1: dependencies: is-typed-array "^1.1.13" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -7461,6 +7392,13 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" @@ -7471,6 +7409,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -7478,6 +7423,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + is-module@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz" @@ -7545,6 +7495,11 @@ is-root@^2.1.0: resolved "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz" integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz" @@ -7583,6 +7538,11 @@ is-typedarray@^1.0.0: resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" @@ -7590,6 +7550,14 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" @@ -7678,6 +7646,17 @@ italia-ts-commons@^8.6.0: node-fetch "^2.6.0" validator "^10.1.0" +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" + jake@^10.8.5: version "10.8.5" resolved "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz" @@ -9078,23 +9057,24 @@ object.assign@^4.1.2, object.assign@^4.1.5: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.5: - version "1.1.5" - resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz" - integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== +object.entries@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -object.fromentries@^2.0.5, object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== +object.fromentries@^2.0.7, object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" object.groupby@^1.0.1: version "1.0.2" @@ -9107,22 +9087,23 @@ object.groupby@^1.0.1: es-abstract "^1.22.3" es-errors "^1.0.0" -object.hasown@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz" - integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== +object.hasown@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" + integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== dependencies: - define-properties "^1.1.4" - es-abstract "^1.19.5" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -object.values@^1.1.5, object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== +object.values@^1.1.7, object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" @@ -9343,7 +9324,7 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -9431,20 +9412,6 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -playwright-core@1.44.1: - version "1.44.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.44.1.tgz#53ec975503b763af6fc1a7aa995f34bc09ff447c" - integrity sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA== - -playwright@1.44.1: - version "1.44.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.44.1.tgz#5634369d777111c1eea9180430b7a184028e7892" - integrity sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg== - dependencies: - playwright-core "1.44.1" - optionalDependencies: - fsevents "2.3.2" - possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz" @@ -10533,10 +10500,10 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react-use-scrollspy@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/react-use-scrollspy/-/react-use-scrollspy-3.0.2.tgz" - integrity sha512-MgXt4p4Ois21Xo2nI1jJyt7J9pxmtF0AQbj5DQWncmMLz1mijwsLQ3w6N7T67yULvluyYJQ9dUnCXFVZh0UIgA== +react-use-scrollspy@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/react-use-scrollspy/-/react-use-scrollspy-3.1.1.tgz#3816294290d93d85d6a13f2ec716a13db13c04e0" + integrity sha512-EXkQoMKqt6VF4fAxcLFsNLZksctXXmtC8LYk1Zb0Cn0MZX1LErikAoAPWWJkel3Ze7NbJRVgpIzwEX4w108tOg== dependencies: lodash "4.17.21" @@ -10627,6 +10594,19 @@ redux@^4.0.0, redux@^4.1.0: dependencies: "@babel/runtime" "^7.9.2" +reflect.getprototypeof@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz" @@ -10669,7 +10649,7 @@ regex-replace@^2.3.1: fs-extra "^4.0.2" replace "^1.1.0" -regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.5.2: +regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz" integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== @@ -10800,13 +10780,14 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.2 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^2.0.0-next.3: - version "2.0.0-next.3" - resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz" - integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" retry@^0.13.1: version "0.13.1" @@ -11069,6 +11050,16 @@ set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + setimmediate@^1.0.5, setimmediate@~1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" @@ -11144,6 +11135,16 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" @@ -11397,19 +11398,23 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.matchall@^4.0.6, string.prototype.matchall@^4.0.7: - version "4.0.7" - resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz" - integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== +string.prototype.matchall@^4.0.11, string.prototype.matchall@^4.0.6: + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.1" - side-channel "^1.0.4" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" string.prototype.padend@^3.0.0: version "3.1.3" @@ -12447,7 +12452,35 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.14, which-typed-array@^1.1.15: +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +which-collection@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9: version "1.1.15" resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz" integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== From cb5c70709eb21015760897e25517f1e24c8289c5 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Wed, 26 Jun 2024 15:45:44 +0000 Subject: [PATCH 18/73] Bump to version 1.26.1-1-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11b3191cf..d1a03ea19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.1", + "version": "1.26.1-1-next", "homepage": "ui", "private": true, "scripts": { From ae6d1fdc59ce6de06a0c5ef9174dc414496504a8 Mon Sep 17 00:00:00 2001 From: Samuele Varianti <128470180+svariant@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:31:48 +0200 Subject: [PATCH 19/73] [VAS-1133] feat: Add new api key for printPaymentsNotice product (#584) * [VAS-1133] feat: Introduce print notice api key list element * [VAS-1133] fix: Api key products psp * [VAS-1133] feat: Refactor api key products * [VAS-1133] feat: Introduce flag print notice for api keys * [VAS-1133] chore: Api key unit test coverage --- src/locale/it.json | 3 +- src/model/ApiKey.tsx | 90 ++-- src/model/__tests__/ApiKey.test.tsx | 18 + src/pages/apiKeys/AddApiKeyPage.tsx | 468 +++++++++--------- .../apiKeys/__tests__/AddApiKeyPage.test.tsx | 137 +++-- 5 files changed, 391 insertions(+), 325 deletions(-) create mode 100644 src/model/__tests__/ApiKey.test.tsx diff --git a/src/locale/it.json b/src/locale/it.json index 97cc98abf..5a4e353bc 100644 --- a/src/locale/it.json +++ b/src/locale/it.json @@ -196,7 +196,8 @@ "FDR_ORG": "FdR - Flussi di Rendicontazione (EC)", "FDR_PSP": "FdR - Flussi di Rendicontazione (PSP)", "BO_EXT_EC": "Backoffice External (EC)", - "BO_EXT_PSP": "Backoffice External (PSP)" + "BO_EXT_PSP": "Backoffice External (PSP)", + "PRINT_NOTICE": "Stampa Avvisi" } }, "channelsPage": { diff --git a/src/model/ApiKey.tsx b/src/model/ApiKey.tsx index d9c2bf952..78015b250 100644 --- a/src/model/ApiKey.tsx +++ b/src/model/ApiKey.tsx @@ -1,58 +1,58 @@ -import {ENV} from "../utils/env"; +import { ENV } from '../utils/env'; export type ProductKeys = { - id: string; - displayName: string; - primaryKey: string; - secondaryKey: string; + id: string; + displayName: string; + primaryKey: string; + secondaryKey: string; }; export type AvailableProductKeys = { - id: string; - title: string; - disabled: boolean; + id: string; + title: string; + disabled: boolean; }; export type ConfiguredProductKeys = { - id: string; - key: string; + id: string; + key: string; }; -export const NODOAUTH = 'Connessione con nodo'; -export const GPD = 'GPD - Posizioni Debitorie'; -export const GPD_REP = 'GPD - Gestione flussi di rendicontazione'; -export const GPD_PAY = 'GPD - Recupero ricevute'; -export const BIZ = 'BIZ - Recupero ricevute Ente Creditore'; -export const FDR_ORG = 'FdR - Flussi di Rendicontazione (EC)'; -export const FDR_PSP = 'FdR - Flussi di Rendicontazione (PSP)'; -export const BO_EXT_EC = 'Backoffice External (EC)'; -export const BO_EXT_PSP = 'Backoffice External (PSP)'; - -export const API_KEY_PSP_PRODUCTS = (): Array => { - const list = [ - {id: 'NODOAUTH', key: NODOAUTH}, - {id: 'BO_EXT_PSP', key: BO_EXT_PSP} - ]; - - if (ENV.FEATURES.FDR.ENABLED) { - return [...list, {id: 'FDR_PSP', key: FDR_PSP}]; - } - return list; +export const API_KEY_PRODUCTS = { + NODOAUTH: { id: 'NODOAUTH', key: 'nodauth-' }, + GPD: { id: 'GPD', key: 'gdp-' }, + GPD_REP: { id: 'GPD_REP', key: 'gpdrep-' }, + GPD_PAY: { id: 'GPD_PAY', key: 'gpdpay-' }, + BIZ: { id: 'BIZ', key: 'biz-' }, + FDR_ORG: { id: 'FDR_ORG', key: 'fdrorg-' }, + FDR_PSP: { id: 'FDR_PSP', key: 'fdrpsp-' }, + BO_EXT_EC: { id: 'BO_EXT_EC', key: 'selfcareboexternalec-' }, + BO_EXT_PSP: { id: 'BO_EXT_PSP', key: 'selfcareboexternalpsp-' }, + PRINT_NOTICE: { id: 'PRINT_NOTICE', key: 'printnotice-' }, }; - -export const API_KEY_PRODUCTS = (): Array => { - const list = [ - {id: 'NODOAUTH', key: NODOAUTH}, - {id: 'GPD', key: GPD}, - {id: 'GPD_PAY', key: GPD_PAY}, - {id: 'GPD_REP', key: GPD_REP}, - {id: 'BIZ', key: BIZ}, - {id: 'BO_EXT_EC', key: BO_EXT_EC} - ]; - - if (ENV.FEATURES.FDR.ENABLED) { - return [...list, {id: 'FDR_ORG', key: FDR_ORG}]; - } - return list; +export const getApiKeyProducts = ( + isPsp: boolean, + flagPrintNotice: boolean +): Array => { + const list = isPsp + ? [API_KEY_PRODUCTS.NODOAUTH, API_KEY_PRODUCTS.BO_EXT_PSP] + : [ + API_KEY_PRODUCTS.NODOAUTH, + API_KEY_PRODUCTS.GPD, + API_KEY_PRODUCTS.GPD_PAY, + API_KEY_PRODUCTS.GPD_REP, + API_KEY_PRODUCTS.BIZ, + API_KEY_PRODUCTS.BO_EXT_EC, + ]; + + if (ENV.FEATURES.FDR.ENABLED) { + // eslint-disable-next-line functional/immutable-data + list.push(isPsp ? API_KEY_PRODUCTS.FDR_PSP : API_KEY_PRODUCTS.FDR_ORG); + } + if (flagPrintNotice && !isPsp) { + // eslint-disable-next-line functional/immutable-data + list.push(API_KEY_PRODUCTS.PRINT_NOTICE); + } + return list; }; diff --git a/src/model/__tests__/ApiKey.test.tsx b/src/model/__tests__/ApiKey.test.tsx new file mode 100644 index 000000000..9d2437247 --- /dev/null +++ b/src/model/__tests__/ApiKey.test.tsx @@ -0,0 +1,18 @@ +import { API_KEY_PRODUCTS, getApiKeyProducts } from '../ApiKey'; +describe("Test ApiKey model methods", ()=> { + test("Test getApiKeysProducts as PSP", () => { + expect(getApiKeyProducts(true, true)).toEqual([API_KEY_PRODUCTS.NODOAUTH, API_KEY_PRODUCTS.BO_EXT_PSP, API_KEY_PRODUCTS.FDR_PSP]) + }) + test("Test getApiKeysProducts as EC", () => { + expect(getApiKeyProducts(false, true)).toEqual([ + API_KEY_PRODUCTS.NODOAUTH, + API_KEY_PRODUCTS.GPD, + API_KEY_PRODUCTS.GPD_PAY, + API_KEY_PRODUCTS.GPD_REP, + API_KEY_PRODUCTS.BIZ, + API_KEY_PRODUCTS.BO_EXT_EC, + API_KEY_PRODUCTS.FDR_ORG, + API_KEY_PRODUCTS.PRINT_NOTICE + ]) + }) +}) \ No newline at end of file diff --git a/src/pages/apiKeys/AddApiKeyPage.tsx b/src/pages/apiKeys/AddApiKeyPage.tsx index adf5e9e4a..bbd6a4d4a 100644 --- a/src/pages/apiKeys/AddApiKeyPage.tsx +++ b/src/pages/apiKeys/AddApiKeyPage.tsx @@ -1,257 +1,259 @@ import { - Box, - Button, - FormControl, - Grid, - InputLabel, - MenuItem, - OutlinedInput, - Paper, - Select, - Stack, - Typography, + Box, + Button, + FormControl, + Grid, + InputLabel, + MenuItem, + OutlinedInput, + Paper, + Select, + Stack, + Typography, } from '@mui/material'; -import {theme} from '@pagopa/mui-italia'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {useFormik} from 'formik'; -import {useEffect, useState} from 'react'; -import {Trans, useTranslation} from 'react-i18next'; -import {useHistory} from 'react-router-dom'; -import {InstitutionApiKeysResource} from '../../api/generated/portal/InstitutionApiKeysResource'; +import { theme } from '@pagopa/mui-italia'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { useFormik } from 'formik'; +import { useEffect, useState } from 'react'; +import { Trans, useTranslation, TFunction } from 'react-i18next'; +import { useHistory } from 'react-router-dom'; +import { InstitutionApiKeysResource } from '../../api/generated/portal/InstitutionApiKeysResource'; import { - API_KEY_PRODUCTS, - API_KEY_PSP_PRODUCTS, - AvailableProductKeys, - ConfiguredProductKeys, - NODOAUTH, + getApiKeyProducts, + AvailableProductKeys, + ConfiguredProductKeys, + API_KEY_PRODUCTS, } from '../../model/ApiKey'; -import {useAppSelector} from '../../redux/hooks'; -import {partiesSelectors} from '../../redux/slices/partiesSlice'; +import { useAppSelector } from '../../redux/hooks'; +import { partiesSelectors } from '../../redux/slices/partiesSlice'; import ROUTES from '../../routes'; -import {createInstitutionApiKeys, getInstitutionApiKeys} from '../../services/apiKeyService'; -import {LOADING_TASK_API_KEY_GENERATION} from '../../utils/constants'; +import { createInstitutionApiKeys, getInstitutionApiKeys } from '../../services/apiKeyService'; +import { LOADING_TASK_API_KEY_GENERATION } from '../../utils/constants'; +import { useFlagValue } from '../../hooks/useFeatureFlags'; function AddApiKeyPage() { - const {t} = useTranslation(); - const [selectedProduct, setSelectedProduct] = useState(); - const [availableProduct, setAvailableProduct] = useState>([]); - const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const setLoading = useLoading(LOADING_TASK_API_KEY_GENERATION); - const addError = useErrorDispatcher(); - const products: Array = - selectedParty?.institutionType === 'PSP' ? API_KEY_PSP_PRODUCTS() : API_KEY_PRODUCTS(); + const { t } = useTranslation(); + const [selectedProduct, setSelectedProduct] = useState(); + const [availableProduct, setAvailableProduct] = useState>([]); + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); + const setLoading = useLoading(LOADING_TASK_API_KEY_GENERATION); + const addError = useErrorDispatcher(); + const products: Array = getApiKeyProducts( + selectedParty?.institutionType === 'PSP', + useFlagValue('payment-notices') + ); - const formik = useFormik({ - initialValues: { - product: '', - }, - onSubmit: (_values) => { - }, - }); + const formik = useFormik({ + initialValues: { + product: '', + }, + onSubmit: (_values) => {}, + }); - const history = useHistory(); + const history = useHistory(); - const goBack = () => { - history.push(ROUTES.APIKEYS); - }; + const goBack = () => { + history.push(ROUTES.APIKEYS); + }; - const handleSubmit = () => { - if (selectedProduct && selectedParty) { - setLoading(true); - createInstitutionApiKeys(selectedParty.partyId, selectedProduct) - .then((_data) => { - history.push(ROUTES.APIKEYS, { - alertSuccessMessage: t('addApiKeyPage.addForm.successMessage'), - }); - }) - .catch((reason) => - addError({ - id: 'ADD_APIKEY', - blocking: false, - error: reason, - techDescription: `An error occurred while adding api keys`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('addApiKeyPage.addForm.errorMessageDesc'), - component: 'Toast', - }) - ) - .finally(() => setLoading(false)); - } - }; + const handleSubmit = () => { + if (selectedProduct && selectedParty) { + setLoading(true); + createInstitutionApiKeys(selectedParty.partyId, selectedProduct) + .then((_data) => { + history.push(ROUTES.APIKEYS, { + alertSuccessMessage: t('addApiKeyPage.addForm.successMessage'), + }); + }) + .catch((reason) => + addError({ + id: 'ADD_APIKEY', + blocking: false, + error: reason, + techDescription: `An error occurred while adding api keys`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('addApiKeyPage.addForm.errorMessageDesc'), + component: 'Toast', + }) + ) + .finally(() => setLoading(false)); + } + }; - useEffect(() => { - if (selectedParty) { - setLoading(true); - void getInstitutionApiKeys(selectedParty.partyId) - .then((data) => { - buildAvailableProduct(data, products, setAvailableProduct); - }) - .finally(() => setLoading(false)); - } - }, [selectedParty]); + useEffect(() => { + if (selectedParty) { + setLoading(true); + void getInstitutionApiKeys(selectedParty.partyId) + .then((data) => { + buildAvailableProduct(data, products, setAvailableProduct, t); + }) + .finally(() => setLoading(false)); + } + }, [selectedParty]); - return ( - + + + + Generazione API Key + + + + + + Inserisci le informazioni per generare la coppia di chiavi + + + + + + - - - - Generazione API Key - - - - - - Inserisci le informazioni per generare la coppia di chiavi - + +
+ + + {t('addApiKeyPage.addForm.product.title')} + + ( - - {selectedProduct} - - )} - input={} - > - {availableProduct.map((p) => ( - setSelectedProduct(p.id)} - > - {p.title} - - ))} - - -
-
-
-
- - - - - - - - -
- ); + {p.title} + + ))} + + + +
+ + + + + + + + + + + + ); } const buildAvailableProduct = ( - data: InstitutionApiKeysResource, - products: Array, - setAvailableProduct: any + data: InstitutionApiKeysResource, + products: Array, + setAvailableProduct: any, + t: TFunction ) => { - if (data?.institution_api_key_list?.some((el) => el.displayName.includes(NODOAUTH))) { - // if nodeAuth was created, elements that are present in both lists will be disabled - setAvailableProduct( - products.map((p) => - data?.institution_api_key_list?.some((el) => el.displayName.includes(p.key)) - ? { - id: p.id, - title: p.key, - disabled: true, - } - : { - id: p.id, - title: p.key, - disabled: false, - } - ) - ); - } else { - // if no apikeys was created, nodeAuth is the only items enabled - setAvailableProduct( - products.map((p) => - p.key.includes(NODOAUTH) - ? { - id: p.id, - title: p.key, - disabled: false, - } - : { - id: p.id, - title: p.key, - disabled: true, - } - ) - ); - } + if (data?.institution_api_key_list?.some((el) => el.id.includes(API_KEY_PRODUCTS.NODOAUTH.key))) { + // if nodeAuth was created, elements that are present in both lists will be disabled + setAvailableProduct( + products.map((p) => + data?.institution_api_key_list?.some((el) => el.id.includes(p.key)) + ? { + id: p.id, + title: t(`addApiKeyPage.products.${p.id}`), + disabled: true, + } + : { + id: p.id, + title: t(`addApiKeyPage.products.${p.id}`), + disabled: false, + } + ) + ); + } else { + // if no apikeys was created, nodeAuth is the only items enabled + setAvailableProduct( + products.map((p) => + p.key.includes(API_KEY_PRODUCTS.NODOAUTH.key) + ? { + id: p.id, + title: t(`addApiKeyPage.products.${p.id}`), + disabled: false, + } + : { + id: p.id, + title: t(`addApiKeyPage.products.${p.id}`), + disabled: true, + } + ) + ); + } }; export default AddApiKeyPage; diff --git a/src/pages/apiKeys/__tests__/AddApiKeyPage.test.tsx b/src/pages/apiKeys/__tests__/AddApiKeyPage.test.tsx index 6277020e0..de306d64c 100644 --- a/src/pages/apiKeys/__tests__/AddApiKeyPage.test.tsx +++ b/src/pages/apiKeys/__tests__/AddApiKeyPage.test.tsx @@ -1,60 +1,105 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {fireEvent, render, screen} from '@testing-library/react'; +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import React from 'react'; -import {Provider} from 'react-redux'; -import {MemoryRouter, Route} from 'react-router-dom'; -import {partiesActions} from '../../../redux/slices/partiesSlice'; -import {store} from '../../../redux/store'; +import { Provider } from 'react-redux'; +import { MemoryRouter, Route } from 'react-router-dom'; +import { partiesActions } from '../../../redux/slices/partiesSlice'; +import { store } from '../../../redux/store'; import routes from '../../../routes'; -import {mockedKeys} from '../../../services/__mocks__/apiKeyService'; -import {ecAdminSignedDirect} from '../../../services/__mocks__/partyService'; +import { createMockedKeys, mockedKeys } from '../../../services/__mocks__/apiKeyService'; +import { ecAdminSignedDirect } from '../../../services/__mocks__/partyService'; import * as ApiKeyService from '../../../services/apiKeyService'; import AddApiKeyPage from '../AddApiKeyPage'; +import { API_KEY_PRODUCTS } from '../../../model/ApiKey'; let getInstitutionApiKeysSpy: jest.SpyInstance; let createInstitutionApiKeysSpy: jest.SpyInstance; beforeEach(() => { - getInstitutionApiKeysSpy = jest.spyOn(ApiKeyService, 'getInstitutionApiKeys'); - createInstitutionApiKeysSpy = jest.spyOn(ApiKeyService, 'createInstitutionApiKeys'); - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); + getInstitutionApiKeysSpy = jest.spyOn(ApiKeyService, 'getInstitutionApiKeys'); + createInstitutionApiKeysSpy = jest.spyOn(ApiKeyService, 'createInstitutionApiKeys'); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); }); describe('', () => { - test('render component AddApiKeyPage', async () => { - store.dispatch(partiesActions.setPartySelected(ecAdminSignedDirect)); - getInstitutionApiKeysSpy.mockResolvedValue(mockedKeys); - - render( - - - - - - - - - - ); - - const selectApiKey = screen - .getByTestId('product-test-id') - .querySelector('input') as HTMLInputElement; - - fireEvent.mouseDown(selectApiKey); - fireEvent.select(selectApiKey, { - target: {value: mockedKeys.institution_api_key_list![0].displayName}, - }); - expect(selectApiKey.value).toBe(mockedKeys.institution_api_key_list![0].displayName); - - const confirmBtn = await screen.findByTestId('api-key-btn-test-id'); - fireEvent.click(confirmBtn); - - const backBtn = await screen.findByTestId('api-key-btn-back-test-id'); - fireEvent.click(backBtn); + test('render component AddApiKeyPage', async () => { + store.dispatch(partiesActions.setPartySelected(ecAdminSignedDirect)); + getInstitutionApiKeysSpy.mockResolvedValue(mockedKeys); + createInstitutionApiKeysSpy.mockResolvedValue(createMockedKeys); + + render( + + + + + + + + + + ); + + const confirmBtn = await screen.findByTestId('api-key-btn-test-id'); + expect(confirmBtn).toBeDisabled(); + + const selectApiKey = screen.getByTestId('product-test-id'); + + fireEvent.mouseDown(screen.getByLabelText('addApiKeyPage.addForm.product.title')); + fireEvent.click( + screen.getByText(new RegExp(`addApiKeyPage.products.${API_KEY_PRODUCTS.BIZ.id}`, 'i')) + ); + + expect(selectApiKey).toHaveTextContent(API_KEY_PRODUCTS.BIZ.id); + + await waitFor(() => { + expect(confirmBtn).toBeEnabled(); + }); + + fireEvent.click(confirmBtn); + + await waitFor(() => { + expect(createInstitutionApiKeysSpy).toBeCalled(); + }); + }); + test('render component AddApiKeyPage createInstitutionApiKeysSpy error', async () => { + store.dispatch(partiesActions.setPartySelected(ecAdminSignedDirect)); + getInstitutionApiKeysSpy.mockResolvedValue(mockedKeys); + createInstitutionApiKeysSpy.mockRejectedValue(""); + + render( + + + + + + + + + + ); + + const confirmBtn = await screen.findByTestId('api-key-btn-test-id'); + expect(confirmBtn).toBeDisabled(); + + const selectApiKey = screen.getByTestId('product-test-id'); + + fireEvent.mouseDown(screen.getByLabelText('addApiKeyPage.addForm.product.title')); + fireEvent.click( + screen.getByText(new RegExp(`addApiKeyPage.products.${API_KEY_PRODUCTS.BIZ.id}`, 'i')) + ); + + expect(selectApiKey).toHaveTextContent(API_KEY_PRODUCTS.BIZ.id); + + await waitFor(() => { + expect(confirmBtn).toBeEnabled(); + }); + + fireEvent.click(confirmBtn); + + await waitFor(() => { + expect(createInstitutionApiKeysSpy).toBeCalled(); }); + }); }); From 17a5ff4ba51b7dcc8ef782fe2ed8da14e6be2bcc Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Thu, 27 Jun 2024 09:32:05 +0000 Subject: [PATCH 20/73] Bump to version 1.26.1-2-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d1a03ea19..5723b05ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.1-1-next", + "version": "1.26.1-2-next", "homepage": "ui", "private": true, "scripts": { From 82ea22bc425025676a826f4a96117f0e376194e3 Mon Sep 17 00:00:00 2001 From: Alessio Cialini <63233981+alessio-cialini@users.noreply.github.com> Date: Mon, 1 Jul 2024 09:38:59 +0200 Subject: [PATCH 21/73] fix: Updated AddEditCommissionBundleForm.tsx to call brokerDelegation as an institution (#587) --- .../components/AddEditCommissionBundleForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx index 4821d7db5..50e9f81ad 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx @@ -126,7 +126,7 @@ const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { Promise.all([ getPaymentTypes(), getTouchpoints(0, 50), - getBrokerDelegation(undefined, selectedParty?.partyId ?? ''), + getBrokerDelegation(selectedParty?.partyId ?? '', undefined), ]) .then(([paymentTypes, touchpoints, brokerDelegation]) => { if (paymentTypes) { From d4b6c8a6d315fd57293ed58244d0db23382e2250 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Mon, 1 Jul 2024 07:39:15 +0000 Subject: [PATCH 22/73] Bump to version 1.26.1-3-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5723b05ad..87653f6b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.1-2-next", + "version": "1.26.1-3-next", "homepage": "ui", "private": true, "scripts": { From c331f8857b7a43287302326039964b4ee01cf25e Mon Sep 17 00:00:00 2001 From: gioelemella <128155546+gioelemella@users.noreply.github.com> Date: Tue, 2 Jul 2024 09:49:31 +0200 Subject: [PATCH 23/73] [VAS-1070] feat; Change station and channel detail view on pending update (#586) * [VAS-1070] improved station API and removed wrapper status value from body * [VAS-1070] integrated new station and channel detail API and removed unused ones. * [VAS-1070] fix unit tests * [VAS-1070] handled station and channel with pending update * [VAS-1070] added common component for alert in station and channel detail page * [VAS-1070] removed created by when undefined * [VAS-1070] fix unit tests * [VAS-1070] fix title * [VAS-1070] rename variable --- package.json | 2 +- src/api/BackofficeClient.ts | 114 ++-- src/components/WrapperCommon/GetAlert.tsx | 98 ++++ .../{ => WrapperCommon}/StatusChip.tsx | 8 +- .../WrapperCommon/__tests__/GetAlert.test.tsx | 136 +++++ src/locale/it.json | 6 +- .../addEditChannel/AddEditChannelForm.tsx | 69 +-- .../addEditChannel/AddEditChannelPage.tsx | 7 +- .../ChannelAssociatePSPPage.tsx | 34 +- .../channels/detail/ChannelDetailPage.tsx | 11 +- .../__tests__/ChannelDetailHeader.test.tsx | 51 -- .../detail/__tests__/DetailButton.test.tsx | 96 ---- .../detail/__tests__/GetChannelAlert.test.tsx | 109 ---- .../detail/components/ChannelDetails.tsx | 51 +- .../detail/components/DetailButtons.tsx | 6 + .../detail/components/GetChannelAlert.tsx | 61 --- .../__tests__/ChannelDetails.test.tsx | 22 +- .../__tests__/DetailButtons.test.tsx | 102 ++++ src/pages/channels/list/ChannelsTable.tsx | 9 +- .../channels/list/ChannelsTableColumns.tsx | 15 +- .../detail/DelegationStationDetailsDrawer.tsx | 3 +- .../addEditStation/AddEditStationForm.tsx | 159 +++--- .../addEditStation/AddEditStationPage.tsx | 4 +- .../__tests__/AddEditStationForm.test.tsx | 53 +- .../stations/detail/StationDetailPage.tsx | 23 +- .../components/DetailButtonsStation.tsx | 425 +++++++-------- .../detail/components/StationDetails.tsx | 70 +-- .../stations/list/StationsTableColumns.tsx | 23 +- .../__tests__/StationsTableColumns.test.tsx | 9 +- src/routes.tsx | 4 +- src/services/__tests__/channelService.test.ts | 31 +- src/services/__tests__/stationService.test.ts | 489 +++++++++--------- src/services/channelService.ts | 23 +- src/services/stationService.ts | 117 ++--- 34 files changed, 1208 insertions(+), 1232 deletions(-) create mode 100644 src/components/WrapperCommon/GetAlert.tsx rename src/components/{ => WrapperCommon}/StatusChip.tsx (88%) create mode 100644 src/components/WrapperCommon/__tests__/GetAlert.test.tsx delete mode 100644 src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx delete mode 100644 src/pages/channels/detail/__tests__/DetailButton.test.tsx delete mode 100644 src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx delete mode 100644 src/pages/channels/detail/components/GetChannelAlert.tsx rename src/pages/channels/detail/{ => components}/__tests__/ChannelDetails.test.tsx (88%) create mode 100644 src/pages/channels/detail/components/__tests__/DetailButtons.test.tsx diff --git a/package.json b/package.json index c98677320..2b12c414c 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "clean:api-portal": "rimraf src/api/generated/portal && rimraf openApi/generated", "generate:api-portal": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/main/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-next": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/next/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", - "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1103-bundle-pspName/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", + "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1070-change-station-channel-detail-view-on-update/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-local": "npm run generate:client", "generate:client": "jq 'walk(if type == \"object\" and has(\"parameters\") then .parameters |= map(select(.name != \"X-Request-Id\")) else . end)' ./openApi/portal-api-docs.json > ./openApi/portal-api-docs.json.temp && mv ./openApi/portal-api-docs.json.temp ./openApi/portal-api-docs.json && yarn run clean:api-portal && mkdirp openApi/generated && gen-api-models --api-spec openApi/portal-api-docs.json --out-dir src/api/generated/portal --no-strict --request-types --response-decoders --client && node openApi/scripts/api-portal_fixPostGen.js" }, diff --git a/src/api/BackofficeClient.ts b/src/api/BackofficeClient.ts index 05a6fd15a..35a4256dc 100644 --- a/src/api/BackofficeClient.ts +++ b/src/api/BackofficeClient.ts @@ -18,7 +18,10 @@ import { ConfigurationStatus, StationOnCreation } from '../model/Station'; import { store } from '../redux/store'; import { extractResponse } from '../utils/client-utils'; import { ENV } from '../utils/env'; -import { WithDefaultsT as WithCustomDefaultsT, createClient as createCustomClient } from './custom/client'; +import { + WithDefaultsT as WithCustomDefaultsT, + createClient as createCustomClient, +} from './custom/client'; import { AvailableCodes } from './generated/portal/AvailableCodes'; import { BrokerAndEcDetailsResource } from './generated/portal/BrokerAndEcDetailsResource'; import { BrokerDto } from './generated/portal/BrokerDto'; @@ -75,7 +78,7 @@ import { PspChannelsResource } from './generated/portal/PspChannelsResource'; import { PublicBundleRequest } from './generated/portal/PublicBundleRequest'; import { StationCodeResource } from './generated/portal/StationCodeResource'; import { StationDetailResource } from './generated/portal/StationDetailResource'; -import { StationDetailsDto, StatusEnum } from './generated/portal/StationDetailsDto'; +import { StationDetailsDto } from './generated/portal/StationDetailsDto'; import { TestStationTypeEnum } from './generated/portal/StationTestDto'; import { TavoloOpDto } from './generated/portal/TavoloOpDto'; import { TavoloOpOperations } from './generated/portal/TavoloOpOperations'; @@ -91,7 +94,6 @@ import { Redirect_protocolEnum, WrapperChannelDetailsDto, } from './generated/portal/WrapperChannelDetailsDto'; -import { WrapperChannelDetailsResource } from './generated/portal/WrapperChannelDetailsResource'; import { WrapperChannelsResource } from './generated/portal/WrapperChannelsResource'; import { WrapperEntities } from './generated/portal/WrapperEntities'; import { WrapperStationDetailsDto } from './generated/portal/WrapperStationDetailsDto'; @@ -400,9 +402,17 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - // retrive of channel detail before on db and then on the node - getChannelDetail: async (channelcode: string): Promise => { - const result = await backofficeClient.getChannelDetail({ 'channel-code': channelcode }); + getChannelDetail: async ({ + channelCode, + status, + }: { + channelCode: string; + status: ConfigurationStatus; + }): Promise => { + const result = await backofficeClient.getChannelDetails({ + 'channel-code': channelCode, + status, + }); return extractResponse(result, 200, onRedirectToLogin); }, @@ -432,7 +442,7 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - createChannel: async (channel: ChannelDetailsDto): Promise => { + createChannel: async (channel: ChannelDetailsDto): Promise => { const channelBody2Send = channelBody(channel); const result = await backofficeClient.createChannel({ body: channelBody2Send, @@ -695,12 +705,13 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - getWrapperEntities: async (code: string): Promise => { - const result = await backofficeClient.getStation({ 'station-code': code }); - return extractResponse(result, 200, onRedirectToLogin); - }, - - createWrapperStation: async (station: WrapperStationDetailsDto): Promise => { + createWrapperStation: async ({ + station, + validationUrl, + }: { + station: WrapperStationDetailsDto; + validationUrl: string; + }): Promise => { const result = await backofficeClient.createWrapperStationDetails({ body: { brokerCode: station.brokerCode, @@ -720,36 +731,24 @@ export const BackofficeApi = { targetHostPof: station.targetHostPof, targetPathPof: station.targetPathPof, targetPortPof: station.targetPortPof, - validationUrl: station.validationUrl, + validationUrl, }, }); return extractResponse(result, 201, onRedirectToLogin); }, - updateWrapperStationToCheck: async ( - stationCode: string, - station: StationDetailsDto - ): Promise => { - const result = await backofficeClient.updateWrapperStationDetails({ - 'station-code': stationCode, - body: { - ...station, - status: StatusEnum.TO_CHECK, - }, - }); - return extractResponse(result, 200, onRedirectToLogin); - }, - - updateWrapperStationToCheckUpdate: async ( - stationCode: string, - station: StationDetailsDto - ): Promise => { + updateWrapperStationDetails: async ({ + stationCode, + station, + validationUrl, + }: { + stationCode: string; + station: StationDetailsDto; + validationUrl: string; + }): Promise => { const result = await backofficeClient.updateWrapperStationDetails({ 'station-code': stationCode, - body: { - ...station, - status: StatusEnum.TO_CHECK_UPDATE, - }, + body: { ...station, validationUrl }, }); return extractResponse(result, 200, onRedirectToLogin); }, @@ -773,34 +772,31 @@ export const BackofficeApi = { return extractResponse(result, 200, onRedirectToLogin); }, - updateStation: async ( - station: StationDetailsDto, - stationcode: string - ): Promise => { + updateStation: async ({ + stationCode, + station, + }: { + stationCode: string; + station: StationDetailsDto; + }): Promise => { const result = await backofficeClient.updateStation({ - body: { - ...station, - status: StatusEnum.APPROVED, - }, - 'station-code': stationcode, + body: station, + 'station-code': stationCode, }); return extractResponse(result, 200, onRedirectToLogin); }, - getWrapperEntitiesStation: async (code: string): Promise => { - const result = await backofficeClient.getWrapperEntitiesStation({ 'station-code': code }); - return extractResponse(result, 200, onRedirectToLogin); - }, - - // before tries to get the detail from the DB, if it doesn't find anything, will try to get the detail form apim - getStationDetail: async (stationId: string): Promise => { - const result = await backofficeClient.getStationDetail({ 'station-code': stationId }); - return extractResponse(result, 200, onRedirectToLogin); - }, - - // get the detail directly from apim - getStation: async (stationId: string): Promise => { - const result = await backofficeClient.getStation({ 'station-code': stationId }); + getStationDetails: async ({ + stationCode, + status, + }: { + stationCode: string; + status: ConfigurationStatus; + }): Promise => { + const result = await backofficeClient.getStationDetails({ + 'station-code': stationCode, + status, + }); return extractResponse(result, 200, onRedirectToLogin); }, diff --git a/src/components/WrapperCommon/GetAlert.tsx b/src/components/WrapperCommon/GetAlert.tsx new file mode 100644 index 000000000..4e3503de5 --- /dev/null +++ b/src/components/WrapperCommon/GetAlert.tsx @@ -0,0 +1,98 @@ +import { Alert, Typography } from '@mui/material'; +import { Box } from '@mui/system'; +import { useTranslation } from 'react-i18next'; +import { WrapperStatusEnum } from '../../api/generated/portal/ChannelDetailsResource'; +import { useUserRole } from '../../hooks/useUserRole'; + +type Props = { + componentPath: string; + wrapperStatus: WrapperStatusEnum; + note: string; + pendingUpdate: boolean; +}; + +// eslint-disable-next-line sonarjs/cognitive-complexity +export default function GetAlert({ + componentPath, + wrapperStatus, + note, + pendingUpdate, +}: Readonly) { + const { t } = useTranslation(); + const { userIsPagopaOperator } = useUserRole(); + + if (wrapperStatus !== WrapperStatusEnum.APPROVED) { + const isToBeValidated = + wrapperStatus === WrapperStatusEnum.TO_CHECK || + wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE; + const isToBeFixed = + wrapperStatus === WrapperStatusEnum.TO_FIX || + wrapperStatus === WrapperStatusEnum.TO_FIX_UPDATE; + + const userHasToTakeAction = + (isToBeValidated && userIsPagopaOperator) || (isToBeFixed && !userIsPagopaOperator); + return ( + + + + + + ); + } else if (pendingUpdate) { + return ( + + + + {t(`${componentPath}.alert.pendingUpdate`)} + + + + ); + } + return null; +} + +function GetAlertContent({ + isToBeFixed, + isToBeValidated, + userIsPagopaOperator, + componentPath, + note, + t, +}: Readonly<{ + isToBeFixed: boolean; + isToBeValidated: boolean; + userIsPagopaOperator: boolean; + componentPath: string; + note: string; + t: (key: string) => string; +}>) { + if (isToBeFixed) { + return ( + <> + + {t(`${componentPath}.alert.toFixTitle`)} + + {note.trim() ? note : t(`${componentPath}.alert.toFixMessage`)} + + ); + } + if (isToBeValidated && userIsPagopaOperator) { + return {t(`${componentPath}.alert.toCheckMessage`)}; + } + if (isToBeValidated && !userIsPagopaOperator) { + return {t(`${componentPath}.alert.waitingForRevision`)}; + } + return null; +} diff --git a/src/components/StatusChip.tsx b/src/components/WrapperCommon/StatusChip.tsx similarity index 88% rename from src/components/StatusChip.tsx rename to src/components/WrapperCommon/StatusChip.tsx index 8687f81bf..dd6592dcf 100644 --- a/src/components/StatusChip.tsx +++ b/src/components/WrapperCommon/StatusChip.tsx @@ -1,7 +1,7 @@ -import {Chip} from '@mui/material'; -import {useTranslation} from 'react-i18next'; -import {useUserRole} from '../hooks/useUserRole'; -import {WrapperStatusEnum} from '../api/generated/portal/WrapperStationResource'; +import { Chip } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { WrapperStatusEnum } from '../../api/generated/portal/StationDetailResource'; +import { useUserRole } from '../../hooks/useUserRole'; type Props = { status: string; diff --git a/src/components/WrapperCommon/__tests__/GetAlert.test.tsx b/src/components/WrapperCommon/__tests__/GetAlert.test.tsx new file mode 100644 index 000000000..0b04c8c74 --- /dev/null +++ b/src/components/WrapperCommon/__tests__/GetAlert.test.tsx @@ -0,0 +1,136 @@ +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { cleanup, render, screen } from '@testing-library/react'; +import React from 'react'; +import { Provider } from 'react-redux'; +import { WrapperStatusEnum } from '../../../api/generated/portal/ChannelDetailsResource'; +import * as useUserRole from '../../../hooks/useUserRole'; +import { ROLE } from '../../../model/RolePermission'; +import { store } from '../../../redux/store'; +import GetAlert from '../GetAlert'; + +beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); + jest.resetModules(); +}); +afterEach(cleanup); + +describe('', () => { + test('render component GetAlert on APPROVED', async () => { + render( + + + + + + ); + + expect(screen.queryByTestId('on-validation-alert-test-id')).not.toBeInTheDocument(); + expect(screen.queryByTestId('pendingUpdate-alert-test-id')).not.toBeInTheDocument(); + }); + + test('render component GetAlert on APPROVED with pending update', async () => { + render( + + + + + + ); + + expect(screen.queryByTestId('on-validation-alert-test-id')).not.toBeInTheDocument(); + expect(screen.getByTestId('pending-update-alert-test-id')).toBeInTheDocument(); + }); + + test('render component GetAlert on TO_FIX', async () => { + render( + + + + + + ); + + expect(screen.queryByTestId('pending-update-alert-test-id')).not.toBeInTheDocument(); + expect(screen.getByTestId('on-validation-alert-test-id')).toBeInTheDocument(); + expect(screen.getByTestId('to-fix-alert-test-id')).toBeInTheDocument(); + expect(screen.queryByTestId('to-check-alert-test-id')).not.toBeInTheDocument(); + expect(screen.queryByTestId('waiting-for-review-alert-test-id')).not.toBeInTheDocument(); + }); + + test('render component GetAlert on TO_CHECK and is operator', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: true, + }); + + render( + + + + + + ); + + expect(screen.queryByTestId('pending-update-alert-test-id')).not.toBeInTheDocument(); + expect(screen.getByTestId('on-validation-alert-test-id')).toBeInTheDocument(); + expect(screen.queryByTestId('to-fix-alert-test-id')).not.toBeInTheDocument(); + expect(screen.getByTestId('to-check-alert-test-id')).toBeInTheDocument(); + expect(screen.queryByTestId('waiting-for-review-alert-test-id')).not.toBeInTheDocument(); + }); + + test('render component GetAlert on TO_CHECK and not operator', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: true, + userIsEcAdmin: false, + userIsPspDirectAdmin: true, + userIsPagopaOperator: false, + userIsAdmin: true, + }); + + render( + + + + + + ); + + expect(screen.queryByTestId('pending-update-alert-test-id')).not.toBeInTheDocument(); + expect(screen.getByTestId('on-validation-alert-test-id')).toBeInTheDocument(); + expect(screen.queryByTestId('to-fix-alert-test-id')).not.toBeInTheDocument(); + expect(screen.queryByTestId('to-check-alert-test-id')).not.toBeInTheDocument(); + expect(screen.getByTestId('waiting-for-review-alert-test-id')).toBeInTheDocument(); + }); +}); diff --git a/src/locale/it.json b/src/locale/it.json index 5a4e353bc..4a74cdc11 100644 --- a/src/locale/it.json +++ b/src/locale/it.json @@ -390,7 +390,8 @@ "toCheckMessage": "Verifica le informazioni inserite dall’ente e approva o richiedi modifiche al canale.", "toFixTitle": "Modifiche richieste", "toFixMessage": "Canale in attesa di correzione da parte dell’ente.", - "waitingForRevision": "Il canale è in attesa di approvazione da parte di un nostro operatore. Riceverai una mail a procedura completata." + "waitingForRevision": "Il canale è in attesa di approvazione da parte di un nostro operatore. Riceverai una mail a procedura completata.", + "pendingUpdate": "Attenzione il canale ha delle modifiche in corso ed è quindi disponibile in sola lettura.\nLa configurazione visualizzata è quella attiva sul nodo, per effettuare delle modifiche spostarsi sul canale da validare." }, "modal": { "title": "Cosa c'è che non va?", @@ -693,7 +694,8 @@ "alert": { "toCheckMessage": "Verifica le informazioni inserite dall’ente e approva o richiedi modifiche alla stazione.", "toFixTitle": "Modifiche richieste", - "toFixMessage": "Stazione in attesa di correzione da parte dell’ente." + "toFixMessage": "Stazione in attesa di correzione da parte dell’ente.", + "pendingUpdate": "Attenzione la stazione ha delle modifiche in corso ed è quindi disponibile in sola lettura.\nLa configurazione visualizzata è quella attiva sul nodo, per effettuare delle modifiche spostarsi sulla stazione da validare." }, "modal": { "title": "Cosa c'è che non va?", diff --git a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx index c757e510d..fecca8279 100644 --- a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx +++ b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx @@ -1,7 +1,12 @@ /* eslint-disable sonarjs/cognitive-complexity */ /* eslint-disable complexity */ -import { useEffect, useState } from 'react'; -import { useHistory } from 'react-router'; +import { + Add, + Badge as BadgeIcon, + CreditCard as CreditCardIcon, + MenuBook as MenuBookIcon, + RemoveCircleOutline, +} from '@mui/icons-material'; import { Box, Button, @@ -15,18 +20,24 @@ import { TextField, Typography, } from '@mui/material'; -import { FormikProps, useFormik } from 'formik'; -import { Trans, useTranslation } from 'react-i18next'; import { ButtonNaked, theme } from '@pagopa/mui-italia'; import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; -import { - Add, - Badge as BadgeIcon, - CreditCard as CreditCardIcon, - MenuBook as MenuBookIcon, - RemoveCircleOutline, -} from '@mui/icons-material'; +import { FormikProps, useFormik } from 'formik'; +import { useEffect, useState } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router'; import { generatePath } from 'react-router-dom'; +import { + ChannelDetailsResource, + ProtocolEnum, + WrapperStatusEnum, +} from '../../../api/generated/portal/ChannelDetailsResource'; +import { PaymentTypes } from '../../../api/generated/portal/PaymentTypes'; +import { useUserRole } from '../../../hooks/useUserRole'; +import { ChannelOnCreation, FormAction } from '../../../model/Channel'; +import { Party } from '../../../model/Party'; +import { sortPaymentType } from '../../../model/PaymentType'; +import { ConfigurationStatus } from '../../../model/Station'; import ROUTES from '../../../routes'; import { createChannel, @@ -34,21 +45,11 @@ import { updateChannel, updateWrapperChannelDetails, } from '../../../services/channelService'; -import { PaymentTypes } from '../../../api/generated/portal/PaymentTypes'; -import { Party } from '../../../model/Party'; +import { getPaymentTypes } from '../../../services/configurationService'; import { LOADING_TASK_CHANNEL_ADD_EDIT, LOADING_TASK_PAYMENT_TYPE } from '../../../utils/constants'; -import { sortPaymentType } from '../../../model/PaymentType'; -import { isValidURL } from '../../components/commonFunctions'; -import { - ChannelDetailsResource, - ProtocolEnum, -} from '../../../api/generated/portal/ChannelDetailsResource'; -import { WrapperStatusEnum } from '../../../api/generated/portal/WrapperChannelDetailsResource'; -import { ChannelOnCreation, FormAction } from '../../../model/Channel'; import { ENV } from '../../../utils/env'; import ConfirmModal from '../../components/ConfirmModal'; -import { getPaymentTypes } from '../../../services/configurationService'; -import { useUserRole } from '../../../hooks/useUserRole'; +import { isValidURL } from '../../components/commonFunctions'; import AddEditChannelFormSectionTitle from './AddEditChannelFormSectionTitle'; import AddEditChannelValidationForm from './components/AddEditChannelValidationForm'; @@ -401,9 +402,11 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct } }; - const redirect = () => { + const redirect = (status: ConfigurationStatus) => { if (userIsPagopaOperator) { - history.push(generatePath(ROUTES.CHANNEL_DETAIL, { channelId: formik.values.channel_code })); + history.push( + generatePath(ROUTES.CHANNEL_DETAIL, { channelId: formik.values.channel_code, status }) + ); } else { history.push(ROUTES.CHANNELS); } @@ -419,11 +422,12 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct try { const validationUrl = `${window.location.origin}${generatePath(ROUTES.CHANNEL_DETAIL, { channelId: formik.values.channel_code, + status: ConfigurationStatus.TO_BE_VALIDATED, })}`; if (formAction === FormAction.Create || formAction === FormAction.Duplicate) { await createWrapperChannelDetails(values as any, validationUrl); - redirect(); + redirect(ConfigurationStatus.TO_BE_VALIDATED); } if (formAction === FormAction.Edit) { @@ -442,10 +446,11 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct } else { throw new Error('Wrong channel wrapper status'); } + redirect(ConfigurationStatus.ACTIVE); } else { - await updateWrapperChannelDetails({channelCode, channel: values, validationUrl}); + await updateWrapperChannelDetails({ channelCode, channel: values, validationUrl }); + redirect(ConfigurationStatus.TO_BE_VALIDATED); } - redirect(); } } catch (reason) { addError({ @@ -705,7 +710,13 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct onClick={() => userIsPagopaOperator ? history.push( - generatePath(ROUTES.CHANNEL_DETAIL, { channelId: formik.values.channel_code }) + generatePath(ROUTES.CHANNEL_DETAIL, { + channelId: formik.values.channel_code, + status: + channelDetail?.wrapperStatus === WrapperStatusEnum.APPROVED + ? ConfigurationStatus.ACTIVE + : ConfigurationStatus.TO_BE_VALIDATED, + }) ) : history.push(ROUTES.CHANNELS) } diff --git a/src/pages/channels/addEditChannel/AddEditChannelPage.tsx b/src/pages/channels/addEditChannel/AddEditChannelPage.tsx index 9e1eb4633..572a09c71 100644 --- a/src/pages/channels/addEditChannel/AddEditChannelPage.tsx +++ b/src/pages/channels/addEditChannel/AddEditChannelPage.tsx @@ -6,14 +6,15 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useHistory, useParams } from 'react-router'; import { ChannelDetailsResource } from '../../../api/generated/portal/ChannelDetailsResource'; -import { WrapperStatusEnum } from '../../../api/generated/portal/WrapperChannelDetailsResource'; +import { WrapperStatusEnum } from '../../../api/generated/portal/StationDetailResource'; +import { useUserRole } from '../../../hooks/useUserRole'; import { FormAction } from '../../../model/Channel'; +import { ConfigurationStatus } from '../../../model/Station'; import { useAppSelector } from '../../../redux/hooks'; import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; import { getChannelCode, getChannelDetail } from '../../../services/channelService'; import { LOADING_TASK_CHANNEL_ADD_EDIT } from '../../../utils/constants'; -import { useUserRole } from '../../../hooks/useUserRole'; import AddEditChannelForm from './AddEditChannelForm'; const AddEditChannelPage = () => { @@ -34,7 +35,7 @@ const AddEditChannelPage = () => { useEffect(() => { if (formAction === FormAction.Edit) { setLoading(true); - getChannelDetail(channelId) + getChannelDetail({channelCode: channelId, status: ConfigurationStatus.TO_BE_VALIDATED}) .then((response) => { setChannelDetail(response); setChannelCode(response.channel_code ?? ''); diff --git a/src/pages/channels/channelAssociatePSP/ChannelAssociatePSPPage.tsx b/src/pages/channels/channelAssociatePSP/ChannelAssociatePSPPage.tsx index da7e88576..10a5c45af 100644 --- a/src/pages/channels/channelAssociatePSP/ChannelAssociatePSPPage.tsx +++ b/src/pages/channels/channelAssociatePSP/ChannelAssociatePSPPage.tsx @@ -1,31 +1,31 @@ -import {useEffect, useState} from 'react'; import Button from '@mui/material/Button'; import FormControl from '@mui/material/FormControl'; import Grid from '@mui/material/Grid'; import Paper from '@mui/material/Paper'; +import { useEffect, useState } from 'react'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import {useTranslation, Trans} from 'react-i18next'; -import {Box} from '@mui/system'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {useFormik} from 'formik'; -import {generatePath, useHistory, useParams} from 'react-router-dom'; -import {theme} from '@pagopa/mui-italia'; +import { Box } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { useFormik } from 'formik'; +import { Trans, useTranslation } from 'react-i18next'; +import { generatePath, useHistory, useParams } from 'react-router-dom'; +import { ChannelDetailsResource } from '../../../api/generated/portal/ChannelDetailsResource'; +import { Delegation } from '../../../api/generated/portal/Delegation'; +import { ConfigurationStatus } from '../../../model/Station'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; -import {LOADING_TASK_PSP_AVAILABLE} from '../../../utils/constants'; -import {addCurrentPSP} from '../../../utils/channel-utils'; import { associatePSPtoChannel, getChannelDetail, } from '../../../services/channelService'; -import {getBrokerDelegation} from '../../../services/institutionService'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; -import {ChannelDetailsResource} from '../../../api/generated/portal/ChannelDetailsResource'; -import {Party} from '../../../model/Party'; -import {Delegation} from '../../../api/generated/portal/Delegation'; -import {getBrokerAndPspDetails} from '../../../services/nodeService'; +import { getBrokerDelegation } from '../../../services/institutionService'; +import { getBrokerAndPspDetails } from '../../../services/nodeService'; +import { addCurrentPSP } from '../../../utils/channel-utils'; +import { LOADING_TASK_PSP_AVAILABLE } from '../../../utils/constants'; import PSPSelectionSearch from './PSPSelectionSearch'; function ChannelAssociatePSPPage() { @@ -102,7 +102,7 @@ function ChannelAssociatePSPPage() { useEffect(() => { setLoading(true); if (selectedParty) { - getChannelDetail(channelId) + getChannelDetail({channelCode: channelId, status: ConfigurationStatus.ACTIVE}) .then((channel) => setChannelDetail(channel)) .catch((reason) => console.error(reason)); getBrokerDelegation(undefined, selectedParty?.partyId, ["PSP"]) diff --git a/src/pages/channels/detail/ChannelDetailPage.tsx b/src/pages/channels/detail/ChannelDetailPage.tsx index 2e6dc7ae4..3d8d829f8 100644 --- a/src/pages/channels/detail/ChannelDetailPage.tsx +++ b/src/pages/channels/detail/ChannelDetailPage.tsx @@ -3,11 +3,12 @@ import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router'; -import { getChannelDetail, getChannelPSPs } from '../../../services/channelService'; -import { LOADING_TASK_CHANNEL_DETAIL } from '../../../utils/constants'; +import { ChannelDetailsResource } from '../../../api/generated/portal/ChannelDetailsResource'; +import { ConfigurationStatus } from '../../../model/Station'; import { useAppSelector } from '../../../redux/hooks'; import { partiesSelectors } from '../../../redux/slices/partiesSlice'; -import { ChannelDetailsResource } from '../../../api/generated/portal/ChannelDetailsResource'; +import { getChannelDetail, getChannelPSPs } from '../../../services/channelService'; +import { LOADING_TASK_CHANNEL_DETAIL } from '../../../utils/constants'; import ChannelDetails from './components/ChannelDetails'; const ChannelDetailPage = () => { @@ -17,12 +18,12 @@ const ChannelDetailPage = () => { const [channelDetail, setChannelDetail] = useState({} as any); const [PSPAssociatedNumber, setPSPAssociatedNumber] = useState(0); const addError = useErrorDispatcher(); - const { channelId } = useParams<{ channelId: string }>(); + const { channelId, status } = useParams<{ channelId: string; status: ConfigurationStatus }>(); const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); useEffect(() => { setLoading(true); - Promise.all([getChannelDetail(channelId), getChannelPSPs(channelId, '', 0)]) + Promise.all([getChannelDetail({channelCode: channelId, status}), getChannelPSPs(channelId, '', 0)]) .then(([channelDetailResponse, channelPSPList]) => { setChannelDetail(channelDetailResponse); setPSPAssociatedNumber(channelPSPList?.page_info?.total_items ?? 0); diff --git a/src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx b/src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx deleted file mode 100644 index 5a295da4b..000000000 --- a/src/pages/channels/detail/__tests__/ChannelDetailHeader.test.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, screen, render, fireEvent} from '@testing-library/react'; -import React from 'react'; -import {MemoryRouter, Route} from 'react-router-dom'; -import {store} from '../../../../redux/store'; -import ChannelDetailHeader from '../components/GetChannelAlert'; -import {StatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsDto'; -import {WrapperStatusEnum,} from '../../../../api/generated/portal/ChannelDetailsResource'; -import {Provider} from 'react-redux'; - - -beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); - jest.resetModules(); -}); -afterEach(cleanup); - -describe('', () => { - const channelId = 'XPAY_03_ONUS'; - test('render component ChannelDetailHeader', async () => { - const channelDetail = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `$test`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - status: StatusEnum.TO_CHECK, - wrapperStatus: WrapperStatusEnum.APPROVED - }; - render( - - - - - - - - - - ); - - }); - -}); - - diff --git a/src/pages/channels/detail/__tests__/DetailButton.test.tsx b/src/pages/channels/detail/__tests__/DetailButton.test.tsx deleted file mode 100644 index 0c34ec7ba..000000000 --- a/src/pages/channels/detail/__tests__/DetailButton.test.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import { fireEvent, render, screen, waitFor} from '@testing-library/react'; -import {MemoryRouter, Route, Router} from 'react-router-dom'; -import {Provider} from 'react-redux'; -import {mockedPaymentTypes} from '../../../../services/__mocks__/configurationService'; -import {StatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsDto'; -import {WrapperStatusEnum,} from '../../../../api/generated/portal/ChannelDetailsResource'; -import {ROLE} from '../../../../model/RolePermission'; -import {store} from '../../../../redux/store'; -import * as useUserRole from '../../../../hooks/useUserRole'; -import {theme} from '@pagopa/mui-italia'; -import {ThemeProvider} from '@mui/system'; -import DetailButtons from '../components/DetailButtons'; - -describe('', () => { - test('render component DetailButtons', async () => { - const channelId = 'XPAY_03_ONUS'; - const channelDetailWrapper = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `${channelId}`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), - status: StatusEnum.TO_CHECK, - }; - render( - - - - - - - - - - ); - }); - - test('render component DetailButtons should contain modal', async () => { - - jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ - userRole: ROLE.PAGOPA_OPERATOR, - userIsPspAdmin: false, - userIsEcAdmin: false, - userIsPspDirectAdmin: false, - userIsPagopaOperator: true, - userIsAdmin: true, - }); - - const channelId = 'XPAY_03_ONUS'; - const channelDetailWrapper = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `${channelId}`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), - status: StatusEnum.TO_CHECK, - wrapperStatus: WrapperStatusEnum.TO_CHECK - }; - render( - - - - - - - - - - ); - - expect(screen.queryByTestId('request-edit-button')).toBeInTheDocument(); - - fireEvent.click(screen.getByTestId('request-edit-button')); - - await waitFor(() => { - expect(screen.queryByTestId('confirm-and-send-button')).toBeInTheDocument(); - }); - const confirmButton = screen.getByTestId('confirm-and-send-button'); - - expect(confirmButton).toBeDisabled(); - - fireEvent.change(screen.getByTestId('requestInput'), {target: {value: 'note'}}); - - await waitFor(() => { - expect(confirmButton).toBeEnabled(); - }); - - fireEvent.click(confirmButton); - - }); -}); diff --git a/src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx b/src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx deleted file mode 100644 index 40bc19545..000000000 --- a/src/pages/channels/detail/__tests__/GetChannelAlert.test.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, render} from '@testing-library/react'; -import React from 'react'; -import {MemoryRouter, Route} from 'react-router-dom'; -import {store} from '../../../../redux/store'; -import * as useUserRole from '../../../../hooks/useUserRole'; -import {ROLE} from '../../../../model/RolePermission'; -import GetChannelAlert from '../components/GetChannelAlert'; -import {StatusEnum} from '../../../../api/generated/portal/WrapperChannelDetailsDto'; -import {WrapperStatusEnum,} from '../../../../api/generated/portal/ChannelDetailsResource'; -import {Provider} from 'react-redux'; - -beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); - jest.resetModules(); -}); -afterEach(cleanup); - -describe('', () => { - const channelId = 'XPAY_03_ONUS'; - test('render component ChannelDetailPage on APPROVED', async () => { - const channelDetail = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `$test`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - status: StatusEnum.APPROVED, - wrapperStatus: WrapperStatusEnum.APPROVED - }; - render( - - - - - - - - - - ); - }); - - test('render component ChannelDetailPage on TO_FIX', async () => { - const channelDetail = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `$test`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - status: StatusEnum.TO_FIX, - wrapperStatus: WrapperStatusEnum.TO_FIX - }; - render( - - - - - - - - - - ); - }); - - test('render component ChannelDetailPage on TO_CHECK', async () => { - - jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ - userRole: ROLE.PAGOPA_OPERATOR, - userIsPspAdmin: false, - userIsEcAdmin: false, - userIsPspDirectAdmin: false, - userIsPagopaOperator: true, - userIsAdmin: true, - }); - - const channelDetail = { - broker_psp_code: '97735020584', - broker_description: 'AgID - Agenzia per l’Italia Digitale', - channel_code: `$test`, - target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', - target_port: 8081, - target_host: ' lab.link.it', - status: StatusEnum.TO_CHECK, - wrapperStatus: WrapperStatusEnum.TO_CHECK - }; - render( - - - - - - - - - - ); - }); - -}); - - diff --git a/src/pages/channels/detail/components/ChannelDetails.tsx b/src/pages/channels/detail/components/ChannelDetails.tsx index 2956b6d8a..e3d0b5f0d 100644 --- a/src/pages/channels/detail/components/ChannelDetails.tsx +++ b/src/pages/channels/detail/components/ChannelDetails.tsx @@ -1,24 +1,23 @@ /* eslint-disable complexity */ import { ArrowBack, VisibilityOff } from '@mui/icons-material'; -import { Breadcrumbs, Chip, Divider, Grid, IconButton, Paper, Typography } from '@mui/material'; -import { Box, Stack } from '@mui/system'; -import { useHistory } from 'react-router-dom'; -import { useTranslation } from 'react-i18next'; -import { useState } from 'react'; import VisibilityIcon from '@mui/icons-material/Visibility'; +import { Chip, Grid, IconButton, Paper, Typography } from '@mui/material'; +import { Box } from '@mui/system'; import { ButtonNaked } from '@pagopa/mui-italia'; -import { StatusChip } from '../../../../components/StatusChip'; -import ROUTES from '../../../../routes'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router-dom'; import { ChannelDetailsResource, + ProtocolEnum, WrapperStatusEnum, } from '../../../../api/generated/portal/ChannelDetailsResource'; -import { ProtocolEnum } from '../../../../api/generated/portal/WrapperChannelDetailsResource'; -import { ENV } from '../../../../utils/env'; +import GetAlert from '../../../../components/WrapperCommon/GetAlert'; +import { StatusChip } from '../../../../components/WrapperCommon/StatusChip'; import { useUserRole } from '../../../../hooks/useUserRole'; +import ROUTES from '../../../../routes'; +import { ENV } from '../../../../utils/env'; import DetailButtons from './DetailButtons'; -import GetChannelAlert from './GetChannelAlert'; - type Props = { channelDetail: ChannelDetailsResource; @@ -87,7 +86,12 @@ const ChannelDetails = ({ )} - + )} - {t('channelDetailPage.createdOn')}{' '} - - {`${channelDetail?.createdAt?.toLocaleDateString('en-GB') ?? '-'}`} - {' '} - {t('general.fromLower')}{' '} - - {channelDetail?.createdBy} - - {'.'} + {channelDetail?.createdBy && ( + <> + {t('channelDetailPage.createdOn')}{' '} + + {`${channelDetail?.createdAt?.toLocaleDateString('en-GB') ?? '-'}`} + {' '} + {t('general.fromLower')}{' '} + + {channelDetail?.createdBy} + + {'.'} + + )} {channelDetail?.modifiedBy && (
{t('channelDetailPage.lastModified')}{' '} @@ -376,4 +384,3 @@ const ChannelDetails = ({ }; export default ChannelDetails; - diff --git a/src/pages/channels/detail/components/DetailButtons.tsx b/src/pages/channels/detail/components/DetailButtons.tsx index 4126e4ce6..2cf307d55 100644 --- a/src/pages/channels/detail/components/DetailButtons.tsx +++ b/src/pages/channels/detail/components/DetailButtons.tsx @@ -118,6 +118,8 @@ function Buttons({ const { userIsPagopaOperator } = useUserRole(); const { t } = useTranslation(); const { channelId } = useParams<{ channelId: string }>(); + const disableOnPendingUpdate = + channelDetails?.wrapperStatus === WrapperStatusEnum.APPROVED && channelDetails?.pendingUpdate; if (userIsPagopaOperator) { return ( @@ -128,6 +130,7 @@ function Buttons({ variant="outlined" onClick={() => setShowModal(true)} data-testid="request-edit-button" + disabled={disableOnPendingUpdate} > {t('channelDetailPage.requestEdit')} @@ -139,6 +142,7 @@ function Buttons({ actionId: FormAction.Edit, })} variant="contained" + disabled={disableOnPendingUpdate} > {t( channelDetails?.wrapperStatus === WrapperStatusEnum.APPROVED @@ -183,6 +187,7 @@ function Buttons({ color="primary" variant="outlined" startIcon={} + disabled={disableOnPendingUpdate} > {t('channelDetailPage.duplicate')} @@ -196,6 +201,7 @@ function Buttons({ })} variant="contained" startIcon={} + disabled={disableOnPendingUpdate} > {t('general.modify')} diff --git a/src/pages/channels/detail/components/GetChannelAlert.tsx b/src/pages/channels/detail/components/GetChannelAlert.tsx deleted file mode 100644 index 45b9eb8f2..000000000 --- a/src/pages/channels/detail/components/GetChannelAlert.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { Alert, Typography } from '@mui/material'; -import { Box } from '@mui/system'; -import { useTranslation } from 'react-i18next'; -import { ChannelDetailsResource } from '../../../../api/generated/portal/ChannelDetailsResource'; -import { WrapperStatusEnum } from '../../../../api/generated/portal/WrapperChannelDetailsResource'; -import { useUserRole } from '../../../../hooks/useUserRole'; - -type Props = { - channelDetail: ChannelDetailsResource; -}; - -// eslint-disable-next-line sonarjs/cognitive-complexity -export default function GetChannelAlert({ channelDetail }: Props) { - const { t } = useTranslation(); - const { userIsPagopaOperator } = useUserRole(); - - if (channelDetail?.wrapperStatus !== WrapperStatusEnum.APPROVED) { - const isToBeValidated = - channelDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK || - channelDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE; - const isToBeFixed = - channelDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX || - channelDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX_UPDATE; - - const userHasToTakeAction = - (isToBeValidated && userIsPagopaOperator) || (isToBeFixed && !userIsPagopaOperator); - return ( - <> - - - {userIsPagopaOperator ? ( - - {t( - `channelDetailValidationPage.alert.${ - isToBeValidated ? 'toCheckMessage' : 'toFixMessage' - }` - )} - - ) : isToBeFixed && channelDetail?.note?.trim() ? ( - <> - - {t('channelDetailValidationPage.alert.toFixTitle')} - - {channelDetail.note} - - ) : ( - isToBeValidated && ( - {t('channelDetailValidationPage.alert.waitingForRevision')} - ) - )} - - - - ); - } - return null; -} diff --git a/src/pages/channels/detail/__tests__/ChannelDetails.test.tsx b/src/pages/channels/detail/components/__tests__/ChannelDetails.test.tsx similarity index 88% rename from src/pages/channels/detail/__tests__/ChannelDetails.test.tsx rename to src/pages/channels/detail/components/__tests__/ChannelDetails.test.tsx index 3aa062eee..1026bd413 100644 --- a/src/pages/channels/detail/__tests__/ChannelDetails.test.tsx +++ b/src/pages/channels/detail/components/__tests__/ChannelDetails.test.tsx @@ -3,13 +3,13 @@ import { theme } from '@pagopa/mui-italia'; import { cleanup, screen, render, fireEvent } from '@testing-library/react'; import React from 'react'; import { MemoryRouter, Route } from 'react-router-dom'; -import { store } from '../../../../redux/store'; +import { store } from '../../../../../redux/store'; import { Provider } from 'react-redux'; -import ChannelDetails from '../components/ChannelDetails'; -import { StatusEnum } from '../../../../api/generated/portal/ChannelDetailsDto'; -import { mockedPaymentTypes } from '../../../../services/__mocks__/configurationService'; -import * as useUserRole from '../../../../hooks/useUserRole'; -import { ROLE } from '../../../../model/RolePermission'; +import ChannelDetails from '../ChannelDetails'; +import { StatusEnum } from '../../../../../api/generated/portal/ChannelDetailsDto'; +import { mockedPaymentTypes } from '../../../../../services/__mocks__/configurationService'; +import * as useUserRole from '../../../../../hooks/useUserRole'; +import { ROLE } from '../../../../../model/RolePermission'; beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(() => {}); @@ -18,7 +18,7 @@ beforeEach(() => { }); afterEach(cleanup); -const passwordFieldValue = 'randomValue'; +const pFieldValue = 'randomValue'; describe('', () => { const channelId = 'XPAY_03_ONUS'; @@ -32,7 +32,7 @@ describe('', () => { proxy_host: ' proxy.link.it', payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), status: StatusEnum.TO_CHECK, - password: passwordFieldValue, + password: pFieldValue, }; const channelDetailToFix = { broker_psp_code: '97735020584', @@ -44,7 +44,7 @@ describe('', () => { proxy_host: ' proxy.link.it', payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), status: StatusEnum.TO_FIX, - password: passwordFieldValue, + password: pFieldValue, note: 'note', }; test('render component ChannelDetails with channelDetail', async () => { @@ -80,7 +80,7 @@ describe('', () => { fireEvent.click(showPasswordButton); - expect(passwordField.innerHTML).toBe(passwordFieldValue); + expect(passwordField.innerHTML).toBe(pFieldValue); }); test('render component ChannelDetails with channelDetail TO_FIX', async () => { @@ -116,7 +116,7 @@ describe('', () => { fireEvent.click(showPasswordButton); - expect(passwordField.innerHTML).toBe(passwordFieldValue); + expect(passwordField.innerHTML).toBe(pFieldValue); }); test('render component ChannelDetails with empty channelDetail', async () => { diff --git a/src/pages/channels/detail/components/__tests__/DetailButtons.test.tsx b/src/pages/channels/detail/components/__tests__/DetailButtons.test.tsx new file mode 100644 index 000000000..99e9a4af7 --- /dev/null +++ b/src/pages/channels/detail/components/__tests__/DetailButtons.test.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { MemoryRouter, Route, Router } from 'react-router-dom'; +import { Provider } from 'react-redux'; +import { mockedPaymentTypes } from '../../../../../services/__mocks__/configurationService'; +import { StatusEnum } from '../../../../../api/generated/portal/WrapperChannelDetailsDto'; +import { WrapperStatusEnum } from '../../../../../api/generated/portal/ChannelDetailsResource'; +import { ROLE } from '../../../../../model/RolePermission'; +import { store } from '../../../../../redux/store'; +import * as useUserRole from '../../../../../hooks/useUserRole'; +import { theme } from '@pagopa/mui-italia'; +import { ThemeProvider } from '@mui/system'; +import DetailButtons from '../DetailButtons'; + +describe('', () => { + test('render component DetailButtons', async () => { + const channelId = 'XPAY_03_ONUS'; + const channelDetailWrapper = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `${channelId}`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), + status: StatusEnum.TO_CHECK, + }; + render( + + + + + + + + + + ); + }); + + test('render component DetailButtons should contain modal', async () => { + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PAGOPA_OPERATOR, + userIsPspAdmin: false, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: true, + userIsAdmin: true, + }); + + const channelId = 'XPAY_03_ONUS'; + const channelDetailWrapper = { + broker_psp_code: '97735020584', + broker_description: 'AgID - Agenzia per l’Italia Digitale', + channel_code: `${channelId}`, + target_path: ' /govpay/api/pagopa/PagamentiTelematiciCCPservice', + target_port: 8081, + target_host: ' lab.link.it', + payment_types: mockedPaymentTypes.payment_types!.map((e) => e.payment_type ?? ''), + status: StatusEnum.TO_CHECK, + wrapperStatus: WrapperStatusEnum.TO_CHECK, + }; + render( + + + + + + + + + + ); + + expect(screen.queryByTestId('request-edit-button')).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('request-edit-button')); + + await waitFor(() => { + expect(screen.queryByTestId('confirm-and-send-button')).toBeInTheDocument(); + }); + const confirmButton = screen.getByTestId('confirm-and-send-button'); + + expect(confirmButton).toBeDisabled(); + + fireEvent.change(screen.getByTestId('requestInput'), { target: { value: 'note' } }); + + await waitFor(() => { + expect(confirmButton).toBeEnabled(); + }); + + fireEvent.click(confirmButton); + }); +}); diff --git a/src/pages/channels/list/ChannelsTable.tsx b/src/pages/channels/list/ChannelsTable.tsx index 78fe9ea60..0d6edaf23 100644 --- a/src/pages/channels/list/ChannelsTable.tsx +++ b/src/pages/channels/list/ChannelsTable.tsx @@ -3,8 +3,6 @@ import { GridColDef } from '@mui/x-data-grid'; import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useHistory } from 'react-router'; -import { generatePath } from 'react-router-dom'; import { WrapperChannelsResource } from '../../../api/generated/portal/WrapperChannelsResource'; import TableDataGrid from '../../../components/Table/TableDataGrid'; import { useUserRole } from '../../../hooks/useUserRole'; @@ -29,16 +27,11 @@ export default function ChannelsTable({ statusFilter, }: Readonly<{ channelCodeFilter: string; statusFilter: ConfigurationStatus }>) { const { t } = useTranslation(); - const history = useHistory(); const { userIsPagopaOperator } = useUserRole(); const addError = useErrorDispatcher(); const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const onRowClick = (channelIdRow: string) => { - history.push(generatePath(`${ROUTES.CHANNEL_DETAIL}`, { channelId: channelIdRow })); - }; - - const columns: Array = buildColumnDefs(t, onRowClick); + const columns: Array = buildColumnDefs(t); const setLoadingOverlay = useLoading(LOADING_TASK_CHANNELS_LIST); const [channels, setChannels] = useState(emptyChannelsResource); diff --git a/src/pages/channels/list/ChannelsTableColumns.tsx b/src/pages/channels/list/ChannelsTableColumns.tsx index c99518c61..269ceab55 100644 --- a/src/pages/channels/list/ChannelsTableColumns.tsx +++ b/src/pages/channels/list/ChannelsTableColumns.tsx @@ -2,15 +2,16 @@ import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid'; import { TFunction } from 'react-i18next'; import { generatePath } from 'react-router'; import { StatusEnum } from '../../../api/generated/portal/ChannelDetailsDto'; -import { StatusChip } from '../../../components/StatusChip'; import GridLinkAction from '../../../components/Table/GridLinkAction'; import { renderCell, showCustomHeader } from '../../../components/Table/TableUtils'; import { FormAction } from '../../../model/Channel'; import ROUTES from '../../../routes'; +import { WrapperStatusEnum } from '../../../api/generated/portal/StationDetailResource'; +import { ConfigurationStatus } from '../../../model/Station'; +import { StatusChip } from '../../../components/WrapperCommon/StatusChip'; export function buildColumnDefs( - t: TFunction<'translation', undefined>, - _onRowClick: (channelId: string) => void + t: TFunction<'translation', undefined> ) { return [ { @@ -97,7 +98,13 @@ export function buildColumnDefs( ); diff --git a/src/pages/delegations/detail/DelegationStationDetailsDrawer.tsx b/src/pages/delegations/detail/DelegationStationDetailsDrawer.tsx index 02c5ec3b3..0e878b9c9 100644 --- a/src/pages/delegations/detail/DelegationStationDetailsDrawer.tsx +++ b/src/pages/delegations/detail/DelegationStationDetailsDrawer.tsx @@ -9,6 +9,7 @@ import {CIBrokerStationResource} from '../../../api/generated/portal/CIBrokerSta import {PaddedDrawer} from '../../../components/PaddedDrawer'; import ROUTES from '../../../routes'; import {formatDateToDDMMYYYY} from '../../../utils/common-utils'; +import { ConfigurationStatus } from '../../../model/Station'; export const DelegationStationDetailsDrawer = ({ t, @@ -104,7 +105,7 @@ export const DelegationStationDetailsDrawer = ({ endIcon={} onClick={() => history.push( - generatePath(ROUTES.STATION_DETAIL, {stationId: drawerValue?.station_code}) + generatePath(ROUTES.STATION_DETAIL, {stationId: drawerValue?.station_code, status: ConfigurationStatus.ACTIVE}) ) } sx={{color: 'primary.main', mt: 'auto', justifyContent: 'start'}} diff --git a/src/pages/stations/addEditStation/AddEditStationForm.tsx b/src/pages/stations/addEditStation/AddEditStationForm.tsx index 7b43df263..3a1241689 100644 --- a/src/pages/stations/addEditStation/AddEditStationForm.tsx +++ b/src/pages/stations/addEditStation/AddEditStationForm.tsx @@ -1,29 +1,29 @@ /* eslint-disable sonarjs/cognitive-complexity */ /* eslint-disable complexity */ import { - Badge as BadgeIcon, - Cable as CableIcon, - CallMade, - Check as CheckIcon, - MenuBook, - NorthEast as NorthEastIcon, + Badge as BadgeIcon, + Cable as CableIcon, + CallMade, + Check as CheckIcon, + MenuBook, + NorthEast as NorthEastIcon, } from '@mui/icons-material'; import { - Button, - FormControl, - FormControlLabel, - Grid, - InputAdornment, - InputLabel, - Link, - MenuItem, - Paper, - Radio, - RadioGroup, - Select, - Stack, - TextField, - Typography, + Button, + FormControl, + FormControlLabel, + Grid, + InputAdornment, + InputLabel, + Link, + MenuItem, + Paper, + Radio, + RadioGroup, + Select, + Stack, + TextField, + Typography, } from '@mui/material'; import CircularProgressIcon from '@mui/material/CircularProgress'; import { Box } from '@mui/system'; @@ -34,48 +34,48 @@ import { useEffect, useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { generatePath, useHistory } from 'react-router-dom'; import { - StationDetailResource, - WrapperStatusEnum, + StationDetailResource, + WrapperStatusEnum, } from '../../../api/generated/portal/StationDetailResource'; import { RedirectProtocolEnum, StatusEnum } from '../../../api/generated/portal/StationDetailsDto'; import { TestStationTypeEnum } from '../../../api/generated/portal/StationTestDto'; import { - TestResultEnum, - TestStationResource, + TestResultEnum, + TestStationResource, } from '../../../api/generated/portal/TestStationResource'; import { useFlagValue } from '../../../hooks/useFeatureFlags'; import { useUserRole } from '../../../hooks/useUserRole'; import { - ConnectionType, - GPDConfigs, - IGPDConfig, - INewConnConfig, - NewConnConfigs, - StationCategory, - StationFormAction, - StationOnCreation, + ConfigurationStatus, + ConnectionType, + GPDConfigs, + IGPDConfig, + INewConnConfig, + NewConnConfigs, + StationCategory, + StationFormAction, + StationOnCreation, } from '../../../model/Station'; import { useAppSelector } from '../../../redux/hooks'; import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import ROUTES from '../../../routes'; import { - createStation, - createWrapperStation, - getStationCodeV2, - testStation, - updateStation, - updateWrapperStationToCheck, - updateWrapperStationToCheckUpdate, + createStation, + createWrapperStation, + getStationCodeV2, + testStation, + updateStation, + updateWrapperStationDetails, } from '../../../services/stationService'; import { - LOADING_TASK_GENERATION_STATION_CODE, - LOADING_TASK_STATION_ADD_EDIT, + LOADING_TASK_GENERATION_STATION_CODE, + LOADING_TASK_STATION_ADD_EDIT, } from '../../../utils/constants'; import { ENV } from '../../../utils/env'; import { - alterStationValuesToFitCategories, - getStationCategoryFromDetail, - splitURL, + alterStationValuesToFitCategories, + getStationCategoryFromDetail, + splitURL, } from '../../../utils/station-utils'; import ConfirmModal from '../../components/ConfirmModal'; import AddEditStationFormSectionTitle from '../addEditStation/AddEditStationFormSectionTitle'; @@ -351,9 +351,9 @@ const AddEditStationForm = ({ stationDetail, formAction }: Props) => { } }; - const redirect = (stCode: string) => { + const redirect = (stCode: string, status: ConfigurationStatus) => { if (userIsPagopaOperator) { - history.push(generatePath(ROUTES.STATION_DETAIL, { stationId: stCode })); + history.push(generatePath(ROUTES.STATION_DETAIL, { stationId: stCode, status })); } else { history.push(ROUTES.STATIONS); } @@ -370,47 +370,34 @@ const AddEditStationForm = ({ stationDetail, formAction }: Props) => { try { const validationUrl = `${window.location.origin}${generatePath(ROUTES.STATION_DETAIL, { stationId: formik.values.stationCode, + status: ConfigurationStatus.TO_BE_VALIDATED, })}`; - // eslint-disable-next-line functional/immutable-data - values.validationUrl = validationUrl; if (formAction === StationFormAction.Create || formAction === StationFormAction.Duplicate) { - await createWrapperStation(values); - redirect(stationCode4Redirect); + await createWrapperStation({ station: values, validationUrl }); + redirect(stationCode4Redirect, ConfigurationStatus.TO_BE_VALIDATED); } if (formAction === StationFormAction.Edit) { - switch (stationDetail?.wrapperStatus) { - case WrapperStatusEnum.TO_CHECK: - if (userIsPagopaOperator) { - await createStation(values); - redirect(stationCode4Redirect); - } else { - await updateWrapperStationToCheck(values); - redirect(stationCode4Redirect); - } - break; - case WrapperStatusEnum.APPROVED: - case WrapperStatusEnum.TO_CHECK_UPDATE: - if (userIsPagopaOperator) { - await updateStation(values, stationCode); - redirect(stationCode4Redirect); - } else { - await updateWrapperStationToCheckUpdate(values); - redirect(stationCode4Redirect); - } - break; - case WrapperStatusEnum.TO_FIX: - await updateWrapperStationToCheck(values); - redirect(stationCode4Redirect); - break; - case WrapperStatusEnum.TO_FIX_UPDATE: - await updateWrapperStationToCheckUpdate(values); - redirect(stationCode4Redirect); - break; - default: - redirect(stationCode4Redirect); - break; + if (userIsPagopaOperator) { + if ( + stationDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK || + stationDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX + ) { + await createStation(values); + } else if ( + stationDetail?.wrapperStatus === WrapperStatusEnum.APPROVED || + stationDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE || + stationDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX_UPDATE + ) { + await updateStation({ stationCode, station: values }); + } else { + throw new Error('Wrong channel wrapper status'); + } + redirect(stationCode4Redirect, ConfigurationStatus.ACTIVE); + } else { + await updateWrapperStationDetails({ stationCode, station: values, validationUrl }); + redirect(stationCode4Redirect, ConfigurationStatus.TO_BE_VALIDATED); } } } catch (reason) { @@ -1140,7 +1127,13 @@ const AddEditStationForm = ({ stationDetail, formAction }: Props) => { onClick={() => history.push( formAction === StationFormAction.Edit - ? generatePath(ROUTES.STATION_DETAIL, { stationId: stationDetail?.stationCode }) + ? generatePath(ROUTES.STATION_DETAIL, { + stationId: stationDetail?.stationCode, + status: + stationDetail?.wrapperStatus === WrapperStatusEnum.APPROVED + ? ConfigurationStatus.ACTIVE + : ConfigurationStatus.TO_BE_VALIDATED, + }) : ROUTES.STATIONS ) } diff --git a/src/pages/stations/addEditStation/AddEditStationPage.tsx b/src/pages/stations/addEditStation/AddEditStationPage.tsx index c2202270e..c86996010 100644 --- a/src/pages/stations/addEditStation/AddEditStationPage.tsx +++ b/src/pages/stations/addEditStation/AddEditStationPage.tsx @@ -9,7 +9,7 @@ import ROUTES from '../../../routes'; import {StationDetailResource} from '../../../api/generated/portal/StationDetailResource'; import {LOADING_TASK_STATION_ADD_EDIT} from '../../../utils/constants'; import {getStationDetail} from '../../../services/stationService'; -import {StationFormAction} from '../../../model/Station'; +import {ConfigurationStatus, StationFormAction} from '../../../model/Station'; import {useAppSelector} from '../../../redux/hooks'; import {partiesSelectors} from '../../../redux/slices/partiesSlice'; import AddEditStationForm from './AddEditStationForm'; @@ -28,7 +28,7 @@ const AddEditStationPage = () => { useEffect(() => { if (formAction !== StationFormAction.Create) { setLoading(true); - getStationDetail(stationId) + getStationDetail({stationCode: stationId, status: ConfigurationStatus.TO_BE_VALIDATED}) .then((response) => { setStationDetail(response); }) diff --git a/src/pages/stations/addEditStation/__tests__/AddEditStationForm.test.tsx b/src/pages/stations/addEditStation/__tests__/AddEditStationForm.test.tsx index 11dd588f2..2f5a37664 100644 --- a/src/pages/stations/addEditStation/__tests__/AddEditStationForm.test.tsx +++ b/src/pages/stations/addEditStation/__tests__/AddEditStationForm.test.tsx @@ -21,7 +21,28 @@ import {mockedFullStation, mockedStationCode} from '../../../../services/__mocks jest.mock('../../../components/commonFunctions'); +let updateWrapperStationDetailsSpy: jest.SpyInstance; +let createWrapperStationSpy: jest.SpyInstance; +let updateStationSpy: jest.SpyInstance; +let createStationSpy: jest.SpyInstance; + beforeEach(() => { + updateWrapperStationDetailsSpy = jest.spyOn( + stationService, + 'updateWrapperStationDetails' + ); + createWrapperStationSpy = jest.spyOn( + stationService, + 'createWrapperStation' + ); + updateStationSpy = jest.spyOn( + stationService, + 'updateStation' + ); + createStationSpy = jest.spyOn( + stationService, + 'createStation' + ); jest.spyOn(console, 'error').mockImplementation(() => { }); jest.spyOn(console, 'warn').mockImplementation(() => { @@ -138,11 +159,7 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType @@ -310,8 +326,8 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType { @@ -328,8 +344,7 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType @@ -365,8 +380,8 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType { @@ -383,8 +398,6 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType @@ -410,8 +423,8 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType { @@ -428,8 +441,6 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType @@ -465,8 +476,8 @@ describe('AddEditStationForm ', (injectedHistory?: ReturnType { diff --git a/src/pages/stations/detail/StationDetailPage.tsx b/src/pages/stations/detail/StationDetailPage.tsx index 9d5c5d3b0..1a95a7537 100644 --- a/src/pages/stations/detail/StationDetailPage.tsx +++ b/src/pages/stations/detail/StationDetailPage.tsx @@ -1,17 +1,18 @@ -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import {useEffect, useState} from 'react'; -import {useParams} from 'react-router-dom'; -import {useTranslation} from 'react-i18next'; -import {getECListByStationCode, getStationDetail} from '../../../services/stationService'; -import {LOADING_TASK_STATION_DETAILS_WRAPPER} from '../../../utils/constants'; -import {useAppSelector} from '../../../redux/hooks'; -import {partiesSelectors} from '../../../redux/slices/partiesSlice'; -import {StationDetailResource} from '../../../api/generated/portal/StationDetailResource'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router-dom'; +import { StationDetailResource } from '../../../api/generated/portal/StationDetailResource'; +import { ConfigurationStatus } from '../../../model/Station'; +import { useAppSelector } from '../../../redux/hooks'; +import { partiesSelectors } from '../../../redux/slices/partiesSlice'; +import { getECListByStationCode, getStationDetail } from '../../../services/stationService'; +import { LOADING_TASK_STATION_DETAILS_WRAPPER } from '../../../utils/constants'; import StationDetails from './components/StationDetails'; const StationDetailPage = () => { const {t} = useTranslation(); - const {stationId} = useParams<{ stationId: string }>(); + const {stationId, status} = useParams<{ stationId: string; status: ConfigurationStatus }>(); const [stationDetail, setStationDetail] = useState(); const [ecAssociatedNumber, setECAssociatedNumber] = useState(0); const addError = useErrorDispatcher(); @@ -29,7 +30,7 @@ const StationDetailPage = () => { } } - Promise.all([getStationDetail(stationId), getEcListByStationCode()]) + Promise.all([getStationDetail({stationCode: stationId, status}), getEcListByStationCode()]) .then(([stationDetail, ecList]) => { setStationDetail(stationDetail); setECAssociatedNumber(ecList?.page_info?.total_items ?? 0); diff --git a/src/pages/stations/detail/components/DetailButtonsStation.tsx b/src/pages/stations/detail/components/DetailButtonsStation.tsx index cf44b3684..2c3ef5dc8 100644 --- a/src/pages/stations/detail/components/DetailButtonsStation.tsx +++ b/src/pages/stations/detail/components/DetailButtonsStation.tsx @@ -1,237 +1,244 @@ -import {useState} from 'react'; -import {Box, Button, Stack, TextField, Typography} from '@mui/material'; -import {generatePath, Link} from 'react-router-dom'; -import {useErrorDispatcher, useLoading} from '@pagopa/selfcare-common-frontend'; -import { - ContentCopy, - Delete, - MiscellaneousServices, - ModeEdit, -} from '@mui/icons-material'; -import {useTranslation} from 'react-i18next'; +import { useState } from 'react'; +import { Box, Button, Stack, TextField, Typography } from '@mui/material'; +import { generatePath, Link } from 'react-router-dom'; +import { useErrorDispatcher, useLoading } from '@pagopa/selfcare-common-frontend'; +import { ContentCopy, Delete, MiscellaneousServices, ModeEdit } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; import ROUTES from '../../../../routes'; -import {StationFormAction} from '../../../../model/Station'; +import { StationFormAction } from '../../../../model/Station'; import { - StationDetailResource, - WrapperStatusEnum, + StationDetailResource, + WrapperStatusEnum, } from '../../../../api/generated/portal/StationDetailResource'; -import {useUserRole} from '../../../../hooks/useUserRole'; -import {updateWrapperStationWithOperatorReview} from '../../../../services/stationService'; -import {LOADING_TASK_STATION_DETAILS_REQUEST_EDIT} from '../../../../utils/constants'; +import { useUserRole } from '../../../../hooks/useUserRole'; +import { updateWrapperStationWithOperatorReview } from '../../../../services/stationService'; +import { LOADING_TASK_STATION_DETAILS_REQUEST_EDIT } from '../../../../utils/constants'; import GenericModal from '../../../../components/Form/GenericModal'; const ModalContent = ({ - setShowModal, - stationDetail, - setStationDetail, - }: { - setShowModal: (value: boolean) => void; + setShowModal, + stationDetail, + setStationDetail, +}: { + setShowModal: (value: boolean) => void; } & Props) => { - const {t} = useTranslation(); + const { t } = useTranslation(); - const addError = useErrorDispatcher(); - const setLoading = useLoading(LOADING_TASK_STATION_DETAILS_REQUEST_EDIT); + const addError = useErrorDispatcher(); + const setLoading = useLoading(LOADING_TASK_STATION_DETAILS_REQUEST_EDIT); - const [input, setInput] = useState(stationDetail?.note ?? ''); + const [input, setInput] = useState(stationDetail?.note ?? ''); - const sendEditRequest = () => { - setLoading(true); - updateWrapperStationWithOperatorReview({ - stationCode: stationDetail?.stationCode ?? '', - ciTaxCode: stationDetail?.brokerCode ?? '', - note: input, + const sendEditRequest = () => { + setLoading(true); + updateWrapperStationWithOperatorReview({ + stationCode: stationDetail?.stationCode ?? '', + ciTaxCode: stationDetail?.brokerCode ?? '', + note: input, + }) + .then((data: StationDetailResource) => { + setStationDetail(data); + }) + .catch((reason) => + addError({ + id: 'PUT_STATION_DETAILS_REQUEST_EDIT', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while getting updating the station with operator's note`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t('stationDetailPageValidation.modal.error'), + component: 'Toast', }) - .then((data: StationDetailResource) => { - setStationDetail(data); - }) - .catch((reason) => - addError({ - id: 'PUT_STATION_DETAILS_REQUEST_EDIT', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while getting updating the station with operator's note`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t('stationDetailPageValidation.modal.error'), - component: 'Toast', - }) - ) - .finally(() => { - setShowModal(false); - setLoading(false); - }); - }; - return ( - <> - {t('stationDetailPageValidation.modal.title')} - - {t('stationDetailPageValidation.modal.subtitle')} - - setInput(e.target.value)} - helperText={t('stationDetailPageValidation.modal.helperText')} - inputProps={{ - 'data-testid': 'requestInput', - maxLength: 200, - }} - /> - - - - - - ); + ) + .finally(() => { + setShowModal(false); + setLoading(false); + }); + }; + return ( + <> + {t('stationDetailPageValidation.modal.title')} + + {t('stationDetailPageValidation.modal.subtitle')} + + setInput(e.target.value)} + helperText={t('stationDetailPageValidation.modal.helperText')} + inputProps={{ + 'data-testid': 'requestInput', + maxLength: 200, + }} + /> + + + + + + ); }; type Props = { - stationDetail: StationDetailResource; - setStationDetail: (value: any) => void; + stationDetail: StationDetailResource; + setStationDetail: (value: any) => void; }; -const DetailButtonsStation = ({stationDetail, setStationDetail}: Props) => { - const {t} = useTranslation(); - const {userIsPagopaOperator} = useUserRole(); +const DetailButtonsStation = ({ stationDetail, setStationDetail }: Props) => { + const { t } = useTranslation(); + const { userIsPagopaOperator } = useUserRole(); - const status = stationDetail?.wrapperStatus; - const stationCode = stationDetail?.stationCode; + const status = stationDetail?.wrapperStatus; + const stationCode = stationDetail?.stationCode; + const disableOnPendingUpdate = + stationDetail?.wrapperStatus === WrapperStatusEnum.APPROVED && stationDetail?.pendingUpdate; - const [showModal, setShowModal] = useState(false); + const [showModal, setShowModal] = useState(false); - const editPath = () => - generatePath(ROUTES.STATION_EDIT, { - stationId: stationCode, - actionId: StationFormAction.Edit, - }); - - if (userIsPagopaOperator) { - return ( - <> - - {(status === WrapperStatusEnum.TO_CHECK || - status === WrapperStatusEnum.TO_CHECK_UPDATE) && ( - - )} - - - {showModal && ( - ( - - )} - /> - )} - - ); - } + const editPath = () => + generatePath(ROUTES.STATION_EDIT, { + stationId: stationCode, + actionId: StationFormAction.Edit, + }); + if (userIsPagopaOperator) { return ( + <> - {status === WrapperStatusEnum.APPROVED ? ( - <> - - - - - - ) : ( - + {(status === WrapperStatusEnum.TO_CHECK || + status === WrapperStatusEnum.TO_CHECK_UPDATE) && ( + + )} + + {showModal && ( + ( + + )} + /> + )} + ); + } + + return ( + + {status === WrapperStatusEnum.APPROVED ? ( + <> + + + + + + ) : ( + + )} + + ); }; export default DetailButtonsStation; diff --git a/src/pages/stations/detail/components/StationDetails.tsx b/src/pages/stations/detail/components/StationDetails.tsx index 564adc425..78981698a 100644 --- a/src/pages/stations/detail/components/StationDetails.tsx +++ b/src/pages/stations/detail/components/StationDetails.tsx @@ -1,69 +1,24 @@ -import { Alert, Box, Divider, Grid, IconButton } from '@mui/material'; +import { ArrowBack, VisibilityOff } from '@mui/icons-material'; +import VisibilityIcon from '@mui/icons-material/Visibility'; +import { Box, Divider, Grid, IconButton } from '@mui/material'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; -import { useTranslation } from 'react-i18next'; import { ButtonNaked } from '@pagopa/mui-italia'; -import { useHistory, useParams } from 'react-router-dom'; import { useState } from 'react'; -import { ArrowBack, VisibilityOff } from '@mui/icons-material'; -import VisibilityIcon from '@mui/icons-material/Visibility'; +import { useTranslation } from 'react-i18next'; +import { useHistory, useParams } from 'react-router-dom'; import { StationDetailResource, WrapperStatusEnum, } from '../../../../api/generated/portal/StationDetailResource'; -import { StatusChip } from '../../../../components/StatusChip'; +import GetAlert from '../../../../components/WrapperCommon/GetAlert'; +import { StatusChip } from '../../../../components/WrapperCommon/StatusChip'; +import { useUserRole } from '../../../../hooks/useUserRole'; import { IProxyConfig, ProxyConfigs } from '../../../../model/Station'; import ROUTES from '../../../../routes'; import { ENV } from '../../../../utils/env'; -import { useUserRole } from '../../../../hooks/useUserRole'; import DetailButtonsStation from './DetailButtonsStation'; -// eslint-disable-next-line sonarjs/cognitive-complexity -const GetAlert = ({ stationDetail }: { stationDetail?: StationDetailResource }) => { - const { t } = useTranslation(); - const { userIsPagopaOperator } = useUserRole(); - - if (stationDetail?.wrapperStatus !== WrapperStatusEnum.APPROVED) { - const isToBeValidated = - stationDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK || - stationDetail?.wrapperStatus === WrapperStatusEnum.TO_CHECK_UPDATE; - const isToBeFixed = - stationDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX || - stationDetail?.wrapperStatus === WrapperStatusEnum.TO_FIX_UPDATE; - - const userHasToTakeAction = - (isToBeValidated && userIsPagopaOperator) || (isToBeFixed && !userIsPagopaOperator); - return ( - <> - {(userIsPagopaOperator || userHasToTakeAction) && ( - - - {isToBeFixed && ( - - {t('stationDetailPageValidation.alert.toFixTitle')} - - )} - - {isToBeFixed && stationDetail?.note?.trim() - ? stationDetail.note - : t( - `stationDetailPageValidation.alert.${ - isToBeValidated ? 'toCheckMessage' : 'toFixMessage' - }` - )} - - - - )} - - ); - } - return null; -}; type Props = { stationDetail?: StationDetailResource; setStationDetail: (value: any) => void; @@ -120,7 +75,12 @@ Props) => { )} - + { > - + {t('stationDetailPageValidation.configuration.title')} diff --git a/src/pages/stations/list/StationsTableColumns.tsx b/src/pages/stations/list/StationsTableColumns.tsx index e715f2ebb..1586a34eb 100644 --- a/src/pages/stations/list/StationsTableColumns.tsx +++ b/src/pages/stations/list/StationsTableColumns.tsx @@ -1,12 +1,12 @@ -import {GridColDef} from '@mui/x-data-grid'; -import {TFunction} from 'react-i18next'; -import {generatePath} from 'react-router-dom'; +import { GridColDef } from '@mui/x-data-grid'; +import { TFunction } from 'react-i18next'; +import { generatePath } from 'react-router-dom'; +import { StatusEnum } from '../../../api/generated/portal/StationDetailsDto'; import GridLinkAction from '../../../components/Table/GridLinkAction'; -import {FormAction} from '../../../model/Station'; +import { renderCell, showCustomHeader } from '../../../components/Table/TableUtils'; +import { ConfigurationStatus, FormAction } from '../../../model/Station'; import ROUTES from '../../../routes'; -import {StatusEnum} from '../../../api/generated/portal/StationDetailsDto'; -import {renderCell, showCustomHeader} from '../../../components/Table/TableUtils'; -import {StatusChip} from '../../../components/StatusChip'; +import { StatusChip } from '../../../components/WrapperCommon/StatusChip'; export function buildColumnDefs( t: TFunction<'translation', undefined>, @@ -131,24 +131,25 @@ export const getRowActions = (params: any, userIsPagopaOperator: boolean) => { const stationCode = params.row.stationCode; if (params.row.wrapperStatus === StatusEnum.APPROVED) { if (userIsPagopaOperator) { - return [manageStationAction(stationCode), manageStationECAction(stationCode)]; + return [manageStationAction(stationCode, ConfigurationStatus.ACTIVE), manageStationECAction(stationCode)]; } return [ - manageStationAction(stationCode), + manageStationAction(stationCode, ConfigurationStatus.ACTIVE), manageStationECAction(stationCode), duplicateStationAction(stationCode), ]; } else { - return [manageStationAction(stationCode), editStationAction(stationCode)]; + return [manageStationAction(stationCode, ConfigurationStatus.TO_BE_VALIDATED), editStationAction(stationCode)]; } }; -export const manageStationAction = (stationCode: string) => ( +export const manageStationAction = (stationCode: string, status: ConfigurationStatus) => ( diff --git a/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx b/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx index 3322b0bb2..5b6ff14cc 100644 --- a/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx +++ b/src/pages/stations/list/__tests__/StationsTableColumns.test.tsx @@ -10,6 +10,7 @@ import { } from '../StationsTableColumns'; import {WrapperStatusEnum} from '../../../../api/generated/portal/StationDetailResource'; import {mockedFullStation} from '../../../../services/__mocks__/stationService'; +import { ConfigurationStatus } from '../../../../model/Station'; beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(() => { @@ -262,26 +263,26 @@ describe('', () => { // Station approved, not an operator expect(getRowActions(paramsApproved, false)).toEqual([ - manageStationAction(mockedFullStation.stationCode), + manageStationAction(mockedFullStation.stationCode, ConfigurationStatus.ACTIVE), manageStationECAction(mockedFullStation.stationCode), duplicateStationAction(mockedFullStation.stationCode), ]); // Station not approved, not an operator expect(getRowActions(paramsToCheck, false)).toEqual([ - manageStationAction(mockedFullStation.stationCode), + manageStationAction(mockedFullStation.stationCode, ConfigurationStatus.TO_BE_VALIDATED), editStationAction(mockedFullStation.stationCode), ]); // Station approved, as operator expect(getRowActions(paramsApproved, true)).toEqual([ - manageStationAction(mockedFullStation.stationCode), + manageStationAction(mockedFullStation.stationCode, ConfigurationStatus.ACTIVE), manageStationECAction(mockedFullStation.stationCode), ]); // Station not approved, as operator expect(getRowActions(paramsToCheck, true)).toEqual([ - manageStationAction(mockedFullStation.stationCode), + manageStationAction(mockedFullStation.stationCode, ConfigurationStatus.TO_BE_VALIDATED), editStationAction(mockedFullStation.stationCode), ]); }); diff --git a/src/routes.tsx b/src/routes.tsx index 5b3ebc5b5..e5276bbb8 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -12,14 +12,14 @@ const ROUTES = { APIKEYS_CREATE: `${BASE_ROUTE}/add-apikey`, CHANNELS: `${BASE_ROUTE}/channels`, - CHANNEL_DETAIL: `${BASE_ROUTE}/channels/:channelId`, + CHANNEL_DETAIL: `${BASE_ROUTE}/channels/detail/:channelId/:status`, CHANNEL_EDIT: `${BASE_ROUTE}/channels/:channelId/:actionId`, CHANNEL_PSP_LIST: `${BASE_ROUTE}/channels/:channelId/psp-list`, CHANNEL_ASSOCIATE_PSP: `${BASE_ROUTE}/channels/:channelId/associate-psp`, CHANNEL_ADD: `${BASE_ROUTE}/channels/add-channel/`, STATIONS: `${BASE_ROUTE}/stations`, - STATION_DETAIL: `${BASE_ROUTE}/stations/:stationId`, + STATION_DETAIL: `${BASE_ROUTE}/stations/detail/:stationId/:status`, STATION_EDIT: `${BASE_ROUTE}/stations/:stationId/:actionId`, STATION_EC_LIST: `${BASE_ROUTE}/stations/:stationId/ec-list`, STATION_ASSOCIATE_EC: `${BASE_ROUTE}/stations/:stationId/associate-ec`, diff --git a/src/services/__tests__/channelService.test.ts b/src/services/__tests__/channelService.test.ts index 5210932d1..faf0b2dcb 100644 --- a/src/services/__tests__/channelService.test.ts +++ b/src/services/__tests__/channelService.test.ts @@ -1,6 +1,5 @@ import { BackofficeApi } from '../../api/BackofficeClient.ts'; import { Redirect_protocolEnum } from '../../api/generated/portal/WrapperChannelDetailsDto.ts'; -import { WrapperChannelDetailsResource } from '../../api/generated/portal/WrapperChannelDetailsResource.ts'; import { ConfigurationStatus } from '../../model/Station.tsx'; import { channelCode } from '../__mocks__/channelService'; import { @@ -16,7 +15,6 @@ import { mockedWfespPlugIn, mockedWrapperChannel, } from '../__mocks__/channelService.ts'; -import { channelWrapperMockedGet } from '../__mocks__/institutionsService.ts'; import { associatePSPtoChannel, createChannel, @@ -28,7 +26,6 @@ import { getChannels, getPSPChannels, getWfespPlugins, - getWrapperEntities, updateChannel, updateWrapperChannelDetails, updateWrapperChannelWithOperatorReview, @@ -46,7 +43,10 @@ describe('ChannelService test mocked', () => { expect(response).toMatchObject(mockedChannels); }); test('Test getChannelDetail', async () => { - const response = await getChannelDetail('channelId'); + const response = await getChannelDetail({ + channelCode: 'channelId', + status: ConfigurationStatus.ACTIVE, + }); expect(response).toMatchObject(mockedChannelDetail('channelId')); }); test('Test getPSPChannels', async () => { @@ -96,10 +96,6 @@ describe('ChannelService test mocked', () => { test('Test dissociatePSPfromChannel', async () => { expect(dissociatePSPfromChannel('channelCode', 'pspTaxCode')).resolves.not.toThrow(); }); - test('Test getWrapperEntities', async () => { - const response = await getWrapperEntities('pspCode'); - expect(response).toMatchObject(channelWrapperMockedGet('pspCode')); - }); test('Test createWrapperChannelDetails', async () => { const response = await createWrapperChannelDetails( { @@ -175,7 +171,9 @@ describe('ChannelService test client', () => { const spyOn = jest .spyOn(BackofficeApi, 'getChannelDetail') .mockReturnValue(new Promise((resolve) => resolve(mockedChannelDetail('channelCode')))); - expect(getChannelDetail('channelId')).resolves.not.toThrow(); + expect( + getChannelDetail({ channelCode: 'channelId', status: ConfigurationStatus.ACTIVE }) + ).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); test('Test getPSPChannels', async () => { @@ -195,9 +193,7 @@ describe('ChannelService test client', () => { test('Test createChannel', async () => { const spyOn = jest .spyOn(BackofficeApi, 'createChannel') - .mockReturnValue( - new Promise((resolve) => resolve(mockedChannel as WrapperChannelDetailsResource)) - ); + .mockReturnValue(new Promise((resolve) => resolve(mockedChannelDetail('channelCode')))); expect( createChannel({ validationUrl: '', @@ -211,9 +207,7 @@ describe('ChannelService test client', () => { test('Test updateChannel', async () => { const spyOn = jest .spyOn(BackofficeApi, 'updateChannel') - .mockReturnValue( - new Promise((resolve) => resolve(mockedChannel as WrapperChannelDetailsResource)) - ); + .mockReturnValue(new Promise((resolve) => resolve(mockedChannelDetail('channelCode')))); expect( updateChannel('channelCode', { validationUrl: '', @@ -256,13 +250,6 @@ describe('ChannelService test client', () => { expect(dissociatePSPfromChannel('channelCode', 'pspTaxCode')).resolves.not.toThrow(); expect(spyOn).toBeCalledTimes(1); }); - test('Test getWrapperEntities', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getWrapperEntities') - .mockReturnValue(new Promise((resolve) => resolve({}))); - expect(getWrapperEntities('pspCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); test('Test createWrapperChannelDetails', async () => { const spyOn = jest .spyOn(BackofficeApi, 'createWrapperChannelDetails') diff --git a/src/services/__tests__/stationService.test.ts b/src/services/__tests__/stationService.test.ts index b518a97d3..b4ac24112 100644 --- a/src/services/__tests__/stationService.test.ts +++ b/src/services/__tests__/stationService.test.ts @@ -15,7 +15,7 @@ import { mockedWrapperStation, stationTestErrorMocked, stationTestMocked, - stationWrapperMockedGet + updateWrapperStation, } from '../__mocks__/stationService'; import { associateEcToStation, @@ -24,274 +24,253 @@ import { dissociateECfromStation, getCreditorInstitutionSegregationCodes, getECListByStationCode, - getStation, getStationAvailableEC, getStationCode, getStationCodeV2, getStationDetail, getStations, - getWrapperStation, testStation, updateStation, - updateWrapperStationToCheck, - updateWrapperStationToCheckUpdate, + updateWrapperStationDetails, updateWrapperStationWithOperatorReview, } from '../stationService'; describe('StationService test mocked', () => { - test('Test createStation', async () => { - const response = await createStation(mockedCreatedStation); - expect(response).toMatchObject(mockedStation); - }); - test('Test getStations', async () => { - const response = await getStations({ - page: 0, - brokerCode: 'brokerCode', - status: ConfigurationStatus.ACTIVE, - stationCode: 'stationCode', - limit: 0, - }); - expect(response).toMatchObject(mockedStations); - }); - test('Test getStation', async () => { - const response = await getStation('stationId'); - expect(response).toMatchObject(mockedFullStation); - }); - test('Test getStationCode', async () => { - const response = await getStationCode('code'); - expect(response).toMatchObject(mockedStationCode); - }); - test('Test getStationCodeV2', async () => { - const response = await getStationCodeV2('code'); - expect(response).toMatchObject(mockedStationCode); - }); - test('Test getECListByStationCode', async () => { - const response = await getECListByStationCode('stationCode', 'ciName', 0); - expect(response).toMatchObject(mockedStationECs); - }); - test('Test dissociateECfromStation', async () => { - const response = await dissociateECfromStation('ecCode', 'stationCode'); - expect(response).toBeUndefined(); - }); - test('Test associateEcToStation', async () => { - const response = await associateEcToStation('ecCode', mockedCreditorInstitutionStationDTO); - expect(response).toMatchObject({stationCode: '123'}); - }); - test('Test getStationAvailableEC', async () => { - const response = await getStationAvailableEC(); - expect(response).toMatchObject(mockedStationAvailableEC); - }); - test('Test createWrapperStation', async () => { - const response = await createWrapperStation(mockedWrapperStation); - expect(response).toMatchObject(mockedWrapperStation); - }); - test('Test getWrapperStation', async () => { - const response = await getWrapperStation('ecCode'); - expect(response).toMatchObject(stationWrapperMockedGet('ecCode')); - }); - test('Test updateWrapperStationToCheck', async () => { - const response = await updateWrapperStationToCheck(mockedStationDetailsDTO); - expect(response).toMatchObject(mockedWrapperStation); - }); - test('Test updateWrapperStationToCheckUpdate', async () => { - const response = await updateWrapperStationToCheckUpdate(mockedStationDetailsDTO); - expect(response).toMatchObject(mockedWrapperStation); - }); - test('Test updateWrapperStationWithOperatorReview', async () => { - const response = await updateWrapperStationWithOperatorReview({ - stationCode: 'stationCode', - ciTaxCode: 'ciTaxCode', - note: 'note', - }); - expect(response).toMatchObject(mockedFullStation); - }); - test('Test updateStation', async () => { - const response = await updateStation(mockedStationDetailsDTO, 'stationCode'); - expect(response).toMatchObject(mockedFullStation); - }); - test('Test getStationDetail', async () => { - const response = await getStationDetail('stationId'); - expect(response).toMatchObject(mockedFullStation); - }); - test('Test getCreditorInstitutionSegregationcodes', async () => { - const response = await getCreditorInstitutionSegregationCodes('ecCode', 'targetCICode'); - expect(response).toMatchObject(mockedSegregationCodeList); - }); - test('Test testStation', async () => { - const response = await testStation( - 'http', - 'localhost', - 8080, - '/success', - TestStationTypeEnum.PA_VERIFY - ); - expect(response).toMatchObject(stationTestMocked); - }); - test('Test testStation error', async () => { - const response = await testStation( - 'http', - 'localhost', - 8080, - '/error', - TestStationTypeEnum.PA_VERIFY - ); - expect(response).toMatchObject(stationTestErrorMocked); - }); + test('Test createStation', async () => { + const response = await createStation(mockedCreatedStation); + expect(response).toMatchObject(mockedStation); + }); + test('Test getStations', async () => { + const response = await getStations({ + page: 0, + brokerCode: 'brokerCode', + status: ConfigurationStatus.ACTIVE, + stationCode: 'stationCode', + limit: 0, + }); + expect(response).toMatchObject(mockedStations); + }); + test('Test getStationCode', async () => { + const response = await getStationCode('code'); + expect(response).toMatchObject(mockedStationCode); + }); + test('Test getStationCodeV2', async () => { + const response = await getStationCodeV2('code'); + expect(response).toMatchObject(mockedStationCode); + }); + test('Test getECListByStationCode', async () => { + const response = await getECListByStationCode('stationCode', 'ciName', 0); + expect(response).toMatchObject(mockedStationECs); + }); + test('Test dissociateECfromStation', async () => { + const response = await dissociateECfromStation('ecCode', 'stationCode'); + expect(response).toBeUndefined(); + }); + test('Test associateEcToStation', async () => { + const response = await associateEcToStation('ecCode', mockedCreditorInstitutionStationDTO); + expect(response).toMatchObject({ stationCode: '123' }); + }); + test('Test getStationAvailableEC', async () => { + const response = await getStationAvailableEC(); + expect(response).toMatchObject(mockedStationAvailableEC); + }); + test('Test createWrapperStation', async () => { + const response = await createWrapperStation({ + station: mockedWrapperStation, + validationUrl: 'url', + }); + expect(response).toMatchObject(mockedWrapperStation); + }); + test('Test updateWrapperStation', async () => { + const response = await updateWrapperStation(mockedStationDetailsDTO); + expect(response).toMatchObject(mockedWrapperStation); + }); + test('Test updateWrapperStationWithOperatorReview', async () => { + const response = await updateWrapperStationWithOperatorReview({ + stationCode: 'stationCode', + ciTaxCode: 'ciTaxCode', + note: 'note', + }); + expect(response).toMatchObject(mockedFullStation); + }); + test('Test updateStation', async () => { + const response = await updateStation({ + station: mockedStationDetailsDTO, + stationCode: 'stationCode', + }); + expect(response).toMatchObject(mockedFullStation); + }); + test('Test getStationDetail', async () => { + const response = await getStationDetail({ + stationCode: 'stationId', + status: ConfigurationStatus.ACTIVE, + }); + expect(response).toMatchObject(mockedFullStation); + }); + test('Test getCreditorInstitutionSegregationcodes', async () => { + const response = await getCreditorInstitutionSegregationCodes('ecCode', 'targetCICode'); + expect(response).toMatchObject(mockedSegregationCodeList); + }); + test('Test testStation', async () => { + const response = await testStation( + 'http', + 'localhost', + 8080, + '/success', + TestStationTypeEnum.PA_VERIFY + ); + expect(response).toMatchObject(stationTestMocked); + }); + test('Test testStation error', async () => { + const response = await testStation( + 'http', + 'localhost', + 8080, + '/error', + TestStationTypeEnum.PA_VERIFY + ); + expect(response).toMatchObject(stationTestErrorMocked); + }); }); describe('StationService test', () => { - const OLD_ENV = process.env; - beforeEach(() => { - jest.resetModules(); - process.env = {...OLD_ENV, REACT_APP_API_MOCK_BACKOFFICE: 'false'}; - }); + const OLD_ENV = process.env; + beforeEach(() => { + jest.resetModules(); + process.env = { ...OLD_ENV, REACT_APP_API_MOCK_BACKOFFICE: 'false' }; + }); - afterAll(() => { - process.env = OLD_ENV; - }); + afterAll(() => { + process.env = OLD_ENV; + }); - test('Test createStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'createStation') - .mockReturnValue(new Promise((resolve) => resolve(mockedStation))); - expect(createStation(mockedCreatedStation)).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getStations', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getStations') - .mockReturnValue(new Promise((resolve) => resolve(mockedStations))); - expect( - getStations({ - page: 0, - brokerCode: 'brokerCode', - status: ConfigurationStatus.ACTIVE, - stationCode: 'stationCode', - limit: 0, - }) - ).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getStation') - .mockReturnValue(new Promise((resolve) => resolve(mockedFullStation))); - expect(getStation('stationId')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getStationCode', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getStationCode') - .mockReturnValue(new Promise((resolve) => resolve(mockedStationCode))); - expect(getStationCode('code')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getStationCodeV2', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getStationCodeV2') - .mockReturnValue(new Promise((resolve) => resolve(mockedStationCode))); - expect(getStationCodeV2('code')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getECListByStationCode', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getECListByStationCode') - .mockReturnValue(new Promise((resolve) => resolve(mockedStationECs))); - expect(getECListByStationCode('stationCode', 'ciName', 0)).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test dissociateECfromStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'dissociateECfromStation') - .mockReturnValue(new Promise((resolve) => resolve())); - expect(dissociateECfromStation('ecCode', 'stationCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test associateEcToStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'associateEcToStation') - .mockReturnValue(new Promise((resolve) => resolve({stationCode: '123'}))); - expect( - associateEcToStation('ecCode', mockedCreditorInstitutionStationDTO) - ).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getStationAvailableEC', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getStationAvailableEc') - .mockReturnValue(new Promise((resolve) => resolve(mockedStationAvailableEC))); - expect(getStationAvailableEC()).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test createWrapperStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'createWrapperStation') - .mockReturnValue(new Promise((resolve) => resolve(mockedWrapperStation))); - expect(createWrapperStation(mockedWrapperStation)).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getWrapperStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getWrapperEntitiesStation') - .mockReturnValue(new Promise((resolve) => resolve(stationWrapperMockedGet('ecCode')))); - expect(getWrapperStation('ecCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateWrapperStationToCheck', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'updateWrapperStationToCheck') - .mockReturnValue(new Promise((resolve) => resolve(mockedWrapperStation))); - expect(updateWrapperStationToCheck(mockedStationDetailsDTO)).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateWrapperStationToCheckUpdate', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'updateWrapperStationToCheckUpdate') - .mockReturnValue(new Promise((resolve) => resolve(mockedWrapperStation))); - expect(updateWrapperStationToCheckUpdate(mockedStationDetailsDTO)).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateWrapperStationWithOperatorReview', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'updateWrapperStationWithOperatorReview') - .mockReturnValue(new Promise((resolve) => resolve(mockedFullStation))); - expect( - updateWrapperStationWithOperatorReview({ - stationCode: 'stationCode', - ciTaxCode: 'ciTaxCode', - note: 'note', - }) - ).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test updateStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'updateStation') - .mockReturnValue(new Promise((resolve) => resolve(mockedFullStation))); - expect(updateStation(mockedStationDetailsDTO, 'stationCode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getStationDetail', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getStationDetail') - .mockReturnValue(new Promise((resolve) => resolve(mockedFullStation))); - expect(getStationDetail('stationId')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test getCreditorInstitutionSegregationcodes', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'getCreditorInstitutionSegregationCodes') - .mockReturnValue(new Promise((resolve) => resolve(mockedSegregationCodeList))); - expect(getCreditorInstitutionSegregationCodes('ecCode', 'targetCICode')).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); - test('Test testStation', async () => { - const spyOn = jest - .spyOn(BackofficeApi, 'testStation') - .mockReturnValue(new Promise((resolve) => resolve(stationTestMocked))); - expect( - testStation('http', 'localhost', 8080, '/success', TestStationTypeEnum.PA_VERIFY) - ).resolves.not.toThrow(); - expect(spyOn).toBeCalledTimes(1); - }); + test('Test createStation', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'createStation') + .mockReturnValue(new Promise((resolve) => resolve(mockedStation))); + expect(createStation(mockedCreatedStation)).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getStations', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getStations') + .mockReturnValue(new Promise((resolve) => resolve(mockedStations))); + expect( + getStations({ + page: 0, + brokerCode: 'brokerCode', + status: ConfigurationStatus.ACTIVE, + stationCode: 'stationCode', + limit: 0, + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getStationCode', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getStationCode') + .mockReturnValue(new Promise((resolve) => resolve(mockedStationCode))); + expect(getStationCode('code')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getStationCodeV2', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getStationCodeV2') + .mockReturnValue(new Promise((resolve) => resolve(mockedStationCode))); + expect(getStationCodeV2('code')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getECListByStationCode', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getECListByStationCode') + .mockReturnValue(new Promise((resolve) => resolve(mockedStationECs))); + expect(getECListByStationCode('stationCode', 'ciName', 0)).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test dissociateECfromStation', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'dissociateECfromStation') + .mockReturnValue(new Promise((resolve) => resolve())); + expect(dissociateECfromStation('ecCode', 'stationCode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test associateEcToStation', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'associateEcToStation') + .mockReturnValue(new Promise((resolve) => resolve({ stationCode: '123' }))); + expect( + associateEcToStation('ecCode', mockedCreditorInstitutionStationDTO) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getStationAvailableEC', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getStationAvailableEc') + .mockReturnValue(new Promise((resolve) => resolve(mockedStationAvailableEC))); + expect(getStationAvailableEC()).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test createWrapperStation', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'createWrapperStation') + .mockReturnValue(new Promise((resolve) => resolve(mockedWrapperStation))); + expect( + createWrapperStation({ station: mockedWrapperStation, validationUrl: 'url' }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test updateWrapperStation', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'updateWrapperStationDetails') + .mockReturnValue(new Promise((resolve) => resolve(mockedWrapperStation))); + expect(updateWrapperStationDetails({stationCode: 'station-code', station: mockedStationDetailsDTO, validationUrl: 'url'})).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test updateWrapperStationWithOperatorReview', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'updateWrapperStationWithOperatorReview') + .mockReturnValue(new Promise((resolve) => resolve(mockedFullStation))); + expect( + updateWrapperStationWithOperatorReview({ + stationCode: 'stationCode', + ciTaxCode: 'ciTaxCode', + note: 'note', + }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test updateStation', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'updateStation') + .mockReturnValue(new Promise((resolve) => resolve(mockedFullStation))); + expect( + updateStation({ station: mockedStationDetailsDTO, stationCode: 'stationCode' }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getStationDetail', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getStationDetails') + .mockReturnValue(new Promise((resolve) => resolve(mockedFullStation))); + expect( + getStationDetail({ stationCode: 'stationId', status: ConfigurationStatus.ACTIVE }) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test getCreditorInstitutionSegregationcodes', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'getCreditorInstitutionSegregationCodes') + .mockReturnValue(new Promise((resolve) => resolve(mockedSegregationCodeList))); + expect(getCreditorInstitutionSegregationCodes('ecCode', 'targetCICode')).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); + test('Test testStation', async () => { + const spyOn = jest + .spyOn(BackofficeApi, 'testStation') + .mockReturnValue(new Promise((resolve) => resolve(stationTestMocked))); + expect( + testStation('http', 'localhost', 8080, '/success', TestStationTypeEnum.PA_VERIFY) + ).resolves.not.toThrow(); + expect(spyOn).toBeCalledTimes(1); + }); }); diff --git a/src/services/channelService.ts b/src/services/channelService.ts index 39cd4905d..30690b117 100644 --- a/src/services/channelService.ts +++ b/src/services/channelService.ts @@ -23,11 +23,10 @@ import { getChannelPSPs as getChannelPSPsMocked, getChannels as getChannelsMocked, getPSPChannels as getPSPChannelsMocked, - getWrapperChannel, getWfespPlugins as mockedGetWfespPlugins, updateChannel as updateChannelMocked, updateWrapperChannel, - updateWrapperChannelWithOperatorReview as updateWrapperChannelWithOperatorReviewMocked + updateWrapperChannelWithOperatorReview as updateWrapperChannelWithOperatorReviewMocked, } from './__mocks__/channelService'; // /channels endpoint @@ -55,12 +54,18 @@ export const getChannels = ({ } }; -export const getChannelDetail = (channelcode: string): Promise => { +export const getChannelDetail = ({ + channelCode, + status, +}: { + channelCode: string; + status: ConfigurationStatus; +}): Promise => { /* istanbul ignore if */ if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getChannelDetailMocked(channelcode); + return getChannelDetailMocked(channelCode); } else { - return BackofficeApi.getChannelDetail(channelcode).then((resources) => resources); + return BackofficeApi.getChannelDetail({ channelCode, status }).then((resources) => resources); } }; @@ -156,14 +161,6 @@ export const dissociatePSPfromChannel = ( } }; -export const getWrapperEntities = (pspCode: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getWrapperChannel(pspCode); - } else { - return BackofficeApi.getWrapperEntities(pspCode).then((resources) => resources); - } -}; - export const createWrapperChannelDetails = ( channel: WrapperChannelDetailsDto, validationUrl: string diff --git a/src/services/stationService.ts b/src/services/stationService.ts index f5d1eedf8..64cc0a803 100644 --- a/src/services/stationService.ts +++ b/src/services/stationService.ts @@ -15,22 +15,21 @@ import { WrapperStationDetailsDto } from '../api/generated/portal/WrapperStation import { WrapperStationsResource } from '../api/generated/portal/WrapperStationsResource'; import { ConfigurationStatus, StationOnCreation } from '../model/Station'; import { - updateStation as UpdateStationMocked, - associateEcToStation as associateEcToStationMocked, - createStationMocked, - createWrapperStation as createStationWrap, - dissociateECfromStation as dissociateECfromStationMocked, - getCreditorInstitutionSegregationcodes as getCreditorInstitutionSegregationcodesMocked, - getECListByStationCode as getECListByStationCodeMocked, - getStationAvailableEC as getStationAvailableECMocked, - getStationCodeMocked, - getStationCodeV2Mocked, - getStationDetail as getStationDetailMock, - getWrapperStation as getStationWrap, - getStations as getStationsMocked, - testStation as testStationMocked, - updateWrapperStation as updateStationWrap, - updateWrapperStationByOpt as updateStationWrapByOpt + updateStation as UpdateStationMocked, + associateEcToStation as associateEcToStationMocked, + createStationMocked, + createWrapperStation as createStationWrap, + dissociateECfromStation as dissociateECfromStationMocked, + getCreditorInstitutionSegregationcodes as getCreditorInstitutionSegregationcodesMocked, + getECListByStationCode as getECListByStationCodeMocked, + getStationAvailableEC as getStationAvailableECMocked, + getStationCodeMocked, + getStationCodeV2Mocked, + getStationDetail as getStationDetailMock, + getStations as getStationsMocked, + testStation as testStationMocked, + updateWrapperStation as updateStationWrap, + updateWrapperStationByOpt as updateStationWrapByOpt, } from '../services/__mocks__/stationService'; export const createStation = (station: StationOnCreation): Promise => { @@ -65,13 +64,6 @@ export const getStations = ({ }).then((resource) => resource); }; -export const getStation = (stationId: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationDetail(stationId); - } - return BackofficeApi.getStation(stationId).then((resource) => resource); -}; - export const getStationCode = (code: string): Promise => { if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { return getStationCodeMocked(code); @@ -134,44 +126,38 @@ export const getStationAvailableEC = ( } }; -export const createWrapperStation = ( - station: WrapperStationDetailsDto -): Promise => { +export const createWrapperStation = ({ + station, + validationUrl, +}: { + station: WrapperStationDetailsDto; + validationUrl: string; +}): Promise => { if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { return createStationWrap(station); } - return BackofficeApi.createWrapperStation(station).then((resources) => resources); -}; - -export const getWrapperStation = (ecCode: string): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationWrap(ecCode); - } else { - return BackofficeApi.getWrapperEntitiesStation(ecCode).then((resources) => resources); - } -}; - -export const updateWrapperStationToCheck = ( - station: StationDetailsDto -): Promise => { - if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return updateStationWrap(station); - } else { - return BackofficeApi.updateWrapperStationToCheck(station.stationCode, station).then( - (resources) => resources - ); - } + return BackofficeApi.createWrapperStation({ station, validationUrl }).then( + (resources) => resources + ); }; -export const updateWrapperStationToCheckUpdate = ( - station: StationDetailsDto -): Promise => { +export const updateWrapperStationDetails = ({ + stationCode, + station, + validationUrl, +}: { + stationCode: string; + station: StationDetailsDto; + validationUrl: string; +}): Promise => { if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { return updateStationWrap(station); } else { - return BackofficeApi.updateWrapperStationToCheckUpdate(station.stationCode, station).then( - (resources) => resources - ); + return BackofficeApi.updateWrapperStationDetails({ + stationCode, + station, + validationUrl, + }).then((resources) => resources); } }; @@ -195,22 +181,31 @@ export const updateWrapperStationWithOperatorReview = ({ } }; -export const updateStation = ( - station: StationDetailsDto, - stationCode: string -): Promise => { +export const updateStation = ({ + stationCode, + station, +}: { + stationCode: string; + station: StationDetailsDto; +}): Promise => { if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { return UpdateStationMocked(station, stationCode); } else { - return BackofficeApi.updateStation(station, stationCode).then((resources) => resources); + return BackofficeApi.updateStation({ station, stationCode }).then((resources) => resources); } }; -export const getStationDetail = (stationId: string): Promise => { +export const getStationDetail = ({ + stationCode, + status, +}: { + stationCode: string; + status: ConfigurationStatus; +}): Promise => { if (process.env.REACT_APP_API_MOCK_BACKOFFICE === 'true') { - return getStationDetailMock(stationId); + return getStationDetailMock(stationCode); } else { - return BackofficeApi.getStationDetail(stationId).then((resource) => resource); + return BackofficeApi.getStationDetails({ stationCode, status }).then((resource) => resource); } }; From 57537066b046912e00615ec5d7138bf305f36f54 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Tue, 2 Jul 2024 07:49:52 +0000 Subject: [PATCH 24/73] Bump to version 1.26.3-1-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b12c414c..c509b57f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.3", + "version": "1.26.3-1-next", "homepage": "ui", "private": true, "scripts": { From 37b5a92d44f83b566ad81b4b97c21204c5a4936c Mon Sep 17 00:00:00 2001 From: Jacopo Date: Wed, 3 Jul 2024 11:26:11 +0200 Subject: [PATCH 25/73] notify --- .github/workflows/ci_integration_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_integration_test.yml b/.github/workflows/ci_integration_test.yml index 9a08cce13..e919b4a4f 100644 --- a/.github/workflows/ci_integration_test.yml +++ b/.github/workflows/ci_integration_test.yml @@ -54,7 +54,7 @@ concurrency: jobs: integration_test: - name: Test ${{(github.event.inputs == null && 'dev') || inputs.environment }} + name: Test ${{(inputs.environment == null && 'dev') || inputs.environment }} runs-on: ubuntu-latest steps: - name: Checkout @@ -149,7 +149,7 @@ jobs: needs: [ integration_test ] runs-on: ubuntu-latest name: Notify - if: ${{ always() && ( inputs == null || inputs.notify == true ) }} + if: ${{ always() && (github.event_name == 'schedule' || inputs.notify == true ) }} steps: - name: Report Status uses: ravsamhq/notify-slack-action@be814b201e233b2dc673608aa46e5447c8ab13f2 # v2 From b6d5e03c73fd6ec4db22bd5cba985e4da3cea651 Mon Sep 17 00:00:00 2001 From: gioelemella <128155546+gioelemella@users.noreply.github.com> Date: Thu, 4 Jul 2024 11:22:42 +0200 Subject: [PATCH 26/73] fix missing translate (#596) --- src/locale/it.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/locale/it.json b/src/locale/it.json index 4a74cdc11..e685a24a1 100644 --- a/src/locale/it.json +++ b/src/locale/it.json @@ -695,6 +695,7 @@ "toCheckMessage": "Verifica le informazioni inserite dall’ente e approva o richiedi modifiche alla stazione.", "toFixTitle": "Modifiche richieste", "toFixMessage": "Stazione in attesa di correzione da parte dell’ente.", + "waitingForRevision": "La stazione è in attesa di approvazione da parte di un nostro operatore. Riceverai una mail a procedura completata.", "pendingUpdate": "Attenzione la stazione ha delle modifiche in corso ed è quindi disponibile in sola lettura.\nLa configurazione visualizzata è quella attiva sul nodo, per effettuare delle modifiche spostarsi sulla stazione da validare." }, "modal": { From 9e2c2e36feddf253aad0049a47b3477cc1e23078 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Thu, 4 Jul 2024 09:23:02 +0000 Subject: [PATCH 27/73] Bump to version 1.26.4-1-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7316535e9..cd8dc0de5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.4", + "version": "1.26.4-1-next", "homepage": "ui", "private": true, "scripts": { From 517895dbb1a643e1671b7aafb4b78b186e45bd10 Mon Sep 17 00:00:00 2001 From: Samuele Varianti <128470180+svariant@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:36:42 +0200 Subject: [PATCH 28/73] fix: Bugs found before release (#597) * fix: Bundle -> hide delete & disable invite EC buttons if bundle is expired * fix: Newconnectivity select channels * fix: Margin top checkbox channels edit page * fix: Unit tests * empty commit --- src/model/Channel.tsx | 65 +- src/model/CommissionBundle.ts | 79 +-- .../addEditChannel/AddEditChannelForm.tsx | 24 +- .../__tests__/AddEditChannelForm.test.tsx | 17 +- .../AddEditChannelValidationForm.tsx | 610 +++++++++--------- .../detail/CommissionBundleDetailPage.tsx | 25 +- ...mmissionBundleDetailSubscriptionsTable.tsx | 2 + 7 files changed, 405 insertions(+), 417 deletions(-) diff --git a/src/model/Channel.tsx b/src/model/Channel.tsx index 238ad0e6f..7ea9fcf88 100644 --- a/src/model/Channel.tsx +++ b/src/model/Channel.tsx @@ -1,42 +1,59 @@ -import { - ChannelDetailsDto, - Payment_modelEnum, - ProtocolEnum, - Redirect_protocolEnum, -} from '../api/generated/portal/ChannelDetailsDto'; -import {StatusEnum} from '../api/generated/portal/WrapperChannelDetailsDto'; +import { ChannelDetailsDto, ProtocolEnum } from '../api/generated/portal/ChannelDetailsDto'; +import { ENV } from '../utils/env'; export type ChannelStatus = 'ACTIVE' | 'REVISION' | 'NEEDCORRECTION'; export enum FormAction { - Create = 'create', - Edit = 'edit', - Duplicate = 'duplicate', + Create = 'create', + Edit = 'edit', + Duplicate = 'duplicate', } export type ChannelExtraInfo = { - targetUnion: string; - newConnection: string; - proxyUnion: string; + targetUnion: string; + newConnection: string; + proxyUnion: string; }; export type ChannelOnCreation = ChannelDetailsDto & ChannelExtraInfo; export type Channel = { - channel_code: string; - enabled: boolean; - status: ChannelStatus; - broker_description: string; + channel_code: string; + enabled: boolean; + status: ChannelStatus; + broker_description: string; }; export type Channels = { - channelsArray: Array; - page_info: { - items_found?: number | undefined; - limit?: number | undefined; - page?: number | undefined; - total_pages?: number | undefined; - }; + channelsArray: Array; + page_info: { + items_found?: number | undefined; + limit?: number | undefined; + page?: number | undefined; + total_pages?: number | undefined; + }; +}; + +export const forwarder01 = + ENV.ENV === 'PROD' + ? 'https://api.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward' + : 'https://api.uat.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward'; + +export const isNewConnectivity = ({ + protocol, + ip, + service, +}: { + protocol?: ProtocolEnum; + ip?: string; + service?: string; +}): boolean => { + console.log('PP', protocol, ip, service, Boolean( + `${protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://'}${ip}${service}` === forwarder01 + )); + return Boolean( + `${protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://'}${ip}${service}` === forwarder01 + ); }; /* diff --git a/src/model/CommissionBundle.ts b/src/model/CommissionBundle.ts index 3d11fde7d..549a29014 100644 --- a/src/model/CommissionBundle.ts +++ b/src/model/CommissionBundle.ts @@ -1,61 +1,68 @@ -import {CIBundleFee} from "../api/generated/portal/CIBundleFee"; -import {CIBundleResource} from "../api/generated/portal/CIBundleResource"; -import {CIBundlesResource} from "../api/generated/portal/CIBundlesResource"; -import {CIBundleSubscriptionsDetail} from "../api/generated/portal/CIBundleSubscriptionsDetail"; -import {CISubscriptionInfo} from "../api/generated/portal/CISubscriptionInfo"; -import {PSPBundleResource, TypeEnum} from "../api/generated/portal/PSPBundleResource"; -import {PSPBundlesResource} from "../api/generated/portal/PSPBundlesResource"; -import {PSPBundleTaxonomy} from "../api/generated/portal/PSPBundleTaxonomy"; +import { CIBundleFee } from '../api/generated/portal/CIBundleFee'; +import { CIBundleResource } from '../api/generated/portal/CIBundleResource'; +import { CIBundlesResource } from '../api/generated/portal/CIBundlesResource'; +import { CIBundleSubscriptionsDetail } from '../api/generated/portal/CIBundleSubscriptionsDetail'; +import { CISubscriptionInfo } from '../api/generated/portal/CISubscriptionInfo'; +import { PSPBundleResource, TypeEnum } from '../api/generated/portal/PSPBundleResource'; +import { PSPBundlesResource } from '../api/generated/portal/PSPBundlesResource'; +import { PSPBundleTaxonomy } from '../api/generated/portal/PSPBundleTaxonomy'; +import { datesAreOnSameDay } from '../utils/common-utils'; export enum FormAction { - Create = 'create', - Edit = 'edit', + Create = 'create', + Edit = 'edit', } export enum SubscriptionStateType { Waiting = 'WAITING', - Accepted = 'ACCEPTED' + Accepted = 'ACCEPTED', } export type BundleCISubscriptionsMethodParams = { - idBundle: string; - pspTaxCode: string; - limit: number; - page: number; - status: SubscriptionStateType; - ciTaxCode?: string; - bundleType: TypeEnum; + idBundle: string; + pspTaxCode: string; + limit: number; + page: number; + status: SubscriptionStateType; + ciTaxCode?: string; + bundleType: TypeEnum; }; export type BundleCISubscriptionsBodyRequest = { - 'id-bundle': string; - 'psp-tax-code': string; - limit: number; - page: number; - status: SubscriptionStateType; - ciTaxCode?: string; - bundleType: TypeEnum; + 'id-bundle': string; + 'psp-tax-code': string; + limit: number; + page: number; + status: SubscriptionStateType; + ciTaxCode?: string; + bundleType: TypeEnum; }; export type BundleCiSubscriptionsDetailMethodParams = { - idBundle: string; - pspTaxCode: string; - ciTaxCode: string; - status: string; - bundleType: TypeEnum; + idBundle: string; + pspTaxCode: string; + ciTaxCode: string; + status: string; + bundleType: TypeEnum; }; export type BundleCiSubscriptionDetailModel = CISubscriptionInfo & CIBundleSubscriptionsDetail; export enum BundleDetailsActionTypes { - DELETE_BUNDLE_PSP = "deleteBundlePsp", - DELETE_BUNDLE_EC = "deleteBundleEc", - REJECT_OFFER_EC = "rejectOfferEc", - ACCEPT_OFFER_EC = "acceptOfferEc", - DELETE_REQUEST_EC = "deleteRequestEc", - CREATE_REQUEST_EC = "createRequestEc" + DELETE_BUNDLE_PSP = 'deleteBundlePsp', + DELETE_BUNDLE_EC = 'deleteBundleEc', + REJECT_OFFER_EC = 'rejectOfferEc', + ACCEPT_OFFER_EC = 'acceptOfferEc', + DELETE_REQUEST_EC = 'deleteRequestEc', + CREATE_REQUEST_EC = 'createRequestEc', } export type BundlesResource = PSPBundlesResource | CIBundlesResource; export type BundleResource = PSPBundleResource | CIBundleResource; export type BundleTaxonomy = PSPBundleTaxonomy | CIBundleFee; + +export const isBundleValid = (bundleDetail: BundleResource) => + bundleDetail.validityDateFrom && new Date().getTime() > bundleDetail.validityDateFrom.getTime(); + +export const isBundleDeleted = (bundleDetail: BundleResource) => + bundleDetail.validityDateTo && datesAreOnSameDay(new Date(), bundleDetail.validityDateTo); diff --git a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx index fecca8279..e37f6ff83 100644 --- a/src/pages/channels/addEditChannel/AddEditChannelForm.tsx +++ b/src/pages/channels/addEditChannel/AddEditChannelForm.tsx @@ -34,7 +34,7 @@ import { } from '../../../api/generated/portal/ChannelDetailsResource'; import { PaymentTypes } from '../../../api/generated/portal/PaymentTypes'; import { useUserRole } from '../../../hooks/useUserRole'; -import { ChannelOnCreation, FormAction } from '../../../model/Channel'; +import { ChannelOnCreation, FormAction, forwarder01 } from '../../../model/Channel'; import { Party } from '../../../model/Party'; import { sortPaymentType } from '../../../model/PaymentType'; import { ConfigurationStatus } from '../../../model/Station'; @@ -47,7 +47,7 @@ import { } from '../../../services/channelService'; import { getPaymentTypes } from '../../../services/configurationService'; import { LOADING_TASK_CHANNEL_ADD_EDIT, LOADING_TASK_PAYMENT_TYPE } from '../../../utils/constants'; -import { ENV } from '../../../utils/env'; +import { isNewConnectivity } from '../../../model/Channel'; import ConfirmModal from '../../components/ConfirmModal'; import { isValidURL } from '../../components/commonFunctions'; import AddEditChannelFormSectionTitle from './AddEditChannelFormSectionTitle'; @@ -72,11 +72,6 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct const [paymentOptions, setPaymentOptions] = useState({ payment_types: [] }); const { userIsPagopaOperator } = useUserRole(); - const forwarder01 = - ENV.ENV === 'PROD' - ? 'https://api.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward' - : 'https://api.uat.platform.pagopa.it/pagopa-node-forwarder/api/v1/forward'; - const initialFormData = ( channelCode: string, channelDetail?: ChannelDetailsResource, @@ -91,12 +86,7 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct digital_stamp_brand: channelDetail.digital_stamp_brand ?? false, flag_io: channelDetail.flag_io ?? false, ip: channelDetail.ip ?? '', - newConnection: - `${channelDetail.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://'}${ - channelDetail.ip - }${channelDetail.service}` === forwarder01 - ? forwarder01 - : '', + newConnection: isNewConnectivity(channelDetail) ? forwarder01 : '', new_password: channelDetail.new_password ?? '', nmp_service: channelDetail.nmp_service ?? '', on_us: channelDetail.on_us ?? false, @@ -213,8 +203,6 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct validateOnMount: true, }); - const [isNewConnectivity, setIsNewConnectivity] = useState(!!formik.values.newConnection); - useEffect(() => { splitTarget(formik.values); }, [formik.values.targetUnion]); @@ -318,7 +306,7 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct const splitNewConnection = (values: ChannelOnCreation) => { const splitUrl = - formik.values.newConnection.trim() !== '' && isNewConnectivity + formik.values.newConnection.trim() !== '' ? splitURL(formik.values.newConnection) : splitURL(formik.values.targetUnion); @@ -695,10 +683,6 @@ const AddEditChannelForm = ({ selectedParty, channelCode, channelDetail, formAct ) : null} diff --git a/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx b/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx index 18290371d..a12a5c5e6 100644 --- a/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx +++ b/src/pages/channels/addEditChannel/__tests__/AddEditChannelForm.test.tsx @@ -371,7 +371,7 @@ describe('', (injectedHistory?: ReturnType { + test('Test of AddEditChannelValidationForm case checkbox select-new-connection-test flag true', async () => { jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ userRole: ROLE.PAGOPA_OPERATOR, userIsPspAdmin: false, @@ -405,16 +405,17 @@ describe('', (injectedHistory?: ReturnType', (injectedHistory?: ReturnType ); + }); test('Test of AddEditChannelValidationForm case chackbox select-new-connection-test flag true on config', async () => { @@ -519,16 +521,17 @@ describe('', (injectedHistory?: ReturnType; - handleChangeNumberOnly: ( - e: React.ChangeEvent, - field: string, - formik: FormikProps - ) => void; - setIsNewConnectivity: Dispatch>; - isNewConnectivity: boolean; - forwarder01: string; - channelDetail?: ChannelDetailsResource; + formik: FormikProps; + handleChangeNumberOnly: ( + e: React.ChangeEvent, + field: string, + formik: FormikProps + ) => void; }; const AddEditChannelValidationForm = ({ - formik, - handleChangeNumberOnly, - setIsNewConnectivity, - isNewConnectivity, - forwarder01, - channelDetail, - }: // eslint-disable-next-line sonarjs/cognitive-complexity - Props) => { - const {t} = useTranslation(); - const newConnectivity = `${ - channelDetail?.protocol === ProtocolEnum.HTTPS ? 'https://' : 'http://' - }${channelDetail?.ip}${channelDetail?.service}`; + formik, + handleChangeNumberOnly +}: // eslint-disable-next-line sonarjs/cognitive-complexity +Props) => { + const { t } = useTranslation(); - useEffect(() => { - if (forwarder01 === newConnectivity) { - setIsNewConnectivity(true); - } - }, [newConnectivity]); + const inputGroupStyle = { + borderRadius: 1, + border: 1, + borderColor: theme.palette.divider, + p: 3, + mb: 3, + }; - const changeCheckBoxValue = () => { - formik.setFieldValue('newConnection', ''); - setIsNewConnectivity(!isNewConnectivity); - }; + const oldConnectionValue = + ENV.ENV === 'prod' ? `http://10.102.1.85:8080` : `http://10.101.1.95:8080`; + const newConnectionValue = ENV.ENV === 'prod' ? `http://0.79.20.35:80` : `http://10.79.20.33:80`; - const inputGroupStyle = { + const proxyOptions = [ + { + label: `${newConnectionValue} - (Nuova Connettività)`, + value: newConnectionValue, + }, + { + label: `${oldConnectionValue} - (Vecchia Connettività)`, + value: oldConnectionValue, + }, + ]; + + return ( + - - - - {t('addEditChannelPage.addForm.validationForm.title')} - - - - - {t('addEditChannelPage.addForm.validationForm.subtitle')} - - + }} + > + + + + {t('addEditChannelPage.addForm.validationForm.title')} + + + + + {t('addEditChannelPage.addForm.validationForm.subtitle')} + + + + + + } + isRequired + > + + + handleChangeNumberOnly(e, 'primitive_version', formik)} + error={formik.touched.primitive_version && Boolean(formik.errors.primitive_version)} + helperText={formik.touched.primitive_version && formik.errors.primitive_version} + inputProps={{ + step: 1, + min: 0, + max: 2, + 'data-testid': 'primitive-version-test', + }} + required + /> - - - } - isRequired - > - - - handleChangeNumberOnly(e, 'primitive_version', formik)} - error={formik.touched.primitive_version && Boolean(formik.errors.primitive_version)} - helperText={formik.touched.primitive_version && formik.errors.primitive_version} - inputProps={{ - step: 1, - min: 0, - max: 2, - 'data-testid': 'primitive-version-test', - }} - required - /> - - - - - - - - - } - > - - - changeCheckBoxValue()} - data-testid="select-new-connection-test" - /> - } - label={t('addEditChannelPage.addForm.validationForm.fields.newConnection')} - /> - - - - - {t('addEditChannelPage.addForm.validationForm.fields.newConnectionChannel')} - - - - - - - - } - isRequired - > - - - - - {t('addEditChannelPage.addForm.validationForm.fields.proxyAddress')} - - - - - - + + } + > + + + + + {t('addEditChannelPage.addForm.validationForm.fields.newConnectionChannel')} + + + + + + + + } + isRequired + > + + + + + {t('addEditChannelPage.addForm.validationForm.fields.proxyAddress')} + + + + + + - - } - > - - - handleChangeNumberOnly(e, 'timeout_a', formik)} - error={formik.touched.timeout_a && Boolean(formik.errors.timeout_a)} - helperText={formik.touched.timeout_a && formik.errors.timeout_a} - /> - + + } + > + + + handleChangeNumberOnly(e, 'timeout_a', formik)} + error={formik.touched.timeout_a && Boolean(formik.errors.timeout_a)} + helperText={formik.touched.timeout_a && formik.errors.timeout_a} + /> + - - handleChangeNumberOnly(e, 'timeout_b', formik)} - error={formik.touched.timeout_b && Boolean(formik.errors.timeout_b)} - helperText={formik.touched.timeout_b && formik.errors.timeout_b} - /> - + + handleChangeNumberOnly(e, 'timeout_b', formik)} + error={formik.touched.timeout_b && Boolean(formik.errors.timeout_b)} + helperText={formik.touched.timeout_b && formik.errors.timeout_b} + /> + - - handleChangeNumberOnly(e, 'timeout_c', formik)} - error={formik.touched.timeout_c && Boolean(formik.errors.timeout_c)} - helperText={formik.touched.timeout_c && formik.errors.timeout_c} - /> - + + handleChangeNumberOnly(e, 'timeout_c', formik)} + error={formik.touched.timeout_c && Boolean(formik.errors.timeout_c)} + helperText={formik.touched.timeout_c && formik.errors.timeout_c} + /> + - - - } - label={t('addEditChannelPage.addForm.validationForm.fields.pspNotify')} - /> - + + + } + label={t('addEditChannelPage.addForm.validationForm.fields.pspNotify')} + /> + - - - } - label={t('addEditChannelPage.addForm.validationForm.fields.digitalStamp')} - /> - - - - - - ); + + + } + label={t('addEditChannelPage.addForm.validationForm.fields.digitalStamp')} + /> + + + + + + ); }; export default AddEditChannelValidationForm; diff --git a/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx b/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx index 3a2030c36..2f38e5b88 100644 --- a/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx +++ b/src/pages/commisionalBundles/detail/CommissionBundleDetailPage.tsx @@ -19,6 +19,8 @@ import { BundleDetailsActionTypes, BundleResource, FormAction, + isBundleDeleted, + isBundleValid, } from '../../../model/CommissionBundle'; import { Party } from '../../../model/Party'; import { useAppSelector, useAppSelectorWithRedirect } from '../../../redux/hooks'; @@ -40,7 +42,7 @@ import CommissionBundleDetailSubscriptionsTable from './components/subscriptions function RenderAlert({ bundleDetail }: Readonly<{ bundleDetail: BundleResource }>) { const { t } = useTranslation(); - if ((bundleDetail as CIBundleResource)?.ciBundleStatus === CiBundleStatusEnum.ON_REMOVAL) { + if ((bundleDetail as CIBundleResource)?.ciBundleStatus === CiBundleStatusEnum.ON_REMOVAL || isBundleDeleted(bundleDetail)) { return ( {t('commissionBundlesPage.commissionBundleDetail.alert.onRemoval')} @@ -95,14 +97,16 @@ const BundleActionButtons = ({ if (orgInfo.types.isPsp) { return ( <> - + {!isBundleDeleted(bundleDetail) && ( + + )} From e318a92ed160ed9fb6ef3ab549d5c64809a0c22e Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Fri, 5 Jul 2024 13:36:59 +0000 Subject: [PATCH 29/73] Bump to version 1.26.4-2-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cd8dc0de5..f9e75a38d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.4-1-next", + "version": "1.26.4-2-next", "homepage": "ui", "private": true, "scripts": { From 1defddd277136045209ded603aaa07bf1ef50763 Mon Sep 17 00:00:00 2001 From: Samuele Varianti <128470180+svariant@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:35:24 +0200 Subject: [PATCH 30/73] [VAS-1146] feat: Implement new boolean "cart" for bundles (#605) * [VAS-1146] feat: Implement new switch for cart bool in bundle add/edit page * [VAS-1146] chore: Unit tests * [VAS-1146] chore: Update packagejson openapi command * empty commit * [VAS-1146] fix: Unit tests * [VAS-1146] feat: Swap api call getChannelsDetails with primitive version check on list elements * [VAS-1146] feat: Improve unit test * [VAS-1146] fix: Unit tests * [VAS-1146] fix: Unit tests * [VAS-1146] feat: Add cart bool to bundle details drawer * fix unit test * [VAS-1146] feat: Improve code --- package.json | 2 +- src/locale/it.json | 4 +- .../AddEditCommissionBundlePage.tsx | 1 + .../AddEditCommissionBundleForm.tsx | 1346 +++++++++-------- .../AddEditCommissionBundleForm.test.tsx | 1039 +++++++------ .../CommissionBundleDetailConfiguration.tsx | 231 +-- ...mmissionBundleDetailConfiguration.test.tsx | 116 +- src/services/__mocks__/bundleService.ts | 3 +- src/services/__mocks__/channelService.ts | 10 + src/services/__mocks__/institutionsService.ts | 2 +- 10 files changed, 1435 insertions(+), 1319 deletions(-) diff --git a/package.json b/package.json index f9e75a38d..1eb709560 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "clean:api-portal": "rimraf src/api/generated/portal && rimraf openApi/generated", "generate:api-portal": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/main/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-next": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/next/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", - "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/next/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", + "generate:api-portal-pr": "wget https://raw.githubusercontent.com/pagopa/pagopa-selfcare-ms-backoffice-backend/VAS-1146-cart-bool-bundle/openapi/openapi.json -O ./openApi/portal-api-docs.json && npm run generate:client", "generate:api-portal-local": "npm run generate:client", "generate:client": "jq 'walk(if type == \"object\" and has(\"parameters\") then .parameters |= map(select(.name != \"X-Request-Id\")) else . end)' ./openApi/portal-api-docs.json > ./openApi/portal-api-docs.json.temp && mv ./openApi/portal-api-docs.json.temp ./openApi/portal-api-docs.json && yarn run clean:api-portal && mkdirp openApi/generated && gen-api-models --api-spec openApi/portal-api-docs.json --out-dir src/api/generated/portal --no-strict --request-types --response-decoders --client && node openApi/scripts/api-portal_fixPostGen.js" }, diff --git a/src/locale/it.json b/src/locale/it.json index e685a24a1..9523ab421 100644 --- a/src/locale/it.json +++ b/src/locale/it.json @@ -1257,7 +1257,9 @@ "paymentOnlyDigitalStamp": "Pagamento solo marca da bollo", "from": "Da", "to": "A", - "all": "Tutti" + "all": "Tutti", + "cart": "Gestione carrello di pagamenti", + "cartInfo": "La gestione del carrello è possibile soltanto per i canali configurati con le primitive in versione 2" }, "addTaxonomies": { "subTitle": "Cerca i servici di incasso sfogliando il catalogo oppure carica una lista di codici.", diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx index 5da031e91..e6229e65d 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/AddEditCommissionBundlePage.tsx @@ -57,6 +57,7 @@ const toNewFormData = ( validityDateFrom: data?.validityDateFrom ?? minDateTomorrow(), validityDateTo: data?.validityDateTo ?? minDateTomorrow(), pspBusinessName: selectedParty?.description ?? '', + cart: data?.cart }); function getABIOrBIC( diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx index 08ad08f41..db5649290 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/components/AddEditCommissionBundleForm.tsx @@ -1,26 +1,28 @@ /* eslint-disable functional/no-let */ /* eslint-disable complexity */ /* eslint-disable sonarjs/cognitive-complexity */ -import { MenuBook } from '@mui/icons-material'; +import { InfoOutlined, MenuBook } from '@mui/icons-material'; import BookmarkAddIcon from '@mui/icons-material/BookmarkAdd'; import DateRangeIcon from '@mui/icons-material/DateRange'; import EuroIcon from '@mui/icons-material/Euro'; import { - Autocomplete, - Box, - FormControl, - FormControlLabel, - FormLabel, - Grid, - InputLabel, - MenuItem, - Paper, - Radio, - RadioGroup, - Select, - TextField, - TextFieldProps, - Typography, + Autocomplete, + Box, + FormControl, + FormControlLabel, + FormLabel, + Grid, + InputLabel, + MenuItem, + Paper, + Radio, + RadioGroup, + Select, + Switch, + TextField, + TextFieldProps, + Tooltip, + Typography, } from '@mui/material'; import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; @@ -37,8 +39,7 @@ import { PaymentTypes } from '../../../../api/generated/portal/PaymentTypes'; import { Touchpoints } from '../../../../api/generated/portal/Touchpoints'; import FormSectionTitle from '../../../../components/Form/FormSectionTitle'; import { useFlagValue } from '../../../../hooks/useFeatureFlags'; -import { useOrganizationType } from "../../../../hooks/useOrganizationType"; -import { useUserRole } from "../../../../hooks/useUserRole"; +import { useOrganizationType } from '../../../../hooks/useOrganizationType'; import { Party } from '../../../../model/Party'; import { sortPaymentType } from '../../../../model/PaymentType'; import { ConfigurationStatus } from '../../../../model/Station'; @@ -49,656 +50,703 @@ import { getChannels } from '../../../../services/channelService'; import { getPaymentTypes } from '../../../../services/configurationService'; import { getBrokerDelegation } from '../../../../services/institutionService'; import { addCurrentBroker } from '../../../../utils/channel-utils'; -import { LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS, LOADING_TASK_GET_CHANNELS_IDS, } from '../../../../utils/constants'; +import { + LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS, + LOADING_TASK_GET_CHANNELS_IDS, +} from '../../../../utils/constants'; +import { WrapperChannelResource } from '../../../../api/generated/portal/WrapperChannelResource'; type Props = { - formik: FormikProps; - isEdit: boolean; - idBrokerPsp: string | undefined; + formik: FormikProps; + isEdit: boolean; + idBrokerPsp: string | undefined; }; -const AddEditCommissionBundleForm = ({isEdit, formik, idBrokerPsp}: Props) => { - const {t} = useTranslation(); - const {userIsPspDirectAdmin} = useUserRole(); - const {orgInfo, orgIsPspDirect} = useOrganizationType(); - const setLoading = useLoading(LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS); - const setLoadingChannels = useLoading(LOADING_TASK_GET_CHANNELS_IDS); - const addError = useErrorDispatcher(); - const isPrivateEnabled = useFlagValue("commission-bundles-private"); - const isPublicEnabled = useFlagValue("commission-bundles-public"); - const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - - const [paymentOptions, setPaymentOptions] = useState(); - const [touchpointList, setTouchpointList] = useState(); - const [brokerDelegationList, setBrokerDelegationList] = useState>([]); - const [channelsId, setChannelsId] = useState>([]); +const AddEditCommissionBundleForm = ({ isEdit, formik, idBrokerPsp }: Props) => { + const { t } = useTranslation(); + const { orgIsPspDirect } = useOrganizationType(); + const setLoading = useLoading(LOADING_TASK_COMMISSION_BUNDLE_SELECT_DATAS); + const setLoadingChannels = useLoading(LOADING_TASK_GET_CHANNELS_IDS); + const addError = useErrorDispatcher(); + const isPrivateEnabled = useFlagValue('commission-bundles-private'); + const isPublicEnabled = useFlagValue('commission-bundles-public'); + const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); - const inputGroupStyle = { - borderRadius: 1, - border: 1, - borderColor: theme.palette.divider, - p: 3, - mb: 3, - }; + const [paymentOptions, setPaymentOptions] = useState(); + const [touchpointList, setTouchpointList] = useState(); + const [brokerDelegationList, setBrokerDelegationList] = useState>([]); + const [channels, setChannels] = useState>([]); + const [isChannelV2, setIsChannelV2] = useState(false); - const getChannelsByBrokerCode = (selectedBrokerCode: string) => { - setLoadingChannels(true); - getChannels({status: ConfigurationStatus.ACTIVE, brokerCode: selectedBrokerCode}) - .then((data) => { - if (data?.channels && data.channels.length > 0) { - setChannelsId(data.channels.map(ch => ch.channel_code)); - } else { - setChannelsId([]); - addError({ - id: 'GET_BROKER_DELEGATIONS_DATA', - blocking: false, - error: new Error(`An error occurred while getting data`), - techDescription: `An error occurred while getting data`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t( - 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageNoBrokerDelegations' - ), - component: 'Toast', - }); - } - }) - .catch((error) => { - setChannelsId([]); - addError({ - id: 'GET_CHANNEL_IDS_DATA', - blocking: false, - error: error as Error, - techDescription: `An error occurred while getting data`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t( - 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageChannelIdsDataDesc' - ), - component: 'Toast', - }); - }) - .finally(() => setLoadingChannels(false)); - }; + const inputGroupStyle = { + borderRadius: 1, + border: 1, + borderColor: theme.palette.divider, + p: 3, + mb: 3, + }; - useEffect(() => { - setLoading(true); - Promise.all([ - getPaymentTypes(), - getTouchpoints(0, 50), - getBrokerDelegation(selectedParty?.partyId ?? '', undefined), - ]) - .then(([paymentTypes, touchpoints, brokerDelegation]) => { - if (paymentTypes) { - setPaymentOptions(paymentTypes); - } - if (touchpoints) { - setTouchpointList(touchpoints); - } - let listBroker = brokerDelegation?.delegation_list ? [...brokerDelegation.delegation_list] : []; - if (orgIsPspDirect) { - listBroker = addCurrentBroker(listBroker, selectedParty as Party); - } - if (listBroker.length > 0) { - setBrokerDelegationList(listBroker); - if (isEdit && idBrokerPsp) { - const brokerTaxCode = listBroker?.find( - (el) => el.broker_id === idBrokerPsp - )?.broker_tax_code; - if (brokerTaxCode) { - getChannelsByBrokerCode(brokerTaxCode); - } - } - } else { - addError({ - id: 'GET_BROKER_DATA', - blocking: false, - error: new Error(`An error occurred while getting data`), - techDescription: `An error occurred while getting data`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t( - 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageNoBroker' - ), - component: 'Toast', - }); - } - }) - .catch((reason) => { - addError({ - id: 'GET_ALL_DATA', - blocking: false, - error: reason as Error, - techDescription: `An error occurred while getting data`, - toNotify: true, - displayableTitle: t('general.errorTitle'), - displayableDescription: t( - 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageAllDataDesc' - ), - component: 'Toast', - }); - }) - .finally(() => { - setLoading(false); - }); - }, [selectedParty]); + const getChannelsByBrokerCode = (selectedBrokerCode: string) => { + setLoadingChannels(true); + getChannels({ status: ConfigurationStatus.ACTIVE, brokerCode: selectedBrokerCode }) + .then((data) => { + if (data?.channels && data.channels.length > 0) { + setChannels([...data.channels]); + handleIsChannelV2(formik.values.idChannel, [...data.channels]); + } else { + setChannels([]); + addError({ + id: 'GET_BROKER_DELEGATIONS_DATA', + blocking: false, + error: new Error(`An error occurred while getting data`), + techDescription: `An error occurred while getting data`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t( + 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageNoBrokerDelegations' + ), + component: 'Toast', + }); + } + }) + .catch((error) => { + setChannels([]); + addError({ + id: 'GET_CHANNEL_IDS_DATA', + blocking: false, + error: error as Error, + techDescription: `An error occurred while getting data`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t( + 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageChannelIdsDataDesc' + ), + component: 'Toast', + }); + }) + .finally(() => setLoadingChannels(false)); + }; - const shouldDisableDate = (date: Date) => date < new Date(); + useEffect(() => { + setLoading(true); + Promise.all([ + getPaymentTypes(), + getTouchpoints(0, 50), + getBrokerDelegation(selectedParty?.partyId ?? '', undefined), + ]) + .then(([paymentTypes, touchpoints, brokerDelegation]) => { + if (paymentTypes) { + setPaymentOptions(paymentTypes); + } + if (touchpoints) { + setTouchpointList(touchpoints); + } + let listBroker = brokerDelegation?.delegation_list + ? [...brokerDelegation.delegation_list] + : []; + if (orgIsPspDirect) { + listBroker = addCurrentBroker(listBroker, selectedParty as Party); + } - function handleBrokerCodesSelection( - value: string | null | undefined - ) { - formik.setFieldValue('idChannel', ''); - if (value === null || value === undefined) { - formik.setFieldValue('idBrokerPsp', ''); - setChannelsId([]); - } else { - const broker = brokerDelegationList?.find( - (el) => el.broker_name === value - ); - formik.handleChange('idBrokerPsp')(broker?.broker_tax_code ?? ""); - if (broker?.broker_tax_code) { - getChannelsByBrokerCode(broker?.broker_tax_code); + if (listBroker.length > 0) { + setBrokerDelegationList(listBroker); + if (isEdit && idBrokerPsp) { + const brokerTaxCode = listBroker?.find( + (el) => el.broker_tax_code === idBrokerPsp + )?.broker_tax_code; + if (brokerTaxCode) { + getChannelsByBrokerCode(brokerTaxCode); } + } + } else { + addError({ + id: 'GET_BROKER_DATA', + blocking: false, + error: new Error(`An error occurred while getting data`), + techDescription: `An error occurred while getting data`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t( + 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageNoBroker' + ), + component: 'Toast', + }); } + }) + .catch((reason) => { + addError({ + id: 'GET_ALL_DATA', + blocking: false, + error: reason as Error, + techDescription: `An error occurred while getting data`, + toNotify: true, + displayableTitle: t('general.errorTitle'), + displayableDescription: t( + 'commissionBundlesPage.addEditCommissionBundle.error.errorMessageAllDataDesc' + ), + component: 'Toast', + }); + }) + .finally(() => { + setLoading(false); + }); + }, [selectedParty]); + + const shouldDisableDate = (date: Date) => date < new Date(); + + function handleBrokerCodesSelection(value: string | null | undefined) { + formik.setFieldValue('idChannel', ''); + handleIsChannelV2(); + if (value === null || value === undefined) { + formik.setFieldValue('idBrokerPsp', ''); + setChannels([]); + } else { + const broker = brokerDelegationList?.find((el) => el.broker_name === value); + formik.handleChange('idBrokerPsp')(broker?.broker_tax_code ?? ''); + if (broker?.broker_tax_code) { + getChannelsByBrokerCode(broker?.broker_tax_code); + } } + } - return ( - <> - - - {t('commissionBundlesPage.addEditCommissionBundle.form.bundleType')} - + const handleIsChannelV2 = ( + channelCode?: string | null, + channelList?: Array + ) => { + let bool = false; + if (channelCode) { + const arrayChannel = channelList ?? channels; + bool = arrayChannel.find((el) => el.channel_code === channelCode)?.primitive_version === 2; + } - - formik.setFieldValue('type', e.target.value)} - data-testid="bundle-type-test" - value={`${formik.values.type}`} - > - } - label={t('commissionBundlesPage.globalBundles')} - sx={{pr: 8}} - disabled={isEdit} - /> - } - label={t('commissionBundlesPage.publicBundles')} - sx={{pr: 8}} - disabled={isEdit || !isPublicEnabled} - /> - } - label={t('commissionBundlesPage.privateBundles')} - disabled={isEdit || !isPrivateEnabled} - /> - - - - - - {t('commissionBundlesPage.addEditCommissionBundle.form.bundleConfiguration')} - + setIsChannelV2(bool); + if (!bool) { + formik.setFieldValue('cart', false); + } + }; + + const handleChangeChannel = (value: string | null) => { + formik.handleChange('idChannel')(value ?? ''); + handleIsChannelV2(value); + }; - - - } - /> - - - formik.handleChange(e)} - error={formik.touched.name && Boolean(formik.errors.name)} - helperText={formik.touched.name && formik.errors.name} - inputProps={{ - 'data-testid': 'name-test', - }} - /> - + return ( + <> + + + {t('commissionBundlesPage.addEditCommissionBundle.form.bundleType')} + - - formik.handleChange(e)} - error={formik.touched.description && Boolean(formik.errors.description)} - helperText={formik.touched.description && formik.errors.description} - inputProps={{ - 'data-testid': 'description-test', - }} - /> - - - - - {t('commissionBundlesPage.addEditCommissionBundle.form.paymentType')} - - - - - - - - {t('commissionBundlesPage.addEditCommissionBundle.form.touchpoint')} - - - - - + + formik.setFieldValue('type', e.target.value)} + data-testid="bundle-type-test" + value={`${formik.values.type}`} + > + } + label={t('commissionBundlesPage.globalBundles')} + sx={{ pr: 8 }} + disabled={isEdit} + /> + } + label={t('commissionBundlesPage.publicBundles')} + sx={{ pr: 8 }} + disabled={isEdit || !isPublicEnabled} + /> + } + label={t('commissionBundlesPage.privateBundles')} + disabled={isEdit || !isPrivateEnabled} + /> + + + + + + {t('commissionBundlesPage.addEditCommissionBundle.form.bundleConfiguration')} + - - } - /> - - - { - const numericValue = parseFloat(value.replace(',', '.')); - formik.setFieldValue('minPaymentAmount', numericValue * 100); - }} - thousandSeparator="" - decimalSeparator="," - allowNegative={false} - decimalScale={2} - fixedDecimalScale={false} - error={ - formik.touched.minPaymentAmount && Boolean(formik.errors.minPaymentAmount) - } - helperText={formik.touched.minPaymentAmount && formik.errors.minPaymentAmount} - InputProps={{ - endAdornment: , - }} - inputProps={{'data-testid': 'min-import-test'}} - /> - + + + } + /> + + + formik.handleChange(e)} + error={formik.touched.name && Boolean(formik.errors.name)} + helperText={formik.touched.name && formik.errors.name} + inputProps={{ + 'data-testid': 'name-test', + }} + /> + - - { - const numericValue = parseFloat(value.replace(',', '.')); - formik.setFieldValue('maxPaymentAmount', numericValue * 100); - }} - thousandSeparator="" - decimalSeparator="," - allowNegative={false} - decimalScale={2} - fixedDecimalScale={false} - error={ - formik.touched.maxPaymentAmount && Boolean(formik.errors.maxPaymentAmount) - } - helperText={formik.touched.maxPaymentAmount && formik.errors.maxPaymentAmount} - InputProps={{ - endAdornment: , - }} - inputProps={{'data-testid': 'max-import-test'}} - /> - - - + + formik.handleChange(e)} + error={formik.touched.description && Boolean(formik.errors.description)} + helperText={formik.touched.description && formik.errors.description} + inputProps={{ + 'data-testid': 'description-test', + }} + /> + + + + + {t('commissionBundlesPage.addEditCommissionBundle.form.paymentType')} + + + + + + + + {t('commissionBundlesPage.addEditCommissionBundle.form.touchpoint')} + + + + + - - } - /> - - - { - const numericValue = parseFloat(value.replace(',', '.')); - formik.setFieldValue('paymentAmount', numericValue * 100); - }} - thousandSeparator="" - decimalSeparator="," - allowNegative={false} - decimalScale={2} - fixedDecimalScale={false} - error={formik.touched.paymentAmount && Boolean(formik.errors.paymentAmount)} - helperText={formik.touched.paymentAmount && formik.errors.paymentAmount} - InputProps={{ - endAdornment: , - }} - inputProps={{'data-testid': 'payment-amount-test'}} - /> - - - - - - } - /> - - - el?.broker_name ?? '') - ?.sort((a, b) => a.localeCompare(b))} - disabled={!(brokerDelegationList && brokerDelegationList.length > 0)} - value={brokerDelegationList?.find(el => el.broker_tax_code === formik.values.idBrokerPsp)?.broker_name ?? ""} - onChange={(_, value) => { - handleBrokerCodesSelection(value); - }} - fullWidth - renderInput={(params) => ( - - )} - PaperComponent={({children}) => ( - {children} - )} - noOptionsText={t( - 'commissionBundlesPage.addEditCommissionBundle.form.noBrokersOption' - )} - data-testid="broker-code-test" - /> - - - a.localeCompare(b)) - } - disabled={!(channelsId && channelsId.length > 0)} - onChange={(_event, value) => { - if (value === null) { - formik.setFieldValue('idChannel', ''); - } else { - formik.handleChange('idChannel')(value); - } - }} - value={formik.values.idChannel} - fullWidth - renderInput={(params) => ( - - )} - PaperComponent={({children}) => ( - {children} - )} - noOptionsText={t( - 'commissionBundlesPage.addEditCommissionBundle.form.noChannelsOption' - )} - data-testid="channels-id-test" - /> - - - - - } - /> - - - - - {t( - 'commissionBundlesPage.addEditCommissionBundle.form.paymentWithDigitalStamp' - )} - - - formik.setFieldValue('digitalStamp', e.target.value === 'true') - } - row - data-testid="digital-stamp-test" - value={formik.values.digitalStamp ? `${formik.values.digitalStamp}` : 'false'} - > - } - label={t('general.no')} - sx={{pr: 3}} - /> - } - disabled={formik.values.digitalStampRestriction} - label={t('general.yes')} - /> - - - - - - - {t( - 'commissionBundlesPage.addEditCommissionBundle.form.paymentOnlyDigitalStamp' - )} - - - formik.setFieldValue('digitalStampRestriction', e.target.value === 'true') - } - row - data-testid="digital-stamp-restriction-test" - value={ - formik.values.digitalStampRestriction - ? `${formik.values.digitalStampRestriction}` - : 'false' - } - > - } - label={t('general.no')} - sx={{pr: 3}} - /> - } - disabled={formik.values.digitalStamp} - label={t('general.yes')} - /> - - - - - - - } - /> - - - - formik.setFieldValue('validityDateFrom', value)} - renderInput={(params: TextFieldProps) => ( - - )} - shouldDisableDate={shouldDisableDate} - disabled={isEdit} - /> - - - - - formik.setFieldValue('validityDateTo', value)} - renderInput={(params: TextFieldProps) => ( - - )} - shouldDisableDate={shouldDisableDate} - /> - - - - - - - - ); + + } + /> + + + { + const numericValue = parseFloat(value.replace(',', '.')); + formik.setFieldValue('minPaymentAmount', numericValue * 100); + }} + thousandSeparator="" + decimalSeparator="," + allowNegative={false} + decimalScale={2} + fixedDecimalScale={false} + error={ + formik.touched.minPaymentAmount && Boolean(formik.errors.minPaymentAmount) + } + helperText={formik.touched.minPaymentAmount && formik.errors.minPaymentAmount} + InputProps={{ + endAdornment: , + }} + inputProps={{ 'data-testid': 'min-import-test' }} + /> + + + + { + const numericValue = parseFloat(value.replace(',', '.')); + formik.setFieldValue('maxPaymentAmount', numericValue * 100); + }} + thousandSeparator="" + decimalSeparator="," + allowNegative={false} + decimalScale={2} + fixedDecimalScale={false} + error={ + formik.touched.maxPaymentAmount && Boolean(formik.errors.maxPaymentAmount) + } + helperText={formik.touched.maxPaymentAmount && formik.errors.maxPaymentAmount} + InputProps={{ + endAdornment: , + }} + inputProps={{ 'data-testid': 'max-import-test' }} + /> + + + + + + } + /> + + + { + const numericValue = parseFloat(value.replace(',', '.')); + formik.setFieldValue('paymentAmount', numericValue * 100); + }} + thousandSeparator="" + decimalSeparator="," + allowNegative={false} + decimalScale={2} + fixedDecimalScale={false} + error={formik.touched.paymentAmount && Boolean(formik.errors.paymentAmount)} + helperText={formik.touched.paymentAmount && formik.errors.paymentAmount} + InputProps={{ + endAdornment: , + }} + inputProps={{ 'data-testid': 'payment-amount-test' }} + /> + + + + + + } + /> + + + el?.broker_name ?? '') + ?.sort((a, b) => a.localeCompare(b))} + disabled={!(brokerDelegationList && brokerDelegationList.length > 0)} + value={ + brokerDelegationList?.find( + (el) => el.broker_tax_code === formik.values.idBrokerPsp + )?.broker_name ?? '' + } + onChange={(_, value) => { + handleBrokerCodesSelection(value); + }} + fullWidth + renderInput={(params) => ( + + )} + PaperComponent={({ children }) => ( + {children} + )} + noOptionsText={t( + 'commissionBundlesPage.addEditCommissionBundle.form.noBrokersOption' + )} + data-testid="broker-code-test" + /> + + + el.channel_code).sort((a, b) => a.localeCompare(b))} + disabled={!(channels && channels.length > 0)} + onChange={(_event, value) => handleChangeChannel(value)} + value={formik.values.idChannel} + fullWidth + renderInput={(params) => ( + + )} + PaperComponent={({ children }) => ( + {children} + )} + noOptionsText={t( + 'commissionBundlesPage.addEditCommissionBundle.form.noChannelsOption' + )} + data-testid="channels-id-test" + /> + + + formik.setFieldValue('cart', e.target.checked)} + checked={formik.values.cart ?? false} + disabled={!isChannelV2} + data-testid="bundle-cart" + /> + } + label={ +
+ {t('commissionBundlesPage.addEditCommissionBundle.form.cart')} + + + +
+ } + /> +
+
+
+ + } + /> + + + + + {t( + 'commissionBundlesPage.addEditCommissionBundle.form.paymentWithDigitalStamp' + )} + + + formik.setFieldValue('digitalStamp', e.target.value === 'true') + } + row + data-testid="digital-stamp-test" + value={formik.values.digitalStamp ? `${formik.values.digitalStamp}` : 'false'} + > + } + label={t('general.no')} + sx={{ pr: 3 }} + /> + } + disabled={formik.values.digitalStampRestriction} + label={t('general.yes')} + /> + + + + + + + {t( + 'commissionBundlesPage.addEditCommissionBundle.form.paymentOnlyDigitalStamp' + )} + + + formik.setFieldValue('digitalStampRestriction', e.target.value === 'true') + } + row + data-testid="digital-stamp-restriction-test" + value={ + formik.values.digitalStampRestriction + ? `${formik.values.digitalStampRestriction}` + : 'false' + } + > + } + label={t('general.no')} + sx={{ pr: 3 }} + /> + } + disabled={formik.values.digitalStamp} + label={t('general.yes')} + /> + + + + + + + } + /> + + + + formik.setFieldValue('validityDateFrom', value)} + renderInput={(params: TextFieldProps) => ( + + )} + shouldDisableDate={shouldDisableDate} + disabled={isEdit} + /> + + + + + formik.setFieldValue('validityDateTo', value)} + renderInput={(params: TextFieldProps) => ( + + )} + shouldDisableDate={shouldDisableDate} + /> + + + + + + + + ); }; export default AddEditCommissionBundleForm; diff --git a/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx b/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx index 5b3368bca..c6b069829 100644 --- a/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx +++ b/src/pages/commisionalBundles/addEditCommissionBundle/components/__tests__/AddEditCommissionBundleForm.test.tsx @@ -1,24 +1,29 @@ -import {ThemeProvider} from '@mui/system'; -import {theme} from '@pagopa/mui-italia'; -import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react'; -import {MemoryRouter, Route} from 'react-router-dom'; -import {createStore, store} from '../../../../../redux/store'; -import {Provider} from 'react-redux'; +import { ThemeProvider } from '@mui/system'; +import { theme } from '@pagopa/mui-italia'; +import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { MemoryRouter, Route } from 'react-router-dom'; +import { createStore, store } from '../../../../../redux/store'; +import { Provider } from 'react-redux'; import React from 'react'; -import {mockedBundleRequest, mockedBundleRequestForEdit, mockedChannelsIdList,} from '../../../../../services/__mocks__/bundleService'; -import {partiesActions} from '../../../../../redux/slices/partiesSlice'; -import {pspOperatorSignedDirect} from '../../../../../services/__mocks__/partyService'; +import { + mockedBundleRequest, + mockedBundleRequestForEdit, + mockedChannelsIdList, +} from '../../../../../services/__mocks__/bundleService'; +import { partiesActions } from '../../../../../redux/slices/partiesSlice'; +import { pspOperatorSignedDirect } from '../../../../../services/__mocks__/partyService'; import AddEditCommissionBundleForm from '../AddEditCommissionBundleForm'; -import {useFormik} from 'formik'; -import {BundleRequest} from '../../../../../api/generated/portal/BundleRequest'; -import {FormAction} from '../../../../../model/CommissionBundle'; -import {mockedDelegatedPSP} from '../../../../../services/__mocks__/institutionsService'; -import {formatDateToDDMMYYYY} from '../../../../../utils/common-utils'; +import { useFormik } from 'formik'; +import { BundleRequest } from '../../../../../api/generated/portal/BundleRequest'; +import { FormAction } from '../../../../../model/CommissionBundle'; +import { mockedDelegatedPSP } from '../../../../../services/__mocks__/institutionsService'; +import { formatDateToDDMMYYYY } from '../../../../../utils/common-utils'; import * as useErrorDispatcher from '@pagopa/selfcare-common-frontend'; import * as useFeatureFlags from '../../../../../hooks/useFeatureFlags'; import * as useUserRole from '../../../../../hooks/useUserRole'; -import {ROLE} from '../../../../../model/RolePermission'; -import {TypeEnum} from '../../../../../api/generated/portal/PSPBundleResource'; +import { ROLE } from '../../../../../model/RolePermission'; +import { TypeEnum } from '../../../../../api/generated/portal/PSPBundleResource'; +import * as useOrganizationType from '../../../../../hooks/useOrganizationType'; let spyOnGetPaymentTypes: jest.SpyInstance; let spyOnGetTouchpoint: jest.SpyInstance; @@ -29,525 +34,567 @@ let spyOnErrorHook: jest.SpyInstance; let spyOnUseFlagValue: jest.SpyInstance; const TestAddEditCommissionBundleForm = ({ - formAction, - initialValues, - injectedStore, - }: { - formAction: string; - initialValues?: BundleRequest; - injectedStore?: ReturnType; + formAction, + initialValues, + injectedStore, +}: { + formAction: string; + initialValues?: BundleRequest; + injectedStore?: ReturnType; }) => { - const formik = useFormik>({ - initialValues: initialValues ?? {}, - onSubmit: async () => jest.fn(), - enableReinitialize: true, - validateOnBlur: true, - validateOnChange: true, - }); - return ( - - - - - - - - - - ); + const formik = useFormik>({ + initialValues: initialValues ?? {}, + onSubmit: async () => jest.fn(), + enableReinitialize: true, + validateOnBlur: true, + validateOnChange: true, + }); + return ( + + + + + + + + + + ); }; const bundleName = 'bundleName'; const bundleDescription = 'description'; describe('', () => { - beforeEach(() => { - spyOnGetPaymentTypes = jest.spyOn( - require('../../../../../services/configurationService'), - 'getPaymentTypes' - ); - spyOnGetTouchpoint = jest.spyOn( - require('../../../../../services/bundleService'), - 'getTouchpoints' - ); - spyOnGetInstitutionService = jest.spyOn( - require('../../../../../services/institutionService'), - 'getBrokerDelegation' - ); - spyOnCreateCommissionBundle = jest.spyOn( - require('../../../../../services/bundleService'), - 'createBundle' - ); - spyOnGetChannelService = jest.spyOn( - require('../../../../../services/channelService'), - 'getChannels' - ); - spyOnErrorHook = jest - .spyOn(useErrorDispatcher, 'useErrorDispatcher') - .mockReturnValue(jest.fn()); - spyOnUseFlagValue = jest.spyOn(useFeatureFlags, 'useFlagValue'); - jest.mock('../../../../../hooks/useUserRole'); - jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ - userRole: ROLE.PSP_ADMIN, - userIsPspAdmin: true, - userIsEcAdmin: false, - userIsPspDirectAdmin: false, - userIsPagopaOperator: false, - userIsAdmin: false, - }); - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); + jest.setTimeout(30000); + beforeEach(() => { + spyOnGetPaymentTypes = jest.spyOn( + require('../../../../../services/configurationService'), + 'getPaymentTypes' + ); + spyOnGetTouchpoint = jest.spyOn( + require('../../../../../services/bundleService'), + 'getTouchpoints' + ); + spyOnGetInstitutionService = jest.spyOn( + require('../../../../../services/institutionService'), + 'getBrokerDelegation' + ); + spyOnCreateCommissionBundle = jest.spyOn( + require('../../../../../services/bundleService'), + 'createBundle' + ); + spyOnGetChannelService = jest.spyOn( + require('../../../../../services/channelService'), + 'getChannels' + ); + spyOnErrorHook = jest + .spyOn(useErrorDispatcher, 'useErrorDispatcher') + .mockReturnValue(jest.fn()); + spyOnUseFlagValue = jest.spyOn(useFeatureFlags, 'useFlagValue'); + jest.spyOn(useUserRole, 'useUserRole').mockReturnValue({ + userRole: ROLE.PSP_ADMIN, + userIsPspAdmin: true, + userIsEcAdmin: false, + userIsPspDirectAdmin: false, + userIsPagopaOperator: false, + userIsAdmin: false, }); + jest.spyOn(useOrganizationType, 'useOrganizationType').mockReturnValue({ + orgInfo: { + types: { + isPsp: true, + isPspBroker: true, + isEc: false, + isEcBroker: false + }, + isSigned: true + }, + orgIsPspDirect: true, + orgIsEcDirect: false, + orgIsBrokerSigned: true, + orgIsPspSigned: true, + orgIsPspBrokerSigned: true, + orgIsEcSigned: false, + orgIsEcBrokerSigned: false, + }); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + cleanup(); + spyOnGetPaymentTypes.mockRestore(); + spyOnGetTouchpoint.mockRestore(); + spyOnGetInstitutionService.mockRestore(); + spyOnCreateCommissionBundle.mockRestore(); + spyOnGetChannelService.mockRestore(); + spyOnErrorHook.mockRestore(); + }); + + const componentRender = ( + formAction: string, + initialValues?: BundleRequest, + injectedStore?: ReturnType + ) => { + render( + + ); - afterEach(() => { - cleanup(); - spyOnGetPaymentTypes.mockRestore(); - spyOnGetTouchpoint.mockRestore(); - spyOnGetInstitutionService.mockRestore(); - spyOnCreateCommissionBundle.mockRestore(); - spyOnGetChannelService.mockRestore(); - spyOnErrorHook.mockRestore(); + const input = { + public: screen + .getByTestId('bundle-type-test') + .querySelector(`[value=${TypeEnum.PUBLIC}]`) as HTMLInputElement, + global: screen + .getByTestId('bundle-type-test') + .querySelector(`[value=${TypeEnum.GLOBAL}]`) as HTMLInputElement, + private: screen + .getByTestId('bundle-type-test') + .querySelector(`[value=${TypeEnum.PRIVATE}]`) as HTMLInputElement, + name: screen.getByTestId('name-test') as HTMLInputElement, + description: screen.getByTestId('description-test') as HTMLInputElement, + paymentType: screen.getByTestId('payment-type-test') as HTMLInputElement, + touchpoint: screen.getByTestId('touchpoint-test') as HTMLInputElement, + minImport: screen.getByTestId('min-import-test') as HTMLInputElement, + maxImport: screen.getByTestId('max-import-test') as HTMLInputElement, + feeApplied: screen.getByTestId('payment-amount-test') as HTMLInputElement, + brokerCodeList: screen + .getByTestId('broker-code-test') + .querySelector('input') as HTMLInputElement, + channelList: screen + .getByTestId('channels-id-test') + .querySelector('input') as HTMLInputElement, + digitalStampYes: screen + .getByTestId('digital-stamp-test') + .querySelector('[value="true"]') as HTMLInputElement, + digitalStampNo: screen + .getByTestId('digital-stamp-test') + .querySelector('[value="false"]') as HTMLInputElement, + digitalStampResYes: screen + .getByTestId('digital-stamp-restriction-test') + .querySelector('[value="true"]') as HTMLInputElement, + digitalStampResNo: screen + .getByTestId('digital-stamp-restriction-test') + .querySelector('[value="false"]') as HTMLInputElement, + fromDate: screen.getByTestId('from-date-test') as HTMLInputElement, + ToDate: screen.getByTestId('to-date-test') as HTMLInputElement, + cartSwitch: screen.getByTestId('bundle-cart') as HTMLInputElement, + }; + + return input; + }; + + test('Test AddEditCommissionBundleForm with all input change in CREATE', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockReturnValue(true); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); - const componentRender = ( - formAction: string, - initialValues?: BundleRequest, - injectedStore?: ReturnType - ) => { - render( - - ); - - const input = { - public: screen - .getByTestId('bundle-type-test') - .querySelector(`[value=${TypeEnum.PUBLIC}]`) as HTMLInputElement, - global: screen - .getByTestId('bundle-type-test') - .querySelector(`[value=${TypeEnum.GLOBAL}]`) as HTMLInputElement, - private: screen - .getByTestId('bundle-type-test') - .querySelector(`[value=${TypeEnum.PRIVATE}]`) as HTMLInputElement, - name: screen.getByTestId('name-test') as HTMLInputElement, - description: screen.getByTestId('description-test') as HTMLInputElement, - paymentType: screen.getByTestId('payment-type-test') as HTMLInputElement, - touchpoint: screen.getByTestId('touchpoint-test') as HTMLInputElement, - minImport: screen.getByTestId('min-import-test') as HTMLInputElement, - maxImport: screen.getByTestId('max-import-test') as HTMLInputElement, - feeApplied: screen.getByTestId('payment-amount-test') as HTMLInputElement, - brokerCodeList: screen - .getByTestId('broker-code-test') - .querySelector('input') as HTMLInputElement, - channelList: screen - .getByTestId('channels-id-test') - .querySelector('input') as HTMLInputElement, - digitalStampYes: screen - .getByTestId('digital-stamp-test') - .querySelector('[value="true"]') as HTMLInputElement, - digitalStampNo: screen - .getByTestId('digital-stamp-test') - .querySelector('[value="false"]') as HTMLInputElement, - digitalStampResYes: screen - .getByTestId('digital-stamp-restriction-test') - .querySelector('[value="true"]') as HTMLInputElement, - digitalStampResNo: screen - .getByTestId('digital-stamp-restriction-test') - .querySelector('[value="false"]') as HTMLInputElement, - fromDate: screen.getByTestId('from-date-test') as HTMLInputElement, - ToDate: screen.getByTestId('to-date-test') as HTMLInputElement, - }; - - return input; - }; + //Change radio group bundle type + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + + fireEvent.click(input.global); + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(true); + expect(input.private.checked).toBe(false); + + fireEvent.click(input.public); + expect(input.public.checked).toBe(true); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + + fireEvent.click(input.private); + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(true); + + // Change input name & description + fireEvent.change(input.name, { target: { value: bundleName } }); + expect(input.name.value).toBe(bundleName); + fireEvent.change(input.description, { target: { value: bundleDescription } }); + expect(input.description.value).toBe(bundleDescription); + + // Change paymentType + fireEvent.mouseDown( + screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.paymentType') + ); + fireEvent.click(screen.getByText(new RegExp('.*Bonifico - SEPA.*', 'i'))); + + expect(input.paymentType).toHaveTextContent('Bonifico - SEPA'); + + // Change touchpoint + fireEvent.mouseDown( + screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.touchpoint') + ); + fireEvent.click(screen.getByText(new RegExp('Tutti', 'i'))); + + expect(input.touchpoint).toHaveTextContent('Tutti'); + + // Change min import number + fireEvent.change(input.minImport, { target: { value: 10 } }); + expect(parseFloat(input.minImport.value)).toBe(10); + // Change max import number + fireEvent.change(input.maxImport, { target: { value: 10 } }); + expect(parseFloat(input.maxImport.value)).toBe(10); + + fireEvent.change(input.feeApplied, { target: { value: '10,8' } }); + expect(input.feeApplied.value).toBe('10,8'); + + fireEvent.change(input.feeApplied, { target: { value: 10.8 } }); + expect(input.feeApplied.value).toBe('10,8'); + + // Change broker code list + expect(input.channelList.disabled).toBe(true); + fireEvent.change(input.brokerCodeList, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + input.brokerCodeList.focus(); + + fireEvent.change(document.activeElement as Element, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + expect(input.brokerCodeList.value).toEqual(mockedDelegatedPSP.delegation_list![1].broker_name); + await waitFor(() => { + expect(spyOnGetChannelService).toBeCalledTimes(1); + expect(input.channelList.disabled).toBe(false); + }); + + fireEvent.change(document.activeElement as Element, { + target: { value: '' }, + }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + await waitFor(() => { + expect(input.channelList.disabled).toBe(true); + }); + + fireEvent.change(input.brokerCodeList, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + input.brokerCodeList.focus(); + + fireEvent.change(document.activeElement as Element, { + target: { value: mockedDelegatedPSP.delegation_list![1].broker_name }, + }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + expect(input.brokerCodeList.value).toEqual(mockedDelegatedPSP.delegation_list![1].broker_name); + await waitFor(() => { + expect(spyOnGetChannelService).toBeCalledTimes(2); + expect(input.channelList.disabled).toBe(false); + }); - test('Test AddEditCommissionBundleForm with all input change in CREATE', async () => { - jest.setTimeout(30000); - const injectStore = createStore(); - spyOnUseFlagValue.mockReturnValue(true); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Change radio group bundle type - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); - - fireEvent.click(input.global); - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(true); - expect(input.private.checked).toBe(false); - - fireEvent.click(input.public); - expect(input.public.checked).toBe(true); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); - - fireEvent.click(input.private); - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(true); - - // Change input name & description - fireEvent.change(input.name, {target: {value: bundleName}}); - expect(input.name.value).toBe(bundleName); - fireEvent.change(input.description, {target: {value: bundleDescription}}); - expect(input.description.value).toBe(bundleDescription); - - // Change paymentType - fireEvent.mouseDown( - screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.paymentType') - ); - fireEvent.click(screen.getByText(new RegExp('.*Bonifico - SEPA.*', 'i'))); - - expect(input.paymentType).toHaveTextContent('Bonifico - SEPA'); - - // Change touchpoint - fireEvent.mouseDown( - screen.getByLabelText('commissionBundlesPage.addEditCommissionBundle.form.touchpoint') - ); - fireEvent.click(screen.getByText(new RegExp('Tutti', 'i'))); - - expect(input.touchpoint).toHaveTextContent('Tutti'); - - // Change min import number - fireEvent.change(input.minImport, {target: {value: 10}}); - expect(parseFloat(input.minImport.value)).toBe(10); - // Change max import number - fireEvent.change(input.maxImport, {target: {value: 10}}); - expect(parseFloat(input.maxImport.value)).toBe(10); - - fireEvent.change(input.feeApplied, {target: {value: '10,8'}}); - expect(input.feeApplied.value).toBe('10,8'); - - fireEvent.change(input.feeApplied, {target: {value: 10.8}}); - expect(input.feeApplied.value).toBe('10,8'); - - // Change broker code list - expect(input.channelList.disabled).toBe(true); - fireEvent.change(input.brokerCodeList, { - target: {value: mockedDelegatedPSP.delegation_list![1].broker_name}, - }); - input.brokerCodeList.focus(); - - fireEvent.change(document.activeElement as Element, { - target: {value: mockedDelegatedPSP.delegation_list![1].broker_name}, - }); - fireEvent.keyDown(document.activeElement as Element, {key: 'ArrowDown'}); - fireEvent.keyDown(document.activeElement as Element, {key: 'Enter'}); - expect(input.brokerCodeList.value).toEqual(mockedDelegatedPSP.delegation_list![1].broker_name); - await waitFor(() => { - expect(spyOnGetChannelService).toBeCalledTimes(1); - expect(input.channelList.disabled).toBe(false); - }); - - fireEvent.change(document.activeElement as Element, { - target: {value: ''}, - }); - fireEvent.keyDown(document.activeElement as Element, {key: 'ArrowDown'}); - fireEvent.keyDown(document.activeElement as Element, {key: 'Enter'}); - await waitFor(() => { - expect(input.channelList.disabled).toBe(true); - }); - - // Change channel id - fireEvent.mouseDown(input.channelList); - fireEvent.select(input.channelList, {target: {value: mockedChannelsIdList[0]}}); - expect(input.channelList.value).toBe(mockedChannelsIdList[0]); - - //Change radio buttons digitalStamp - expect(input.digitalStampYes.checked).toBe(false); - expect(input.digitalStampNo.checked).toBe(true); - expect(input.digitalStampResYes.disabled).toBe(false); - - fireEvent.click(input.digitalStampYes); - expect(input.digitalStampYes.checked).toBe(true); - expect(input.digitalStampNo.checked).toBe(false); - expect(input.digitalStampResYes.disabled).toBe(true); - - fireEvent.click(input.digitalStampNo); - expect(input.digitalStampYes.checked).toBe(false); - expect(input.digitalStampNo.checked).toBe(true); - expect(input.digitalStampResYes.disabled).toBe(false); - - //Change radio buttons digitalStampRes - expect(input.digitalStampResYes.checked).toBe(false); - expect(input.digitalStampResNo.checked).toBe(true); - expect(input.digitalStampYes.disabled).toBe(false); - - fireEvent.click(input.digitalStampResYes); - expect(input.digitalStampResYes.checked).toBe(true); - expect(input.digitalStampResNo.checked).toBe(false); - expect(input.digitalStampYes.disabled).toBe(true); - - fireEvent.click(input.digitalStampResNo); - expect(input.digitalStampResYes.checked).toBe(false); - expect(input.digitalStampResNo.checked).toBe(true); - expect(input.digitalStampYes.disabled).toBe(false); - - // Change dates - const formatDate = (date: Date) => { - const day = date.getDate().toString().padStart(2, '0'); - const month = (date.getMonth() + 1).toString().padStart(2, '0'); - const year = date.getFullYear(); - return `${day}/${month}/${year}`; - }; - - const fromDate = new Date(2028, 9, 27); - const toDate = new Date(2028, 9, 28); - - fireEvent.change(input.fromDate, {target: {value: formatDate(fromDate)}}); - expect(input.fromDate.value).toBe('27/10/2028'); - - fireEvent.change(input.ToDate, {target: {value: formatDate(toDate)}}); - expect(input.ToDate.value).toBe('28/10/2028'); + // Change channel id + fireEvent.change(input.channelList, { + target: { value: mockedChannelsIdList[0] }, }); + input.channelList.focus(); - test('Test AddEditCommissionBundleForm with all input change in EDIT', async () => { - const injectStore = createStore(); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Edit, mockedBundleRequestForEdit, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(true); - expect(input.global.disabled).toBe(true); - expect(input.private.disabled).toBe(true); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(true); - expect(input.private.checked).toBe(false); - - // Check input name & description - expect(input.name.value).toBe(mockedBundleRequest.name); - expect(input.description.value).toBe(mockedBundleRequest.description); - - // Check paymentType - //TODO FIX DEFAULT LIST - // const selectPaymentTypeBtn = await within(input.paymentType).getByRole('button'); - // expect(selectPaymentTypeBtn.textContent).toBe(mockedBundleRequest.paymentType); - - // Check touchpoint - //TODO FIX DEFAULT LIST - // const selectTouchPointBtn = await within(input.touchpoint).getByRole('button'); - // expect(selectTouchPointBtn.textContent).toBe(mockedBundleRequest.paymentType); - - // Check min import number - expect(input.minImport.value).toBe( - (mockedBundleRequest.minPaymentAmount! / 100)?.toString().replace('.', ',') - ); - // Check max import number - expect(input.maxImport.value).toBe( - (mockedBundleRequest.maxPaymentAmount! / 100)?.toString().replace('.', ',') - ); - - expect(input.feeApplied.value).toBe( - (mockedBundleRequest.paymentAmount! / 100)?.toString().replace('.', ',') - ); - - // Check broker code list - expect(input.brokerCodeList.value).toBe( - mockedDelegatedPSP.delegation_list!.find((el) => el.broker_tax_code === mockedBundleRequestForEdit.idBrokerPsp) - ?.broker_name - ); - - // Check channel id - expect(input.channelList.value).toBe(mockedBundleRequest.idChannel); - - //Check radio buttons digitalStamp - expect(input.digitalStampYes.checked).toBe(false); - expect(input.digitalStampNo.checked).toBe(true); - - expect(input.digitalStampYes.disabled).toBe(true); - - //Check radio buttons digitalStampRes - expect(input.digitalStampResYes.checked).toBe(true); - expect(input.digitalStampResNo.checked).toBe(false); - - expect(input.digitalStampResYes.disabled).toBe(false); - - fireEvent.click(input.digitalStampResYes); - expect(input.digitalStampResYes.checked).toBe(true); - expect(input.digitalStampResNo.checked).toBe(false); - expect(input.digitalStampYes.disabled).toBe(true); - - // Check dates - expect(input.fromDate.disabled).toBe(true); - expect(input.fromDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateFrom)); - - expect(input.ToDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateTo)); + fireEvent.change(document.activeElement as Element, { + target: { value: mockedChannelsIdList[0] }, }); + fireEvent.keyDown(document.activeElement as Element, { key: 'ArrowDown' }); + fireEvent.keyDown(document.activeElement as Element, { key: 'Enter' }); + expect(input.channelList.value).toEqual(mockedChannelsIdList[0]); + + //Change radio buttons digitalStamp + expect(input.digitalStampYes.checked).toBe(false); + expect(input.digitalStampNo.checked).toBe(true); + expect(input.digitalStampResYes.disabled).toBe(false); + + fireEvent.click(input.digitalStampYes); + expect(input.digitalStampYes.checked).toBe(true); + expect(input.digitalStampNo.checked).toBe(false); + expect(input.digitalStampResYes.disabled).toBe(true); + + fireEvent.click(input.digitalStampNo); + expect(input.digitalStampYes.checked).toBe(false); + expect(input.digitalStampNo.checked).toBe(true); + expect(input.digitalStampResYes.disabled).toBe(false); + + //Change radio buttons digitalStampRes + expect(input.digitalStampResYes.checked).toBe(false); + expect(input.digitalStampResNo.checked).toBe(true); + expect(input.digitalStampYes.disabled).toBe(false); + + fireEvent.click(input.digitalStampResYes); + expect(input.digitalStampResYes.checked).toBe(true); + expect(input.digitalStampResNo.checked).toBe(false); + expect(input.digitalStampYes.disabled).toBe(true); + + fireEvent.click(input.digitalStampResNo); + expect(input.digitalStampResYes.checked).toBe(false); + expect(input.digitalStampResNo.checked).toBe(true); + expect(input.digitalStampYes.disabled).toBe(false); + + // Change dates + const formatDate = (date: Date) => { + const day = date.getDate().toString().padStart(2, '0'); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const year = date.getFullYear(); + return `${day}/${month}/${year}`; + }; + + const fromDate = new Date(2028, 9, 27); + const toDate = new Date(2028, 9, 28); + + fireEvent.change(input.fromDate, { target: { value: formatDate(fromDate) } }); + expect(input.fromDate.value).toBe('27/10/2028'); + + fireEvent.change(input.ToDate, { target: { value: formatDate(toDate) } }); + expect(input.ToDate.value).toBe('28/10/2028'); + }); - test('Test AddEditCommissionBundleForm feature flag only global types', async () => { - const injectStore = createStore(); - spyOnUseFlagValue.mockReturnValue(false); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(true); - expect(input.global.disabled).toBe(false); - expect(input.private.disabled).toBe(true); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); + test('Test AddEditCommissionBundleForm with all input change in EDIT', async () => { + const injectStore = createStore(); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Edit, mockedBundleRequestForEdit, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); }); - test('Test AddEditCommissionBundleForm feature flag only global & private types', async () => { - const injectStore = createStore(); - spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-private'); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(true); - expect(input.global.disabled).toBe(false); - expect(input.private.disabled).toBe(false); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); + //Check radio group bundle type + expect(input.public.disabled).toBe(true); + expect(input.global.disabled).toBe(true); + expect(input.private.disabled).toBe(true); + + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(true); + expect(input.private.checked).toBe(false); + + // Check input name & description + expect(input.name.value).toBe(mockedBundleRequest.name); + expect(input.description.value).toBe(mockedBundleRequest.description); + + // Check paymentType + //TODO FIX DEFAULT LIST + // const selectPaymentTypeBtn = await within(input.paymentType).getByRole('button'); + // expect(selectPaymentTypeBtn.textContent).toBe(mockedBundleRequest.paymentType); + + // Check touchpoint + //TODO FIX DEFAULT LIST + // const selectTouchPointBtn = await within(input.touchpoint).getByRole('button'); + // expect(selectTouchPointBtn.textContent).toBe(mockedBundleRequest.paymentType); + + // Check min import number + expect(input.minImport.value).toBe( + (mockedBundleRequest.minPaymentAmount! / 100)?.toString().replace('.', ',') + ); + // Check max import number + expect(input.maxImport.value).toBe( + (mockedBundleRequest.maxPaymentAmount! / 100)?.toString().replace('.', ',') + ); + + expect(input.feeApplied.value).toBe( + (mockedBundleRequest.paymentAmount! / 100)?.toString().replace('.', ',') + ); + + // Check broker code list + expect(input.brokerCodeList.value).toBe( + mockedDelegatedPSP.delegation_list!.find( + (el) => el.broker_tax_code === mockedBundleRequestForEdit.idBrokerPsp + )?.broker_name + ); + + // Check channel id + expect(input.channelList.value).toBe(mockedBundleRequest.idChannel); + + //Check radio buttons digitalStamp + expect(input.digitalStampYes.checked).toBe(false); + expect(input.digitalStampNo.checked).toBe(true); + + expect(input.digitalStampYes.disabled).toBe(true); + + //Check radio buttons digitalStampRes + expect(input.digitalStampResYes.checked).toBe(true); + expect(input.digitalStampResNo.checked).toBe(false); + + expect(input.digitalStampResYes.disabled).toBe(false); + + fireEvent.click(input.digitalStampResYes); + expect(input.digitalStampResYes.checked).toBe(true); + expect(input.digitalStampResNo.checked).toBe(false); + expect(input.digitalStampYes.disabled).toBe(true); + + // Check dates + expect(input.fromDate.disabled).toBe(true); + expect(input.fromDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateFrom)); + + expect(input.ToDate.value).toBe(formatDateToDDMMYYYY(mockedBundleRequest.validityDateTo)); + }); + + test('Test AddEditCommissionBundleForm feature flag only global types', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockReturnValue(false); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); - test('Test AddEditCommissionBundleForm feature flag only global & public types', async () => { - const injectStore = createStore(); - spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-public'); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - const {...input} = componentRender(FormAction.Create, undefined, injectStore); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); - - //Check radio group bundle type - expect(input.public.disabled).toBe(false); - expect(input.global.disabled).toBe(false); - expect(input.private.disabled).toBe(true); - - expect(input.public.checked).toBe(false); - expect(input.global.checked).toBe(false); - expect(input.private.checked).toBe(false); + //Check radio group bundle type + expect(input.public.disabled).toBe(true); + expect(input.global.disabled).toBe(false); + expect(input.private.disabled).toBe(true); + + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + }); + + test('Test AddEditCommissionBundleForm feature flag only global & private types', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-private'); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); + }); + + //Check radio group bundle type + expect(input.public.disabled).toBe(true); + expect(input.global.disabled).toBe(false); + expect(input.private.disabled).toBe(false); + + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + }); + + test('Test AddEditCommissionBundleForm feature flag only global & public types', async () => { + const injectStore = createStore(); + spyOnUseFlagValue.mockImplementation((arg) => arg === 'commission-bundles-public'); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + const { ...input } = componentRender(FormAction.Create, undefined, injectStore); + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); - test('Test fetch error getPaymentTypes', async () => { - const mockError = new Error('API error message getPaymentTypes'); - spyOnGetPaymentTypes.mockRejectedValue(mockError); + //Check radio group bundle type + expect(input.public.disabled).toBe(false); + expect(input.global.disabled).toBe(false); + expect(input.private.disabled).toBe(true); - componentRender(FormAction.Create); + expect(input.public.checked).toBe(false); + expect(input.global.checked).toBe(false); + expect(input.private.checked).toBe(false); + }); - await waitFor(() => { - expect(spyOnGetPaymentTypes).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - }); + test('Test fetch error getPaymentTypes', async () => { + const mockError = new Error('API error message getPaymentTypes'); + spyOnGetPaymentTypes.mockRejectedValue(mockError); + + componentRender(FormAction.Create); + + await waitFor(() => { + expect(spyOnGetPaymentTypes).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); }); + }); - test('Test fetch error getTouchpoint', async () => { - const mockError = new Error('API error message GetTouchpoint'); - spyOnGetTouchpoint.mockRejectedValue(mockError); + test('Test fetch error getTouchpoint', async () => { + const mockError = new Error('API error message GetTouchpoint'); + spyOnGetTouchpoint.mockRejectedValue(mockError); - componentRender(FormAction.Create); + componentRender(FormAction.Create); - await waitFor(() => { - expect(spyOnGetTouchpoint).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetTouchpoint).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); }); + }); - test('Test fetch error getBrokerDelegation', async () => { - const mockError = new Error('API error message getBrokerDelegation'); - spyOnGetInstitutionService.mockRejectedValue(mockError); + test('Test fetch error getBrokerDelegation', async () => { + const mockError = new Error('API error message getBrokerDelegation'); + spyOnGetInstitutionService.mockRejectedValue(mockError); - componentRender(FormAction.Create); + componentRender(FormAction.Create); - await waitFor(() => { - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); + }); - test('Test fetch getBrokerDelegation empty list', async () => { - spyOnGetInstitutionService.mockReturnValue(new Promise((resolve) => resolve([]))); + test('Test fetch getBrokerDelegation empty list', async () => { + spyOnGetInstitutionService.mockReturnValue(new Promise((resolve) => resolve([]))); - componentRender(FormAction.Create); + componentRender(FormAction.Create); - await waitFor(() => { - expect(spyOnGetInstitutionService).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - expect(spyOnGetChannelService).not.toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetInstitutionService).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); + expect(spyOnGetChannelService).not.toHaveBeenCalled(); }); + }); + + test('Test fetch getChannels empty list', async () => { + spyOnGetInstitutionService.mockReturnValue(Promise.resolve(mockedDelegatedPSP)); + spyOnGetChannelService.mockReturnValue(new Promise((resolve) => resolve([]))); + const injectStore = createStore(); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - test('Test fetch getChannels empty list', async () => { - spyOnGetChannelService.mockReturnValue(new Promise((resolve) => resolve([]))); - const injectStore = createStore(); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - - await waitFor(() => { - expect(spyOnGetChannelService).toHaveBeenCalled(); - expect(spyOnErrorHook).toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnGetChannelService).toHaveBeenCalled(); + expect(spyOnErrorHook).toHaveBeenCalled(); }); + }); + + test('Test fetch getChannels throw error', async () => { + const mockError = new Error('API error message getChannels'); + spyOnGetChannelService.mockRejectedValue(mockError); + const injectStore = createStore(); + await waitFor(() => + injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) + ); + componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - test('Test fetch getChannels throw error', async () => { - const mockError = new Error('API error message getChannels'); - spyOnGetChannelService.mockRejectedValue(mockError); - const injectStore = createStore(); - await waitFor(() => - injectStore.dispatch(partiesActions.setPartySelected(pspOperatorSignedDirect)) - ); - componentRender(FormAction.Edit, mockedBundleRequest, injectStore); - - await waitFor(() => { - expect(spyOnErrorHook).toHaveBeenCalled(); - expect(spyOnGetChannelService).toHaveBeenCalled(); - }); + await waitFor(() => { + expect(spyOnErrorHook).toHaveBeenCalled(); + expect(spyOnGetChannelService).toHaveBeenCalled(); }); + }); }); diff --git a/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx b/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx index 4cc1b56e3..4ee2e91c3 100644 --- a/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx +++ b/src/pages/commisionalBundles/detail/components/CommissionBundleDetailConfiguration.tsx @@ -1,129 +1,134 @@ -import {Divider, Typography, Paper, Grid} from '@mui/material'; -import {useTranslation, TFunction} from 'react-i18next'; -import {Box} from '@mui/system'; -import {ButtonNaked} from '@pagopa/mui-italia'; -import {TitleBox} from '@pagopa/selfcare-common-frontend'; -import {useState} from 'react'; -import {PaddedDrawer} from '../../../../components/PaddedDrawer'; +import { Divider, Typography, Paper, Grid } from '@mui/material'; +import { useTranslation, TFunction } from 'react-i18next'; +import { Box } from '@mui/system'; +import { ButtonNaked } from '@pagopa/mui-italia'; +import { TitleBox } from '@pagopa/selfcare-common-frontend'; +import { useState } from 'react'; +import { PaddedDrawer } from '../../../../components/PaddedDrawer'; import { - formatBooleanValueToYesOrNo, - formatCurrencyEur, - formatDateToDDMMYYYY, + formatBooleanValueToYesOrNo, + formatCurrencyEur, + formatDateToDDMMYYYY, } from '../../../../utils/common-utils'; -import {BundleResource} from '../../../../model/CommissionBundle'; -import {CIBundleResource, CiBundleStatusEnum} from '../../../../api/generated/portal/CIBundleResource'; +import { BundleResource } from '../../../../model/CommissionBundle'; +import { + CIBundleResource, + CiBundleStatusEnum, +} from '../../../../api/generated/portal/CIBundleResource'; const bundleConfigurationFields = { - col1: [ - ['paymentType', 'commissionBundlesPage.addEditCommissionBundle.form.paymentType'], - ['touchpoint', 'commissionBundlesPage.addEditCommissionBundle.form.touchpoint'], - ['paymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.commission'], - ], - col2: [ - ['minPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.minImport'], - ['maxPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.maxImport'], - ['idBrokerPsp', 'commissionBundlesPage.addEditCommissionBundle.form.brokerCode'], - ['pspBusinessName', 'commissionBundlesPage.addEditCommissionBundle.form.pspName'], - ], - col3: [ - ['idChannel', 'commissionBundlesPage.addEditCommissionBundle.form.channelCode'], - ['digitalStamp', 'commissionBundlesPage.addEditCommissionBundle.form.paymentWithDigitalStamp'], - [ - 'digitalStampRestriction', - 'commissionBundlesPage.addEditCommissionBundle.form.paymentOnlyDigitalStamp', - ], + col1: [ + ['paymentType', 'commissionBundlesPage.addEditCommissionBundle.form.paymentType'], + ['touchpoint', 'commissionBundlesPage.addEditCommissionBundle.form.touchpoint'], + ['paymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.commission'], + ], + col2: [ + ['minPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.minImport'], + ['maxPaymentAmount', 'commissionBundlesPage.addEditCommissionBundle.form.maxImport'], + ['idBrokerPsp', 'commissionBundlesPage.addEditCommissionBundle.form.brokerCode'], + ['pspBusinessName', 'commissionBundlesPage.addEditCommissionBundle.form.pspName'], + ], + col3: [ + ['idChannel', 'commissionBundlesPage.addEditCommissionBundle.form.channelCode'], + ['cart', 'commissionBundlesPage.addEditCommissionBundle.form.cart'], + ['digitalStamp', 'commissionBundlesPage.addEditCommissionBundle.form.paymentWithDigitalStamp'], + [ + 'digitalStampRestriction', + 'commissionBundlesPage.addEditCommissionBundle.form.paymentOnlyDigitalStamp', ], - col4: [ - ['validityDateFrom', 'commissionBundlesPage.list.headerFields.startDate'], - ['validityDateTo', 'commissionBundlesPage.list.headerFields.endDate'], - ['lastUpdatedDate', 'commissionBundlesPage.commissionBundleDetail.lastChange'], - ] + ], + col4: [ + ['validityDateFrom', 'commissionBundlesPage.list.headerFields.startDate'], + ['validityDateTo', 'commissionBundlesPage.list.headerFields.endDate'], + ['lastUpdatedDate', 'commissionBundlesPage.commissionBundleDetail.lastChange'], + ], }; const formatConfigValues = (value: any, t: TFunction<'translation'>) => { - if (typeof value === 'string' && value) { - return t(value); - } - if (typeof value === 'boolean') { - return formatBooleanValueToYesOrNo(value, t); - } - if (typeof value === 'number') { - return formatCurrencyEur(value); - } - if (typeof value === 'object') { - return formatDateToDDMMYYYY(value); - } - return '-'; + if (typeof value === 'string' && value) { + return t(value); + } + if (typeof value === 'boolean') { + return formatBooleanValueToYesOrNo(value, t); + } + if (typeof value === 'number') { + return formatCurrencyEur(value); + } + if (typeof value === 'object') { + return formatDateToDDMMYYYY(value); + } + return '-'; }; export default function CommissionBundleDetailConfiguration({ - bundleDetail, - }: { - bundleDetail: BundleResource; + bundleDetail, +}: { + bundleDetail: BundleResource; }) { - const {t} = useTranslation(); - const [openDrawer, setOpenDrawer] = useState(false); + const { t } = useTranslation(); + const [openDrawer, setOpenDrawer] = useState(false); - const columns: Array>> = new Array(bundleConfigurationFields.col1); + const columns: Array>> = new Array(bundleConfigurationFields.col1); - const mapColumn = (col: Array>, isDrawer: boolean, isFirstColumn?: boolean) => - col.map((entry: Array, index: number) => ( - - {isDrawer && (!isFirstColumn || index !== 0) && } - - {t(entry[1])} - - - {formatConfigValues(bundleDetail?.[entry[0] as keyof BundleResource], t)} - - - )); + const mapColumn = (col: Array>, isDrawer: boolean, isFirstColumn?: boolean) => + col.map((entry: Array, index: number) => ( + + {isDrawer && (!isFirstColumn || index !== 0) && } + + {t(entry[1])} + + + {formatConfigValues(bundleDetail?.[entry[0] as keyof BundleResource], t)} + + + )); - return ( - 2 - ? '370px' - : '310px', - display: 'flex', - flexDirection: 'column', - }} - > - - {t('commissionBundlesPage.commissionBundleDetail.configuration')} - - - {columns.map((col, i) => ( - - {mapColumn(col, false)} - - ))} - - setOpenDrawer(true)} - sx={{color: 'primary.main', mt: 'auto', justifyContent: 'start'}} - weight="default" - data-testid="show-more-bundle-configuration-test" - > - + {t('general.showMore')} - - - <> - - {Object.values(bundleConfigurationFields).map((col, i) => mapColumn(col, true, i === 0))} - - - - ); + ? '370px' + : '310px', + display: 'flex', + flexDirection: 'column', + }} + > + + {t('commissionBundlesPage.commissionBundleDetail.configuration')} + + + {columns.map((col, i) => ( + + {mapColumn(col, false)} + + ))} + + setOpenDrawer(true)} + sx={{ color: 'primary.main', mt: 'auto', justifyContent: 'start' }} + weight="default" + data-testid="show-more-bundle-configuration-test" + > + + {t('general.showMore')} + + + <> + + {Object.values(bundleConfigurationFields).map((col, i) => mapColumn(col, true, i === 0))} + + + + ); } diff --git a/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx b/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx index 7bba95acf..45eb5726c 100644 --- a/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx +++ b/src/pages/commisionalBundles/detail/components/__tests__/CommissionBundleDetailConfiguration.test.tsx @@ -1,83 +1,85 @@ -import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react'; +import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; import React from 'react'; import CommissionBundleDetailConfiguration from '../CommissionBundleDetailConfiguration'; import { - mockedCommissionBundlePspDetailGlobal, - mockedCommissionBundlePspDetailPrivate, - mockedCommissionBundlePspDetailPublic, + mockedCommissionBundlePspDetailGlobal, + mockedCommissionBundlePspDetailPrivate, + mockedCommissionBundlePspDetailPublic, } from '../../../../../services/__mocks__/bundleService'; beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(() => { - }); - jest.spyOn(console, 'warn').mockImplementation(() => { - }); + jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(console, 'warn').mockImplementation(() => {}); }); afterEach(cleanup); describe('', () => { - test('render component CommissionBundleDetailConfiguration bundle type GLOBAl', async () => { - render( - - ); + test('render component CommissionBundleDetailConfiguration bundle type GLOBAl', async () => { + render( + + ); - await waitFor(async () => { - const buttonDrawer = await screen.findByTestId('show-more-bundle-configuration-test'); - expect(buttonDrawer).toBeDefined(); - expect(screen.queryAllByTestId('detail-column').length).toBe(3); + let buttonDrawer; + await waitFor(async () => { + buttonDrawer = screen.queryByTestId('show-more-bundle-configuration-test'); + expect(buttonDrawer).toBeDefined(); + expect(screen.queryAllByTestId('detail-column').length).toBe(3); + }); - //Open Drawer - fireEvent.click(buttonDrawer); - expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); - expect(screen.queryAllByTestId('detail-column').length).toBe(16); - }); + //Open Drawer + fireEvent.click(buttonDrawer); + expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); + expect(screen.queryAllByTestId('detail-column').length).toBe(17); - const closeDrawerButton = screen.getByTestId('close-drawer-button'); - fireEvent.click(closeDrawerButton); + const closeDrawerButton = screen.getByTestId('close-drawer-button'); + fireEvent.click(closeDrawerButton); - await waitFor(() => { - expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); - }); + await waitFor(() => { + expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); }); + }); - test('render component CommissionBundleDetailConfiguration bundle type PRIVATE', async () => { - render( - - ); + test('render component CommissionBundleDetailConfiguration bundle type PRIVATE', async () => { + render( + + ); - await waitFor(async () => { - const buttonDrawer = await screen.findByTestId('show-more-bundle-configuration-test'); - expect(buttonDrawer).toBeDefined(); - expect(screen.queryAllByTestId('detail-column').length).toBe(3); + let buttonDrawer; + await waitFor(async () => { + buttonDrawer = screen.queryByTestId('show-more-bundle-configuration-test'); + expect(buttonDrawer).toBeDefined(); + expect(screen.queryAllByTestId('detail-column').length).toBe(3); + }); - //Open Drawer - fireEvent.click(buttonDrawer); - expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); - expect(screen.queryAllByTestId('detail-column').length).toBe(16); - }); + //Open Drawer + fireEvent.click(buttonDrawer); + expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); + expect(screen.queryAllByTestId('detail-column').length).toBe(17); - const closeDrawerButton = screen.getByTestId('close-drawer-button'); - fireEvent.click(closeDrawerButton); + const closeDrawerButton = screen.getByTestId('close-drawer-button'); + fireEvent.click(closeDrawerButton); - await waitFor(() => { - expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); - }); + await waitFor(() => { + expect(screen.queryByTestId('padded-drawer')).not.toBeInTheDocument(); }); + }); - test('render component CommissionBundleDetailConfiguration bundle type PUBLIC', async () => { - render( - - ); - - await waitFor(async () => { - const buttonDrawer = await screen.findByTestId('show-more-bundle-configuration-test'); - expect(buttonDrawer).toBeDefined(); - expect(screen.queryAllByTestId('detail-column').length).toBe(3); + test('render component CommissionBundleDetailConfiguration bundle type PUBLIC', async () => { + render( + + ); - //Open Drawer - fireEvent.click(buttonDrawer); - expect(screen.queryAllByTestId('detail-column').length).toBe(16); - }); + let buttonDrawer; + await waitFor(async () => { + buttonDrawer = screen.queryByTestId('show-more-bundle-configuration-test'); + expect(buttonDrawer).toBeDefined(); + expect(screen.queryAllByTestId('detail-column').length).toBe(3); }); + + //Open Drawer + fireEvent.click(buttonDrawer); + expect(screen.queryByTestId('padded-drawer')).toBeInTheDocument(); + expect(screen.queryAllByTestId('detail-column').length).toBe(17); + }); }); diff --git a/src/services/__mocks__/bundleService.ts b/src/services/__mocks__/bundleService.ts index ffd59422a..6df433bbe 100644 --- a/src/services/__mocks__/bundleService.ts +++ b/src/services/__mocks__/bundleService.ts @@ -120,6 +120,7 @@ const baseCommissionBundlePspDetail: PSPBundleResource = { validityDateTo: new Date('2028-02-22'), insertedDate: new Date('2024-02-15T09:36:04.792731104'), lastUpdatedDate: new Date('2024-02-17T09:36:04.792731104'), + cart:false }; export const mockedCommissionBundlePspDetailGlobal: PSPBundleResource = { @@ -197,7 +198,7 @@ export const mockedBundleRequestForEdit: BundleRequest = { digitalStamp: false, digitalStampRestriction: true, idChannel: '97735020584_01', - idBrokerPsp: '800011104871', + idBrokerPsp: 'idBrokerPsp', name: 'Commission Bundle Name', description: 'Commission bundle description', paymentAmount: 5556, diff --git a/src/services/__mocks__/channelService.ts b/src/services/__mocks__/channelService.ts index 7398df01a..ef4f6488c 100644 --- a/src/services/__mocks__/channelService.ts +++ b/src/services/__mocks__/channelService.ts @@ -24,30 +24,35 @@ export const mockedChannels: WrapperChannelsResource = { enabled: true, broker_description: 'Intermediario XPAY', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 2, }, { channel_code: 'XPAY_03', enabled: true, broker_description: 'Intermediario XPAY', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, { channel_code: 'WFESP_07_tot', enabled: true, broker_description: 'Intermediario per test WFESP', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, { channel_code: 'WFESP_07_salvo', enabled: false, broker_description: 'Intermediario per test WFESP', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, { channel_code: 'WFESP_07_ila', enabled: true, broker_description: 'Intermediario per test WFESP', wrapperStatus: WrapperStatusEnum.APPROVED, + primitive_version: 1, }, ], page_info: { @@ -216,30 +221,35 @@ export const mockedChannelsMerged: WrapperChannelsResource = { createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.APPROVED, modifiedAt: new Date(), + primitive_version: 2, }, { channel_code: '97735020584_02', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_CHECK, modifiedAt: new Date(), + primitive_version: 1, }, { channel_code: '97735020584_03', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_CHECK_UPDATE, modifiedAt: new Date(), + primitive_version: 1, }, { channel_code: '97735020584_04', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_FIX, modifiedAt: new Date(), + primitive_version: 1, }, { channel_code: '97735020584_05', createdAt: new Date('2023-05-04T17:52:33.993Z'), wrapperStatus: WrapperStatusEnum.TO_FIX_UPDATE, modifiedAt: new Date(), + primitive_version: 1, }, ], }; diff --git a/src/services/__mocks__/institutionsService.ts b/src/services/__mocks__/institutionsService.ts index 30e480c8a..0980c4aa1 100644 --- a/src/services/__mocks__/institutionsService.ts +++ b/src/services/__mocks__/institutionsService.ts @@ -48,7 +48,7 @@ export const mockedDelegatedPSP: DelegationResource = { institution_name: 'Azienda Pubblica di Servizi alla Persona Test 1', broker_name: 'PSP1', tax_code: '800011104871', - broker_tax_code: '800011104871', + broker_tax_code: 'idBrokerPsp', }, { broker_id: 'fce5332f-56a4-45b8-8fdc-7667ccdfca5e2', From 0a8e85f4b85fbc36c474f78ed6d47dc0fe3f47d0 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Wed, 10 Jul 2024 13:35:43 +0000 Subject: [PATCH 31/73] Bump to version 1.26.4-3-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1eb709560..d756ed497 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.26.4-2-next", + "version": "1.26.4-3-next", "homepage": "ui", "private": true, "scripts": { From 3fef2d67e648dae1f755ef331eacfb81b9d65a05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:57:40 +0200 Subject: [PATCH 32/73] build(deps): Bump axios from 0.28.1 to 1.7.2 (#599) Bumps [axios](https://github.com/axios/axios) from 0.28.1 to 1.7.2. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v0.28.1...v1.7.2) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacopo Carlini --- package.json | 2 +- yarn.lock | 19 +++++++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index f67608ec8..1e7cfeb28 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@types/papaparse": "^5.3.14", "@types/react-router-dom": "^5.1.8", "@types/react-router-hash-link": "^2.4.5", - "axios": "^0.28.0", + "axios": "^1.7.2", "buffer": "^6.0.3", "date-fns": "^2.30.0", "formik": "^2.2.9", diff --git a/yarn.lock b/yarn.lock index c772ab529..66ba35216 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4085,12 +4085,12 @@ axe-core@^4.3.5: resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.4.2.tgz" integrity sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA== -axios@^0.28.0: - version "0.28.1" - resolved "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz" - integrity sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ== +axios@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" + integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== dependencies: - follow-redirects "^1.15.0" + follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -6482,14 +6482,9 @@ flatted@^3.1.0: resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== -follow-redirects@^1.0.0: - version "1.15.1" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz" - integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== - -follow-redirects@^1.15.0: +follow-redirects@^1.0.0, follow-redirects@^1.15.6: version "1.15.6" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: From b84a046077eb0aaa7933b19733417fa67f5d3c86 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Mon, 15 Jul 2024 15:57:58 +0000 Subject: [PATCH 33/73] Bump to version 1.27.0-1-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e7cfeb28..2475f972a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.27.0", + "version": "1.27.0-1-next", "homepage": "ui", "private": true, "scripts": { From 63558813317626e06c17ab6b3f608a846b2e72e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:58:07 +0200 Subject: [PATCH 34/73] build(deps): Bump @types/node from 20.10.1 to 20.14.10 (#600) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.10.1 to 20.14.10. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacopo Carlini --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2475f972a..160d919e1 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@mui/x-date-pickers": "^5.0.3", "@pagopa/mui-italia": "0.8.12", "@pagopa/selfcare-common-frontend": "^1.11.8", - "@types/node": "^20.9.4", + "@types/node": "^20.14.10", "@types/papaparse": "^5.3.14", "@types/react-router-dom": "^5.1.8", "@types/react-router-hash-link": "^2.4.5", diff --git a/yarn.lock b/yarn.lock index 66ba35216..eb69b834c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3027,10 +3027,10 @@ resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/node@*", "@types/node@^20.9.4": - version "20.10.1" - resolved "https://registry.npmjs.org/@types/node/-/node-20.10.1.tgz" - integrity sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg== +"@types/node@*", "@types/node@^20.14.10": + version "20.14.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a" + integrity sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ== dependencies: undici-types "~5.26.4" From 07c0740cff5fcc9913041bfcb5177bb2ac36e4c4 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Mon, 15 Jul 2024 15:58:27 +0000 Subject: [PATCH 35/73] Bump to version 1.27.0-2-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 160d919e1..c8d0e0a53 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.27.0-1-next", + "version": "1.27.0-2-next", "homepage": "ui", "private": true, "scripts": { From 2b4c6f91ffdeea5ab01831f129ebb9d03711f14a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:58:32 +0200 Subject: [PATCH 36/73] build(deps): Bump @mui/icons-material from 5.15.9 to 5.16.1 (#608) Bumps [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) from 5.15.9 to 5.16.1. - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/v5.16.1/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v5.16.1/packages/mui-icons-material) --- updated-dependencies: - dependency-name: "@mui/icons-material" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jacopo Carlini --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c8d0e0a53..737858556 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "dependencies": { "@mui/base": "5.0.0-alpha.79", - "@mui/icons-material": "^5.15.9", + "@mui/icons-material": "^5.16.1", "@mui/lab": "^5.0.0-alpha.80", "@mui/material": "^5.8.2", "@mui/system": "^5.15.20", diff --git a/yarn.lock b/yarn.lock index eb69b834c..64f536de8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2194,10 +2194,10 @@ resolved "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.18.tgz" integrity sha512-/9pVk+Al8qxAjwFUADv4BRZgMpZM4m5E+2Q/20qhVPuIJWqKp4Ie4tGExac6zu93rgPTYVQGgu+1vjiT0E+cEw== -"@mui/icons-material@^5.15.9", "@mui/icons-material@^5.8.2": - version "5.15.9" - resolved "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.15.9.tgz" - integrity sha512-6tLQoM6RylQuDnHR6qQay0G0pJgKmrhn5MIm0IfrwtmSO8eV5iUFR+nNUTXsWa24gt7ZbIKnJ962UlYaeXa4bg== +"@mui/icons-material@^5.16.1", "@mui/icons-material@^5.8.2": + version "5.16.1" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.16.1.tgz#abb72fa73d508a50a1b2e0b15cb5e4f89ef31ff9" + integrity sha512-ogQPweYba4+5XZykilwxn2/oS78uwoQ0BVBpOhhCJo0ooZsqTTsalhzP2qD/RdGqMQ8xyXPz1sYM2djTruVVVA== dependencies: "@babel/runtime" "^7.23.9" From 038b7d36268a076b647141ab53d2493d222b3a17 Mon Sep 17 00:00:00 2001 From: pagopa-github-bot Date: Mon, 15 Jul 2024 15:58:47 +0000 Subject: [PATCH 37/73] Bump to version 1.27.0-3-next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 737858556..1460408a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pagopa-selfcare-backoffice-frontend", - "version": "1.27.0-2-next", + "version": "1.27.0-3-next", "homepage": "ui", "private": true, "scripts": { From a8bef9aaad20fd4a707d1731a13625748a12e163 Mon Sep 17 00:00:00 2001 From: Alessio Cialini <63233981+alessio-cialini@users.noreply.github.com> Date: Thu, 18 Jul 2024 09:29:39 +0200 Subject: [PATCH 38/73] [VAS-1166] feat: add tos and privacy pages (#607) * [VAS-1116] feat: add privacy and tos pages * [VAS-1116] feat: Updated footer config, and management for the snippet pages * [VAS-1116] feat: Updated tests * [VAS-1116] feat: Updated Snippet.tsx * [VAS-1116] feat: Updated Snippet.tsx and tests * [VAS-1116] feat: Updated App.test.tsx * [VAS-1116] feat: Updated App.test.tsx * Bump to version 1.26.4-4-VAS-1166-feat-add-tos-and-privacy-pages [skip ci] * [VAS-1116] feat: Updated App.test * Bump to version 1.26.4-5-VAS-1166-feat-add-tos-and-privacy-pages [skip ci] --------- Co-authored-by: pagopa-github-bot Co-authored-by: Jacopo Carlini --- src/App.tsx | 25 +- src/__tests__/App.test.tsx | 84 +++++- src/components/CommonFooter/CommonFooter.tsx | 248 ++++++++++++++++++ src/components/Layout/Layout.tsx | 4 +- src/components/Snippet/Snippet.tsx | 33 +++ .../Snippet/__tests__/Snippet.test.tsx | 33 +++ src/components/TOS/TOSWall.tsx | 14 +- src/data/privacy.json | 4 + src/data/tos.json | 2 +- src/locale/it.json | 44 +++- src/pages/tos/TOS.tsx | 45 ---- src/pages/tos_and_privacy/TOS_AND_PRIVACY.tsx | 34 +++ .../__tests__/TOS_AND_PRIVACY.test.tsx | 62 +++++ src/routes.tsx | 3 +- src/utils/dom-utility.ts | 33 +++ src/utils/onetrust-utils.ts | 10 + 16 files changed, 614 insertions(+), 64 deletions(-) create mode 100644 src/components/CommonFooter/CommonFooter.tsx create mode 100644 src/components/Snippet/Snippet.tsx create mode 100644 src/components/Snippet/__tests__/Snippet.test.tsx create mode 100644 src/data/privacy.json delete mode 100644 src/pages/tos/TOS.tsx create mode 100644 src/pages/tos_and_privacy/TOS_AND_PRIVACY.tsx create mode 100644 src/pages/tos_and_privacy/__tests__/TOS_AND_PRIVACY.test.tsx create mode 100644 src/utils/dom-utility.ts create mode 100644 src/utils/onetrust-utils.ts diff --git a/src/App.tsx b/src/App.tsx index f98894c50..94cb33f90 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -48,13 +48,17 @@ import StationsPage from './pages/stations/list/StationsPage'; import StationAssociateECPage from './pages/stations/stationAssociateEC/StationAssociateECPage'; import StationECListPage from './pages/stations/stationECList/StationECPage'; import PaymentNoticesPage from './pages/notices/PaymentNoticesPage'; -import { TOS } from './pages/tos/TOS'; +import { TOS_AND_PRIVACY } from './pages/tos_and_privacy/TOS_AND_PRIVACY'; import routes from './routes'; import CommissionBundleDetailActivationPage from './pages/commisionalBundles/detail/CommissionBundleDetailActivationPage'; import { getMaintenanceMessage } from './services/maintenanceService'; import { MaintenanceMessage } from './api/generated/portal/MaintenanceMessage'; import CommissionBundleDetailOffersAddRecipientsPage from './pages/commisionalBundles/detail/CommissionBundleDetailOffersAddRecipientsPage'; import PaymentNoticesAddEditPage from './pages/notices/addEdit/PaymentNoticesAddEditPage'; +import { rewriteLinks } from './utils/onetrust-utils'; +import tosJson from './data/tos.json'; +import privacyJson from './data/privacy.json'; + const SecuredRoutes = withLogin( withFeatureFlags( @@ -87,10 +91,10 @@ const SecuredRoutes = withLogin( ); } - if (!isTOSAccepted && location.pathname !== routes.TOS) { + if (!isTOSAccepted && location.pathname !== routes.TOS && location.pathname !== routes.PRIVACY) { return ( - + ); } @@ -315,8 +319,21 @@ const SecuredRoutes = withLogin( - + { + rewriteLinks(routes.TOS, '.otnotice-content a');}} + /> + + + + { + rewriteLinks(routes.PRIVACY, '.otnotice-content a');}} + /> + diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index e517b0908..865719474 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -4,7 +4,7 @@ import {ThemeProvider} from '@mui/system'; import {theme} from '@pagopa/mui-italia'; import {createMemoryHistory} from 'history'; import {Provider} from 'react-redux'; -import {BrowserRouter} from 'react-router-dom'; +import {BrowserRouter, MemoryRouter, Route} from 'react-router-dom'; import {createStore} from '../redux/store'; import App from '../App'; import {verifyMockExecution as verifyLoginMockExecution} from '../decorators/__mocks__/withLogin'; @@ -19,12 +19,6 @@ import {mockedPartyProducts} from '../services/__mocks__/productService'; const mockSignOutFn = jest.fn(); -jest.mock('../hooks/useTOSAgreementLocalStorage', () => () => ({ - isTOSAccepted: true, - acceptTOS: mockSignOutFn, - acceptedTOS: '', -})); - jest.mock('../decorators/withLogin'); jest.mock('../decorators/withParties'); jest.mock('../decorators/withSelectedParty'); @@ -61,9 +55,85 @@ const renderApp = ( }; test('Test rendering', () => { + + jest.mock('../hooks/useTOSAgreementLocalStorage', () => () => ({ + isTOSAccepted: true, + acceptTOS: mockSignOutFn, + acceptedTOS: '', + })); + const {store} = renderApp(); verifyLoginMockExecution(store.getState()); verifyPartiesMockExecution(store.getState()); verifySelectedPartyProductsMockExecution(store.getState()); }); + +test('Test rendering tosNotAccepted', () => { + + jest.mock('../hooks/useTOSAgreementLocalStorage', () => () => ({ + isTOSAccepted: false + })); + + const store = createStore(); + const history = createMemoryHistory(); + + render( + + + + + + + + + + ); + +}); + +test('Test rendering tos', () => { + + jest.mock('../hooks/useTOSAgreementLocalStorage', () => () => ({ + isTOSAccepted: false + })); + + const store = createStore(); + const history = createMemoryHistory(); + + render( + + + + + + + + + + ); + +}); + +test('Test rendering privacy', () => { + + jest.mock('../hooks/useTOSAgreementLocalStorage', () => () => ({ + isTOSAccepted: false + })); + + const store = createStore(); + const history = createMemoryHistory(); + + render( + + + + + + + + + + ); + +}); diff --git a/src/components/CommonFooter/CommonFooter.tsx b/src/components/CommonFooter/CommonFooter.tsx new file mode 100644 index 000000000..3cca948fa --- /dev/null +++ b/src/components/CommonFooter/CommonFooter.tsx @@ -0,0 +1,248 @@ +import { + Footer as MuiItaliaFooter, + FooterLinksType, + PreLoginFooterLinksType, +} from '@pagopa/mui-italia/dist/components/Footer/Footer'; +import { Trans, useTranslation } from 'react-i18next'; +import { useState } from 'react'; +import { LangCode } from '@pagopa/mui-italia'; +import i18n from '@pagopa/selfcare-common-frontend/locale/locale-utils'; +import { CONFIG } from '@pagopa/selfcare-common-frontend/config/env'; +import { LANGUAGES, pagoPALink } from '@pagopa/selfcare-common-frontend/components/Footer/FooterConfig'; +import ROUTES from '../../routes'; + +type FooterProps = { + loggedUser: boolean; + productsJsonUrl?: string; + onExit?: (exitAction: () => void) => void; +}; +declare const window: any; +// eslint-disable-next-line sonarjs/cognitive-complexity +export default function Footer({ + loggedUser, + productsJsonUrl, + onExit = (exitAction) => exitAction(), +}: FooterProps) { + const { t } = useTranslation(); + const [selectedLanguage, setSelectedLanguage] = useState(); + + // TODO Temporary solution, will be changed as soon as possible + const isPnpgDev = + window.location.hostname?.startsWith('pnpg.dev') || + window.location.hostname?.startsWith('imprese.dev'); + const isPnpgUat = + window.location.hostname?.startsWith('pnpg.uat') || + window.location.hostname?.startsWith('imprese.uat'); + const isPnpg = + window.location.hostname?.startsWith('pnpg.selfcare') || + window.location.hostname?.startsWith('imprese.notifichedigitali'); + + const preLoginLinks: PreLoginFooterLinksType = { + // First column + aboutUs: { + title: undefined, + links: [ + // TODO + // { + // label: 'PNRR', + // href: 'CONFIG.FOOTER.LINK.PNRR', + // ariaLabel: 'Vai al link: PNRR', + // linkType: 'internal', + // }, + { + label: t('common.footer.preLoginLinks.aboutUs.links.aboutUs'), + href: CONFIG.FOOTER.LINK.ABOUTUS, + ariaLabel: 'Vai al link: Chi siamo', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.aboutUs.links.media'), + href: CONFIG.FOOTER.LINK.MEDIA, + ariaLabel: 'Vai al link: Media', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.aboutUs.links.workwithud'), + href: CONFIG.FOOTER.LINK.WORKWITHUS, + ariaLabel: 'Vai al link: Lavora con noi', + linkType: 'internal', + }, + ], + }, + // Third column + resources: { + title: t('common.footer.preLoginLinks.resources.title'), + links: [ + { + label: t('common.footer.preLoginLinks.resources.links.privacyPolicy'), + href: isPnpgDev + ? 'https://imprese.dev.notifichedigitali.it/informativa-privacy' + : isPnpgUat + ? 'https://imprese.uat.notifichedigitali.it/informativa-privacy' + : isPnpg + ? 'https://imprese.notifichedigitali.it/informativa-privacy' + : ROUTES.PRIVACY, + ariaLabel: 'Vai al link: Privacy Policy', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.certifications'), + href: CONFIG.FOOTER.LINK.CERTIFICATIONS, + ariaLabel: 'Vai al link: Certificazioni', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.informationsecurity'), + href: CONFIG.FOOTER.LINK.INFORMATIONSECURITY, + ariaLabel: 'Vai al link: Sicurezza delle informazioni', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.protectionofpersonaldata'), + href: CONFIG.FOOTER.LINK.PROTECTIONOFPERSONALDATA, + ariaLabel: 'Vai al link: Diritto alla protezione dei dati personali', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.cookie'), + onClick: () => window.OneTrust.ToggleInfoDisplay(), + ariaLabel: 'Vai al link: Preferenze Cookie', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.termsandconditions'), + href: isPnpgDev + ? 'https://imprese.dev.notifichedigitali.it/termini-di-servizio' + : isPnpgUat + ? 'https://imprese.uat.notifichedigitali.it/termini-di-servizio' + : isPnpg + ? 'https://imprese.notifichedigitali.it/termini-di-servizio' + : ROUTES.TOS, + ariaLabel: 'Vai al link: Termini e Condizioni', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.transparentcompany'), + href: CONFIG.FOOTER.LINK.TRANSPARENTCOMPANY, + ariaLabel: 'Vai al link: Società trasparente', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.disclosurePolicy'), + href: CONFIG.FOOTER.LINK.DISCLOSUREPOLICY, + ariaLabel: 'Vai al link: Responsible Disclosure Policy', + linkType: 'internal', + }, + { + label: t('common.footer.preLoginLinks.resources.links.Model321'), + href: CONFIG.FOOTER.LINK.MODEL321, + ariaLabel: 'Vai al link: Modello 321', + linkType: 'internal', + }, + ], + }, + // Fourth column + followUs: { + title: t('common.footer.preLoginLinks.followUs.title'), + socialLinks: [ + { + icon: 'linkedin', + title: 'LinkedIn', + href: CONFIG.FOOTER.LINK.LINKEDIN, + ariaLabel: 'Link: vai al sito LinkedIn di PagoPA S.p.A.', + }, + { + title: 'Twitter', + icon: 'twitter', + href: CONFIG.FOOTER.LINK.TWITTER, + ariaLabel: 'Link: vai al sito Twitter di PagoPA S.p.A.', + }, + { + icon: 'instagram', + title: 'Instagram', + href: CONFIG.FOOTER.LINK.INSTAGRAM, + ariaLabel: 'Link: vai al sito Instagram di PagoPA S.p.A.', + }, + { + icon: 'medium', + title: 'Medium', + href: CONFIG.FOOTER.LINK.MEDIUM, + ariaLabel: 'Link: vai al sito Medium di PagoPA S.p.A.', + }, + ], + links: [ + // TODO + // { + // label: 'Accessibilità', + // href: CONFIG.FOOTER.LINK.ACCESSIBILITY, + // ariaLabel: 'Vai al link: Accessibilità', + // linkType: 'internal', + // }, + ], + }, + }; + const postLoginLinks: Array = [ + { + label: t('common.footer.postLoginLinks.privacyPolicy'), + href: isPnpgDev + ? 'https://imprese.dev.notifichedigitali.it/informativa-privacy' + : isPnpgUat + ? 'https://imprese.uat.notifichedigitali.it/informativa-privacy' + : isPnpg + ? 'https://imprese.notifichedigitali.it/informativa-privacy' + : ROUTES.PRIVACY, + ariaLabel: 'Vai al link: Privacy policy', + linkType: 'internal', + }, + { + label: t('common.footer.postLoginLinks.protectionofpersonaldata'), + href: CONFIG.FOOTER.LINK.PROTECTIONOFPERSONALDATA, + ariaLabel: 'Vai al link: Diritto alla protezione dei dati personali', + linkType: 'internal', + }, + { + label: t('common.footer.postLoginLinks.termsandconditions'), + href: isPnpgDev + ? 'https://imprese.dev.notifichedigitali.it/termini-di-servizio' + : isPnpgUat + ? 'https://imprese.uat.notifichedigitali.it/termini-di-servizio' + : isPnpg + ? 'https://imprese.notifichedigitali.it/termini-di-servizio' + : ROUTES.TOS, + ariaLabel: 'Vai al link: Termini e condizioni', + linkType: 'internal', + }, + // TODO + // { + // label: 'Accessibilità', + // href: CONFIG.FOOTER.LINK.ACCESSIBILITY, + // ariaLabel: 'Vai al link: Accessibilità', + // linkType: 'internal', + // }, + ]; + const companyLegalInfo = ( + + PagoPA S.p.A. - Società per azioni con socio unico - Capitale sociale di euro + 1,000,000 interamente versato - Sede legale in Roma, Piazza Colonna 370,
+ CAP 00187 - N. di iscrizione a Registro Imprese di Roma, CF e P.IVA 15376371009 +
+ ); + + return ( + { + await i18n.changeLanguage(language); + setSelectedLanguage(language); + }} + currentLangCode={selectedLanguage} + productsJsonUrl={productsJsonUrl} + /> + ); +} \ No newline at end of file diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index 6ee719834..bd47640d8 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -1,10 +1,10 @@ import {Box, Grid} from '@mui/material'; -import {Footer} from '@pagopa/selfcare-common-frontend'; import {useUnloadEventOnExit} from '@pagopa/selfcare-common-frontend/hooks/useUnloadEventInterceptor'; import React from 'react'; import {useSelector} from 'react-redux'; import {userSelectors} from '@pagopa/selfcare-common-frontend/redux/slices/userSlice'; import Header from '../Header'; +import CommonFooter from '../CommonFooter/CommonFooter'; // import withParties, { WithPartiesProps } from '../../decorators/withParties'; // import SideMenu from '../SideMenu/SideMenu'; @@ -37,7 +37,7 @@ const Layout = ({children}: Props) => { {children} -