@openmrs/esm-billing-app 1.0.2-pre.880 → 1.0.2-pre.889

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 (102) hide show
  1. package/dist/1119.js +1 -1
  2. package/dist/1197.js +1 -1
  3. package/dist/1537.js +1 -0
  4. package/dist/1537.js.map +1 -0
  5. package/dist/2146.js +1 -1
  6. package/dist/2690.js +1 -1
  7. package/dist/3099.js +1 -1
  8. package/dist/3584.js +1 -1
  9. package/dist/4055.js +1 -1
  10. package/dist/4132.js +1 -1
  11. package/dist/4300.js +1 -1
  12. package/dist/4335.js +1 -1
  13. package/dist/4618.js +1 -1
  14. package/dist/4652.js +1 -1
  15. package/dist/{2372.js → 4692.js} +1 -1
  16. package/dist/4692.js.map +1 -0
  17. package/dist/4944.js +1 -1
  18. package/dist/5173.js +1 -1
  19. package/dist/5241.js +1 -1
  20. package/dist/5442.js +1 -1
  21. package/dist/5661.js +1 -1
  22. package/dist/6022.js +1 -1
  23. package/dist/6468.js +1 -1
  24. package/dist/6679.js +1 -1
  25. package/dist/6840.js +1 -1
  26. package/dist/6859.js +1 -1
  27. package/dist/7097.js +1 -1
  28. package/dist/7159.js +1 -1
  29. package/dist/723.js +1 -1
  30. package/dist/7617.js +1 -1
  31. package/dist/795.js +1 -1
  32. package/dist/8163.js +1 -1
  33. package/dist/8349.js +1 -1
  34. package/dist/8618.js +1 -1
  35. package/dist/890.js +1 -1
  36. package/dist/9214.js +1 -1
  37. package/dist/9538.js +1 -1
  38. package/dist/9569.js +1 -1
  39. package/dist/986.js +1 -1
  40. package/dist/9879.js +1 -1
  41. package/dist/9895.js +1 -1
  42. package/dist/9900.js +1 -1
  43. package/dist/9913.js +1 -1
  44. package/dist/main.js +1 -1
  45. package/dist/main.js.map +1 -1
  46. package/dist/openmrs-esm-billing-app.js +1 -1
  47. package/dist/openmrs-esm-billing-app.js.buildmanifest.json +169 -145
  48. package/dist/routes.json +1 -1
  49. package/package.json +2 -2
  50. package/src/billable-services/{create-edit/add-billable-service.scss → billable-service-form/billable-service-form.scss} +30 -1
  51. package/src/billable-services/{create-edit/add-billable-service.test.tsx → billable-service-form/billable-service-form.test.tsx} +178 -82
  52. package/src/billable-services/{create-edit/add-billable-service.component.tsx → billable-service-form/billable-service-form.workspace.tsx} +63 -47
  53. package/src/billable-services/billable-services-home.component.tsx +2 -8
  54. package/src/billable-services/billable-services-left-panel-menu.component.tsx +1 -1
  55. package/src/billable-services/billable-services-menu-item/item.component.tsx +5 -4
  56. package/src/billable-services/billable-services.component.tsx +14 -11
  57. package/src/billable-services/cash-point/add-cash-point.modal.tsx +47 -45
  58. package/src/billable-services-admin-card-link.component.test.tsx +2 -2
  59. package/src/billable-services-admin-card-link.component.tsx +1 -1
  60. package/src/index.ts +8 -4
  61. package/src/routes.json +7 -4
  62. package/translations/am.json +7 -2
  63. package/translations/ar.json +7 -2
  64. package/translations/ar_SY.json +7 -2
  65. package/translations/bn.json +7 -2
  66. package/translations/de.json +7 -2
  67. package/translations/en.json +7 -2
  68. package/translations/en_US.json +7 -2
  69. package/translations/es.json +7 -2
  70. package/translations/es_MX.json +7 -2
  71. package/translations/fr.json +7 -2
  72. package/translations/he.json +7 -2
  73. package/translations/hi.json +7 -2
  74. package/translations/hi_IN.json +7 -2
  75. package/translations/id.json +7 -2
  76. package/translations/it.json +7 -2
  77. package/translations/ka.json +7 -2
  78. package/translations/km.json +7 -2
  79. package/translations/ku.json +7 -2
  80. package/translations/ky.json +7 -2
  81. package/translations/lg.json +7 -2
  82. package/translations/ne.json +7 -2
  83. package/translations/pl.json +7 -2
  84. package/translations/pt.json +7 -2
  85. package/translations/pt_BR.json +7 -2
  86. package/translations/qu.json +7 -2
  87. package/translations/ro_RO.json +7 -2
  88. package/translations/ru_RU.json +7 -2
  89. package/translations/si.json +7 -2
  90. package/translations/sw.json +7 -2
  91. package/translations/sw_KE.json +7 -2
  92. package/translations/tr.json +7 -2
  93. package/translations/tr_TR.json +7 -2
  94. package/translations/uk.json +7 -2
  95. package/translations/uz.json +7 -2
  96. package/translations/uz@Latn.json +7 -2
  97. package/translations/uz_UZ.json +7 -2
  98. package/translations/vi.json +7 -2
  99. package/translations/zh.json +7 -2
  100. package/translations/zh_CN.json +7 -2
  101. package/dist/2372.js.map +0 -1
  102. package/src/billable-services/create-edit/edit-billable-service.modal.tsx +0 -51
@@ -1,9 +1,11 @@
1
1
  import React, { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import {
3
3
  Button,
4
+ ButtonSet,
4
5
  ComboBox,
5
6
  Dropdown,
6
7
  Form,
8
+ FormGroup,
7
9
  FormLabel,
8
10
  InlineLoading,
9
11
  Layer,
@@ -19,7 +21,13 @@ import { useTranslation } from 'react-i18next';
19
21
  import { Add, TrashCan } from '@carbon/react/icons';
20
22
  import { z } from 'zod';
21
23
  import { zodResolver } from '@hookform/resolvers/zod';
22
- import { getCoreTranslation, navigate, ResponsiveWrapper, showSnackbar, useDebounce } from '@openmrs/esm-framework';
24
+ import {
25
+ getCoreTranslation,
26
+ ResponsiveWrapper,
27
+ showSnackbar,
28
+ useDebounce,
29
+ useLayoutType,
30
+ } from '@openmrs/esm-framework';
23
31
  import type { BillableService, ServicePrice } from '../../types';
24
32
  import {
25
33
  createBillableService,
@@ -28,13 +36,14 @@ import {
28
36
  usePaymentModes,
29
37
  useServiceTypes,
30
38
  } from '../billable-service.resource';
31
- import styles from './add-billable-service.scss';
39
+ import styles from './billable-service-form.scss';
32
40
 
33
- interface AddBillableServiceProps {
41
+ interface BillableServiceFormWorkspaceProps {
34
42
  serviceToEdit?: BillableService;
35
- onClose: () => void;
36
- onServiceUpdated?: () => void;
37
- isModal?: boolean;
43
+ closeWorkspace: () => void;
44
+ closeWorkspaceWithSavedChanges?: () => void;
45
+ promptBeforeClosing?: (testFcn: () => boolean) => void;
46
+ onWorkspaceClose?: () => void;
38
47
  }
39
48
 
40
49
  interface BillableServiceFormData {
@@ -163,13 +172,15 @@ const createBillableServiceSchema = (t: TFunction) => {
163
172
  });
164
173
  };
165
174
 
166
- const AddBillableService: React.FC<AddBillableServiceProps> = ({
175
+ const BillableServiceFormWorkspace: React.FC<BillableServiceFormWorkspaceProps> = ({
167
176
  serviceToEdit,
168
- onClose,
169
- onServiceUpdated,
170
- isModal = false,
177
+ closeWorkspace,
178
+ closeWorkspaceWithSavedChanges,
179
+ onWorkspaceClose,
171
180
  }) => {
172
181
  const { t } = useTranslation();
182
+ const layout = useLayoutType();
183
+ const isTablet = layout === 'tablet';
173
184
  const { paymentModes, isLoadingPaymentModes } = usePaymentModes();
174
185
  const { serviceTypes, isLoadingServiceTypes } = useServiceTypes();
175
186
 
@@ -192,17 +203,13 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
192
203
  const handleRemovePaymentMode = (index: number) => remove(index);
193
204
 
194
205
  const searchInputRef = useRef(null);
206
+ const [isSubmitting, setIsSubmitting] = useState(false);
195
207
 
196
208
  const selectedConcept = useWatch({ control, name: 'concept' });
197
209
  const [searchTerm, setSearchTerm] = useState('');
198
210
  const debouncedSearchTerm = useDebounce(searchTerm.trim());
199
211
  const { searchResults, isSearching } = useConceptsSearch(debouncedSearchTerm);
200
212
 
201
- const handleNavigateToServiceDashboard = () =>
202
- navigate({
203
- to: window.getOpenmrsSpaBase() + 'billable-services',
204
- });
205
-
206
213
  // Re-initialize form when editing and dependencies load
207
214
  // Needed because serviceTypes/paymentModes may not be available during initial render
208
215
  useEffect(() => {
@@ -212,6 +219,8 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
212
219
  }, [serviceToEdit, isLoadingPaymentModes, isLoadingServiceTypes, reset]);
213
220
 
214
221
  const onSubmit = async (data: BillableServiceFormData) => {
222
+ setIsSubmitting(true);
223
+
215
224
  const payload = {
216
225
  name: data.name,
217
226
  shortName: data.shortName || '',
@@ -236,27 +245,34 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
236
245
  }
237
246
 
238
247
  showSnackbar({
239
- title: t('billableService', 'Billable service'),
248
+ title: serviceToEdit
249
+ ? t('billableServiceUpdated', 'Billable service updated')
250
+ : t('billableServiceCreated', 'Billable service created'),
240
251
  subtitle: serviceToEdit
241
- ? t('updatedSuccessfully', 'Billable service updated successfully')
242
- : t('createdSuccessfully', 'Billable service created successfully'),
252
+ ? t('billableServiceUpdatedSuccessfully', 'Billable service updated successfully')
253
+ : t('billableServiceCreatedSuccessfully', 'Billable service created successfully'),
243
254
  kind: 'success',
244
255
  });
245
256
 
246
- if (serviceToEdit) {
247
- onClose();
257
+ // Call onWorkspaceClose callback to refresh data in parent component
258
+ if (onWorkspaceClose) {
259
+ onWorkspaceClose();
248
260
  }
249
261
 
250
- if (onServiceUpdated) {
251
- onServiceUpdated();
262
+ // Close the workspace
263
+ if (closeWorkspaceWithSavedChanges) {
264
+ closeWorkspaceWithSavedChanges();
265
+ } else {
266
+ closeWorkspace();
252
267
  }
253
- handleNavigateToServiceDashboard();
254
268
  } catch (error) {
255
269
  showSnackbar({
256
270
  title: t('billPaymentError', 'Bill payment error'),
257
271
  kind: 'error',
258
272
  subtitle: error instanceof Error ? error.message : String(error),
259
273
  });
274
+ } finally {
275
+ setIsSubmitting(false);
260
276
  }
261
277
  };
262
278
 
@@ -279,14 +295,13 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
279
295
  }
280
296
 
281
297
  return (
282
- <Form id="billable-service-form" className={styles.form} onSubmit={handleSubmit(onSubmit)}>
283
- <Stack gap={5}>
284
- <h4>
285
- {serviceToEdit
286
- ? t('editBillableService', 'Edit billable service')
287
- : t('addBillableService', 'Add billable service')}
288
- </h4>
289
- <section>
298
+ <Form
299
+ aria-label={t('billableServiceForm', 'Billable service form')}
300
+ className={styles.form}
301
+ id="billable-service-form"
302
+ onSubmit={handleSubmit(onSubmit)}>
303
+ <Stack className={styles.stack} gap={5}>
304
+ <FormGroup className={styles.formGroup}>
290
305
  {serviceToEdit ? (
291
306
  <FormLabel className={styles.serviceNameLabel}>{serviceToEdit.name}</FormLabel>
292
307
  ) : (
@@ -310,8 +325,8 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
310
325
  )}
311
326
  />
312
327
  )}
313
- </section>
314
- <section>
328
+ </FormGroup>
329
+ <FormGroup>
315
330
  <Controller
316
331
  name="shortName"
317
332
  control={control}
@@ -332,8 +347,8 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
332
347
  </Layer>
333
348
  )}
334
349
  />
335
- </section>
336
- <section>
350
+ </FormGroup>
351
+ <FormGroup>
337
352
  <FormLabel className={styles.conceptLabel}>{t('associatedConcept', 'Associated concept')}</FormLabel>
338
353
  <ResponsiveWrapper>
339
354
  <Search
@@ -386,8 +401,8 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
386
401
  </Layer>
387
402
  );
388
403
  })()}
389
- </section>
390
- <section>
404
+ </FormGroup>
405
+ <FormGroup>
391
406
  <Controller
392
407
  name="serviceType"
393
408
  control={control}
@@ -409,7 +424,7 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
409
424
  </Layer>
410
425
  )}
411
426
  />
412
- </section>
427
+ </FormGroup>
413
428
  <section>
414
429
  <div>
415
430
  {fields.map((field, index) => (
@@ -440,6 +455,7 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
440
455
  <Layer>
441
456
  <NumberInput
442
457
  allowEmpty
458
+ disableWheel
443
459
  id={`price-${index}`}
444
460
  invalid={!!errors?.payment?.[index]?.price}
445
461
  invalidText={errors?.payment?.[index]?.price?.message}
@@ -473,16 +489,16 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
473
489
  </div>
474
490
  </section>
475
491
  </Stack>
476
- {!isModal && (
477
- <section>
478
- <Button kind="secondary" onClick={onClose}>
479
- {getCoreTranslation('cancel')}
480
- </Button>
481
- <Button type="submit">{getCoreTranslation('save')}</Button>
482
- </section>
483
- )}
492
+ <ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
493
+ <Button className={styles.button} kind="secondary" disabled={isSubmitting} onClick={closeWorkspace}>
494
+ {getCoreTranslation('cancel')}
495
+ </Button>
496
+ <Button className={styles.button} kind="primary" disabled={isSubmitting} type="submit">
497
+ {isSubmitting ? <InlineLoading description={t('saving', 'Saving') + '...'} /> : getCoreTranslation('save')}
498
+ </Button>
499
+ </ButtonSet>
484
500
  </Form>
485
501
  );
486
502
  };
487
503
 
488
- export default AddBillableService;
504
+ export default BillableServiceFormWorkspace;
@@ -2,8 +2,7 @@ import React from 'react';
2
2
  import classNames from 'classnames';
3
3
  import { BrowserRouter, Routes, Route } from 'react-router-dom';
4
4
  import { useTranslation } from 'react-i18next';
5
- import { useLeftNav, navigate, WorkspaceContainer, useLayoutType, isDesktop } from '@openmrs/esm-framework';
6
- import AddBillableService from './create-edit/add-billable-service.component';
5
+ import { useLeftNav, WorkspaceContainer, useLayoutType, isDesktop } from '@openmrs/esm-framework';
7
6
  import BillWaiver from './bill-waiver/bill-waiver.component';
8
7
  import BillableServicesDashboard from './dashboard/dashboard.component';
9
8
  import BillingHeader from '../billing-header/billing-header.component';
@@ -18,10 +17,6 @@ const BillableServiceHome: React.FC = () => {
18
17
 
19
18
  useLeftNav({ name: 'billable-services-left-panel-slot', basePath });
20
19
 
21
- const handleCloseAddService = () => {
22
- navigate({ to: `${basePath}` });
23
- };
24
-
25
20
  return (
26
21
  <BrowserRouter basename={basePath}>
27
22
  <div className={styles.pageWrapper}>
@@ -29,10 +24,9 @@ const BillableServiceHome: React.FC = () => {
29
24
  <BillingHeader title={t('billableServicesManagement', 'Billable services management')} />
30
25
  <Routes>
31
26
  <Route path="/" element={<BillableServicesDashboard />} />
32
- <Route path="/add-service" element={<AddBillableService onClose={handleCloseAddService} />} />
33
- <Route path="/waive-bill" element={<BillWaiver />} />
34
27
  <Route path="/cash-point-config" element={<CashPointConfiguration />} />
35
28
  <Route path="/payment-modes-config" element={<PaymentModesConfig />} />
29
+ <Route path="/waive-bill" element={<BillWaiver />} />
36
30
  </Routes>
37
31
  </main>
38
32
  </div>
@@ -23,7 +23,7 @@ function BillableServicesMenuExtension({ config }: { config: BillableServicesMen
23
23
  };
24
24
 
25
25
  const menu = (
26
- <SideNavMenu title={title} renderIcon={Icon}>
26
+ <SideNavMenu defaultExpanded title={title} renderIcon={Icon}>
27
27
  {items.map((item) => (
28
28
  <SideNavMenuItem key={item.name} onClick={() => handleNavigation(item.path)}>
29
29
  {item.title}
@@ -1,16 +1,17 @@
1
- import { ClickableTile } from '@carbon/react';
2
1
  import React from 'react';
3
- import styles from './item.scss';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { ClickableTile } from '@carbon/react';
4
4
  import { Receipt } from '@carbon/react/icons';
5
+ import styles from './item.scss';
5
6
 
6
7
  const Item = () => {
7
- // items
8
+ const { t } = useTranslation();
8
9
  const openmrsSpaBase = window['getOpenmrsSpaBase']();
9
10
 
10
11
  return (
11
12
  <ClickableTile className={styles.customTile} id="menu-item" href={`${openmrsSpaBase}billable-services`}>
12
13
  <div className="customTileTitle">{<Receipt size={24} />}</div>
13
- <div>Billable Services</div>
14
+ <div>{t('billableServices', 'Billable services')}</div>
14
15
  </ClickableTile>
15
16
  );
16
17
  };
@@ -24,17 +24,16 @@ import {
24
24
  ErrorState,
25
25
  getCoreTranslation,
26
26
  isDesktop,
27
- navigate,
28
- showModal,
27
+ launchWorkspace,
29
28
  useConfig,
30
29
  useLayoutType,
31
30
  usePagination,
32
31
  type LayoutType,
33
32
  } from '@openmrs/esm-framework';
34
33
  import { EmptyState } from '@openmrs/esm-patient-common-lib';
35
- import { type BillableService } from '../types/index';
34
+ import { type BillableService } from '../types';
35
+ import { type BillingConfig } from '../config-schema';
36
36
  import { useBillableServices } from './billable-service.resource';
37
- import type { BillingConfig } from '../config-schema';
38
37
  import styles from './billable-services.scss';
39
38
 
40
39
  interface FilterableTableHeaderProps {
@@ -79,8 +78,10 @@ const BillableServices = () => {
79
78
  ];
80
79
 
81
80
  const launchBillableServiceForm = useCallback(() => {
82
- navigate({ to: window.getOpenmrsSpaBase() + 'billable-services/add-service' });
83
- }, []);
81
+ launchWorkspace('billable-service-form', {
82
+ workspaceTitle: t('addBillableService', 'Add billable service'),
83
+ });
84
+ }, [t]);
84
85
 
85
86
  const searchResults: BillableService[] = useMemo(() => {
86
87
  const flatBillableServices = Array.isArray(billableServices) ? billableServices.flat() : billableServices;
@@ -127,13 +128,13 @@ const BillableServices = () => {
127
128
 
128
129
  const handleEditService = useCallback(
129
130
  (service: BillableService) => {
130
- const dispose = showModal('edit-billable-service-modal', {
131
+ launchWorkspace('billable-service-form', {
132
+ workspaceTitle: t('editBillableService', 'Edit billable service'),
131
133
  serviceToEdit: service,
132
- onServiceUpdated: mutate,
133
- closeModal: () => dispose(),
134
+ onWorkspaceClose: mutate,
134
135
  });
135
136
  },
136
- [mutate],
137
+ [mutate, t],
137
138
  );
138
139
 
139
140
  if (isLoading) {
@@ -282,7 +283,9 @@ function FilterableTableHeader({ layout, handleSearch, isValidating, responsiveS
282
283
  kind="primary"
283
284
  renderIcon={(props) => <ArrowRight size={16} {...props} />}
284
285
  onClick={() => {
285
- navigate({ to: window.getOpenmrsSpaBase() + 'billable-services/add-service' });
286
+ launchWorkspace('billable-service-form', {
287
+ workspaceTitle: t('addBillableService', 'Add billable service'),
288
+ });
286
289
  }}
287
290
  iconDescription={t('addNewBillableService', 'Add new billable service')}>
288
291
  {t('addNewService', 'Add new service')}
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
3
3
  import { useForm, Controller } from 'react-hook-form';
4
4
  import { z } from 'zod';
5
5
  import { zodResolver } from '@hookform/resolvers/zod';
6
- import { Button, Dropdown, Form, ModalBody, ModalFooter, ModalHeader, TextInput } from '@carbon/react';
6
+ import { Button, Dropdown, Form, ModalBody, ModalFooter, ModalHeader, Stack, TextInput } from '@carbon/react';
7
7
  import { showSnackbar, openmrsFetch, restBaseUrl, getCoreTranslation } from '@openmrs/esm-framework';
8
8
 
9
9
  type CashPointFormValues = {
@@ -107,50 +107,52 @@ const AddCashPointModal: React.FC<AddCashPointModalProps> = ({ closeModal, onCas
107
107
  <ModalHeader closeModal={closeModal} title={t('addCashPoint', 'Add Cash Point')} />
108
108
  <Form onSubmit={handleSubmit(onSubmit)}>
109
109
  <ModalBody>
110
- <Controller
111
- name="name"
112
- control={control}
113
- render={({ field }) => (
114
- <TextInput
115
- id="cash-point-name"
116
- labelText={t('cashPointName', 'Cash Point Name')}
117
- placeholder={t('cashPointNamePlaceholder', 'For example, Pharmacy Cash Point')}
118
- invalid={!!errors.name}
119
- invalidText={errors.name?.message}
120
- {...field}
121
- />
122
- )}
123
- />
124
- <Controller
125
- name="uuid"
126
- control={control}
127
- render={({ field }) => (
128
- <TextInput
129
- id="cash-point-uuid"
130
- labelText={t('cashPointUuid', 'Cash Point UUID')}
131
- placeholder={t('cashPointUuidPlaceholder', 'Enter UUID')}
132
- invalid={!!errors.uuid}
133
- invalidText={errors.uuid?.message}
134
- {...field}
135
- />
136
- )}
137
- />
138
- <Controller
139
- name="location"
140
- control={control}
141
- render={({ field }) => (
142
- <Dropdown
143
- id="cash-point-location"
144
- label={t('selectLocation', 'Select Location')}
145
- titleText={t('cashPointLocation', 'Cash Point Location')}
146
- items={locations}
147
- selectedItem={locations.find((loc) => loc.id === field.value)}
148
- onChange={({ selectedItem }) => field.onChange(selectedItem?.id)}
149
- invalid={!!errors.location}
150
- invalidText={errors.location?.message}
151
- />
152
- )}
153
- />
110
+ <Stack gap={5}>
111
+ <Controller
112
+ name="name"
113
+ control={control}
114
+ render={({ field }) => (
115
+ <TextInput
116
+ id="cash-point-name"
117
+ labelText={t('cashPointName', 'Cash Point Name')}
118
+ placeholder={t('cashPointNamePlaceholder', 'For example, Pharmacy Cash Point')}
119
+ invalid={!!errors.name}
120
+ invalidText={errors.name?.message}
121
+ {...field}
122
+ />
123
+ )}
124
+ />
125
+ <Controller
126
+ name="uuid"
127
+ control={control}
128
+ render={({ field }) => (
129
+ <TextInput
130
+ id="cash-point-uuid"
131
+ labelText={t('cashPointUuid', 'Cash Point UUID')}
132
+ placeholder={t('cashPointUuidPlaceholder', 'Enter UUID')}
133
+ invalid={!!errors.uuid}
134
+ invalidText={errors.uuid?.message}
135
+ {...field}
136
+ />
137
+ )}
138
+ />
139
+ <Controller
140
+ name="location"
141
+ control={control}
142
+ render={({ field }) => (
143
+ <Dropdown
144
+ id="cash-point-location"
145
+ label={t('selectLocation', 'Select Location')}
146
+ titleText={t('cashPointLocation', 'Cash Point Location')}
147
+ items={locations}
148
+ selectedItem={locations.find((loc) => loc.id === field.value)}
149
+ onChange={({ selectedItem }) => field.onChange(selectedItem?.id)}
150
+ invalid={!!errors.location}
151
+ invalidText={errors.location?.message}
152
+ />
153
+ )}
154
+ />
155
+ </Stack>
154
156
  </ModalBody>
155
157
  <ModalFooter>
156
158
  <Button kind="secondary" onClick={closeModal}>
@@ -8,10 +8,10 @@ describe('BillableServicesCardLink', () => {
8
8
  const manageBillableServicesText = screen.getByText('Manage billable services');
9
9
  expect(manageBillableServicesText).toHaveClass('heading');
10
10
 
11
- const billiableText = screen.getByText('Billable Services');
11
+ const billiableText = screen.getByText('Billable services', { exact: true });
12
12
  expect(billiableText).toHaveClass('content');
13
13
 
14
- const billiableServiceLink = screen.getByRole('link', { name: /Billable Services/i });
14
+ const billiableServiceLink = screen.getByRole('link', { name: /Manage billable services/i });
15
15
  expect(billiableServiceLink).toHaveAttribute('href', '/spa/billable-services');
16
16
  });
17
17
  });
@@ -12,7 +12,7 @@ const BillableServicesCardLink: React.FC = () => {
12
12
  <ClickableTile href={`${window.spaBase}/billable-services`} target="_blank" rel="noopener noreferrer">
13
13
  <div>
14
14
  <div className="heading">{header}</div>
15
- <div className="content">{t('billableServices', 'Billable Services')}</div>
15
+ <div className="content">{t('billableServices', 'Billable services')}</div>
16
16
  </div>
17
17
  <div className="iconWrapper">
18
18
  <ArrowRight size={16} />
package/src/index.ts CHANGED
@@ -14,7 +14,6 @@ import BillableServicesCardLink from './billable-services-admin-card-link.compon
14
14
  import BillHistory from './bill-history/bill-history.component';
15
15
  import BillingCheckInForm from './billing-form/billing-checkin-form.component';
16
16
  import DeletePaymentModeModal from './billable-services/payment-modes/delete-payment-mode.modal';
17
- import EditBillableServiceModal from './billable-services/create-edit/edit-billable-service.modal';
18
17
  import EditBillLineItemModal from './bill-item-actions/edit-bill-item.modal';
19
18
  import RequirePaymentModal from './modal/require-payment.modal';
20
19
  import RootComponent from './root.component';
@@ -48,6 +47,7 @@ export const billingSummaryDashboardLink = getSyncLifecycle(
48
47
  options,
49
48
  );
50
49
 
50
+ // t('billableServices', 'Billable services')
51
51
  export const billableServicesAppMenuItem = getSyncLifecycle(appMenu, options);
52
52
 
53
53
  export const billableServicesCardLink = getSyncLifecycle(BillableServicesCardLink, options);
@@ -66,8 +66,6 @@ export const deletePaymentModeModal = getSyncLifecycle(DeletePaymentModeModal, o
66
66
 
67
67
  export const addCashPointModal = getSyncLifecycle(AddCashPointModal, options);
68
68
 
69
- export const editBillableServiceModal = getSyncLifecycle(EditBillableServiceModal, options);
70
-
71
69
  export const editBillLineItemModal = getSyncLifecycle(EditBillLineItemModal, options);
72
70
 
73
71
  export const root = getSyncLifecycle(RootComponent, options);
@@ -77,7 +75,13 @@ export const visitAttributeTags = getSyncLifecycle(VisitAttributeTags, options);
77
75
  // t('billingForm', 'Billing form')
78
76
  export const billingFormWorkspace = getAsyncLifecycle(() => import('./billing-form/billing-form.component'), options);
79
77
 
80
- // t('billableServices', 'Billable Services')
78
+ // t('billableServiceForm', 'Billable service form')
79
+ export const billableServiceFormWorkspace = getAsyncLifecycle(
80
+ () => import('./billable-services/billable-service-form/billable-service-form.workspace'),
81
+ options,
82
+ );
83
+
84
+ // t('billableServices', 'Billable services')
81
85
  export const billableServicesLeftPanelLink = getSyncLifecycle(
82
86
  createBillableServicesLeftPanelLink({
83
87
  name: 'billable-services',
package/src/routes.json CHANGED
@@ -114,10 +114,6 @@
114
114
  "name": "edit-bill-line-item-modal",
115
115
  "component": "editBillLineItemModal"
116
116
  },
117
- {
118
- "name": "edit-billable-service-modal",
119
- "component": "editBillableServiceModal"
120
- },
121
117
  {
122
118
  "name": "require-billing-modal",
123
119
  "component": "requirePaymentModal"
@@ -129,6 +125,13 @@
129
125
  "title": "billingForm",
130
126
  "component": "billingFormWorkspace",
131
127
  "type": "form"
128
+ },
129
+ {
130
+ "name": "billable-service-form",
131
+ "title": "billableServiceForm",
132
+ "component": "billableServiceFormWorkspace",
133
+ "type": "form",
134
+ "width": "wider"
132
135
  }
133
136
  ],
134
137
  "featureFlags": [
@@ -20,9 +20,14 @@
20
20
  "amountToWaiveLabel": "Amount to waive",
21
21
  "associatedConcept": "Associated concept",
22
22
  "billableService": "Billable service",
23
+ "billableServiceCreated": "Billable service created",
24
+ "billableServiceCreatedSuccessfully": "Billable service created successfully",
25
+ "billableServiceForm": "Billable service form",
23
26
  "billableServices": "Billable services",
24
27
  "billableServices__lower": "billable services",
25
28
  "billableServicesManagement": "Billable services management",
29
+ "billableServiceUpdated": "Billable service updated",
30
+ "billableServiceUpdatedSuccessfully": "Billable service updated successfully",
26
31
  "billAmount": "Bill amount",
27
32
  "billCode": "Bill code",
28
33
  "billCreatedSuccessfully": "Bill created successfully",
@@ -197,14 +202,14 @@
197
202
  "sellingPrice": "Selling price",
198
203
  "serviceList": "Service list",
199
204
  "serviceName": "Service name",
200
- "serviceNameExceedsLimit": "Service name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
205
+ "serviceNameExceedsLimit": "Service name cannot exceed {{MAX_NAME_LENGTH}} characters",
201
206
  "serviceNameRequired": "Service name is required",
202
207
  "servicesList": "Services list",
203
208
  "serviceStatus": "Service status",
204
209
  "serviceType": "Service type",
205
210
  "serviceTypeRequired": "Service type is required",
206
211
  "shortName": "Short name",
207
- "shortNameExceedsLimit": "Short name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
212
+ "shortNameExceedsLimit": "Short name cannot exceed {{MAX_NAME_LENGTH}} characters",
208
213
  "status": "Service status",
209
214
  "submitting": "Submitting",
210
215
  "success": "Success",
@@ -20,9 +20,14 @@
20
20
  "amountToWaiveLabel": "Amount to waive",
21
21
  "associatedConcept": "Associated concept",
22
22
  "billableService": "Billable service",
23
+ "billableServiceCreated": "Billable service created",
24
+ "billableServiceCreatedSuccessfully": "Billable service created successfully",
25
+ "billableServiceForm": "Billable service form",
23
26
  "billableServices": "Billable services",
24
27
  "billableServices__lower": "billable services",
25
28
  "billableServicesManagement": "Billable services management",
29
+ "billableServiceUpdated": "Billable service updated",
30
+ "billableServiceUpdatedSuccessfully": "Billable service updated successfully",
26
31
  "billAmount": "Bill amount",
27
32
  "billCode": "Bill code",
28
33
  "billCreatedSuccessfully": "Bill created successfully",
@@ -197,14 +202,14 @@
197
202
  "sellingPrice": "Selling price",
198
203
  "serviceList": "Service list",
199
204
  "serviceName": "Service name",
200
- "serviceNameExceedsLimit": "Service name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
205
+ "serviceNameExceedsLimit": "Service name cannot exceed {{MAX_NAME_LENGTH}} characters",
201
206
  "serviceNameRequired": "Service name is required",
202
207
  "servicesList": "Services list",
203
208
  "serviceStatus": "Service status",
204
209
  "serviceType": "Service type",
205
210
  "serviceTypeRequired": "Service type is required",
206
211
  "shortName": "Short name",
207
- "shortNameExceedsLimit": "Short name exceeds the character limit of {{MAX_NAME_LENGTH}}.",
212
+ "shortNameExceedsLimit": "Short name cannot exceed {{MAX_NAME_LENGTH}} characters",
208
213
  "status": "Service status",
209
214
  "submitting": "Submitting",
210
215
  "success": "Success",