@openmrs/esm-billing-app 1.0.1-pre.95 → 1.0.2-pre.56
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.
- package/.eslintignore +0 -1
- package/.eslintrc +33 -24
- package/.husky/pre-commit +1 -1
- package/.turbo.json +1 -1
- package/.tx/config +11 -0
- package/README.md +111 -1
- package/dist/1119.js +1 -0
- package/dist/1197.js +1 -0
- package/dist/1362.js +1 -0
- package/dist/1362.js.map +1 -0
- package/dist/2146.js +1 -0
- package/dist/2690.js +1 -0
- package/dist/3029.js +2 -0
- package/dist/3029.js.LICENSE.txt +7 -0
- package/dist/3029.js.map +1 -0
- package/dist/3099.js +1 -0
- package/dist/3511.js +1 -0
- package/dist/3511.js.map +1 -0
- package/dist/3584.js +1 -0
- package/dist/4055.js +1 -0
- package/dist/4132.js +1 -0
- package/dist/4225.js +1 -0
- package/dist/4225.js.map +1 -0
- package/dist/4300.js +1 -0
- package/dist/4335.js +1 -0
- package/dist/4618.js +1 -0
- package/dist/4652.js +1 -0
- package/dist/4817.js +2 -0
- package/dist/4817.js.LICENSE.txt +77 -0
- package/dist/4817.js.map +1 -0
- package/dist/4944.js +1 -0
- package/dist/4993.js +1 -0
- package/dist/4993.js.map +1 -0
- package/dist/5173.js +1 -0
- package/dist/5241.js +1 -0
- package/dist/5442.js +1 -0
- package/dist/5661.js +1 -0
- package/dist/6022.js +1 -0
- package/dist/6468.js +1 -0
- package/dist/6540.js +2 -0
- package/dist/6540.js.map +1 -0
- package/dist/6606.js +2 -0
- package/dist/{591.js.LICENSE.txt → 6606.js.LICENSE.txt} +2 -2
- package/dist/6606.js.map +1 -0
- package/dist/6679.js +1 -0
- package/dist/6840.js +1 -0
- package/dist/6859.js +1 -0
- package/dist/6941.js +1 -0
- package/dist/6941.js.map +1 -0
- package/dist/7097.js +1 -0
- package/dist/7159.js +1 -0
- package/dist/723.js +1 -0
- package/dist/7255.js +1 -0
- package/dist/7255.js.map +1 -0
- package/dist/7617.js +1 -0
- package/dist/763.js +1 -0
- package/dist/763.js.map +1 -0
- package/dist/8163.js +1 -0
- package/dist/8349.js +1 -0
- package/dist/8618.js +1 -0
- package/dist/890.js +1 -0
- package/dist/9055.js +1 -0
- package/dist/9055.js.map +1 -0
- package/dist/9214.js +1 -0
- package/dist/9538.js +1 -0
- package/dist/{935.js → 961.js} +2 -2
- package/dist/{935.js.map → 961.js.map} +1 -1
- package/dist/986.js +1 -0
- package/dist/9879.js +1 -0
- package/dist/9895.js +1 -0
- package/dist/9900.js +1 -0
- package/dist/9913.js +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.LICENSE.txt +31 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-billing-app.js +1 -1
- package/dist/openmrs-esm-billing-app.js.buildmanifest.json +844 -165
- package/dist/openmrs-esm-billing-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/jest.config.js +4 -1
- package/package.json +19 -21
- package/src/bill-history/bill-history.component.tsx +19 -7
- package/src/bill-history/bill-history.scss +24 -9
- package/src/bill-history/bill-history.test.tsx +58 -16
- package/src/bill-item-actions/bill-item-actions.scss +26 -0
- package/src/bill-item-actions/edit-bill-item.component.tsx +221 -0
- package/src/bill-item-actions/edit-bill-item.test.tsx +137 -0
- package/src/billable-services/bill-waiver/bill-selection.component.tsx +1 -1
- package/src/billable-services/bill-waiver/bill-waiver-form.component.tsx +2 -2
- package/src/billable-services/bill-waiver/bill-waiver-form.scss +4 -4
- package/src/billable-services/bill-waiver/bill-waiver.component.tsx +4 -4
- package/src/billable-services/bill-waiver/patient-bills.component.tsx +1 -1
- package/src/billable-services/billable-service.resource.ts +19 -6
- package/src/billable-services/billable-services-home.component.tsx +19 -3
- package/src/billable-services/billable-services-menu-item/item.component.tsx +17 -0
- package/src/billable-services/billable-services-menu-item/item.scss +14 -0
- package/src/billable-services/billable-services.component.tsx +48 -9
- package/src/billable-services/billable-services.scss +10 -9
- package/src/billable-services/billable-services.test.tsx +172 -8
- package/src/billable-services/cash-point/cash-point-configuration.component.tsx +276 -0
- package/src/billable-services/cash-point/cash-point-configuration.scss +23 -0
- package/src/billable-services/create-edit/add-billable-service.component.tsx +126 -47
- package/src/billable-services/create-edit/add-billable-service.scss +14 -8
- package/src/billable-services/create-edit/add-billable-service.test.tsx +12 -10
- package/src/billable-services/dashboard/dashboard.scss +3 -3
- package/src/billable-services/payyment-modes/payment-modes-config.component.tsx +280 -0
- package/src/billable-services/payyment-modes/payment-modes-config.scss +23 -0
- package/src/billing-dashboard/billing-dashboard.component.tsx +17 -4
- package/src/billing-dashboard/billing-dashboard.scss +3 -3
- package/src/billing-form/billing-form.component.tsx +31 -25
- package/src/billing-form/billing-form.scss +9 -10
- package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +38 -14
- package/src/billing-header/billing-header.component.tsx +21 -5
- package/src/billing-header/billing-header.scss +1 -1
- package/src/billing.resource.ts +24 -8
- package/src/bills-table/bills-table.component.tsx +46 -36
- package/src/bills-table/bills-table.scss +6 -6
- package/src/bills-table/bills-table.test.tsx +108 -68
- package/src/config-schema.ts +36 -1
- package/src/constants.ts +2 -0
- package/src/dashboard.meta.ts +2 -1
- package/src/helpers/functions.ts +0 -2
- package/src/hooks/selectedDateContext.ts +10 -0
- package/src/index.ts +22 -27
- package/src/invoice/invoice-table.component.tsx +95 -56
- package/src/invoice/invoice-table.scss +7 -8
- package/src/invoice/invoice-table.test.tsx +151 -0
- package/src/invoice/invoice.component.tsx +7 -9
- package/src/invoice/invoice.scss +2 -2
- package/src/invoice/invoice.test.tsx +199 -169
- package/src/invoice/payments/payment-form/payment-form.component.tsx +84 -55
- package/src/invoice/payments/payment-form/payment-form.test.tsx +174 -0
- package/src/invoice/payments/payment-history/payment-history.component.tsx +9 -7
- package/src/invoice/payments/payment-history/payment-history.test.tsx +160 -0
- package/src/invoice/payments/payments.component.test.tsx +121 -0
- package/src/invoice/payments/payments.component.tsx +57 -48
- package/src/invoice/payments/utils.ts +17 -13
- package/src/invoice/printable-invoice/print-receipt.component.tsx +23 -8
- package/src/invoice/printable-invoice/print-receipt.test.tsx +50 -0
- package/src/metrics-cards/card.component.tsx +4 -2
- package/src/metrics-cards/metrics-cards.test.tsx +1 -1
- package/src/modal/require-payment-modal.component.tsx +2 -2
- package/src/modal/require-payment-modal.test.tsx +66 -0
- package/src/modal/require-payment.scss +2 -1
- package/src/routes.json +40 -8
- package/src/types/index.ts +15 -0
- package/{i18next-parser.config.js → tools/i18next-parser.config.js} +19 -19
- package/tools/update-openmrs-deps.mjs +42 -0
- package/translations/am.json +53 -0
- package/translations/ar.json +170 -0
- package/translations/ar_SY.json +170 -0
- package/translations/bn.json +170 -0
- package/translations/de.json +170 -0
- package/translations/en.json +53 -0
- package/translations/es.json +53 -0
- package/translations/es_MX.json +170 -0
- package/translations/fr.json +53 -0
- package/translations/he.json +53 -0
- package/translations/hi.json +170 -0
- package/translations/hi_IN.json +170 -0
- package/translations/id.json +170 -0
- package/translations/it.json +170 -0
- package/translations/km.json +53 -0
- package/translations/ku.json +170 -0
- package/translations/ky.json +170 -0
- package/translations/lg.json +170 -0
- package/translations/ne.json +170 -0
- package/translations/pl.json +170 -0
- package/translations/pt.json +170 -0
- package/translations/pt_BR.json +170 -0
- package/translations/qu.json +170 -0
- package/translations/ro_RO.json +170 -0
- package/translations/ru_RU.json +170 -0
- package/translations/si.json +170 -0
- package/translations/sw.json +170 -0
- package/translations/sw_KE.json +170 -0
- package/translations/tr.json +170 -0
- package/translations/tr_TR.json +170 -0
- package/translations/uk.json +170 -0
- package/translations/uz.json +170 -0
- package/translations/uz@Latn.json +170 -0
- package/translations/uz_UZ.json +170 -0
- package/translations/vi.json +170 -0
- package/translations/zh.json +170 -0
- package/translations/zh_CN.json +170 -0
- package/tsconfig.json +10 -8
- package/webpack.config.js +1 -1
- package/dist/146.js +0 -1
- package/dist/146.js.map +0 -1
- package/dist/294.js +0 -2
- package/dist/294.js.map +0 -1
- package/dist/319.js +0 -1
- package/dist/384.js +0 -1
- package/dist/384.js.map +0 -1
- package/dist/421.js +0 -1
- package/dist/421.js.map +0 -1
- package/dist/533.js +0 -1
- package/dist/533.js.map +0 -1
- package/dist/574.js +0 -1
- package/dist/591.js +0 -2
- package/dist/591.js.map +0 -1
- package/dist/614.js +0 -2
- package/dist/614.js.LICENSE.txt +0 -37
- package/dist/614.js.map +0 -1
- package/dist/753.js +0 -1
- package/dist/753.js.map +0 -1
- package/dist/757.js +0 -1
- package/dist/770.js +0 -1
- package/dist/770.js.map +0 -1
- package/dist/783.js +0 -1
- package/dist/783.js.map +0 -1
- package/dist/788.js +0 -1
- package/dist/800.js +0 -2
- package/dist/800.js.LICENSE.txt +0 -3
- package/dist/800.js.map +0 -1
- package/dist/807.js +0 -1
- package/dist/833.js +0 -1
- package/dist/992.js +0 -1
- package/dist/992.js.map +0 -1
- package/src/root.scss +0 -30
- /package/dist/{294.js.LICENSE.txt → 6540.js.LICENSE.txt} +0 -0
- /package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +0 -0
- /package/{src → tools}/setup-tests.ts +0 -0
- /package/{test-helpers.tsx → tools/test-helpers.tsx} +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import React, { useCallback, useRef, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useRef, useState, useEffect } from 'react';
|
|
3
2
|
import {
|
|
4
3
|
Button,
|
|
5
4
|
ComboBox,
|
|
@@ -12,14 +11,15 @@ import {
|
|
|
12
11
|
TextInput,
|
|
13
12
|
Tile,
|
|
14
13
|
} from '@carbon/react';
|
|
15
|
-
import { navigate, showSnackbar, useDebounce, useLayoutType, useSession } from '@openmrs/esm-framework';
|
|
16
14
|
import { Add, TrashCan, WarningFilled } from '@carbon/react/icons';
|
|
17
15
|
import { Controller, useFieldArray, useForm } from 'react-hook-form';
|
|
18
16
|
import { useTranslation } from 'react-i18next';
|
|
19
17
|
import { z } from 'zod';
|
|
20
18
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
19
|
+
import { navigate, showSnackbar, useDebounce, useLayoutType } from '@openmrs/esm-framework';
|
|
21
20
|
import {
|
|
22
21
|
createBillableSerice,
|
|
22
|
+
updateBillableService,
|
|
23
23
|
useConceptsSearch,
|
|
24
24
|
usePaymentModes,
|
|
25
25
|
useServiceTypes,
|
|
@@ -44,25 +44,35 @@ const servicePriceSchema = z.object({
|
|
|
44
44
|
]),
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
const paymentFormSchema = z.object({
|
|
47
|
+
const paymentFormSchema = z.object({
|
|
48
|
+
payment: z.array(servicePriceSchema).min(1, 'At least one payment option is required'),
|
|
49
|
+
});
|
|
48
50
|
|
|
49
51
|
const DEFAULT_PAYMENT_OPTION = { paymentMode: '', price: 0 };
|
|
50
52
|
|
|
51
|
-
const AddBillableService: React.FC = () => {
|
|
53
|
+
const AddBillableService: React.FC<{ editingService?: any; onClose: () => void }> = ({ editingService, onClose }) => {
|
|
52
54
|
const { t } = useTranslation();
|
|
53
55
|
|
|
54
56
|
const { paymentModes, isLoading: isLoadingPaymentModes } = usePaymentModes();
|
|
55
57
|
const { serviceTypes, isLoading: isLoadingServicesTypes } = useServiceTypes();
|
|
56
|
-
const [billableServicePayload, setBillableServicePayload] = useState
|
|
58
|
+
const [billableServicePayload, setBillableServicePayload] = useState(editingService || {});
|
|
57
59
|
|
|
58
60
|
const {
|
|
59
61
|
control,
|
|
60
62
|
handleSubmit,
|
|
61
|
-
formState: { errors },
|
|
63
|
+
formState: { errors, isValid },
|
|
64
|
+
setValue,
|
|
62
65
|
} = useForm<any>({
|
|
63
66
|
mode: 'all',
|
|
64
|
-
defaultValues: {
|
|
67
|
+
defaultValues: {
|
|
68
|
+
name: editingService?.name,
|
|
69
|
+
serviceShortName: editingService?.shortName,
|
|
70
|
+
serviceType: editingService?.serviceType,
|
|
71
|
+
conceptsSearch: editingService?.concept,
|
|
72
|
+
payment: editingService?.servicePrices || [DEFAULT_PAYMENT_OPTION],
|
|
73
|
+
},
|
|
65
74
|
resolver: zodResolver(paymentFormSchema),
|
|
75
|
+
shouldUnregister: !editingService,
|
|
66
76
|
});
|
|
67
77
|
const { fields, remove, append } = useFieldArray({ name: 'payment', control: control });
|
|
68
78
|
|
|
@@ -86,50 +96,94 @@ const AddBillableService: React.FC = () => {
|
|
|
86
96
|
to: window.getOpenmrsSpaBase() + 'billable-services',
|
|
87
97
|
});
|
|
88
98
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (editingService && !isLoadingPaymentModes) {
|
|
101
|
+
setBillableServicePayload(editingService);
|
|
102
|
+
setValue('serviceName', editingService.name || '');
|
|
103
|
+
setValue('shortName', editingService.shortName || '');
|
|
104
|
+
setValue('serviceType', editingService.serviceType || '');
|
|
105
|
+
setValue(
|
|
106
|
+
'payment',
|
|
107
|
+
editingService.servicePrices.map((payment) => ({
|
|
108
|
+
paymentMode: payment.paymentMode?.uuid || '',
|
|
109
|
+
price: payment.price,
|
|
110
|
+
})),
|
|
111
|
+
);
|
|
112
|
+
setValue('conceptsSearch', editingService.concept);
|
|
113
|
+
|
|
114
|
+
if (editingService.concept) {
|
|
115
|
+
setSelectedConcept(editingService.concept);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}, [editingService, isLoadingPaymentModes, paymentModes, serviceTypes, setValue]);
|
|
119
|
+
|
|
120
|
+
const MAX_NAME_LENGTH = 19;
|
|
98
121
|
|
|
99
122
|
const onSubmit = (data) => {
|
|
100
|
-
const payload
|
|
123
|
+
const payload = {
|
|
124
|
+
name: billableServicePayload.name.substring(0, MAX_NAME_LENGTH),
|
|
125
|
+
shortName: billableServicePayload.shortName.substring(0, MAX_NAME_LENGTH),
|
|
126
|
+
serviceType: billableServicePayload.serviceType.uuid,
|
|
127
|
+
servicePrices: data.payment.map((payment) => {
|
|
128
|
+
const mode = paymentModes.find((m) => m.uuid === payment.paymentMode);
|
|
129
|
+
return {
|
|
130
|
+
paymentMode: payment.paymentMode,
|
|
131
|
+
name: mode?.name || 'Unknown',
|
|
132
|
+
price: parseFloat(payment.price),
|
|
133
|
+
};
|
|
134
|
+
}),
|
|
135
|
+
serviceStatus: 'ENABLED',
|
|
136
|
+
concept: selectedConcept?.uuid,
|
|
137
|
+
};
|
|
101
138
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
servicePrices.push(element);
|
|
106
|
-
});
|
|
107
|
-
payload.name = billableServicePayload.serviceName;
|
|
108
|
-
payload.shortName = billableServicePayload.shortName;
|
|
109
|
-
payload.serviceType = billableServicePayload.serviceType.uuid;
|
|
110
|
-
payload.servicePrices = servicePrices;
|
|
111
|
-
payload.serviceStatus = 'ENABLED';
|
|
112
|
-
payload.concept = selectedConcept?.concept?.uuid;
|
|
139
|
+
const saveAction = editingService
|
|
140
|
+
? updateBillableService(editingService.uuid, payload)
|
|
141
|
+
: createBillableSerice(payload);
|
|
113
142
|
|
|
114
|
-
|
|
143
|
+
saveAction.then(
|
|
115
144
|
(resp) => {
|
|
116
145
|
showSnackbar({
|
|
117
146
|
title: t('billableService', 'Billable service'),
|
|
118
|
-
subtitle:
|
|
147
|
+
subtitle: editingService
|
|
148
|
+
? t('updatedSuccessfully', 'Billable service updated successfully')
|
|
149
|
+
: t('createdSuccessfully', 'Billable service created successfully'),
|
|
119
150
|
kind: 'success',
|
|
120
151
|
timeoutInMs: 3000,
|
|
121
152
|
});
|
|
153
|
+
onClose();
|
|
122
154
|
handleNavigateToServiceDashboard();
|
|
123
155
|
},
|
|
124
156
|
(error) => {
|
|
125
|
-
showSnackbar({ title: 'Bill payment error', kind: 'error', subtitle: error?.message });
|
|
157
|
+
showSnackbar({ title: t('billPaymentError', 'Bill payment error'), kind: 'error', subtitle: error?.message });
|
|
126
158
|
},
|
|
127
159
|
);
|
|
128
160
|
};
|
|
129
161
|
|
|
162
|
+
const getPaymentErrorMessage = () => {
|
|
163
|
+
const paymentError = errors.payment;
|
|
164
|
+
if (paymentError && typeof paymentError.message === 'string') {
|
|
165
|
+
return paymentError.message;
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
if (isLoadingPaymentModes && isLoadingServicesTypes) {
|
|
171
|
+
return (
|
|
172
|
+
<InlineLoading
|
|
173
|
+
status="active"
|
|
174
|
+
iconDescription={t('loadingDescription', 'Loading')}
|
|
175
|
+
description={t('loading', 'Loading data...')}
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
130
180
|
return (
|
|
131
|
-
<Form className={styles.form}>
|
|
132
|
-
<h4>
|
|
181
|
+
<Form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
|
|
182
|
+
<h4>
|
|
183
|
+
{editingService
|
|
184
|
+
? t('editBillableServices', 'Edit Billable Services')
|
|
185
|
+
: t('addBillableServices', 'Add Billable Services')}
|
|
186
|
+
</h4>
|
|
133
187
|
<section className={styles.section}>
|
|
134
188
|
<Layer>
|
|
135
189
|
<TextInput
|
|
@@ -137,14 +191,24 @@ const AddBillableService: React.FC = () => {
|
|
|
137
191
|
type="text"
|
|
138
192
|
labelText={t('serviceName', 'Service Name')}
|
|
139
193
|
size="md"
|
|
140
|
-
|
|
194
|
+
value={billableServicePayload.name || ''}
|
|
195
|
+
onChange={(e) => {
|
|
196
|
+
const newName = e.target.value.substring(0, MAX_NAME_LENGTH);
|
|
141
197
|
setBillableServicePayload({
|
|
142
198
|
...billableServicePayload,
|
|
143
|
-
|
|
144
|
-
})
|
|
145
|
-
}
|
|
199
|
+
name: newName,
|
|
200
|
+
});
|
|
201
|
+
}}
|
|
146
202
|
placeholder="Enter service name"
|
|
203
|
+
maxLength={MAX_NAME_LENGTH}
|
|
147
204
|
/>
|
|
205
|
+
{billableServicePayload.name?.length >= MAX_NAME_LENGTH && (
|
|
206
|
+
<span className={styles.errorMessage}>
|
|
207
|
+
{t('serviceNameExceedsLimit', 'Service Name exceeds the character limit of {{MAX_NAME_LENGTH}}.', {
|
|
208
|
+
MAX_NAME_LENGTH,
|
|
209
|
+
})}
|
|
210
|
+
</span>
|
|
211
|
+
)}
|
|
148
212
|
</Layer>
|
|
149
213
|
</section>
|
|
150
214
|
<section className={styles.section}>
|
|
@@ -154,14 +218,24 @@ const AddBillableService: React.FC = () => {
|
|
|
154
218
|
type="text"
|
|
155
219
|
labelText={t('serviceShortName', 'Short Name')}
|
|
156
220
|
size="md"
|
|
157
|
-
|
|
221
|
+
value={billableServicePayload.shortName || ''}
|
|
222
|
+
onChange={(e) => {
|
|
223
|
+
const newShortName = e.target.value.substring(0, MAX_NAME_LENGTH);
|
|
158
224
|
setBillableServicePayload({
|
|
159
225
|
...billableServicePayload,
|
|
160
|
-
shortName:
|
|
161
|
-
})
|
|
162
|
-
}
|
|
226
|
+
shortName: newShortName,
|
|
227
|
+
});
|
|
228
|
+
}}
|
|
163
229
|
placeholder="Enter service short name"
|
|
230
|
+
maxLength={MAX_NAME_LENGTH}
|
|
164
231
|
/>
|
|
232
|
+
{billableServicePayload.shortName?.length >= MAX_NAME_LENGTH && (
|
|
233
|
+
<span className={styles.errorMessage}>
|
|
234
|
+
{t('shortNameExceedsLimit', 'Short Name exceeds the character limit of {{MAX_NAME_LENGTH}}.', {
|
|
235
|
+
MAX_NAME_LENGTH,
|
|
236
|
+
})}
|
|
237
|
+
</span>
|
|
238
|
+
)}
|
|
165
239
|
</Layer>
|
|
166
240
|
</section>
|
|
167
241
|
<section>
|
|
@@ -179,6 +253,7 @@ const AddBillableService: React.FC = () => {
|
|
|
179
253
|
placeholder={t('searchConcepts', 'Search associated concept')}
|
|
180
254
|
className={errors?.search && styles.serviceError}
|
|
181
255
|
onChange={(e) => {
|
|
256
|
+
setSearchTerm(e.target.value);
|
|
182
257
|
onChange(e);
|
|
183
258
|
handleSearchTermChange(e);
|
|
184
259
|
}}
|
|
@@ -200,6 +275,7 @@ const AddBillableService: React.FC = () => {
|
|
|
200
275
|
</ResponsiveWrapper>
|
|
201
276
|
)}
|
|
202
277
|
/>
|
|
278
|
+
|
|
203
279
|
{(() => {
|
|
204
280
|
if (!debouncedSearchTerm || selectedConcept) return null;
|
|
205
281
|
if (isSearching)
|
|
@@ -237,7 +313,8 @@ const AddBillableService: React.FC = () => {
|
|
|
237
313
|
id="serviceType"
|
|
238
314
|
items={serviceTypes ?? []}
|
|
239
315
|
titleText={t('serviceType', 'Service Type')}
|
|
240
|
-
itemToString={(item) => item?.display}
|
|
316
|
+
itemToString={(item) => item?.display || ''}
|
|
317
|
+
selectedItem={billableServicePayload.serviceType || null}
|
|
241
318
|
onChange={({ selectedItem }) => {
|
|
242
319
|
setBillableServicePayload({
|
|
243
320
|
...billableServicePayload,
|
|
@@ -261,11 +338,12 @@ const AddBillableService: React.FC = () => {
|
|
|
261
338
|
render={({ field }) => (
|
|
262
339
|
<Layer>
|
|
263
340
|
<Dropdown
|
|
264
|
-
onChange={({ selectedItem }) => field.onChange(selectedItem
|
|
341
|
+
onChange={({ selectedItem }) => field.onChange(selectedItem.uuid)}
|
|
265
342
|
titleText={t('paymentMode', 'Payment Mode')}
|
|
266
343
|
label={t('selectPaymentMethod', 'Select payment method')}
|
|
267
344
|
items={paymentModes ?? []}
|
|
268
345
|
itemToString={(item) => (item ? item.name : '')}
|
|
346
|
+
selectedItem={paymentModes.find((mode) => mode.uuid === field.value)}
|
|
269
347
|
invalid={!!errors?.payment?.[index]?.paymentMode}
|
|
270
348
|
invalidText={errors?.payment?.[index]?.paymentMode?.message}
|
|
271
349
|
/>
|
|
@@ -288,7 +366,7 @@ const AddBillableService: React.FC = () => {
|
|
|
288
366
|
)}
|
|
289
367
|
/>
|
|
290
368
|
<div className={styles.removeButtonContainer}>
|
|
291
|
-
<TrashCan onClick={handleRemovePaymentMode} className={styles.removeButton} size={20} />
|
|
369
|
+
<TrashCan onClick={() => handleRemovePaymentMode(index)} className={styles.removeButton} size={20} />
|
|
292
370
|
</div>
|
|
293
371
|
</div>
|
|
294
372
|
))}
|
|
@@ -300,14 +378,15 @@ const AddBillableService: React.FC = () => {
|
|
|
300
378
|
iconDescription="Add">
|
|
301
379
|
{t('addPaymentOptions', 'Add payment option')}
|
|
302
380
|
</Button>
|
|
381
|
+
{getPaymentErrorMessage() && <div className={styles.errorMessage}>{getPaymentErrorMessage()}</div>}
|
|
303
382
|
</div>
|
|
304
383
|
</section>
|
|
305
384
|
|
|
306
385
|
<section>
|
|
307
|
-
<Button kind="secondary" onClick={
|
|
386
|
+
<Button kind="secondary" onClick={onClose}>
|
|
308
387
|
{t('cancel', 'Cancel')}
|
|
309
388
|
</Button>
|
|
310
|
-
<Button type="submit"
|
|
389
|
+
<Button type="submit" disabled={!isValid || Object.keys(errors).length > 0}>
|
|
311
390
|
{t('save', 'Save')}
|
|
312
391
|
</Button>
|
|
313
392
|
</section>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
@use '@carbon/colors';
|
|
2
2
|
@use '@carbon/layout';
|
|
3
3
|
@use '@carbon/type';
|
|
4
|
-
@
|
|
4
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
5
5
|
|
|
6
6
|
.form {
|
|
7
7
|
display: flex;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
.container {
|
|
28
|
-
margin:
|
|
28
|
+
margin: layout.$spacing-05;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
.paymentContainer {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
display: grid;
|
|
44
44
|
grid-template-columns: repeat(4, minmax(auto, 1fr));
|
|
45
45
|
align-items: flex-start;
|
|
46
|
-
column-gap:
|
|
46
|
+
column-gap: layout.$spacing-05;
|
|
47
47
|
margin: 0.625rem 0;
|
|
48
48
|
width: 100%;
|
|
49
49
|
}
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
.service {
|
|
79
|
-
padding:
|
|
79
|
+
padding: layout.$spacing-05 layout.$spacing-04;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
.conceptsList {
|
|
@@ -93,17 +93,17 @@
|
|
|
93
93
|
.emptyResults {
|
|
94
94
|
@include type.type-style('body-compact-01');
|
|
95
95
|
color: $text-02;
|
|
96
|
-
min-height:
|
|
96
|
+
min-height: layout.$spacing-05;
|
|
97
97
|
border: 1px solid $ui-03;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
.conceptLabel {
|
|
101
101
|
@include type.type-style('label-02');
|
|
102
|
-
margin:
|
|
102
|
+
margin: layout.$spacing-05;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
.errorContainer {
|
|
106
|
-
margin:
|
|
106
|
+
margin: layout.$spacing-05;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
.serviceError {
|
|
@@ -126,6 +126,12 @@
|
|
|
126
126
|
|
|
127
127
|
.spinner {
|
|
128
128
|
&:global(.cds--inline-loading) {
|
|
129
|
-
min-height:
|
|
129
|
+
min-height: layout.$spacing-05;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
+
|
|
133
|
+
.errorMessage {
|
|
134
|
+
color: red;
|
|
135
|
+
font-size: 0.875rem;
|
|
136
|
+
}
|
|
137
|
+
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
2
|
import userEvent from '@testing-library/user-event';
|
|
4
|
-
import
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import { type FetchResponse, navigate } from '@openmrs/esm-framework';
|
|
5
5
|
import {
|
|
6
6
|
useBillableServices,
|
|
7
7
|
usePaymentModes,
|
|
8
8
|
useServiceTypes,
|
|
9
9
|
createBillableSerice,
|
|
10
10
|
} from '../billable-service.resource';
|
|
11
|
-
import
|
|
11
|
+
import AddBillableService from './add-billable-service.component';
|
|
12
12
|
|
|
13
13
|
const mockUseBillableServices = useBillableServices as jest.MockedFunction<typeof useBillableServices>;
|
|
14
14
|
const mockUsePaymentModes = usePaymentModes as jest.MockedFunction<typeof usePaymentModes>;
|
|
15
15
|
const mockUseServiceTypes = useServiceTypes as jest.MockedFunction<typeof useServiceTypes>;
|
|
16
16
|
const mockCreateBillableSerice = createBillableSerice as jest.MockedFunction<typeof createBillableSerice>;
|
|
17
17
|
const mockNavigate = navigate as jest.MockedFunction<typeof navigate>;
|
|
18
|
-
const mockShowSnackbar = showSnackbar as jest.MockedFunction<typeof showSnackbar>;
|
|
19
18
|
|
|
20
19
|
jest.mock('../billable-service.resource', () => ({
|
|
21
20
|
useBillableServices: jest.fn(),
|
|
@@ -57,6 +56,7 @@ xdescribe('AddBillableService', () => {
|
|
|
57
56
|
|
|
58
57
|
test('should render billable services form and generate correct payload', async () => {
|
|
59
58
|
const user = userEvent.setup();
|
|
59
|
+
const mockOnClose = jest.fn();
|
|
60
60
|
mockUseBillableServices.mockReturnValue({
|
|
61
61
|
billableServices: [],
|
|
62
62
|
isLoading: false,
|
|
@@ -66,10 +66,11 @@ xdescribe('AddBillableService', () => {
|
|
|
66
66
|
});
|
|
67
67
|
mockUsePaymentModes.mockReturnValue({ paymentModes: mockPaymentModes, error: null, isLoading: false });
|
|
68
68
|
mockUseServiceTypes.mockReturnValue({ serviceTypes: mockServiceTypes, error: false, isLoading: false });
|
|
69
|
-
render(<AddBillableService />);
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
render(<AddBillableService onClose={mockOnClose} />);
|
|
71
|
+
|
|
72
|
+
const formTitle = screen.getByRole('heading', { name: /Add Billable Services/i });
|
|
73
|
+
expect(formTitle).toBeInTheDocument();
|
|
73
74
|
|
|
74
75
|
const serviceNameTextInp = screen.getByRole('textbox', { name: /Service Name/i });
|
|
75
76
|
expect(serviceNameTextInp).toBeInTheDocument();
|
|
@@ -131,6 +132,7 @@ xdescribe('AddBillableService', () => {
|
|
|
131
132
|
|
|
132
133
|
test("should navigate back to billable services dashboard when 'Cancel' button is clicked", async () => {
|
|
133
134
|
const user = userEvent.setup();
|
|
135
|
+
const mockOnClose = jest.fn();
|
|
134
136
|
mockUseBillableServices.mockReturnValue({
|
|
135
137
|
billableServices: [],
|
|
136
138
|
isLoading: false,
|
|
@@ -140,13 +142,13 @@ xdescribe('AddBillableService', () => {
|
|
|
140
142
|
});
|
|
141
143
|
mockUsePaymentModes.mockReturnValue({ paymentModes: mockPaymentModes, error: null, isLoading: false });
|
|
142
144
|
mockUseServiceTypes.mockReturnValue({ serviceTypes: mockServiceTypes, error: false, isLoading: false });
|
|
143
|
-
|
|
145
|
+
|
|
146
|
+
render(<AddBillableService onClose={mockOnClose} />);
|
|
144
147
|
|
|
145
148
|
const cancelBtn = screen.getByRole('button', { name: /Cancel/i });
|
|
146
149
|
expect(cancelBtn).toBeInTheDocument();
|
|
147
150
|
await user.click(cancelBtn);
|
|
148
151
|
|
|
149
|
-
expect(
|
|
150
|
-
expect(mockNavigate).toHaveBeenCalledWith({ to: '/openmrs/spa/billable-services' });
|
|
152
|
+
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
|
151
153
|
});
|
|
152
154
|
});
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
@use '@carbon/type';
|
|
4
4
|
|
|
5
5
|
.container {
|
|
6
|
-
height: calc(100vh -
|
|
6
|
+
height: calc(100vh - layout.$spacing-09);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.servicesTableContainer {
|
|
10
|
-
margin:
|
|
10
|
+
margin: layout.$spacing-07 layout.$spacing-05;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
.illo {
|
|
@@ -22,6 +22,6 @@
|
|
|
22
22
|
|
|
23
23
|
.tile {
|
|
24
24
|
border: 1px solid colors.$gray-20;
|
|
25
|
-
padding:
|
|
25
|
+
padding: layout.$spacing-06 0;
|
|
26
26
|
text-align: center;
|
|
27
27
|
}
|