diff --git a/src/pages/ConsumerClientManagePage/ConsumerClientManage.page.tsx b/src/pages/ConsumerClientManagePage/ConsumerClientManage.page.tsx
index f5fb5bbac..052a12360 100644
--- a/src/pages/ConsumerClientManagePage/ConsumerClientManage.page.tsx
+++ b/src/pages/ConsumerClientManagePage/ConsumerClientManage.page.tsx
@@ -7,7 +7,6 @@ import { TabContext, TabList, TabPanel } from '@mui/lab'
import { Alert, Button, Grid, Link, Stack, Tab, Typography } from '@mui/material'
import React from 'react'
import { useTranslation } from 'react-i18next'
-import { VoucherInstructions } from './components/VoucherInstructions'
import { useClientKind } from '@/hooks/useClientKind'
import { ClientOperators } from './components/ClientOperators'
import { ClientPublicKeys } from './components/ClientPublicKeys'
@@ -19,12 +18,16 @@ import SyncIcon from '@mui/icons-material/Sync'
import { useDrawerState } from '@/hooks/useDrawerState'
import { SetClientAdminDrawer } from './components/SetClientAdminDrawer/SetClientAdminDrawer'
import { apiV2GuideLink } from '@/config/constants'
+import { useNavigate } from '@/router'
+import type { ActionItemButton } from '@/types/common.types'
const ConsumerClientManagePage: React.FC = () => {
const { t } = useTranslation('client', { keyPrefix: 'edit' })
+ const { t: tCommon } = useTranslation('common', { keyPrefix: 'actions' })
const { clientId } = useParams<'SUBSCRIBE_CLIENT_EDIT' | 'SUBSCRIBE_INTEROP_M2M_CLIENT_EDIT'>()
const clientKind = useClientKind()
- const { activeTab, updateActiveTab } = useActiveTab('voucher')
+ const { activeTab, updateActiveTab } = useActiveTab('clientOperators')
+ const navigate = useNavigate()
const { data: client, isLoading: isLoadingClient } = useQuery(ClientQueries.getSingle(clientId))
@@ -44,11 +47,18 @@ const ConsumerClientManagePage: React.FC = () => {
})
}
+ const voucherSimulationAction: ActionItemButton = {
+ action: () =>
+ navigate(clientKind === 'API' ? 'SIMULATE_GET_VOUCHER_API' : 'SIMULATE_GET_VOUCHER_CONSUMER'),
+ label: tCommon('simulateVoucher'),
+ variant: 'contained',
+ }
+
return (
{
)}
-
-
-
-
-
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsContext.tsx b/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsContext.tsx
deleted file mode 100644
index dbe91bd11..000000000
--- a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsContext.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import React from 'react'
-import { createContext } from '@/utils/common.utils'
-import noop from 'lodash/noop'
-import { useSearchParams } from 'react-router-dom'
-
-type VoucherInstructionsContextType = {
- selectedPurposeId: string | undefined
- selectedKeyId: string | undefined
- handleSelectedPurposeIdChange: (purpose: string) => void
- handleSelectedKeyIdChange: (key: string) => void
- clientId: string
- goToNextStep: VoidFunction
- goToPreviousStep: VoidFunction
-}
-
-const initialState: VoucherInstructionsContextType = {
- selectedPurposeId: undefined,
- selectedKeyId: undefined,
- handleSelectedPurposeIdChange: noop,
- handleSelectedKeyIdChange: noop,
- clientId: '',
- goToNextStep: noop,
- goToPreviousStep: noop,
-}
-
-const { useContext, Provider } = createContext(
- 'VoucherInstructionsContext',
- initialState
-)
-
-type VoucherInstructionsContextProviderProps = {
- children: React.ReactNode
- clientId: string
- goToNextStep: VoidFunction
- goToPreviousStep: VoidFunction
-}
-
-const VoucherInstructionsContextProvider: React.FC = ({
- children,
- clientId,
- goToNextStep,
- goToPreviousStep,
-}) => {
- const [searchParams, setSearchParams] = useSearchParams()
-
- const handleSelectedPurposeIdChange = React.useCallback(
- (purposeId: string) => {
- setSearchParams((prev) => {
- prev.set('purposeId', purposeId)
- return prev
- })
- },
- [setSearchParams]
- )
-
- const handleSelectedKeyIdChange = React.useCallback(
- (keyId: string) => {
- setSearchParams((prev) => {
- prev.set('keyId', keyId)
- return prev
- })
- },
- [setSearchParams]
- )
-
- const selectedPurposeId = searchParams.get('purposeId') || undefined
- const selectedKeyId = searchParams.get('keyId') || undefined
-
- const providerValue = React.useMemo(
- () => ({
- selectedPurposeId,
- handleSelectedPurposeIdChange,
- selectedKeyId,
- handleSelectedKeyIdChange,
- clientId,
- goToNextStep,
- goToPreviousStep,
- }),
- [
- selectedPurposeId,
- handleSelectedPurposeIdChange,
- selectedKeyId,
- handleSelectedKeyIdChange,
- clientId,
- goToNextStep,
- goToPreviousStep,
- ]
- )
-
- return {children}
-}
-
-export { useContext as useVoucherInstructionsContext, VoucherInstructionsContextProvider }
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1.tsx b/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1.tsx
deleted file mode 100644
index 233b6e24b..000000000
--- a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-import React from 'react'
-import { SectionContainer } from '@/components/layout/containers'
-import { useTranslation } from 'react-i18next'
-import { Alert, FormControl, InputLabel, MenuItem, Select } from '@mui/material'
-import { useVoucherInstructionsContext } from '../VoucherInstructionsContext'
-import { ClientQueries } from '@/api/client'
-import OpenInNewIcon from '@mui/icons-material/OpenInNew'
-import ApiIcon from '@mui/icons-material/Api'
-import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
-import { verifyVoucherGuideLink } from '@/config/constants'
-import { VoucherInstructionsStep1CurrentIdsDrawer } from './VoucherInstructionsStep1CurrentIdsDrawer'
-import { useDrawerState } from '@/hooks/useDrawerState'
-import { StepActions } from '@/components/shared/StepActions'
-import { useClientKind } from '@/hooks/useClientKind'
-import { useSuspenseQuery } from '@tanstack/react-query'
-
-export const VoucherInstructionsStep1: React.FC = () => {
- const { t } = useTranslation('voucher')
- const clientKind = useClientKind()
- const {
- clientId,
- selectedPurposeId,
- handleSelectedPurposeIdChange,
- handleSelectedKeyIdChange,
- selectedKeyId,
- goToNextStep,
- } = useVoucherInstructionsContext()
-
- const { isOpen, openDrawer, closeDrawer } = useDrawerState()
-
- const { data: clientKeys } = useSuspenseQuery(ClientQueries.getAllKeysList({ clientId }))
- const { data: client } = useSuspenseQuery(ClientQueries.getSingle(clientId))
-
- const purposeSelectLabelId = React.useId()
- const purposeSelectId = React.useId()
- const keySelectLabelId = React.useId()
- const keySelectId = React.useId()
-
- const purposes = client.purposes
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault()
- goToNextStep()
- }
-
- const canGoToNextStep =
- clientKind === 'CONSUMER' ? Boolean(selectedKeyId && selectedPurposeId) : Boolean(selectedKeyId)
-
- if (clientKind === 'CONSUMER' && purposes.length === 0) {
- return {t('noPurposesLabel')}
- }
-
- if (clientKeys.length === 0) {
- return {t('noKeysLabel')}
- }
-
- return (
- <>
-
-
- >
- )
-}
diff --git a/src/pages/ConsumerSimulateGetVoucherPage/ConsumerSimulateGetVoucherPage.page.tsx b/src/pages/ConsumerSimulateGetVoucherPage/ConsumerSimulateGetVoucherPage.page.tsx
new file mode 100644
index 000000000..4d50f3e1c
--- /dev/null
+++ b/src/pages/ConsumerSimulateGetVoucherPage/ConsumerSimulateGetVoucherPage.page.tsx
@@ -0,0 +1,15 @@
+import { PageContainer } from '@/components/layout/containers'
+import { useTranslation } from 'react-i18next'
+import { VoucherInstructions } from './components/VoucherInstructions'
+
+const ConsumerDebugVoucherPage: React.FC = () => {
+ const { t } = useTranslation('pages', { keyPrefix: 'consumerSimulateGetVoucher' })
+
+ return (
+
+
+
+ )
+}
+
+export default ConsumerDebugVoucherPage
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/ClientVoucherIntructionsPurposeSelect.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/ClientVoucherIntructionsPurposeSelect.tsx
similarity index 100%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/ClientVoucherIntructionsPurposeSelect.tsx
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/ClientVoucherIntructionsPurposeSelect.tsx
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/CodeSnippetPreview.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/CodeSnippetPreview.tsx
similarity index 100%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/CodeSnippetPreview.tsx
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/CodeSnippetPreview.tsx
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructions.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructions.tsx
similarity index 68%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructions.tsx
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructions.tsx
index 7eb7ef087..198e0161a 100644
--- a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructions.tsx
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructions.tsx
@@ -1,7 +1,6 @@
import React from 'react'
import { Stepper } from '@/components/shared/Stepper'
import { useActiveStep } from '@/hooks/useActiveStep'
-import { Grid } from '@mui/material'
import { useTranslation } from 'react-i18next'
import { useClientKind } from '@/hooks/useClientKind'
import { SectionContainerSkeleton } from '@/components/layout/containers'
@@ -11,13 +10,8 @@ import { VoucherInstructionsStep1 } from './VoucherInstructionsStep1'
import { VoucherInstructionsStep2 } from './VoucherInstructionsStep2'
import { VoucherInstructionsStep3 } from './VoucherInstructionsStep3'
import { VoucherInstructionsStep4 } from './VoucherInstructionsStep4'
-import { HeadSection } from '@/components/shared/HeadSection'
-interface VoucherInstructionsProps {
- clientId: string
-}
-
-export const VoucherInstructions: React.FC = ({ clientId }) => {
+export const VoucherInstructions: React.FC = () => {
const { t } = useTranslation('voucher')
const clientKind = useClientKind()
const { activeStep, forward, back } = useActiveStep()
@@ -38,23 +32,17 @@ export const VoucherInstructions: React.FC = ({ client
const contextProps = {
goToPreviousStep: back,
goToNextStep: forward,
- clientId,
}
return (
<>
-
-
-
-
- }
- >
-
-
-
-
+
+ }
+ >
+
+
>
)
diff --git a/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsContext.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsContext.tsx
new file mode 100644
index 000000000..e1edac28c
--- /dev/null
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsContext.tsx
@@ -0,0 +1,42 @@
+import React from 'react'
+import { createContext } from '@/utils/common.utils'
+import noop from 'lodash/noop'
+
+type VoucherInstructionsContextType = {
+ goToNextStep: VoidFunction
+ goToPreviousStep: VoidFunction
+}
+
+const initialState: VoucherInstructionsContextType = {
+ goToNextStep: noop,
+ goToPreviousStep: noop,
+}
+
+const { useContext, Provider } = createContext(
+ 'VoucherInstructionsContext',
+ initialState
+)
+
+type VoucherInstructionsContextProviderProps = {
+ children: React.ReactNode
+ goToNextStep: VoidFunction
+ goToPreviousStep: VoidFunction
+}
+
+const VoucherInstructionsContextProvider: React.FC = ({
+ children,
+ goToNextStep,
+ goToPreviousStep,
+}) => {
+ const providerValue = React.useMemo(
+ () => ({
+ goToNextStep,
+ goToPreviousStep,
+ }),
+ [goToNextStep, goToPreviousStep]
+ )
+
+ return {children}
+}
+
+export { useContext as useVoucherInstructionsContext, VoucherInstructionsContextProvider }
diff --git a/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1.tsx
new file mode 100644
index 000000000..74fcbb143
--- /dev/null
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1.tsx
@@ -0,0 +1,195 @@
+import React, { useEffect } from 'react'
+import { SectionContainer } from '@/components/layout/containers'
+import { useTranslation } from 'react-i18next'
+import { Alert, Box, FormControl } from '@mui/material'
+import { ClientQueries } from '@/api/client'
+import OpenInNewIcon from '@mui/icons-material/OpenInNew'
+import ApiIcon from '@mui/icons-material/Api'
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
+import { verifyVoucherGuideLink } from '@/config/constants'
+import { VoucherInstructionsStep1CurrentIdsDrawer } from './VoucherInstructionsStep1CurrentIdsDrawer'
+import { useDrawerState } from '@/hooks/useDrawerState'
+import { StepActions } from '@/components/shared/StepActions'
+import { useClientKind } from '@/hooks/useClientKind'
+import { useQuery } from '@tanstack/react-query'
+import { useAutocompleteTextInput } from '@pagopa/interop-fe-commons'
+import { useForm, FormProvider, type SubmitHandler } from 'react-hook-form'
+import { RHFAutocompleteSingle, RHFSelect } from '@/components/shared/react-hook-form-inputs'
+import { useVoucherInstructionsContext } from '../VoucherInstructionsContext'
+import { useSearchParams } from 'react-router-dom'
+
+interface VoucherInstructionsStep1Form {
+ clientId: string | null
+ purposeId: string | null
+ keyId: string | null
+}
+
+export const VoucherInstructionsStep1: React.FC = () => {
+ const { t } = useTranslation('voucher')
+ const clientKind = useClientKind()
+ const { goToNextStep } = useVoucherInstructionsContext()
+ const [searchParams, setSearchParams] = useSearchParams()
+
+ const formMethods = useForm({
+ defaultValues: {
+ clientId: searchParams.get('clientId'),
+ purposeId: searchParams.get('purposeId'),
+ keyId: searchParams.get('keyId'),
+ },
+ })
+
+ const { watch, handleSubmit, setValue } = formMethods
+
+ const clientId = watch('clientId') || ''
+ const purposeId = watch('purposeId') || ''
+ const keyId = watch('keyId')
+
+ const [clientSearch, setClientSearch] = useAutocompleteTextInput('')
+ const { isOpen, openDrawer, closeDrawer } = useDrawerState()
+
+ const { data: clients, isFetching: isFetchingClients } = useQuery({
+ ...ClientQueries.getList({
+ kind: clientKind,
+ q: clientSearch,
+ offset: 0,
+ limit: 50,
+ }),
+ })
+
+ const { data: clientKeys, isFetching: isFetchingKeys } = useQuery({
+ ...ClientQueries.getAllKeysList({ clientId }),
+ enabled: Boolean(clientId),
+ })
+
+ const { data: client, isFetching: isFetchingClient } = useQuery({
+ ...ClientQueries.getSingle(clientId),
+ enabled: Boolean(clientId),
+ })
+
+ const purposes = client?.purposes
+
+ const canGoToNextStep = clientKind === 'CONSUMER' ? Boolean(keyId && purposeId) : Boolean(keyId)
+
+ const options = React.useMemo(() => {
+ const results = clients?.results ?? []
+ return results.map((att) => ({
+ label: att.name,
+ value: att.id,
+ }))
+ }, [clients])
+
+ const onSubmit: SubmitHandler = (values) => {
+ if (clientKind === 'CONSUMER' && !Boolean(values.keyId && values.purposeId)) return
+
+ if (clientKind === 'API' && !Boolean(values.keyId)) return
+
+ setSearchParams((prev) => {
+ if (values.clientId) prev.set('clientId', values.clientId)
+ if (values.purposeId) prev.set('purposeId', values.purposeId)
+ if (values.keyId) prev.set('keyId', values.keyId)
+ return prev
+ })
+ goToNextStep()
+ }
+
+ /**
+ * Subscribes to the form values changes
+ * and updates the actual visible questions on values change.
+ */
+ useEffect(() => {
+ const subscription = watch((_, { name }) => {
+ if (name === 'clientId') {
+ setValue('purposeId', null)
+ setValue('keyId', null)
+ setSearchParams({})
+ }
+ })
+ return () => subscription.unsubscribe()
+ }, [watch, setValue, setSearchParams])
+
+ return (
+
+
+ ,
+ label: t('step1.goToTechnicalDocsLabel'),
+ href: verifyVoucherGuideLink,
+ target: '_blank',
+ },
+ {
+ startIcon: ,
+ label: t('step1.showCurrentSelectionIds'),
+ component: 'button',
+ type: 'button',
+ onClick: openDrawer,
+ },
+ ]}
+ >
+
+ setClientSearch(value)}
+ options={options}
+ loading={isFetchingClients}
+ />
+
+ {clientKind === 'CONSUMER' ? (
+ !clientId || purposes?.length || isFetchingClient ? (
+
+ ({
+ label: `${purpose.title} per ${purpose.eservice.name}`,
+ value: purpose.purposeId,
+ }))}
+ rules={{ required: true }}
+ disabled={!clientId || isFetchingClient}
+ />
+
+ ) : (
+
+ {t('noPurposesLabel')}
+
+ )
+ ) : null}
+ {!Boolean(clientId) || clientKeys?.length || isFetchingClient || isFetchingKeys ? (
+
+ ({ label: key.name, value: key.keyId }))}
+ rules={{ required: true }}
+ disabled={!clientKeys || isFetchingClients || isFetchingKeys || isFetchingClient}
+ />
+
+ ) : (
+
+ {t('noKeysLabel')}
+
+ )}
+
+ ,
+ }}
+ />
+
+
+
+ )
+}
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1CurrentIdsDrawer.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1CurrentIdsDrawer.tsx
similarity index 92%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1CurrentIdsDrawer.tsx
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1CurrentIdsDrawer.tsx
index b1d87c4c4..31cda6b1a 100644
--- a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1CurrentIdsDrawer.tsx
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/VoucherInstructionsStep1CurrentIdsDrawer.tsx
@@ -1,6 +1,5 @@
import { Drawer } from '@/components/shared/Drawer'
import React from 'react'
-import { useVoucherInstructionsContext } from '../VoucherInstructionsContext'
import { PurposeQueries } from '@/api/purpose'
import { InformationContainer } from '@pagopa/interop-fe-commons'
import { Trans, useTranslation } from 'react-i18next'
@@ -11,17 +10,18 @@ import { useQuery } from '@tanstack/react-query'
type VoucherInstructionsStep1CurrentIdsDrawerProps = {
isOpen: boolean
onClose: VoidFunction
+ clientId: string
+ purposeId: string
}
export const VoucherInstructionsStep1CurrentIdsDrawer: React.FC<
VoucherInstructionsStep1CurrentIdsDrawerProps
-> = ({ isOpen, onClose }) => {
+> = ({ isOpen, onClose, clientId, purposeId }) => {
const { t } = useTranslation('voucher', { keyPrefix: 'step1.currentIdsDrawer' })
- const { clientId, selectedPurposeId } = useVoucherInstructionsContext()
const { data: purpose } = useQuery({
- ...PurposeQueries.getSingle(selectedPurposeId!),
- enabled: Boolean(selectedPurposeId),
+ ...PurposeQueries.getSingle(purposeId || ''),
+ enabled: Boolean(purposeId),
})
return (
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/index.ts b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/index.ts
similarity index 100%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep1/index.ts
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep1/index.ts
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep2.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep2.tsx
similarity index 91%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep2.tsx
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep2.tsx
index 5eb981939..47639d409 100644
--- a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep2.tsx
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep2.tsx
@@ -10,6 +10,7 @@ import { InformationContainer } from '@pagopa/interop-fe-commons'
import { useVoucherInstructionsContext } from './VoucherInstructionsContext'
import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
+import { useSearchParams } from 'react-router-dom'
const CLIENT_ASSERTION_TYP = 'JWT'
const CLIENT_ASSERTION_ALG = 'RS256'
@@ -17,9 +18,13 @@ const CLIENT_ASSERTION_ALG = 'RS256'
export const VoucherInstructionsStep2: React.FC = () => {
const { t } = useTranslation('voucher')
const clientKind = useClientKind()
+ const [searchParams] = useSearchParams()
- const { selectedPurposeId, selectedKeyId, clientId, goToNextStep, goToPreviousStep } =
- useVoucherInstructionsContext()
+ const { goToNextStep, goToPreviousStep } = useVoucherInstructionsContext()
+
+ const clientId = searchParams.get('clientId') || ''
+ const purposeId = searchParams.get('purposeId') || ''
+ const keyId = searchParams.get('keyId') || ''
const filename =
clientKind === 'CONSUMER' ? 'create_client_assertion.py' : 'create_m2m_client_assertion.py'
@@ -49,9 +54,9 @@ export const VoucherInstructionsStep2: React.FC = () => {
@@ -107,13 +112,13 @@ export const VoucherInstructionsStep2: React.FC = () => {
tooltipTitle: t('step2.assertionPayload.audField.copySuccessFeedbackText'),
}}
/>
- {clientKind === 'CONSUMER' && selectedPurposeId && (
+ {clientKind === 'CONSUMER' && Boolean(purposeId) && (
@@ -170,13 +175,13 @@ export const VoucherInstructionsStep2: React.FC = () => {
},
]}
scriptSubstitutionValues={{
- INSERISCI_VALORE_KID: selectedKeyId!,
+ INSERISCI_VALORE_KID: keyId,
INSERISCI_VALORE_ALG: CLIENT_ASSERTION_ALG,
INSERISCI_VALORE_TYP: CLIENT_ASSERTION_TYP,
- INSERISCI_VALORE_ISS: clientId,
- INSERISCI_VALORE_SUB: clientId,
+ INSERISCI_VALORE_ISS: clientId!,
+ INSERISCI_VALORE_SUB: clientId!,
INSERISCI_VALORE_AUD: CLIENT_ASSERTION_JWT_AUDIENCE,
- INSERISCI_VALORE_PUR: selectedPurposeId ?? '',
+ INSERISCI_VALORE_PUR: purposeId,
}}
/>
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep3.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep3.tsx
similarity index 95%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep3.tsx
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep3.tsx
index 99d295f49..b18be04bb 100644
--- a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep3.tsx
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep3.tsx
@@ -11,6 +11,7 @@ import { Link } from '@/router'
import { useVoucherInstructionsContext } from './VoucherInstructionsContext'
import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
+import { useSearchParams } from 'react-router-dom'
const CLIENT_ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
const GRANT_TYPE = 'client_credentials'
@@ -18,8 +19,11 @@ const GRANT_TYPE = 'client_credentials'
export const VoucherInstructionsStep3: React.FC = () => {
const { t } = useTranslation('voucher')
const clientKind = useClientKind()
+ const [searchParams] = useSearchParams()
- const { clientId, goToPreviousStep, goToNextStep } = useVoucherInstructionsContext()
+ const { goToPreviousStep, goToNextStep } = useVoucherInstructionsContext()
+
+ const clientId = searchParams.get('clientId') || ''
return (
<>
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep4.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep4.tsx
similarity index 95%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep4.tsx
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep4.tsx
index 013dd3e35..ef9a61488 100644
--- a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/VoucherInstructionsStep4.tsx
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/VoucherInstructionsStep4.tsx
@@ -17,15 +17,19 @@ import {
apiSignalhubPushLink,
apiSignalhubPullLink,
} from '@/config/constants'
+import { useSearchParams } from 'react-router-dom'
export const VoucherInstructionsStep4: React.FC = () => {
const { t } = useTranslation('voucher')
const clientKind = useClientKind()
- const { selectedPurposeId, goToPreviousStep } = useVoucherInstructionsContext()
+ const { goToPreviousStep } = useVoucherInstructionsContext()
+ const [searchParams] = useSearchParams()
+
+ const purposeId = searchParams.get('purposeId') || ''
const { data: purpose } = useQuery({
- ...PurposeQueries.getSingle(selectedPurposeId!),
- enabled: Boolean(selectedPurposeId),
+ ...PurposeQueries.getSingle(purposeId),
+ enabled: Boolean(purposeId),
})
const eserviceName = purpose ? purpose.eservice.name : ''
diff --git a/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/__test__/VoucherInstructions.test.tsx b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/__test__/VoucherInstructions.test.tsx
new file mode 100644
index 000000000..102a0221d
--- /dev/null
+++ b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/__test__/VoucherInstructions.test.tsx
@@ -0,0 +1,35 @@
+import { MemoryRouter } from 'react-router-dom'
+import { VoucherInstructions } from '../VoucherInstructions'
+import { screen } from '@testing-library/react'
+import { renderWithApplicationContext } from '@/utils/testing.utils'
+
+describe('VoucherInstructions testing', () => {
+ it('should render instruction for get consumer voucher simulation', () => {
+ renderWithApplicationContext(
+
+
+ ,
+ {
+ withReactQueryContext: true,
+ }
+ )
+
+ expect(screen.getByText('step1.description')).toBeInTheDocument()
+ expect(screen.getByLabelText('step1.clientSelectInput.label')).toBeInTheDocument()
+ expect(screen.getByLabelText('step1.purposeSelectInput.label')).toBeInTheDocument()
+ })
+
+ it('should render instruction for get api voucher simulation', () => {
+ renderWithApplicationContext(
+
+
+ ,
+ {
+ withReactQueryContext: true,
+ }
+ )
+
+ expect(screen.getByText('step1.description')).toBeInTheDocument()
+ expect(screen.getByLabelText('step1.clientSelectInput.label')).toBeInTheDocument()
+ })
+})
diff --git a/src/pages/ConsumerClientManagePage/components/VoucherInstructions/index.ts b/src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/index.ts
similarity index 100%
rename from src/pages/ConsumerClientManagePage/components/VoucherInstructions/index.ts
rename to src/pages/ConsumerSimulateGetVoucherPage/components/VoucherInstructions/index.ts
diff --git a/src/pages/ConsumerSimulateGetVoucherPage/index.ts b/src/pages/ConsumerSimulateGetVoucherPage/index.ts
new file mode 100644
index 000000000..0a3c36afb
--- /dev/null
+++ b/src/pages/ConsumerSimulateGetVoucherPage/index.ts
@@ -0,0 +1 @@
+export { default as ConsumerSimulateGetVoucherPage } from './ConsumerSimulateGetVoucherPage.page'
diff --git a/src/pages/DeveloperToolsPage/DeveloperTools.page.tsx b/src/pages/DeveloperToolsPage/DeveloperTools.page.tsx
index 1a90d27b6..7232d344b 100644
--- a/src/pages/DeveloperToolsPage/DeveloperTools.page.tsx
+++ b/src/pages/DeveloperToolsPage/DeveloperTools.page.tsx
@@ -61,6 +61,26 @@ const DeveloperToolsPage: React.FC = () => {
+
+
+
+
+ {t('sectionVoucherSimulation.firstButton')}
+
+
+ {t('sectionVoucherSimulation.secondButton')}
+
+
+
+
)
diff --git a/src/router/routes.tsx b/src/router/routes.tsx
index e4c9b90cd..2c5a0f415 100644
--- a/src/router/routes.tsx
+++ b/src/router/routes.tsx
@@ -67,6 +67,7 @@ import { ConsumerPurposeTemplateDetailsPage } from '@/pages/ConsumerPurposeTempl
import ConsumerPurposeTemplateCatalogDetailsPage from '@/pages/ConsumerPurposeTemplateCatalogDetailsPage/ConsumerPurposeTemplateCatalogDetailsPage'
import { ConsumerPurposeTemplateSummaryPage } from '@/pages/ConsumerPurposeTemplateSummaryPage'
import { ConsumerPurposeTemplateEditPage } from '@/pages/ConsumerPurposeTemplateEditPage'
+import { ConsumerSimulateGetVoucherPage } from '@/pages/ConsumerSimulateGetVoucherPage'
export const { routes, reactRouterDOMRoutes, hooks, components, utils } = new InteropRouterBuilder<
LangCode,
@@ -387,6 +388,22 @@ export const { routes, reactRouterDOMRoutes, hooks, components, utils } = new In
hideSideNav: false,
authLevels: ['admin', 'support', 'api', 'security'],
})
+ .addRoute({
+ key: 'SIMULATE_GET_VOUCHER_API',
+ path: '/tool-sviluppo/api-interop/simulazione-voucher',
+ element: ,
+ public: false,
+ hideSideNav: true,
+ authLevels: ['admin', 'support', 'api', 'security'],
+ })
+ .addRoute({
+ key: 'SIMULATE_GET_VOUCHER_CONSUMER',
+ path: '/tool-sviluppo/api-e-service/simulazione-voucher',
+ element: ,
+ public: false,
+ hideSideNav: true,
+ authLevels: ['admin', 'support', 'api', 'security'],
+ })
.addRoute({
key: 'TENANT',
path: '/aderente',
diff --git a/src/static/locales/en/common.json b/src/static/locales/en/common.json
index ff3496b9d..5654efd42 100644
--- a/src/static/locales/en/common.json
+++ b/src/static/locales/en/common.json
@@ -56,7 +56,8 @@
"markAsRead": "Mark as read",
"marsAsNotRead": "Mark as not read",
"specifyProcessing": "Specify processing",
- "save": "Save"
+ "save": "Save",
+ "simulateVoucher": "Simulate obtaining the voucher"
},
"table": {
"headData": {
diff --git a/src/static/locales/en/developer-tools.json b/src/static/locales/en/developer-tools.json
index 55b531f97..5c87fe649 100644
--- a/src/static/locales/en/developer-tools.json
+++ b/src/static/locales/en/developer-tools.json
@@ -15,6 +15,12 @@
"title": "Debug Client Assertion",
"description": "Tool to generate, view, and validate client assertion JWT, useful for debugging and integration with OAuth 2.0 flows.",
"button": "Run debug"
+ },
+ "sectionVoucherSimulation": {
+ "title": "Simulate getting a voucher",
+ "description": "Through this feature you can simulate obtaining a voucher. Once you have selected the parameters, you can perform a client assertion, request a voucher and verify that it is compatible.",
+ "firstButton": "E-service simulation",
+ "secondButton": "Interop simulation"
}
}
},
diff --git a/src/static/locales/en/pages.json b/src/static/locales/en/pages.json
index 36371066e..b5510d155 100644
--- a/src/static/locales/en/pages.json
+++ b/src/static/locales/en/pages.json
@@ -35,6 +35,10 @@
"title": "Client Assertion Debug",
"description": "The debug tool allows you to highlight any anomalies contained in your client assertion necessary for obtaining an access token."
},
+ "consumerSimulateGetVoucher": {
+ "title": "Simulate getting a voucher",
+ "description": "Through this feature you can simulate obtaining a voucher. Once you have selected the parameters, you can perform a client assertion, request a voucher and verify that it is compatible."
+ },
"tenantCertifier": {
"title": "Party Certifier",
"description": "Create and manage certified attributes and assign them to compliant entities."
diff --git a/src/static/locales/en/shared-components.json b/src/static/locales/en/shared-components.json
index 90b7b10e6..1305f70bb 100644
--- a/src/static/locales/en/shared-components.json
+++ b/src/static/locales/en/shared-components.json
@@ -510,6 +510,8 @@
"SUBSCRIBE_PURPOSE_TEMPLATE_CATALOG_DETAILS": "Template Details",
"SUBSCRIBE_PURPOSE_TEMPLATE_EDIT": "Edit Purpose Template",
"SUBSCRIBE_PURPOSE_CREATE_FROM_TEMPLATE": "Create Purpose from Template",
- "SUBSCRIBE_PURPOSE_FROM_TEMPLATE_EDIT": "Edit Purpose from Template"
+ "SUBSCRIBE_PURPOSE_FROM_TEMPLATE_EDIT": "Edit Purpose from Template",
+ "SIMULATE_GET_VOUCHER_API": "Simulate getting a voucher",
+ "SIMULATE_GET_VOUCHER_CONSUMER": "Simulate getting a voucher"
}
}
diff --git a/src/static/locales/en/voucher.json b/src/static/locales/en/voucher.json
index 56728435a..1a5139650 100644
--- a/src/static/locales/en/voucher.json
+++ b/src/static/locales/en/voucher.json
@@ -19,6 +19,9 @@
"CONSUMER": "Select purpose and public key"
},
"description": "Used to show you the correct parameters to populate the client assertion",
+ "clientSelectInput": {
+ "label": "Choose the client to use"
+ },
"purposeSelectInput": {
"label": "Choose the purpose to use"
},
diff --git a/src/static/locales/it/common.json b/src/static/locales/it/common.json
index 6f63d7e83..a30d37c08 100644
--- a/src/static/locales/it/common.json
+++ b/src/static/locales/it/common.json
@@ -56,7 +56,8 @@
"markAsRead": "Segna come letto",
"marsAsNotRead": "Segna da leggere",
"specifyProcessing": "Indica trattamento",
- "save": "Salva"
+ "save": "Salva",
+ "simulateVoucher": "Simula l'ottenimento del voucher"
},
"table": {
"headData": {
diff --git a/src/static/locales/it/developer-tools.json b/src/static/locales/it/developer-tools.json
index e46af6c94..5a15853d0 100644
--- a/src/static/locales/it/developer-tools.json
+++ b/src/static/locales/it/developer-tools.json
@@ -15,6 +15,12 @@
"title": "Debug Client Assertion",
"description": "Strumento per generare, visualizzare e validare client assertion JWT, utile per il debug e l’integrazione con flussi OAuth 2.0.",
"button": "Effettua il debug"
+ },
+ "sectionVoucherSimulation": {
+ "title": "Simula l’ottenimento di un voucher",
+ "description": "Attraverso questa funzionalità potrai simulare l’ottenimento di un voucher. Una volta selezionati i parametri, potrai effettuare una client assertion, richiedere un voucher e verificare che sia compatibile.",
+ "firstButton": "Simulazione per e-service",
+ "secondButton": "Simulazione per interoperabilità"
}
}
},
diff --git a/src/static/locales/it/pages.json b/src/static/locales/it/pages.json
index 1238e6b5b..a2c09312e 100644
--- a/src/static/locales/it/pages.json
+++ b/src/static/locales/it/pages.json
@@ -35,6 +35,10 @@
"title": "Debug client assertion",
"description": "Lo strumento di debug ti consente di evidenziare eventuali anomalie contenute nella tua client assertion necessaria per l’ottenimento dell’access token."
},
+ "consumerSimulateGetVoucher": {
+ "title": "Simula l’ottenimento di un voucher",
+ "description": "Attraverso questa funzionalità potrai simulare l’ottenimento di un voucher. Una volta selezionati i parametri, potrai effettuare una client assertion, richiedere un voucher e verificare che sia compatibile."
+ },
"tenantCertifier": {
"title": "Ente certificatore",
"description": "Crea e gestisci gli attributi certificati e assegnali agli enti conformi."
diff --git a/src/static/locales/it/shared-components.json b/src/static/locales/it/shared-components.json
index 9460bcf93..cdf49ad0a 100644
--- a/src/static/locales/it/shared-components.json
+++ b/src/static/locales/it/shared-components.json
@@ -475,6 +475,8 @@
"PARTY_REGISTRY": "Anagrafica e attributi",
"NOT_FOUND": "Pagina non trovata",
"SUBSCRIBE_DEBUG_VOUCHER": "Debug client assertion",
+ "SIMULATE_GET_VOUCHER_API": "Simula l’ottenimento di un voucher",
+ "SIMULATE_GET_VOUCHER_CONSUMER": "Simula l’ottenimento di un voucher",
"ASSISTENCE_PARTY_SELECTION": "Selezione ente",
"ASSISTENCE_PARTY_SELECTION_ERROR": "Errore selezione ente",
"DEFAULT": "",
diff --git a/src/static/locales/it/voucher.json b/src/static/locales/it/voucher.json
index e7f4521cb..5e79c335a 100644
--- a/src/static/locales/it/voucher.json
+++ b/src/static/locales/it/voucher.json
@@ -19,6 +19,9 @@
"CONSUMER": "Seleziona finalità e chiave pubblica"
},
"description": "Serve a mostrarti i parametri corretti per valorizzare la client assertion",
+ "clientSelectInput": {
+ "label": "Scegli un client da utilizzare"
+ },
"purposeSelectInput": {
"label": "Scegli la finalità da utilizzare"
},