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(); }); + }); });