Skip to content
Open
Show file tree
Hide file tree
Changes from 8 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
30 changes: 19 additions & 11 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 All @@ -50,6 +51,23 @@ export const RegistrationCax = () => {
}
}, [])

const renderStepComponent = (step) => {
switch (step) {
case 1:
return <CompanyDataCax />
case 2:
return <ResponsibilitiesCax />
case 3:
return <CompanyRoleCax />
case 4:
return <DragDrop />
case 5:
return <WalletCax />
default:
return <VerifyRegistration />
}
}

return (
<Container>
<Header />
Expand All @@ -62,17 +80,7 @@ export const RegistrationCax = () => {
<div>{t('registration.regiSubHeading')}</div>
</div>
<Stepper></Stepper>
{currentActiveStep === 1 ? (
<CompanyDataCax />
) : currentActiveStep === 2 ? (
<ResponsibilitiesCax />
) : currentActiveStep === 3 ? (
<CompanyRoleCax />
) : currentActiveStep === 4 ? (
<DragDrop />
) : (
<VerifyRegistration />
)}
{renderStepComponent(currentActiveStep)}
</Col>
)}
</Row>
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
Loading