@palladium-ethiopia/esm-clinical-workflow-app 5.4.2-pre.34 → 5.4.2-pre.37

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 (28) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/dist/164.js +1 -1
  3. package/dist/164.js.map +1 -1
  4. package/dist/{160.js → 693.js} +1 -1
  5. package/dist/693.js.map +1 -0
  6. package/dist/ethiopia-esm-clinical-workflow-app.js +1 -1
  7. package/dist/ethiopia-esm-clinical-workflow-app.js.buildmanifest.json +28 -28
  8. package/dist/main.js +4 -4
  9. package/dist/main.js.map +1 -1
  10. package/dist/routes.json +1 -1
  11. package/package.json +1 -1
  12. package/src/config-schema.ts +2 -0
  13. package/src/index.ts +1 -1
  14. package/src/mru/billing-information/billing-information.resource.ts +60 -59
  15. package/src/mru/billing-information/billing-information.scss +21 -3
  16. package/src/mru/billing-information/billing-information.workspace.tsx +106 -252
  17. package/src/mru/billing-information/components/BillingTypeAttributes.tsx +106 -0
  18. package/src/mru/billing-information/components/CreditSubTypeFields.tsx +145 -0
  19. package/src/mru/billing-information/components/CreditSubTypeSelection.tsx +66 -0
  20. package/src/mru/billing-information/components/FreeSubTypeFields.tsx +7 -0
  21. package/src/mru/billing-information/components/FreeSubTypeSelection.tsx +61 -0
  22. package/src/mru/billing-information/components/index.ts +5 -0
  23. package/src/mru/billing-information/hooks/index.ts +4 -0
  24. package/src/mru/billing-information/hooks/useBillingForm.ts +22 -0
  25. package/src/mru/billing-information/hooks/useBillingType.ts +18 -0
  26. package/src/mru/billing-information/hooks/useCreditCompanies.ts +17 -0
  27. package/src/mru/billing-information/hooks/usePaymentModes.ts +17 -0
  28. package/dist/160.js.map +0 -1
@@ -1,37 +1,29 @@
1
- import React, { useEffect, useMemo } from 'react';
2
- import {
3
- Button,
4
- ButtonSet,
5
- InlineLoading,
6
- ContentSwitcher,
7
- Dropdown,
8
- Switch,
9
- TextInput,
10
- Form,
11
- FormGroup,
12
- } from '@carbon/react';
1
+ import React, { useEffect } from 'react';
2
+ import { Button, ButtonSet, InlineLoading, ContentSwitcher, Switch, Form } from '@carbon/react';
13
3
  import {
14
4
  DefaultWorkspaceProps,
15
5
  ExtensionSlot,
16
6
  usePatient,
17
- OpenmrsDatePicker,
18
7
  useConfig,
19
8
  useVisit,
20
9
  showSnackbar,
21
10
  } from '@openmrs/esm-framework';
22
11
  import { useTranslation } from 'react-i18next';
23
- import type { TFunction } from 'i18next';
24
-
25
- import { useForm, Controller, Control, FieldErrors, useWatch } from 'react-hook-form';
26
- import { zodResolver } from '@hookform/resolvers/zod';
27
12
 
28
13
  import {
29
14
  type BillingFormData,
30
- createBillingFormSchema,
31
15
  createBillingInformationVisitAttribute,
32
16
  updateVisitWithBillingInformation,
33
17
  } from './billing-information.resource';
34
18
  import type { ClinicalWorkflowConfig } from '../../config-schema';
19
+ import { usePaymentModes, useCreditCompanies, useBillingForm, useBillingType } from './hooks';
20
+ import {
21
+ BillingTypeAttributes,
22
+ CreditSubTypeSelection,
23
+ FreeSubTypeSelection,
24
+ CreditSubTypeFields,
25
+ FreeSubTypeFields,
26
+ } from './components';
35
27
  import styles from './billing-information.scss';
36
28
 
37
29
  type BillingInformationWorkspaceProps = DefaultWorkspaceProps & {
@@ -48,30 +40,30 @@ const BillingInformationWorkspace: React.FC<BillingInformationWorkspaceProps> =
48
40
  const { patient, isLoading } = usePatient(patientUuid);
49
41
  const { activeVisit, mutate: mutateVisit } = useVisit(patientUuid);
50
42
  const { billingVisitAttributeTypes } = useConfig<ClinicalWorkflowConfig>();
51
- const billingFormSchema = useMemo(() => createBillingFormSchema(t), [t]);
52
43
 
44
+ // Custom hooks for data fetching
45
+ const { billingTypes } = usePaymentModes();
46
+
47
+ // Form management hook
53
48
  const {
54
49
  control,
55
50
  handleSubmit,
56
51
  watch,
57
52
  setValue,
58
53
  formState: { errors, isDirty },
59
- } = useForm<BillingFormData>({
60
- resolver: zodResolver(billingFormSchema),
61
- mode: 'onTouched',
62
- defaultValues: {
63
- billingType: undefined,
64
- creditType: '',
65
- name: '',
66
- code: '',
67
- id: '',
68
- expiryDate: '',
69
- zone: '',
70
- freeType: '',
71
- },
72
- });
54
+ } = useBillingForm(t, billingTypes);
55
+
56
+ // Watch form values
57
+ const billingTypeUuid = watch('billingTypeUuid');
58
+ const creditSubType = watch('creditSubType');
59
+ const freeSubType = watch('freeSubType');
60
+ const attributes = watch('attributes') || {};
61
+
62
+ // Billing type logic hook
63
+ const { selectedBillingType, isCreditType, isFreeType } = useBillingType(billingTypes, billingTypeUuid);
73
64
 
74
- const billingType = watch('billingType');
65
+ // Fetch credit companies conditionally
66
+ const { creditCompanies } = useCreditCompanies(isCreditType && creditSubType === 'creditCompany');
75
67
 
76
68
  const onSubmit = async (data: BillingFormData) => {
77
69
  try {
@@ -101,35 +93,24 @@ const BillingInformationWorkspace: React.FC<BillingInformationWorkspaceProps> =
101
93
  }
102
94
  };
103
95
 
104
- const handleBillingTypeChange = (type: 'credit' | 'free' | 'cash') => {
105
- // Clear form fields to avoid carrying over values from previous billing type
106
- setValue('billingType', type, { shouldDirty: true });
107
- setValue('creditType', '', { shouldDirty: false });
108
- setValue('name', '', { shouldDirty: false });
109
- setValue('code', '', { shouldDirty: false });
110
- setValue('id', '', { shouldDirty: false });
111
- setValue('expiryDate', '', { shouldDirty: false });
112
- setValue('zone', '', { shouldDirty: false });
113
- setValue('freeType', '', { shouldDirty: false });
96
+ const handleBillingTypeChange = (uuid: string) => {
97
+ // Clear attributes and sub-types when changing billing type
98
+ setValue('billingTypeUuid', uuid, { shouldDirty: true });
99
+ setValue('creditSubType', undefined, { shouldDirty: false });
100
+ setValue('freeSubType', undefined, { shouldDirty: false });
101
+ setValue('attributes', {}, { shouldDirty: false });
114
102
  };
115
103
 
116
104
  const getSelectedIndex = () => {
117
- if (billingType === 'cash') {
118
- return 0;
105
+ if (!billingTypeUuid) {
106
+ return -1;
119
107
  }
120
- if (billingType === 'free') {
121
- return 1;
122
- }
123
- if (billingType === 'credit') {
124
- return 2;
125
- }
126
- return -1;
108
+ return billingTypes.findIndex((bt) => bt.uuid === billingTypeUuid);
127
109
  };
128
110
 
129
111
  const handleContentSwitcherChange = ({ index }: { index: number }) => {
130
- const types: ('cash' | 'free' | 'credit')[] = ['cash', 'free', 'credit'];
131
- if (index >= 0 && index < types.length) {
132
- handleBillingTypeChange(types[index]);
112
+ if (index >= 0 && index < billingTypes.length) {
113
+ handleBillingTypeChange(billingTypes[index].uuid);
133
114
  }
134
115
  };
135
116
 
@@ -141,6 +122,8 @@ const BillingInformationWorkspace: React.FC<BillingInformationWorkspaceProps> =
141
122
  return <InlineLoading status="active" iconDescription="Loading" description="Loading billing information..." />;
142
123
  }
143
124
 
125
+ //
126
+
144
127
  return (
145
128
  <>
146
129
  {patient && (
@@ -156,14 +139,75 @@ const BillingInformationWorkspace: React.FC<BillingInformationWorkspaceProps> =
156
139
  <Form onSubmit={handleSubmit(onSubmit)}>
157
140
  <div className={styles.billingInformationContainer}>
158
141
  <p className={styles.sectionTitle}>{t('paymentMethods', 'Payment Methods')}</p>
159
- <ContentSwitcher onChange={handleContentSwitcherChange} selectedIndex={getSelectedIndex()} size="md">
160
- <Switch name="cash" text={t('cash', 'Cash')} />
161
- <Switch name="free" text={t('free', 'Free')} />
162
- <Switch name="credit" text={t('credit', 'Credit')} />
142
+
143
+ <ContentSwitcher
144
+ className={styles.paymentTypeSwitcher}
145
+ onChange={handleContentSwitcherChange}
146
+ selectedIndex={getSelectedIndex()}
147
+ size="md">
148
+ {billingTypes?.map((billingType) => (
149
+ <Switch
150
+ className={styles.paymentTypeSwitch}
151
+ key={billingType.uuid}
152
+ name={billingType.uuid}
153
+ text={billingType.name}
154
+ />
155
+ ))}
163
156
  </ContentSwitcher>
164
157
 
165
- {billingType === 'credit' && <CreditDetails control={control} errors={errors} t={t} />}
166
- {billingType === 'free' && <FreeDetails control={control} errors={errors} t={t} />}
158
+ {/* Credit sub-type selection */}
159
+ {isCreditType && (
160
+ <CreditSubTypeSelection
161
+ control={control}
162
+ errors={errors}
163
+ t={t}
164
+ creditSubType={creditSubType}
165
+ setValue={setValue}
166
+ />
167
+ )}
168
+
169
+ {/* Free sub-type selection */}
170
+ {isFreeType && (
171
+ <FreeSubTypeSelection
172
+ control={control}
173
+ errors={errors}
174
+ t={t}
175
+ freeSubType={freeSubType}
176
+ setValue={setValue}
177
+ />
178
+ )}
179
+
180
+ {/* Conditional fields based on Credit sub-type */}
181
+ {isCreditType && creditSubType && (
182
+ <CreditSubTypeFields
183
+ control={control}
184
+ errors={errors}
185
+ t={t}
186
+ creditSubType={creditSubType}
187
+ creditCompanies={creditCompanies}
188
+ attributes={attributes}
189
+ setValue={setValue}
190
+ />
191
+ )}
192
+
193
+ {/* Conditional fields based on Free sub-type */}
194
+ {isFreeType && freeSubType && <FreeSubTypeFields />}
195
+
196
+ {/* Default attribute types for other billing types */}
197
+ {selectedBillingType &&
198
+ !isCreditType &&
199
+ !isFreeType &&
200
+ selectedBillingType.attributeTypes &&
201
+ selectedBillingType.attributeTypes.length > 0 && (
202
+ <BillingTypeAttributes
203
+ control={control}
204
+ errors={errors}
205
+ t={t}
206
+ attributeTypes={selectedBillingType.attributeTypes}
207
+ attributes={attributes}
208
+ setValue={setValue}
209
+ />
210
+ )}
167
211
  </div>
168
212
  <ButtonSet className={styles.buttonSet}>
169
213
  <Button className={styles.button} kind="secondary" onClick={() => closeWorkspace()}>
@@ -179,193 +223,3 @@ const BillingInformationWorkspace: React.FC<BillingInformationWorkspaceProps> =
179
223
  };
180
224
 
181
225
  export default BillingInformationWorkspace;
182
-
183
- type CreditDetailsProps = {
184
- control: Control<BillingFormData>;
185
- errors: FieldErrors<BillingFormData>;
186
- t: TFunction;
187
- };
188
-
189
- const CreditDetails: React.FC<CreditDetailsProps> = ({ control, errors, t }) => {
190
- const creditType = useWatch({
191
- control,
192
- name: 'creditType',
193
- });
194
-
195
- const creditTypeOptions = [
196
- {
197
- id: 'chbi',
198
- text: t('chbi', 'CHBI'),
199
- },
200
- {
201
- id: 'shi',
202
- text: t('shi', 'SHI'),
203
- },
204
- {
205
- id: 'creditCompanies',
206
- text: t('creditCompanies', 'Credit Companies'),
207
- },
208
- {
209
- id: 'insurance',
210
- text: t('insurance', 'Insurance'),
211
- },
212
- ];
213
-
214
- const showCreditCompanyFields = creditType === 'creditCompanies' || creditType === 'insurance';
215
-
216
- return (
217
- <FormGroup className={styles.creditDetailsContainer} legendText={t('creditDetails', 'Credit Details')}>
218
- <Controller
219
- name="creditType"
220
- control={control}
221
- render={({ field: { onChange, value } }) => (
222
- <Dropdown
223
- id="credit-type"
224
- invalid={!!errors.creditType}
225
- invalidText={errors.creditType?.message || 'invalid selection'}
226
- itemToString={(item) => item?.text ?? ''}
227
- items={creditTypeOptions}
228
- label="Credit"
229
- titleText="Credit"
230
- type="default"
231
- selectedItem={creditTypeOptions.find((item) => item.id === value) || null}
232
- onChange={({ selectedItem }) => onChange(selectedItem?.id || '')}
233
- />
234
- )}
235
- />
236
-
237
- {showCreditCompanyFields && (
238
- <FormGroup
239
- legendText={t('creditTypeDetails', 'Credit Type Details')}
240
- className={styles.creditTypeDetailsContainer}>
241
- <Controller
242
- name="id"
243
- control={control}
244
- render={({ field: { onChange, value } }) => (
245
- <TextInput
246
- id="credit-id"
247
- labelText={t('id', 'ID')}
248
- value={value || ''}
249
- onChange={(e) => onChange(e.target.value)}
250
- placeholder={t('enterId', 'Enter ID')}
251
- invalid={!!errors.id}
252
- invalidText={errors.id?.message}
253
- />
254
- )}
255
- />
256
-
257
- <Controller
258
- name="name"
259
- control={control}
260
- render={({ field: { onChange, value } }) => (
261
- <TextInput
262
- id="credit-name"
263
- labelText={t('name', 'Name')}
264
- value={value || ''}
265
- onChange={(e) => onChange(e.target.value)}
266
- placeholder={t('enterName', 'Enter name')}
267
- invalid={!!errors.name}
268
- invalidText={errors.name?.message}
269
- />
270
- )}
271
- />
272
-
273
- <Controller
274
- name="code"
275
- control={control}
276
- render={({ field: { onChange, value } }) => (
277
- <TextInput
278
- id="credit-code"
279
- labelText={t('code', 'Code')}
280
- value={value || ''}
281
- onChange={(e) => onChange(e.target.value)}
282
- placeholder={t('enterCode', 'Enter code')}
283
- invalid={!!errors.code}
284
- invalidText={errors.code?.message}
285
- />
286
- )}
287
- />
288
-
289
- <Controller
290
- name="expiryDate"
291
- control={control}
292
- render={({ field: { onChange, value } }) => (
293
- <OpenmrsDatePicker
294
- id="credit-expiry-date"
295
- labelText={t('expiryDate', 'Expiry Date')}
296
- minDate={new Date()}
297
- value={value || ''}
298
- onChange={(date) => {
299
- const dateValue = typeof date === 'string' ? date : date.toISOString().split('T')[0];
300
- onChange(dateValue);
301
- }}
302
- />
303
- )}
304
- />
305
- <Controller
306
- name="zone"
307
- control={control}
308
- render={({ field: { onChange, value } }) => (
309
- <TextInput
310
- id="credit-zone"
311
- labelText={t('zone', 'Zone')}
312
- value={value || ''}
313
- onChange={(e) => onChange(e.target.value)}
314
- placeholder={t('enterZone', 'Enter zone')}
315
- invalid={!!errors.zone}
316
- invalidText={errors.zone?.message}
317
- />
318
- )}
319
- />
320
- </FormGroup>
321
- )}
322
- </FormGroup>
323
- );
324
- };
325
-
326
- type FreeDetailsProps = {
327
- control: Control<BillingFormData>;
328
- errors: FieldErrors<BillingFormData>;
329
- t: TFunction;
330
- };
331
-
332
- const FreeDetails: React.FC<FreeDetailsProps> = ({ control, errors, t }) => {
333
- const items = [
334
- {
335
- id: 'staff',
336
- text: t('staff', 'Staff'),
337
- },
338
- {
339
- id: '24Hours',
340
- text: t('24Hours', '24 Hours'),
341
- },
342
- {
343
- id: 'exempted',
344
- text: t('exempted', 'Exempted'),
345
- },
346
- ];
347
-
348
- return (
349
- <FormGroup className={styles.freeDetailsContainer} legendText={t('freeDetails', 'Free Details')}>
350
- <Controller
351
- name="freeType"
352
- control={control}
353
- render={({ field: { onChange, value } }) => (
354
- <Dropdown
355
- id="free-type"
356
- hideLabel={true}
357
- invalid={!!errors.freeType}
358
- invalidText={errors.freeType?.message || 'invalid selection'}
359
- itemToString={(item) => item?.text ?? ''}
360
- items={items}
361
- label={t('selectOption', 'Select a free type')}
362
- titleText={t('selectOption', 'Select a free type')}
363
- type="default"
364
- selectedItem={items.find((item) => item.id === value) || null}
365
- onChange={({ selectedItem }) => onChange(selectedItem?.id || '')}
366
- />
367
- )}
368
- />
369
- </FormGroup>
370
- );
371
- };
@@ -0,0 +1,106 @@
1
+ import React from 'react';
2
+ import { Controller, Control, FieldErrors } from 'react-hook-form';
3
+ import { TextInput, FormGroup } from '@carbon/react';
4
+ import { OpenmrsDatePicker } from '@openmrs/esm-framework';
5
+ import type { TFunction } from 'i18next';
6
+ import type { BillingFormData } from '../billing-information.resource';
7
+ import styles from '../billing-information.scss';
8
+
9
+ type BillingTypeAttributesProps = {
10
+ control: Control<BillingFormData>;
11
+ errors: FieldErrors<BillingFormData>;
12
+ t: TFunction;
13
+ attributeTypes: Array<{
14
+ uuid: string;
15
+ name: string;
16
+ description?: string;
17
+ format?: string;
18
+ required?: boolean;
19
+ }>;
20
+ attributes: Record<string, any>;
21
+ setValue: (name: string, value: any, options?: { shouldDirty?: boolean }) => void;
22
+ };
23
+
24
+ export const BillingTypeAttributes: React.FC<BillingTypeAttributesProps> = ({
25
+ control,
26
+ errors,
27
+ t,
28
+ attributeTypes,
29
+ attributes,
30
+ setValue,
31
+ }) => {
32
+ const renderAttributeField = (attrType: {
33
+ uuid: string;
34
+ name: string;
35
+ description?: string;
36
+ format?: string;
37
+ required?: boolean;
38
+ }) => {
39
+ const fieldName = `attributes.${attrType.uuid}` as const;
40
+ const fieldError = errors.attributes?.[attrType.uuid];
41
+ const errorMessage =
42
+ fieldError && typeof fieldError === 'object' && 'message' in fieldError
43
+ ? String(fieldError.message)
44
+ : fieldError
45
+ ? String(fieldError)
46
+ : undefined;
47
+
48
+ // Determine field type based on format
49
+ const isDateField =
50
+ attrType.format?.toLowerCase().includes('date') || attrType.format === 'org.openmrs.util.AttributableDate';
51
+
52
+ if (isDateField) {
53
+ return (
54
+ <Controller
55
+ key={attrType.uuid}
56
+ name={fieldName}
57
+ control={control}
58
+ render={({ field: { onChange, value } }) => (
59
+ <OpenmrsDatePicker
60
+ id={`attribute-${attrType.uuid}`}
61
+ labelText={attrType.name}
62
+ value={value || ''}
63
+ onChange={(date) => {
64
+ const dateValue = typeof date === 'string' ? date : date.toISOString().split('T')[0];
65
+ onChange(dateValue);
66
+ setValue(fieldName, dateValue, { shouldDirty: true });
67
+ }}
68
+ invalid={!!fieldError}
69
+ invalidText={errorMessage}
70
+ />
71
+ )}
72
+ />
73
+ );
74
+ }
75
+
76
+ // Default to text input
77
+ return (
78
+ <Controller
79
+ key={attrType.uuid}
80
+ name={fieldName}
81
+ control={control}
82
+ render={({ field: { onChange, value } }) => (
83
+ <TextInput
84
+ id={`attribute-${attrType.uuid}`}
85
+ labelText={attrType.name}
86
+ value={value || ''}
87
+ onChange={(e) => {
88
+ onChange(e.target.value);
89
+ setValue(fieldName, e.target.value, { shouldDirty: true });
90
+ }}
91
+ placeholder={attrType.description || t('enterValue', 'Enter {{name}}', { name: attrType.name })}
92
+ invalid={!!fieldError}
93
+ invalidText={errorMessage}
94
+ required={attrType.required}
95
+ />
96
+ )}
97
+ />
98
+ );
99
+ };
100
+
101
+ return (
102
+ <FormGroup className={styles.billingTypeAttributesContainer} legendText={t('billingDetails', 'Billing Details')}>
103
+ {attributeTypes.map((attrType) => renderAttributeField(attrType))}
104
+ </FormGroup>
105
+ );
106
+ };
@@ -0,0 +1,145 @@
1
+ import React from 'react';
2
+ import { Control, FieldErrors } from 'react-hook-form';
3
+ import { TextInput, Dropdown, FormGroup } from '@carbon/react';
4
+ import { OpenmrsDatePicker, useConfig } from '@openmrs/esm-framework';
5
+ import type { TFunction } from 'i18next';
6
+ import type { BillingFormData } from '../billing-information.resource';
7
+ import type { ClinicalWorkflowConfig } from '../../../config-schema';
8
+ import styles from '../billing-information.scss';
9
+
10
+ type CreditSubTypeFieldsProps = {
11
+ control: Control<BillingFormData>;
12
+ errors: FieldErrors<BillingFormData>;
13
+ t: TFunction;
14
+ creditSubType: string;
15
+ creditCompanies: Array<{ uuid: string; name: string }>;
16
+ attributes: Record<string, any>;
17
+ setValue: (name: string, value: any, options?: { shouldDirty?: boolean }) => void;
18
+ };
19
+
20
+ export const CreditSubTypeFields: React.FC<CreditSubTypeFieldsProps> = ({
21
+ control,
22
+ errors,
23
+ t,
24
+ creditSubType,
25
+ creditCompanies,
26
+ attributes,
27
+ setValue,
28
+ }) => {
29
+ const { billingVisitAttributeTypes } = useConfig<ClinicalWorkflowConfig>();
30
+
31
+ // Use creditTypeDetails UUID to store all credit details as a JSON object
32
+ const creditDetailsKey = billingVisitAttributeTypes.creditTypeDetails || 'creditTypeDetails';
33
+ const creditDetails = attributes[creditDetailsKey]
34
+ ? typeof attributes[creditDetailsKey] === 'string'
35
+ ? JSON.parse(attributes[creditDetailsKey])
36
+ : attributes[creditDetailsKey]
37
+ : {};
38
+
39
+ const updateCreditDetails = (fieldName: string, value: any) => {
40
+ const updatedDetails = { ...creditDetails, [fieldName]: value };
41
+ setValue(`attributes.${creditDetailsKey}`, JSON.stringify(updatedDetails), { shouldDirty: true });
42
+ };
43
+
44
+ const renderField = (fieldName: string, label: string, isDate = false, isDropdown = false, items: any[] = []) => {
45
+ const fieldValue = creditDetails[fieldName] || '';
46
+ const creditDetailsError = errors.attributes?.[creditDetailsKey];
47
+ const errorMessage =
48
+ creditDetailsError && typeof creditDetailsError === 'object' && 'message' in creditDetailsError
49
+ ? String(creditDetailsError.message)
50
+ : creditDetailsError
51
+ ? String(creditDetailsError)
52
+ : undefined;
53
+
54
+ if (isDropdown) {
55
+ return (
56
+ <Dropdown
57
+ key={fieldName}
58
+ id={`attribute-${fieldName}`}
59
+ titleText={label}
60
+ label={label}
61
+ items={items}
62
+ itemToString={(item) => (item ? (typeof item === 'string' ? item : item.name || item.uuid) : '')}
63
+ selectedItem={
64
+ items.find((item) => (typeof item === 'string' ? item === fieldValue : item.uuid === fieldValue)) || null
65
+ }
66
+ onChange={({ selectedItem }) => {
67
+ const selectedValue = typeof selectedItem === 'string' ? selectedItem : selectedItem?.uuid || '';
68
+ updateCreditDetails(fieldName, selectedValue);
69
+ }}
70
+ invalid={!!creditDetailsError}
71
+ invalidText={errorMessage}
72
+ />
73
+ );
74
+ }
75
+
76
+ if (isDate) {
77
+ return (
78
+ <OpenmrsDatePicker
79
+ key={fieldName}
80
+ id={`attribute-${fieldName}`}
81
+ labelText={label}
82
+ value={fieldValue || ''}
83
+ onChange={(date) => {
84
+ const dateValue = typeof date === 'string' ? date : date.toISOString().split('T')[0];
85
+ updateCreditDetails(fieldName, dateValue);
86
+ }}
87
+ invalid={!!creditDetailsError}
88
+ invalidText={errorMessage}
89
+ />
90
+ );
91
+ }
92
+
93
+ return (
94
+ <TextInput
95
+ key={fieldName}
96
+ id={`attribute-${fieldName}`}
97
+ labelText={label}
98
+ value={fieldValue || ''}
99
+ onChange={(e) => {
100
+ updateCreditDetails(fieldName, e.target.value);
101
+ }}
102
+ placeholder={t('enterValue', 'Enter {{name}}', { name: label })}
103
+ invalid={!!creditDetailsError}
104
+ invalidText={errorMessage}
105
+ />
106
+ );
107
+ };
108
+
109
+ return (
110
+ <FormGroup className={styles.creditTypeDetailsContainer} legendText={t('creditDetails', 'Credit Details')}>
111
+ {creditSubType === 'cbhi' && (
112
+ <>
113
+ {renderField('cbhiId', t('cbhiId', 'CBHI ID'))}
114
+ {renderField('cbhiExpiryDate', t('expiryDate', 'Expiry Date'), true)}
115
+ </>
116
+ )}
117
+ {creditSubType === 'shi' && (
118
+ <>
119
+ {renderField('shiId', t('shiId', 'SHI ID'))}
120
+ {renderField('shiExpiryDate', t('expiryDate', 'Expiry Date'), true)}
121
+ </>
122
+ )}
123
+ {creditSubType === 'insurance' && (
124
+ <>
125
+ {renderField('insuranceName', t('insuranceName', 'Insurance Name'))}
126
+ {renderField('insuranceId', t('insuranceId', 'Insurance ID'))}
127
+ {renderField('insuranceCode', t('insuranceCode', 'Insurance Code'))}
128
+ {renderField('insuranceZone', t('insuranceZone', 'Insurance Zone'))}
129
+ {renderField('insuranceExpiryDate', t('insuranceExpiryDate', 'Insurance Expiry Date'), true)}
130
+ </>
131
+ )}
132
+ {creditSubType === 'creditCompany' && (
133
+ <>
134
+ {renderField(
135
+ 'creditCompany',
136
+ t('creditCompany', 'Credit Company'),
137
+ false,
138
+ true,
139
+ creditCompanies.map((company) => ({ uuid: company.uuid, name: company.name })),
140
+ )}
141
+ </>
142
+ )}
143
+ </FormGroup>
144
+ );
145
+ };