@ampath/esm-dha-workflow-app 4.0.0-next.4 → 4.0.0-next.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/109.js +2 -0
  2. package/dist/{731.js.LICENSE.txt → 109.js.LICENSE.txt} +3 -3
  3. package/dist/109.js.map +1 -0
  4. package/dist/161.js +1 -0
  5. package/dist/161.js.map +1 -0
  6. package/dist/32.js +2 -0
  7. package/dist/32.js.map +1 -0
  8. package/dist/324.js +2 -0
  9. package/dist/324.js.LICENSE.txt +9 -0
  10. package/dist/324.js.map +1 -0
  11. package/dist/70.js +1 -1
  12. package/dist/91.js +1 -1
  13. package/dist/91.js.map +1 -1
  14. package/dist/main.js +1 -1
  15. package/dist/main.js.map +1 -1
  16. package/dist/openmrs-esm-home-app.js +1 -1
  17. package/dist/openmrs-esm-home-app.js.buildmanifest.json +114 -87
  18. package/dist/openmrs-esm-home-app.js.map +1 -1
  19. package/dist/routes.json +1 -1
  20. package/package.json +1 -1
  21. package/src/registry/client-details/client-details.tsx +40 -0
  22. package/src/registry/modal/client-details-modal/client-details-modal.scss +28 -0
  23. package/src/registry/modal/client-details-modal/client-details-modal.tsx +72 -0
  24. package/src/registry/modal/otp-verification-modal/otp-verification-modal.scss +6 -0
  25. package/src/registry/modal/otp-verification-modal/otp-verification-modal.tsx +172 -0
  26. package/src/registry/payment-details/payment-options/payment-options.tsx +21 -0
  27. package/src/registry/registry.component.scss +58 -0
  28. package/src/registry/registry.component.tsx +240 -2
  29. package/src/registry/registry.resource.ts +58 -0
  30. package/src/registry/types/index.ts +160 -0
  31. package/src/registry/utils/hie-adapter.ts +56 -0
  32. package/src/registry/utils/mask-data.ts +21 -0
  33. package/dist/561.js +0 -2
  34. package/dist/561.js.map +0 -1
  35. package/dist/731.js +0 -2
  36. package/dist/731.js.map +0 -1
  37. package/dist/819.js +0 -1
  38. package/dist/819.js.map +0 -1
  39. /package/dist/{561.js.LICENSE.txt → 32.js.LICENSE.txt} +0 -0
@@ -0,0 +1,40 @@
1
+ import React, { useMemo } from 'react';
2
+ import { type HieClient } from '../types';
3
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@carbon/react';
4
+ import { generateHieClientDetails } from '../utils/hie-adapter';
5
+ interface ClientDetailsProps {
6
+ client: HieClient;
7
+ }
8
+ export const ClientDetails: React.FC<ClientDetailsProps> = ({ client }) => {
9
+ const clientDetails = useMemo(() => generateHieClientDetails(client), [client]);
10
+
11
+ if (!client || !clientDetails) {
12
+ return (
13
+ <>
14
+ <h4>No patient Data to Display</h4>
15
+ </>
16
+ );
17
+ }
18
+ return (
19
+ <>
20
+ <Table>
21
+ <TableHead>
22
+ <TableRow>
23
+ <TableHeader>Field</TableHeader>
24
+ <TableHeader>Value</TableHeader>
25
+ </TableRow>
26
+ </TableHead>
27
+ <TableBody>
28
+ {Object.keys(clientDetails).map((key) => (
29
+ <TableRow>
30
+ <TableCell>{key}</TableCell>
31
+ <TableCell>{clientDetails[key]}</TableCell>
32
+ </TableRow>
33
+ ))}
34
+ </TableBody>
35
+ </Table>
36
+ </>
37
+ );
38
+ };
39
+
40
+ export default ClientDetails;
@@ -0,0 +1,28 @@
1
+ .clientDetailsLayout{
2
+ display: flex;
3
+ flex-direction: column;
4
+ width: 100%;
5
+ row-gap: 5px;
6
+ }
7
+ .sectionHeader{
8
+ display: flex;
9
+ flex-direction: column;
10
+ row-gap: 5px;
11
+ margin-top: 5px;
12
+ margin-bottom: 10px;
13
+ }
14
+ .sectionContent{
15
+ display: flex;
16
+ flex-direction: column;
17
+ row-gap: 5px;
18
+ }
19
+ .actionSection{
20
+ display: flex;
21
+ flex-direction: row;
22
+ width: 100%;
23
+ column-gap: 5px;
24
+ }
25
+ .btnContainer{
26
+ margin-top: 2px;
27
+ margin-bottom: 2px;
28
+ }
@@ -0,0 +1,72 @@
1
+ import { Button, Modal, ModalBody, Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
2
+ import { type HieClient } from '../../types';
3
+ import React from 'react';
4
+ import styles from './client-details-modal.scss';
5
+ import ClientDetails from '../../client-details/client-details';
6
+ import PaymentOptionsComponent from '../../payment-details/payment-options/payment-options';
7
+
8
+ interface ClientDetailsModalProps {
9
+ client: HieClient;
10
+ open: boolean;
11
+ onModalClose: () => void;
12
+ onSubmit: () => void;
13
+ }
14
+
15
+ const ClientDetailsModal: React.FC<ClientDetailsModalProps> = ({ client, open, onModalClose, onSubmit }) => {
16
+ if (!client) {
17
+ return <>No Client data</>;
18
+ }
19
+ return (
20
+ <>
21
+ <Modal
22
+ open={open}
23
+ size="md"
24
+ onSecondarySubmit={onModalClose}
25
+ onRequestClose={onModalClose}
26
+ onRequestSubmit={onSubmit}
27
+ primaryButtonText=""
28
+ secondaryButtonText="Cancel"
29
+ >
30
+ <ModalBody>
31
+ <div className={styles.clientDetailsLayout}>
32
+ <div className={styles.sectionHeader}>
33
+ <h4 className={styles.sectionTitle}>Patient/Payment Details</h4>
34
+ </div>
35
+ <div className={styles.sectionContent}>
36
+ <Tabs>
37
+ <TabList contained>
38
+ <Tab>Patient Details</Tab>
39
+ <Tab>Payment Details</Tab>
40
+ </TabList>
41
+ <TabPanels>
42
+ <TabPanel>
43
+ <ClientDetails client={client} />
44
+ </TabPanel>
45
+ <TabPanel>
46
+ <PaymentOptionsComponent />
47
+ </TabPanel>
48
+ </TabPanels>
49
+ </Tabs>
50
+ </div>
51
+ <div className={styles.actionSection}>
52
+ <div className={styles.btnContainer}>
53
+ <Button kind="primary">Book Appointment</Button>
54
+ </div>
55
+ <div className={styles.btnContainer}>
56
+ <Button kind="secondary">Walk In Orders</Button>
57
+ </div>
58
+ <div className={styles.btnContainer}>
59
+ <Button kind="tertiary">Send To Triage</Button>
60
+ </div>
61
+ <div className={styles.btnContainer}>
62
+ <Button kind="primary">Send To Consultation</Button>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </ModalBody>
67
+ </Modal>
68
+ </>
69
+ );
70
+ };
71
+
72
+ export default ClientDetailsModal;
@@ -0,0 +1,6 @@
1
+ .modalVerificationLayout {
2
+ display: flex;
3
+ flex-direction: column;
4
+ row-gap: 10px;
5
+ width: 100%;
6
+ }
@@ -0,0 +1,172 @@
1
+ import React, { useState } from 'react';
2
+ import { type RequestCustomOtpDto } from '../../types';
3
+ import { Button, Modal, ModalBody, TextInput } from '@carbon/react';
4
+ import styles from './otp-verification-modal.scss';
5
+ import { showSnackbar } from '@openmrs/esm-framework';
6
+ import { requestCustomOtp, validateCustomOtp } from '../../registry.resource';
7
+
8
+ interface OtpVerificationModalpProps {
9
+ requestCustomOtpDto: RequestCustomOtpDto;
10
+ phoneNumber: string;
11
+ open: boolean;
12
+ onModalClose: () => void;
13
+ }
14
+ const OtpVerificationModal: React.FC<OtpVerificationModalpProps> = ({
15
+ requestCustomOtpDto,
16
+ phoneNumber,
17
+ open,
18
+ onModalClose,
19
+ }) => {
20
+ const [otp, setOtp] = useState('');
21
+ const [otpStatus, setOtpStatus] = useState<string>('DRAFT');
22
+ const [loading, setLoading] = useState<boolean>(false);
23
+ const [sessionId, setSessionId] = useState<string>('');
24
+
25
+ const handleSendOtp = async () => {
26
+ if (!requestCustomOtpDto.identificationNumber) {
27
+ showAlert('error', 'Invalid Identification Value', 'Please enter a valid ID value');
28
+ return;
29
+ }
30
+ setLoading(true);
31
+ try {
32
+ const response = await requestCustomOtp(requestCustomOtpDto);
33
+ setSessionId(response.sessionId);
34
+ setOtpStatus('OTP_SENT');
35
+
36
+ showAlert('success', 'OTP sent successfully', `A code was sent to ${response.maskedPhone}`);
37
+ } catch (err: any) {
38
+ const errorMessage = err.message || 'Failed to send OTP';
39
+ showAlert('error', 'Error sending OTP', errorMessage);
40
+ } finally {
41
+ setLoading(false);
42
+ }
43
+ };
44
+ const showAlert = (alertType: 'error' | 'success', title: string, subtitle: string) => {
45
+ showSnackbar({
46
+ kind: alertType,
47
+ title: title,
48
+ subtitle: subtitle,
49
+ });
50
+ };
51
+
52
+ const handleVerifyOtp = async () => {
53
+ if (!otp.trim()) {
54
+ showAlert('error', 'Please enter the OTP code', '');
55
+ return;
56
+ }
57
+
58
+ setLoading(true);
59
+
60
+ try {
61
+ const payload = { sessionId, otp, locationUuid: requestCustomOtpDto.locationUuid };
62
+ await validateCustomOtp(payload);
63
+
64
+ setOtpStatus('OTP_VERIFIED');
65
+
66
+ showSnackbar({
67
+ kind: 'success',
68
+ title: 'OTP Verified',
69
+ subtitle: 'You can now fetch data from Client Registry.',
70
+ });
71
+ } catch (err: any) {
72
+ const errorMessage = err.message || 'OTP verification failed';
73
+ showSnackbar({
74
+ kind: 'error',
75
+ title: 'OTP Verification Failed',
76
+ subtitle: errorMessage,
77
+ });
78
+ } finally {
79
+ setLoading(false);
80
+ }
81
+ };
82
+
83
+ const onSubmit = () => {};
84
+ return (
85
+ <>
86
+ <Modal
87
+ open={open}
88
+ size="md"
89
+ onSecondarySubmit={onModalClose}
90
+ onRequestClose={onModalClose}
91
+ onRequestSubmit={onSubmit}
92
+ primaryButtonText=""
93
+ secondaryButtonText="Cancel"
94
+ >
95
+ <ModalBody>
96
+ <div className={styles.modalVerificationLayout}>
97
+ <div className={styles.sectionHeader}>
98
+ <h4 className={styles.sectionTitle}>One Time Password (OTP)</h4>
99
+ <h6>Enter one time password to proceed</h6>
100
+ </div>
101
+ <div className={styles.sectionContent}>
102
+ <div className={styles.contentHeader}>
103
+ {otpStatus === 'DRAFT' ? (
104
+ <>
105
+ <h6>Send Code to Phone {phoneNumber}</h6>
106
+ </>
107
+ ) : (
108
+ <></>
109
+ )}
110
+
111
+ {otpStatus === 'OTP_SENT' ? (
112
+ <>
113
+ <TextInput
114
+ id="otp-input"
115
+ labelText="Enter OTP"
116
+ value={otp}
117
+ onChange={(e) => setOtp(e.target.value)}
118
+ placeholder="Enter the code sent to your phone"
119
+ />
120
+ </>
121
+ ) : (
122
+ <></>
123
+ )}
124
+
125
+ {otpStatus === 'OTP_VERIFIED' ? (
126
+ <>
127
+ <h6>OTP Verification Successfull!</h6>
128
+ </>
129
+ ) : (
130
+ <></>
131
+ )}
132
+ </div>
133
+ </div>
134
+ <div className={styles.sectionAction}>
135
+ {otpStatus === 'DRAFT' ? (
136
+ <>
137
+ <Button kind="primary" onClick={handleSendOtp}>
138
+ Send OTP
139
+ </Button>
140
+ </>
141
+ ) : (
142
+ <></>
143
+ )}
144
+
145
+ {otpStatus === 'OTP_SENT' ? (
146
+ <>
147
+ <Button kind="primary" onClick={handleVerifyOtp}>
148
+ Verify
149
+ </Button>
150
+ </>
151
+ ) : (
152
+ <></>
153
+ )}
154
+
155
+ {otpStatus === 'OTP_VERIFIED' ? (
156
+ <>
157
+ <Button kind="primary" onClick={onModalClose}>
158
+ Continue
159
+ </Button>
160
+ </>
161
+ ) : (
162
+ <></>
163
+ )}
164
+ </div>
165
+ </div>
166
+ </ModalBody>
167
+ </Modal>
168
+ </>
169
+ );
170
+ };
171
+
172
+ export default OtpVerificationModal;
@@ -0,0 +1,21 @@
1
+ import { RadioButton, RadioButtonGroup } from '@carbon/react';
2
+ import React from 'react';
3
+ const PaymentOptionsComponent: React.FC = () => {
4
+ const handleSelectedPatientOption = (p: string) => {};
5
+ return (
6
+ <>
7
+ <RadioButtonGroup
8
+ defaultSelected="sha"
9
+ legendText="Patient"
10
+ onChange={(v) => handleSelectedPatientOption(v as string)}
11
+ name="payment-options-radio-group"
12
+ >
13
+ <RadioButton id="sha" labelText="Social Health Authority" value="sha" />
14
+ <RadioButton id="insurance" labelText="Other Insurance" value="other" />
15
+ <RadioButton id="cash" labelText="Cash" value="cash" />
16
+ </RadioButtonGroup>
17
+ </>
18
+ );
19
+ };
20
+
21
+ export default PaymentOptionsComponent;
@@ -0,0 +1,58 @@
1
+ .registryLayout{
2
+ display: flex;
3
+ flex-direction: column;
4
+ width: 100%;
5
+ row-gap: 10px;
6
+ padding: 2% 2%;
7
+ }
8
+ .registryHeader{
9
+ display: flex;
10
+ flex-direction: column;
11
+ row-gap: 10px;
12
+ width: 100%;
13
+ }
14
+ .registryContent{
15
+ display: flex;
16
+ flex-direction: column;
17
+ width: 100%;
18
+ }
19
+ .formRow{
20
+ display: flex;
21
+ flex-direction: row;
22
+ width: 100%;
23
+ column-gap: 5px;
24
+ }
25
+ .formControl{
26
+ width: 30%;
27
+ }
28
+ .hieData{
29
+ margin-top: 15px;
30
+ display: flex;
31
+ flex-direction: column;
32
+ width: 50%;
33
+ row-gap: 10px;
34
+ }
35
+ .btnContainer{
36
+ padding: 5px 5px;
37
+ }
38
+ .selectionHeader{
39
+ display: flex;
40
+ flex-direction: column;
41
+ width: 100%;
42
+ row-gap: 5px;
43
+ }
44
+ .patientSelect{
45
+ display: flex;
46
+ flex-direction: row;
47
+ width: 100%;
48
+ column-gap: 5px;
49
+ }
50
+ .patientSelectRadio{
51
+ width: 70%;
52
+ }
53
+ .patientConfirmSelection{
54
+ display: flex;
55
+ flex-direction: row;
56
+ width: 30%;
57
+ column-gap: 5px;
58
+ }
@@ -1,7 +1,245 @@
1
- import React from 'react';
1
+ import {
2
+ Button,
3
+ Dropdown,
4
+ InlineLoading,
5
+ RadioButton,
6
+ RadioButtonGroup,
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableHead,
11
+ TableHeader,
12
+ TableRow,
13
+ TextInput,
14
+ } from '@carbon/react';
15
+ import React, { useState } from 'react';
16
+ import styles from './registry.component.scss';
17
+ import { type HieClient, IDENTIFIER_TYPES, type IdentifierType, type RequestCustomOtpDto } from './types';
18
+ import { fetchClientRegistryData } from './registry.resource';
19
+ import { showSnackbar, useSession } from '@openmrs/esm-framework';
20
+ import OtpVerificationModal from './modal/otp-verification-modal/otp-verification-modal';
21
+ import { maskExceptFirstAndLast, maskValue } from './utils/mask-data';
22
+ import ClientDetailsModal from './modal/client-details-modal/client-details-modal';
2
23
  interface RegistryComponentProps {}
3
24
  const RegistryComponent: React.FC<RegistryComponentProps> = () => {
4
- return <>Registry Component</>;
25
+ const [identifierType, setIdentifierType] = useState<IdentifierType>('National ID');
26
+ const [identifierValue, setIdentifierValue] = useState('');
27
+ const [loading, setLoading] = useState<boolean>(false);
28
+ const [client, setClient] = useState<HieClient>();
29
+ const [selectedPatient, setSelectedPatient] = useState<string>('principal');
30
+ const [displayOtpModal, setDisplayOtpModal] = useState<boolean>(false);
31
+ const [displayClientDetailsModal, setDisplayClientDetailsModal] = useState<boolean>(false);
32
+ const [requestCustomOtpDto, setRequestCustomOtpDto] = useState<RequestCustomOtpDto>();
33
+ const session = useSession();
34
+ const locationUuid = session.sessionLocation.uuid;
35
+
36
+ const handleSearchPatient = async () => {
37
+ setLoading(true);
38
+ try {
39
+ const payload = {
40
+ identificationNumber: identifierValue,
41
+ identificationType: identifierType,
42
+ locationUuid,
43
+ };
44
+
45
+ setRequestCustomOtpDto(payload);
46
+
47
+ const result = await fetchClientRegistryData(payload);
48
+ const patients = Array.isArray(result) ? result : [];
49
+
50
+ if (patients.length === 0) throw new Error('No matching patient found in Client Registry.');
51
+
52
+ const patient = patients[0];
53
+ setClient(patient);
54
+ showAlert('success', 'Client Data Loaded', 'Patient fetched successfully');
55
+ } catch (err: any) {
56
+ const errorMessage = err.message || 'Failed to fetch client data';
57
+ showAlert('error', 'Fetch Failed', errorMessage);
58
+ } finally {
59
+ setLoading(false);
60
+ }
61
+ };
62
+ const showAlert = (alertType: 'error' | 'success', title: string, subtitle: string) => {
63
+ showSnackbar({
64
+ kind: alertType,
65
+ title: title,
66
+ subtitle: subtitle,
67
+ });
68
+ };
69
+ const handleSelectedPatient = (sp: string) => {
70
+ setSelectedPatient(sp);
71
+ };
72
+ const handleOtpVerification = () => {
73
+ setDisplayOtpModal(true);
74
+ };
75
+ const handleModelClose = () => {
76
+ setDisplayOtpModal(false);
77
+ setDisplayClientDetailsModal(true);
78
+ };
79
+ const onClientDetailsModalClose = () => {
80
+ setDisplayClientDetailsModal(false);
81
+ };
82
+ const handleClientDetailsSubmit = () => {
83
+ return;
84
+ };
85
+ return (
86
+ <>
87
+ <div className={styles.registryLayout}>
88
+ <div className={styles.registryHeader}>
89
+ <h4>Client Registry</h4>
90
+ <p>Please enter identification number to begin</p>
91
+ </div>
92
+ <div className={styles.registryContent}>
93
+ <div className={styles.formRow}>
94
+ <div className={styles.formControl}>
95
+ <Dropdown
96
+ id="identifier-type-dropdown"
97
+ label="Identifier Type"
98
+ titleText="Select Identifier Type"
99
+ items={IDENTIFIER_TYPES}
100
+ selectedItem={identifierType}
101
+ onChange={({ selectedItem }) => setIdentifierType(selectedItem as IdentifierType)}
102
+ />
103
+ </div>
104
+
105
+ <div className={styles.formControl}>
106
+ <TextInput
107
+ id="identifier-value"
108
+ labelText={`${identifierType} Value`}
109
+ value={identifierValue}
110
+ onChange={(e) => setIdentifierValue(e.target.value)}
111
+ placeholder={`Enter ${identifierType.toLowerCase()} value`}
112
+ />
113
+ </div>
114
+ <div className={styles.formControl}>
115
+ <Button kind="primary" onClick={handleSearchPatient} disabled={loading}>
116
+ {loading ? <InlineLoading description="Searching..." /> : 'Search'}
117
+ </Button>
118
+ </div>
119
+ </div>
120
+ {client ? (
121
+ <div className={styles.formRow}>
122
+ <div className={styles.hieData}>
123
+ <div className={styles.selectionHeader}>
124
+ <h5>Please select one patient and request patient to share the OTP sent</h5>
125
+ </div>
126
+ <div className={styles.patientSelect}>
127
+ <div className={styles.patientSelectRadio}>
128
+ <RadioButtonGroup
129
+ defaultSelected="principal"
130
+ legendText="Patient"
131
+ onChange={(v) => handleSelectedPatient(v as string)}
132
+ name="radio-button-default-group"
133
+ >
134
+ <RadioButton id="principal" labelText="Principal" value="principal" />
135
+ <RadioButton id="dependants" labelText="Dependants" value="dependants" />
136
+ </RadioButtonGroup>
137
+ </div>
138
+ <div className={styles.patientConfirmSelection}>
139
+ <div className={styles.btnContainer}>
140
+ <Button kind="primary" onClick={handleOtpVerification}>
141
+ {' '}
142
+ Confirm
143
+ </Button>
144
+ </div>
145
+ <div className={styles.btnContainer}>
146
+ <Button kind="secondary">Cancel</Button>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ {selectedPatient === 'principal' ? (
151
+ <>
152
+ <Table>
153
+ <TableHead>
154
+ <TableRow>
155
+ <TableHeader>Name</TableHeader>
156
+ <TableHeader>CR</TableHeader>
157
+ <TableHeader>Phone No</TableHeader>
158
+ <TableHeader>ID No</TableHeader>
159
+ </TableRow>
160
+ </TableHead>
161
+ <TableBody>
162
+ <TableRow>
163
+ <TableCell>
164
+ {client.first_name} {maskExceptFirstAndLast(client.middle_name)}{' '}
165
+ {maskExceptFirstAndLast(client.last_name)}
166
+ </TableCell>
167
+ <TableCell>{maskValue(client.id)}</TableCell>
168
+ <TableCell>{maskValue(client.phone)}</TableCell>
169
+ <TableCell>{maskValue(client.identification_number)}</TableCell>
170
+ </TableRow>
171
+ </TableBody>
172
+ </Table>
173
+ </>
174
+ ) : (
175
+ <></>
176
+ )}
177
+ {selectedPatient === 'dependants' ? (
178
+ <>
179
+ <Table>
180
+ <TableHead>
181
+ <TableRow>
182
+ <TableHeader>Name</TableHeader>
183
+ <TableHeader>CR</TableHeader>
184
+ <TableHeader>Relationship</TableHeader>
185
+ </TableRow>
186
+ </TableHead>
187
+ <TableBody>
188
+ {client.dependants.map((d) => {
189
+ const dependant = d.result[0];
190
+ const relationship = d.relationship;
191
+ return (
192
+ <>
193
+ <TableRow>
194
+ <TableCell>
195
+ {dependant.first_name} {maskExceptFirstAndLast(dependant.middle_name)}{' '}
196
+ {maskExceptFirstAndLast(dependant.last_name)}
197
+ </TableCell>
198
+ <TableCell>{maskValue(dependant.id)}</TableCell>
199
+ <TableCell>{relationship}</TableCell>
200
+ </TableRow>
201
+ </>
202
+ );
203
+ })}
204
+ </TableBody>
205
+ </Table>
206
+ </>
207
+ ) : (
208
+ <></>
209
+ )}
210
+
211
+ {displayOtpModal ? (
212
+ <OtpVerificationModal
213
+ requestCustomOtpDto={requestCustomOtpDto}
214
+ phoneNumber={client.phone}
215
+ open={displayOtpModal}
216
+ onModalClose={handleModelClose}
217
+ />
218
+ ) : (
219
+ <></>
220
+ )}
221
+
222
+ {client && displayClientDetailsModal ? (
223
+ <>
224
+ <ClientDetailsModal
225
+ client={client}
226
+ open={displayClientDetailsModal}
227
+ onModalClose={onClientDetailsModalClose}
228
+ onSubmit={handleClientDetailsSubmit}
229
+ />{' '}
230
+ </>
231
+ ) : (
232
+ <></>
233
+ )}
234
+ </div>
235
+ </div>
236
+ ) : (
237
+ <></>
238
+ )}
239
+ </div>
240
+ </div>
241
+ </>
242
+ );
5
243
  };
6
244
 
7
245
  export default RegistryComponent;