diff --git a/.env.development.local b/.env.development.local index fb3866162..bbdb41bc5 100644 --- a/.env.development.local +++ b/.env.development.local @@ -37,4 +37,4 @@ REACT_APP_ONETRUST_DOMAIN_ID=a8f58d7a-7f6a-4fe6-ac02-f95bac3876d4-test REACT_APP_PAGOPA_HELP_EMAIL=assistenza@selfcare.it REACT_APP_OPERATOR_EMAIL_ADDRESSES='stefano.bafaro@pagopa.it;' -REACT_APP_JWT=DUMMY \ No newline at end of file +REACT_APP_JWT=DUMMY diff --git a/src/App.tsx b/src/App.tsx index 7de7bfcb4..c9c80d2b7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -356,6 +356,7 @@ const SecuredRoutes = withLogin( orgInfo.types.isEcIPA} > diff --git a/src/components/ProtectedRoute/ProtectedRoute.tsx b/src/components/ProtectedRoute/ProtectedRoute.tsx index fbc14a0aa..7a5b9e4ac 100644 --- a/src/components/ProtectedRoute/ProtectedRoute.tsx +++ b/src/components/ProtectedRoute/ProtectedRoute.tsx @@ -1,16 +1,18 @@ -import {Redirect} from 'react-router-dom'; +import { Redirect } from 'react-router-dom'; import ROUTES from '../../routes'; -import {usePermissions} from '../../hooks/usePermissions'; -import {PermissionName} from '../../model/RolePermission'; -import {useFlagValue} from '../../hooks/useFeatureFlags'; +import { usePermissions } from '../../hooks/usePermissions'; +import { PermissionName } from '../../model/RolePermission'; +import { useFlagValue } from '../../hooks/useFeatureFlags'; +import { OrgInfo, useOrganizationType } from '../../hooks/useOrganizationType'; type ProtectedRouteProps = { permission: PermissionName; flagValue?: string; + orgCheckCondition?: (orgInfo: OrgInfo) => boolean; children: JSX.Element; }; -export const ProtectedRoute = ({permission, flagValue = "", children}: ProtectedRouteProps) => { - const {userHasPermission} = usePermissions(); +export const ProtectedRoute = ({ permission, flagValue = "", orgCheckCondition = (_) => true, children }: ProtectedRouteProps) => { + const { userHasPermission } = usePermissions(); if (!userHasPermission(permission)) { console.error( 'Permission error - You do not have permission to perform this action -', @@ -18,10 +20,12 @@ export const ProtectedRoute = ({permission, flagValue = "", children}: Protected ); } + const { orgInfo } = useOrganizationType(); const featureIsEnabled = useFlagValue(flagValue) || flagValue === ""; - return featureIsEnabled && userHasPermission(permission) ? ( + const orgCheck = orgCheckCondition(orgInfo); + return featureIsEnabled && userHasPermission(permission) && orgCheck ? ( children ) : ( - + ); }; diff --git a/src/components/ProtectedRoute/__tests__/ProtectedRoute.test.tsx b/src/components/ProtectedRoute/__tests__/ProtectedRoute.test.tsx index 6333ef84d..a900fe08d 100644 --- a/src/components/ProtectedRoute/__tests__/ProtectedRoute.test.tsx +++ b/src/components/ProtectedRoute/__tests__/ProtectedRoute.test.tsx @@ -43,11 +43,13 @@ describe('ProtectedRoute component', () => { jest.spyOn(useFlagValue, 'useFlagValue').mockReturnValue(true); const {getByText} = render( +
Child Component
+
); const childComponent = screen.queryByText('Child Component'); @@ -61,11 +63,33 @@ describe('ProtectedRoute component', () => { jest.spyOn(useFlagValue, 'useFlagValue').mockReturnValue(false); const {getByText} = render( +
Child Component
+
+ ); + + const childComponent = screen.queryByText('Child Component'); + expect(childComponent).toBeNull(); + }); + + test("should not render children when org check fails", () => { + jest.spyOn(usePermissions, 'usePermissions').mockReturnValue({ + userHasPermission: (_) => true, + }); + jest.spyOn(useFlagValue, 'useFlagValue').mockReturnValue(true); + + render( + + + false}> +
Child Component
+
+
+
); const childComponent = screen.queryByText('Child Component'); diff --git a/src/components/SideMenu/SideMenu.tsx b/src/components/SideMenu/SideMenu.tsx index d4a381bea..f66e15006 100644 --- a/src/components/SideMenu/SideMenu.tsx +++ b/src/components/SideMenu/SideMenu.tsx @@ -25,6 +25,7 @@ import { usePermissions } from '../../hooks/usePermissions'; import { userIsPagopaOperator } from '../../hooks/useUserRole'; import { useFlagValue } from '../../hooks/useFeatureFlags'; import { useOrganizationType } from '../../hooks/useOrganizationType'; +import { ShowSettingsSection } from '../../pages/settings/utils'; import SidenavItem from './SidenavItem'; @@ -225,7 +226,7 @@ export default function SideMenu({ /> )} - { useFlagValue('settings-section') && orgInfo.types.isEcIPA &&( + {ShowSettingsSection(useFlagValue, userHasPermission, orgInfo) && ( Promise) => { export const useFlagValue = (name: string): boolean => { const featureFlags = useAppSelector(featureFlagsSelectors.selectFeatureFlags); - return featureFlags ? featureFlags![name] : false; + return featureFlags ? featureFlags[name] : false; }; diff --git a/src/model/RolePermission.ts b/src/model/RolePermission.ts index dca3d2752..2e00b8e50 100644 --- a/src/model/RolePermission.ts +++ b/src/model/RolePermission.ts @@ -152,9 +152,7 @@ export const permissions = { ROLE.EC_OPERATOR, ROLE.EC_DIRECT_ADMIN, ROLE.EC_DIRECT_OPERATOR, - ROLE.PT_UNSIGNED, ROLE.PT_EC_OPERATOR, - ROLE.PT_PSP_OPERATOR, ROLE.PT_PSPEC_OPERATOR, ROLE.PAGOPA_OPERATOR, ] diff --git a/src/pages/dashboard/DashboardPage.tsx b/src/pages/dashboard/DashboardPage.tsx index 3fa73ccce..214443b54 100644 --- a/src/pages/dashboard/DashboardPage.tsx +++ b/src/pages/dashboard/DashboardPage.tsx @@ -1,12 +1,15 @@ -import {Alert, AlertTitle, Box, Card, Grid, Link, Typography} from '@mui/material'; -import {TitleBox} from '@pagopa/selfcare-common-frontend'; -import {Trans, useTranslation} from 'react-i18next'; -import { useHistory} from 'react-router-dom'; +import { Alert, AlertTitle, Box, Card, Grid, Link, Typography } from '@mui/material'; +import { TitleBox } from '@pagopa/selfcare-common-frontend'; +import { Trans, useTranslation } from 'react-i18next'; +import { useHistory } from 'react-router-dom'; import SideMenuLayout from '../../components/SideMenu/SideMenuLayout'; -import {usePermissions} from '../../hooks/usePermissions'; -import {useAppSelector} from '../../redux/hooks'; -import {partiesSelectors} from '../../redux/slices/partiesSlice'; +import { usePermissions } from '../../hooks/usePermissions'; +import { useAppSelector } from '../../redux/hooks'; +import { partiesSelectors } from '../../redux/slices/partiesSlice'; import ROUTES from '../../routes'; +import { ShowSettingsSection } from '../settings/utils'; +import { useFlagValue } from '../../hooks/useFeatureFlags'; +import { useOrganizationType } from '../../hooks/useOrganizationType'; import DownloadSection from './components/DownloadSection'; import ECRegistrationData from './components/ECRegistrationData'; import NextSteps from './components/NextSteps'; @@ -15,11 +18,12 @@ import PSPRegistrationData from './components/PSPRegistrationData'; import PTRegistrationData from './components/PTRegistrationData'; const DashboardPage = () => { - const {t} = useTranslation(); + const { t } = useTranslation(); const history = useHistory(); const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); const signinData = useAppSelector(partiesSelectors.selectSigninData); - const {userHasPermission} = usePermissions(); + const { orgInfo, orgIsBrokerSigned } = useOrganizationType(); + const { userHasPermission } = usePermissions(); return ( { variantSubTitle="body1" /> {history.location.state && (history.location.state as any).alertSuccessMessage && ( - + {(history.location.state as any).alertSuccessMessage} )} - - - {t('dashboardPage.newServiceAlerts.RTP.title')} - {t('dashboardPage.newServiceAlerts.RTP.subtitle')} - + {t('dashboardPage.newServiceAlerts.RTP.title')} + {t('dashboardPage.newServiceAlerts.RTP.subtitle')} + - ), + service_link: ( + ), }} /> - + + )} - + {t('dashboardPage.registrationData.title')} {selectedParty?.institutionType === 'PSP' ? ( - + ) : selectedParty?.institutionType === 'PT' ? ( - + ) : ( - + )} @@ -72,7 +77,7 @@ const DashboardPage = () => { {selectedParty && userHasPermission('operation-table-read-write') && ( - + )} diff --git a/src/pages/settings/components/ServiceSettingsCard.tsx b/src/pages/settings/components/ServiceSettingsCard.tsx index 67b7a74fc..11ca444a0 100644 --- a/src/pages/settings/components/ServiceSettingsCard.tsx +++ b/src/pages/settings/components/ServiceSettingsCard.tsx @@ -25,7 +25,8 @@ import { useAppSelector } from '../../../redux/hooks'; import { partiesSelectors } from '../../../redux/slices/partiesSlice'; import { ServiceConsentResponse } from '../../../api/generated/portal/ServiceConsentResponse'; import { ServiceIdEnum } from '../../../api/generated/portal/ServiceConsentInfo'; -import { rtpServiceStartingTimestamp, URLS } from './utils'; +import { rtpServiceStartingTimestamp, URLS } from '../utils'; +import { useUserRole } from '../../../hooks/useUserRole'; export type ServiceInfo = { serviceId: ServiceIdEnum; @@ -88,6 +89,7 @@ const StatusChip = ({ serviceInfo }: ({ serviceInfo: ServiceInfo })) => { const ServiceButton = ({ serviceInfo, onClick }: ({ serviceInfo: ServiceInfo; onClick: () => void })) => { const { t } = useTranslation(); + const userRole = useUserRole(); if (serviceInfo.consent === ConsentEnum.OPT_IN) { return (); @@ -104,6 +107,7 @@ const ServiceButton = ({ serviceInfo, onClick }: ({ serviceInfo: ServiceInfo; on variant="contained" endIcon={} onClick={onClick} + disabled={!userRole.userIsAdmin} > {t(`serviceConsent.${serviceInfo.serviceId}.enableButtonText`)} ); @@ -118,6 +122,7 @@ const ServiceStatusChangeModal = ({ serviceInfo, modalOpenFlag, onModalStateChan const translationRootKey = `serviceConsent.${serviceId}.popups.${isServiceEnabled ? "disableService" : "enableService"}`; const setLoading = useLoading('PUT_CONSENT'); const selectedParty = useAppSelector(partiesSelectors.selectPartySelected); + const userRole = useUserRole(); const addError = useErrorDispatcher(); return ( } + disabled={!userRole.userIsAdmin} onClick={() => { setLoading(true); saveServiceConsent(selectedParty?.partyId || '', serviceId, ConsentEnum.OPT_OUT) @@ -179,6 +185,7 @@ const ServiceStatusChangeModal = ({ serviceInfo, modalOpenFlag, onModalStateChan