Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<div id="app" style='width:100%; height:100%'></div>
<script>
// Do NOT change 'ENV' without changing 'custom_env_vars_anchor' in scripts/inject-dynamic-env.sh as well
const ENV = {PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",REALM:"CX-Central",CLIENT_ID_REGISTRATION:"Cl1-CX-Registration"}
const ENV = {PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",REALM:"CX-Central",CLIENT_ID_REGISTRATION:"Cl1-CX-Registration",ISSUER_ID:"did:web:example.org:api:administration:staticdata:did:BPNL00000003CRHK"}
</script>
<script type="module" src="/src/index.tsx"></script>
</body>
Expand Down
4 changes: 2 additions & 2 deletions scripts/inject-dynamic-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
###############################################################

# Define custom variable
custom_env_vars='{PORTAL_ASSETS_URL:"'$PORTAL_ASSETS_URL'",PORTAL_BACKEND_URL:"'$PORTAL_BACKEND_URL'",CENTRALIDP_URL:"'$CENTRALIDP_URL'",REALM:"'$REALM'",CLIENT_ID_REGISTRATION:"'$CLIENT_ID_REGISTRATION'"}'
custom_env_vars='{PORTAL_ASSETS_URL:"'$PORTAL_ASSETS_URL'",PORTAL_BACKEND_URL:"'$PORTAL_BACKEND_URL'",CENTRALIDP_URL:"'$CENTRALIDP_URL'",REALM:"'$REALM'",CLIENT_ID_REGISTRATION:"'$CLIENT_ID_REGISTRATION'",ISSUER_ID:"'$ISSUER_ID'"}'
# Define anchor variable
custom_env_vars_anchor='{PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",REALM:"CX-Central",CLIENT_ID_REGISTRATION:"Cl1-CX-Registration"}'
custom_env_vars_anchor='{PORTAL_ASSETS_URL:"http://localhost:3000/assets",PORTAL_BACKEND_URL:"https://portal-backend.example.org",CENTRALIDP_URL:"https://centralidp.example.org/auth",REALM:"CX-Central",CLIENT_ID_REGISTRATION:"Cl1-CX-Registration",ISSUER_ID:"did:web:example.org:api:administration:staticdata:did:BPNL00000003CRHK"}'
# Read content of the reference index.html file into the index_html_reference variable
index_html_reference=`cat /usr/share/nginx/html/index.html.reference`
# Replace the anchor variable with the custom variable in the index.html file
Expand Down
15 changes: 12 additions & 3 deletions src/components/StepHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,26 @@ type StepHeaderProps = {
step: number
stepName: string
stepDescription: string
className?: string
additionalDescription?: string
}
const StepHeader = ({ step, stepName, stepDescription }: StepHeaderProps) => {
const StepHeader = ({
step,
stepName,
stepDescription,
className = '',
additionalDescription = '',
}: StepHeaderProps) => {
return (
<div className="head-section">
<div className={`head-section ${className}`}>
<div className="mx-auto step-highlight d-flex align-items-center justify-content-center">
{step}
</div>
<h4 className="mx-auto d-flex align-items-center justify-content-center">
{stepName}
</h4>
<div className="mx-auto text-center col-9">
<div className="mx-auto text-center col-9 subheader">
<span className="additonal-subheader">{additionalDescription}</span>
{stepDescription}
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions src/components/cax-registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { Tooltip } from 'react-tooltip'
import { useSelector } from 'react-redux'
import 'react-datepicker/dist/react-datepicker.css'
import { CompanyDataCax } from './cax-companyData'
import { WalletCax } from './cax-wallet'
import { ResponsibilitiesCax } from './cax-responsibilities'
import { DragDrop } from './dragdrop'
import { CompanyRoleCax } from './cax-companyRole'
Expand Down Expand Up @@ -70,6 +71,8 @@ export const RegistrationCax = () => {
<CompanyRoleCax />
) : currentActiveStep === 4 ? (
<DragDrop />
) : currentActiveStep === 5 ? (
<WalletCax />
) : (
<VerifyRegistration />
)}
Expand Down
193 changes: 193 additions & 0 deletions src/components/cax-wallet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/********************************************************************************
* Copyright (c) 2025 Cofinity-X GmbH
*
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
import { useTranslation } from 'react-i18next'
import { useState, useCallback, useEffect } from 'react'
import { FooterButton } from './footerButton'
import { useDispatch, useSelector } from 'react-redux'
import { Row } from 'react-bootstrap'
import {
addCurrentStep,
getCurrentStep,
} from '../state/features/user/userApiSlice'
import { Notify } from './Snackbar'
import StepHeader from './StepHeader'
import FormGroup from '@mui/material/FormGroup'
import FormControlLabel from '@mui/material/FormControlLabel'
import Checkbox from '@mui/material/Checkbox'
import TextField from '@mui/material/TextField'
import { useValidateDidMutation } from '../state/features/applicationWallet/applicationWalletApiSlice'
import { DataErrorCodes } from '../helpers/DataError'

export const WalletCax = () => {
const { t } = useTranslation()
const dispatch = useDispatch()
const [loading, setLoading] = useState(false)
const [apiError, setApiError] = useState(false)
const [message, setMessage] = useState('')

const currentActiveStep = useSelector(getCurrentStep)

const [nextClicked, setNextClicked] = useState(false)
const [isChecked, setIsChecked] = useState(false)
const [did, setDid] = useState('')
const [
validateDidTrigger,
{ error: didValidationError, isLoading: isValidating },
] = useValidateDidMutation()
const didTrimmed = did.trim()
const isNextDisabled = isChecked && didTrimmed.length === 0
const LS_KEY_WALLET_DID = 'registration.wallet.did'

const backClick = useCallback(() => {
dispatch(addCurrentStep(currentActiveStep - 1))
}, [dispatch, currentActiveStep])

const handleCheckboxChange = useCallback((e) => {
const checked = e.target.checked
setIsChecked(checked)
if (!checked) {
setDid('')
}
}, [])

const handleDidChange = useCallback((e) => {
setDid(e.target.value)
}, [])

useEffect(() => {
const stored = window.localStorage.getItem(LS_KEY_WALLET_DID) || ''
setDid(stored)
}, [])

useEffect(() => {
window.localStorage.setItem(LS_KEY_WALLET_DID, did)
}, [did])

const nextClick = useCallback(async () => {
if (isNextDisabled) return
if (loading) return
setNextClicked(true)
try {
if (isChecked) {
setLoading(true)
await validateDidTrigger(didTrimmed).unwrap()
}
dispatch(addCurrentStep(currentActiveStep + 1))
} catch (err) {
//backend is sending 400 as response whenever an invalid DID is being given
if (err.status == 400) {
setMessage(t('wallet.didValidationFailed'))
}

DataErrorCodes.includes(err.status)
? setMessage(t(`ErrorMessage.${err.status}`))
: setMessage(t('ErrorMessage.default'))
setApiError(true)
setLoading(false)
}
}, [
isNextDisabled,
validateDidTrigger,
didTrimmed,
dispatch,
currentActiveStep,
])

const [notifyError, setNotifyError] = useState(false)
useEffect(() => {
if (nextClicked && (didValidationError || apiError)) {
setNotifyError(true)
} else {
setNotifyError(false)
}
}, [nextClicked, didValidationError, apiError])

const renderSnackbar = () => {
return <Notify message={message} />
}

const issuerId = (ENV as any).ISSUER_ID

return (
<>
<div className="mx-auto col-9 container-registration">
<StepHeader
step={currentActiveStep}
stepName={t('wallet.title')}
stepDescription={t('wallet.subtitle')}
additionalDescription={t('wallet.optional')}
className="wallet-header"
/>
<div className="mx-auto col-9">
<FormGroup className="col-12 wallet-page-checkbox">
<FormControlLabel
control={
<Checkbox
checked={isChecked}
onChange={handleCheckboxChange}
inputProps={{ 'aria-label': t('wallet.userAgreementText') }}
/>
}
label={t('wallet.userAgreementText')}
/>
</FormGroup>
<Row className="col-12">
<label htmlFor="wallet-did" className="did-label">
{t('wallet.didLabel')}
</label>
<TextField
id="wallet-did"
value={did}
onChange={handleDidChange}
disabled={!isChecked}
placeholder="did:web:<URI>"
variant="filled"
className="did-input"
error={false}
helperText=" "
fullWidth
/>
{isChecked && (
<div className="issuer-cred-info-container">
<div className="issuer-cred-info">
{t('wallet.issuerCredsInfo')}
</div>
<span className="issuer-cred-id">{issuerId}</span>{' '}
</div>
)}
</Row>
</div>
</div>

<FooterButton
labelNext={loading ? t('button.validating') : t('button.next')}
labelBack={t('button.back')}
handleBackClick={backClick}
handleNextClick={nextClick}
loading={loading}
disabled={isNextDisabled || isValidating}
helpUrl={
'/documentation/?path=user%2F01.+Onboarding%2F02.+Registration%2F02.+Add+Company+Data.md'
}
/>
{notifyError && renderSnackbar()}
</>
)
}
2 changes: 1 addition & 1 deletion src/components/stepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const Stepper = () => {

return (
<div className="mx-auto col-11 reg-steps">
<Row className="stepper-wrapper row-cols-5">
<Row className="stepper-wrapper row-cols-6">
{Object.entries(stepNames).map((element, index) => {
const stepNumber = +element[0]
const stepName = element[1]
Expand Down
64 changes: 51 additions & 13 deletions src/components/verifyRegistration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import {
import { Notify } from './Snackbar'
import StepHeader from './StepHeader'

import { useSaveHolderDidMutation } from '../state/features/applicationWallet/applicationWalletApiSlice'

export const VerifyRegistration = () => {
const { t } = useTranslation()
const history = useHistory()
Expand All @@ -53,6 +55,8 @@ export const VerifyRegistration = () => {
const obj = status?.[status.length - 1]
const applicationId = obj?.applicationId

const LS_KEY_WALLET_DID = 'registration.wallet.did'
const walletDID = window.localStorage.getItem(LS_KEY_WALLET_DID) || ''
const {
data: registrationData,
error: dataError,
Expand All @@ -61,28 +65,32 @@ export const VerifyRegistration = () => {
const { data: documents, error: documentsError } =
useFetchDocumentsQuery(applicationId)
const [updateRegistration] = useUpdateRegistrationMutation()

const [saveHolderDid] = useSaveHolderDidMutation()

useEffect(() => {
refetch()
}, [])

const backClick = () => {
dispatch(addCurrentStep(currentActiveStep - 1))
}

const nextClick = async () => {
if (loading) return
setLoading(true)
await updateRegistration(applicationId)
.unwrap()
.then(() => {
history.push('/finish')
})
.catch((errors: any) => {
console.log('errors', errors)
setLoading(false)
setSubmitError(true)
})
try {
const companyId = registrationData?.companyId
if (companyId && walletDID.trim()) {
await saveHolderDid({ companyId, did: walletDID.trim() }).unwrap()
}

await updateRegistration(applicationId).unwrap()
history.push('/finish')
} catch (errors: any) {
console.log('errors', errors)
setLoading(false)
setSubmitError(true)
}
}

const getTooltip = () => {
Expand All @@ -108,7 +116,7 @@ export const VerifyRegistration = () => {
return (
<>
<div className="mx-auto col-9 container-registration">
<StepHeader
<StepHeader
step={currentActiveStep}
stepName={t('verifyRegistration.title')}
stepDescription={t('verifyRegistration.subtitle')}
Expand Down Expand Up @@ -236,6 +244,36 @@ export const VerifyRegistration = () => {
})}
</ul>
</Row>
<Row>
<ul className="list-group-cax px-2">
<li className="list-group-item-cax list-header">
<Row>
<span className="col-11">
{t('verifyRegistration.wallet')}
</span>
</Row>
</li>
{walletDID !== '' && (
<li className="list-group-item-cax" key="Wallet">
<Row>
<span className="col-6">
{t('verifyRegistration.verifyPageParticipantWallet')}
</span>
<span className="col-6 verify-wallet-did">{walletDID}</span>
</Row>
</li>
)}
{walletDID == '' && (
<li key="wallet" className="list-group-item-cax">
<Row>
<span className="col-12">
{t('verifyRegistration.companyProvidedWallet')}
</span>
</Row>
</li>
)}
</ul>
</Row>
</div>
</div>
{(dataError ?? documentsError ?? submitError) && renderSnackbar()}
Expand Down
12 changes: 12 additions & 0 deletions src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export {}

declare global {
const ENV: {
PORTAL_ASSETS_URL: string
PORTAL_BACKEND_URL: string
CENTRALIDP_URL: string
REALM: string
CLIENT_ID_REGISTRATION: string
ISSUER_ID: string
}
}
Loading