@openmrs/esm-billing-app 1.0.2-pre.90 → 1.0.2-pre.901
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/.eslintrc +16 -2
- package/README.md +54 -9
- package/__mocks__/bills.mock.ts +12 -0
- package/__mocks__/react-i18next.js +6 -5
- package/dist/1119.js +1 -1
- package/dist/1146.js +1 -2
- package/dist/1146.js.map +1 -1
- package/dist/1197.js +1 -1
- package/dist/1537.js +1 -0
- package/dist/1537.js.map +1 -0
- package/dist/1856.js +1 -0
- package/dist/1856.js.map +1 -0
- package/dist/2146.js +1 -1
- package/dist/2524.js +1 -0
- package/dist/2524.js.map +1 -0
- package/dist/2690.js +1 -1
- package/dist/3099.js +1 -1
- package/dist/3584.js +1 -1
- package/dist/3717.js +2 -0
- package/dist/3717.js.map +1 -0
- package/dist/4055.js +1 -1
- package/dist/4132.js +1 -1
- package/dist/4300.js +1 -1
- package/dist/4335.js +1 -1
- package/dist/4618.js +1 -1
- package/dist/4652.js +1 -1
- package/dist/4692.js +1 -0
- package/dist/4692.js.map +1 -0
- package/dist/4724.js +1 -0
- package/dist/4724.js.map +1 -0
- package/dist/4739.js +1 -1
- package/dist/4739.js.map +1 -1
- package/dist/4944.js +1 -1
- package/dist/5173.js +1 -1
- package/dist/5241.js +1 -1
- package/dist/5442.js +1 -1
- package/dist/5661.js +1 -1
- package/dist/6022.js +1 -1
- package/dist/6468.js +1 -1
- package/dist/6540.js +1 -1
- package/dist/6540.js.map +1 -1
- package/dist/6679.js +1 -1
- package/dist/6840.js +1 -1
- package/dist/6859.js +1 -1
- package/dist/7097.js +1 -1
- package/dist/7159.js +1 -1
- package/dist/723.js +1 -1
- package/dist/7255.js +1 -1
- package/dist/7255.js.map +1 -1
- package/dist/7617.js +1 -1
- package/dist/795.js +1 -1
- package/dist/8163.js +1 -1
- package/dist/8349.js +1 -1
- package/dist/8618.js +1 -1
- package/dist/8708.js +2 -0
- package/dist/{6557.js.LICENSE.txt → 8708.js.LICENSE.txt} +22 -0
- package/dist/8708.js.map +1 -0
- package/dist/890.js +1 -1
- package/dist/9214.js +1 -1
- package/dist/9538.js +1 -1
- package/dist/9569.js +1 -1
- package/dist/961.js +1 -1
- package/dist/961.js.map +1 -1
- package/dist/986.js +1 -1
- package/dist/9879.js +1 -1
- package/dist/9895.js +1 -1
- package/dist/9900.js +1 -1
- package/dist/9913.js +1 -1
- package/dist/main.js +1 -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 +282 -296
- package/dist/openmrs-esm-billing-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/e2e/README.md +19 -18
- package/e2e/core/test.ts +1 -1
- package/e2e/fixtures/api.ts +1 -1
- package/e2e/specs/sample-test.spec.ts +0 -1
- package/e2e/support/github/Dockerfile +1 -1
- package/package.json +18 -15
- package/src/bill-history/bill-history.component.tsx +20 -28
- package/src/bill-history/bill-history.scss +4 -94
- package/src/bill-history/bill-history.test.tsx +37 -78
- package/src/bill-item-actions/bill-item-actions.scss +21 -5
- package/src/bill-item-actions/edit-bill-item.modal.tsx +225 -0
- package/src/bill-item-actions/edit-bill-item.test.tsx +214 -40
- package/src/billable-services/bill-waiver/bill-selection.component.tsx +5 -5
- package/src/billable-services/bill-waiver/bill-waiver-form.component.tsx +28 -32
- package/src/billable-services/bill-waiver/patient-bills.component.tsx +7 -7
- package/src/billable-services/bill-waiver/utils.ts +13 -3
- package/src/billable-services/{create-edit/add-billable-service.scss → billable-service-form/billable-service-form.scss} +32 -64
- package/src/billable-services/billable-service-form/billable-service-form.test.tsx +893 -0
- package/src/billable-services/billable-service-form/billable-service-form.workspace.tsx +504 -0
- package/src/billable-services/billable-service.resource.ts +42 -26
- package/src/billable-services/billable-services-home.component.tsx +13 -42
- package/src/billable-services/billable-services-left-panel-link.component.tsx +48 -0
- package/src/billable-services/billable-services-left-panel-menu.component.tsx +46 -0
- package/src/billable-services/billable-services-menu-item/item.component.tsx +5 -4
- package/src/billable-services/billable-services.component.tsx +156 -152
- package/src/billable-services/billable-services.scss +29 -0
- package/src/billable-services/billable-services.test.tsx +6 -49
- package/src/billable-services/cash-point/add-cash-point.modal.tsx +170 -0
- package/src/billable-services/cash-point/cash-point-configuration.component.tsx +19 -193
- package/src/billable-services/cash-point/cash-point-configuration.scss +1 -5
- package/src/billable-services/dashboard/dashboard.component.tsx +0 -2
- package/src/billable-services/payment-modes/add-payment-mode.modal.tsx +121 -0
- package/src/billable-services/payment-modes/delete-payment-mode.modal.tsx +74 -0
- package/src/billable-services/payment-modes/payment-modes-config.component.tsx +125 -0
- package/src/billable-services/{payyment-modes → payment-modes}/payment-modes-config.scss +5 -4
- package/src/billable-services-admin-card-link.component.test.tsx +2 -2
- package/src/billable-services-admin-card-link.component.tsx +1 -1
- package/src/billing-dashboard/billing-dashboard.scss +1 -1
- package/src/billing-form/billing-checkin-form.component.tsx +21 -17
- package/src/billing-form/billing-checkin-form.test.tsx +99 -26
- package/src/billing-form/billing-form.component.tsx +222 -292
- package/src/billing-form/billing-form.scss +143 -0
- package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +1 -1
- package/src/billing.resource.ts +69 -74
- package/src/bills-table/bills-table.component.tsx +3 -3
- package/src/bills-table/bills-table.test.tsx +98 -54
- package/src/config-schema.ts +52 -24
- package/src/dashboard.meta.ts +4 -2
- package/src/helpers/functions.ts +5 -4
- package/src/index.ts +71 -9
- package/src/invoice/invoice-table.component.tsx +36 -70
- package/src/invoice/invoice-table.scss +8 -5
- package/src/invoice/invoice-table.test.tsx +273 -62
- package/src/invoice/invoice.component.tsx +39 -32
- package/src/invoice/invoice.scss +11 -4
- package/src/invoice/invoice.test.tsx +324 -120
- package/src/invoice/payments/invoice-breakdown/invoice-breakdown.scss +9 -9
- package/src/invoice/payments/payment-form/payment-form.component.tsx +43 -34
- package/src/invoice/payments/payment-form/payment-form.scss +5 -6
- package/src/invoice/payments/payment-form/payment-form.test.tsx +216 -66
- package/src/invoice/payments/payment-history/payment-history.component.tsx +6 -4
- package/src/invoice/payments/payment-history/payment-history.test.tsx +9 -14
- package/src/invoice/payments/payments.component.tsx +55 -67
- package/src/invoice/payments/payments.scss +4 -3
- package/src/invoice/payments/payments.test.tsx +282 -0
- package/src/invoice/payments/utils.ts +15 -27
- package/src/invoice/printable-invoice/print-receipt.component.tsx +3 -2
- package/src/invoice/printable-invoice/print-receipt.test.tsx +14 -25
- package/src/invoice/printable-invoice/printable-footer.component.tsx +2 -2
- package/src/invoice/printable-invoice/printable-footer.test.tsx +4 -13
- package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +12 -11
- package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +16 -14
- package/src/invoice/printable-invoice/printable-invoice.component.tsx +20 -34
- package/src/left-panel-link.test.tsx +1 -4
- package/src/metrics-cards/metrics-cards.component.tsx +16 -6
- package/src/metrics-cards/metrics-cards.scss +4 -0
- package/src/metrics-cards/metrics-cards.test.tsx +18 -5
- package/src/modal/require-payment-modal.test.tsx +27 -22
- package/src/modal/{require-payment-modal.component.tsx → require-payment.modal.tsx} +18 -19
- package/src/routes.json +44 -20
- package/src/types/index.ts +81 -23
- package/translations/am.json +132 -75
- package/translations/ar.json +133 -76
- package/translations/ar_SY.json +133 -76
- package/translations/bn.json +135 -78
- package/translations/de.json +133 -76
- package/translations/en.json +133 -78
- package/translations/en_US.json +133 -76
- package/translations/es.json +132 -75
- package/translations/es_MX.json +133 -76
- package/translations/fr.json +138 -81
- package/translations/he.json +132 -75
- package/translations/hi.json +133 -76
- package/translations/hi_IN.json +133 -76
- package/translations/id.json +133 -76
- package/translations/it.json +159 -102
- package/translations/ka.json +133 -76
- package/translations/km.json +132 -75
- package/translations/ku.json +133 -76
- package/translations/ky.json +133 -76
- package/translations/lg.json +133 -76
- package/translations/ne.json +133 -76
- package/translations/pl.json +133 -76
- package/translations/pt.json +133 -76
- package/translations/pt_BR.json +133 -76
- package/translations/qu.json +133 -76
- package/translations/ro_RO.json +222 -165
- package/translations/ru_RU.json +133 -76
- package/translations/si.json +133 -76
- package/translations/sw.json +133 -76
- package/translations/sw_KE.json +133 -76
- package/translations/tr.json +133 -76
- package/translations/tr_TR.json +133 -76
- package/translations/uk.json +133 -76
- package/translations/uz.json +133 -76
- package/translations/uz@Latn.json +133 -76
- package/translations/uz_UZ.json +133 -76
- package/translations/vi.json +133 -76
- package/translations/zh.json +133 -76
- package/translations/zh_CN.json +164 -107
- package/dist/1146.js.LICENSE.txt +0 -21
- package/dist/2352.js +0 -1
- package/dist/2352.js.map +0 -1
- package/dist/246.js +0 -1
- package/dist/246.js.map +0 -1
- package/dist/4689.js +0 -2
- package/dist/4689.js.map +0 -1
- package/dist/6557.js +0 -2
- package/dist/6557.js.map +0 -1
- package/dist/8638.js +0 -1
- package/dist/8638.js.map +0 -1
- package/dist/9968.js +0 -1
- package/dist/9968.js.map +0 -1
- package/src/bill-item-actions/edit-bill-item.component.tsx +0 -221
- package/src/billable-services/create-edit/add-billable-service.component.tsx +0 -401
- package/src/billable-services/create-edit/add-billable-service.test.tsx +0 -154
- package/src/billable-services/dashboard/service-metrics.component.tsx +0 -41
- package/src/billable-services/payyment-modes/payment-modes-config.component.tsx +0 -280
- package/src/invoice/payments/payments.component.test.tsx +0 -121
- /package/dist/{4689.js.LICENSE.txt → 3717.js.LICENSE.txt} +0 -0
|
@@ -1,65 +1,36 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
2
3
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
3
|
-
import { SideNav, SideNavItems, SideNavLink, SideNavMenu, SideNavMenuItem } from '@carbon/react';
|
|
4
|
-
import { Wallet, Money, Settings } from '@carbon/react/icons';
|
|
5
4
|
import { useTranslation } from 'react-i18next';
|
|
6
|
-
import {
|
|
7
|
-
import AddBillableService from './create-edit/add-billable-service.component';
|
|
5
|
+
import { useLeftNav, WorkspaceContainer, useLayoutType, isDesktop } from '@openmrs/esm-framework';
|
|
8
6
|
import BillWaiver from './bill-waiver/bill-waiver.component';
|
|
9
7
|
import BillableServicesDashboard from './dashboard/dashboard.component';
|
|
10
8
|
import BillingHeader from '../billing-header/billing-header.component';
|
|
11
9
|
import CashPointConfiguration from './cash-point/cash-point-configuration.component';
|
|
12
|
-
import PaymentModesConfig from './
|
|
10
|
+
import PaymentModesConfig from './payment-modes/payment-modes-config.component';
|
|
13
11
|
import styles from './billable-services.scss';
|
|
14
12
|
|
|
15
13
|
const BillableServiceHome: React.FC = () => {
|
|
16
14
|
const { t } = useTranslation();
|
|
15
|
+
const layout = useLayoutType();
|
|
17
16
|
const basePath = `${window.spaBase}/billable-services`;
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
navigate({ to: `${basePath}/${path}` });
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const handleCloseAddService = () => {
|
|
24
|
-
navigate({ to: `${basePath}` });
|
|
25
|
-
};
|
|
18
|
+
useLeftNav({ name: 'billable-services-left-panel-slot', basePath });
|
|
26
19
|
|
|
27
20
|
return (
|
|
28
|
-
<BrowserRouter basename={
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
<SideNavItems>
|
|
33
|
-
<SideNavLink onClick={() => handleNavigation('')} renderIcon={Wallet} isActive>
|
|
34
|
-
{t('billableServices', 'Billable Services')}
|
|
35
|
-
</SideNavLink>
|
|
36
|
-
<UserHasAccess privilege="coreapps.systemAdministration">
|
|
37
|
-
<SideNavLink onClick={() => handleNavigation('waive-bill')} renderIcon={Money}>
|
|
38
|
-
{t('billWaiver', 'Bill waiver')}
|
|
39
|
-
</SideNavLink>
|
|
40
|
-
<SideNavMenu title={t('billingSettings', 'Billing Settings')} renderIcon={Settings}>
|
|
41
|
-
<SideNavMenuItem onClick={() => handleNavigation('cash-point-config')}>
|
|
42
|
-
{t('cashPointConfig', 'Cash Point Config')}
|
|
43
|
-
</SideNavMenuItem>
|
|
44
|
-
<SideNavMenuItem onClick={() => handleNavigation('payment-modes-config')}>
|
|
45
|
-
{t('paymentModesConfig', 'Payment Modes Config')}
|
|
46
|
-
</SideNavMenuItem>
|
|
47
|
-
</SideNavMenu>
|
|
48
|
-
</UserHasAccess>
|
|
49
|
-
</SideNavItems>
|
|
50
|
-
</SideNav>
|
|
51
|
-
</section>
|
|
52
|
-
<section>
|
|
53
|
-
<BillingHeader title={t('billServicesManagement', 'Bill services management')} />
|
|
21
|
+
<BrowserRouter basename={basePath}>
|
|
22
|
+
<div className={styles.pageWrapper}>
|
|
23
|
+
<main className={classNames(styles.pageContent, { [styles.hasLeftNav]: isDesktop(layout) })}>
|
|
24
|
+
<BillingHeader title={t('billableServicesManagement', 'Billable services management')} />
|
|
54
25
|
<Routes>
|
|
55
26
|
<Route path="/" element={<BillableServicesDashboard />} />
|
|
56
|
-
<Route path="/add-service" element={<AddBillableService onClose={handleCloseAddService} />} />
|
|
57
|
-
<Route path="/waive-bill" element={<BillWaiver />} />
|
|
58
27
|
<Route path="/cash-point-config" element={<CashPointConfiguration />} />
|
|
59
28
|
<Route path="/payment-modes-config" element={<PaymentModesConfig />} />
|
|
29
|
+
<Route path="/waive-bill" element={<BillWaiver />} />
|
|
60
30
|
</Routes>
|
|
61
|
-
</
|
|
62
|
-
</
|
|
31
|
+
</main>
|
|
32
|
+
</div>
|
|
33
|
+
<WorkspaceContainer contextKey="billable-services" />
|
|
63
34
|
</BrowserRouter>
|
|
64
35
|
);
|
|
65
36
|
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { BrowserRouter, useLocation } from 'react-router-dom';
|
|
3
|
+
import { SideNavLink } from '@carbon/react';
|
|
4
|
+
import { navigate, UserHasAccess } from '@openmrs/esm-framework';
|
|
5
|
+
|
|
6
|
+
export interface BillableServicesLinkConfig {
|
|
7
|
+
name: string;
|
|
8
|
+
title: string;
|
|
9
|
+
path: string;
|
|
10
|
+
icon?: React.ComponentType;
|
|
11
|
+
privilege?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function BillableServicesLinkExtension({ config }: { config: BillableServicesLinkConfig }) {
|
|
15
|
+
const { title, path, icon: Icon, privilege } = config;
|
|
16
|
+
const location = useLocation();
|
|
17
|
+
const spaBasePath = `${window.spaBase}/billable-services`;
|
|
18
|
+
|
|
19
|
+
const isActive = useMemo(() => {
|
|
20
|
+
const currentPath = location.pathname.replace(spaBasePath, '');
|
|
21
|
+
if (path === '' || path === '/') {
|
|
22
|
+
return currentPath === '' || currentPath === '/';
|
|
23
|
+
}
|
|
24
|
+
return currentPath.startsWith(`/${path}`);
|
|
25
|
+
}, [location.pathname, path, spaBasePath]);
|
|
26
|
+
|
|
27
|
+
const handleNavigation = () => {
|
|
28
|
+
navigate({ to: `${spaBasePath}/${path}` });
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const link = (
|
|
32
|
+
<SideNavLink onClick={handleNavigation} renderIcon={Icon} isActive={isActive}>
|
|
33
|
+
{title}
|
|
34
|
+
</SideNavLink>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (privilege) {
|
|
38
|
+
return <UserHasAccess privilege={privilege}>{link}</UserHasAccess>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return link;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const createBillableServicesLeftPanelLink = (config: BillableServicesLinkConfig) => () => (
|
|
45
|
+
<BrowserRouter>
|
|
46
|
+
<BillableServicesLinkExtension config={config} />
|
|
47
|
+
</BrowserRouter>
|
|
48
|
+
);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
3
|
+
import { SideNavMenu, SideNavMenuItem } from '@carbon/react';
|
|
4
|
+
import { navigate, UserHasAccess } from '@openmrs/esm-framework';
|
|
5
|
+
|
|
6
|
+
export interface BillableServicesMenuConfig {
|
|
7
|
+
title: string;
|
|
8
|
+
icon?: React.ComponentType;
|
|
9
|
+
privilege?: string;
|
|
10
|
+
items: Array<{
|
|
11
|
+
name: string;
|
|
12
|
+
title: string;
|
|
13
|
+
path: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function BillableServicesMenuExtension({ config }: { config: BillableServicesMenuConfig }) {
|
|
18
|
+
const { title, icon: Icon, items, privilege } = config;
|
|
19
|
+
const spaBasePath = `${window.spaBase}/billable-services`;
|
|
20
|
+
|
|
21
|
+
const handleNavigation = (path: string) => {
|
|
22
|
+
navigate({ to: `${spaBasePath}/${path}` });
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const menu = (
|
|
26
|
+
<SideNavMenu defaultExpanded title={title} renderIcon={Icon}>
|
|
27
|
+
{items.map((item) => (
|
|
28
|
+
<SideNavMenuItem key={item.name} onClick={() => handleNavigation(item.path)}>
|
|
29
|
+
{item.title}
|
|
30
|
+
</SideNavMenuItem>
|
|
31
|
+
))}
|
|
32
|
+
</SideNavMenu>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (privilege) {
|
|
36
|
+
return <UserHasAccess privilege={privilege}>{menu}</UserHasAccess>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return menu;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const createBillableServicesLeftPanelMenu = (config: BillableServicesMenuConfig) => () => (
|
|
43
|
+
<BrowserRouter>
|
|
44
|
+
<BillableServicesMenuExtension config={config} />
|
|
45
|
+
</BrowserRouter>
|
|
46
|
+
);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { ClickableTile } from '@carbon/react';
|
|
2
1
|
import React from 'react';
|
|
3
|
-
import
|
|
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
|
-
|
|
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
|
|
14
|
+
<div>{t('billableServices', 'Billable services')}</div>
|
|
14
15
|
</ClickableTile>
|
|
15
16
|
);
|
|
16
17
|
};
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
DataTable,
|
|
7
7
|
InlineLoading,
|
|
8
8
|
Layer,
|
|
9
|
-
Modal,
|
|
10
9
|
OverflowMenu,
|
|
11
10
|
OverflowMenuItem,
|
|
12
11
|
Pagination,
|
|
@@ -21,65 +20,76 @@ import {
|
|
|
21
20
|
Tile,
|
|
22
21
|
} from '@carbon/react';
|
|
23
22
|
import { ArrowRight } from '@carbon/react/icons';
|
|
24
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
ErrorState,
|
|
25
|
+
getCoreTranslation,
|
|
26
|
+
isDesktop,
|
|
27
|
+
launchWorkspace,
|
|
28
|
+
useConfig,
|
|
29
|
+
useLayoutType,
|
|
30
|
+
usePagination,
|
|
31
|
+
type LayoutType,
|
|
32
|
+
} from '@openmrs/esm-framework';
|
|
25
33
|
import { EmptyState } from '@openmrs/esm-patient-common-lib';
|
|
26
|
-
import { type BillableService } from '../types
|
|
34
|
+
import { type BillableService } from '../types';
|
|
35
|
+
import { type BillingConfig } from '../config-schema';
|
|
27
36
|
import { useBillableServices } from './billable-service.resource';
|
|
28
|
-
import AddBillableService from './create-edit/add-billable-service.component';
|
|
29
37
|
import styles from './billable-services.scss';
|
|
30
38
|
|
|
39
|
+
interface FilterableTableHeaderProps {
|
|
40
|
+
layout: LayoutType;
|
|
41
|
+
handleSearch: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
42
|
+
isValidating: boolean;
|
|
43
|
+
responsiveSize: 'sm' | 'md' | 'lg';
|
|
44
|
+
t: (key: string, fallback: string) => string;
|
|
45
|
+
}
|
|
46
|
+
|
|
31
47
|
const BillableServices = () => {
|
|
32
48
|
const { t } = useTranslation();
|
|
33
49
|
const { billableServices, isLoading, isValidating, error, mutate } = useBillableServices();
|
|
34
50
|
const layout = useLayoutType();
|
|
35
|
-
const
|
|
51
|
+
const { pageSize: configuredPageSize } = useConfig<BillingConfig>();
|
|
36
52
|
const [searchString, setSearchString] = useState('');
|
|
37
53
|
const responsiveSize = isDesktop(layout) ? 'lg' : 'sm';
|
|
38
|
-
const pageSizes =
|
|
39
|
-
const [pageSize, setPageSize] = useState(
|
|
40
|
-
|
|
41
|
-
const [showOverlay, setShowOverlay] = useState(false);
|
|
42
|
-
const [editingService, setEditingService] = useState(null);
|
|
54
|
+
const pageSizes = [10, 20, 30, 40, 50];
|
|
55
|
+
const [pageSize, setPageSize] = useState(configuredPageSize ?? 10);
|
|
43
56
|
|
|
44
57
|
const headerData = [
|
|
45
58
|
{
|
|
46
|
-
header: t('serviceName', 'Service
|
|
59
|
+
header: t('serviceName', 'Service name'),
|
|
47
60
|
key: 'serviceName',
|
|
48
61
|
},
|
|
49
62
|
{
|
|
50
|
-
header: t('shortName', 'Short
|
|
63
|
+
header: t('shortName', 'Short name'),
|
|
51
64
|
key: 'shortName',
|
|
52
65
|
},
|
|
53
66
|
{
|
|
54
|
-
header: t('serviceType', 'Service
|
|
67
|
+
header: t('serviceType', 'Service type'),
|
|
55
68
|
key: 'serviceType',
|
|
56
69
|
},
|
|
57
70
|
{
|
|
58
|
-
header: t('
|
|
71
|
+
header: t('serviceStatus', 'Service status'),
|
|
59
72
|
key: 'status',
|
|
60
73
|
},
|
|
61
74
|
{
|
|
62
75
|
header: t('prices', 'Prices'),
|
|
63
76
|
key: 'prices',
|
|
64
77
|
},
|
|
65
|
-
{
|
|
66
|
-
header: t('actions', 'Actions'),
|
|
67
|
-
key: 'actions',
|
|
68
|
-
},
|
|
69
78
|
];
|
|
70
79
|
|
|
71
80
|
const launchBillableServiceForm = useCallback(() => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}, []);
|
|
81
|
+
launchWorkspace('billable-service-form', {
|
|
82
|
+
workspaceTitle: t('addBillableService', 'Add billable service'),
|
|
83
|
+
});
|
|
84
|
+
}, [t]);
|
|
76
85
|
|
|
77
86
|
const searchResults: BillableService[] = useMemo(() => {
|
|
78
87
|
const flatBillableServices = Array.isArray(billableServices) ? billableServices.flat() : billableServices;
|
|
79
88
|
|
|
80
89
|
if (flatBillableServices !== undefined && flatBillableServices.length > 0) {
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
const trimmedSearch = searchString.trim();
|
|
91
|
+
if (trimmedSearch) {
|
|
92
|
+
const search = trimmedSearch.toLowerCase();
|
|
83
93
|
return flatBillableServices.filter((service: BillableService) =>
|
|
84
94
|
Object.entries(service).some(([header, value]) => {
|
|
85
95
|
return header === 'uuid' ? false : `${value}`.toLowerCase().includes(search);
|
|
@@ -94,31 +104,16 @@ const BillableServices = () => {
|
|
|
94
104
|
const rowData = [];
|
|
95
105
|
|
|
96
106
|
if (results) {
|
|
97
|
-
results.forEach((service
|
|
107
|
+
results.forEach((service) => {
|
|
98
108
|
const s = {
|
|
99
|
-
id:
|
|
109
|
+
id: service.uuid,
|
|
100
110
|
uuid: service.uuid,
|
|
101
111
|
serviceName: service.name,
|
|
102
112
|
shortName: service.shortName,
|
|
103
113
|
serviceType: service?.serviceType?.display,
|
|
104
114
|
status: service.serviceStatus,
|
|
105
|
-
prices: '--',
|
|
106
|
-
actions: (
|
|
107
|
-
<TableCell>
|
|
108
|
-
<OverflowMenu size="sm" flipped>
|
|
109
|
-
<OverflowMenuItem
|
|
110
|
-
itemText={t('editBillableService', 'Edit Billable Service')}
|
|
111
|
-
onClick={() => handleEditService(service)}
|
|
112
|
-
/>
|
|
113
|
-
</OverflowMenu>
|
|
114
|
-
</TableCell>
|
|
115
|
-
),
|
|
115
|
+
prices: service.servicePrices.map((price) => `${price.name} (${price.price})`).join(', ') || '--',
|
|
116
116
|
};
|
|
117
|
-
let cost = '';
|
|
118
|
-
service.servicePrices.forEach((price) => {
|
|
119
|
-
cost += `${price.name} (${price.price}) `;
|
|
120
|
-
});
|
|
121
|
-
s.prices = cost;
|
|
122
117
|
rowData.push(s);
|
|
123
118
|
});
|
|
124
119
|
}
|
|
@@ -130,132 +125,138 @@ const BillableServices = () => {
|
|
|
130
125
|
},
|
|
131
126
|
[goTo, setSearchString],
|
|
132
127
|
);
|
|
133
|
-
const handleEditService = useCallback((service) => {
|
|
134
|
-
setEditingService(service);
|
|
135
|
-
setShowOverlay(true);
|
|
136
|
-
}, []);
|
|
137
128
|
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
129
|
+
const handleEditService = useCallback(
|
|
130
|
+
(service: BillableService) => {
|
|
131
|
+
launchWorkspace('billable-service-form', {
|
|
132
|
+
workspaceTitle: t('editBillableService', 'Edit billable service'),
|
|
133
|
+
serviceToEdit: service,
|
|
134
|
+
onWorkspaceClose: mutate,
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
[mutate, t],
|
|
138
|
+
);
|
|
142
139
|
|
|
143
140
|
if (isLoading) {
|
|
144
|
-
|
|
141
|
+
return (
|
|
142
|
+
<InlineLoading
|
|
143
|
+
status="active"
|
|
144
|
+
iconDescription={getCoreTranslation('loading')}
|
|
145
|
+
description={t('loading', 'Loading data') + '...'}
|
|
146
|
+
/>
|
|
147
|
+
);
|
|
145
148
|
}
|
|
149
|
+
|
|
146
150
|
if (error) {
|
|
147
|
-
<ErrorState headerTitle={t('billableService', 'Billable
|
|
151
|
+
return <ErrorState headerTitle={t('billableService', 'Billable service')} error={error} />;
|
|
148
152
|
}
|
|
153
|
+
|
|
149
154
|
if (billableServices.length === 0) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
return (
|
|
156
|
+
<EmptyState
|
|
157
|
+
displayText={t('billableServices__lower', 'billable services')}
|
|
158
|
+
headerTitle={t('billableService', 'Billable service')}
|
|
159
|
+
launchForm={launchBillableServiceForm}
|
|
160
|
+
/>
|
|
161
|
+
);
|
|
155
162
|
}
|
|
156
163
|
|
|
157
164
|
return (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
165
|
+
<div className={styles.serviceContainer}>
|
|
166
|
+
<FilterableTableHeader
|
|
167
|
+
handleSearch={handleSearch}
|
|
168
|
+
isValidating={isValidating}
|
|
169
|
+
layout={layout}
|
|
170
|
+
responsiveSize={responsiveSize}
|
|
171
|
+
t={t}
|
|
172
|
+
/>
|
|
173
|
+
<DataTable
|
|
174
|
+
isSortable
|
|
175
|
+
rows={rowData}
|
|
176
|
+
headers={headerData}
|
|
177
|
+
overflowMenuOnHover={isDesktop(layout)}
|
|
178
|
+
size={responsiveSize}
|
|
179
|
+
useZebraStyles={rowData?.length > 1}>
|
|
180
|
+
{({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => (
|
|
181
|
+
<TableContainer>
|
|
182
|
+
<Table {...getTableProps()} aria-label={t('serviceList', 'Service list')}>
|
|
183
|
+
<TableHead>
|
|
184
|
+
<TableRow>
|
|
185
|
+
{headers.map((header) => (
|
|
186
|
+
<TableHeader
|
|
187
|
+
{...getHeaderProps({
|
|
188
|
+
header,
|
|
189
|
+
})}
|
|
190
|
+
key={header.key}>
|
|
191
|
+
{header.header}
|
|
192
|
+
</TableHeader>
|
|
193
|
+
))}
|
|
194
|
+
<TableHeader aria-label={getCoreTranslation('actions')} />
|
|
195
|
+
</TableRow>
|
|
196
|
+
</TableHead>
|
|
197
|
+
<TableBody>
|
|
198
|
+
{rows.map((row) => (
|
|
199
|
+
<TableRow
|
|
200
|
+
key={row.id}
|
|
201
|
+
{...getRowProps({
|
|
202
|
+
row,
|
|
203
|
+
})}>
|
|
204
|
+
{row.cells.map((cell) => (
|
|
205
|
+
<TableCell key={cell.id}>{cell.value}</TableCell>
|
|
195
206
|
))}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
size={responsiveSize}
|
|
223
|
-
onChange={({ pageSize: newPageSize, page: newPage }) => {
|
|
224
|
-
if (newPageSize !== pageSize) {
|
|
225
|
-
setPageSize(newPageSize);
|
|
226
|
-
}
|
|
227
|
-
if (newPage !== currentPage) {
|
|
228
|
-
goTo(newPage);
|
|
229
|
-
}
|
|
230
|
-
}}
|
|
231
|
-
/>
|
|
232
|
-
)}
|
|
207
|
+
<TableCell className="cds--table-column-menu">
|
|
208
|
+
<OverflowMenu size="lg" flipped>
|
|
209
|
+
<OverflowMenuItem
|
|
210
|
+
className={styles.menuItem}
|
|
211
|
+
itemText={t('editBillableService', 'Edit billable service')}
|
|
212
|
+
onClick={() => handleEditService(results.find((service) => service.uuid === row.id))}
|
|
213
|
+
/>
|
|
214
|
+
</OverflowMenu>
|
|
215
|
+
</TableCell>
|
|
216
|
+
</TableRow>
|
|
217
|
+
))}
|
|
218
|
+
</TableBody>
|
|
219
|
+
</Table>
|
|
220
|
+
</TableContainer>
|
|
221
|
+
)}
|
|
222
|
+
</DataTable>
|
|
223
|
+
{searchResults?.length === 0 && (
|
|
224
|
+
<div className={styles.filterEmptyState}>
|
|
225
|
+
<Layer level={0}>
|
|
226
|
+
<Tile className={styles.filterEmptyStateTile}>
|
|
227
|
+
<p className={styles.filterEmptyStateContent}>
|
|
228
|
+
{t('noMatchingServicesToDisplay', 'No matching services to display')}
|
|
229
|
+
</p>
|
|
230
|
+
<p className={styles.filterEmptyStateHelper}>{t('checkFilters', 'Check the filters above')}</p>
|
|
231
|
+
</Tile>
|
|
232
|
+
</Layer>
|
|
233
233
|
</div>
|
|
234
|
-
) : (
|
|
235
|
-
<EmptyState
|
|
236
|
-
launchForm={launchBillableServiceForm}
|
|
237
|
-
displayText={t('noServicesToDisplay', 'There are no services to display')}
|
|
238
|
-
headerTitle={t('billableService', 'Billable service')}
|
|
239
|
-
/>
|
|
240
234
|
)}
|
|
241
|
-
{
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
235
|
+
{paginated && (
|
|
236
|
+
<Pagination
|
|
237
|
+
forwardText={t('nextPage', 'Next page')}
|
|
238
|
+
backwardText={t('previousPage', 'Previous page')}
|
|
239
|
+
page={currentPage}
|
|
240
|
+
pageSize={pageSize}
|
|
241
|
+
pageSizes={pageSizes}
|
|
242
|
+
totalItems={searchResults?.length}
|
|
243
|
+
className={styles.pagination}
|
|
244
|
+
size={responsiveSize}
|
|
245
|
+
onChange={({ pageSize: newPageSize, page: newPage }) => {
|
|
246
|
+
if (newPageSize !== pageSize) {
|
|
247
|
+
setPageSize(newPageSize);
|
|
248
|
+
}
|
|
249
|
+
if (newPage !== currentPage) {
|
|
250
|
+
goTo(newPage);
|
|
251
|
+
}
|
|
252
|
+
}}
|
|
253
|
+
/>
|
|
253
254
|
)}
|
|
254
|
-
|
|
255
|
+
</div>
|
|
255
256
|
);
|
|
256
257
|
};
|
|
257
258
|
|
|
258
|
-
function FilterableTableHeader({ layout, handleSearch, isValidating, responsiveSize, t }) {
|
|
259
|
+
function FilterableTableHeader({ layout, handleSearch, isValidating, responsiveSize, t }: FilterableTableHeaderProps) {
|
|
259
260
|
return (
|
|
260
261
|
<>
|
|
261
262
|
<div className={styles.headerContainer}>
|
|
@@ -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
|
-
|
|
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')}
|
|
@@ -291,4 +294,5 @@ function FilterableTableHeader({ layout, handleSearch, isValidating, responsiveS
|
|
|
291
294
|
</>
|
|
292
295
|
);
|
|
293
296
|
}
|
|
297
|
+
|
|
294
298
|
export default BillableServices;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
@use '@carbon/colors';
|
|
1
2
|
@use '@carbon/layout';
|
|
2
3
|
@use '@carbon/type';
|
|
3
4
|
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
@@ -217,3 +218,31 @@
|
|
|
217
218
|
grid-template-columns: 16rem 1fr;
|
|
218
219
|
}
|
|
219
220
|
|
|
221
|
+
.menuItem {
|
|
222
|
+
max-width: none;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.pageWrapper {
|
|
226
|
+
display: flex;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.pageContent {
|
|
230
|
+
display: flex;
|
|
231
|
+
flex-grow: 1;
|
|
232
|
+
flex-direction: column;
|
|
233
|
+
margin: 0;
|
|
234
|
+
// Full vertical height minus the primary navigation menu height
|
|
235
|
+
height: calc(100vh - layout.$spacing-09);
|
|
236
|
+
// Ensure the width is fixed and does not expand based on children
|
|
237
|
+
width: calc(100% - 16rem);
|
|
238
|
+
background-color: colors.$gray-10;
|
|
239
|
+
|
|
240
|
+
& a {
|
|
241
|
+
width: 100%;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
&.hasLeftNav {
|
|
245
|
+
// Make space for the left nav menu
|
|
246
|
+
margin-inline-start: 16rem;
|
|
247
|
+
}
|
|
248
|
+
}
|