@digihmis/esm-administration-app 1.0.0
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/README.md +4 -0
- package/dist/101.js +1 -0
- package/dist/101.js.map +1 -0
- package/dist/117.js +1 -0
- package/dist/117.js.map +1 -0
- package/dist/132.js +1 -0
- package/dist/132.js.map +1 -0
- package/dist/15.js +1 -0
- package/dist/15.js.map +1 -0
- package/dist/152.js +1 -0
- package/dist/152.js.map +1 -0
- package/dist/153.js +1 -0
- package/dist/153.js.map +1 -0
- package/dist/190.js +1 -0
- package/dist/190.js.map +1 -0
- package/dist/209.js +1 -0
- package/dist/209.js.map +1 -0
- package/dist/266.js +1 -0
- package/dist/266.js.map +1 -0
- package/dist/317.js +1 -0
- package/dist/317.js.map +1 -0
- package/dist/349.js +1 -0
- package/dist/349.js.map +1 -0
- package/dist/371.js +1 -0
- package/dist/371.js.map +1 -0
- package/dist/378.js +1 -0
- package/dist/378.js.map +1 -0
- package/dist/394.js +1 -0
- package/dist/394.js.map +1 -0
- package/dist/442.js +1 -0
- package/dist/442.js.map +1 -0
- package/dist/45.js +1 -0
- package/dist/45.js.map +1 -0
- package/dist/454.js +1 -0
- package/dist/454.js.map +1 -0
- package/dist/466.js +1 -0
- package/dist/466.js.map +1 -0
- package/dist/482.js +1 -0
- package/dist/482.js.map +1 -0
- package/dist/501.js +1 -0
- package/dist/501.js.map +1 -0
- package/dist/508.js +1 -0
- package/dist/508.js.map +1 -0
- package/dist/578.js +1 -0
- package/dist/578.js.map +1 -0
- package/dist/598.js +1 -0
- package/dist/598.js.map +1 -0
- package/dist/606.js +1 -0
- package/dist/606.js.map +1 -0
- package/dist/61.js +1 -0
- package/dist/61.js.map +1 -0
- package/dist/640.js +1 -0
- package/dist/640.js.map +1 -0
- package/dist/685.js +1 -0
- package/dist/685.js.map +1 -0
- package/dist/689.js +1 -0
- package/dist/689.js.map +1 -0
- package/dist/709.js +1 -0
- package/dist/709.js.map +1 -0
- package/dist/712.js +1 -0
- package/dist/712.js.map +1 -0
- package/dist/720.js +1 -0
- package/dist/720.js.map +1 -0
- package/dist/737.js +12 -0
- package/dist/737.js.map +1 -0
- package/dist/742.js +1 -0
- package/dist/742.js.map +1 -0
- package/dist/747.js +1 -0
- package/dist/747.js.map +1 -0
- package/dist/771.js +1 -0
- package/dist/771.js.map +1 -0
- package/dist/806.js +1 -0
- package/dist/806.js.map +1 -0
- package/dist/912.js +1 -0
- package/dist/912.js.map +1 -0
- package/dist/913.js +1 -0
- package/dist/913.js.map +1 -0
- package/dist/916.js +15 -0
- package/dist/916.js.map +1 -0
- package/dist/940.js +1 -0
- package/dist/940.js.map +1 -0
- package/dist/digihmis-esm-administration-app.js +6 -0
- package/dist/digihmis-esm-administration-app.js.buildmanifest.json +1100 -0
- package/dist/digihmis-esm-administration-app.js.map +1 -0
- package/dist/main.js +17 -0
- package/dist/main.js.map +1 -0
- package/dist/routes.json +1 -0
- package/increment-version.js +17 -0
- package/jest.config.js +26 -0
- package/package.json +51 -0
- package/release-version.js +16 -0
- package/rspack.config.js +1 -0
- package/src/bed-management/bed-management.component.tsx +19 -0
- package/src/bed-management/bed-management.scss +0 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-modal/billing-charge-items.modal.tsx +79 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-modal/billing-charge-items.resource.ts +11 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/billing-charge-item.workspace.tsx +212 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/billing-charge-items.resource.ts +51 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/billing-charge-service.workspace.tsx +296 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/components/concept-search.component.tsx +67 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/components/price.component.tsx +81 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/components/stock-search.component.tsx +107 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/global/billing-charge-commodity.scss +61 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/global/billing-charge-items.scss +59 -0
- package/src/billing-management/billing-charge-items/billing-charge-items-workspace/schemas/form-schemas.ts +33 -0
- package/src/billing-management/billing-charge-items/billing-charge-items.component.tsx +222 -0
- package/src/billing-management/billing-charge-items/billing-charge-items.resource.ts +20 -0
- package/src/billing-management/billing-charge-items/billing-charge-items.scss +84 -0
- package/src/billing-management/billing-charge-items/type/index.ts +88 -0
- package/src/billing-management/billing-charge-items/utils/index.ts +96 -0
- package/src/billing-management/billing-management.component.tsx +21 -0
- package/src/billing-management/billing-management.scss +0 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-modal/billing-delete-payment-modes.modal.scss +28 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-modal/billing-delete-payment-modes.modal.tsx +67 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-modal/delete-payment-mode.test.tsx +56 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-workspace/billing-payment-modes-form-schema.ts +52 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-workspace/billing-payment-modes.resource.ts +35 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-workspace/billing-payment-modes.workspace.scss +33 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-workspace/billing-payment-modes.workspace.test.tsx +239 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-workspace/billing-payment-modes.workspace.tsx +218 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-workspace/payment-attributes/payment-mode-attributes.component.tsx +156 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes-workspace/payment-attributes/payment-mode-attributes.scss +10 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes.component.tsx +243 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes.resource.ts +23 -0
- package/src/billing-management/billing-payment-modes/billing-payment-modes.scss +140 -0
- package/src/billing-management/billing-payment-modes/type/index.ts +42 -0
- package/src/billing-management/billing-payment-points/billing-payment-point-modal/billing-delete-payment-modes.modal.scss +28 -0
- package/src/billing-management/billing-payment-points/billing-payment-point-modal/billing-delete-payment-point.modal.tsx +72 -0
- package/src/billing-management/billing-payment-points/billing-payment-point-modal/delete-payment-point.test.tsx +56 -0
- package/src/billing-management/billing-payment-points/billing-payment-point.component.tsx +202 -0
- package/src/billing-management/billing-payment-points/billing-payment-point.resource.ts +16 -0
- package/src/billing-management/billing-payment-points/billing-payment-point.scss +0 -0
- package/src/billing-management/billing-payment-points/billing-payment-points-workspace/billing-payment-point.resource.ts +39 -0
- package/src/billing-management/billing-payment-points/billing-payment-points-workspace/billing-payment-point.workspace.scss +33 -0
- package/src/billing-management/billing-payment-points/billing-payment-points-workspace/billing-payment-points.workspace.tsx +194 -0
- package/src/billing-management/billing-payment-points/type/index.ts +35 -0
- package/src/billing-management/billing-tabs/billing-tabs.component.scss +15 -0
- package/src/billing-management/billing-tabs/billing-tabs.component.tsx +36 -0
- package/src/components/custom-icon-wrapper/custom-icon-wrapper.component.tsx +17 -0
- package/src/components/custom-page-header/custom-page-header.component.tsx +38 -0
- package/src/components/custom-page-header/custom-page-header.scss +76 -0
- package/src/config-schema.ts +142 -0
- package/src/constant/index.ts +1 -0
- package/src/dashboard.meta.ts +47 -0
- package/src/declarations.d.ts +6 -0
- package/src/form-builder/form-builder.component.tsx +19 -0
- package/src/form-builder/form-builder.scss +0 -0
- package/src/hooks/useConcept.ts +13 -0
- package/src/hooks/useQueues.ts +22 -0
- package/src/hooks/useSystemSetting.ts +18 -0
- package/src/index.ts +133 -0
- package/src/left-panel/left-panel.component.tsx +49 -0
- package/src/left-panel/left-panel.scss +13 -0
- package/src/location-management/components/auto-suggest/autosuggest.component.tsx +149 -0
- package/src/location-management/components/auto-suggest/autosuggest.scss +61 -0
- package/src/location-management/components/auto-suggest/location-autosuggest.component.tsx +97 -0
- package/src/location-management/components/auto-suggest/location-autosuggest.scss +48 -0
- package/src/location-management/components/custom-results-tile/results-tile.component.tsx +43 -0
- package/src/location-management/components/custom-results-tile/results-tile.scss +86 -0
- package/src/location-management/forms/add-location/add-location.workspace.scss +71 -0
- package/src/location-management/forms/add-location/add-location.workspace.tsx +199 -0
- package/src/location-management/forms/search-location/search-location.workspace.scss +71 -0
- package/src/location-management/forms/search-location/search-location.workspace.tsx +214 -0
- package/src/location-management/helpers/index.ts +33 -0
- package/src/location-management/hooks/UseFacilityLocations.ts +12 -0
- package/src/location-management/hooks/useLocation.ts +18 -0
- package/src/location-management/hooks/useLocationTags.ts +15 -0
- package/src/location-management/location-management-dashboard.component.tsx +21 -0
- package/src/location-management/location-management-dashboard.scss +3 -0
- package/src/location-management/tables/locations-table.component.tsx +242 -0
- package/src/location-management/tables/locations-table.resource.ts +26 -0
- package/src/location-management/tables/locations-table.scss +114 -0
- package/src/location-management/types/index.ts +120 -0
- package/src/queue-management/queue-management-dashboard.component.tsx +23 -0
- package/src/queue-management/queue-management-dashboard.scss +8 -0
- package/src/queue-management/queue-management-table/queue-management-table.component.tsx +296 -0
- package/src/queue-management/queue-management-table/queue-management-table.scss +78 -0
- package/src/queue-management/queue-management-table/queue-management.resource.ts +39 -0
- package/src/queue-management/queue-management-workspace/queue-room/queue-room-form.scss +56 -0
- package/src/queue-management/queue-management-workspace/queue-room/queue-room-form.test.tsx +82 -0
- package/src/queue-management/queue-management-workspace/queue-room/queue-room-form.workspace.tsx +169 -0
- package/src/queue-management/queue-management-workspace/queue-room/queue-room.resource.ts +20 -0
- package/src/queue-management/queue-management-workspace/queue-service/queue-service-form.scss +61 -0
- package/src/queue-management/queue-management-workspace/queue-service/queue-service-form.test.tsx +127 -0
- package/src/queue-management/queue-management-workspace/queue-service/queue-service-form.workspace.tsx +178 -0
- package/src/queue-management/queue-management-workspace/queue-service/queue-service.resource.ts +55 -0
- package/src/queue-management/queue-types/index.ts +33 -0
- package/src/routes.json +157 -0
- package/src/setup-tests.ts +1 -0
- package/src/system-info/system-info.component.tsx +338 -0
- package/src/system-info/system-info.resource.ts +40 -0
- package/src/system-info/system-info.scss +622 -0
- package/src/type/index.ts +6 -0
- package/translations/am.json +111 -0
- package/translations/ar.json +115 -0
- package/translations/en.json +111 -0
- package/translations/es.json +112 -0
- package/translations/fr.json +112 -0
- package/translations/he.json +112 -0
- package/translations/km.json +110 -0
- package/translations/pt.json +112 -0
- package/translations/sw.json +111 -0
- package/translations/vi.json +110 -0
- package/translations/zh.json +110 -0
- package/tsconfig.json +5 -0
- package/version.js +27 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ModalBody, ModalFooter, Button, ModalHeader } from '@carbon/react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
|
|
5
|
+
import styles from './billing-delete-payment-modes.modal.scss';
|
|
6
|
+
import { PaymentPoint } from '../type';
|
|
7
|
+
import { deletePaymentPoint, handleMutation } from '../billing-payment-points-workspace/billing-payment-point.resource';
|
|
8
|
+
|
|
9
|
+
type DeletePaymentPointModalProps = {
|
|
10
|
+
closeModal: () => void;
|
|
11
|
+
paymentPoint: PaymentPoint;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const DeletePaymentPointModal: React.FC<DeletePaymentPointModalProps> = ({ closeModal, paymentPoint }) => {
|
|
15
|
+
const { t } = useTranslation();
|
|
16
|
+
const paymentPointName = paymentPoint?.name || '';
|
|
17
|
+
|
|
18
|
+
const handleDelete = async () => {
|
|
19
|
+
try {
|
|
20
|
+
await deletePaymentPoint(paymentPoint.uuid);
|
|
21
|
+
showSnackbar({
|
|
22
|
+
title: t('paymentPointDeleted', 'Payment point {{paymentPointName}} successfully deleted', {
|
|
23
|
+
paymentPointName,
|
|
24
|
+
}),
|
|
25
|
+
subtitle: t('paymentPointDeletedSubtitle', 'The payment point has been deleted'),
|
|
26
|
+
kind: 'success',
|
|
27
|
+
isLowContrast: true,
|
|
28
|
+
timeoutInMs: 5000,
|
|
29
|
+
autoClose: true,
|
|
30
|
+
});
|
|
31
|
+
handleMutation(`${restBaseUrl}/cashier/cashPoint?v=full`);
|
|
32
|
+
closeModal();
|
|
33
|
+
} catch (error) {
|
|
34
|
+
showSnackbar({
|
|
35
|
+
title: t('paymentPointDeletedError', 'Error deleting payment point'),
|
|
36
|
+
subtitle: t(
|
|
37
|
+
'paymentPointDeletedErrorSubtitle',
|
|
38
|
+
'An error occurred while deleting the payment point. Please try again.',
|
|
39
|
+
),
|
|
40
|
+
kind: 'error',
|
|
41
|
+
isLowContrast: true,
|
|
42
|
+
timeoutInMs: 5000,
|
|
43
|
+
autoClose: true,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<>
|
|
50
|
+
<ModalHeader className={styles.modalHeaderLabel} closeModal={closeModal}>
|
|
51
|
+
{t('deletePaymentMode', 'Delete Payment Mode')}
|
|
52
|
+
</ModalHeader>
|
|
53
|
+
<ModalBody className={styles.modalHeaderHeading}>
|
|
54
|
+
{t(
|
|
55
|
+
'deletePaymentPointDescription',
|
|
56
|
+
`Are you sure you want to delete this {{paymentPointName}} payment point? Proceed cautiously.`,
|
|
57
|
+
{ paymentPointName },
|
|
58
|
+
)}
|
|
59
|
+
</ModalBody>
|
|
60
|
+
<ModalFooter>
|
|
61
|
+
<Button kind="secondary" onClick={closeModal}>
|
|
62
|
+
{t('cancel', 'Cancel')}
|
|
63
|
+
</Button>
|
|
64
|
+
<Button kind="danger" onClick={handleDelete}>
|
|
65
|
+
{t('delete', 'Delete')}
|
|
66
|
+
</Button>
|
|
67
|
+
</ModalFooter>
|
|
68
|
+
</>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default DeletePaymentPointModal;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import DeletePaymentModeModal from './billing-delete-payment-point.modal';
|
|
5
|
+
import { PaymentMethod } from '../type';
|
|
6
|
+
import { deletePaymentMode } from '../billing-payment-modes-workspace/billing-payment-modes.resource';
|
|
7
|
+
|
|
8
|
+
const mockDeletePaymentMode = jest.mocked(deletePaymentMode);
|
|
9
|
+
|
|
10
|
+
jest.mock('./payment-mode.resource', () => ({
|
|
11
|
+
deletePaymentMode: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
describe('DeletePaymentModeModal', () => {
|
|
15
|
+
test('should be able to delete payment mode when user clicks on delete button', async () => {
|
|
16
|
+
const user = userEvent.setup();
|
|
17
|
+
const mockCloseModal = jest.fn();
|
|
18
|
+
const mockPaymentMode = {
|
|
19
|
+
uuid: '123',
|
|
20
|
+
name: 'Test Payment Mode',
|
|
21
|
+
description: 'Test Description',
|
|
22
|
+
retired: false,
|
|
23
|
+
auditInfo: {
|
|
24
|
+
creator: {
|
|
25
|
+
uuid: '456',
|
|
26
|
+
display: 'Test Creator',
|
|
27
|
+
},
|
|
28
|
+
dateCreated: '2021-01-01',
|
|
29
|
+
},
|
|
30
|
+
} as PaymentMethod;
|
|
31
|
+
|
|
32
|
+
render(<DeletePaymentModeModal closeModal={mockCloseModal} paymentMode={mockPaymentMode} />);
|
|
33
|
+
|
|
34
|
+
const deleteButton = await screen.findByRole('button', { name: /Delete/i });
|
|
35
|
+
await user.click(deleteButton);
|
|
36
|
+
|
|
37
|
+
expect(mockDeletePaymentMode).toHaveBeenCalledWith(mockPaymentMode.uuid);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should be able to cancel deletion of payment mode when user clicks on cancel button', async () => {
|
|
41
|
+
const user = userEvent.setup();
|
|
42
|
+
const mockCloseModal = jest.fn();
|
|
43
|
+
const mockPaymentMode = {
|
|
44
|
+
uuid: '123',
|
|
45
|
+
name: 'Test Payment Mode',
|
|
46
|
+
description: 'Test Description',
|
|
47
|
+
} as PaymentMethod;
|
|
48
|
+
|
|
49
|
+
render(<DeletePaymentModeModal closeModal={mockCloseModal} paymentMode={mockPaymentMode} />);
|
|
50
|
+
|
|
51
|
+
const cancelButton = await screen.findByRole('button', { name: /Cancel/i });
|
|
52
|
+
await user.click(cancelButton);
|
|
53
|
+
|
|
54
|
+
expect(mockCloseModal).toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
DataTable,
|
|
5
|
+
DataTableSkeleton,
|
|
6
|
+
Table,
|
|
7
|
+
TableBody,
|
|
8
|
+
TableCell,
|
|
9
|
+
TableContainer,
|
|
10
|
+
TableHead,
|
|
11
|
+
TableHeader,
|
|
12
|
+
TableRow,
|
|
13
|
+
Layer,
|
|
14
|
+
Pagination,
|
|
15
|
+
Tile,
|
|
16
|
+
IconButton,
|
|
17
|
+
} from '@carbon/react';
|
|
18
|
+
import { Add, Edit, TrashCan } from '@carbon/react/icons';
|
|
19
|
+
import { launchWorkspace, useLayoutType, ErrorState, showModal } from '@openmrs/esm-framework';
|
|
20
|
+
import { useTranslation } from 'react-i18next';
|
|
21
|
+
import styles from './billing-payment-point.scss';
|
|
22
|
+
import { CardHeader } from '@openmrs/esm-patient-common-lib';
|
|
23
|
+
import { usePaymentPoints } from './billing-payment-point.resource';
|
|
24
|
+
import { PaymentPoint } from './type';
|
|
25
|
+
|
|
26
|
+
const PaymentPointTable = () => {
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
const layout = useLayoutType();
|
|
29
|
+
const isTablet = layout === 'tablet';
|
|
30
|
+
const responsiveSize = isTablet ? 'lg' : 'sm';
|
|
31
|
+
|
|
32
|
+
const { paymentPoints, isLoading, error } = usePaymentPoints();
|
|
33
|
+
|
|
34
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
35
|
+
const [currentPageSize, setCurrentPageSize] = useState(10);
|
|
36
|
+
const pageSizes = [10, 20, 30, 40, 50];
|
|
37
|
+
|
|
38
|
+
const headers = [
|
|
39
|
+
{
|
|
40
|
+
key: 'dateCreated',
|
|
41
|
+
header: t('dateCreated', 'Date Created'),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
key: 'name',
|
|
45
|
+
header: t('name', 'Name'),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: 'description',
|
|
49
|
+
header: t('description', 'Description'),
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: 'retired',
|
|
53
|
+
header: t('retired', 'Retired'),
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const tableRows = useMemo(() => {
|
|
58
|
+
if (!paymentPoints || !Array.isArray(paymentPoints)) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return paymentPoints.map((point) => ({
|
|
63
|
+
id: point.uuid,
|
|
64
|
+
dateCreated: point?.auditInfo?.dateCreated ? new Date(point.auditInfo.dateCreated).toLocaleDateString() : '-',
|
|
65
|
+
name: point.name || '-',
|
|
66
|
+
description: point.description || '-',
|
|
67
|
+
retired: point.retired ? t('yes', 'Yes') : t('no', 'No'),
|
|
68
|
+
paymentPoint: point,
|
|
69
|
+
}));
|
|
70
|
+
}, [paymentPoints, t]);
|
|
71
|
+
|
|
72
|
+
const paginatedRows = useMemo(() => {
|
|
73
|
+
const startIndex = (currentPage - 1) * currentPageSize;
|
|
74
|
+
const endIndex = startIndex + currentPageSize;
|
|
75
|
+
return tableRows.slice(startIndex, endIndex);
|
|
76
|
+
}, [tableRows, currentPage, currentPageSize]);
|
|
77
|
+
|
|
78
|
+
const handleAddPaymentPoint = () => {
|
|
79
|
+
launchWorkspace('payment-point-workspace', {
|
|
80
|
+
workspaceTitle: t('addPaymentPoint', 'Add Payment Point'),
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const showDeletePaymentPointModal = (paymentPoint: PaymentPoint) => {
|
|
85
|
+
const dispose = showModal('delete-payment-point-modal', {
|
|
86
|
+
closeModal: () => dispose(),
|
|
87
|
+
paymentPoint,
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (isLoading) {
|
|
92
|
+
return (
|
|
93
|
+
<div className={styles.section}>
|
|
94
|
+
<h3>{t('paymentPoints', 'Payment Points')}</h3>
|
|
95
|
+
<DataTableSkeleton role="progressbar" compact={!isTablet} zebra />
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (error) {
|
|
101
|
+
return <ErrorState error={error} headerTitle={t('paymentPoints', 'Payment Points')} />;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div className={styles.section}>
|
|
106
|
+
<CardHeader title={t('paymentPoints', 'Payment Points')}>
|
|
107
|
+
<Button kind="ghost" renderIcon={(props) => <Add size={16} {...props} />} onClick={handleAddPaymentPoint}>
|
|
108
|
+
{t('addPaymentPoint', 'Add Payment Point')}
|
|
109
|
+
</Button>
|
|
110
|
+
</CardHeader>
|
|
111
|
+
<Layer>
|
|
112
|
+
<DataTable rows={paginatedRows} headers={headers} isSortable size={responsiveSize} useZebraStyles>
|
|
113
|
+
{({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => (
|
|
114
|
+
<TableContainer>
|
|
115
|
+
<Table {...getTableProps()} aria-label={t('paymentPointsTable', 'Payment points table')}>
|
|
116
|
+
<TableHead>
|
|
117
|
+
<TableRow>
|
|
118
|
+
{headers.map((header) => (
|
|
119
|
+
<TableHeader key={header.key} {...getHeaderProps({ header })}>
|
|
120
|
+
{header.header}
|
|
121
|
+
</TableHeader>
|
|
122
|
+
))}
|
|
123
|
+
<TableHeader>{t('actions', 'Actions')}</TableHeader>
|
|
124
|
+
</TableRow>
|
|
125
|
+
</TableHead>
|
|
126
|
+
<TableBody>
|
|
127
|
+
{rows.map((row, index) => {
|
|
128
|
+
const paymentPoint = paginatedRows[index]?.paymentPoint;
|
|
129
|
+
return (
|
|
130
|
+
<TableRow key={row.id} {...getRowProps({ row })}>
|
|
131
|
+
{row.cells.map((cell) => (
|
|
132
|
+
<TableCell key={cell.id}>{cell.value}</TableCell>
|
|
133
|
+
))}
|
|
134
|
+
<TableCell>
|
|
135
|
+
<div style={{ display: 'flex', gap: '0.5rem' }}>
|
|
136
|
+
<IconButton
|
|
137
|
+
kind="ghost"
|
|
138
|
+
size={responsiveSize}
|
|
139
|
+
label={t('edit', 'Edit')}
|
|
140
|
+
onClick={() =>
|
|
141
|
+
launchWorkspace('payment-point-workspace', {
|
|
142
|
+
workspaceTitle: t('editPaymentPoint', 'Edit Payment Point'),
|
|
143
|
+
initialPaymentPoint: paymentPoint,
|
|
144
|
+
})
|
|
145
|
+
}>
|
|
146
|
+
<Edit />
|
|
147
|
+
</IconButton>
|
|
148
|
+
<IconButton
|
|
149
|
+
kind="danger--ghost"
|
|
150
|
+
size={responsiveSize}
|
|
151
|
+
label={t('delete', 'Delete')}
|
|
152
|
+
onClick={() => showDeletePaymentPointModal(paymentPoint)}>
|
|
153
|
+
<TrashCan />
|
|
154
|
+
</IconButton>
|
|
155
|
+
</div>
|
|
156
|
+
</TableCell>
|
|
157
|
+
</TableRow>
|
|
158
|
+
);
|
|
159
|
+
})}
|
|
160
|
+
</TableBody>
|
|
161
|
+
</Table>
|
|
162
|
+
{tableRows.length === 0 ? (
|
|
163
|
+
<div className={styles.tileContainer}>
|
|
164
|
+
<Tile className={styles.tile}>
|
|
165
|
+
<div className={styles.tileContent}>
|
|
166
|
+
<p className={styles.content}>{t('noPaymentPointsFound', 'No payment points found')}</p>
|
|
167
|
+
<p className={styles.emptyStateHelperText}>
|
|
168
|
+
{t('checkFilters', 'Please check the filters above and try again')}
|
|
169
|
+
</p>
|
|
170
|
+
</div>
|
|
171
|
+
</Tile>
|
|
172
|
+
</div>
|
|
173
|
+
) : null}
|
|
174
|
+
{tableRows.length > 0 && (
|
|
175
|
+
<Pagination
|
|
176
|
+
forwardText={t('nextPage', 'Next page')}
|
|
177
|
+
backwardText={t('previousPage', 'Previous page')}
|
|
178
|
+
page={currentPage}
|
|
179
|
+
pageSize={currentPageSize}
|
|
180
|
+
pageSizes={pageSizes}
|
|
181
|
+
totalItems={tableRows.length}
|
|
182
|
+
className={styles.pagination}
|
|
183
|
+
onChange={({ pageSize, page }) => {
|
|
184
|
+
if (pageSize !== currentPageSize) {
|
|
185
|
+
setCurrentPageSize(pageSize);
|
|
186
|
+
setCurrentPage(1);
|
|
187
|
+
}
|
|
188
|
+
if (page !== currentPage) {
|
|
189
|
+
setCurrentPage(page);
|
|
190
|
+
}
|
|
191
|
+
}}
|
|
192
|
+
/>
|
|
193
|
+
)}
|
|
194
|
+
</TableContainer>
|
|
195
|
+
)}
|
|
196
|
+
</DataTable>
|
|
197
|
+
</Layer>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export default PaymentPointTable;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import { PaymentPoint } from './type';
|
|
3
|
+
import useSWR from 'swr';
|
|
4
|
+
|
|
5
|
+
export const usePaymentPoints = () => {
|
|
6
|
+
const url = `${restBaseUrl}/cashier/cashPoint?v=full`;
|
|
7
|
+
|
|
8
|
+
const { data, isLoading, error, mutate } = useSWR<FetchResponse<{ results: Array<PaymentPoint> }>>(url, openmrsFetch);
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
paymentPoints: data?.data?.results ?? [],
|
|
12
|
+
error,
|
|
13
|
+
isLoading,
|
|
14
|
+
mutate,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import { type PaymentPoint } from '../type';
|
|
3
|
+
import { mutate } from 'swr';
|
|
4
|
+
|
|
5
|
+
export const createPaymentPoint = (payload: Partial<PaymentPoint>) => {
|
|
6
|
+
const url = `${restBaseUrl}/cashier/cashPoint?v=full`;
|
|
7
|
+
return openmrsFetch(url, {
|
|
8
|
+
method: 'POST',
|
|
9
|
+
body: payload,
|
|
10
|
+
headers: {
|
|
11
|
+
'Content-Type': 'application/json',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const updatePaymentPoint = (uuid: string, payload: Partial<PaymentPoint>) => {
|
|
17
|
+
const url = `${restBaseUrl}/cashier/cashPoint/${uuid}`;
|
|
18
|
+
return openmrsFetch(url, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
body: payload,
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const deletePaymentPoint = (uuid: string) => {
|
|
28
|
+
const url = `${restBaseUrl}/cashier/cashPoint/${uuid}`;
|
|
29
|
+
return openmrsFetch(url, {
|
|
30
|
+
method: 'DELETE',
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const handleMutation = (mutateUrl: string) => {
|
|
38
|
+
return mutate(mutateUrl);
|
|
39
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
|
+
|
|
5
|
+
.form {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
justify-content: space-between;
|
|
9
|
+
height: 100%;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.formContainer {
|
|
13
|
+
margin: layout.$spacing-05;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.tablet {
|
|
17
|
+
padding: layout.$spacing-06 layout.$spacing-05;
|
|
18
|
+
background-color: colors.$white;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.desktop {
|
|
22
|
+
padding: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.paymentMethods {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
row-gap: layout.$spacing-05;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.formStackControl {
|
|
32
|
+
row-gap: layout.$layout-01;
|
|
33
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import {
|
|
4
|
+
DefaultWorkspaceProps,
|
|
5
|
+
ResponsiveWrapper,
|
|
6
|
+
restBaseUrl,
|
|
7
|
+
showSnackbar,
|
|
8
|
+
useLayoutType,
|
|
9
|
+
} from '@openmrs/esm-framework';
|
|
10
|
+
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
|
11
|
+
import styles from './billing-payment-point.workspace.scss';
|
|
12
|
+
import { TextInput, ButtonSet, Button, InlineLoading, Stack, Toggle } from '@carbon/react';
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
15
|
+
import classNames from 'classnames';
|
|
16
|
+
import { type PaymentPoint } from '../type';
|
|
17
|
+
import { createPaymentPoint, updatePaymentPoint, handleMutation } from './billing-payment-point.resource';
|
|
18
|
+
|
|
19
|
+
const paymentPointSchema = z.object({
|
|
20
|
+
name: z.string().min(1, { message: 'Payment point name is required' }),
|
|
21
|
+
description: z.string().min(1, { message: 'Description is required' }),
|
|
22
|
+
retired: z.boolean().optional().default(false),
|
|
23
|
+
location: z.string().optional().default(''),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
type PaymentPointFormSchema = z.infer<typeof paymentPointSchema>;
|
|
27
|
+
|
|
28
|
+
type PaymentPointWorkspaceProps = DefaultWorkspaceProps & {
|
|
29
|
+
initialPaymentPoint?: PaymentPoint;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const PaymentPointWorkspace: React.FC<PaymentPointWorkspaceProps> = ({
|
|
33
|
+
closeWorkspace,
|
|
34
|
+
promptBeforeClosing,
|
|
35
|
+
closeWorkspaceWithSavedChanges,
|
|
36
|
+
initialPaymentPoint = {} as PaymentPoint,
|
|
37
|
+
}) => {
|
|
38
|
+
const { t } = useTranslation();
|
|
39
|
+
const isTablet = useLayoutType() === 'tablet';
|
|
40
|
+
const isEditMode = !!initialPaymentPoint?.uuid;
|
|
41
|
+
|
|
42
|
+
const formDefaultValues: PaymentPointFormSchema = isEditMode
|
|
43
|
+
? {
|
|
44
|
+
name: initialPaymentPoint.name ?? '',
|
|
45
|
+
description: initialPaymentPoint.description ?? '',
|
|
46
|
+
retired: initialPaymentPoint.retired ?? false,
|
|
47
|
+
location: initialPaymentPoint.location?.uuid ?? '',
|
|
48
|
+
}
|
|
49
|
+
: {
|
|
50
|
+
name: '',
|
|
51
|
+
description: '',
|
|
52
|
+
retired: false,
|
|
53
|
+
location: '',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const formMethods = useForm<PaymentPointFormSchema>({
|
|
57
|
+
resolver: zodResolver(paymentPointSchema),
|
|
58
|
+
mode: 'all',
|
|
59
|
+
defaultValues: formDefaultValues,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const { errors, isSubmitting, isDirty } = formMethods.formState;
|
|
63
|
+
|
|
64
|
+
const onSubmit = async (data: PaymentPointFormSchema) => {
|
|
65
|
+
const payload: Partial<PaymentPoint> = {
|
|
66
|
+
name: data.name,
|
|
67
|
+
description: data.description,
|
|
68
|
+
retired: data.retired ?? false,
|
|
69
|
+
...(data.location && { location: { uuid: data.location } as any }),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const response = isEditMode
|
|
74
|
+
? await updatePaymentPoint(initialPaymentPoint.uuid, payload)
|
|
75
|
+
: await createPaymentPoint(payload);
|
|
76
|
+
|
|
77
|
+
if (response.ok) {
|
|
78
|
+
const successMessage = isEditMode
|
|
79
|
+
? t('paymentPointUpdated', 'Payment point updated successfully')
|
|
80
|
+
: t('paymentPointCreated', 'Payment point created successfully');
|
|
81
|
+
|
|
82
|
+
const successSubtitle = isEditMode
|
|
83
|
+
? t('paymentPointUpdatedSubtitle', 'The payment point has been updated successfully')
|
|
84
|
+
: t('paymentPointCreatedSubtitle', 'The payment point has been created successfully');
|
|
85
|
+
|
|
86
|
+
showSnackbar({
|
|
87
|
+
title: successMessage,
|
|
88
|
+
subtitle: successSubtitle,
|
|
89
|
+
kind: 'success',
|
|
90
|
+
isLowContrast: true,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
closeWorkspaceWithSavedChanges();
|
|
94
|
+
handleMutation(`${restBaseUrl}/cashier/cashPoint?v=full`);
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const errorObject = error?.responseBody?.error;
|
|
98
|
+
const errorMessage = errorObject?.message ?? 'An error occurred while saving the payment point';
|
|
99
|
+
|
|
100
|
+
showSnackbar({
|
|
101
|
+
title: t('paymentPointSaveFailed', 'Payment point save failed'),
|
|
102
|
+
subtitle: t(
|
|
103
|
+
'paymentPointSaveFailedSubtitle',
|
|
104
|
+
'An error occurred while saving the payment point: {{errorMessage}}',
|
|
105
|
+
{ errorMessage },
|
|
106
|
+
),
|
|
107
|
+
kind: 'error',
|
|
108
|
+
isLowContrast: true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const handleError = (errors) => {
|
|
114
|
+
showSnackbar({
|
|
115
|
+
title: t('paymentPointSaveFailed', 'Payment point save failed'),
|
|
116
|
+
subtitle: t('paymentPointSaveFailedSubtitle', 'Please check the form for errors'),
|
|
117
|
+
kind: 'error',
|
|
118
|
+
isLowContrast: true,
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (isDirty) {
|
|
124
|
+
promptBeforeClosing(() => isDirty);
|
|
125
|
+
}
|
|
126
|
+
}, [isDirty, promptBeforeClosing]);
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<FormProvider {...formMethods}>
|
|
130
|
+
<form onSubmit={formMethods.handleSubmit(onSubmit, handleError)} className={styles.form}>
|
|
131
|
+
<div className={styles.formContainer}>
|
|
132
|
+
<Stack className={styles.formStackControl} gap={7}>
|
|
133
|
+
<ResponsiveWrapper>
|
|
134
|
+
<Controller
|
|
135
|
+
name="name"
|
|
136
|
+
control={formMethods.control}
|
|
137
|
+
render={({ field }) => (
|
|
138
|
+
<TextInput
|
|
139
|
+
{...field}
|
|
140
|
+
id="name"
|
|
141
|
+
type="text"
|
|
142
|
+
labelText={t('paymentPointName', 'Payment point name')}
|
|
143
|
+
placeholder={t('paymentPointNamePlaceholder', 'Enter payment point name')}
|
|
144
|
+
invalid={!!errors.name}
|
|
145
|
+
invalidText={errors.name?.message}
|
|
146
|
+
/>
|
|
147
|
+
)}
|
|
148
|
+
/>
|
|
149
|
+
</ResponsiveWrapper>
|
|
150
|
+
|
|
151
|
+
<ResponsiveWrapper>
|
|
152
|
+
<Controller
|
|
153
|
+
name="description"
|
|
154
|
+
control={formMethods.control}
|
|
155
|
+
render={({ field }) => (
|
|
156
|
+
<TextInput
|
|
157
|
+
{...field}
|
|
158
|
+
id="description"
|
|
159
|
+
type="text"
|
|
160
|
+
labelText={t('paymentPointDescription', 'Payment point description')}
|
|
161
|
+
placeholder={t('paymentPointDescriptionPlaceholder', 'Enter payment point description')}
|
|
162
|
+
invalid={!!errors.description}
|
|
163
|
+
invalidText={errors.description?.message}
|
|
164
|
+
/>
|
|
165
|
+
)}
|
|
166
|
+
/>
|
|
167
|
+
</ResponsiveWrapper>
|
|
168
|
+
</Stack>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<ButtonSet className={classNames({ [styles.tablet]: isTablet, [styles.desktop]: !isTablet })}>
|
|
172
|
+
<Button style={{ maxWidth: '50%' }} kind="secondary" onClick={() => closeWorkspace()}>
|
|
173
|
+
{t('cancel', 'Cancel')}
|
|
174
|
+
</Button>
|
|
175
|
+
<Button
|
|
176
|
+
disabled={isSubmitting || Object.keys(errors).length > 0}
|
|
177
|
+
style={{ maxWidth: '50%' }}
|
|
178
|
+
kind="primary"
|
|
179
|
+
type="submit">
|
|
180
|
+
{isSubmitting ? (
|
|
181
|
+
<span style={{ display: 'flex', justifyItems: 'center' }}>
|
|
182
|
+
{t('submitting', 'Submitting...')} <InlineLoading status="active" iconDescription="Loading" />
|
|
183
|
+
</span>
|
|
184
|
+
) : (
|
|
185
|
+
t('saveAndClose', 'Save & close')
|
|
186
|
+
)}
|
|
187
|
+
</Button>
|
|
188
|
+
</ButtonSet>
|
|
189
|
+
</form>
|
|
190
|
+
</FormProvider>
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export default PaymentPointWorkspace;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface PaymentPoint {
|
|
2
|
+
uuid: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
retired: boolean;
|
|
6
|
+
retireReason: any;
|
|
7
|
+
auditInfo: AuditInfo;
|
|
8
|
+
location: Location;
|
|
9
|
+
resourceVersion: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface AuditInfo {
|
|
13
|
+
creator: Creator;
|
|
14
|
+
dateCreated: string;
|
|
15
|
+
changedBy: any;
|
|
16
|
+
dateChanged: any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface Creator {
|
|
20
|
+
uuid: string;
|
|
21
|
+
display: string;
|
|
22
|
+
links: Array<Link>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface Link {
|
|
26
|
+
rel: string;
|
|
27
|
+
uri: string;
|
|
28
|
+
resourceAlias: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface Location {
|
|
32
|
+
uuid: string;
|
|
33
|
+
display: string;
|
|
34
|
+
links: Array<Link>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '@carbon/colors';
|
|
4
|
+
|
|
5
|
+
.adminPage {
|
|
6
|
+
padding: layout.$spacing-05;
|
|
7
|
+
background: var(--cds-field);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
--cds-border-interactive: #2e6b8a;
|
|
12
|
+
--cds-focus: none;
|
|
13
|
+
--cds-interactive: #2e6b8a;
|
|
14
|
+
--cds-link-primary: #2e6b8a;
|
|
15
|
+
}
|