From d0ef63a282aa982a309de11404742523316b02c0 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 23 Jul 2025 09:49:26 +0200 Subject: [PATCH 01/53] feat: added NotificationConfig page --- .../NotificationConfig.page.tsx | 40 +++++++++++++++++++ src/pages/NotificationConfigPage/index.ts | 1 + 2 files changed, 41 insertions(+) create mode 100644 src/pages/NotificationConfigPage/NotificationConfig.page.tsx create mode 100644 src/pages/NotificationConfigPage/index.ts diff --git a/src/pages/NotificationConfigPage/NotificationConfig.page.tsx b/src/pages/NotificationConfigPage/NotificationConfig.page.tsx new file mode 100644 index 000000000..1a41e9dca --- /dev/null +++ b/src/pages/NotificationConfigPage/NotificationConfig.page.tsx @@ -0,0 +1,40 @@ +import { PageContainer } from '@/components/layout/containers' +import { useActiveTab } from '@/hooks/useActiveTab' +import { TabContext, TabList, TabPanel } from '@mui/lab' +import { Tab } from '@mui/material' + +const NotificationConfigPage: React.FC = () => { + const { activeTab, updateActiveTab } = useActiveTab('notificationConfig') + return ( + + + + + + + + +
Notifiche in app
+
+ +
Notifhe email
+
+
+
+ ) +} + +export default NotificationConfigPage diff --git a/src/pages/NotificationConfigPage/index.ts b/src/pages/NotificationConfigPage/index.ts new file mode 100644 index 000000000..01abbdbd5 --- /dev/null +++ b/src/pages/NotificationConfigPage/index.ts @@ -0,0 +1 @@ +export { default as NotificationConfigPage } from './NotificationConfig.page' From 39e5c04d2f6316e43ee2db4378f5170c81ec6644 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 23 Jul 2025 10:51:23 +0200 Subject: [PATCH 02/53] feat: added several components --- src/pages/NotificationConfigPage/index.ts | 1 - .../NotificationUserConfig.page.tsx} | 10 +-- .../EmailNotificationUserConfigTab.tsx | 75 +++++++++++++++++++ .../InAppNotificationUserConfigTab.tsx | 0 .../components/NotificationConfigSection.tsx | 54 +++++++++++++ src/pages/NotificationUserConfigPage/index.ts | 1 + 6 files changed, 135 insertions(+), 6 deletions(-) delete mode 100644 src/pages/NotificationConfigPage/index.ts rename src/pages/{NotificationConfigPage/NotificationConfig.page.tsx => NotificationUserConfigPage/NotificationUserConfig.page.tsx} (78%) create mode 100644 src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx create mode 100644 src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx create mode 100644 src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx create mode 100644 src/pages/NotificationUserConfigPage/index.ts diff --git a/src/pages/NotificationConfigPage/index.ts b/src/pages/NotificationConfigPage/index.ts deleted file mode 100644 index 01abbdbd5..000000000 --- a/src/pages/NotificationConfigPage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as NotificationConfigPage } from './NotificationConfig.page' diff --git a/src/pages/NotificationConfigPage/NotificationConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx similarity index 78% rename from src/pages/NotificationConfigPage/NotificationConfig.page.tsx rename to src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 1a41e9dca..8b224ba8c 100644 --- a/src/pages/NotificationConfigPage/NotificationConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -2,14 +2,14 @@ import { PageContainer } from '@/components/layout/containers' import { useActiveTab } from '@/hooks/useActiveTab' import { TabContext, TabList, TabPanel } from '@mui/lab' import { Tab } from '@mui/material' +import { EmailNotificationUserConfigTab } from './components/EmailNotificationUserConfigTab' -const NotificationConfigPage: React.FC = () => { +const NotificationUserConfigPage: React.FC = () => { const { activeTab, updateActiveTab } = useActiveTab('notificationConfig') return ( { -
Notifiche in app
+
-
Notifhe email
+
) } -export default NotificationConfigPage +export default NotificationUserConfigPage diff --git a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx new file mode 100644 index 000000000..65aa7ab8d --- /dev/null +++ b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx @@ -0,0 +1,75 @@ +import { FormProvider, useForm } from 'react-hook-form' +import { NotificationConfigSection } from './NotificationConfigSection' + +export type NotificationSectionSchema = { + title: string + description: string + subsections: { + name: string + title: string + description: string + components: { + name: string + description: string + }[] + }[] +} +export type NotificationConfigSchema = { + [key: string]: NotificationSectionSchema +} + +const notificationSchema: NotificationConfigSchema = { + subscriber: { + title: 'Fruizione', + description: + "Le comunicazioni relative alla fruizione di e-service comprendono lo stato di una richiesta, l'aggiornamento di una nuova versione, la sospensione e riattivazione", + subsections: [ + { + name: 'agreements', + title: 'Richieste di fruizione inoltrate', + description: + 'Ricevi aggiornamenti sullo stato di avanzamento delel tue richieste di fruizione verso gli e-service', + components: [ + { + name: 'avanzamentoRichiesta', + description: 'Ricevi notifiche sullo stato di avanzamento della tua richiesta', + }, + { + name: 'suspendedOrReactivated', + description: 'Ricevi notifiche quando una richiesta viene sospesa o riattivata', + }, + ], + }, + { + name: 'purposes', + title: 'Finalità', + description: 'Ricevi aggiornamenti sulle finalità che hai inoltrato', + components: [ + { + name: 'acceptedOrRefusedPurpose', + description: 'Ricevi notifihe quando viene accettata o rifiutata una finalità', + }, + ], + }, + ], + }, +} + +export const EmailNotificationUserConfigTab = () => { + const formMethods = useForm() + + return ( +
+ + {Object.keys(notificationSchema).map((sectionName) => { + return ( + + ) + })} + +
+ ) +} diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx new file mode 100644 index 000000000..70cd915ea --- /dev/null +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -0,0 +1,54 @@ +import { SectionContainer } from '@/components/layout/containers' +import { RHFRadioGroup, RHFSwitch } from '@/components/shared/react-hook-form-inputs' +import { Stack } from '@mui/system' +import { useFormContext } from 'react-hook-form' +import type { NotificationSectionSchema } from './EmailNotificationUserConfigTab' + +type NotificationConfigSectionProps = { + section: NotificationSectionSchema +} +export const NotificationConfigSection: React.FC = ({ + section, +}) => { + const { watch } = useFormContext() + + const customizeNotification = watch('generalUpdate') + + const renderSubSections = () => { + return section.subsections.map((subsection) => { + return ( + + + {subsection.components.map((component) => { + return ( + + ) + })} + + + ) + }) + } + + return ( + + + {customizeNotification === 'custom' && renderSubSections()} + + ) +} diff --git a/src/pages/NotificationUserConfigPage/index.ts b/src/pages/NotificationUserConfigPage/index.ts new file mode 100644 index 000000000..9c061c007 --- /dev/null +++ b/src/pages/NotificationUserConfigPage/index.ts @@ -0,0 +1 @@ +export { default as NotificationUserConfigPage } from './NotificationUserConfig.page' From 2bf47dada9a42b01279943fa630934c94aa48428 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 23 Jul 2025 11:54:48 +0200 Subject: [PATCH 03/53] feat: start to add mutation --- scripts/open-api-type-generator.js | 2 +- src/api/notification/index.ts | 2 ++ src/api/notification/notification.mutations.ts | 11 +++++++++++ src/api/notification/notification.queries.ts | 0 src/api/notification/notification.services.ts | 12 ++++++++++++ 5 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/api/notification/index.ts create mode 100644 src/api/notification/notification.mutations.ts create mode 100644 src/api/notification/notification.queries.ts create mode 100644 src/api/notification/notification.services.ts diff --git a/scripts/open-api-type-generator.js b/scripts/open-api-type-generator.js index c9ffa9873..efeed1d12 100644 --- a/scripts/open-api-type-generator.js +++ b/scripts/open-api-type-generator.js @@ -2,7 +2,7 @@ import { generateApi } from 'swagger-typescript-api' import path from 'path' const openApiSpecificationFileUrl = - 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/develop/packages/api-clients/open-api/bffApi.yml' + 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/PIN-7100_notification_bff_api_spec/packages/api-clients/open-api/bffApi.yml' const apiFolderPath = path.resolve('./src/api/') diff --git a/src/api/notification/index.ts b/src/api/notification/index.ts new file mode 100644 index 000000000..45bee0122 --- /dev/null +++ b/src/api/notification/index.ts @@ -0,0 +1,2 @@ +export * from './notification.services' +export * from './notification.mutations' diff --git a/src/api/notification/notification.mutations.ts b/src/api/notification/notification.mutations.ts new file mode 100644 index 000000000..cd3309c42 --- /dev/null +++ b/src/api/notification/notification.mutations.ts @@ -0,0 +1,11 @@ +import { useMutation } from '@tanstack/react-query' +import { notificationServices } from './index' +function useUpdateNotificationUserConfigs() { + return useMutation({ + mutationFn: notificationServices.updateUserNotificationConfiguration, + }) +} + +export const NotificationMutations = { + useUpdateNotificationUserConfigs, +} diff --git a/src/api/notification/notification.queries.ts b/src/api/notification/notification.queries.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts new file mode 100644 index 000000000..5c0273aaa --- /dev/null +++ b/src/api/notification/notification.services.ts @@ -0,0 +1,12 @@ +import axiosInstance from '@/config/axios' +import { BACKEND_FOR_FRONTEND_URL } from '@/config/env' +import type { NotificationConfigSeed } from '../api.generatedTypes' + +async function updateUserNotificationConfiguration(payload: NotificationConfigSeed) { + return await axiosInstance.post( + `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs`, + payload + ) +} + +export const notificationServices = { updateUserNotificationConfiguration } From 32ef19ee14c24fa4731c7ff170284fe53938d893 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Tue, 26 Aug 2025 16:19:14 +0200 Subject: [PATCH 04/53] chore: added message icon --- src/components/sidebar/useGetSidebarItems.tsx | 18 ++++++++++++++++-- src/icons/MessageIcon/MessageIcon.tsx | 13 +++++++++++++ src/icons/MessageIcon/index.ts | 1 + src/icons/index.ts | 1 + src/router/routes.tsx | 9 +++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/icons/MessageIcon/MessageIcon.tsx create mode 100644 src/icons/MessageIcon/index.ts diff --git a/src/components/sidebar/useGetSidebarItems.tsx b/src/components/sidebar/useGetSidebarItems.tsx index 3a4bd939f..ca7eb3186 100644 --- a/src/components/sidebar/useGetSidebarItems.tsx +++ b/src/components/sidebar/useGetSidebarItems.tsx @@ -7,8 +7,16 @@ import React from 'react' import type { RouteKey } from '@/router' import { routes } from '@/router' import DnsIcon from '@mui/icons-material/Dns' -import { ConsumerIcon, ProviderIcon, CatalogIcon, DeveloperToolIcon, MyTenantIcon } from '@/icons' +import { + ConsumerIcon, + ProviderIcon, + CatalogIcon, + DeveloperToolIcon, + MyTenantIcon, + MessageIcon, +} from '@/icons' import { useTranslation } from 'react-i18next' +import { Message } from '@mui/icons-material' export function useGetSidebarItems(): SidebarRoutes { const { t } = useTranslation('sidebar', { keyPrefix: 'menuItem' }) @@ -84,7 +92,13 @@ export function useGetSidebarItems(): SidebarRoutes { { icon: DeveloperToolIcon, rootRouteKey: 'DEVELOPER_TOOLS', - label: 'Tool per lo sviluppo ', + label: 'Tool per lo sviluppo', + children: [], + }, + { + icon: MessageIcon, + rootRouteKey: 'NOTIFICATIONS', + label: 'Notifiche ', children: [], }, ] diff --git a/src/icons/MessageIcon/MessageIcon.tsx b/src/icons/MessageIcon/MessageIcon.tsx new file mode 100644 index 000000000..10d320b04 --- /dev/null +++ b/src/icons/MessageIcon/MessageIcon.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import { SvgIcon } from '@mui/material' + +export const MessageIcon = () => ( + + + +) + +MessageIcon.muiName = 'MessageIcon' diff --git a/src/icons/MessageIcon/index.ts b/src/icons/MessageIcon/index.ts new file mode 100644 index 000000000..4affbdb5d --- /dev/null +++ b/src/icons/MessageIcon/index.ts @@ -0,0 +1 @@ +export * from './MessageIcon' diff --git a/src/icons/index.ts b/src/icons/index.ts index ddad0e799..848a0b069 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -3,3 +3,4 @@ export * from './ProviderIcon' export * from './MyTenantIcon' export * from './CatalogIcon' export * from './DeveloperToolIcon' +export * from './MessageIcon' diff --git a/src/router/routes.tsx b/src/router/routes.tsx index 2e4e3413a..855881f73 100644 --- a/src/router/routes.tsx +++ b/src/router/routes.tsx @@ -58,6 +58,7 @@ import RoutesWrapper from './components/RoutesWrapper' import type { LangCode } from '@/types/common.types' import type { UserProductRole } from '@/types/party.types' import ConsumerEServiceTemplateDetailsPage from '@/pages/ConsumerEServiceTemplateDetailsPage/ConsumerEServiceTemplateDetails.page' +import { NotificationUserConfigPage } from '@/pages/NotificationUserConfigPage' export const { routes, reactRouterDOMRoutes, hooks, components, utils } = new InteropRouterBuilder< LangCode, @@ -571,6 +572,14 @@ export const { routes, reactRouterDOMRoutes, hooks, components, utils } = new In hideSideNav: false, authLevels: ['admin', 'support', 'security'], }) + .addRoute({ + key: 'NOTIFICATIONS', + path: '/notifiche', + element: , + public: false, + hideSideNav: false, + authLevels: ['admin', 'support', 'security', 'api'], + }) .build() export type RouteKey = InferRouteKey From 9a292f0ddac91bfefc3f8a4ae001b2eae9b89ee2 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Tue, 26 Aug 2025 16:58:02 +0200 Subject: [PATCH 05/53] chore: added SwithcLabelDescription component --- .../react-hook-form-inputs/RHFSwitch.tsx | 2 +- .../SwitchLabelDescription.tsx | 23 +++++ .../shared/react-hook-form-inputs/index.ts | 1 + .../NotificationUserConfig.page.tsx | 3 +- .../InAppNotificationUserConfigTab.tsx | 98 +++++++++++++++++++ .../components/NotificationConfigSection.tsx | 25 ++--- 6 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 src/components/shared/react-hook-form-inputs/SwitchLabelDescription.tsx diff --git a/src/components/shared/react-hook-form-inputs/RHFSwitch.tsx b/src/components/shared/react-hook-form-inputs/RHFSwitch.tsx index 36a50cda4..1f482fc44 100644 --- a/src/components/shared/react-hook-form-inputs/RHFSwitch.tsx +++ b/src/components/shared/react-hook-form-inputs/RHFSwitch.tsx @@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next' import { getAriaAccessibilityInputProps, mapValidationErrorMessages } from '@/utils/form.utils' export type RHFSwitchProps = Omit & { - label: string + label: string | React.ReactNode infoLabel?: string name: string rules?: ControllerProps['rules'] diff --git a/src/components/shared/react-hook-form-inputs/SwitchLabelDescription.tsx b/src/components/shared/react-hook-form-inputs/SwitchLabelDescription.tsx new file mode 100644 index 000000000..d7f3645a4 --- /dev/null +++ b/src/components/shared/react-hook-form-inputs/SwitchLabelDescription.tsx @@ -0,0 +1,23 @@ +import { Typography } from '@mui/material' +import { Box } from '@mui/system' + +type SwitchLabelDescriptionProps = { + label: string + description: string +} + +export const SwitchLabelDescription: React.FC = ({ + label, + description, +}) => { + return ( + + + {label} + + + {description} + + + ) +} diff --git a/src/components/shared/react-hook-form-inputs/index.ts b/src/components/shared/react-hook-form-inputs/index.ts index 2b0f8f195..2b66ebb1b 100644 --- a/src/components/shared/react-hook-form-inputs/index.ts +++ b/src/components/shared/react-hook-form-inputs/index.ts @@ -5,3 +5,4 @@ export * from './RHFRadioGroup' export * from './RHFCheckboxGroup' export * from './RHFSingleFileInput' export * from './RHFCheckbox' +export * from './SwitchLabelDescription' diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 8b224ba8c..765a6b36c 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -3,6 +3,7 @@ import { useActiveTab } from '@/hooks/useActiveTab' import { TabContext, TabList, TabPanel } from '@mui/lab' import { Tab } from '@mui/material' import { EmailNotificationUserConfigTab } from './components/EmailNotificationUserConfigTab' +import { InAppNotificationUserConfigTab } from './components/InAppNotificationUserConfigTab' const NotificationUserConfigPage: React.FC = () => { const { activeTab, updateActiveTab } = useActiveTab('notificationConfig') @@ -27,7 +28,7 @@ const NotificationUserConfigPage: React.FC = () => { - + diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index e69de29bb..c5de5aae8 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -0,0 +1,98 @@ +import { FormProvider, useForm } from 'react-hook-form' +import { NotificationConfigSection } from './NotificationConfigSection' +import { SectionContainer } from '@/components/layout/containers' +import { Box, Link, Typography } from '@mui/material' +import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' +import { useTranslation } from 'react-i18next' + +export type NotificationSectionSchema = { + title: string + description: string + subsections: { + name: string + title: string + description: string + components: { + name: string + description: string + }[] + }[] +} +export type NotificationConfigSchema = { + [key: string]: NotificationSectionSchema +} + +const notificationSchema: NotificationConfigSchema = { + subscriber: { + title: 'Fruizione', + description: + "Le comunicazioni relative alla fruizione di e-service comprendono lo stato di una richiesta, l'aggiornamento di una nuova versione, la sospensione e riattivazione", + subsections: [ + { + name: 'agreements', + title: 'Richieste di fruizione inoltrate', + description: + 'Ricevi aggiornamenti sullo stato di avanzamento delel tue richieste di fruizione verso gli e-service', + components: [ + { + name: 'avanzamentoRichiesta', + description: 'Ricevi notifiche sullo stato di avanzamento della tua richiesta', + }, + { + name: 'suspendedOrReactivated', + description: 'Ricevi notifiche quando una richiesta viene sospesa o riattivata', + }, + ], + }, + { + name: 'purposes', + title: 'Finalità', + description: 'Ricevi aggiornamenti sulle finalità che hai inoltrato', + components: [ + { + name: 'acceptedOrRefusedPurpose', + description: 'Ricevi notifihe quando viene accettata o rifiutata una finalità', + }, + ], + }, + ], + }, +} + +export const InAppNotificationUserConfigTab = () => { + const formMethods = useForm() + const { t } = useTranslation('common') + + return ( + + + + Dubbi? Vai al manuale + + + + } + /> + {/* {Object.keys(notificationSchema).map((sectionName) => { + return ( + + ) + })} */} + + + + ) +} diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index 70cd915ea..3eddc5cf1 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -17,24 +17,13 @@ export const NotificationConfigSection: React.FC const renderSubSections = () => { return section.subsections.map((subsection) => { return ( - - - {subsection.components.map((component) => { - return ( - - ) - })} - - + + {subsection.components.map((component) => { + return ( + + ) + })} + ) }) } From e2f76798975592e99dc7fd565b1c9e4818e43cb7 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 27 Aug 2025 10:41:53 +0200 Subject: [PATCH 06/53] chore: update NotificationConfigSection --- .../EmailNotificationUserConfigTab.tsx | 5 +- .../InAppNotificationUserConfigTab.tsx | 134 ++++++++++++++---- .../components/NotificationConfigSection.tsx | 52 +++---- 3 files changed, 130 insertions(+), 61 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx index 65aa7ab8d..c8dede92e 100644 --- a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx @@ -3,7 +3,6 @@ import { NotificationConfigSection } from './NotificationConfigSection' export type NotificationSectionSchema = { title: string - description: string subsections: { name: string title: string @@ -21,8 +20,6 @@ export type NotificationConfigSchema = { const notificationSchema: NotificationConfigSchema = { subscriber: { title: 'Fruizione', - description: - "Le comunicazioni relative alla fruizione di e-service comprendono lo stato di una richiesta, l'aggiornamento di una nuova versione, la sospensione e riattivazione", subsections: [ { name: 'agreements', @@ -65,7 +62,7 @@ export const EmailNotificationUserConfigTab = () => { return ( ) })} diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index c5de5aae8..e67f01784 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -1,23 +1,24 @@ import { FormProvider, useForm } from 'react-hook-form' import { NotificationConfigSection } from './NotificationConfigSection' import { SectionContainer } from '@/components/layout/containers' -import { Box, Link, Typography } from '@mui/material' +import { Box, Card, Link, Stack, Typography } from '@mui/material' import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { useTranslation } from 'react-i18next' +import MenuBookIcon from '@mui/icons-material/MenuBook' -export type NotificationSectionSchema = { +export type NotificationSubSectionSchema = { + name: string title: string - description: string - subsections: { + components: { name: string title: string description: string - components: { - name: string - description: string - }[] }[] } +export type NotificationSectionSchema = { + title: string + subsections: NotificationSubSectionSchema[] +} export type NotificationConfigSchema = { [key: string]: NotificationSectionSchema } @@ -25,33 +26,89 @@ export type NotificationConfigSchema = { const notificationSchema: NotificationConfigSchema = { subscriber: { title: 'Fruizione', - description: - "Le comunicazioni relative alla fruizione di e-service comprendono lo stato di una richiesta, l'aggiornamento di una nuova versione, la sospensione e riattivazione", subsections: [ { - name: 'agreements', - title: 'Richieste di fruizione inoltrate', - description: - 'Ricevi aggiornamenti sullo stato di avanzamento delel tue richieste di fruizione verso gli e-service', + name: 'fruizioneDati', + title: 'Fruizione dei dati', components: [ { - name: 'avanzamentoRichiesta', + name: 'variazioneDiStatoEservice', + title: 'Variazione di stato degli e-service', description: 'Ricevi notifiche sullo stato di avanzamento della tua richiesta', }, { - name: 'suspendedOrReactivated', + name: 'richiestaDiFruizione', + title: 'Accettazione o rifiuto delle richieste di fruizione', description: 'Ricevi notifiche quando una richiesta viene sospesa o riattivata', }, + { + name: 'variazionestatoRichiestaFruizione', + title: 'Variazione dello stato della richiesta di fruizione', + description: 'Ricevi notifiche quando una richiesta viene sospesa o riattivata', + }, + ], + }, + { + name: 'finalita', + title: 'Finalità', + components: [ + { + name: 'accettazioneFinalita', + title: 'Accettazione o rifiuto di una finalità', + description: 'Avvisami quando una finalità viene accettata o rifiutata', + }, + { + name: 'variazioneFinalita', + title: 'Variazione di stato di una finalità', + description: + 'Avvisami quando lo stato di una finalità viene sospesa, archiviata o riattivata', + }, + ], + }, + { + name: 'soglieDiCarico', + title: 'Soglie di carico', + components: [ + { + name: 'statoSoglieDiCarico', + title: 'Stato delle soglie di carico', + description: + 'Avvisami quando una mia richiesta supera le soglie massime stabilite dall’erogatore', + }, + { + name: 'adeguamentoSoglia', + title: 'Richieste di adeguamento soglia', + description: + 'Avvisami quando un erogatore accetta o rifiuta una richiesta di adeguamento delle soglie', + }, + ], + }, + ], + }, + provider: { + title: 'Erogazione', + subsections: [ + { + name: 'richiesteFruizione', + title: 'Fruizione dei dati', + components: [ + { + name: 'gestioneRichiesteInArrivo', + title: 'Gestione delle richieste di fruizione in arrivo', + description: + 'Avvisami sulle nuove richieste di fruizione in arrivo e quelle accettate automaticamente', + }, ], }, { - name: 'purposes', + name: 'finalita', title: 'Finalità', - description: 'Ricevi aggiornamenti sulle finalità che hai inoltrato', components: [ { - name: 'acceptedOrRefusedPurpose', - description: 'Ricevi notifihe quando viene accettata o rifiutata una finalità', + name: 'variazioneFinalita', + title: 'Variazione di stato di una finalità', + description: + 'Avvisami quando lo stato di una finalità viene sospesa, archiviata o riattivata', }, ], }, @@ -83,14 +140,35 @@ export const InAppNotificationUserConfigTab = () => { /> } /> - {/* {Object.keys(notificationSchema).map((sectionName) => { - return ( - - ) - })} */} + + {Object.keys(notificationSchema).map((sectionName) => { + return ( + + + + + + + {notificationSchema[sectionName].title} + + + + + + + {notificationSchema[sectionName].subsections.map((subsection) => ( + + ))} + + + ) + })} diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index 3eddc5cf1..84066920d 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -1,43 +1,37 @@ -import { SectionContainer } from '@/components/layout/containers' -import { RHFRadioGroup, RHFSwitch } from '@/components/shared/react-hook-form-inputs' -import { Stack } from '@mui/system' +import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' +import { Box } from '@mui/system' import { useFormContext } from 'react-hook-form' import type { NotificationSectionSchema } from './EmailNotificationUserConfigTab' +import { Typography } from '@mui/material' +import { NotificationSubSectionSchema } from './InAppNotificationUserConfigTab' type NotificationConfigSectionProps = { - section: NotificationSectionSchema + subsection: NotificationSubSectionSchema } export const NotificationConfigSection: React.FC = ({ - section, + subsection, }) => { const { watch } = useFormContext() const customizeNotification = watch('generalUpdate') - const renderSubSections = () => { - return section.subsections.map((subsection) => { - return ( - - {subsection.components.map((component) => { - return ( - - ) - })} - - ) - }) - } - return ( - - - {customizeNotification === 'custom' && renderSubSections()} - + <> + + {subsection.title} + + + {subsection.components.map((component) => ( + + } + /> + ))} + + ) } From 99bd626120691a79717968038da7cb1405cb111a Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 27 Aug 2025 11:47:41 +0200 Subject: [PATCH 07/53] feat: added translation --- src/api/notification/notification.services.ts | 4 ++-- src/config/react-i18next.ts | 4 ++++ .../NotificationUserConfig.page.tsx | 18 ++++++++---------- .../EmailNotificationUserConfigTab.tsx | 9 ++------- .../InAppNotificationUserConfigTab.tsx | 14 +++++--------- src/react-i18next.d.ts | 3 +++ src/static/locales/en/notification.json | 16 ++++++++++++++++ src/static/locales/en/shared-components.json | 3 ++- src/static/locales/it/notification.json | 16 ++++++++++++++++ src/static/locales/it/shared-components.json | 3 ++- 10 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 src/static/locales/en/notification.json create mode 100644 src/static/locales/it/notification.json diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index 5c0273aaa..d8b0d9050 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -1,8 +1,8 @@ import axiosInstance from '@/config/axios' import { BACKEND_FOR_FRONTEND_URL } from '@/config/env' -import type { NotificationConfigSeed } from '../api.generatedTypes' +// import type { NotificationConfigSeed } from '../api.generatedTypes' -async function updateUserNotificationConfiguration(payload: NotificationConfigSeed) { +async function updateUserNotificationConfiguration(payload: unknown) { return await axiosInstance.post( `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs`, payload diff --git a/src/config/react-i18next.ts b/src/config/react-i18next.ts index ae0579087..f771340ba 100644 --- a/src/config/react-i18next.ts +++ b/src/config/react-i18next.ts @@ -21,6 +21,7 @@ import assistanceEnNs from '@/static/locales/en/assistance.json' import keychainEnNs from '@/static/locales/en/keychain.json' import eserviceTemplateEnNs from '@/static/locales/en/eserviceTemplate.json' import developerToolsEnNs from '@/static/locales/en/developer-tools.json' +import notificationEnNs from '@/static/locales/en/notification.json' import pagesItNs from '@/static/locales/it/pages.json' import commonItNs from '@/static/locales/it/common.json' @@ -42,6 +43,7 @@ import keychainItNs from '@/static/locales/it/keychain.json' import eserviceTemplateItNs from '@/static/locales/it/eserviceTemplate.json' import developerToolsItNs from '@/static/locales/it/developer-tools.json' import sidebarNs from '@/static/locales/it/sidebar.json' +import notificationItNs from '@/static/locales/it/notification.json' i18n.use(initReactI18next).init({ debug: false, @@ -72,6 +74,7 @@ i18n.use(initReactI18next).init({ eserviceTemplate: eserviceTemplateItNs, 'developer-tools': developerToolsItNs, sidebar: sidebarNs, + notification: notificationItNs, }, en: { pages: pagesEnNs, @@ -94,6 +97,7 @@ i18n.use(initReactI18next).init({ eserviceTemplate: eserviceTemplateEnNs, 'developer-tools': developerToolsEnNs, sidebar: sidebarNs, + notification: notificationEnNs, }, }, }) diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 765a6b36c..bd4f8d2bc 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -4,27 +4,25 @@ import { TabContext, TabList, TabPanel } from '@mui/lab' import { Tab } from '@mui/material' import { EmailNotificationUserConfigTab } from './components/EmailNotificationUserConfigTab' import { InAppNotificationUserConfigTab } from './components/InAppNotificationUserConfigTab' +import { useTranslation } from 'react-i18next' const NotificationUserConfigPage: React.FC = () => { const { activeTab, updateActiveTab } = useActiveTab('notificationConfig') + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) + return ( - - - + + + diff --git a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx index c8dede92e..888408f27 100644 --- a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx @@ -1,5 +1,4 @@ import { FormProvider, useForm } from 'react-hook-form' -import { NotificationConfigSection } from './NotificationConfigSection' export type NotificationSectionSchema = { title: string @@ -59,12 +58,8 @@ export const EmailNotificationUserConfigTab = () => {
{Object.keys(notificationSchema).map((sectionName) => { - return ( - - ) + // eslint-disable-next-line react/jsx-key + return
TODO
})}
diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index e67f01784..faf941502 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -118,25 +118,21 @@ const notificationSchema: NotificationConfigSchema = { export const InAppNotificationUserConfigTab = () => { const formMethods = useForm() - const { t } = useTranslation('common') + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) return ( - + - Dubbi? Vai al manuale + Dubbi? Vai al manuale (TODO TRANSLATE) } /> diff --git a/src/react-i18next.d.ts b/src/react-i18next.d.ts index b8a047c32..6cba27f75 100644 --- a/src/react-i18next.d.ts +++ b/src/react-i18next.d.ts @@ -18,6 +18,8 @@ import type keychainNs from '@/static/locales/en/keychain.json' import type eserviceTemplateNs from '@/static/locales/en/eserviceTemplate.json' import type developerToolsNs from '@/static/locales/en/developer-tools.json' import type sidebarNs from '@/static/locales/en/sidebar.json' +import type notificationNs from '@/static/locales/en/finalita.json' + declare module 'i18next' { interface CustomTypeOptions { defaultNS: 'common' @@ -42,6 +44,7 @@ declare module 'i18next' { eserviceTemplate: typeof eserviceTemplateNs 'developer-tools': typeof developerToolsNs sidebar: typeof sidebarNs + notification: typeof notificationNs } } } diff --git a/src/static/locales/en/notification.json b/src/static/locales/en/notification.json new file mode 100644 index 000000000..60c7c8a0c --- /dev/null +++ b/src/static/locales/en/notification.json @@ -0,0 +1,16 @@ +{ + "configurationPage": { + "title": "Configurazione notifiche utente", + "description": "Gestisci le tue impostazioni di notifica in app e via email personale.", + "inAppTabTitle": "Notifiche in-app", + "emailTabTitle": "Email", + "inAppTab": { + "title": "Configurazione delle preferenze di notifica in piattaforma", + "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", + "enableAllNotifications": { + "label": "Abilita la ricezione delle notifiche in piattaforma", + "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" + } + } + } +} diff --git a/src/static/locales/en/shared-components.json b/src/static/locales/en/shared-components.json index c85c0962c..03beb264e 100644 --- a/src/static/locales/en/shared-components.json +++ b/src/static/locales/en/shared-components.json @@ -411,6 +411,7 @@ "WATCH_RISK_ANALYSIS_FOR_ESERVICE": "Risk analysis", "DEVELOPER_TOOLS": "Developer tools", "RISK_ANALYSIS_EXPORTER_TOOL": "Export risk analysis", - "CLIENT_MANAGEMENT": "Client management" + "CLIENT_MANAGEMENT": "Client management", + "NOTIFICATIONS": "Notifications" } } diff --git a/src/static/locales/it/notification.json b/src/static/locales/it/notification.json new file mode 100644 index 000000000..60c7c8a0c --- /dev/null +++ b/src/static/locales/it/notification.json @@ -0,0 +1,16 @@ +{ + "configurationPage": { + "title": "Configurazione notifiche utente", + "description": "Gestisci le tue impostazioni di notifica in app e via email personale.", + "inAppTabTitle": "Notifiche in-app", + "emailTabTitle": "Email", + "inAppTab": { + "title": "Configurazione delle preferenze di notifica in piattaforma", + "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", + "enableAllNotifications": { + "label": "Abilita la ricezione delle notifiche in piattaforma", + "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" + } + } + } +} diff --git a/src/static/locales/it/shared-components.json b/src/static/locales/it/shared-components.json index b86a0e5b7..ed670530a 100644 --- a/src/static/locales/it/shared-components.json +++ b/src/static/locales/it/shared-components.json @@ -411,6 +411,7 @@ "WATCH_RISK_ANALYSIS_FOR_ESERVICE": "Analisi del rischio", "DEVELOPER_TOOLS": "Tool per lo sviluppo", "RISK_ANALYSIS_EXPORTER_TOOL": "Export analisi del rischio", - "CLIENT_MANAGEMENT": "Gestione dei client" + "CLIENT_MANAGEMENT": "Gestione dei client", + "NOTIFICATIONS": "Notifiche" } } From 8951811cb18827a8d5dc953ce653dec48c3b26b3 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Thu, 28 Aug 2025 09:41:35 +0200 Subject: [PATCH 08/53] chore: association switch - configuration --- scripts/open-api-type-generator.js | 2 +- src/api/api.generatedTypes.ts | 218 +++++++++++ src/api/notification/notification.services.ts | 2 +- .../InAppNotificationUserConfigTab.tsx | 346 +++++++++++++----- .../components/NotificationConfigSection.tsx | 4 +- src/static/locales/en/notification.json | 163 +++++++++ src/static/locales/it/notification.json | 163 +++++++++ 7 files changed, 800 insertions(+), 98 deletions(-) diff --git a/scripts/open-api-type-generator.js b/scripts/open-api-type-generator.js index efeed1d12..c9ffa9873 100644 --- a/scripts/open-api-type-generator.js +++ b/scripts/open-api-type-generator.js @@ -2,7 +2,7 @@ import { generateApi } from 'swagger-typescript-api' import path from 'path' const openApiSpecificationFileUrl = - 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/PIN-7100_notification_bff_api_spec/packages/api-clients/open-api/bffApi.yml' + 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/develop/packages/api-clients/open-api/bffApi.yml' const apiFolderPath = path.resolve('./src/api/') diff --git a/src/api/api.generatedTypes.ts b/src/api/api.generatedTypes.ts index 25c4fdd1e..f103693be 100644 --- a/src/api/api.generatedTypes.ts +++ b/src/api/api.generatedTypes.ts @@ -1960,6 +1960,60 @@ export interface UpdateEServiceTemplateVersionDocumentSeed { prettyName: string } +export interface Notifications { + results: Notification[] + /** @format int32 */ + totalCount: number +} + +export interface Notification { + /** + * Unique identifier of the notification + * @format uuid + */ + id: string + /** + * ID of the user + * @format uuid + */ + userId: string + /** + * ID of the tenant + * @format uuid + */ + tenantId: string + /** Content of the notification */ + body: string + /** + * Timestamp when the notification was read + * @format date-time + */ + readAt: string | null + /** + * Timestamp when the notification was created + * @format date-time + */ + createdAt: string +} + +export interface NotificationConfig { + newEServiceVersionPublished: boolean +} + +export type TenantNotificationConfig = NotificationConfig + +export interface UserNotificationConfig { + inAppConfig: NotificationConfig + emailConfig: NotificationConfig +} + +export type TenantNotificationConfigUpdateSeed = NotificationConfig + +export interface UserNotificationConfigUpdateSeed { + inAppConfig: NotificationConfig + emailConfig: NotificationConfig +} + export interface ProblemError { /** * Internal code of the error @@ -2638,6 +2692,26 @@ export interface IsEServiceNameAvailableParams { name: string } +export interface GetNotificationsParams { + /** Query to filter notifications */ + q?: string + /** + * @format int32 + * @min 0 + */ + offset: number + /** + * @format int32 + * @min 1 + * @max 50 + */ + limit: number +} + +export interface MarkNotificationsAsReadPayload { + ids: string[] +} + export namespace Consumers { /** * @description retrieves a list of consumer agreements @@ -7187,6 +7261,150 @@ export namespace Creators { } } +export namespace InAppNotifications { + /** + * @description Retrieves a list of notifications + * @tags inAppNotifications + * @name GetNotifications + * @summary Retrieves a list of notifications + * @request GET:/inAppNotifications + */ + export namespace GetNotifications { + export type RequestParams = {} + export type RequestQuery = { + /** Query to filter notifications */ + q?: string + /** + * @format int32 + * @min 0 + */ + offset: number + /** + * @format int32 + * @min 1 + * @max 50 + */ + limit: number + } + export type RequestBody = never + export type RequestHeaders = {} + export type ResponseBody = void + } + /** + * @description Mark a list of notifications as read + * @tags inAppNotifications + * @name MarkNotificationsAsRead + * @summary Mark a list of notifications as read + * @request POST:/inAppNotifications/bulk/markAsRead + * @secure + */ + export namespace MarkNotificationsAsRead { + export type RequestParams = {} + export type RequestQuery = {} + export type RequestBody = MarkNotificationsAsReadPayload + export type RequestHeaders = {} + export type ResponseBody = void + } + /** + * @description Mark a notification as read + * @tags inAppNotifications + * @name MarkNotificationAsRead + * @summary Mark a notification as read + * @request POST:/inAppNotifications/:notificationId/markAsRead + * @secure + */ + export namespace MarkNotificationAsRead { + export type RequestParams = { + /** @format uuid */ + notificationId: string + } + export type RequestQuery = {} + export type RequestBody = never + export type RequestHeaders = {} + export type ResponseBody = void + } + /** + * @description Delete a notification + * @tags inAppNotifications + * @name DeleteNotification + * @summary Delete a notification + * @request DELETE:/inAppNotifications/:notificationId + * @secure + */ + export namespace DeleteNotification { + export type RequestParams = { + /** @format uuid */ + notificationId: string + } + export type RequestQuery = {} + export type RequestBody = never + export type RequestHeaders = {} + export type ResponseBody = void + } +} + +export namespace TenantNotificationConfigs { + /** + * No description + * @tags notificationConfigs + * @name GetTenantNotificationConfig + * @summary Retrieve the tenant's notification configuration + * @request GET:/tenantNotificationConfigs + */ + export namespace GetTenantNotificationConfig { + export type RequestParams = {} + export type RequestQuery = {} + export type RequestBody = never + export type RequestHeaders = {} + export type ResponseBody = TenantNotificationConfig + } + /** + * No description + * @tags notificationConfigs + * @name UpdateTenantNotificationConfig + * @summary Update the tenant's notification configuration + * @request POST:/tenantNotificationConfigs + */ + export namespace UpdateTenantNotificationConfig { + export type RequestParams = {} + export type RequestQuery = {} + export type RequestBody = TenantNotificationConfigUpdateSeed + export type RequestHeaders = {} + export type ResponseBody = void + } +} + +export namespace UserNotificationConfigs { + /** + * No description + * @tags notificationConfigs + * @name GetUserNotificationConfig + * @summary Retrieve the user's notification configuration + * @request GET:/userNotificationConfigs + */ + export namespace GetUserNotificationConfig { + export type RequestParams = {} + export type RequestQuery = {} + export type RequestBody = never + export type RequestHeaders = {} + export type ResponseBody = UserNotificationConfig + } + /** + * No description + * @tags notificationConfigs + * @name UpdateUserNotificationConfig + * @summary Update the user's notification configuration + * @request POST:/userNotificationConfigs + */ + export namespace UpdateUserNotificationConfig { + export type RequestParams = {} + export type RequestQuery = {} + export type RequestBody = UserNotificationConfigUpdateSeed + export type RequestHeaders = {} + export type ResponseBody = void + } +} + export namespace ApiDocs { /** * @description Display the API documentation diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index d8b0d9050..49a10507e 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -1,6 +1,6 @@ import axiosInstance from '@/config/axios' import { BACKEND_FOR_FRONTEND_URL } from '@/config/env' -// import type { NotificationConfigSeed } from '../api.generatedTypes' +import type { NotificationCon } from '../api.generatedTypes' async function updateUserNotificationConfiguration(payload: unknown) { return await axiosInstance.post( diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index faf941502..cf4527b2b 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -10,7 +10,7 @@ export type NotificationSubSectionSchema = { name: string title: string components: { - name: string + key: string title: string description: string }[] @@ -23,103 +23,261 @@ export type NotificationConfigSchema = { [key: string]: NotificationSectionSchema } -const notificationSchema: NotificationConfigSchema = { - subscriber: { - title: 'Fruizione', - subsections: [ - { - name: 'fruizioneDati', - title: 'Fruizione dei dati', - components: [ - { - name: 'variazioneDiStatoEservice', - title: 'Variazione di stato degli e-service', - description: 'Ricevi notifiche sullo stato di avanzamento della tua richiesta', - }, - { - name: 'richiestaDiFruizione', - title: 'Accettazione o rifiuto delle richieste di fruizione', - description: 'Ricevi notifiche quando una richiesta viene sospesa o riattivata', - }, - { - name: 'variazionestatoRichiestaFruizione', - title: 'Variazione dello stato della richiesta di fruizione', - description: 'Ricevi notifiche quando una richiesta viene sospesa o riattivata', - }, - ], - }, - { - name: 'finalita', - title: 'Finalità', - components: [ - { - name: 'accettazioneFinalita', - title: 'Accettazione o rifiuto di una finalità', - description: 'Avvisami quando una finalità viene accettata o rifiutata', - }, - { - name: 'variazioneFinalita', - title: 'Variazione di stato di una finalità', - description: - 'Avvisami quando lo stato di una finalità viene sospesa, archiviata o riattivata', - }, - ], - }, - { - name: 'soglieDiCarico', - title: 'Soglie di carico', - components: [ - { - name: 'statoSoglieDiCarico', - title: 'Stato delle soglie di carico', - description: - 'Avvisami quando una mia richiesta supera le soglie massime stabilite dall’erogatore', - }, - { - name: 'adeguamentoSoglia', - title: 'Richieste di adeguamento soglia', - description: - 'Avvisami quando un erogatore accetta o rifiuta una richiesta di adeguamento delle soglie', - }, - ], - }, - ], - }, - provider: { - title: 'Erogazione', - subsections: [ - { - name: 'richiesteFruizione', - title: 'Fruizione dei dati', - components: [ - { - name: 'gestioneRichiesteInArrivo', - title: 'Gestione delle richieste di fruizione in arrivo', - description: - 'Avvisami sulle nuove richieste di fruizione in arrivo e quelle accettate automaticamente', - }, - ], - }, - { - name: 'finalita', - title: 'Finalità', - components: [ - { - name: 'variazioneFinalita', - title: 'Variazione di stato di una finalità', - description: - 'Avvisami quando lo stato di una finalità viene sospesa, archiviata o riattivata', - }, - ], - }, - ], - }, -} - export const InAppNotificationUserConfigTab = () => { const formMethods = useForm() const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) + const notificationSchema: NotificationConfigSchema = { + subscriber: { + title: t('subscriber.title'), + subsections: [ + { + name: 'fruizioneDati', + title: t('subscriber.dataUsage.title'), + components: [ + { + key: 'eserviceStateChangedToConsumer', + title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', + description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + }, + { + key: 'agreementActivatedRejectedToConsumer', + title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', + description: t('subscriber.dataUsage.components.agreementManagement.description'), + }, + { + key: 'agreementSuspendedUnsuspendedToConsumer', + title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', + description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + }, + ], + }, + { + name: 'finalita', + title: t('subscriber.purpose.title'), + components: [ + { + key: 'purposeActivatedRejectedToConsumer', + title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', + description: t('subscriber.purpose.components.purposeManagement.description'), + }, + { + key: 'purposeSuspendedUnsuspendedToConsumer', + title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', + description: t('subscriber.purpose.components.purposeStateUpdated.description'), + }, + ], + }, + { + name: 'soglieDiCarico', + title: t('subscriber.thresholds.title'), + components: [ + { + key: 'statoSoglieDiCarico', + title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), + description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + }, + { + key: 'adeguamentoSoglia', + title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), + description: t( + 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' + ), + }, + ], + }, + ], + }, + provider: { + title: t('provider.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('provider.agreement.title'), + components: [ + { + key: 'agreementManagementToProducer', + title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', + description: t('provider.agreement.components.agreementRequestReceived.description'), + }, + { + key: 'agreementSuspendedUnsuspendedToProducer', + title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', + description: t('provider.agreement.components.agreementStateUpdated.description'), + }, + ], + }, + { + name: 'finalita', + title: t('provider.purpose.title'), + components: [ + { + key: 'purposeStatusChangedToProducer', + title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', + description: t('provider.purpose.components.purposeStateUpdated.description'), + }, + ], + }, + { + name: 'clientSoglieDiCarico', + title: t('provider.clientAndThresholds.title'), + components: [ + { + key: 'clientAddedRemovedToProducer', + title: + t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + + '(05)', + description: t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' + ), + }, + { + key: 'todo', + title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdExceeded.description' + ), + }, + { + key: 'todo', + title: + t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' + ), + }, + ], + }, + { + name: 'eserviceTemplate', + title: t('provider.eserviceTemplate.title'), + components: [ + { + key: 'newEserviceTemplateVersionToInstantiator', + title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', + description: t( + 'provider.eserviceTemplate.components.instanceFromTemplate.description' + ), + }, + { + key: 'eserviceTemplateStatusChangedToInstantiator', + title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', + description: t( + 'provider.eserviceTemplate.components.templateStateUpdated.description' + ), + }, + { + key: 'newTemplateVersion', + title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', + description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), + }, + { + key: 'eserviceTemplateNameChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', + description: t( + 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' + ), + }, + { + key: 'templateStatusChangedToProducer', + title: + t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + + '(09)', + description: t( + 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' + ), + }, + ], + }, + ], + }, + delegations: { + title: t('delegation.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('delegation.delegationAssignment.title'), + components: [ + { + key: 'delegationApprovedRejectedToDelegator', + title: + t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', + description: t( + 'delegation.delegationAssignment.components.delegationUpdated.description' + ), + }, + { + key: 'eserviceNewVersionSubmittedToDelegator', + title: + t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + + '(21)', + description: t( + 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' + ), + }, + ], + }, + { + name: 'delegationReceive', + title: t('delegation.delegationReceive.title'), + components: [ + { + key: 'delegationSubmittedRevokedToDelegate', + title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', + description: t( + 'delegation.delegationReceive.components.delegationUpdated.description' + ), + }, + { + key: 'eserviceNewVersionApprovedRejectedToDelegate', + title: + t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + + '(22)', + description: t( + 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' + ), + }, + ], + }, + ], + }, + keyAndAttributes: { + title: t('keyAndAttributes.title'), + subsections: [ + { + name: 'attributes', + title: t('keyAndAttributes.attributes.title'), + components: [ + { + key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', + title: + t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', + description: t( + 'keyAndAttributes.attributes.components.attributesStateUpdated.description' + ), + }, + ], + }, + { + name: 'keys', + title: t('keyAndAttributes.keys.title'), + components: [ + { + key: 'clientKeyAddedDeletedToClientUsers', + title: + t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', + description: t( + 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' + ), + }, + ], + }, + ], + }, + } + return ( diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index 84066920d..b2f6f2da5 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -24,8 +24,8 @@ export const NotificationConfigSection: React.FC {subsection.components.map((component) => ( } diff --git a/src/static/locales/en/notification.json b/src/static/locales/en/notification.json index 60c7c8a0c..66aedc511 100644 --- a/src/static/locales/en/notification.json +++ b/src/static/locales/en/notification.json @@ -10,6 +10,169 @@ "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" + }, + "subscriber": { + "title": "Fruizione", + "dataUsage": { + "title": "Fruizione dei dati", + "components": { + "eServiceStateUpdated": { + "label": "Variazione di stato degli e-service", + "description": "Avvisami quando lo stato di un e-service cambia" + }, + "agreementManagement": { + "label": "Accettazione o rifiuto delle richieste di fruizione", + "description": "Avvisami quando una mia richiesta di fruizione viene accettata o rifiutata" + }, + "agreementStateUpdated": { + "label": "Variazione dello stato della richiesta di fruizione", + "description": "Avvisami quando una mia richiesta di fruizione viene sospesa o riattivata" + } + } + }, + "purpose": { + "title": "Finalità", + "components": { + "purposeManagement": { + "label": "Accettazione o rifiuto di una finalità", + "description": "Avvisami quando una finalità viene accettata o rifiutata" + }, + "purposeStateUpdated": { + "label": "Variazione di stato di una finalità", + "description": "Avvisami quando lo stato di una finalità viene sospesa, archiviata o riattivata" + } + } + }, + "thresholds": { + "title": "Soglie di carico", + "components": { + "thresholdsExcedeed": { + "label": "Stato delle soglie di carico", + "description": "Avvisami quando una mia richiesta supera le soglie massime stabilite dall’erogatore" + }, + "thresholsdAdjustmentRequest": { + "label": "Richiesta di adeguamento soglia", + "description": "Avvisami quando un erogatore accetta o rifiuta una richiesta di adeguamento delle soglie" + } + } + } + }, + "provider": { + "title": "Erogazione", + "agreement": { + "title": "Richieste di fruizione", + "components": { + "agreementRequestReceived": { + "label": "Gestione delle richieste di fruizione in arrivo", + "description": "Avvisami sulle nuove richieste di fruizione in arrivo e quelle accettate automaticamente" + }, + "agreementStateUpdated": { + "label": "Variazione dello stato di una richiesta di fruizione", + "description": "Avvisami se una richiesta di fruizione per un mio e-service viene sospesa, archiviata o riattivata" + } + } + }, + "purpose": { + "title": "Finalità", + "components": { + "purposeStateUpdated": { + "label": "Variazioni di stato di una finalità", + "description": "Avvisami quando una finalità collegata ad un mio e-service viene sospesa, archiviata o riattivata" + } + } + }, + "clientAndThresholds": { + "title": "Client e soglie", + "components": { + "clientAssociationFromSubscriber": { + "label": "Associazione di un client da parte del fruitore", + "description": "Avvisami quando un fruitore associa un client ad un mio e-service" + }, + "thresholdExceeded": { + "label": "Superamento delle soglie", + "description": "Avvisami quando la stima di carico complessiva che ho stabilito per un mio e-service viene superata" + }, + "thresholdAdjustmentRequest": { + "label": "Richiesta di adeguamento soglia", + "description": "Avvisami quando un fruitore richiede una modifica delle soglie di un mio e-service" + } + } + }, + "eserviceTemplate": { + "title": "Template di e-service", + "components": { + "instanceFromTemplate": { + "label": "Generazione istanze da template e-service", + "description": "Avvisami quando viene generata un’istanza di e-service da un mio template" + }, + "templateStateUpdated": { + "label": "Variazione dello stato di un template", + "description": "Avvisami quando lo stato di un mio template viene modificato" + }, + "newTemplateVersion": { + "label": "Nuova versione di template", + "description": "Avvisami quando il creatore di un template di mio interesse e-service pubblica una nuova versione" + }, + "templatePropertiesUpdated": { + "label": "Variazione delle proprietà di un template", + "description": "Avvisami quando le proprietà di un template di mio interesse vengono modificate" + }, + "templateStateArchivedSuspended": { + "label": "Variazione dello stato di un template", + "description": "Avvisami quando un template di mio interesse viene sospeso, archiviato o riattivato" + } + } + } + }, + "delegation": { + "title": "Deleghe", + "delegationAssignment": { + "title": "Conferimento di un e-service in delega", + "components": { + "delegationUpdated": { + "label": "Stato di accettazione di una delega", + "description": "Avvisami quando una delega viene accettata o rifiutata dall’ente a cui l’ho conferita" + }, + "eserviceDelegatedCreated": { + "label": "Approvazione delle richieste del delegato", + "description": "Avvisami quando il delegato genera una nuova versione di e-service in delega affinché possa valutarla" + } + } + }, + "delegationReceive": { + "title": "Ricezione di una delega per un e-service", + "components": { + "delegationUpdated": { + "label": "Stato delle deleghe ricevute", + "description": "Avvisami quando un ente mi affida o mi revoca la gestione di un e-service tramite delega" + }, + "eserviceDelegatedApproval": { + "label": "Approvazione della pubblicazione di una nuova versione di e-service", + "description": "Avvisami quando l’ente delegante ha approvato o rifiutato la mia richiesta di variazione della versione" + } + } + } + }, + "keyAndAttributes": { + "title": "Attributi e chiavi", + "attributes": { + "title": "Attributi certificati o verificati", + "components": { + "attributesStateUpdated": { + "label": "Conferimento o revoca di attributi certificati o verificati", + "description": "Avvisami quando mi viene conferito o revocato un attributo certificato o verificato" + } + } + }, + "keys": { + "title": "Chiavi", + "components": { + "clientKeysAssociationUpdated": { + "label": "Variazioni sullo stato delle chiavi collegate ad un client", + "description": "Avvisami quando lo stato di una chiave collegata ad un client cambia oppure è bene venga sostituita." + } + } + } } } } diff --git a/src/static/locales/it/notification.json b/src/static/locales/it/notification.json index 60c7c8a0c..66aedc511 100644 --- a/src/static/locales/it/notification.json +++ b/src/static/locales/it/notification.json @@ -10,6 +10,169 @@ "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" + }, + "subscriber": { + "title": "Fruizione", + "dataUsage": { + "title": "Fruizione dei dati", + "components": { + "eServiceStateUpdated": { + "label": "Variazione di stato degli e-service", + "description": "Avvisami quando lo stato di un e-service cambia" + }, + "agreementManagement": { + "label": "Accettazione o rifiuto delle richieste di fruizione", + "description": "Avvisami quando una mia richiesta di fruizione viene accettata o rifiutata" + }, + "agreementStateUpdated": { + "label": "Variazione dello stato della richiesta di fruizione", + "description": "Avvisami quando una mia richiesta di fruizione viene sospesa o riattivata" + } + } + }, + "purpose": { + "title": "Finalità", + "components": { + "purposeManagement": { + "label": "Accettazione o rifiuto di una finalità", + "description": "Avvisami quando una finalità viene accettata o rifiutata" + }, + "purposeStateUpdated": { + "label": "Variazione di stato di una finalità", + "description": "Avvisami quando lo stato di una finalità viene sospesa, archiviata o riattivata" + } + } + }, + "thresholds": { + "title": "Soglie di carico", + "components": { + "thresholdsExcedeed": { + "label": "Stato delle soglie di carico", + "description": "Avvisami quando una mia richiesta supera le soglie massime stabilite dall’erogatore" + }, + "thresholsdAdjustmentRequest": { + "label": "Richiesta di adeguamento soglia", + "description": "Avvisami quando un erogatore accetta o rifiuta una richiesta di adeguamento delle soglie" + } + } + } + }, + "provider": { + "title": "Erogazione", + "agreement": { + "title": "Richieste di fruizione", + "components": { + "agreementRequestReceived": { + "label": "Gestione delle richieste di fruizione in arrivo", + "description": "Avvisami sulle nuove richieste di fruizione in arrivo e quelle accettate automaticamente" + }, + "agreementStateUpdated": { + "label": "Variazione dello stato di una richiesta di fruizione", + "description": "Avvisami se una richiesta di fruizione per un mio e-service viene sospesa, archiviata o riattivata" + } + } + }, + "purpose": { + "title": "Finalità", + "components": { + "purposeStateUpdated": { + "label": "Variazioni di stato di una finalità", + "description": "Avvisami quando una finalità collegata ad un mio e-service viene sospesa, archiviata o riattivata" + } + } + }, + "clientAndThresholds": { + "title": "Client e soglie", + "components": { + "clientAssociationFromSubscriber": { + "label": "Associazione di un client da parte del fruitore", + "description": "Avvisami quando un fruitore associa un client ad un mio e-service" + }, + "thresholdExceeded": { + "label": "Superamento delle soglie", + "description": "Avvisami quando la stima di carico complessiva che ho stabilito per un mio e-service viene superata" + }, + "thresholdAdjustmentRequest": { + "label": "Richiesta di adeguamento soglia", + "description": "Avvisami quando un fruitore richiede una modifica delle soglie di un mio e-service" + } + } + }, + "eserviceTemplate": { + "title": "Template di e-service", + "components": { + "instanceFromTemplate": { + "label": "Generazione istanze da template e-service", + "description": "Avvisami quando viene generata un’istanza di e-service da un mio template" + }, + "templateStateUpdated": { + "label": "Variazione dello stato di un template", + "description": "Avvisami quando lo stato di un mio template viene modificato" + }, + "newTemplateVersion": { + "label": "Nuova versione di template", + "description": "Avvisami quando il creatore di un template di mio interesse e-service pubblica una nuova versione" + }, + "templatePropertiesUpdated": { + "label": "Variazione delle proprietà di un template", + "description": "Avvisami quando le proprietà di un template di mio interesse vengono modificate" + }, + "templateStateArchivedSuspended": { + "label": "Variazione dello stato di un template", + "description": "Avvisami quando un template di mio interesse viene sospeso, archiviato o riattivato" + } + } + } + }, + "delegation": { + "title": "Deleghe", + "delegationAssignment": { + "title": "Conferimento di un e-service in delega", + "components": { + "delegationUpdated": { + "label": "Stato di accettazione di una delega", + "description": "Avvisami quando una delega viene accettata o rifiutata dall’ente a cui l’ho conferita" + }, + "eserviceDelegatedCreated": { + "label": "Approvazione delle richieste del delegato", + "description": "Avvisami quando il delegato genera una nuova versione di e-service in delega affinché possa valutarla" + } + } + }, + "delegationReceive": { + "title": "Ricezione di una delega per un e-service", + "components": { + "delegationUpdated": { + "label": "Stato delle deleghe ricevute", + "description": "Avvisami quando un ente mi affida o mi revoca la gestione di un e-service tramite delega" + }, + "eserviceDelegatedApproval": { + "label": "Approvazione della pubblicazione di una nuova versione di e-service", + "description": "Avvisami quando l’ente delegante ha approvato o rifiutato la mia richiesta di variazione della versione" + } + } + } + }, + "keyAndAttributes": { + "title": "Attributi e chiavi", + "attributes": { + "title": "Attributi certificati o verificati", + "components": { + "attributesStateUpdated": { + "label": "Conferimento o revoca di attributi certificati o verificati", + "description": "Avvisami quando mi viene conferito o revocato un attributo certificato o verificato" + } + } + }, + "keys": { + "title": "Chiavi", + "components": { + "clientKeysAssociationUpdated": { + "label": "Variazioni sullo stato delle chiavi collegate ad un client", + "description": "Avvisami quando lo stato di una chiave collegata ad un client cambia oppure è bene venga sostituita." + } + } + } } } } From b970629944836e07addebd197ae84758f6c67977 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Thu, 28 Aug 2025 12:35:47 +0200 Subject: [PATCH 09/53] chore: added services and queries --- src/api/notification/index.ts | 1 + .../notification/notification.mutations.ts | 4 +- src/api/notification/notification.queries.ts | 15 + src/api/notification/notification.services.ts | 19 +- .../InAppNotificationUserConfigTab.tsx | 263 +----------------- .../hooks/useNotificationInAppConfigForm.ts | 259 +++++++++++++++++ 6 files changed, 306 insertions(+), 255 deletions(-) create mode 100644 src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts diff --git a/src/api/notification/index.ts b/src/api/notification/index.ts index 45bee0122..1a2c159ef 100644 --- a/src/api/notification/index.ts +++ b/src/api/notification/index.ts @@ -1,2 +1,3 @@ export * from './notification.services' export * from './notification.mutations' +export * from './notification.queries' diff --git a/src/api/notification/notification.mutations.ts b/src/api/notification/notification.mutations.ts index cd3309c42..5b6864d4c 100644 --- a/src/api/notification/notification.mutations.ts +++ b/src/api/notification/notification.mutations.ts @@ -1,8 +1,8 @@ import { useMutation } from '@tanstack/react-query' -import { notificationServices } from './index' +import { NotificationServices } from './index' function useUpdateNotificationUserConfigs() { return useMutation({ - mutationFn: notificationServices.updateUserNotificationConfiguration, + mutationFn: NotificationServices.updateUserNotificationConfiguration, }) } diff --git a/src/api/notification/notification.queries.ts b/src/api/notification/notification.queries.ts index e69de29bb..3913ca8d7 100644 --- a/src/api/notification/notification.queries.ts +++ b/src/api/notification/notification.queries.ts @@ -0,0 +1,15 @@ +import { queryOptions } from '@tanstack/react-query' +import { NotificationServices } from './notification.services' +import { AgreementServices } from '../agreement' +import { GetAgreementsProducersParams } from '../api.generatedTypes' + +function getUserNotificationConfiguration() { + return queryOptions({ + queryKey: ['getUserNotificationConfiguration'], + queryFn: () => NotificationServices.getUserNotificationConfiguration(), + }) +} + +export const NotificationQueries = { + getUserNotificationConfiguration, +} diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index 49a10507e..9a184518c 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -1,12 +1,25 @@ import axiosInstance from '@/config/axios' import { BACKEND_FOR_FRONTEND_URL } from '@/config/env' -import type { NotificationCon } from '../api.generatedTypes' +import type { + UserNotificationConfig, + UserNotificationConfigUpdateSeed, +} from '../api.generatedTypes' -async function updateUserNotificationConfiguration(payload: unknown) { +async function updateUserNotificationConfiguration(payload: UserNotificationConfigUpdateSeed) { return await axiosInstance.post( `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs`, payload ) } -export const notificationServices = { updateUserNotificationConfiguration } +async function getUserNotificationConfiguration() { + const response = await axiosInstance.get( + `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs` + ) + return response.data +} + +export const NotificationServices = { + updateUserNotificationConfiguration, + getUserNotificationConfiguration, +} diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index cf4527b2b..0296c2a4c 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -5,6 +5,9 @@ import { Box, Card, Link, Stack, Typography } from '@mui/material' import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' +import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' +import { keepPreviousData, useQuery } from '@tanstack/react-query' +import { NotificationQueries } from '@/api/notification' export type NotificationSubSectionSchema = { name: string @@ -23,260 +26,20 @@ export type NotificationConfigSchema = { [key: string]: NotificationSectionSchema } +// TODO: Definire get +// TODO: Definire i campi che sono visibili in base al role +// TODO: Definire POST + export const InAppNotificationUserConfigTab = () => { const formMethods = useForm() const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) - const notificationSchema: NotificationConfigSchema = { - subscriber: { - title: t('subscriber.title'), - subsections: [ - { - name: 'fruizioneDati', - title: t('subscriber.dataUsage.title'), - components: [ - { - key: 'eserviceStateChangedToConsumer', - title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', - description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), - }, - { - key: 'agreementActivatedRejectedToConsumer', - title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', - description: t('subscriber.dataUsage.components.agreementManagement.description'), - }, - { - key: 'agreementSuspendedUnsuspendedToConsumer', - title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', - description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), - }, - ], - }, - { - name: 'finalita', - title: t('subscriber.purpose.title'), - components: [ - { - key: 'purposeActivatedRejectedToConsumer', - title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', - description: t('subscriber.purpose.components.purposeManagement.description'), - }, - { - key: 'purposeSuspendedUnsuspendedToConsumer', - title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', - description: t('subscriber.purpose.components.purposeStateUpdated.description'), - }, - ], - }, - { - name: 'soglieDiCarico', - title: t('subscriber.thresholds.title'), - components: [ - { - key: 'statoSoglieDiCarico', - title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), - description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), - }, - { - key: 'adeguamentoSoglia', - title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), - description: t( - 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' - ), - }, - ], - }, - ], - }, - provider: { - title: t('provider.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('provider.agreement.title'), - components: [ - { - key: 'agreementManagementToProducer', - title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', - description: t('provider.agreement.components.agreementRequestReceived.description'), - }, - { - key: 'agreementSuspendedUnsuspendedToProducer', - title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', - description: t('provider.agreement.components.agreementStateUpdated.description'), - }, - ], - }, - { - name: 'finalita', - title: t('provider.purpose.title'), - components: [ - { - key: 'purposeStatusChangedToProducer', - title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', - description: t('provider.purpose.components.purposeStateUpdated.description'), - }, - ], - }, - { - name: 'clientSoglieDiCarico', - title: t('provider.clientAndThresholds.title'), - components: [ - { - key: 'clientAddedRemovedToProducer', - title: - t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + - '(05)', - description: t( - 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' - ), - }, - { - key: 'todo', - title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdExceeded.description' - ), - }, - { - key: 'todo', - title: - t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + - 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' - ), - }, - ], - }, - { - name: 'eserviceTemplate', - title: t('provider.eserviceTemplate.title'), - components: [ - { - key: 'newEserviceTemplateVersionToInstantiator', - title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', - description: t( - 'provider.eserviceTemplate.components.instanceFromTemplate.description' - ), - }, - { - key: 'eserviceTemplateStatusChangedToInstantiator', - title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', - description: t( - 'provider.eserviceTemplate.components.templateStateUpdated.description' - ), - }, - { - key: 'newTemplateVersion', - title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', - description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), - }, - { - key: 'eserviceTemplateNameChangedToInstantiator', - title: - t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', - description: t( - 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' - ), - }, - { - key: 'templateStatusChangedToProducer', - title: - t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + - '(09)', - description: t( - 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' - ), - }, - ], - }, - ], - }, - delegations: { - title: t('delegation.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('delegation.delegationAssignment.title'), - components: [ - { - key: 'delegationApprovedRejectedToDelegator', - title: - t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', - description: t( - 'delegation.delegationAssignment.components.delegationUpdated.description' - ), - }, - { - key: 'eserviceNewVersionSubmittedToDelegator', - title: - t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + - '(21)', - description: t( - 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' - ), - }, - ], - }, - { - name: 'delegationReceive', - title: t('delegation.delegationReceive.title'), - components: [ - { - key: 'delegationSubmittedRevokedToDelegate', - title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', - description: t( - 'delegation.delegationReceive.components.delegationUpdated.description' - ), - }, - { - key: 'eserviceNewVersionApprovedRejectedToDelegate', - title: - t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + - '(22)', - description: t( - 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' - ), - }, - ], - }, - ], - }, - keyAndAttributes: { - title: t('keyAndAttributes.title'), - subsections: [ - { - name: 'attributes', - title: t('keyAndAttributes.attributes.title'), - components: [ - { - key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', - title: - t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', - description: t( - 'keyAndAttributes.attributes.components.attributesStateUpdated.description' - ), - }, - ], - }, - { - name: 'keys', - title: t('keyAndAttributes.keys.title'), - components: [ - { - key: 'clientKeyAddedDeletedToClientUsers', - title: - t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', - description: t( - 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' - ), - }, - ], - }, - ], - }, - } + // const { data } = useQuery({ + // ...NotificationQueries.getUserNotificationConfiguration(), + // placeholderData: keepPreviousData, + // }) + + const { notificationSchema } = useNotificationInAppConfigForm() return ( diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts new file mode 100644 index 000000000..5e81db968 --- /dev/null +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -0,0 +1,259 @@ +import { useTranslation } from 'react-i18next' +import { type NotificationConfigSchema } from '../components/InAppNotificationUserConfigTab' + +export function useNotificationInAppConfigForm() { + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) + + const notificationSchema: NotificationConfigSchema = { + subscriber: { + title: t('subscriber.title'), + subsections: [ + { + name: 'fruizioneDati', + title: t('subscriber.dataUsage.title'), + components: [ + { + key: 'eserviceStateChangedToConsumer', + title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', + description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + }, + { + key: 'agreementActivatedRejectedToConsumer', + title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', + description: t('subscriber.dataUsage.components.agreementManagement.description'), + }, + { + key: 'agreementSuspendedUnsuspendedToConsumer', + title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', + description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + }, + ], + }, + { + name: 'finalita', + title: t('subscriber.purpose.title'), + components: [ + { + key: 'purposeActivatedRejectedToConsumer', + title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', + description: t('subscriber.purpose.components.purposeManagement.description'), + }, + { + key: 'purposeSuspendedUnsuspendedToConsumer', + title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', + description: t('subscriber.purpose.components.purposeStateUpdated.description'), + }, + ], + }, + { + name: 'soglieDiCarico', + title: t('subscriber.thresholds.title'), + components: [ + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), + description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + }, + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), + description: t( + 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' + ), + }, + ], + }, + ], + }, + provider: { + title: t('provider.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('provider.agreement.title'), + components: [ + { + key: 'agreementManagementToProducer', + title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', + description: t('provider.agreement.components.agreementRequestReceived.description'), + }, + { + key: 'agreementSuspendedUnsuspendedToProducer', + title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', + description: t('provider.agreement.components.agreementStateUpdated.description'), + }, + ], + }, + { + name: 'finalita', + title: t('provider.purpose.title'), + components: [ + { + key: 'purposeStatusChangedToProducer', + title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', + description: t('provider.purpose.components.purposeStateUpdated.description'), + }, + ], + }, + { + name: 'clientSoglieDiCarico', + title: t('provider.clientAndThresholds.title'), + components: [ + { + key: 'clientAddedRemovedToProducer', + title: + t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + + '(05)', + description: t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' + ), + }, + { + key: 'TODO', + title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdExceeded.description' + ), + }, + { + key: 'TODO', + title: + t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' + ), + }, + ], + }, + { + name: 'eserviceTemplate', + title: t('provider.eserviceTemplate.title'), + components: [ + { + key: 'newEserviceTemplateVersionToInstantiator', + title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', + description: t( + 'provider.eserviceTemplate.components.instanceFromTemplate.description' + ), + }, + { + key: 'eserviceTemplateStatusChangedToInstantiator', + title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', + description: t( + 'provider.eserviceTemplate.components.templateStateUpdated.description' + ), + }, + { + key: 'newTemplateVersion', + title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', + description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), + }, + { + key: 'eserviceTemplateNameChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', + description: t( + 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' + ), + }, + { + key: 'templateStatusChangedToProducer', + title: + t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + + '(09)', + description: t( + 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' + ), + }, + ], + }, + ], + }, + delegations: { + title: t('delegation.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('delegation.delegationAssignment.title'), + components: [ + { + key: 'delegationApprovedRejectedToDelegator', + title: + t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', + description: t( + 'delegation.delegationAssignment.components.delegationUpdated.description' + ), + }, + { + key: 'eserviceNewVersionSubmittedToDelegator', + title: + t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + + '(21)', + description: t( + 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' + ), + }, + ], + }, + { + name: 'delegationReceive', + title: t('delegation.delegationReceive.title'), + components: [ + { + key: 'delegationSubmittedRevokedToDelegate', + title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', + description: t( + 'delegation.delegationReceive.components.delegationUpdated.description' + ), + }, + { + key: 'eserviceNewVersionApprovedRejectedToDelegate', + title: + t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + + '(22)', + description: t( + 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' + ), + }, + ], + }, + ], + }, + keyAndAttributes: { + title: t('keyAndAttributes.title'), + subsections: [ + { + name: 'attributes', + title: t('keyAndAttributes.attributes.title'), + components: [ + { + key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', + title: + t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', + description: t( + 'keyAndAttributes.attributes.components.attributesStateUpdated.description' + ), + }, + ], + }, + { + name: 'keys', + title: t('keyAndAttributes.keys.title'), + components: [ + { + key: 'clientKeyAddedDeletedToClientUsers', + title: + t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', + description: t( + 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' + ), + }, + ], + }, + ], + }, + } + + return { notificationSchema } +} From 6628007e5faf44dd8d522e6e92152b2c4aa3c62f Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Tue, 2 Sep 2025 16:37:24 +0200 Subject: [PATCH 10/53] chore: added defaultValue retrieving from get (mocked) api --- scripts/open-api-type-generator.js | 2 +- src/api/api.generatedTypes.ts | 30 +++++++- src/api/notification/notification.queries.ts | 2 - src/api/notification/notification.services.ts | 44 ++++++++++- .../NotificationUserConfig.page.tsx | 12 ++- .../EmailNotificationUserConfigTab.tsx | 8 +- .../InAppNotificationUserConfigTab.tsx | 75 ++++++++++--------- .../components/NotificationConfigSection.tsx | 8 +- .../hooks/useNotificationInAppConfigForm.ts | 22 +++++- 9 files changed, 147 insertions(+), 56 deletions(-) diff --git a/scripts/open-api-type-generator.js b/scripts/open-api-type-generator.js index c9ffa9873..5f3eea3df 100644 --- a/scripts/open-api-type-generator.js +++ b/scripts/open-api-type-generator.js @@ -2,7 +2,7 @@ import { generateApi } from 'swagger-typescript-api' import path from 'path' const openApiSpecificationFileUrl = - 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/develop/packages/api-clients/open-api/bffApi.yml' + 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/update-bff-api/packages/api-clients/open-api/bffApi.yml' const apiFolderPath = path.resolve('./src/api/') diff --git a/src/api/api.generatedTypes.ts b/src/api/api.generatedTypes.ts index f103693be..73e842e27 100644 --- a/src/api/api.generatedTypes.ts +++ b/src/api/api.generatedTypes.ts @@ -1997,17 +1997,39 @@ export interface Notification { } export interface NotificationConfig { - newEServiceVersionPublished: boolean + agreementSuspendedUnsuspendedToProducer: boolean + agreementManagementToProducer: boolean + clientAddedRemovedToProducer: boolean + purposeStatusChangedToProducer: boolean + templateStatusChangedToProducer: boolean + agreementSuspendedUnsuspendedToConsumer: boolean + eserviceStateChangedToConsumer: boolean + agreementActivatedRejectedToConsumer: boolean + purposeActivatedRejectedToConsumer: boolean + purposeSuspendedUnsuspendedToConsumer: boolean + newEserviceTemplateVersionToInstantiator: boolean + eserviceTemplateNameChangedToInstantiator: boolean + eserviceTemplateStatusChangedToInstantiator: boolean + delegationApprovedRejectedToDelegator: boolean + eserviceNewVersionSubmittedToDelegator: boolean + eserviceNewVersionApprovedRejectedToDelegate: boolean + delegationSubmittedRevokedToDelegate: boolean + certifiedVerifiedAttributeAssignedRevokedToAssignee: boolean + clientKeyAddedDeletedToClientUsers: boolean +} + +export interface TenantNotificationConfig { + enabled: boolean } -export type TenantNotificationConfig = NotificationConfig - export interface UserNotificationConfig { inAppConfig: NotificationConfig emailConfig: NotificationConfig } -export type TenantNotificationConfigUpdateSeed = NotificationConfig +export interface TenantNotificationConfigUpdateSeed { + enabled: boolean +} export interface UserNotificationConfigUpdateSeed { inAppConfig: NotificationConfig diff --git a/src/api/notification/notification.queries.ts b/src/api/notification/notification.queries.ts index 3913ca8d7..765c26870 100644 --- a/src/api/notification/notification.queries.ts +++ b/src/api/notification/notification.queries.ts @@ -1,7 +1,5 @@ import { queryOptions } from '@tanstack/react-query' import { NotificationServices } from './notification.services' -import { AgreementServices } from '../agreement' -import { GetAgreementsProducersParams } from '../api.generatedTypes' function getUserNotificationConfiguration() { return queryOptions({ diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index 9a184518c..610bfb90f 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -1,6 +1,7 @@ import axiosInstance from '@/config/axios' import { BACKEND_FOR_FRONTEND_URL } from '@/config/env' import type { + NotificationConfig, UserNotificationConfig, UserNotificationConfigUpdateSeed, } from '../api.generatedTypes' @@ -13,13 +14,48 @@ async function updateUserNotificationConfiguration(payload: UserNotificationConf } async function getUserNotificationConfiguration() { - const response = await axiosInstance.get( - `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs` - ) - return response.data + // const response = await axiosInstance.get( + // `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs` + // ) + // return response.data + + return new Promise((resolve) => { + setTimeout(() => { + resolve({ + emailConfig: getNotificationConfig(Math.random() < 0.5), + inAppConfig: getNotificationConfig(Math.random() < 0.5), + }) + }, 1000) + }) } export const NotificationServices = { updateUserNotificationConfiguration, getUserNotificationConfiguration, } + +//TODO: To delete: + +function getNotificationConfig(randomValue: boolean): NotificationConfig { + return { + agreementSuspendedUnsuspendedToProducer: randomValue, // 04 + agreementManagementToProducer: randomValue, // 03 + clientAddedRemovedToProducer: randomValue, // 05 + purposeStatusChangedToProducer: randomValue, // 07 + templateStatusChangedToProducer: randomValue, //09 + agreementSuspendedUnsuspendedToConsumer: randomValue, // 13 + eserviceStateChangedToConsumer: randomValue, // 11 + agreementActivatedRejectedToConsumer: randomValue, // 12 + purposeActivatedRejectedToConsumer: randomValue, // 15 + purposeSuspendedUnsuspendedToConsumer: randomValue, // 16 + newEserviceTemplateVersionToInstantiator: randomValue, // 17 + eserviceTemplateNameChangedToInstantiator: randomValue, //18 + eserviceTemplateStatusChangedToInstantiator: randomValue, // 19 + delegationApprovedRejectedToDelegator: randomValue, // 20 + eserviceNewVersionSubmittedToDelegator: randomValue, // 21 + eserviceNewVersionApprovedRejectedToDelegate: randomValue, // 22 + delegationSubmittedRevokedToDelegate: randomValue, // 23 + certifiedVerifiedAttributeAssignedRevokedToAssignee: randomValue, // 24 + clientKeyAddedDeletedToClientUsers: randomValue, // 25 + } +} diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index bd4f8d2bc..c41f96ed4 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -5,11 +5,18 @@ import { Tab } from '@mui/material' import { EmailNotificationUserConfigTab } from './components/EmailNotificationUserConfigTab' import { InAppNotificationUserConfigTab } from './components/InAppNotificationUserConfigTab' import { useTranslation } from 'react-i18next' +import { NotificationQueries } from '@/api/notification' +import { keepPreviousData, useQuery } from '@tanstack/react-query' const NotificationUserConfigPage: React.FC = () => { const { activeTab, updateActiveTab } = useActiveTab('notificationConfig') const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) + const { data } = useQuery({ + ...NotificationQueries.getUserNotificationConfiguration(), + placeholderData: keepPreviousData, + }) + return ( {
- + {/* TODO: Put load skeleton here */} + {data?.inAppConfig && } - + {data?.emailConfig && }{' '}
diff --git a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx index 888408f27..f738f6406 100644 --- a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx @@ -1,5 +1,9 @@ +import type { NotificationConfig } from '@/api/api.generatedTypes' import { FormProvider, useForm } from 'react-hook-form' +type EmailNotificationUserConfigTabProps = { + emailConfig: NotificationConfig +} export type NotificationSectionSchema = { title: string subsections: { @@ -51,7 +55,9 @@ const notificationSchema: NotificationConfigSchema = { }, } -export const EmailNotificationUserConfigTab = () => { +export const EmailNotificationUserConfigTab: React.FC = ({ + emailConfig, +}) => { const formMethods = useForm() return ( diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index 0296c2a4c..b8ef3d8a5 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -6,9 +6,12 @@ import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hoo import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' -import { keepPreviousData, useQuery } from '@tanstack/react-query' -import { NotificationQueries } from '@/api/notification' +import { type NotificationConfig } from '@/api/api.generatedTypes' +import React from 'react' +type InAppNotificationUserConfigTabProps = { + inAppConfig: NotificationConfig +} export type NotificationSubSectionSchema = { name: string title: string @@ -16,6 +19,7 @@ export type NotificationSubSectionSchema = { key: string title: string description: string + defaultValue?: boolean }[] } export type NotificationSectionSchema = { @@ -30,16 +34,15 @@ export type NotificationConfigSchema = { // TODO: Definire i campi che sono visibili in base al role // TODO: Definire POST -export const InAppNotificationUserConfigTab = () => { +export const InAppNotificationUserConfigTab: React.FC = ({ + inAppConfig, +}) => { const formMethods = useForm() const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) - // const { data } = useQuery({ - // ...NotificationQueries.getUserNotificationConfiguration(), - // placeholderData: keepPreviousData, - // }) + const { notificationSchema } = useNotificationInAppConfigForm(inAppConfig) - const { notificationSchema } = useNotificationInAppConfigForm() + const enableAllNotifications = formMethods.watch('enableShowNotification', true) return ( @@ -49,7 +52,8 @@ export const InAppNotificationUserConfigTab = () => { { } /> - {Object.keys(notificationSchema).map((sectionName) => { - return ( - - - - - - - {notificationSchema[sectionName].title} - - + {enableAllNotifications && + Object.keys(notificationSchema).map((sectionName) => { + return ( + + + + + + + {notificationSchema[sectionName].title} + + - - + + - {notificationSchema[sectionName].subsections.map((subsection) => ( - - ))} - - - ) - })} + {notificationSchema[sectionName].subsections.map((subsection) => ( + + ))} + + + ) + })} diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index b2f6f2da5..051564846 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -1,9 +1,8 @@ import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { Box } from '@mui/system' import { useFormContext } from 'react-hook-form' -import type { NotificationSectionSchema } from './EmailNotificationUserConfigTab' import { Typography } from '@mui/material' -import { NotificationSubSectionSchema } from './InAppNotificationUserConfigTab' +import type { NotificationSubSectionSchema } from './InAppNotificationUserConfigTab' type NotificationConfigSectionProps = { subsection: NotificationSubSectionSchema @@ -11,10 +10,6 @@ type NotificationConfigSectionProps = { export const NotificationConfigSection: React.FC = ({ subsection, }) => { - const { watch } = useFormContext() - - const customizeNotification = watch('generalUpdate') - return ( <> @@ -26,6 +21,7 @@ export const NotificationConfigSection: React.FC sx={{ mt: 1, mb: 1 }} key={component.key} name={component.key} + defaultChecked={component.defaultValue} label={ } diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts index 5e81db968..3067c8bfe 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -1,7 +1,8 @@ import { useTranslation } from 'react-i18next' import { type NotificationConfigSchema } from '../components/InAppNotificationUserConfigTab' +import type { NotificationConfig } from '@/api/api.generatedTypes' -export function useNotificationInAppConfigForm() { +export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) const notificationSchema: NotificationConfigSchema = { @@ -16,16 +17,19 @@ export function useNotificationInAppConfigForm() { key: 'eserviceStateChangedToConsumer', title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + defaultValue: inAppConfig?.eserviceStateChangedToConsumer, }, { key: 'agreementActivatedRejectedToConsumer', title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', description: t('subscriber.dataUsage.components.agreementManagement.description'), + defaultValue: inAppConfig?.agreementActivatedRejectedToConsumer, }, { key: 'agreementSuspendedUnsuspendedToConsumer', title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + defaultValue: inAppConfig?.agreementSuspendedUnsuspendedToConsumer, }, ], }, @@ -37,11 +41,13 @@ export function useNotificationInAppConfigForm() { key: 'purposeActivatedRejectedToConsumer', title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', description: t('subscriber.purpose.components.purposeManagement.description'), + defaultValue: inAppConfig?.purposeActivatedRejectedToConsumer, }, { key: 'purposeSuspendedUnsuspendedToConsumer', title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', description: t('subscriber.purpose.components.purposeStateUpdated.description'), + defaultValue: inAppConfig?.purposeSuspendedUnsuspendedToConsumer, }, ], }, @@ -76,11 +82,13 @@ export function useNotificationInAppConfigForm() { key: 'agreementManagementToProducer', title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', description: t('provider.agreement.components.agreementRequestReceived.description'), + defaultValue: inAppConfig.agreementManagementToProducer, }, { key: 'agreementSuspendedUnsuspendedToProducer', title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', description: t('provider.agreement.components.agreementStateUpdated.description'), + defaultValue: inAppConfig.agreementSuspendedUnsuspendedToProducer, }, ], }, @@ -92,6 +100,7 @@ export function useNotificationInAppConfigForm() { key: 'purposeStatusChangedToProducer', title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', description: t('provider.purpose.components.purposeStateUpdated.description'), + defaultValue: inAppConfig.purposeStatusChangedToProducer, }, ], }, @@ -107,6 +116,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' ), + defaultValue: inAppConfig.clientAddedRemovedToProducer, }, { key: 'TODO', @@ -136,6 +146,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.instanceFromTemplate.description' ), + defaultValue: inAppConfig.newEserviceTemplateVersionToInstantiator, }, { key: 'eserviceTemplateStatusChangedToInstantiator', @@ -143,6 +154,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.templateStateUpdated.description' ), + defaultValue: inAppConfig.eserviceTemplateStatusChangedToInstantiator, }, { key: 'newTemplateVersion', @@ -156,6 +168,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' ), + defaultValue: inAppConfig.eserviceTemplateNameChangedToInstantiator, }, { key: 'templateStatusChangedToProducer', @@ -165,6 +178,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' ), + defaultValue: inAppConfig.templateStatusChangedToProducer, }, ], }, @@ -184,6 +198,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationAssignment.components.delegationUpdated.description' ), + defaultValue: inAppConfig.delegationApprovedRejectedToDelegator, }, { key: 'eserviceNewVersionSubmittedToDelegator', @@ -193,6 +208,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' ), + defaultValue: inAppConfig.eserviceNewVersionSubmittedToDelegator, }, ], }, @@ -206,6 +222,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationReceive.components.delegationUpdated.description' ), + defaultValue: inAppConfig.delegationSubmittedRevokedToDelegate, }, { key: 'eserviceNewVersionApprovedRejectedToDelegate', @@ -215,6 +232,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' ), + defaultValue: inAppConfig.eserviceNewVersionApprovedRejectedToDelegate, }, ], }, @@ -234,6 +252,7 @@ export function useNotificationInAppConfigForm() { description: t( 'keyAndAttributes.attributes.components.attributesStateUpdated.description' ), + defaultValue: inAppConfig.certifiedVerifiedAttributeAssignedRevokedToAssignee, }, ], }, @@ -248,6 +267,7 @@ export function useNotificationInAppConfigForm() { description: t( 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' ), + defaultValue: inAppConfig.clientKeyAddedDeletedToClientUsers, }, ], }, From 17f12e5866b081556c77ce6f671fe08cfe218533 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Tue, 2 Sep 2025 17:01:37 +0200 Subject: [PATCH 11/53] refactor: removed var inAppConfig from hook --- .../InAppNotificationUserConfigTab.tsx | 22 ++++++++++++------- .../components/NotificationConfigSection.tsx | 2 -- .../hooks/useNotificationInAppConfigForm.ts | 22 +------------------ 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index b8ef3d8a5..cb9a49ba4 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' import { type NotificationConfig } from '@/api/api.generatedTypes' -import React from 'react' +import React, { useEffect } from 'react' type InAppNotificationUserConfigTabProps = { inAppConfig: NotificationConfig @@ -19,7 +19,6 @@ export type NotificationSubSectionSchema = { key: string title: string description: string - defaultValue?: boolean }[] } export type NotificationSectionSchema = { @@ -37,12 +36,19 @@ export type NotificationConfigSchema = { export const InAppNotificationUserConfigTab: React.FC = ({ inAppConfig, }) => { - const formMethods = useForm() const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) - const { notificationSchema } = useNotificationInAppConfigForm(inAppConfig) + const { notificationSchema } = useNotificationInAppConfigForm() - const enableAllNotifications = formMethods.watch('enableShowNotification', true) + const formMethods = useForm({ + defaultValues: inAppConfig, + }) + + const valueChanged = formMethods.watch() + + useEffect(() => { + console.log('valueChanged', valueChanged) + }, [valueChanged]) return ( @@ -52,8 +58,8 @@ export const InAppNotificationUserConfigTab: React.FC - {enableAllNotifications && + {true && Object.keys(notificationSchema).map((sectionName) => { return ( diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index 051564846..dcae5a34b 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -1,6 +1,5 @@ import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { Box } from '@mui/system' -import { useFormContext } from 'react-hook-form' import { Typography } from '@mui/material' import type { NotificationSubSectionSchema } from './InAppNotificationUserConfigTab' @@ -21,7 +20,6 @@ export const NotificationConfigSection: React.FC sx={{ mt: 1, mb: 1 }} key={component.key} name={component.key} - defaultChecked={component.defaultValue} label={ } diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts index 3067c8bfe..5e81db968 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -1,8 +1,7 @@ import { useTranslation } from 'react-i18next' import { type NotificationConfigSchema } from '../components/InAppNotificationUserConfigTab' -import type { NotificationConfig } from '@/api/api.generatedTypes' -export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) { +export function useNotificationInAppConfigForm() { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) const notificationSchema: NotificationConfigSchema = { @@ -17,19 +16,16 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) key: 'eserviceStateChangedToConsumer', title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), - defaultValue: inAppConfig?.eserviceStateChangedToConsumer, }, { key: 'agreementActivatedRejectedToConsumer', title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', description: t('subscriber.dataUsage.components.agreementManagement.description'), - defaultValue: inAppConfig?.agreementActivatedRejectedToConsumer, }, { key: 'agreementSuspendedUnsuspendedToConsumer', title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), - defaultValue: inAppConfig?.agreementSuspendedUnsuspendedToConsumer, }, ], }, @@ -41,13 +37,11 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) key: 'purposeActivatedRejectedToConsumer', title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', description: t('subscriber.purpose.components.purposeManagement.description'), - defaultValue: inAppConfig?.purposeActivatedRejectedToConsumer, }, { key: 'purposeSuspendedUnsuspendedToConsumer', title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', description: t('subscriber.purpose.components.purposeStateUpdated.description'), - defaultValue: inAppConfig?.purposeSuspendedUnsuspendedToConsumer, }, ], }, @@ -82,13 +76,11 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) key: 'agreementManagementToProducer', title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', description: t('provider.agreement.components.agreementRequestReceived.description'), - defaultValue: inAppConfig.agreementManagementToProducer, }, { key: 'agreementSuspendedUnsuspendedToProducer', title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', description: t('provider.agreement.components.agreementStateUpdated.description'), - defaultValue: inAppConfig.agreementSuspendedUnsuspendedToProducer, }, ], }, @@ -100,7 +92,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) key: 'purposeStatusChangedToProducer', title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', description: t('provider.purpose.components.purposeStateUpdated.description'), - defaultValue: inAppConfig.purposeStatusChangedToProducer, }, ], }, @@ -116,7 +107,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' ), - defaultValue: inAppConfig.clientAddedRemovedToProducer, }, { key: 'TODO', @@ -146,7 +136,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'provider.eserviceTemplate.components.instanceFromTemplate.description' ), - defaultValue: inAppConfig.newEserviceTemplateVersionToInstantiator, }, { key: 'eserviceTemplateStatusChangedToInstantiator', @@ -154,7 +143,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'provider.eserviceTemplate.components.templateStateUpdated.description' ), - defaultValue: inAppConfig.eserviceTemplateStatusChangedToInstantiator, }, { key: 'newTemplateVersion', @@ -168,7 +156,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' ), - defaultValue: inAppConfig.eserviceTemplateNameChangedToInstantiator, }, { key: 'templateStatusChangedToProducer', @@ -178,7 +165,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' ), - defaultValue: inAppConfig.templateStatusChangedToProducer, }, ], }, @@ -198,7 +184,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'delegation.delegationAssignment.components.delegationUpdated.description' ), - defaultValue: inAppConfig.delegationApprovedRejectedToDelegator, }, { key: 'eserviceNewVersionSubmittedToDelegator', @@ -208,7 +193,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' ), - defaultValue: inAppConfig.eserviceNewVersionSubmittedToDelegator, }, ], }, @@ -222,7 +206,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'delegation.delegationReceive.components.delegationUpdated.description' ), - defaultValue: inAppConfig.delegationSubmittedRevokedToDelegate, }, { key: 'eserviceNewVersionApprovedRejectedToDelegate', @@ -232,7 +215,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' ), - defaultValue: inAppConfig.eserviceNewVersionApprovedRejectedToDelegate, }, ], }, @@ -252,7 +234,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'keyAndAttributes.attributes.components.attributesStateUpdated.description' ), - defaultValue: inAppConfig.certifiedVerifiedAttributeAssignedRevokedToAssignee, }, ], }, @@ -267,7 +248,6 @@ export function useNotificationInAppConfigForm(inAppConfig: NotificationConfig) description: t( 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' ), - defaultValue: inAppConfig.clientKeyAddedDeletedToClientUsers, }, ], }, From af2f2bfe2a793eb4b14c6a120b2cdf976ccb9059 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 3 Sep 2025 09:01:47 +0200 Subject: [PATCH 12/53] chore: add debounce --- .../InAppNotificationUserConfigTab.tsx | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index cb9a49ba4..9dca79b8a 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -1,3 +1,4 @@ +import React, { useCallback, useEffect, useRef } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { NotificationConfigSection } from './NotificationConfigSection' import { SectionContainer } from '@/components/layout/containers' @@ -7,7 +8,7 @@ import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' import { type NotificationConfig } from '@/api/api.generatedTypes' -import React, { useEffect } from 'react' +import { debounce } from 'lodash' type InAppNotificationUserConfigTabProps = { inAppConfig: NotificationConfig @@ -29,10 +30,6 @@ export type NotificationConfigSchema = { [key: string]: NotificationSectionSchema } -// TODO: Definire get -// TODO: Definire i campi che sono visibili in base al role -// TODO: Definire POST - export const InAppNotificationUserConfigTab: React.FC = ({ inAppConfig, }) => { @@ -40,15 +37,25 @@ export const InAppNotificationUserConfigTab: React.FC({ - defaultValues: inAppConfig, + const formMethods = useForm({ + defaultValues: { ...inAppConfig, enableAllNotification: false }, }) const valueChanged = formMethods.watch() + const valuesRef = useRef(valueChanged) + valuesRef.current = valueChanged + + const debounceFn = useCallback( + debounce(() => { + console.log('value has been changed: call API', valuesRef.current) + //TODO: Dedcide timing in ms + }, 1000), + [] + ) useEffect(() => { - console.log('valueChanged', valueChanged) - }, [valueChanged]) + if (valueChanged) debounceFn() + }, [debounceFn, valueChanged]) return ( @@ -58,8 +65,7 @@ export const InAppNotificationUserConfigTab: React.FC - {true && + {valueChanged.enableAllNotification && Object.keys(notificationSchema).map((sectionName) => { return ( From decc7b874781d5f8630bec6affbec54618a2138b Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 3 Sep 2025 17:18:15 +0200 Subject: [PATCH 13/53] chore: added handling of "enable all" for section --- src/api/notification/notification.services.ts | 2 +- .../NotificationUserConfig.page.tsx | 2 +- .../InAppNotificationUserConfigTab.tsx | 49 ++++++++++++++++--- src/static/locales/en/notification.json | 3 ++ src/static/locales/it/notification.json | 3 ++ 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index 610bfb90f..2e6fb33da 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -23,7 +23,7 @@ async function getUserNotificationConfiguration() { setTimeout(() => { resolve({ emailConfig: getNotificationConfig(Math.random() < 0.5), - inAppConfig: getNotificationConfig(Math.random() < 0.5), + inAppConfig: getNotificationConfig(false), }) }, 1000) }) diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index c41f96ed4..962ec84c4 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -9,7 +9,7 @@ import { NotificationQueries } from '@/api/notification' import { keepPreviousData, useQuery } from '@tanstack/react-query' const NotificationUserConfigPage: React.FC = () => { - const { activeTab, updateActiveTab } = useActiveTab('notificationConfig') + const { activeTab, updateActiveTab } = useActiveTab('inApp') const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) const { data } = useQuery({ diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index 9dca79b8a..7d16e5131 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -2,7 +2,15 @@ import React, { useCallback, useEffect, useRef } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { NotificationConfigSection } from './NotificationConfigSection' import { SectionContainer } from '@/components/layout/containers' -import { Box, Card, Link, Stack, Typography } from '@mui/material' +import { + Box, + Card, + Link, + Stack, + Typography, + Switch as MUISwitch, + FormControlLabel, +} from '@mui/material' import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' @@ -37,7 +45,9 @@ export const InAppNotificationUserConfigTab: React.FC({ + const formMethods = useForm< + NotificationConfig & { enableAllNotification: boolean; subscriber: boolean } + >({ defaultValues: { ...inAppConfig, enableAllNotification: false }, }) @@ -57,11 +67,27 @@ export const InAppNotificationUserConfigTab: React.FC, + checked: boolean, + sectionName: string + ) => { + if (checked) { + const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap((s) => + s.components.map((c) => c.key) + ) + + sectionComponentsKeys.map((inAppConfigKey) => { + formMethods.setValue(inAppConfigKey as keyof NotificationConfig, true) + }) + } + } + return ( - Dubbi? Vai al manuale (TODO TRANSLATE) + {t('manualLinkLabel')} @@ -92,8 +118,19 @@ export const InAppNotificationUserConfigTab: React.FC - - + + handleChangeSectionSwitch(event, checked, sectionName) + } + /> + } + label={t('enableSectionAllNotifications')} + /> {notificationSchema[sectionName].subsections.map((subsection) => ( diff --git a/src/static/locales/en/notification.json b/src/static/locales/en/notification.json index 66aedc511..d6fba587a 100644 --- a/src/static/locales/en/notification.json +++ b/src/static/locales/en/notification.json @@ -6,11 +6,14 @@ "emailTabTitle": "Email", "inAppTab": { "title": "Configurazione delle preferenze di notifica in piattaforma", + "manualLinkLabel": "Dubbi? Vai sul manuale", "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", + "enableSectionAllNotifications": "Abilita tutto", "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" }, + "subscriber": { "title": "Fruizione", "dataUsage": { diff --git a/src/static/locales/it/notification.json b/src/static/locales/it/notification.json index 66aedc511..d6fba587a 100644 --- a/src/static/locales/it/notification.json +++ b/src/static/locales/it/notification.json @@ -6,11 +6,14 @@ "emailTabTitle": "Email", "inAppTab": { "title": "Configurazione delle preferenze di notifica in piattaforma", + "manualLinkLabel": "Dubbi? Vai sul manuale", "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", + "enableSectionAllNotifications": "Abilita tutto", "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" }, + "subscriber": { "title": "Fruizione", "dataUsage": { From 9aa02f5d6a916119d40127bb786165b3da51a2c2 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Thu, 4 Sep 2025 12:26:20 +0200 Subject: [PATCH 14/53] chore: changdd switch "enable all" with button --- .../EmailNotificationUserConfigTab.tsx | 162 +++++++---- .../InAppNotificationUserConfigTab.tsx | 54 ++-- .../hooks/useNotificationEmailConfigForm.ts | 259 ++++++++++++++++++ .../hooks/useNotificationInAppConfigForm.ts | 2 +- src/static/locales/en/notification.json | 16 +- src/static/locales/it/notification.json | 16 +- 6 files changed, 407 insertions(+), 102 deletions(-) create mode 100644 src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts diff --git a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx index f738f6406..9d9193602 100644 --- a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx @@ -1,73 +1,117 @@ import type { NotificationConfig } from '@/api/api.generatedTypes' +import { SectionContainer } from '@/components/layout/containers' +import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' +import { Box, Card, Link, Stack, Typography, Button } from '@mui/material' import { FormProvider, useForm } from 'react-hook-form' +import { useTranslation } from 'react-i18next' +import MenuBookIcon from '@mui/icons-material/MenuBook' +import { NotificationConfigSection } from './NotificationConfigSection' +import { useNotificationEmailConfigForm } from '../hooks/useNotificationEmailConfigForm' +import { useCallback, useEffect, useRef } from 'react' +import { debounce } from 'lodash' type EmailNotificationUserConfigTabProps = { emailConfig: NotificationConfig } -export type NotificationSectionSchema = { - title: string - subsections: { - name: string - title: string - description: string - components: { - name: string - description: string - }[] - }[] -} -export type NotificationConfigSchema = { - [key: string]: NotificationSectionSchema -} - -const notificationSchema: NotificationConfigSchema = { - subscriber: { - title: 'Fruizione', - subsections: [ - { - name: 'agreements', - title: 'Richieste di fruizione inoltrate', - description: - 'Ricevi aggiornamenti sullo stato di avanzamento delel tue richieste di fruizione verso gli e-service', - components: [ - { - name: 'avanzamentoRichiesta', - description: 'Ricevi notifiche sullo stato di avanzamento della tua richiesta', - }, - { - name: 'suspendedOrReactivated', - description: 'Ricevi notifiche quando una richiesta viene sospesa o riattivata', - }, - ], - }, - { - name: 'purposes', - title: 'Finalità', - description: 'Ricevi aggiornamenti sulle finalità che hai inoltrato', - components: [ - { - name: 'acceptedOrRefusedPurpose', - description: 'Ricevi notifihe quando viene accettata o rifiutata una finalità', - }, - ], - }, - ], - }, -} export const EmailNotificationUserConfigTab: React.FC = ({ emailConfig, }) => { - const formMethods = useForm() + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.emailTab' }) + const formMethods = useForm({ + defaultValues: { ...emailConfig, enableAllNotification: false }, + }) + const { notificationSchema } = useNotificationEmailConfigForm() + const userMail = 'pippo@mail.com' + + const valueChanged = formMethods.watch() + const valuesRef = useRef(valueChanged) + valuesRef.current = valueChanged + + const debounceFn = useCallback( + debounce(() => { + console.log('value has been changed: call API', valuesRef.current) + //TODO: Dedcide timing in ms + }, 1000), + [] + ) + + useEffect(() => { + if (valueChanged) debounceFn() + }, [debounceFn, valueChanged]) + + const onClickEnableAllSectionSwitch = (sectionName: string) => { + const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap((s) => + s.components.map((c) => c.key) + ) + + sectionComponentsKeys.map((inAppConfigKey) => { + formMethods.setValue(inAppConfigKey as keyof NotificationConfig, true) + }) + } return ( -
- - {Object.keys(notificationSchema).map((sectionName) => { - // eslint-disable-next-line react/jsx-key - return
TODO
- })} -
-
+ + + + Indirizzo email + {userMail} + + + {t('linkLabel')} + + + + } + /> + {valueChanged.enableAllNotification && + Object.keys(notificationSchema).map((sectionName) => { + return ( + + + + + + + {notificationSchema[sectionName].title} + + + + + + + {notificationSchema[sectionName].subsections.map((subsection) => ( + + ))} + + + ) + })} + + + ) } diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index 7d16e5131..ee28576b6 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -2,15 +2,7 @@ import React, { useCallback, useEffect, useRef } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { NotificationConfigSection } from './NotificationConfigSection' import { SectionContainer } from '@/components/layout/containers' -import { - Box, - Card, - Link, - Stack, - Typography, - Switch as MUISwitch, - FormControlLabel, -} from '@mui/material' +import { Box, Card, Link, Stack, Typography, Button } from '@mui/material' import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' @@ -45,9 +37,7 @@ export const InAppNotificationUserConfigTab: React.FC({ + const formMethods = useForm({ defaultValues: { ...inAppConfig, enableAllNotification: false }, }) @@ -67,20 +57,14 @@ export const InAppNotificationUserConfigTab: React.FC, - checked: boolean, - sectionName: string - ) => { - if (checked) { - const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap((s) => - s.components.map((c) => c.key) - ) + const onClickEnableAllSectionSwitch = (sectionName: string) => { + const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap((s) => + s.components.map((c) => c.key) + ) - sectionComponentsKeys.map((inAppConfigKey) => { - formMethods.setValue(inAppConfigKey as keyof NotificationConfig, true) - }) - } + sectionComponentsKeys.map((inAppConfigKey) => { + formMethods.setValue(inAppConfigKey as keyof NotificationConfig, true) + }) } return ( @@ -118,19 +102,13 @@ export const InAppNotificationUserConfigTab: React.FC - - handleChangeSectionSwitch(event, checked, sectionName) - } - /> - } - label={t('enableSectionAllNotifications')} - /> +
{notificationSchema[sectionName].subsections.map((subsection) => ( diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts new file mode 100644 index 000000000..b3acc9a41 --- /dev/null +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts @@ -0,0 +1,259 @@ +import { useTranslation } from 'react-i18next' +import { type NotificationConfigSchema } from '../components/InAppNotificationUserConfigTab' + +export function useNotificationEmailConfigForm() { + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) + + const notificationSchema: NotificationConfigSchema = { + subscriber: { + title: t('subscriber.title'), + subsections: [ + { + name: 'fruizioneDati', + title: t('subscriber.dataUsage.title'), + components: [ + { + key: 'eserviceStateChangedToConsumer', + title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', + description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + }, + { + key: 'agreementActivatedRejectedToConsumer', + title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', + description: t('subscriber.dataUsage.components.agreementManagement.description'), + }, + { + key: 'agreementSuspendedUnsuspendedToConsumer', + title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', + description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + }, + ], + }, + { + name: 'finalita', + title: t('subscriber.purpose.title'), + components: [ + { + key: 'purposeActivatedRejectedToConsumer', + title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', + description: t('subscriber.purpose.components.purposeManagement.description'), + }, + { + key: 'purposeSuspendedUnsuspendedToConsumer', + title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', + description: t('subscriber.purpose.components.purposeStateUpdated.description'), + }, + ], + }, + { + name: 'soglieDiCarico', + title: t('subscriber.thresholds.title'), + components: [ + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), + description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + }, + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), + description: t( + 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' + ), + }, + ], + }, + ], + }, + provider: { + title: t('provider.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('provider.agreement.title'), + components: [ + { + key: 'agreementManagementToProducer', + title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', + description: t('provider.agreement.components.agreementRequestReceived.description'), + }, + { + key: 'agreementSuspendedUnsuspendedToProducer', + title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', + description: t('provider.agreement.components.agreementStateUpdated.description'), + }, + ], + }, + { + name: 'finalita', + title: t('provider.purpose.title'), + components: [ + { + key: 'purposeStatusChangedToProducer', + title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', + description: t('provider.purpose.components.purposeStateUpdated.description'), + }, + ], + }, + { + name: 'clientSoglieDiCarico', + title: t('provider.clientAndThresholds.title'), + components: [ + { + key: 'clientAddedRemovedToProducer', + title: + t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + + '(05)', + description: t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' + ), + }, + { + key: 'TODO', + title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdExceeded.description' + ), + }, + { + key: 'TODO', + title: + t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' + ), + }, + ], + }, + { + name: 'eserviceTemplate', + title: t('provider.eserviceTemplate.title'), + components: [ + { + key: 'newEserviceTemplateVersionToInstantiator', + title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', + description: t( + 'provider.eserviceTemplate.components.instanceFromTemplate.description' + ), + }, + { + key: 'eserviceTemplateStatusChangedToInstantiator', + title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', + description: t( + 'provider.eserviceTemplate.components.templateStateUpdated.description' + ), + }, + { + key: 'newTemplateVersion', + title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', + description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), + }, + { + key: 'eserviceTemplateNameChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', + description: t( + 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' + ), + }, + { + key: 'templateStatusChangedToProducer', + title: + t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + + '(09)', + description: t( + 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' + ), + }, + ], + }, + ], + }, + delegations: { + title: t('delegation.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('delegation.delegationAssignment.title'), + components: [ + { + key: 'delegationApprovedRejectedToDelegator', + title: + t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', + description: t( + 'delegation.delegationAssignment.components.delegationUpdated.description' + ), + }, + { + key: 'eserviceNewVersionSubmittedToDelegator', + title: + t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + + '(21)', + description: t( + 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' + ), + }, + ], + }, + { + name: 'delegationReceive', + title: t('delegation.delegationReceive.title'), + components: [ + { + key: 'delegationSubmittedRevokedToDelegate', + title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', + description: t( + 'delegation.delegationReceive.components.delegationUpdated.description' + ), + }, + { + key: 'eserviceNewVersionApprovedRejectedToDelegate', + title: + t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + + '(22)', + description: t( + 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' + ), + }, + ], + }, + ], + }, + keyAndAttributes: { + title: t('keyAndAttributes.title'), + subsections: [ + { + name: 'attributes', + title: t('keyAndAttributes.attributes.title'), + components: [ + { + key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', + title: + t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', + description: t( + 'keyAndAttributes.attributes.components.attributesStateUpdated.description' + ), + }, + ], + }, + { + name: 'keys', + title: t('keyAndAttributes.keys.title'), + components: [ + { + key: 'clientKeyAddedDeletedToClientUsers', + title: + t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', + description: t( + 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' + ), + }, + ], + }, + ], + }, + } + + return { notificationSchema } +} diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts index 5e81db968..1e098be5c 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next' import { type NotificationConfigSchema } from '../components/InAppNotificationUserConfigTab' export function useNotificationInAppConfigForm() { - const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) const notificationSchema: NotificationConfigSchema = { subscriber: { diff --git a/src/static/locales/en/notification.json b/src/static/locales/en/notification.json index d6fba587a..a8b56f890 100644 --- a/src/static/locales/en/notification.json +++ b/src/static/locales/en/notification.json @@ -12,8 +12,20 @@ "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" - }, - + } + }, + "emailTab": { + "title": "Configurazione delle preferenze di notifica tramite email", + "description": "Le notifiche email ti informeranno sulla tua casella personale gli eventi che ti riguardano. La mail che utilizzeremo è quella che ci hai fornito in fase di iscrizione.", + "linkLabel": "Non è la tua mail? Scopri come aggiornarla", + "mailLabel": "Indirizzo email", + "enableSectionAllNotifications": "Abilita tutto", + "enableAllNotifications": { + "label": "Abilita la ricezione delle notifiche e-mail", + "description": "Disabilitando questa opzione, non riceverai nessuna e-mail" + } + }, + "sections": { "subscriber": { "title": "Fruizione", "dataUsage": { diff --git a/src/static/locales/it/notification.json b/src/static/locales/it/notification.json index d6fba587a..a8b56f890 100644 --- a/src/static/locales/it/notification.json +++ b/src/static/locales/it/notification.json @@ -12,8 +12,20 @@ "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" - }, - + } + }, + "emailTab": { + "title": "Configurazione delle preferenze di notifica tramite email", + "description": "Le notifiche email ti informeranno sulla tua casella personale gli eventi che ti riguardano. La mail che utilizzeremo è quella che ci hai fornito in fase di iscrizione.", + "linkLabel": "Non è la tua mail? Scopri come aggiornarla", + "mailLabel": "Indirizzo email", + "enableSectionAllNotifications": "Abilita tutto", + "enableAllNotifications": { + "label": "Abilita la ricezione delle notifiche e-mail", + "description": "Disabilitando questa opzione, non riceverai nessuna e-mail" + } + }, + "sections": { "subscriber": { "title": "Fruizione", "dataUsage": { From 512161155bd357fce06886e46b0c91c738d61b33 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Mon, 8 Sep 2025 12:29:25 +0200 Subject: [PATCH 15/53] chore: added visibilty field (in-app) --- .../InAppNotificationUserConfigTab.tsx | 2 ++ .../components/NotificationConfigSection.tsx | 30 ++++++++++++------- .../hooks/useNotificationInAppConfigForm.ts | 24 +++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index ee28576b6..24f083b1d 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -9,6 +9,7 @@ import MenuBookIcon from '@mui/icons-material/MenuBook' import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' import { type NotificationConfig } from '@/api/api.generatedTypes' import { debounce } from 'lodash' +import type { UserProductRole } from '@/types/party.types' type InAppNotificationUserConfigTabProps = { inAppConfig: NotificationConfig @@ -20,6 +21,7 @@ export type NotificationSubSectionSchema = { key: string title: string description: string + visibility: UserProductRole[] }[] } export type NotificationSectionSchema = { diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index dcae5a34b..e3a46d689 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -2,6 +2,7 @@ import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hoo import { Box } from '@mui/system' import { Typography } from '@mui/material' import type { NotificationSubSectionSchema } from './InAppNotificationUserConfigTab' +import { AuthHooks } from '@/api/auth' type NotificationConfigSectionProps = { subsection: NotificationSubSectionSchema @@ -9,22 +10,31 @@ type NotificationConfigSectionProps = { export const NotificationConfigSection: React.FC = ({ subsection, }) => { + const { currentRoles } = AuthHooks.useJwt() + return ( <> {subsection.title} - {subsection.components.map((component) => ( - - } - /> - ))} + {subsection.components.map( + (component) => + // is currentRoles authorized to show the switch ? + currentRoles.some((item) => component.visibility.includes(item)) && ( + + } + /> + ) + )} ) diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts index 1e098be5c..ed7e59631 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -16,16 +16,19 @@ export function useNotificationInAppConfigForm() { key: 'eserviceStateChangedToConsumer', title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + visibility: ['admin', 'security'], }, { key: 'agreementActivatedRejectedToConsumer', title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', description: t('subscriber.dataUsage.components.agreementManagement.description'), + visibility: ['admin'], }, { key: 'agreementSuspendedUnsuspendedToConsumer', title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + visibility: ['admin', 'security'], }, ], }, @@ -37,11 +40,13 @@ export function useNotificationInAppConfigForm() { key: 'purposeActivatedRejectedToConsumer', title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', description: t('subscriber.purpose.components.purposeManagement.description'), + visibility: ['admin'], }, { key: 'purposeSuspendedUnsuspendedToConsumer', title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', description: t('subscriber.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'security'], }, ], }, @@ -53,6 +58,7 @@ export function useNotificationInAppConfigForm() { key: 'TODO', title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + visibility: ['admin'], // To define }, { key: 'TODO', @@ -60,6 +66,7 @@ export function useNotificationInAppConfigForm() { description: t( 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' ), + visibility: ['admin'], // To define }, ], }, @@ -76,11 +83,13 @@ export function useNotificationInAppConfigForm() { key: 'agreementManagementToProducer', title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', description: t('provider.agreement.components.agreementRequestReceived.description'), + visibility: ['admin'], }, { key: 'agreementSuspendedUnsuspendedToProducer', title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', description: t('provider.agreement.components.agreementStateUpdated.description'), + visibility: ['admin'], }, ], }, @@ -92,6 +101,7 @@ export function useNotificationInAppConfigForm() { key: 'purposeStatusChangedToProducer', title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', description: t('provider.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'api'], }, ], }, @@ -107,6 +117,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' ), + visibility: ['admin', 'api'], }, { key: 'TODO', @@ -114,6 +125,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.clientAndThresholds.components.thresholdExceeded.description' ), + visibility: ['admin', 'api'], // To define }, { key: 'TODO', @@ -123,6 +135,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' ), + visibility: ['admin', 'api'], // To define }, ], }, @@ -136,6 +149,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.instanceFromTemplate.description' ), + visibility: ['admin', 'security'], }, { key: 'eserviceTemplateStatusChangedToInstantiator', @@ -143,11 +157,13 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.templateStateUpdated.description' ), + visibility: ['admin', 'security'], }, { key: 'newTemplateVersion', title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), + visibility: ['admin', 'security'], // To define }, { key: 'eserviceTemplateNameChangedToInstantiator', @@ -156,6 +172,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' ), + visibility: ['admin', 'security'], }, { key: 'templateStatusChangedToProducer', @@ -165,6 +182,7 @@ export function useNotificationInAppConfigForm() { description: t( 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' ), + visibility: ['admin', 'api'], }, ], }, @@ -184,6 +202,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationAssignment.components.delegationUpdated.description' ), + visibility: ['admin'], }, { key: 'eserviceNewVersionSubmittedToDelegator', @@ -193,6 +212,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' ), + visibility: ['admin'], }, ], }, @@ -206,6 +226,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationReceive.components.delegationUpdated.description' ), + visibility: ['admin'], }, { key: 'eserviceNewVersionApprovedRejectedToDelegate', @@ -215,6 +236,7 @@ export function useNotificationInAppConfigForm() { description: t( 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' ), + visibility: ['admin', 'api'], }, ], }, @@ -234,6 +256,7 @@ export function useNotificationInAppConfigForm() { description: t( 'keyAndAttributes.attributes.components.attributesStateUpdated.description' ), + visibility: ['admin'], }, ], }, @@ -248,6 +271,7 @@ export function useNotificationInAppConfigForm() { description: t( 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' ), + visibility: ['admin', 'security'], // To define }, ], }, From 9fe01f7d5cf77cae79486fd252e5802e55720b9b Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Mon, 8 Sep 2025 12:51:57 +0200 Subject: [PATCH 16/53] refactor: moved types into specific file --- .../InAppNotificationUserConfigTab.tsx | 33 +++++-------------- .../components/NotificationConfigSection.tsx | 2 +- .../hooks/useNotificationEmailConfigForm.ts | 26 ++++++++++++++- .../hooks/useNotificationInAppConfigForm.ts | 2 +- src/pages/NotificationUserConfigPage/types.ts | 19 +++++++++++ 5 files changed, 55 insertions(+), 27 deletions(-) create mode 100644 src/pages/NotificationUserConfigPage/types.ts diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index 24f083b1d..527d51b86 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -9,28 +9,11 @@ import MenuBookIcon from '@mui/icons-material/MenuBook' import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' import { type NotificationConfig } from '@/api/api.generatedTypes' import { debounce } from 'lodash' -import type { UserProductRole } from '@/types/party.types' +import type { NotificationSubSectionSchema } from '../types' type InAppNotificationUserConfigTabProps = { inAppConfig: NotificationConfig } -export type NotificationSubSectionSchema = { - name: string - title: string - components: { - key: string - title: string - description: string - visibility: UserProductRole[] - }[] -} -export type NotificationSectionSchema = { - title: string - subsections: NotificationSubSectionSchema[] -} -export type NotificationConfigSchema = { - [key: string]: NotificationSectionSchema -} export const InAppNotificationUserConfigTab: React.FC = ({ inAppConfig, @@ -60,11 +43,11 @@ export const InAppNotificationUserConfigTab: React.FC { - const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap((s) => - s.components.map((c) => c.key) + const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap( + (s: NotificationSubSectionSchema) => s.components.map((c) => c.key) ) - sectionComponentsKeys.map((inAppConfigKey) => { + sectionComponentsKeys.map((inAppConfigKey: string) => { formMethods.setValue(inAppConfigKey as keyof NotificationConfig, true) }) } @@ -113,9 +96,11 @@ export const InAppNotificationUserConfigTab: React.FC
- {notificationSchema[sectionName].subsections.map((subsection) => ( - - ))} + {notificationSchema[sectionName].subsections.map( + (subsection: NotificationSubSectionSchema) => ( + + ) + )}
) diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index e3a46d689..633469d86 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -1,8 +1,8 @@ import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { Box } from '@mui/system' import { Typography } from '@mui/material' -import type { NotificationSubSectionSchema } from './InAppNotificationUserConfigTab' import { AuthHooks } from '@/api/auth' +import type { NotificationSubSectionSchema } from '../types' type NotificationConfigSectionProps = { subsection: NotificationSubSectionSchema diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts index b3acc9a41..cab457e3d 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts @@ -1,5 +1,5 @@ import { useTranslation } from 'react-i18next' -import { type NotificationConfigSchema } from '../components/InAppNotificationUserConfigTab' +import { type NotificationConfigSchema } from '../types' export function useNotificationEmailConfigForm() { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) @@ -16,16 +16,19 @@ export function useNotificationEmailConfigForm() { key: 'eserviceStateChangedToConsumer', title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + visibility: ['admin', 'security'], }, { key: 'agreementActivatedRejectedToConsumer', title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', description: t('subscriber.dataUsage.components.agreementManagement.description'), + visibility: ['admin', 'security'], }, { key: 'agreementSuspendedUnsuspendedToConsumer', title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + visibility: ['admin', 'security'], }, ], }, @@ -37,11 +40,13 @@ export function useNotificationEmailConfigForm() { key: 'purposeActivatedRejectedToConsumer', title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', description: t('subscriber.purpose.components.purposeManagement.description'), + visibility: ['admin'], }, { key: 'purposeSuspendedUnsuspendedToConsumer', title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', description: t('subscriber.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'security'], }, ], }, @@ -53,6 +58,7 @@ export function useNotificationEmailConfigForm() { key: 'TODO', title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + visibility: ['admin', 'security'], // to be define }, { key: 'TODO', @@ -60,6 +66,7 @@ export function useNotificationEmailConfigForm() { description: t( 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' ), + visibility: ['admin', 'security'], // to be define }, ], }, @@ -76,11 +83,13 @@ export function useNotificationEmailConfigForm() { key: 'agreementManagementToProducer', title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', description: t('provider.agreement.components.agreementRequestReceived.description'), + visibility: ['admin'], }, { key: 'agreementSuspendedUnsuspendedToProducer', title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', description: t('provider.agreement.components.agreementStateUpdated.description'), + visibility: ['admin'], }, ], }, @@ -92,6 +101,7 @@ export function useNotificationEmailConfigForm() { key: 'purposeStatusChangedToProducer', title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', description: t('provider.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'api'], }, ], }, @@ -107,6 +117,7 @@ export function useNotificationEmailConfigForm() { description: t( 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' ), + visibility: ['admin', 'api'], }, { key: 'TODO', @@ -114,6 +125,7 @@ export function useNotificationEmailConfigForm() { description: t( 'provider.clientAndThresholds.components.thresholdExceeded.description' ), + visibility: ['admin', 'api'], // to be defined }, { key: 'TODO', @@ -123,6 +135,7 @@ export function useNotificationEmailConfigForm() { description: t( 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' ), + visibility: ['admin', 'api'], // to be defined }, ], }, @@ -136,6 +149,7 @@ export function useNotificationEmailConfigForm() { description: t( 'provider.eserviceTemplate.components.instanceFromTemplate.description' ), + visibility: ['admin', 'security'], }, { key: 'eserviceTemplateStatusChangedToInstantiator', @@ -143,11 +157,13 @@ export function useNotificationEmailConfigForm() { description: t( 'provider.eserviceTemplate.components.templateStateUpdated.description' ), + visibility: ['admin', 'security'], }, { key: 'newTemplateVersion', title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), + visibility: ['admin', 'security'], // to be defined }, { key: 'eserviceTemplateNameChangedToInstantiator', @@ -156,6 +172,7 @@ export function useNotificationEmailConfigForm() { description: t( 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' ), + visibility: ['admin', 'security'], }, { key: 'templateStatusChangedToProducer', @@ -165,6 +182,7 @@ export function useNotificationEmailConfigForm() { description: t( 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' ), + visibility: ['admin', 'api'], }, ], }, @@ -184,6 +202,7 @@ export function useNotificationEmailConfigForm() { description: t( 'delegation.delegationAssignment.components.delegationUpdated.description' ), + visibility: ['admin'], }, { key: 'eserviceNewVersionSubmittedToDelegator', @@ -193,6 +212,7 @@ export function useNotificationEmailConfigForm() { description: t( 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' ), + visibility: ['admin'], }, ], }, @@ -206,6 +226,7 @@ export function useNotificationEmailConfigForm() { description: t( 'delegation.delegationReceive.components.delegationUpdated.description' ), + visibility: ['admin'], }, { key: 'eserviceNewVersionApprovedRejectedToDelegate', @@ -215,6 +236,7 @@ export function useNotificationEmailConfigForm() { description: t( 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' ), + visibility: ['admin', 'api'], }, ], }, @@ -234,6 +256,7 @@ export function useNotificationEmailConfigForm() { description: t( 'keyAndAttributes.attributes.components.attributesStateUpdated.description' ), + visibility: ['admin'], }, ], }, @@ -248,6 +271,7 @@ export function useNotificationEmailConfigForm() { description: t( 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' ), + visibility: ['admin', 'security'], }, ], }, diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts index ed7e59631..8e5e590b9 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -1,5 +1,5 @@ import { useTranslation } from 'react-i18next' -import { type NotificationConfigSchema } from '../components/InAppNotificationUserConfigTab' +import { type NotificationConfigSchema } from '../types' export function useNotificationInAppConfigForm() { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) diff --git a/src/pages/NotificationUserConfigPage/types.ts b/src/pages/NotificationUserConfigPage/types.ts new file mode 100644 index 000000000..3e20c9ebb --- /dev/null +++ b/src/pages/NotificationUserConfigPage/types.ts @@ -0,0 +1,19 @@ +import { type UserProductRole } from '@/types/party.types' + +export type NotificationSubSectionSchema = { + name: string + title: string + components: { + key: string + title: string + description: string + visibility: UserProductRole[] + }[] +} +export type NotificationSectionSchema = { + title: string + subsections: NotificationSubSectionSchema[] +} +export type NotificationConfigSchema = { + [key: string]: NotificationSectionSchema +} From b77bb1c4a88c76cf68804fcafca12132c7457ad1 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Sep 2025 15:20:26 +0200 Subject: [PATCH 17/53] test: added NotificationUserConfigPage test --- .../NotificationUserConfig.page.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 962ec84c4..986c42778 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -12,11 +12,6 @@ const NotificationUserConfigPage: React.FC = () => { const { activeTab, updateActiveTab } = useActiveTab('inApp') const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) - const { data } = useQuery({ - ...NotificationQueries.getUserNotificationConfiguration(), - placeholderData: keepPreviousData, - }) - return ( Date: Wed, 10 Sep 2025 15:21:01 +0200 Subject: [PATCH 18/53] test: added NotificationUserConfigPage test (II) --- src/api/notification/notification.services.ts | 2 +- .../NotificationUserConfig.page.tsx | 58 +++++++--- .../NotificationUserConfigPage.test.tsx | 29 +++++ .../InAppNotificationUserConfigTab.tsx | 106 +++++++++--------- 4 files changed, 126 insertions(+), 69 deletions(-) create mode 100644 src/pages/NotificationUserConfigPage/__test__/NotificationUserConfigPage.test.tsx diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index 2e6fb33da..e409fbdd3 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -25,7 +25,7 @@ async function getUserNotificationConfiguration() { emailConfig: getNotificationConfig(Math.random() < 0.5), inAppConfig: getNotificationConfig(false), }) - }, 1000) + }, 5000) }) } diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 986c42778..00257ad6a 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -1,4 +1,5 @@ -import { PageContainer } from '@/components/layout/containers' +import React from 'react' +import { PageContainer, SectionContainerSkeleton } from '@/components/layout/containers' import { useActiveTab } from '@/hooks/useActiveTab' import { TabContext, TabList, TabPanel } from '@mui/lab' import { Tab } from '@mui/material' @@ -6,7 +7,7 @@ import { EmailNotificationUserConfigTab } from './components/EmailNotificationUs import { InAppNotificationUserConfigTab } from './components/InAppNotificationUserConfigTab' import { useTranslation } from 'react-i18next' import { NotificationQueries } from '@/api/notification' -import { keepPreviousData, useQuery } from '@tanstack/react-query' +import { useSuspenseQuery } from '@tanstack/react-query' const NotificationUserConfigPage: React.FC = () => { const { activeTab, updateActiveTab } = useActiveTab('inApp') @@ -21,22 +22,47 @@ const NotificationUserConfigPage: React.FC = () => { // to: '', // }} > - - - - - - - - {/* TODO: Put load skeleton here */} - {data?.inAppConfig && } - - - {data?.emailConfig && }{' '} - - + }> + + ) } +const NotificationUserConfigTabs: React.FC<{ activeTab: string; updateActiveTab: any }> = ({ + activeTab, + updateActiveTab, +}) => { + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) + + const { data } = useSuspenseQuery({ + ...NotificationQueries.getUserNotificationConfiguration(), + }) + return ( + + + + + + + + {data?.inAppConfig && } + + + {data?.emailConfig && }{' '} + + + ) +} + +export const NotificationUserConfigPageSkeleton = () => { + return ( + + ) +} + export default NotificationUserConfigPage diff --git a/src/pages/NotificationUserConfigPage/__test__/NotificationUserConfigPage.test.tsx b/src/pages/NotificationUserConfigPage/__test__/NotificationUserConfigPage.test.tsx new file mode 100644 index 000000000..9d28036d1 --- /dev/null +++ b/src/pages/NotificationUserConfigPage/__test__/NotificationUserConfigPage.test.tsx @@ -0,0 +1,29 @@ +import { mockUseJwt, renderWithApplicationContext } from '@/utils/testing.utils' +import { screen, waitFor } from '@testing-library/react' +import NotificationUserConfigPage from '../NotificationUserConfig.page' + +mockUseJwt() +describe('NotificationUserConfigPage', () => { + beforeEach(() => { + renderWithApplicationContext(, { + withRouterContext: true, + withReactQueryContext: true, + }) + }) + + it('Should be visible a Skeleton when the page is loading', () => { + expect(screen.getByTestId('notification-page-skeleton')).toBeInTheDocument() + }) + + it('Should be visible the page title and page description even if the page is loading', () => { + expect(screen.getByText('title')).toBeInTheDocument() + expect(screen.getByText('description')).toBeInTheDocument() + }) + + it('Should be visible the two tabs even if the page has been loaded', () => { + waitFor(() => { + expect(screen.getByRole('tab', { name: 'inAppTabTitle' })).toBeInTheDocument() + expect(screen.getByRole('tab', { name: 'emailTabTitle' })).toBeInTheDocument() + }) + }) +}) diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index 527d51b86..dc415dabb 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -53,60 +53,62 @@ export const InAppNotificationUserConfigTab: React.FC - - - {t('manualLinkLabel')} - - - - } - /> + loading}> + + + + {t('manualLinkLabel')} + + + + } + /> - {valueChanged.enableAllNotification && - Object.keys(notificationSchema).map((sectionName) => { - return ( - - - - - - - {notificationSchema[sectionName].title} - - - - + + + + {notificationSchema[sectionName].title} + + + + - {notificationSchema[sectionName].subsections.map( - (subsection: NotificationSubSectionSchema) => ( - - ) - )} - - - ) - })} - - -
+ {notificationSchema[sectionName].subsections.map( + (subsection: NotificationSubSectionSchema) => ( + + ) + )} + + + ) + })} + + + + ) } From 47bb2216e050ae5ae431d4b296db46c0a503b912 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Sep 2025 15:26:06 +0200 Subject: [PATCH 19/53] test: fix useGetSidebarItems.test.tsx --- src/components/sidebar/__test__/useGetSidebarItems.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sidebar/__test__/useGetSidebarItems.test.tsx b/src/components/sidebar/__test__/useGetSidebarItems.test.tsx index 673ee41a6..b93eb52c2 100644 --- a/src/components/sidebar/__test__/useGetSidebarItems.test.tsx +++ b/src/components/sidebar/__test__/useGetSidebarItems.test.tsx @@ -15,6 +15,6 @@ describe('useGetSidebarItems', () => { mockUseGetActiveUserParty() const { result } = renderHook(() => useGetSidebarItems()) - expect(result.current.length).toBe(6) + expect(result.current.length).toBe(7) }) }) From 3cf662ea8085bf8608e93c91881b697ff0ccd304 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Sep 2025 16:25:47 +0200 Subject: [PATCH 20/53] test: InAppNotificationUserConfigTab --- .../NotificationUserConfig.page.tsx | 8 +- .../InAppNotificationUserconfigTab.test.tsx | 59 ++++++++++ .../InAppNotificationUserConfigTab.tsx | 111 +++++++++--------- 3 files changed, 119 insertions(+), 59 deletions(-) create mode 100644 src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 00257ad6a..02b49ee20 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -29,10 +29,10 @@ const NotificationUserConfigPage: React.FC = () => { ) } -const NotificationUserConfigTabs: React.FC<{ activeTab: string; updateActiveTab: any }> = ({ - activeTab, - updateActiveTab, -}) => { +const NotificationUserConfigTabs: React.FC<{ + activeTab: string + updateActiveTab: (_: unknown, newTab: string) => void +}> = ({ activeTab, updateActiveTab }) => { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) const { data } = useSuspenseQuery({ diff --git a/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx b/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx new file mode 100644 index 000000000..492389a5e --- /dev/null +++ b/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx @@ -0,0 +1,59 @@ +import { mockUseJwt, renderWithApplicationContext } from '@/utils/testing.utils' +import { fireEvent, screen } from '@testing-library/react' +import { InAppNotificationUserConfigTab } from '../components/InAppNotificationUserConfigTab' +import { NotificationConfig } from '@/api/api.generatedTypes' + +mockUseJwt() + +const inAppNotificationConfigMock: NotificationConfig = { + agreementSuspendedUnsuspendedToProducer: true, // 04 + agreementManagementToProducer: true, // 03 + clientAddedRemovedToProducer: true, // 05 + purposeStatusChangedToProducer: true, // 07 + templateStatusChangedToProducer: true, //09 + agreementSuspendedUnsuspendedToConsumer: true, // 13 + eserviceStateChangedToConsumer: true, // 11 + agreementActivatedRejectedToConsumer: true, // 12 + purposeActivatedRejectedToConsumer: true, // 15 + purposeSuspendedUnsuspendedToConsumer: true, // 16 + newEserviceTemplateVersionToInstantiator: true, // 17 + eserviceTemplateNameChangedToInstantiator: true, //18 + eserviceTemplateStatusChangedToInstantiator: true, // 19 + delegationApprovedRejectedToDelegator: true, // 20 + eserviceNewVersionSubmittedToDelegator: true, // 21 + eserviceNewVersionApprovedRejectedToDelegate: true, // 22 + delegationSubmittedRevokedToDelegate: true, // 23 + certifiedVerifiedAttributeAssignedRevokedToAssignee: true, // 24 + clientKeyAddedDeletedToClientUsers: true, // 25 +} + +describe('InAppNotificationUserconfigTab', () => { + beforeEach(() => { + renderWithApplicationContext( + , + { + withRouterContext: true, + withReactQueryContext: true, + } + ) + }) + + it('Should not able to see all sections if main switch is off', () => { + const mainSwitch = screen.getByTestId('enableAllNotification') + expect(mainSwitch).toBeInTheDocument() + + const allSections = screen.queryAllByTestId(/config-section-/) + expect(allSections).toHaveLength(0) + }) + + it('Shold be able to see all sections if main switch is on', async () => { + const mainSwitch = screen.getByTestId('enableAllNotification-testId') + expect(mainSwitch).toBeInTheDocument() + + fireEvent.click(mainSwitch) + const allSections = screen.getAllByTestId(/config-section-/) + + screen.debug(allSections) + expect(allSections).toHaveLength(4) + }) +}) diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index dc415dabb..644abe3f1 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -32,7 +32,7 @@ export const InAppNotificationUserConfigTab: React.FC { - console.log('value has been changed: call API', valuesRef.current) + // console.log('value has been changed: call API', valuesRef.current) //TODO: Dedcide timing in ms }, 1000), [] @@ -52,63 +52,64 @@ export const InAppNotificationUserConfigTab: React.FCloading}> - - - - {t('manualLinkLabel')} - - - - } - /> + + + + {t('manualLinkLabel')} + + + + } + /> - {valueChanged.enableAllNotification && - Object.keys(notificationSchema).map((sectionName) => { - return ( - - - { + return ( + + + + + + + {notificationSchema[sectionName].title} + + + - + {t('enableSectionAllNotifications')} + + - {notificationSchema[sectionName].subsections.map( - (subsection: NotificationSubSectionSchema) => ( - - ) - )} - - - ) - })} - - - - + {notificationSchema[sectionName].subsections.map( + (subsection: NotificationSubSectionSchema) => ( + + ) + )} + + + ) + })} + + + ) } From 18541294eb133febf4e42df20c2f98ca82f55e8e Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Sep 2025 16:30:10 +0200 Subject: [PATCH 21/53] test: fix InAppNotificationUserConfigTab --- .../__test__/InAppNotificationUserconfigTab.test.tsx | 5 ++--- .../components/InAppNotificationUserConfigTab.tsx | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx b/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx index 492389a5e..67bef190b 100644 --- a/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx +++ b/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx @@ -1,7 +1,7 @@ import { mockUseJwt, renderWithApplicationContext } from '@/utils/testing.utils' import { fireEvent, screen } from '@testing-library/react' import { InAppNotificationUserConfigTab } from '../components/InAppNotificationUserConfigTab' -import { NotificationConfig } from '@/api/api.generatedTypes' +import { type NotificationConfig } from '@/api/api.generatedTypes' mockUseJwt() @@ -47,13 +47,12 @@ describe('InAppNotificationUserconfigTab', () => { }) it('Shold be able to see all sections if main switch is on', async () => { - const mainSwitch = screen.getByTestId('enableAllNotification-testId') + const mainSwitch = screen.getByTestId('enableAllNotification') expect(mainSwitch).toBeInTheDocument() fireEvent.click(mainSwitch) const allSections = screen.getAllByTestId(/config-section-/) - screen.debug(allSections) expect(allSections).toHaveLength(4) }) }) diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index 644abe3f1..de47be20d 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -62,7 +62,7 @@ export const InAppNotificationUserConfigTab: React.FC Date: Wed, 10 Sep 2025 16:35:30 +0200 Subject: [PATCH 22/53] temp: fix on notification.services --- src/api/notification/notification.services.ts | 3 ++- .../components/InAppNotificationUserConfigTab.tsx | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index e409fbdd3..486b07a87 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -5,6 +5,7 @@ import type { UserNotificationConfig, UserNotificationConfigUpdateSeed, } from '../api.generatedTypes' +import * as crypto from 'crypto' async function updateUserNotificationConfiguration(payload: UserNotificationConfigUpdateSeed) { return await axiosInstance.post( @@ -22,7 +23,7 @@ async function getUserNotificationConfiguration() { return new Promise((resolve) => { setTimeout(() => { resolve({ - emailConfig: getNotificationConfig(Math.random() < 0.5), + emailConfig: getNotificationConfig(crypto.randomBytes(1)[0] < 128), inAppConfig: getNotificationConfig(false), }) }, 5000) diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx index de47be20d..c765158d3 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx @@ -52,8 +52,6 @@ export const InAppNotificationUserConfigTab: React.FC From 829dde9782a570dccd0d86d24e5537692e9cc669 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Sep 2025 16:40:32 +0200 Subject: [PATCH 23/53] test: EmailNotificationUserconfigTab --- ...EmailAppNotificationUserconfigTab.test.tsx | 59 +++++++++++++++++++ .../EmailNotificationUserConfigTab.tsx | 3 +- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx diff --git a/src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx b/src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx new file mode 100644 index 000000000..0cbb52316 --- /dev/null +++ b/src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx @@ -0,0 +1,59 @@ +import { mockUseJwt, renderWithApplicationContext } from '@/utils/testing.utils' +import { fireEvent, screen } from '@testing-library/react' +import { InAppNotificationUserConfigTab } from '../components/InAppNotificationUserConfigTab' +import { type NotificationConfig } from '@/api/api.generatedTypes' +import { EmailNotificationUserConfigTab } from '../components/EmailNotificationUserConfigTab' + +mockUseJwt() + +const emailAppNotificationConfigMock: NotificationConfig = { + agreementSuspendedUnsuspendedToProducer: true, // 04 + agreementManagementToProducer: true, // 03 + clientAddedRemovedToProducer: true, // 05 + purposeStatusChangedToProducer: true, // 07 + templateStatusChangedToProducer: true, //09 + agreementSuspendedUnsuspendedToConsumer: true, // 13 + eserviceStateChangedToConsumer: true, // 11 + agreementActivatedRejectedToConsumer: true, // 12 + purposeActivatedRejectedToConsumer: true, // 15 + purposeSuspendedUnsuspendedToConsumer: true, // 16 + newEserviceTemplateVersionToInstantiator: true, // 17 + eserviceTemplateNameChangedToInstantiator: true, //18 + eserviceTemplateStatusChangedToInstantiator: true, // 19 + delegationApprovedRejectedToDelegator: true, // 20 + eserviceNewVersionSubmittedToDelegator: true, // 21 + eserviceNewVersionApprovedRejectedToDelegate: true, // 22 + delegationSubmittedRevokedToDelegate: true, // 23 + certifiedVerifiedAttributeAssignedRevokedToAssignee: true, // 24 + clientKeyAddedDeletedToClientUsers: true, // 25 +} + +describe('EmailAppNotificationUserconfigTab', () => { + beforeEach(() => { + renderWithApplicationContext( + , + { + withRouterContext: true, + withReactQueryContext: true, + } + ) + }) + + it('Should not able to see all sections if main switch is off', () => { + const mainSwitch = screen.getByTestId('enableAllNotification') + expect(mainSwitch).toBeInTheDocument() + + const allSections = screen.queryAllByTestId(/config-section-/) + expect(allSections).toHaveLength(0) + }) + + it('Shold be able to see all sections if main switch is on', async () => { + const mainSwitch = screen.getByTestId('enableAllNotification') + expect(mainSwitch).toBeInTheDocument() + + fireEvent.click(mainSwitch) + const allSections = screen.getAllByTestId(/config-section-/) + + expect(allSections).toHaveLength(4) + }) +}) diff --git a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx index 9d9193602..81417b9ca 100644 --- a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx @@ -67,6 +67,7 @@ export const EmailNotificationUserConfigTab: React.FC { return ( - + Date: Thu, 11 Sep 2025 10:52:08 +0200 Subject: [PATCH 24/53] test: add formProvider --- .../NotificationConfigSection.test.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx diff --git a/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx new file mode 100644 index 000000000..146c63f4a --- /dev/null +++ b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx @@ -0,0 +1,42 @@ +import { renderWithApplicationContext } from '@/utils/testing.utils' +import { NotificationConfigSection } from '../components/NotificationConfigSection' +import { screen } from '@testing-library/react' +import { FormProvider } from 'react-hook-form' + +describe('NotificationConfigSection', () => { + beforeEach(() => { + renderWithApplicationContext( + // + + // , + { withRouterContext: true, withReactQueryContext: true } + ) + }) + it('Should render the section title', () => { + const sectionTitle = screen.getByText('Test subsection') + + expect(sectionTitle).toBeInTheDocument() + }) + + it('Should render switch within sub-section', () => { + const switchTitle = screen.getByText('firstSwitchTitle') + expect(switchTitle).toBeInTheDocument() + + screen.debug() + const switchDescription = screen.getByText('firstSwitchDescription') + expect(switchDescription).toBeInTheDocument() + }) +}) From c93e8d7418a3beabed0c2ad8ab47d91463f9d4d4 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Thu, 18 Sep 2025 09:30:31 +0200 Subject: [PATCH 25/53] chore: update NotificationUserConfigTab --- scripts/open-api-type-generator.js | 2 +- src/api/api.generatedTypes.ts | 52 ++ .../notification/notification.mutations.ts | 2 +- src/api/notification/notification.queries.ts | 6 +- src/api/notification/notification.services.ts | 37 +- src/components/sidebar/useGetSidebarItems.tsx | 23 +- .../NotificationUserConfig.page.tsx | 68 +- ...EmailAppNotificationUserconfigTab.test.tsx | 59 -- .../NotificationConfigSection.test.tsx | 31 +- ...tsx => NotificationConfigUserTab.test.tsx} | 35 +- .../EmailNotificationUserConfigTab.tsx | 118 --- ...gTab.tsx => NotificationUserConfigTab.tsx} | 87 +- .../hooks/useNotificationEmailConfigForm.ts | 283 ------ .../hooks/useNotificationInAppConfigForm.ts | 847 ++++++++++++------ src/pages/NotificationUserConfigPage/types.ts | 2 + src/static/locales/en/notification.json | 4 +- src/static/locales/it/notification.json | 4 +- 17 files changed, 825 insertions(+), 835 deletions(-) delete mode 100644 src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx rename src/pages/NotificationUserConfigPage/__test__/{InAppNotificationUserconfigTab.test.tsx => NotificationConfigUserTab.test.tsx} (66%) delete mode 100644 src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx rename src/pages/NotificationUserConfigPage/components/{InAppNotificationUserConfigTab.tsx => NotificationUserConfigTab.tsx} (59%) delete mode 100644 src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts diff --git a/scripts/open-api-type-generator.js b/scripts/open-api-type-generator.js index 5f3eea3df..c9ffa9873 100644 --- a/scripts/open-api-type-generator.js +++ b/scripts/open-api-type-generator.js @@ -2,7 +2,7 @@ import { generateApi } from 'swagger-typescript-api' import path from 'path' const openApiSpecificationFileUrl = - 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/update-bff-api/packages/api-clients/open-api/bffApi.yml' + 'https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/develop/packages/api-clients/open-api/bffApi.yml' const apiFolderPath = path.resolve('./src/api/') diff --git a/src/api/api.generatedTypes.ts b/src/api/api.generatedTypes.ts index 73e842e27..94caf8443 100644 --- a/src/api/api.generatedTypes.ts +++ b/src/api/api.generatedTypes.ts @@ -2730,6 +2730,10 @@ export interface GetNotificationsParams { limit: number } +export interface DeleteNotificationsPayload { + ids: string[] +} + export interface MarkNotificationsAsReadPayload { ids: string[] } @@ -7312,6 +7316,21 @@ export namespace InAppNotifications { export type RequestHeaders = {} export type ResponseBody = void } + /** + * @description Delete bulk notifications + * @tags inAppNotifications + * @name DeleteNotifications + * @summary Delete bulk notifications + * @request DELETE:/inAppNotifications + * @secure + */ + export namespace DeleteNotifications { + export type RequestParams = {} + export type RequestQuery = {} + export type RequestBody = DeleteNotificationsPayload + export type RequestHeaders = {} + export type ResponseBody = void + } /** * @description Mark a list of notifications as read * @tags inAppNotifications @@ -7345,6 +7364,39 @@ export namespace InAppNotifications { export type RequestHeaders = {} export type ResponseBody = void } + /** + * @description Mark a notification as unread + * @tags inAppNotifications + * @name MarkNotificationAsUnread + * @summary Mark a notification as unread + * @request POST:/inAppNotifications/:notificationId/markAsUnread + * @secure + */ + export namespace MarkNotificationAsUnread { + export type RequestParams = { + /** @format uuid */ + notificationId: string + } + export type RequestQuery = {} + export type RequestBody = never + export type RequestHeaders = {} + export type ResponseBody = void + } + /** + * @description Mark a list of notifications as unread + * @tags inAppNotifications + * @name MarkNotificationsAsUnread + * @summary Mark a list of notifications as unread + * @request POST:/inAppNotifications/bulk/markAsUnread + * @secure + */ + export namespace MarkNotificationsAsUnread { + export type RequestParams = {} + export type RequestQuery = {} + export type RequestBody = never + export type RequestHeaders = {} + export type ResponseBody = void + } /** * @description Delete a notification * @tags inAppNotifications diff --git a/src/api/notification/notification.mutations.ts b/src/api/notification/notification.mutations.ts index 5b6864d4c..aaec52b0a 100644 --- a/src/api/notification/notification.mutations.ts +++ b/src/api/notification/notification.mutations.ts @@ -2,7 +2,7 @@ import { useMutation } from '@tanstack/react-query' import { NotificationServices } from './index' function useUpdateNotificationUserConfigs() { return useMutation({ - mutationFn: NotificationServices.updateUserNotificationConfiguration, + mutationFn: NotificationServices.updateUserNotificationConfigs, }) } diff --git a/src/api/notification/notification.queries.ts b/src/api/notification/notification.queries.ts index 765c26870..65bd5af74 100644 --- a/src/api/notification/notification.queries.ts +++ b/src/api/notification/notification.queries.ts @@ -1,13 +1,13 @@ import { queryOptions } from '@tanstack/react-query' import { NotificationServices } from './notification.services' -function getUserNotificationConfiguration() { +function getUserNotificationConfigs() { return queryOptions({ queryKey: ['getUserNotificationConfiguration'], - queryFn: () => NotificationServices.getUserNotificationConfiguration(), + queryFn: () => NotificationServices.getUserNotificationConfigs(), }) } export const NotificationQueries = { - getUserNotificationConfiguration, + getUserNotificationConfigs, } diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index 486b07a87..3c0ac52b7 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -5,38 +5,35 @@ import type { UserNotificationConfig, UserNotificationConfigUpdateSeed, } from '../api.generatedTypes' -import * as crypto from 'crypto' -async function updateUserNotificationConfiguration(payload: UserNotificationConfigUpdateSeed) { +async function updateUserNotificationConfigs(payload: UserNotificationConfigUpdateSeed) { return await axiosInstance.post( - `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs`, + `${BACKEND_FOR_FRONTEND_URL}/userNotificationConfigs`, payload ) } -async function getUserNotificationConfiguration() { - // const response = await axiosInstance.get( - // `${BACKEND_FOR_FRONTEND_URL}/notification-config/userNotificationConfigs` - // ) - // return response.data +async function getUserNotificationConfigs() { + const response = await axiosInstance.get( + `${BACKEND_FOR_FRONTEND_URL}/userNotificationConfigs` + ) + return response.data - return new Promise((resolve) => { - setTimeout(() => { - resolve({ - emailConfig: getNotificationConfig(crypto.randomBytes(1)[0] < 128), - inAppConfig: getNotificationConfig(false), - }) - }, 5000) - }) + // return new Promise((resolve) => { + // setTimeout(() => { + // resolve({ + // emailConfig: getNotificationConfig(crypto.randomBytes(1)[0] < 128), + // inAppConfig: getNotificationConfig(false), + // }) + // }, 5000) + // }) } export const NotificationServices = { - updateUserNotificationConfiguration, - getUserNotificationConfiguration, + updateUserNotificationConfigs, + getUserNotificationConfigs, } -//TODO: To delete: - function getNotificationConfig(randomValue: boolean): NotificationConfig { return { agreementSuspendedUnsuspendedToProducer: randomValue, // 04 diff --git a/src/components/sidebar/useGetSidebarItems.tsx b/src/components/sidebar/useGetSidebarItems.tsx index ca7eb3186..deb9c97cb 100644 --- a/src/components/sidebar/useGetSidebarItems.tsx +++ b/src/components/sidebar/useGetSidebarItems.tsx @@ -7,16 +7,9 @@ import React from 'react' import type { RouteKey } from '@/router' import { routes } from '@/router' import DnsIcon from '@mui/icons-material/Dns' -import { - ConsumerIcon, - ProviderIcon, - CatalogIcon, - DeveloperToolIcon, - MyTenantIcon, - MessageIcon, -} from '@/icons' +import { ConsumerIcon, ProviderIcon, CatalogIcon, DeveloperToolIcon, MyTenantIcon } from '@/icons' +import NotificationsIcon from '@mui/icons-material/Notifications' import { useTranslation } from 'react-i18next' -import { Message } from '@mui/icons-material' export function useGetSidebarItems(): SidebarRoutes { const { t } = useTranslation('sidebar', { keyPrefix: 'menuItem' }) @@ -31,6 +24,12 @@ export function useGetSidebarItems(): SidebarRoutes { icon: CatalogIcon, label: t('eserviceCatalog'), children: [], + }, + { + icon: NotificationsIcon, + rootRouteKey: 'NOTIFICATIONS', + label: 'Notifiche ', + children: [], divider: true, }, { @@ -95,12 +94,6 @@ export function useGetSidebarItems(): SidebarRoutes { label: 'Tool per lo sviluppo', children: [], }, - { - icon: MessageIcon, - rootRouteKey: 'NOTIFICATIONS', - label: 'Notifiche ', - children: [], - }, ] const userHasRouteRoles = (routeKey: RouteKey) => { diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 02b49ee20..1f4cc7986 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -3,14 +3,20 @@ import { PageContainer, SectionContainerSkeleton } from '@/components/layout/con import { useActiveTab } from '@/hooks/useActiveTab' import { TabContext, TabList, TabPanel } from '@mui/lab' import { Tab } from '@mui/material' -import { EmailNotificationUserConfigTab } from './components/EmailNotificationUserConfigTab' -import { InAppNotificationUserConfigTab } from './components/InAppNotificationUserConfigTab' +import { NotificationConfigUserTab } from './components/NotificationUserConfigTab' import { useTranslation } from 'react-i18next' -import { NotificationQueries } from '@/api/notification' -import { useSuspenseQuery } from '@tanstack/react-query' +import { NotificationMutations, NotificationQueries } from '@/api/notification' +import { useQuery } from '@tanstack/react-query' +import { match } from 'ts-pattern' +import { + type NotificationConfig, + type UserNotificationConfigUpdateSeed, +} from '@/api/api.generatedTypes' +import type { NotificationConfigType } from './types' const NotificationUserConfigPage: React.FC = () => { const { activeTab, updateActiveTab } = useActiveTab('inApp') + const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) return ( @@ -35,9 +41,43 @@ const NotificationUserConfigTabs: React.FC<{ }> = ({ activeTab, updateActiveTab }) => { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) - const { data } = useSuspenseQuery({ - ...NotificationQueries.getUserNotificationConfiguration(), + const { data } = useQuery({ + ...NotificationQueries.getUserNotificationConfigs(), }) + + const { mutate: updateUserNotificationConfigs } = + NotificationMutations.useUpdateNotificationUserConfigs() + + const handleUpdate = (notificationConfig: NotificationConfig, type: NotificationConfigType) => { + const unnecessaryKeys = ['enableAllNotification'] + const removeUnnecessaryKeys = (config: NotificationConfig) => { + return Object.fromEntries( + Object.entries(config).filter(([key]) => !unnecessaryKeys.includes(key)) + ) as NotificationConfig + } + + const notificationConfigSeed = match(type) + .with( + 'inApp', + () => + ({ + inAppConfig: removeUnnecessaryKeys(notificationConfig), + emailConfig: data?.emailConfig as NotificationConfig, + }) as UserNotificationConfigUpdateSeed + ) + .with( + 'email', + () => + ({ + inAppConfig: data?.inAppConfig as NotificationConfig, + emailConfig: removeUnnecessaryKeys(notificationConfig), + }) as UserNotificationConfigUpdateSeed + ) + .exhaustive() + + updateUserNotificationConfigs(notificationConfigSeed) + } + return ( @@ -46,10 +86,22 @@ const NotificationUserConfigTabs: React.FC<{ - {data?.inAppConfig && } + {data?.inAppConfig && ( + handleUpdate(notification, 'inApp')} + /> + )} - {data?.emailConfig && }{' '} + {data?.emailConfig && ( + handleUpdate(notification, 'inApp')} + /> + )} ) diff --git a/src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx b/src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx deleted file mode 100644 index 0cbb52316..000000000 --- a/src/pages/NotificationUserConfigPage/__test__/EmailAppNotificationUserconfigTab.test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { mockUseJwt, renderWithApplicationContext } from '@/utils/testing.utils' -import { fireEvent, screen } from '@testing-library/react' -import { InAppNotificationUserConfigTab } from '../components/InAppNotificationUserConfigTab' -import { type NotificationConfig } from '@/api/api.generatedTypes' -import { EmailNotificationUserConfigTab } from '../components/EmailNotificationUserConfigTab' - -mockUseJwt() - -const emailAppNotificationConfigMock: NotificationConfig = { - agreementSuspendedUnsuspendedToProducer: true, // 04 - agreementManagementToProducer: true, // 03 - clientAddedRemovedToProducer: true, // 05 - purposeStatusChangedToProducer: true, // 07 - templateStatusChangedToProducer: true, //09 - agreementSuspendedUnsuspendedToConsumer: true, // 13 - eserviceStateChangedToConsumer: true, // 11 - agreementActivatedRejectedToConsumer: true, // 12 - purposeActivatedRejectedToConsumer: true, // 15 - purposeSuspendedUnsuspendedToConsumer: true, // 16 - newEserviceTemplateVersionToInstantiator: true, // 17 - eserviceTemplateNameChangedToInstantiator: true, //18 - eserviceTemplateStatusChangedToInstantiator: true, // 19 - delegationApprovedRejectedToDelegator: true, // 20 - eserviceNewVersionSubmittedToDelegator: true, // 21 - eserviceNewVersionApprovedRejectedToDelegate: true, // 22 - delegationSubmittedRevokedToDelegate: true, // 23 - certifiedVerifiedAttributeAssignedRevokedToAssignee: true, // 24 - clientKeyAddedDeletedToClientUsers: true, // 25 -} - -describe('EmailAppNotificationUserconfigTab', () => { - beforeEach(() => { - renderWithApplicationContext( - , - { - withRouterContext: true, - withReactQueryContext: true, - } - ) - }) - - it('Should not able to see all sections if main switch is off', () => { - const mainSwitch = screen.getByTestId('enableAllNotification') - expect(mainSwitch).toBeInTheDocument() - - const allSections = screen.queryAllByTestId(/config-section-/) - expect(allSections).toHaveLength(0) - }) - - it('Shold be able to see all sections if main switch is on', async () => { - const mainSwitch = screen.getByTestId('enableAllNotification') - expect(mainSwitch).toBeInTheDocument() - - fireEvent.click(mainSwitch) - const allSections = screen.getAllByTestId(/config-section-/) - - expect(allSections).toHaveLength(4) - }) -}) diff --git a/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx index 146c63f4a..685734a14 100644 --- a/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx +++ b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx @@ -1,27 +1,24 @@ import { renderWithApplicationContext } from '@/utils/testing.utils' import { NotificationConfigSection } from '../components/NotificationConfigSection' import { screen } from '@testing-library/react' -import { FormProvider } from 'react-hook-form' describe('NotificationConfigSection', () => { beforeEach(() => { renderWithApplicationContext( - // - - // , + , { withRouterContext: true, withReactQueryContext: true } ) }) diff --git a/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigUserTab.test.tsx similarity index 66% rename from src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx rename to src/pages/NotificationUserConfigPage/__test__/NotificationConfigUserTab.test.tsx index 67bef190b..63857c458 100644 --- a/src/pages/NotificationUserConfigPage/__test__/InAppNotificationUserconfigTab.test.tsx +++ b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigUserTab.test.tsx @@ -1,6 +1,6 @@ import { mockUseJwt, renderWithApplicationContext } from '@/utils/testing.utils' -import { fireEvent, screen } from '@testing-library/react' -import { InAppNotificationUserConfigTab } from '../components/InAppNotificationUserConfigTab' +import { fireEvent, screen, waitFor } from '@testing-library/react' +import { NotificationConfigUserTab } from '../components/NotificationUserConfigTab' import { type NotificationConfig } from '@/api/api.generatedTypes' mockUseJwt() @@ -30,7 +30,11 @@ const inAppNotificationConfigMock: NotificationConfig = { describe('InAppNotificationUserconfigTab', () => { beforeEach(() => { renderWithApplicationContext( - , + , { withRouterContext: true, withReactQueryContext: true, @@ -38,6 +42,10 @@ describe('InAppNotificationUserconfigTab', () => { ) }) + it('Should not be se to user email into "inApp" tab', () => { + const mailLabel = screen.queryByTestId('mailLabel') + expect(mailLabel).not.toBeInTheDocument() + }) it('Should not able to see all sections if main switch is off', () => { const mainSwitch = screen.getByTestId('enableAllNotification') expect(mainSwitch).toBeInTheDocument() @@ -55,4 +63,25 @@ describe('InAppNotificationUserconfigTab', () => { expect(allSections).toHaveLength(4) }) + + describe.only('mail tab', () => { + beforeEach(() => { + renderWithApplicationContext( + , + { + withRouterContext: true, + withReactQueryContext: true, + } + ) + }) + + it('Should be able to see user email', () => { + const email = screen.getByTestId('test-email') + expect(email).toBeInTheDocument() + }) + }) }) diff --git a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx deleted file mode 100644 index 81417b9ca..000000000 --- a/src/pages/NotificationUserConfigPage/components/EmailNotificationUserConfigTab.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import type { NotificationConfig } from '@/api/api.generatedTypes' -import { SectionContainer } from '@/components/layout/containers' -import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' -import { Box, Card, Link, Stack, Typography, Button } from '@mui/material' -import { FormProvider, useForm } from 'react-hook-form' -import { useTranslation } from 'react-i18next' -import MenuBookIcon from '@mui/icons-material/MenuBook' -import { NotificationConfigSection } from './NotificationConfigSection' -import { useNotificationEmailConfigForm } from '../hooks/useNotificationEmailConfigForm' -import { useCallback, useEffect, useRef } from 'react' -import { debounce } from 'lodash' - -type EmailNotificationUserConfigTabProps = { - emailConfig: NotificationConfig -} - -export const EmailNotificationUserConfigTab: React.FC = ({ - emailConfig, -}) => { - const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.emailTab' }) - const formMethods = useForm({ - defaultValues: { ...emailConfig, enableAllNotification: false }, - }) - const { notificationSchema } = useNotificationEmailConfigForm() - const userMail = 'pippo@mail.com' - - const valueChanged = formMethods.watch() - const valuesRef = useRef(valueChanged) - valuesRef.current = valueChanged - - const debounceFn = useCallback( - debounce(() => { - console.log('value has been changed: call API', valuesRef.current) - //TODO: Dedcide timing in ms - }, 1000), - [] - ) - - useEffect(() => { - if (valueChanged) debounceFn() - }, [debounceFn, valueChanged]) - - const onClickEnableAllSectionSwitch = (sectionName: string) => { - const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap((s) => - s.components.map((c) => c.key) - ) - - sectionComponentsKeys.map((inAppConfigKey) => { - formMethods.setValue(inAppConfigKey as keyof NotificationConfig, true) - }) - } - - return ( - - - - Indirizzo email - {userMail} - - - {t('linkLabel')} - - - - } - /> - {valueChanged.enableAllNotification && - Object.keys(notificationSchema).map((sectionName) => { - return ( - - - - - - - {notificationSchema[sectionName].title} - - - - - - - {notificationSchema[sectionName].subsections.map((subsection) => ( - - ))} - - - ) - })} - - - - ) -} diff --git a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx similarity index 59% rename from src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx rename to src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx index c765158d3..752ab9bb0 100644 --- a/src/pages/NotificationUserConfigPage/components/InAppNotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx @@ -8,39 +8,59 @@ import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' import { type NotificationConfig } from '@/api/api.generatedTypes' -import { debounce } from 'lodash' -import type { NotificationSubSectionSchema } from '../types' +import { debounce, isEqual } from 'lodash' +import type { NotificationSubSectionSchema, NotificationConfigType } from '../types' -type InAppNotificationUserConfigTabProps = { - inAppConfig: NotificationConfig +type NotificationConfigUserTabProps = { + notificationConfig: NotificationConfig + handleUpdateNotificationConfigs: ( + notificationConfig: NotificationConfig, + type: NotificationConfigType + ) => void + type: NotificationConfigType } -export const InAppNotificationUserConfigTab: React.FC = ({ - inAppConfig, +export const NotificationConfigUserTab: React.FC = ({ + notificationConfig, + handleUpdateNotificationConfigs, + type, }) => { - const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.inAppTab' }) + const { t } = useTranslation('notification', { keyPrefix: `configurationPage.${type}` }) - const { notificationSchema } = useNotificationInAppConfigForm() + const { notificationSchema } = useNotificationInAppConfigForm('inApp') + + const userEmail = 'pippo@mail.com' const formMethods = useForm({ - defaultValues: { ...inAppConfig, enableAllNotification: false }, + defaultValues: { ...notificationConfig, enableAllNotification: true }, }) const valueChanged = formMethods.watch() - const valuesRef = useRef(valueChanged) + const valuesRef = useRef(valueChanged) + const previousValuesRef = useRef(null) + + console.log('type', type) + valuesRef.current = valueChanged + // eslint-disable-next-line react-hooks/exhaustive-deps const debounceFn = useCallback( debounce(() => { - // console.log('value has been changed: call API', valuesRef.current) - //TODO: Dedcide timing in ms + previousValuesRef.current = valuesRef.current + handleUpdateNotificationConfigs(valuesRef.current, type) }, 1000), [] ) useEffect(() => { - if (valueChanged) debounceFn() - }, [debounceFn, valueChanged]) + if ( + formMethods.formState.isDirty && + valueChanged && + !isEqual(valueChanged, previousValuesRef.current) + ) { + debounceFn() + } + }, [debounceFn, valueChanged, formMethods.formState.isDirty]) const onClickEnableAllSectionSwitch = (sectionName: string) => { const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap( @@ -55,20 +75,33 @@ export const InAppNotificationUserConfigTab: React.FC - - {t('manualLinkLabel')} - + {type === 'inApp' && ( + + {t('manualLinkLabel')} + + )} + + {type === 'email' && ( + + Indirizzo email + {userEmail} + + )} - - } - /> + {type === 'inApp' && ( + + } + /> + )} + + {type === 'email' &&
EMAIL DA CONFIGURARE
} {valueChanged.enableAllNotification && Object.keys(notificationSchema).map((sectionName) => { diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts deleted file mode 100644 index cab457e3d..000000000 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationEmailConfigForm.ts +++ /dev/null @@ -1,283 +0,0 @@ -import { useTranslation } from 'react-i18next' -import { type NotificationConfigSchema } from '../types' - -export function useNotificationEmailConfigForm() { - const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) - - const notificationSchema: NotificationConfigSchema = { - subscriber: { - title: t('subscriber.title'), - subsections: [ - { - name: 'fruizioneDati', - title: t('subscriber.dataUsage.title'), - components: [ - { - key: 'eserviceStateChangedToConsumer', - title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', - description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), - visibility: ['admin', 'security'], - }, - { - key: 'agreementActivatedRejectedToConsumer', - title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', - description: t('subscriber.dataUsage.components.agreementManagement.description'), - visibility: ['admin', 'security'], - }, - { - key: 'agreementSuspendedUnsuspendedToConsumer', - title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', - description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'finalita', - title: t('subscriber.purpose.title'), - components: [ - { - key: 'purposeActivatedRejectedToConsumer', - title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', - description: t('subscriber.purpose.components.purposeManagement.description'), - visibility: ['admin'], - }, - { - key: 'purposeSuspendedUnsuspendedToConsumer', - title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', - description: t('subscriber.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'soglieDiCarico', - title: t('subscriber.thresholds.title'), - components: [ - { - key: 'TODO', - title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), - description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), - visibility: ['admin', 'security'], // to be define - }, - { - key: 'TODO', - title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), - description: t( - 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' - ), - visibility: ['admin', 'security'], // to be define - }, - ], - }, - ], - }, - provider: { - title: t('provider.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('provider.agreement.title'), - components: [ - { - key: 'agreementManagementToProducer', - title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', - description: t('provider.agreement.components.agreementRequestReceived.description'), - visibility: ['admin'], - }, - { - key: 'agreementSuspendedUnsuspendedToProducer', - title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', - description: t('provider.agreement.components.agreementStateUpdated.description'), - visibility: ['admin'], - }, - ], - }, - { - name: 'finalita', - title: t('provider.purpose.title'), - components: [ - { - key: 'purposeStatusChangedToProducer', - title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', - description: t('provider.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'api'], - }, - ], - }, - { - name: 'clientSoglieDiCarico', - title: t('provider.clientAndThresholds.title'), - components: [ - { - key: 'clientAddedRemovedToProducer', - title: - t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + - '(05)', - description: t( - 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' - ), - visibility: ['admin', 'api'], - }, - { - key: 'TODO', - title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdExceeded.description' - ), - visibility: ['admin', 'api'], // to be defined - }, - { - key: 'TODO', - title: - t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + - 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' - ), - visibility: ['admin', 'api'], // to be defined - }, - ], - }, - { - name: 'eserviceTemplate', - title: t('provider.eserviceTemplate.title'), - components: [ - { - key: 'newEserviceTemplateVersionToInstantiator', - title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', - description: t( - 'provider.eserviceTemplate.components.instanceFromTemplate.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'eserviceTemplateStatusChangedToInstantiator', - title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', - description: t( - 'provider.eserviceTemplate.components.templateStateUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'newTemplateVersion', - title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', - description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), - visibility: ['admin', 'security'], // to be defined - }, - { - key: 'eserviceTemplateNameChangedToInstantiator', - title: - t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', - description: t( - 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'templateStatusChangedToProducer', - title: - t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + - '(09)', - description: t( - 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - delegations: { - title: t('delegation.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('delegation.delegationAssignment.title'), - components: [ - { - key: 'delegationApprovedRejectedToDelegator', - title: - t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', - description: t( - 'delegation.delegationAssignment.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionSubmittedToDelegator', - title: - t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + - '(21)', - description: t( - 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'delegationReceive', - title: t('delegation.delegationReceive.title'), - components: [ - { - key: 'delegationSubmittedRevokedToDelegate', - title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', - description: t( - 'delegation.delegationReceive.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionApprovedRejectedToDelegate', - title: - t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + - '(22)', - description: t( - 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - keyAndAttributes: { - title: t('keyAndAttributes.title'), - subsections: [ - { - name: 'attributes', - title: t('keyAndAttributes.attributes.title'), - components: [ - { - key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', - title: - t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', - description: t( - 'keyAndAttributes.attributes.components.attributesStateUpdated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'keys', - title: t('keyAndAttributes.keys.title'), - components: [ - { - key: 'clientKeyAddedDeletedToClientUsers', - title: - t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', - description: t( - 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' - ), - visibility: ['admin', 'security'], - }, - ], - }, - ], - }, - } - - return { notificationSchema } -} diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts index 8e5e590b9..efed9eb8d 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -1,283 +1,578 @@ import { useTranslation } from 'react-i18next' -import { type NotificationConfigSchema } from '../types' +import { type NotificationConfigSchema, type NotificationConfigType } from '../types' +import { match } from 'ts-pattern' -export function useNotificationInAppConfigForm() { +export function useNotificationInAppConfigForm(type: NotificationConfigType) { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) - const notificationSchema: NotificationConfigSchema = { - subscriber: { - title: t('subscriber.title'), - subsections: [ - { - name: 'fruizioneDati', - title: t('subscriber.dataUsage.title'), - components: [ - { - key: 'eserviceStateChangedToConsumer', - title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', - description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), - visibility: ['admin', 'security'], - }, - { - key: 'agreementActivatedRejectedToConsumer', - title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', - description: t('subscriber.dataUsage.components.agreementManagement.description'), - visibility: ['admin'], - }, - { - key: 'agreementSuspendedUnsuspendedToConsumer', - title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', - description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'finalita', - title: t('subscriber.purpose.title'), - components: [ - { - key: 'purposeActivatedRejectedToConsumer', - title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', - description: t('subscriber.purpose.components.purposeManagement.description'), - visibility: ['admin'], - }, - { - key: 'purposeSuspendedUnsuspendedToConsumer', - title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', - description: t('subscriber.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'soglieDiCarico', - title: t('subscriber.thresholds.title'), - components: [ - { - key: 'TODO', - title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), - description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), - visibility: ['admin'], // To define - }, - { - key: 'TODO', - title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), - description: t( - 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' - ), - visibility: ['admin'], // To define - }, - ], - }, - ], - }, - provider: { - title: t('provider.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('provider.agreement.title'), - components: [ - { - key: 'agreementManagementToProducer', - title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', - description: t('provider.agreement.components.agreementRequestReceived.description'), - visibility: ['admin'], - }, - { - key: 'agreementSuspendedUnsuspendedToProducer', - title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', - description: t('provider.agreement.components.agreementStateUpdated.description'), - visibility: ['admin'], - }, - ], - }, - { - name: 'finalita', - title: t('provider.purpose.title'), - components: [ - { - key: 'purposeStatusChangedToProducer', - title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', - description: t('provider.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'api'], - }, - ], - }, - { - name: 'clientSoglieDiCarico', - title: t('provider.clientAndThresholds.title'), - components: [ - { - key: 'clientAddedRemovedToProducer', - title: - t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + - '(05)', - description: t( - 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' - ), - visibility: ['admin', 'api'], - }, - { - key: 'TODO', - title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdExceeded.description' - ), - visibility: ['admin', 'api'], // To define - }, - { - key: 'TODO', - title: - t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + - 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' - ), - visibility: ['admin', 'api'], // To define - }, - ], - }, - { - name: 'eserviceTemplate', - title: t('provider.eserviceTemplate.title'), - components: [ - { - key: 'newEserviceTemplateVersionToInstantiator', - title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', - description: t( - 'provider.eserviceTemplate.components.instanceFromTemplate.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'eserviceTemplateStatusChangedToInstantiator', - title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', - description: t( - 'provider.eserviceTemplate.components.templateStateUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'newTemplateVersion', - title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', - description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), - visibility: ['admin', 'security'], // To define - }, - { - key: 'eserviceTemplateNameChangedToInstantiator', - title: - t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', - description: t( - 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'templateStatusChangedToProducer', - title: - t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + - '(09)', - description: t( - 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - delegations: { - title: t('delegation.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('delegation.delegationAssignment.title'), - components: [ - { - key: 'delegationApprovedRejectedToDelegator', - title: - t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', - description: t( - 'delegation.delegationAssignment.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionSubmittedToDelegator', - title: - t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + - '(21)', - description: t( - 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'delegationReceive', - title: t('delegation.delegationReceive.title'), - components: [ - { - key: 'delegationSubmittedRevokedToDelegate', - title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', - description: t( - 'delegation.delegationReceive.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionApprovedRejectedToDelegate', - title: - t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + - '(22)', - description: t( - 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - keyAndAttributes: { - title: t('keyAndAttributes.title'), - subsections: [ - { - name: 'attributes', - title: t('keyAndAttributes.attributes.title'), - components: [ - { - key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', - title: - t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', - description: t( - 'keyAndAttributes.attributes.components.attributesStateUpdated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'keys', - title: t('keyAndAttributes.keys.title'), - components: [ - { - key: 'clientKeyAddedDeletedToClientUsers', - title: - t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', - description: t( - 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' - ), - visibility: ['admin', 'security'], // To define - }, - ], - }, - ], - }, - } + const notificationSchema: NotificationConfigSchema = match(type) + .with('inApp', () => ({ + subscriber: { + title: t('subscriber.title'), + subsections: [ + { + name: 'fruizioneDati', + title: t('subscriber.dataUsage.title'), + components: [ + { + key: 'eserviceStateChangedToConsumer', + title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', + description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + visibility: ['admin', ''], + }, + { + key: 'agreementActivatedRejectedToConsumer', + title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', + description: t('subscriber.dataUsage.components.agreementManagement.description'), + visibility: ['admin'], + }, + { + key: 'agreementSuspendedUnsuspendedToConsumer', + title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', + description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'finalita', + title: t('subscriber.purpose.title'), + components: [ + { + key: 'purposeActivatedRejectedToConsumer', + title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', + description: t('subscriber.purpose.components.purposeManagement.description'), + visibility: ['admin'], + }, + { + key: 'purposeSuspendedUnsuspendedToConsumer', + title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', + description: t('subscriber.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'soglieDiCarico', + title: t('subscriber.thresholds.title'), + components: [ + // { + // key: 'TODO', + // title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), + // description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + // visibility: ['admin'], // To define + // }, + // { + // key: 'TODO', + // title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), + // description: t( + // 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' + // ), + // visibility: ['admin'], // To define + // }, + ], + }, + ], + }, + provider: { + title: t('provider.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('provider.agreement.title'), + components: [ + { + key: 'agreementManagementToProducer', + title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', + description: t( + 'provider.agreement.components.agreementRequestReceived.description' + ), + visibility: ['admin'], + }, + { + key: 'agreementSuspendedUnsuspendedToProducer', + title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', + description: t('provider.agreement.components.agreementStateUpdated.description'), + visibility: ['admin'], + }, + ], + }, + { + name: 'finalita', + title: t('provider.purpose.title'), + components: [ + { + key: 'purposeStatusChangedToProducer', + title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', + description: t('provider.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'api'], + }, + ], + }, + { + name: 'clientSoglieDiCarico', + title: t('provider.clientAndThresholds.title'), + components: [ + { + key: 'clientAddedRemovedToProducer', + title: + t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.label' + ) + '(05)', + description: t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' + ), + visibility: ['admin', 'api'], + }, + // { + // key: 'TODO', + // title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', + // description: t( + // 'provider.clientAndThresholds.components.thresholdExceeded.description' + // ), + // visibility: ['admin', 'api'], // To define + // }, + // { + // key: 'TODO', + // title: + // t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + + // 'BOH', + // description: t( + // 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' + // ), + // visibility: ['admin', 'api'], // To define + // }, + ], + }, + { + name: 'eserviceTemplate', + title: t('provider.eserviceTemplate.title'), + components: [ + { + key: 'newEserviceTemplateVersionToInstantiator', + title: + t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', + description: t( + 'provider.eserviceTemplate.components.instanceFromTemplate.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'eserviceTemplateStatusChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', + description: t( + 'provider.eserviceTemplate.components.templateStateUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'newTemplateVersion', + title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', + description: t( + 'provider.eserviceTemplate.components.newTemplateVersion.description' + ), + visibility: ['admin', 'security'], // To define + }, + { + key: 'eserviceTemplateNameChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + + '(18)', + description: t( + 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'templateStatusChangedToProducer', + title: + t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + + '(09)', + description: t( + 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + delegations: { + title: t('delegation.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('delegation.delegationAssignment.title'), + components: [ + { + key: 'delegationApprovedRejectedToDelegator', + title: + t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', + description: t( + 'delegation.delegationAssignment.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionSubmittedToDelegator', + title: + t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + + '(21)', + description: t( + 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'delegationReceive', + title: t('delegation.delegationReceive.title'), + components: [ + { + key: 'delegationSubmittedRevokedToDelegate', + title: + t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', + description: t( + 'delegation.delegationReceive.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionApprovedRejectedToDelegate', + title: + t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + + '(22)', + description: t( + 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + keyAndAttributes: { + title: t('keyAndAttributes.title'), + subsections: [ + { + name: 'attributes', + title: t('keyAndAttributes.attributes.title'), + components: [ + { + key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', + title: + t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', + description: t( + 'keyAndAttributes.attributes.components.attributesStateUpdated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'keys', + title: t('keyAndAttributes.keys.title'), + components: [ + { + key: 'clientKeyAddedDeletedToClientUsers', + title: + t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', + description: t( + 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' + ), + visibility: ['admin', 'security'], // To define + }, + ], + }, + ], + }, + })) + .with('email', () => ({ + subscriber: { + title: t('subscriber.title'), + subsections: [ + { + name: 'fruizioneDati', + title: t('subscriber.dataUsage.title'), + components: [ + { + key: 'eserviceStateChangedToConsumer', + title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', + description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + visibility: ['admin', 'security'], + }, + { + key: 'agreementActivatedRejectedToConsumer', + title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', + description: t('subscriber.dataUsage.components.agreementManagement.description'), + visibility: ['admin', 'security'], + }, + { + key: 'agreementSuspendedUnsuspendedToConsumer', + title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', + description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'finalita', + title: t('subscriber.purpose.title'), + components: [ + { + key: 'purposeActivatedRejectedToConsumer', + title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', + description: t('subscriber.purpose.components.purposeManagement.description'), + visibility: ['admin'], + }, + { + key: 'purposeSuspendedUnsuspendedToConsumer', + title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', + description: t('subscriber.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'soglieDiCarico', + title: t('subscriber.thresholds.title'), + components: [ + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), + description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + visibility: ['admin', 'security'], // to be define + }, + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), + description: t( + 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' + ), + visibility: ['admin', 'security'], // to be define + }, + ], + }, + ], + }, + provider: { + title: t('provider.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('provider.agreement.title'), + components: [ + { + key: 'agreementManagementToProducer', + title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', + description: t( + 'provider.agreement.components.agreementRequestReceived.description' + ), + visibility: ['admin'], + }, + { + key: 'agreementSuspendedUnsuspendedToProducer', + title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', + description: t('provider.agreement.components.agreementStateUpdated.description'), + visibility: ['admin'], + }, + ], + }, + { + name: 'finalita', + title: t('provider.purpose.title'), + components: [ + { + key: 'purposeStatusChangedToProducer', + title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', + description: t('provider.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'api'], + }, + ], + }, + { + name: 'clientSoglieDiCarico', + title: t('provider.clientAndThresholds.title'), + components: [ + { + key: 'clientAddedRemovedToProducer', + title: + t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.label' + ) + '(05)', + description: t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' + ), + visibility: ['admin', 'api'], + }, + { + key: 'TODO', + title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdExceeded.description' + ), + visibility: ['admin', 'api'], // to be defined + }, + { + key: 'TODO', + title: + t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' + ), + visibility: ['admin', 'api'], // to be defined + }, + ], + }, + { + name: 'eserviceTemplate', + title: t('provider.eserviceTemplate.title'), + components: [ + { + key: 'newEserviceTemplateVersionToInstantiator', + title: + t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', + description: t( + 'provider.eserviceTemplate.components.instanceFromTemplate.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'eserviceTemplateStatusChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', + description: t( + 'provider.eserviceTemplate.components.templateStateUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'newTemplateVersion', + title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', + description: t( + 'provider.eserviceTemplate.components.newTemplateVersion.description' + ), + visibility: ['admin', 'security'], // to be defined + }, + { + key: 'eserviceTemplateNameChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + + '(18)', + description: t( + 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'templateStatusChangedToProducer', + title: + t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + + '(09)', + description: t( + 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + delegations: { + title: t('delegation.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('delegation.delegationAssignment.title'), + components: [ + { + key: 'delegationApprovedRejectedToDelegator', + title: + t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', + description: t( + 'delegation.delegationAssignment.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionSubmittedToDelegator', + title: + t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + + '(21)', + description: t( + 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'delegationReceive', + title: t('delegation.delegationReceive.title'), + components: [ + { + key: 'delegationSubmittedRevokedToDelegate', + title: + t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', + description: t( + 'delegation.delegationReceive.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionApprovedRejectedToDelegate', + title: + t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + + '(22)', + description: t( + 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + keyAndAttributes: { + title: t('keyAndAttributes.title'), + subsections: [ + { + name: 'attributes', + title: t('keyAndAttributes.attributes.title'), + components: [ + { + key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', + title: + t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', + description: t( + 'keyAndAttributes.attributes.components.attributesStateUpdated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'keys', + title: t('keyAndAttributes.keys.title'), + components: [ + { + key: 'clientKeyAddedDeletedToClientUsers', + title: + t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', + description: t( + 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' + ), + visibility: ['admin', 'security'], + }, + ], + }, + ], + }, + })) + .exhaustive() return { notificationSchema } } diff --git a/src/pages/NotificationUserConfigPage/types.ts b/src/pages/NotificationUserConfigPage/types.ts index 3e20c9ebb..0c6b9e28f 100644 --- a/src/pages/NotificationUserConfigPage/types.ts +++ b/src/pages/NotificationUserConfigPage/types.ts @@ -1,5 +1,7 @@ import { type UserProductRole } from '@/types/party.types' +export type NotificationConfigType = 'email' | 'inApp' + export type NotificationSubSectionSchema = { name: string title: string diff --git a/src/static/locales/en/notification.json b/src/static/locales/en/notification.json index a8b56f890..7229eb670 100644 --- a/src/static/locales/en/notification.json +++ b/src/static/locales/en/notification.json @@ -4,7 +4,7 @@ "description": "Gestisci le tue impostazioni di notifica in app e via email personale.", "inAppTabTitle": "Notifiche in-app", "emailTabTitle": "Email", - "inAppTab": { + "inApp": { "title": "Configurazione delle preferenze di notifica in piattaforma", "manualLinkLabel": "Dubbi? Vai sul manuale", "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", @@ -14,7 +14,7 @@ "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" } }, - "emailTab": { + "email": { "title": "Configurazione delle preferenze di notifica tramite email", "description": "Le notifiche email ti informeranno sulla tua casella personale gli eventi che ti riguardano. La mail che utilizzeremo è quella che ci hai fornito in fase di iscrizione.", "linkLabel": "Non è la tua mail? Scopri come aggiornarla", diff --git a/src/static/locales/it/notification.json b/src/static/locales/it/notification.json index a8b56f890..7229eb670 100644 --- a/src/static/locales/it/notification.json +++ b/src/static/locales/it/notification.json @@ -4,7 +4,7 @@ "description": "Gestisci le tue impostazioni di notifica in app e via email personale.", "inAppTabTitle": "Notifiche in-app", "emailTabTitle": "Email", - "inAppTab": { + "inApp": { "title": "Configurazione delle preferenze di notifica in piattaforma", "manualLinkLabel": "Dubbi? Vai sul manuale", "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", @@ -14,7 +14,7 @@ "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" } }, - "emailTab": { + "email": { "title": "Configurazione delle preferenze di notifica tramite email", "description": "Le notifiche email ti informeranno sulla tua casella personale gli eventi che ti riguardano. La mail che utilizzeremo è quella che ci hai fornito in fase di iscrizione.", "linkLabel": "Non è la tua mail? Scopri come aggiornarla", From 07a6b9ac6a28be589111e6f792d69b2046512466 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Thu, 18 Sep 2025 14:48:24 +0200 Subject: [PATCH 26/53] refactor: added some logic within usenNotificationConfigHook --- .../components/NotificationUserConfigTab.tsx | 105 +- .../hooks/useNotificationInAppConfigForm.ts | 1135 +++++++++-------- src/static/locales/en/notification.json | 8 +- src/static/locales/it/notification.json | 8 +- 4 files changed, 665 insertions(+), 591 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx index 752ab9bb0..cb0b0bf4d 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx @@ -2,14 +2,26 @@ import React, { useCallback, useEffect, useRef } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { NotificationConfigSection } from './NotificationConfigSection' import { SectionContainer } from '@/components/layout/containers' -import { Box, Card, Link, Stack, Typography, Button } from '@mui/material' +import { + Box, + Card, + Link, + Stack, + Typography, + Button, + FormControl, + InputLabel, + MenuItem, + Select, +} from '@mui/material' import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { useTranslation } from 'react-i18next' import MenuBookIcon from '@mui/icons-material/MenuBook' -import { useNotificationInAppConfigForm } from '../hooks/useNotificationInAppConfigForm' +import { useNotificationInAppConfigForm as useNotificationInAppConfigHook } from '../hooks/useNotificationInAppConfigForm' import { type NotificationConfig } from '@/api/api.generatedTypes' import { debounce, isEqual } from 'lodash' import type { NotificationSubSectionSchema, NotificationConfigType } from '../types' +import { match } from 'ts-pattern' type NotificationConfigUserTabProps = { notificationConfig: NotificationConfig @@ -27,9 +39,12 @@ export const NotificationConfigUserTab: React.FC }) => { const { t } = useTranslation('notification', { keyPrefix: `configurationPage.${type}` }) - const { notificationSchema } = useNotificationInAppConfigForm('inApp') + const { notificationSchema, sectionComponentKeysMap } = useNotificationInAppConfigHook(type) + const [emailPreferencesChoice, setPreferencesChoices] = React.useState< + 'notSend' | 'digest' | 'customize' + >('customize') - const userEmail = 'pippo@mail.com' + const userEmail = 'pippo@mail.com' // TODO: Should be available with api const formMethods = useForm({ defaultValues: { ...notificationConfig, enableAllNotification: true }, @@ -39,8 +54,6 @@ export const NotificationConfigUserTab: React.FC const valuesRef = useRef(valueChanged) const previousValuesRef = useRef(null) - console.log('type', type) - valuesRef.current = valueChanged // eslint-disable-next-line react-hooks/exhaustive-deps @@ -62,14 +75,27 @@ export const NotificationConfigUserTab: React.FC } }, [debounceFn, valueChanged, formMethods.formState.isDirty]) - const onClickEnableAllSectionSwitch = (sectionName: string) => { - const sectionComponentsKeys = notificationSchema[sectionName].subsections.flatMap( - (s: NotificationSubSectionSchema) => s.components.map((c) => c.key) + const onClickEnableAllSectionSwitch = (sectionName: string, value: boolean) => { + sectionComponentKeysMap[sectionName].map((inAppConfigKey: string) => { + formMethods.setValue(inAppConfigKey as keyof NotificationConfig, value) + }) + } + + const getSwitchBySections = (sectionName: string) => { + return sectionComponentKeysMap[sectionName].filter( + (item) => !valuesRef.current[item as keyof NotificationConfig] ) + } - sectionComponentsKeys.map((inAppConfigKey: string) => { - formMethods.setValue(inAppConfigKey as keyof NotificationConfig, true) - }) + const isEnabledShowPreferencesSwitch = (): boolean => { + return match(type) + .with('email', () => { + return emailPreferencesChoice === 'customize' + }) + .with('inApp', () => { + return valueChanged.enableAllNotification + }) + .exhaustive() } return ( @@ -82,12 +108,41 @@ export const NotificationConfigUserTab: React.FC )} {type === 'email' && ( - - Indirizzo email - {userEmail} - + <> + + Indirizzo email + {userEmail} + + + {t('linkLabel')} + + )} - + + {type === 'email' && ( + + {t('emailPreferencesLabel')} + + + )} + + {type === 'inApp' && ( /> )} - {type === 'email' &&
EMAIL DA CONFIGURARE
} - - {valueChanged.enableAllNotification && + {isEnabledShowPreferencesSwitch() && Object.keys(notificationSchema).map((sectionName) => { + const isAllSwitchWithinSectionDisabled = getSwitchBySections(sectionName).length <= 0 return ( @@ -124,9 +178,16 @@ export const NotificationConfigUserTab: React.FC diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts index efed9eb8d..5998c3fe5 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationInAppConfigForm.ts @@ -1,578 +1,579 @@ import { useTranslation } from 'react-i18next' +import type { NotificationSubSectionSchema } from '../types' import { type NotificationConfigSchema, type NotificationConfigType } from '../types' import { match } from 'ts-pattern' +import React from 'react' export function useNotificationInAppConfigForm(type: NotificationConfigType) { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) + const inAppNotificationConfigSchema: NotificationConfigSchema = { + subscriber: { + title: t('subscriber.title'), + subsections: [ + { + name: 'fruizioneDati', + title: t('subscriber.dataUsage.title'), + components: [ + { + key: 'eserviceStateChangedToConsumer', + title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', + description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + visibility: ['admin', 'security'], + }, + { + key: 'agreementActivatedRejectedToConsumer', + title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', + description: t('subscriber.dataUsage.components.agreementManagement.description'), + visibility: ['admin'], + }, + { + key: 'agreementSuspendedUnsuspendedToConsumer', + title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', + description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'finalita', + title: t('subscriber.purpose.title'), + components: [ + { + key: 'purposeActivatedRejectedToConsumer', + title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', + description: t('subscriber.purpose.components.purposeManagement.description'), + visibility: ['admin'], + }, + { + key: 'purposeSuspendedUnsuspendedToConsumer', + title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', + description: t('subscriber.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'soglieDiCarico', + title: t('subscriber.thresholds.title'), + components: [ + // { + // key: 'TODO', + // title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), + // description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + // visibility: ['admin'], // To define + // }, + // { + // key: 'TODO', + // title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), + // description: t( + // 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' + // ), + // visibility: ['admin'], // To define + // }, + ], + }, + ], + }, + provider: { + title: t('provider.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('provider.agreement.title'), + components: [ + { + key: 'agreementManagementToProducer', + title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', + description: t('provider.agreement.components.agreementRequestReceived.description'), + visibility: ['admin'], + }, + { + key: 'agreementSuspendedUnsuspendedToProducer', + title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', + description: t('provider.agreement.components.agreementStateUpdated.description'), + visibility: ['admin'], + }, + ], + }, + { + name: 'finalita', + title: t('provider.purpose.title'), + components: [ + { + key: 'purposeStatusChangedToProducer', + title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', + description: t('provider.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'api'], + }, + ], + }, + { + name: 'clientSoglieDiCarico', + title: t('provider.clientAndThresholds.title'), + components: [ + { + key: 'clientAddedRemovedToProducer', + title: + t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + + '(05)', + description: t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' + ), + visibility: ['admin', 'api'], + }, + // { + // key: 'TODO', + // title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', + // description: t( + // 'provider.clientAndThresholds.components.thresholdExceeded.description' + // ), + // visibility: ['admin', 'api'], // To define + // }, + // { + // key: 'TODO', + // title: + // t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + + // 'BOH', + // description: t( + // 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' + // ), + // visibility: ['admin', 'api'], // To define + // }, + ], + }, + { + name: 'eserviceTemplate', + title: t('provider.eserviceTemplate.title'), + components: [ + { + key: 'newEserviceTemplateVersionToInstantiator', + title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', + description: t( + 'provider.eserviceTemplate.components.instanceFromTemplate.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'eserviceTemplateStatusChangedToInstantiator', + title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', + description: t( + 'provider.eserviceTemplate.components.templateStateUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'newTemplateVersion', + title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', + description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), + visibility: ['admin', 'security'], // To define + }, + { + key: 'eserviceTemplateNameChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', + description: t( + 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'templateStatusChangedToProducer', + title: + t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + + '(09)', + description: t( + 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + delegations: { + title: t('delegation.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('delegation.delegationAssignment.title'), + components: [ + { + key: 'delegationApprovedRejectedToDelegator', + title: + t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', + description: t( + 'delegation.delegationAssignment.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionSubmittedToDelegator', + title: + t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + + '(21)', + description: t( + 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'delegationReceive', + title: t('delegation.delegationReceive.title'), + components: [ + { + key: 'delegationSubmittedRevokedToDelegate', + title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', + description: t( + 'delegation.delegationReceive.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionApprovedRejectedToDelegate', + title: + t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + + '(22)', + description: t( + 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + keyAndAttributes: { + title: t('keyAndAttributes.title'), + subsections: [ + { + name: 'attributes', + title: t('keyAndAttributes.attributes.title'), + components: [ + { + key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', + title: + t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', + description: t( + 'keyAndAttributes.attributes.components.attributesStateUpdated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'keys', + title: t('keyAndAttributes.keys.title'), + components: [ + { + key: 'clientKeyAddedDeletedToClientUsers', + title: + t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', + description: t( + 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' + ), + visibility: ['admin', 'security'], // To define + }, + ], + }, + ], + }, + } + const emailNotificationConfigSchema: NotificationConfigSchema = { + subscriber: { + title: t('subscriber.title'), + subsections: [ + { + name: 'fruizioneDati', + title: t('subscriber.dataUsage.title'), + components: [ + { + key: 'eserviceStateChangedToConsumer', + title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', + description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), + visibility: ['admin', 'security'], + }, + { + key: 'agreementActivatedRejectedToConsumer', + title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', + description: t('subscriber.dataUsage.components.agreementManagement.description'), + visibility: ['admin', 'security'], + }, + { + key: 'agreementSuspendedUnsuspendedToConsumer', + title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', + description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'finalita', + title: t('subscriber.purpose.title'), + components: [ + { + key: 'purposeActivatedRejectedToConsumer', + title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', + description: t('subscriber.purpose.components.purposeManagement.description'), + visibility: ['admin'], + }, + { + key: 'purposeSuspendedUnsuspendedToConsumer', + title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', + description: t('subscriber.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'security'], + }, + ], + }, + { + name: 'soglieDiCarico', + title: t('subscriber.thresholds.title'), + components: [ + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), + description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), + visibility: ['admin', 'security'], // to be define + }, + { + key: 'TODO', + title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), + description: t( + 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' + ), + visibility: ['admin', 'security'], // to be define + }, + ], + }, + ], + }, + provider: { + title: t('provider.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('provider.agreement.title'), + components: [ + { + key: 'agreementManagementToProducer', + title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', + description: t('provider.agreement.components.agreementRequestReceived.description'), + visibility: ['admin'], + }, + { + key: 'agreementSuspendedUnsuspendedToProducer', + title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', + description: t('provider.agreement.components.agreementStateUpdated.description'), + visibility: ['admin'], + }, + ], + }, + { + name: 'finalita', + title: t('provider.purpose.title'), + components: [ + { + key: 'purposeStatusChangedToProducer', + title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', + description: t('provider.purpose.components.purposeStateUpdated.description'), + visibility: ['admin', 'api'], + }, + ], + }, + { + name: 'clientSoglieDiCarico', + title: t('provider.clientAndThresholds.title'), + components: [ + { + key: 'clientAddedRemovedToProducer', + title: + t('provider.clientAndThresholds.components.clientAssociationFromSubscriber.label') + + '(05)', + description: t( + 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' + ), + visibility: ['admin', 'api'], + }, + { + key: 'TODO', + title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdExceeded.description' + ), + visibility: ['admin', 'api'], // to be defined + }, + { + key: 'TODO', + title: + t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + + 'BOH', + description: t( + 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' + ), + visibility: ['admin', 'api'], // to be defined + }, + ], + }, + { + name: 'eserviceTemplate', + title: t('provider.eserviceTemplate.title'), + components: [ + { + key: 'newEserviceTemplateVersionToInstantiator', + title: t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', + description: t( + 'provider.eserviceTemplate.components.instanceFromTemplate.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'eserviceTemplateStatusChangedToInstantiator', + title: t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', + description: t( + 'provider.eserviceTemplate.components.templateStateUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'newTemplateVersion', + title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', + description: t('provider.eserviceTemplate.components.newTemplateVersion.description'), + visibility: ['admin', 'security'], // to be defined + }, + { + key: 'eserviceTemplateNameChangedToInstantiator', + title: + t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + '(18)', + description: t( + 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' + ), + visibility: ['admin', 'security'], + }, + { + key: 'templateStatusChangedToProducer', + title: + t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + + '(09)', + description: t( + 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + delegations: { + title: t('delegation.title'), + subsections: [ + { + name: 'richiesteFruizione', + title: t('delegation.delegationAssignment.title'), + components: [ + { + key: 'delegationApprovedRejectedToDelegator', + title: + t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', + description: t( + 'delegation.delegationAssignment.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionSubmittedToDelegator', + title: + t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + + '(21)', + description: t( + 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'delegationReceive', + title: t('delegation.delegationReceive.title'), + components: [ + { + key: 'delegationSubmittedRevokedToDelegate', + title: t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', + description: t( + 'delegation.delegationReceive.components.delegationUpdated.description' + ), + visibility: ['admin'], + }, + { + key: 'eserviceNewVersionApprovedRejectedToDelegate', + title: + t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + + '(22)', + description: t( + 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' + ), + visibility: ['admin', 'api'], + }, + ], + }, + ], + }, + keyAndAttributes: { + title: t('keyAndAttributes.title'), + subsections: [ + { + name: 'attributes', + title: t('keyAndAttributes.attributes.title'), + components: [ + { + key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', + title: + t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', + description: t( + 'keyAndAttributes.attributes.components.attributesStateUpdated.description' + ), + visibility: ['admin'], + }, + ], + }, + { + name: 'keys', + title: t('keyAndAttributes.keys.title'), + components: [ + { + key: 'clientKeyAddedDeletedToClientUsers', + title: + t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', + description: t( + 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' + ), + visibility: ['admin', 'security'], + }, + ], + }, + ], + }, + } const notificationSchema: NotificationConfigSchema = match(type) - .with('inApp', () => ({ - subscriber: { - title: t('subscriber.title'), - subsections: [ - { - name: 'fruizioneDati', - title: t('subscriber.dataUsage.title'), - components: [ - { - key: 'eserviceStateChangedToConsumer', - title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', - description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), - visibility: ['admin', ''], - }, - { - key: 'agreementActivatedRejectedToConsumer', - title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', - description: t('subscriber.dataUsage.components.agreementManagement.description'), - visibility: ['admin'], - }, - { - key: 'agreementSuspendedUnsuspendedToConsumer', - title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', - description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'finalita', - title: t('subscriber.purpose.title'), - components: [ - { - key: 'purposeActivatedRejectedToConsumer', - title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', - description: t('subscriber.purpose.components.purposeManagement.description'), - visibility: ['admin'], - }, - { - key: 'purposeSuspendedUnsuspendedToConsumer', - title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', - description: t('subscriber.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'soglieDiCarico', - title: t('subscriber.thresholds.title'), - components: [ - // { - // key: 'TODO', - // title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), - // description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), - // visibility: ['admin'], // To define - // }, - // { - // key: 'TODO', - // title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), - // description: t( - // 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' - // ), - // visibility: ['admin'], // To define - // }, - ], - }, - ], - }, - provider: { - title: t('provider.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('provider.agreement.title'), - components: [ - { - key: 'agreementManagementToProducer', - title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', - description: t( - 'provider.agreement.components.agreementRequestReceived.description' - ), - visibility: ['admin'], - }, - { - key: 'agreementSuspendedUnsuspendedToProducer', - title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', - description: t('provider.agreement.components.agreementStateUpdated.description'), - visibility: ['admin'], - }, - ], - }, - { - name: 'finalita', - title: t('provider.purpose.title'), - components: [ - { - key: 'purposeStatusChangedToProducer', - title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', - description: t('provider.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'api'], - }, - ], - }, - { - name: 'clientSoglieDiCarico', - title: t('provider.clientAndThresholds.title'), - components: [ - { - key: 'clientAddedRemovedToProducer', - title: - t( - 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.label' - ) + '(05)', - description: t( - 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' - ), - visibility: ['admin', 'api'], - }, - // { - // key: 'TODO', - // title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', - // description: t( - // 'provider.clientAndThresholds.components.thresholdExceeded.description' - // ), - // visibility: ['admin', 'api'], // To define - // }, - // { - // key: 'TODO', - // title: - // t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + - // 'BOH', - // description: t( - // 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' - // ), - // visibility: ['admin', 'api'], // To define - // }, - ], - }, - { - name: 'eserviceTemplate', - title: t('provider.eserviceTemplate.title'), - components: [ - { - key: 'newEserviceTemplateVersionToInstantiator', - title: - t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', - description: t( - 'provider.eserviceTemplate.components.instanceFromTemplate.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'eserviceTemplateStatusChangedToInstantiator', - title: - t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', - description: t( - 'provider.eserviceTemplate.components.templateStateUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'newTemplateVersion', - title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', - description: t( - 'provider.eserviceTemplate.components.newTemplateVersion.description' - ), - visibility: ['admin', 'security'], // To define - }, - { - key: 'eserviceTemplateNameChangedToInstantiator', - title: - t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + - '(18)', - description: t( - 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'templateStatusChangedToProducer', - title: - t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + - '(09)', - description: t( - 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - delegations: { - title: t('delegation.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('delegation.delegationAssignment.title'), - components: [ - { - key: 'delegationApprovedRejectedToDelegator', - title: - t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', - description: t( - 'delegation.delegationAssignment.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionSubmittedToDelegator', - title: - t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + - '(21)', - description: t( - 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'delegationReceive', - title: t('delegation.delegationReceive.title'), - components: [ - { - key: 'delegationSubmittedRevokedToDelegate', - title: - t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', - description: t( - 'delegation.delegationReceive.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionApprovedRejectedToDelegate', - title: - t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + - '(22)', - description: t( - 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - keyAndAttributes: { - title: t('keyAndAttributes.title'), - subsections: [ - { - name: 'attributes', - title: t('keyAndAttributes.attributes.title'), - components: [ - { - key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', - title: - t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', - description: t( - 'keyAndAttributes.attributes.components.attributesStateUpdated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'keys', - title: t('keyAndAttributes.keys.title'), - components: [ - { - key: 'clientKeyAddedDeletedToClientUsers', - title: - t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', - description: t( - 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' - ), - visibility: ['admin', 'security'], // To define - }, - ], - }, - ], - }, - })) - .with('email', () => ({ - subscriber: { - title: t('subscriber.title'), - subsections: [ - { - name: 'fruizioneDati', - title: t('subscriber.dataUsage.title'), - components: [ - { - key: 'eserviceStateChangedToConsumer', - title: t('subscriber.dataUsage.components.eServiceStateUpdated.label') + '(11)', - description: t('subscriber.dataUsage.components.eServiceStateUpdated.description'), - visibility: ['admin', 'security'], - }, - { - key: 'agreementActivatedRejectedToConsumer', - title: t('subscriber.dataUsage.components.agreementManagement.label') + '(12)', - description: t('subscriber.dataUsage.components.agreementManagement.description'), - visibility: ['admin', 'security'], - }, - { - key: 'agreementSuspendedUnsuspendedToConsumer', - title: t('subscriber.dataUsage.components.agreementStateUpdated.label') + '(13)', - description: t('subscriber.dataUsage.components.agreementStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'finalita', - title: t('subscriber.purpose.title'), - components: [ - { - key: 'purposeActivatedRejectedToConsumer', - title: t('subscriber.purpose.components.purposeManagement.label') + '(15)', - description: t('subscriber.purpose.components.purposeManagement.description'), - visibility: ['admin'], - }, - { - key: 'purposeSuspendedUnsuspendedToConsumer', - title: t('subscriber.purpose.components.purposeStateUpdated.label') + '(16)', - description: t('subscriber.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'security'], - }, - ], - }, - { - name: 'soglieDiCarico', - title: t('subscriber.thresholds.title'), - components: [ - { - key: 'TODO', - title: t('subscriber.thresholds.components.thresholdsExcedeed.label'), - description: t('subscriber.thresholds.components.thresholdsExcedeed.description'), - visibility: ['admin', 'security'], // to be define - }, - { - key: 'TODO', - title: t('subscriber.thresholds.components.thresholsdAdjustmentRequest.label'), - description: t( - 'subscriber.thresholds.components.thresholsdAdjustmentRequest.description' - ), - visibility: ['admin', 'security'], // to be define - }, - ], - }, - ], - }, - provider: { - title: t('provider.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('provider.agreement.title'), - components: [ - { - key: 'agreementManagementToProducer', - title: t('provider.agreement.components.agreementRequestReceived.label') + '(03)', - description: t( - 'provider.agreement.components.agreementRequestReceived.description' - ), - visibility: ['admin'], - }, - { - key: 'agreementSuspendedUnsuspendedToProducer', - title: t('provider.agreement.components.agreementStateUpdated.label') + '(04)', - description: t('provider.agreement.components.agreementStateUpdated.description'), - visibility: ['admin'], - }, - ], - }, - { - name: 'finalita', - title: t('provider.purpose.title'), - components: [ - { - key: 'purposeStatusChangedToProducer', - title: t('provider.purpose.components.purposeStateUpdated.label') + '(07)', - description: t('provider.purpose.components.purposeStateUpdated.description'), - visibility: ['admin', 'api'], - }, - ], - }, - { - name: 'clientSoglieDiCarico', - title: t('provider.clientAndThresholds.title'), - components: [ - { - key: 'clientAddedRemovedToProducer', - title: - t( - 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.label' - ) + '(05)', - description: t( - 'provider.clientAndThresholds.components.clientAssociationFromSubscriber.description' - ), - visibility: ['admin', 'api'], - }, - { - key: 'TODO', - title: t('provider.clientAndThresholds.components.thresholdExceeded.label') + 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdExceeded.description' - ), - visibility: ['admin', 'api'], // to be defined - }, - { - key: 'TODO', - title: - t('provider.clientAndThresholds.components.thresholdAdjustmentRequest.label') + - 'BOH', - description: t( - 'provider.clientAndThresholds.components.thresholdAdjustmentRequest.description' - ), - visibility: ['admin', 'api'], // to be defined - }, - ], - }, - { - name: 'eserviceTemplate', - title: t('provider.eserviceTemplate.title'), - components: [ - { - key: 'newEserviceTemplateVersionToInstantiator', - title: - t('provider.eserviceTemplate.components.instanceFromTemplate.label') + '(17)', - description: t( - 'provider.eserviceTemplate.components.instanceFromTemplate.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'eserviceTemplateStatusChangedToInstantiator', - title: - t('provider.eserviceTemplate.components.templateStateUpdated.label') + '(19)', - description: t( - 'provider.eserviceTemplate.components.templateStateUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'newTemplateVersion', - title: t('provider.eserviceTemplate.components.newTemplateVersion.label') + 'BOH', - description: t( - 'provider.eserviceTemplate.components.newTemplateVersion.description' - ), - visibility: ['admin', 'security'], // to be defined - }, - { - key: 'eserviceTemplateNameChangedToInstantiator', - title: - t('provider.eserviceTemplate.components.templatePropertiesUpdated.label') + - '(18)', - description: t( - 'provider.eserviceTemplate.components.templatePropertiesUpdated.description' - ), - visibility: ['admin', 'security'], - }, - { - key: 'templateStatusChangedToProducer', - title: - t('provider.eserviceTemplate.components.templateStateArchivedSuspended.label') + - '(09)', - description: t( - 'provider.eserviceTemplate.components.templateStateArchivedSuspended.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - delegations: { - title: t('delegation.title'), - subsections: [ - { - name: 'richiesteFruizione', - title: t('delegation.delegationAssignment.title'), - components: [ - { - key: 'delegationApprovedRejectedToDelegator', - title: - t('delegation.delegationAssignment.components.delegationUpdated.label') + '(20)', - description: t( - 'delegation.delegationAssignment.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionSubmittedToDelegator', - title: - t('delegation.delegationAssignment.components.eserviceDelegatedCreated.label') + - '(21)', - description: t( - 'delegation.delegationAssignment.components.eserviceDelegatedCreated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'delegationReceive', - title: t('delegation.delegationReceive.title'), - components: [ - { - key: 'delegationSubmittedRevokedToDelegate', - title: - t('delegation.delegationReceive.components.delegationUpdated.label') + '(23)', - description: t( - 'delegation.delegationReceive.components.delegationUpdated.description' - ), - visibility: ['admin'], - }, - { - key: 'eserviceNewVersionApprovedRejectedToDelegate', - title: - t('delegation.delegationReceive.components.eserviceDelegatedApproval.label') + - '(22)', - description: t( - 'delegation.delegationReceive.components.eserviceDelegatedApproval.description' - ), - visibility: ['admin', 'api'], - }, - ], - }, - ], - }, - keyAndAttributes: { - title: t('keyAndAttributes.title'), - subsections: [ - { - name: 'attributes', - title: t('keyAndAttributes.attributes.title'), - components: [ - { - key: 'certifiedVerifiedAttributeAssignedRevokedToAssignee', - title: - t('keyAndAttributes.attributes.components.attributesStateUpdated.label') + '(24)', - description: t( - 'keyAndAttributes.attributes.components.attributesStateUpdated.description' - ), - visibility: ['admin'], - }, - ], - }, - { - name: 'keys', - title: t('keyAndAttributes.keys.title'), - components: [ - { - key: 'clientKeyAddedDeletedToClientUsers', - title: - t('keyAndAttributes.keys.components.clientKeysAssociationUpdated.label') + '(25)', - description: t( - 'keyAndAttributes.keys.components.clientKeysAssociationUpdated.description' - ), - visibility: ['admin', 'security'], - }, - ], - }, - ], - }, - })) + .with('inApp', () => { + return inAppNotificationConfigSchema + }) + .with('email', () => { + return emailNotificationConfigSchema + }) .exhaustive() - return { notificationSchema } + const sectionComponentKeysMap = React.useMemo(() => { + const keyMap: Record = {} + + Object.keys(notificationSchema).forEach((sectionName) => { + keyMap[sectionName] = notificationSchema[sectionName].subsections.flatMap( + (section: NotificationSubSectionSchema) => section.components.map((c) => c.key) + ) + }) + return keyMap + }, [notificationSchema]) + + return { notificationSchema, sectionComponentKeysMap } } diff --git a/src/static/locales/en/notification.json b/src/static/locales/en/notification.json index 7229eb670..2cf708f1d 100644 --- a/src/static/locales/en/notification.json +++ b/src/static/locales/en/notification.json @@ -9,6 +9,7 @@ "manualLinkLabel": "Dubbi? Vai sul manuale", "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", "enableSectionAllNotifications": "Abilita tutto", + "disableSectionAllNotifications": "Disabilita tutto", "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" @@ -20,10 +21,15 @@ "linkLabel": "Non è la tua mail? Scopri come aggiornarla", "mailLabel": "Indirizzo email", "enableSectionAllNotifications": "Abilita tutto", + "disableSectionAllNotifications": "Disabilita tutto", "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche e-mail", "description": "Disabilitando questa opzione, non riceverai nessuna e-mail" - } + }, + "emailPreferencesLabel": "Preferenze di ricezione", + "notSend": "Non inviare le notifiche via e-mail", + "digest": "Invia una e-mail di resoconto settimanale", + "customize": "Personalizza le notifiche via e-mail" }, "sections": { "subscriber": { diff --git a/src/static/locales/it/notification.json b/src/static/locales/it/notification.json index 7229eb670..2cf708f1d 100644 --- a/src/static/locales/it/notification.json +++ b/src/static/locales/it/notification.json @@ -9,6 +9,7 @@ "manualLinkLabel": "Dubbi? Vai sul manuale", "description": "Le notifiche di piattaforma ti informeranno sugli eventi che ti riguardano.", "enableSectionAllNotifications": "Abilita tutto", + "disableSectionAllNotifications": "Disabilita tutto", "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche in piattaforma", "description": "Disabilitando questa opzione, non riceverai nessuna notifica in piattaforma" @@ -20,10 +21,15 @@ "linkLabel": "Non è la tua mail? Scopri come aggiornarla", "mailLabel": "Indirizzo email", "enableSectionAllNotifications": "Abilita tutto", + "disableSectionAllNotifications": "Disabilita tutto", "enableAllNotifications": { "label": "Abilita la ricezione delle notifiche e-mail", "description": "Disabilitando questa opzione, non riceverai nessuna e-mail" - } + }, + "emailPreferencesLabel": "Preferenze di ricezione", + "notSend": "Non inviare le notifiche via e-mail", + "digest": "Invia una e-mail di resoconto settimanale", + "customize": "Personalizza le notifiche via e-mail" }, "sections": { "subscriber": { From 72759824b95eaefdea62442bf688bd956604bfb3 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Thu, 18 Sep 2025 15:25:23 +0200 Subject: [PATCH 27/53] chore: added info for "digest" --- .../components/NotificationUserConfigTab.tsx | 7 +++++++ src/static/locales/en/notification.json | 1 + src/static/locales/it/notification.json | 1 + 3 files changed, 9 insertions(+) diff --git a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx index cb0b0bf4d..339f7849a 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx @@ -13,6 +13,7 @@ import { InputLabel, MenuItem, Select, + Alert, } from '@mui/material' import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { useTranslation } from 'react-i18next' @@ -142,6 +143,12 @@ export const NotificationConfigUserTab: React.FC )} + {emailPreferencesChoice === 'digest' && type === 'email' && ( + + {t('digestInfoDescription')} + + )} + {type === 'inApp' && ( Date: Thu, 18 Sep 2025 15:41:29 +0200 Subject: [PATCH 28/53] feat: added tenant notification configuration --- .../UpdatePartyMailDrawer.tsx | 23 +++++++++++++++++-- src/static/locales/en/party.json | 3 +++ src/static/locales/it/party.json | 3 +++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx b/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx index 5430dc035..cf6fab062 100644 --- a/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx +++ b/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx @@ -2,7 +2,11 @@ import type { Mail } from '@/api/api.generatedTypes' import { AuthHooks } from '@/api/auth' import { TenantMutations } from '@/api/tenant' import { Drawer } from '@/components/shared/Drawer' -import { RHFTextField } from '@/components/shared/react-hook-form-inputs' +import { + RHFSwitch, + RHFTextField, + SwitchLabelDescription, +} from '@/components/shared/react-hook-form-inputs' import { emailRegex } from '@/utils/form.utils' import { Alert, Stack, Box } from '@mui/material' import isEqual from 'lodash/isEqual' @@ -28,7 +32,7 @@ export const UpdatePartyMailDrawer: React.FC = ({ }) => { const { t } = useTranslation('party', { keyPrefix: 'contacts' }) const { t: tCommon } = useTranslation('common') - const { jwt } = AuthHooks.useJwt() + const { jwt, currentRoles } = AuthHooks.useJwt() const { mutateAsync: updateMail } = TenantMutations.useUpdateMail() @@ -114,6 +118,21 @@ export const UpdatePartyMailDrawer: React.FC = ({ }} /> + {currentRoles.includes('admin') && ( + + + } + /> + + )} {email?.address && ( {t('drawer.mailChangeAlert')} diff --git a/src/static/locales/en/party.json b/src/static/locales/en/party.json index b46caca4a..074aa38fa 100644 --- a/src/static/locales/en/party.json +++ b/src/static/locales/en/party.json @@ -39,6 +39,9 @@ "mailField": { "label": "Party mail address (required)" }, + "notificationActivationField": { + "label": "Receive courtesy emails for the organization through this mailbox" + }, "descriptionField": { "label": "Notes", "infoLabel": "Min 10 chars, max 250 chars" diff --git a/src/static/locales/it/party.json b/src/static/locales/it/party.json index e36af17bc..36a893c90 100644 --- a/src/static/locales/it/party.json +++ b/src/static/locales/it/party.json @@ -39,6 +39,9 @@ "mailField": { "label": "Indirizzo email ente (richiesto)" }, + "notificationActivationField": { + "label": "Ricevi email di cortesia per l’ente attraverso questa casella" + }, "descriptionField": { "label": "Note", "infoLabel": "Min 10 caratteri, max 250 caratteri" From 45865cee2484290dad0d744575e9eca29a4746a6 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Fri, 19 Sep 2025 12:10:14 +0200 Subject: [PATCH 29/53] chore: added outcome snackbar when saving new configuration --- src/api/notification/notification.mutations.ts | 8 ++++++++ src/static/locales/en/notification.json | 4 ++++ src/static/locales/it/notification.json | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/src/api/notification/notification.mutations.ts b/src/api/notification/notification.mutations.ts index aaec52b0a..a4b24344d 100644 --- a/src/api/notification/notification.mutations.ts +++ b/src/api/notification/notification.mutations.ts @@ -1,8 +1,16 @@ import { useMutation } from '@tanstack/react-query' import { NotificationServices } from './index' +import { useTranslation } from 'react-i18next' function useUpdateNotificationUserConfigs() { + const { t } = useTranslation('notification', { + keyPrefix: 'configurationPage.outcome', + }) return useMutation({ mutationFn: NotificationServices.updateUserNotificationConfigs, + meta: { + successToastLabel: t('success'), + errorToastLabel: t('error'), + }, }) } diff --git a/src/static/locales/en/notification.json b/src/static/locales/en/notification.json index 58be82eec..c2f2cefc2 100644 --- a/src/static/locales/en/notification.json +++ b/src/static/locales/en/notification.json @@ -196,6 +196,10 @@ } } } + }, + "outcome": { + "success": "Preferenza di notifica salvata.", + "error": "Non è stato possibile aggiornare la preferenza di notifica. Riprova più tardi." } } } diff --git a/src/static/locales/it/notification.json b/src/static/locales/it/notification.json index 58be82eec..c2f2cefc2 100644 --- a/src/static/locales/it/notification.json +++ b/src/static/locales/it/notification.json @@ -196,6 +196,10 @@ } } } + }, + "outcome": { + "success": "Preferenza di notifica salvata.", + "error": "Non è stato possibile aggiornare la preferenza di notifica. Riprova più tardi." } } } From 6ee3b5dc761e5f3f5bafc21547bf6e68e874e3da Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Fri, 19 Sep 2025 12:49:19 +0200 Subject: [PATCH 30/53] chore: added information about tenant config on UpdatePartyMailDrawer --- .../notification/notification.mutations.ts | 7 ++ src/api/notification/notification.queries.ts | 8 +++ src/api/notification/notification.services.ts | 71 ++++++++++--------- .../PartyContactsSection.tsx | 23 +++++- .../UpdatePartyMailDrawer.tsx | 13 +++- src/static/locales/en/notification.json | 5 ++ src/static/locales/it/notification.json | 5 ++ 7 files changed, 97 insertions(+), 35 deletions(-) diff --git a/src/api/notification/notification.mutations.ts b/src/api/notification/notification.mutations.ts index a4b24344d..c8881e65d 100644 --- a/src/api/notification/notification.mutations.ts +++ b/src/api/notification/notification.mutations.ts @@ -14,6 +14,13 @@ function useUpdateNotificationUserConfigs() { }) } +function useUpdateNotificationTenantConfigs() { + return useMutation({ + mutationFn: NotificationServices.updateTenantNotificationConfigs, + }) +} + export const NotificationMutations = { useUpdateNotificationUserConfigs, + useUpdateNotificationTenantConfigs, } diff --git a/src/api/notification/notification.queries.ts b/src/api/notification/notification.queries.ts index 65bd5af74..479fdf619 100644 --- a/src/api/notification/notification.queries.ts +++ b/src/api/notification/notification.queries.ts @@ -8,6 +8,14 @@ function getUserNotificationConfigs() { }) } +function getTenantNotificationConfigs() { + return queryOptions({ + queryKey: ['getTenantNotificationConfiguration'], + queryFn: () => NotificationServices.getTenantNotificationConfigs(), + }) +} + export const NotificationQueries = { getUserNotificationConfigs, + getTenantNotificationConfigs, } diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index 3c0ac52b7..d7c0a4e47 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -2,6 +2,8 @@ import axiosInstance from '@/config/axios' import { BACKEND_FOR_FRONTEND_URL } from '@/config/env' import type { NotificationConfig, + TenantNotificationConfig, + TenantNotificationConfigUpdateSeed, UserNotificationConfig, UserNotificationConfigUpdateSeed, } from '../api.generatedTypes' @@ -13,47 +15,50 @@ async function updateUserNotificationConfigs(payload: UserNotificationConfigUpda ) } +async function updateTenantNotificationConfigs(payload: TenantNotificationConfigUpdateSeed) { + console.log('payload', payload) + return await axiosInstance.post( + `${BACKEND_FOR_FRONTEND_URL}/tenantNotificationConfigs`, + payload + ) +} + async function getUserNotificationConfigs() { const response = await axiosInstance.get( `${BACKEND_FOR_FRONTEND_URL}/userNotificationConfigs` ) return response.data - - // return new Promise((resolve) => { - // setTimeout(() => { - // resolve({ - // emailConfig: getNotificationConfig(crypto.randomBytes(1)[0] < 128), - // inAppConfig: getNotificationConfig(false), - // }) - // }, 5000) - // }) } - +async function getTenantNotificationConfigs() { + const response = await axiosInstance.get( + `${BACKEND_FOR_FRONTEND_URL}/tenantNotificationConfigs` + ) + return response.data +} export const NotificationServices = { updateUserNotificationConfigs, + updateTenantNotificationConfigs, getUserNotificationConfigs, + getTenantNotificationConfigs, } -function getNotificationConfig(randomValue: boolean): NotificationConfig { - return { - agreementSuspendedUnsuspendedToProducer: randomValue, // 04 - agreementManagementToProducer: randomValue, // 03 - clientAddedRemovedToProducer: randomValue, // 05 - purposeStatusChangedToProducer: randomValue, // 07 - templateStatusChangedToProducer: randomValue, //09 - agreementSuspendedUnsuspendedToConsumer: randomValue, // 13 - eserviceStateChangedToConsumer: randomValue, // 11 - agreementActivatedRejectedToConsumer: randomValue, // 12 - purposeActivatedRejectedToConsumer: randomValue, // 15 - purposeSuspendedUnsuspendedToConsumer: randomValue, // 16 - newEserviceTemplateVersionToInstantiator: randomValue, // 17 - eserviceTemplateNameChangedToInstantiator: randomValue, //18 - eserviceTemplateStatusChangedToInstantiator: randomValue, // 19 - delegationApprovedRejectedToDelegator: randomValue, // 20 - eserviceNewVersionSubmittedToDelegator: randomValue, // 21 - eserviceNewVersionApprovedRejectedToDelegate: randomValue, // 22 - delegationSubmittedRevokedToDelegate: randomValue, // 23 - certifiedVerifiedAttributeAssignedRevokedToAssignee: randomValue, // 24 - clientKeyAddedDeletedToClientUsers: randomValue, // 25 - } -} +// DELETE THIS +// agreementSuspendedUnsuspendedToProducer: randomValue, // 04 +// agreementManagementToProducer: randomValue, // 03 +// clientAddedRemovedToProducer: randomValue, // 05 +// purposeStatusChangedToProducer: randomValue, // 07 +// templateStatusChangedToProducer: randomValue, //09 +// agreementSuspendedUnsuspendedToConsumer: randomValue, // 13 +// eserviceStateChangedToConsumer: randomValue, // 11 +// agreementActivatedRejectedToConsumer: randomValue, // 12 +// purposeActivatedRejectedToConsumer: randomValue, // 15 +// purposeSuspendedUnsuspendedToConsumer: randomValue, // 16 +// newEserviceTemplateVersionToInstantiator: randomValue, // 17 +// eserviceTemplateNameChangedToInstantiator: randomValue, //18 +// eserviceTemplateStatusChangedToInstantiator: randomValue, // 19 +// delegationApprovedRejectedToDelegator: randomValue, // 20 +// eserviceNewVersionSubmittedToDelegator: randomValue, // 21 +// eserviceNewVersionApprovedRejectedToDelegate: randomValue, // 22 +// delegationSubmittedRevokedToDelegate: randomValue, // 23 +// certifiedVerifiedAttributeAssignedRevokedToAssignee: randomValue, // 24 +// clientKeyAddedDeletedToClientUsers: randomValue, // 25 diff --git a/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx b/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx index 7f898fd12..6a67008e9 100644 --- a/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx +++ b/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx @@ -7,13 +7,20 @@ import { AuthHooks } from '@/api/auth' import { UpdatePartyMailDrawer } from './UpdatePartyMailDrawer' import EditIcon from '@mui/icons-material/Edit' import { TenantHooks } from '@/api/tenant' +import { NotificationMutations, NotificationQueries } from '@/api/notification' +import { useQuery } from '@tanstack/react-query' export const PartyContactsSection: React.FC = () => { const { t } = useTranslation('party', { keyPrefix: 'contacts' }) const { t: tCommon } = useTranslation('common') + const { t: tNotification } = useTranslation('notification', { keyPrefix: 'tenantPage' }) + const { isAdmin } = AuthHooks.useJwt() const { data: user } = TenantHooks.useGetActiveUserParty() + const { data: tenantEmailNotifictionConfigs } = useQuery({ + ...NotificationQueries.getTenantNotificationConfigs(), + }) const email = user.contactMail const [isDrawerOpen, setIsDrawerOpen] = React.useState(false) @@ -47,13 +54,27 @@ export const PartyContactsSection: React.FC = () => { > + + - +
diff --git a/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx b/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx index cf6fab062..6e8f11726 100644 --- a/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx +++ b/src/pages/PartyRegistryPage/components/PartyContactsSection/UpdatePartyMailDrawer.tsx @@ -1,5 +1,6 @@ import type { Mail } from '@/api/api.generatedTypes' import { AuthHooks } from '@/api/auth' +import { NotificationMutations } from '@/api/notification' import { TenantMutations } from '@/api/tenant' import { Drawer } from '@/components/shared/Drawer' import { @@ -17,28 +18,34 @@ import { useTranslation } from 'react-i18next' type UpdatePartyMailFormValues = { contactEmail: string description: string + enabledTenantNotificationConfigEmail: boolean } type UpdatePartyMailDrawerProps = { isOpen: boolean onClose: VoidFunction email?: Mail + enabledTenantNotificationConfigEmail?: boolean } export const UpdatePartyMailDrawer: React.FC = ({ isOpen, onClose, email, + enabledTenantNotificationConfigEmail, }) => { const { t } = useTranslation('party', { keyPrefix: 'contacts' }) const { t: tCommon } = useTranslation('common') const { jwt, currentRoles } = AuthHooks.useJwt() const { mutateAsync: updateMail } = TenantMutations.useUpdateMail() + const { mutate: updateNotificationTenantConfigs } = + NotificationMutations.useUpdateNotificationTenantConfigs() const defaultValues = { contactEmail: email?.address ?? '', description: email?.description ?? '', + enabledTenantNotificationConfigEmail: enabledTenantNotificationConfigEmail ?? false, } const formMethods = useForm({ defaultValues }) @@ -60,6 +67,10 @@ export const UpdatePartyMailDrawer: React.FC = ({ }, { onSuccess() { + console.log('invio il valore di notifica:', values.enabledTenantNotificationConfigEmail) + updateNotificationTenantConfigs({ + enabled: values.enabledTenantNotificationConfigEmail, + }) onClose() }, } @@ -123,7 +134,7 @@ export const UpdatePartyMailDrawer: React.FC = ({ Date: Tue, 23 Sep 2025 10:32:54 +0200 Subject: [PATCH 31/53] test: added several test --- src/api/notification/notification.services.ts | 2 - .../NotificationUserConfig.page.tsx | 4 +- .../NotificationConfigSection.test.tsx | 39 ++++---- .../NotificationConfigUserTab.test.tsx | 96 ++++++++++++------- .../components/NotificationConfigSection.tsx | 1 + .../components/NotificationUserConfigTab.tsx | 18 +++- .../hooks/useNotificationInAppConfigForm.ts | 28 +++--- src/utils/testing.utils.tsx | 15 +++ 8 files changed, 131 insertions(+), 72 deletions(-) diff --git a/src/api/notification/notification.services.ts b/src/api/notification/notification.services.ts index d7c0a4e47..d3c88047c 100644 --- a/src/api/notification/notification.services.ts +++ b/src/api/notification/notification.services.ts @@ -1,7 +1,6 @@ import axiosInstance from '@/config/axios' import { BACKEND_FOR_FRONTEND_URL } from '@/config/env' import type { - NotificationConfig, TenantNotificationConfig, TenantNotificationConfigUpdateSeed, UserNotificationConfig, @@ -16,7 +15,6 @@ async function updateUserNotificationConfigs(payload: UserNotificationConfigUpda } async function updateTenantNotificationConfigs(payload: TenantNotificationConfigUpdateSeed) { - console.log('payload', payload) return await axiosInstance.post( `${BACKEND_FOR_FRONTEND_URL}/tenantNotificationConfigs`, payload diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 1f4cc7986..9b2425b4a 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -6,7 +6,7 @@ import { Tab } from '@mui/material' import { NotificationConfigUserTab } from './components/NotificationUserConfigTab' import { useTranslation } from 'react-i18next' import { NotificationMutations, NotificationQueries } from '@/api/notification' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useSuspenseQuery } from '@tanstack/react-query' import { match } from 'ts-pattern' import { type NotificationConfig, @@ -41,7 +41,7 @@ const NotificationUserConfigTabs: React.FC<{ }> = ({ activeTab, updateActiveTab }) => { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) - const { data } = useQuery({ + const { data } = useSuspenseQuery({ ...NotificationQueries.getUserNotificationConfigs(), }) diff --git a/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx index 685734a14..6318a4091 100644 --- a/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx +++ b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigSection.test.tsx @@ -1,24 +1,32 @@ -import { renderWithApplicationContext } from '@/utils/testing.utils' +import { + mockUseJwt, + ReactHookFormWrapper, + renderWithApplicationContext, +} from '@/utils/testing.utils' import { NotificationConfigSection } from '../components/NotificationConfigSection' import { screen } from '@testing-library/react' +mockUseJwt({ currentRoles: ['admin'] }) + describe('NotificationConfigSection', () => { beforeEach(() => { renderWithApplicationContext( - , + + + , { withRouterContext: true, withReactQueryContext: true } ) }) @@ -32,7 +40,6 @@ describe('NotificationConfigSection', () => { const switchTitle = screen.getByText('firstSwitchTitle') expect(switchTitle).toBeInTheDocument() - screen.debug() const switchDescription = screen.getByText('firstSwitchDescription') expect(switchDescription).toBeInTheDocument() }) diff --git a/src/pages/NotificationUserConfigPage/__test__/NotificationConfigUserTab.test.tsx b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigUserTab.test.tsx index 63857c458..c998998f4 100644 --- a/src/pages/NotificationUserConfigPage/__test__/NotificationConfigUserTab.test.tsx +++ b/src/pages/NotificationUserConfigPage/__test__/NotificationConfigUserTab.test.tsx @@ -1,9 +1,10 @@ import { mockUseJwt, renderWithApplicationContext } from '@/utils/testing.utils' -import { fireEvent, screen, waitFor } from '@testing-library/react' +import { cleanup, fireEvent, screen, within } from '@testing-library/react' import { NotificationConfigUserTab } from '../components/NotificationUserConfigTab' import { type NotificationConfig } from '@/api/api.generatedTypes' +import { type NotificationConfigType } from '../types' -mockUseJwt() +mockUseJwt({ currentRoles: ['admin'] }) const inAppNotificationConfigMock: NotificationConfig = { agreementSuspendedUnsuspendedToProducer: true, // 04 @@ -28,11 +29,11 @@ const inAppNotificationConfigMock: NotificationConfig = { } describe('InAppNotificationUserconfigTab', () => { - beforeEach(() => { + const renderComponent = (type: NotificationConfigType, ovverideNotificationConfig = {}) => { renderWithApplicationContext( , { @@ -40,43 +41,70 @@ describe('InAppNotificationUserconfigTab', () => { withReactQueryContext: true, } ) - }) + } - it('Should not be se to user email into "inApp" tab', () => { - const mailLabel = screen.queryByTestId('mailLabel') - expect(mailLabel).not.toBeInTheDocument() - }) - it('Should not able to see all sections if main switch is off', () => { - const mainSwitch = screen.getByTestId('enableAllNotification') - expect(mainSwitch).toBeInTheDocument() + describe('inApp', () => { + beforeEach(() => { + renderComponent('inApp') + }) - const allSections = screen.queryAllByTestId(/config-section-/) - expect(allSections).toHaveLength(0) - }) + it('Should not be se to user email into "inApp" tab', () => { + const mailLabel = screen.queryByTestId('mailLabel') + expect(mailLabel).not.toBeInTheDocument() + }) + + it.skip('Should not able to see all sections if main switch is off', () => { + const mainSwitch = screen.getByTestId('enableAllNotification') + expect(mainSwitch).toBeInTheDocument() + + const allSections = screen.queryAllByTestId(/config-section-/) + expect(allSections).toHaveLength(0) + }) - it('Shold be able to see all sections if main switch is on', async () => { - const mainSwitch = screen.getByTestId('enableAllNotification') - expect(mainSwitch).toBeInTheDocument() + it('Should be able to see four sections [consumer,provider,delegator,keys&Attributes] if main switch is on', () => { + expect(screen.getByTestId('config-section-subscriber')).toBeInTheDocument() + expect(screen.getByTestId('config-section-provider')).toBeInTheDocument() + expect(screen.getByTestId('config-section-delegations')).toBeInTheDocument() + expect(screen.getByTestId('config-section-keyAndAttributes')).toBeInTheDocument() + }) + + it('Should be able to turn on all switch for [subscriber] section if click on "enable all" for a section"', async () => { + cleanup() + + renderComponent('inApp', { + certifiedVerifiedAttributeAssignedRevokedToAssignee: false, + clientKeyAddedDeletedToClientUsers: false, + }) + // To test this will be tested keyAndAttributes section with key: [certifiedVerifiedAttributeAssignedRevokedToAssignee,clientKeyAddedDeletedToClientUsers] + + const firstKey = screen.getByTestId('certifiedVerifiedAttributeAssignedRevokedToAssignee') + const secondKey = screen.getByTestId('clientKeyAddedDeletedToClientUsers') + const enableAllSectionButton = screen.getByTestId( + 'enableSectionAllNotifications-keyAndAttributes' + ) - fireEvent.click(mainSwitch) - const allSections = screen.getAllByTestId(/config-section-/) + expect(firstKey).toBeInTheDocument() + expect(secondKey).toBeInTheDocument() + expect(firstKey).not.toBeChecked() + expect(secondKey).not.toBeChecked() - expect(allSections).toHaveLength(4) + screen.debug(firstKey) + + expect( + within(enableAllSectionButton).getByText('enableSectionAllNotifications') + ).toBeInTheDocument() + + fireEvent.click(enableAllSectionButton) + // Expect that after click enableSectionall button all switch will be checked and appear disable button + expect( + within(enableAllSectionButton).queryByText('disableSectionAllNotifications') + ).toBeInTheDocument() + }) }) - describe.only('mail tab', () => { + describe('mail', () => { beforeEach(() => { - renderWithApplicationContext( - , - { - withRouterContext: true, - withReactQueryContext: true, - } - ) + renderComponent('email') }) it('Should be able to see user email', () => { diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx index 633469d86..792418bf3 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSection.tsx @@ -24,6 +24,7 @@ export const NotificationConfigSection: React.FC currentRoles.some((item) => component.visibility.includes(item)) && ( const onClickEnableAllSectionSwitch = (sectionName: string, value: boolean) => { sectionComponentKeysMap[sectionName].map((inAppConfigKey: string) => { - formMethods.setValue(inAppConfigKey as keyof NotificationConfig, value) + formMethods.setValue(inAppConfigKey as keyof NotificationConfig, value, { + shouldDirty: true, + }) }) } @@ -166,6 +168,7 @@ export const NotificationConfigUserTab: React.FC {isEnabledShowPreferencesSwitch() && Object.keys(notificationSchema).map((sectionName) => { const isAllSwitchWithinSectionDisabled = getSwitchBySections(sectionName).length <= 0 + return ( @@ -183,6 +186,7 @@ export const NotificationConfigUserTab: React.FC
+ + + {subsections.map((subsection: NotificationSubSectionSchema) => { + return ( + + ) + })} + + ) } diff --git a/src/pages/NotificationUserConfigPage/components/NotificationConfigSubSection.tsx b/src/pages/NotificationUserConfigPage/components/NotificationConfigSubSection.tsx new file mode 100644 index 000000000..fd7ef2374 --- /dev/null +++ b/src/pages/NotificationUserConfigPage/components/NotificationConfigSubSection.tsx @@ -0,0 +1,42 @@ +import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' +import { Box } from '@mui/system' +import { Typography } from '@mui/material' +import { AuthHooks } from '@/api/auth' +import type { NotificationSubSectionSchema } from '../types' + +type NotificationConfigSubSectionProps = { + subsection: NotificationSubSectionSchema +} +export const NotificationConfigSubSection: React.FC = ({ + subsection, +}) => { + const { currentRoles } = AuthHooks.useJwt() + + return ( + <> + + {subsection.title} + + + {subsection.components.map( + (component) => + // is currentRoles authorized to show the switch ? + currentRoles.some((item) => component.visibility.includes(item)) && ( + + } + /> + ) + )} + + + ) +} diff --git a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx index 65c431c9c..02e3d6c8b 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx @@ -1,14 +1,10 @@ import React, { useEffect } from 'react' import { Controller, FormProvider, useForm } from 'react-hook-form' -import { NotificationConfigSection } from './NotificationConfigSection' import { SectionContainer } from '@/components/layout/containers' import { Box, - Card, - Link, Stack, Typography, - Button, FormControl, InputLabel, MenuItem, @@ -20,13 +16,10 @@ import { useTranslation } from 'react-i18next' import { useNotificationConfigHook } from '../hooks/useNotificationConfigHook' import { type NotificationConfig } from '@/api/api.generatedTypes' import { debounce } from 'lodash' -import type { - NotificationSubSectionSchema, - NotificationConfigType, - NotificationPreferenceChoiceType, -} from '../types' +import type { NotificationConfigType, NotificationPreferenceChoiceType } from '../types' import { match } from 'ts-pattern' import { AuthHooks } from '@/api/auth' +import { NotificationConfigSection } from './NotificationConfigSection' type NotificationConfigFormValues = NotificationConfig & { preferenceChoice: NotificationPreferenceChoiceType @@ -198,54 +191,16 @@ export const NotificationConfigUserTab: React.FC {isEnabledShowPreferencesSwitch() && Object.keys(notificationSchema).map((sectionName) => { const isAllSwitchWithinSectionDisabled = getSwitchBySections(sectionName).length <= 0 - const SectionIcon = notificationSchema[sectionName].icon return ( - - - - - - - {notificationSchema[sectionName].title} - - - - - - {notificationSchema[sectionName].subsections.map( - (subsection: NotificationSubSectionSchema) => { - return ( - - ) - } - )} - - + ) })} From f07e590cf3c5ec1c023d534018aad3e36fdf43a3 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Dec 2025 11:12:36 +0100 Subject: [PATCH 48/53] refactor: add useNotificationConfigForm --- .../NotificationUserConfig.page.tsx | 32 ---- .../components/NotificationUserConfigTab.tsx | 160 +++++++++--------- ...k.ts => useGetNotificationConfigSchema.ts} | 2 +- .../hooks/useNotificationConfigForm.ts | 64 +++++++ 4 files changed, 146 insertions(+), 112 deletions(-) rename src/pages/NotificationUserConfigPage/hooks/{useNotificationConfigHook.ts => useGetNotificationConfigSchema.ts} (99%) create mode 100644 src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 3fdfdcf69..879b47c50 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -47,38 +47,6 @@ const NotificationUserConfigTabs: React.FC<{ const { mutate: updateUserNotificationConfigs } = NotificationMutations.useUpdateNotificationUserConfigs() - // const handleUpdate = ( - // notificationConfig: NotificationConfig, - // type: NotificationConfigType, - // preferenceChoice: - // | UserNotificationConfig['emailNotificationPreference'] - // | UserNotificationConfig['inAppNotificationPreference'] - // ) => { - // const unnecessaryKeys = ['preferenceChoice'] - // const removeUnnecessaryKeys = (config: NotificationConfig) => { - // return Object.fromEntries( - // Object.entries(config).filter(([key]) => !unnecessaryKeys.includes(key)) - // ) as NotificationConfig - // } - - // const notificationConfigSeed = match(type) - // .with('inApp', () => ({ - // inAppNotificationPreference: preferenceChoice, - // inAppConfig: removeUnnecessaryKeys(notificationConfig), - // emailNotificationPreference: data?.emailNotificationPreference, - // emailConfig: data?.emailConfig, - // })) - // .with('email', () => ({ - // inAppNotificationPreference: data?.inAppNotificationPreference, - // inAppConfig: data?.inAppConfig, - // emailConfig: removeUnnecessaryKeys(notificationConfig), - // emailNotificationPreference: preferenceChoice, - // })) - // .exhaustive() - - // updateUserNotificationConfigs(notificationConfigSeed) - // } - const handleUpdateNotificationConfigEmail = ( notificationConfig: NotificationConfig, preferenceChoice: UserNotificationConfig['emailNotificationPreference'] diff --git a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx index 02e3d6c8b..bdf0eed51 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx @@ -1,5 +1,6 @@ -import React, { useEffect } from 'react' -import { Controller, FormProvider, useForm } from 'react-hook-form' +import React from 'react' +import type { UseFormReturn } from 'react-hook-form' +import { Controller, FormProvider } from 'react-hook-form' import { SectionContainer } from '@/components/layout/containers' import { Box, @@ -13,13 +14,13 @@ import { } from '@mui/material' import { RHFSwitch, SwitchLabelDescription } from '@/components/shared/react-hook-form-inputs' import { useTranslation } from 'react-i18next' -import { useNotificationConfigHook } from '../hooks/useNotificationConfigHook' +import { useGetNotificationConfigSchema } from '../hooks/useGetNotificationConfigSchema' import { type NotificationConfig } from '@/api/api.generatedTypes' -import { debounce } from 'lodash' import type { NotificationConfigType, NotificationPreferenceChoiceType } from '../types' import { match } from 'ts-pattern' import { AuthHooks } from '@/api/auth' import { NotificationConfigSection } from './NotificationConfigSection' +import { useNotificationConfigForm } from '../hooks/useNotificationConfigForm' type NotificationConfigFormValues = NotificationConfig & { preferenceChoice: NotificationPreferenceChoiceType @@ -41,38 +42,15 @@ export const NotificationConfigUserTab: React.FC }) => { const { t: tConfiguration } = useTranslation('notification', { keyPrefix: 'configurationPage' }) const { t } = useTranslation('notification', { keyPrefix: `configurationPage.${type}` }) - - const { notificationSchema, sectionComponentKeysMap } = useNotificationConfigHook(type) const { userEmail } = AuthHooks.useJwt() - const formMethods = useForm< - NotificationConfig & { - preferenceChoice: NotificationPreferenceChoiceType - } - >({ - defaultValues: { ...notificationConfig, preferenceChoice: notificationConfig.preferenceChoice }, + const { formMethods, preferenceChoice, valueChanged } = useNotificationConfigForm({ + handleUpdateNotificationConfigs, + notificationConfig, + type, }) - const valueChanged = formMethods.watch() - const preferenceChoice = formMethods.getValues('preferenceChoice') - - const debouncedUpdate = React.useMemo( - () => - debounce((data: NotificationConfigFormValues) => { - const preferenceChoice = formMethods.getValues('preferenceChoice') - handleUpdateNotificationConfigs(data, type, preferenceChoice) - }, 1000), - [handleUpdateNotificationConfigs, formMethods, type] - ) - useEffect(() => { - const subscription = formMethods.watch((value) => { - debouncedUpdate(value as NotificationConfigFormValues) - }) - - return () => { - subscription.unsubscribe() - } - }, [formMethods, formMethods.watch, formMethods.formState.isDirty, debouncedUpdate]) + const { notificationSchema, sectionComponentKeysMap } = useGetNotificationConfigSchema(type) const onClickEnableAllSectionSwitch = (sectionName: string, value: boolean) => { sectionComponentKeysMap[sectionName].forEach((inAppConfigKey: string) => { @@ -99,27 +77,57 @@ export const NotificationConfigUserTab: React.FC .exhaustive() } - const InAppConfigHeader = () => ( - <> - {/* Need to understand whats the link should point to */} - {/* - {t('manualLinkLabel')} - */} - - - } - /> - - + return ( + + + {type === 'email' ? ( + + ) : ( + + )} + {preferenceChoice !== 'DIGEST' && ( + + {tConfiguration('infoAlert')} + + )} + + {isEnabledShowPreferencesSwitch() && + Object.keys(notificationSchema).map((sectionName) => { + const isAllSwitchWithinSectionDisabled = getSwitchBySections(sectionName).length <= 0 + + return ( + + ) + })} + + + ) +} - const EmailConfigHeader = () => ( +type EmailConfigHeaderProps = { + userEmail: string | undefined + formMethods: UseFormReturn + preferenceChoice: NotificationPreferenceChoiceType +} +const EmailConfigHeader = ({ + userEmail, + formMethods, + preferenceChoice, +}: EmailConfigHeaderProps) => { + const { t } = useTranslation('notification', { keyPrefix: `configurationPage.email` }) + return ( <> Indirizzo email @@ -148,7 +156,8 @@ export const NotificationConfigUserTab: React.FC )} /> - {/* )} ) +} +const InAppConfigHeader = () => { + const { t } = useTranslation('notification', { keyPrefix: `configurationPage.inApp` }) return ( - - - {type === 'email' ? : } - {preferenceChoice !== 'DIGEST' && ( - - {tConfiguration('infoAlert')} - - )} - - {isEnabledShowPreferencesSwitch() && - Object.keys(notificationSchema).map((sectionName) => { - const isAllSwitchWithinSectionDisabled = getSwitchBySections(sectionName).length <= 0 - - return ( - - ) - })} - - - + <> + {/* Need to understand whats the link should point to */} + {/* + {t('manualLinkLabel')} + */} + + + } + /> + + ) } diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigHook.ts b/src/pages/NotificationUserConfigPage/hooks/useGetNotificationConfigSchema.ts similarity index 99% rename from src/pages/NotificationUserConfigPage/hooks/useNotificationConfigHook.ts rename to src/pages/NotificationUserConfigPage/hooks/useGetNotificationConfigSchema.ts index a787c6d76..8058b3f2f 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigHook.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useGetNotificationConfigSchema.ts @@ -6,7 +6,7 @@ import React from 'react' import { ConsumerIcon, ProviderIcon, MyTenantIcon } from '@/icons' import CodeIcon from '@mui/icons-material/Code' -export function useNotificationConfigHook(type: NotificationConfigType) { +export function useGetNotificationConfigSchema(type: NotificationConfigType) { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage.sections' }) const notificationConfigSchema: NotificationConfigSchema = { diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts new file mode 100644 index 000000000..016e47763 --- /dev/null +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts @@ -0,0 +1,64 @@ +import React, { useEffect, useMemo } from 'react' +import type { UseFormReturn } from 'react-hook-form' +import { useForm } from 'react-hook-form' +import { debounce } from 'lodash' +import type { NotificationConfigType, NotificationPreferenceChoiceType } from '../types' +import { type NotificationConfig } from '@/api/api.generatedTypes' + +type NotificationConfigFormValues = NotificationConfig & { + preferenceChoice: NotificationPreferenceChoiceType +} + +type UseNotificationConfigFormProps = { + notificationConfig: NotificationConfigFormValues + handleUpdateNotificationConfigs: ( + notificationConfig: NotificationConfig, + type: NotificationConfigType, + preferenceChoice: NotificationPreferenceChoiceType + ) => void + type: NotificationConfigType +} + +type UseNotificationConfigFormReturn = { + formMethods: UseFormReturn + preferenceChoice: NotificationPreferenceChoiceType + valueChanged: NotificationConfigFormValues +} + +export const useNotificationConfigForm = ({ + notificationConfig, + handleUpdateNotificationConfigs, + type, +}: UseNotificationConfigFormProps): UseNotificationConfigFormReturn => { + const formMethods = useForm({ + defaultValues: { ...notificationConfig, preferenceChoice: notificationConfig.preferenceChoice }, + }) + + const valueChanged = formMethods.watch() + const preferenceChoice = formMethods.getValues('preferenceChoice') + + const debouncedUpdate = useMemo( + () => + debounce((data: NotificationConfigFormValues) => { + const currentPreferenceChoice = formMethods.getValues('preferenceChoice') + handleUpdateNotificationConfigs(data, type, currentPreferenceChoice) + }, 1000), + [handleUpdateNotificationConfigs, formMethods, type] + ) + + useEffect(() => { + const subscription = formMethods.watch((value) => { + debouncedUpdate(value as NotificationConfigFormValues) + }) + + return () => { + subscription.unsubscribe() + } + }, [formMethods, debouncedUpdate]) + + return { + formMethods, + preferenceChoice, + valueChanged, + } +} From 7ab80b5ed067a2550685b7a1fc1dfcc31cca100c Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Dec 2025 11:24:08 +0100 Subject: [PATCH 49/53] fix : minor refactor fix --- .../components/NotificationUserConfigTab.tsx | 20 +++++++------------ .../hooks/useNotificationConfigForm.ts | 15 ++++---------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx index bdf0eed51..492483680 100644 --- a/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx +++ b/src/pages/NotificationUserConfigPage/components/NotificationUserConfigTab.tsx @@ -44,7 +44,7 @@ export const NotificationConfigUserTab: React.FC const { t } = useTranslation('notification', { keyPrefix: `configurationPage.${type}` }) const { userEmail } = AuthHooks.useJwt() - const { formMethods, preferenceChoice, valueChanged } = useNotificationConfigForm({ + const { formMethods, preferenceChoice, valuesChanged } = useNotificationConfigForm({ handleUpdateNotificationConfigs, notificationConfig, type, @@ -62,20 +62,14 @@ export const NotificationConfigUserTab: React.FC const getSwitchBySections = (sectionName: string) => { return sectionComponentKeysMap[sectionName].filter( - (item) => !valueChanged[item as keyof NotificationConfig] + (item) => !valuesChanged[item as keyof NotificationConfig] ) } - const isEnabledShowPreferencesSwitch = (): boolean => { - return match(type) - .with('email', () => { - return preferenceChoice === 'ENABLED' - }) - .with('inApp', () => { - return !!preferenceChoice - }) - .exhaustive() - } + const isEnabledShowPreferencesSwitch = match(type) + .with('email', () => preferenceChoice === 'ENABLED') + .with('inApp', () => !!preferenceChoice) + .exhaustive() return ( @@ -95,7 +89,7 @@ export const NotificationConfigUserTab: React.FC )} - {isEnabledShowPreferencesSwitch() && + {isEnabledShowPreferencesSwitch && Object.keys(notificationSchema).map((sectionName) => { const isAllSwitchWithinSectionDisabled = getSwitchBySections(sectionName).length <= 0 diff --git a/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts b/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts index 016e47763..1d4243f21 100644 --- a/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts +++ b/src/pages/NotificationUserConfigPage/hooks/useNotificationConfigForm.ts @@ -1,5 +1,4 @@ -import React, { useEffect, useMemo } from 'react' -import type { UseFormReturn } from 'react-hook-form' +import { useEffect, useMemo } from 'react' import { useForm } from 'react-hook-form' import { debounce } from 'lodash' import type { NotificationConfigType, NotificationPreferenceChoiceType } from '../types' @@ -19,22 +18,16 @@ type UseNotificationConfigFormProps = { type: NotificationConfigType } -type UseNotificationConfigFormReturn = { - formMethods: UseFormReturn - preferenceChoice: NotificationPreferenceChoiceType - valueChanged: NotificationConfigFormValues -} - export const useNotificationConfigForm = ({ notificationConfig, handleUpdateNotificationConfigs, type, -}: UseNotificationConfigFormProps): UseNotificationConfigFormReturn => { +}: UseNotificationConfigFormProps) => { const formMethods = useForm({ defaultValues: { ...notificationConfig, preferenceChoice: notificationConfig.preferenceChoice }, }) - const valueChanged = formMethods.watch() + const valuesChanged = formMethods.watch() const preferenceChoice = formMethods.getValues('preferenceChoice') const debouncedUpdate = useMemo( @@ -59,6 +52,6 @@ export const useNotificationConfigForm = ({ return { formMethods, preferenceChoice, - valueChanged, + valuesChanged, } } From f0b51b9b961742ce4c14603e404f603646e695e8 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Dec 2025 11:31:36 +0100 Subject: [PATCH 50/53] fix: removed useless change --- src/api/auth/auth.utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/auth/auth.utils.ts b/src/api/auth/auth.utils.ts index bba5414c7..40f1fc3b5 100644 --- a/src/api/auth/auth.utils.ts +++ b/src/api/auth/auth.utils.ts @@ -11,7 +11,7 @@ export type ParsedJwt = ReturnType export const parseJwt = memoize((token: string | null | undefined) => { const jwt = token ? jwtDecode(token) : undefined const currentRoles = jwt ? jwt.organization.roles.map((r) => r.role) : [] - const isAdmin = currentRoles.length === 1 && currentRoles[0] === '' + const isAdmin = currentRoles.length === 1 && currentRoles[0] === 'admin' const isOperatorAPI = currentRoles.includes('api') const isOperatorSecurity = currentRoles.includes('security') const isSupport = currentRoles.includes('support') From 956241e1004fdcaa8a27bfaeebc80363367dd1da Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Dec 2025 11:38:54 +0100 Subject: [PATCH 51/53] refactor: update name and remove useless spread operator --- .../PartyContactsSection/PartyContactsSection.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx b/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx index 349c9aef8..24475d774 100644 --- a/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx +++ b/src/pages/PartyRegistryPage/components/PartyContactsSection/PartyContactsSection.tsx @@ -18,9 +18,9 @@ export const PartyContactsSection: React.FC = () => { const { isAdmin } = AuthHooks.useJwt() const { data: user } = TenantHooks.useGetActiveUserParty() - const { data: tenantEmailNotifictionConfigs } = useQuery({ - ...NotificationQueries.getTenantNotificationConfigs(), - }) + const { data: tenantEmailNotificationConfigs } = useQuery( + NotificationQueries.getTenantNotificationConfigs() + ) const email = user.contactMail const [isDrawerOpen, setIsDrawerOpen] = React.useState(false) @@ -57,7 +57,7 @@ export const PartyContactsSection: React.FC = () => { { isOpen={isDrawerOpen} onClose={onCloseDrawer} email={email} - enabledTenantNotificationConfigEmail={tenantEmailNotifictionConfigs?.enabled} + enabledTenantNotificationConfigEmail={tenantEmailNotificationConfigs?.enabled} /> From 273ae12c81bd969253a0299e9c0704e69c2e23b4 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Dec 2025 14:22:19 +0100 Subject: [PATCH 52/53] refactor: moved SwitchLabelDescription --- .../{react-hook-form-inputs => }/SwitchLabelDescription.tsx | 2 +- src/components/shared/react-hook-form-inputs/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/components/shared/{react-hook-form-inputs => }/SwitchLabelDescription.tsx (86%) diff --git a/src/components/shared/react-hook-form-inputs/SwitchLabelDescription.tsx b/src/components/shared/SwitchLabelDescription.tsx similarity index 86% rename from src/components/shared/react-hook-form-inputs/SwitchLabelDescription.tsx rename to src/components/shared/SwitchLabelDescription.tsx index d7f3645a4..2c12c7a1b 100644 --- a/src/components/shared/react-hook-form-inputs/SwitchLabelDescription.tsx +++ b/src/components/shared/SwitchLabelDescription.tsx @@ -15,7 +15,7 @@ export const SwitchLabelDescription: React.FC = ({ {label} - + {description} diff --git a/src/components/shared/react-hook-form-inputs/index.ts b/src/components/shared/react-hook-form-inputs/index.ts index 519230c3d..d00726a1a 100644 --- a/src/components/shared/react-hook-form-inputs/index.ts +++ b/src/components/shared/react-hook-form-inputs/index.ts @@ -5,5 +5,5 @@ export * from './RHFRadioGroup' export * from './RHFCheckboxGroup' export * from './RHFSingleFileInput' export * from './RHFCheckbox' -export * from './SwitchLabelDescription' +export * from '../SwitchLabelDescription' export * from './RHFSelect' From 7895e403e13901fd94c205c4dcb6fe75d902ea95 Mon Sep 17 00:00:00 2001 From: borgesis95 Date: Wed, 10 Dec 2025 14:51:11 +0100 Subject: [PATCH 53/53] fix: added skeleton within tab --- .../NotificationUserConfig.page.tsx | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx index 879b47c50..05468b638 100644 --- a/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx +++ b/src/pages/NotificationUserConfigPage/NotificationUserConfig.page.tsx @@ -6,7 +6,7 @@ import { Tab } from '@mui/material' import { NotificationConfigUserTab } from './components/NotificationUserConfigTab' import { useTranslation } from 'react-i18next' import { NotificationMutations, NotificationQueries } from '@/api/notification' -import { useSuspenseQuery } from '@tanstack/react-query' +import { useQuery } from '@tanstack/react-query' import type { UserNotificationConfig } from '@/api/api.generatedTypes' import { type NotificationConfig, @@ -27,9 +27,7 @@ const NotificationUserConfigPage: React.FC = () => { // to: '', // }} > - }> - - + ) } @@ -40,9 +38,7 @@ const NotificationUserConfigTabs: React.FC<{ }> = ({ activeTab, updateActiveTab }) => { const { t } = useTranslation('notification', { keyPrefix: 'configurationPage' }) - const { data } = useSuspenseQuery({ - ...NotificationQueries.getUserNotificationConfigs(), - }) + const { data, isFetching } = useQuery(NotificationQueries.getUserNotificationConfigs()) const { mutate: updateUserNotificationConfigs } = NotificationMutations.useUpdateNotificationUserConfigs() @@ -51,6 +47,7 @@ const NotificationUserConfigTabs: React.FC<{ notificationConfig: NotificationConfig, preferenceChoice: UserNotificationConfig['emailNotificationPreference'] ) => { + if (!data) return const emailConfigSeed = omit(notificationConfig, 'preferenceChoice') const notificationConfigSeed: UserNotificationConfigUpdateSeed = { inAppNotificationPreference: data?.inAppNotificationPreference, @@ -66,6 +63,7 @@ const NotificationUserConfigTabs: React.FC<{ notificationConfig: NotificationConfig, preferenceChoice: UserNotificationConfig['inAppNotificationPreference'] ) => { + if (!data) return const inAppConfigSeed = omit(notificationConfig, 'preferenceChoice') const notificationConfigSeed: UserNotificationConfigUpdateSeed = { @@ -85,9 +83,10 @@ const NotificationUserConfigTabs: React.FC<{ - {data && ( - <> - + <> + + {isFetching && } + {data && ( - - + )} + + + {isFetching && } + {data && ( - - - )} + )} + + ) }