@thrustdevs/esm-procedure-orders-app 1.0.2-pre.6

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 (207) hide show
  1. package/.turbo/turbo-build.log +41 -0
  2. package/README.md +7 -0
  3. package/dist/122.js +1 -0
  4. package/dist/122.js.map +1 -0
  5. package/dist/144.js +2 -0
  6. package/dist/144.js.LICENSE.txt +19 -0
  7. package/dist/144.js.map +1 -0
  8. package/dist/182.js +1 -0
  9. package/dist/182.js.map +1 -0
  10. package/dist/205.js +1 -0
  11. package/dist/205.js.map +1 -0
  12. package/dist/216.js +2 -0
  13. package/dist/216.js.LICENSE.txt +9 -0
  14. package/dist/216.js.map +1 -0
  15. package/dist/290.js +2 -0
  16. package/dist/290.js.LICENSE.txt +5 -0
  17. package/dist/290.js.map +1 -0
  18. package/dist/300.js +1 -0
  19. package/dist/341.js +2 -0
  20. package/dist/341.js.LICENSE.txt +29 -0
  21. package/dist/341.js.map +1 -0
  22. package/dist/41.js +2 -0
  23. package/dist/41.js.LICENSE.txt +9 -0
  24. package/dist/41.js.map +1 -0
  25. package/dist/470.js +1 -0
  26. package/dist/470.js.map +1 -0
  27. package/dist/495.js +1 -0
  28. package/dist/495.js.map +1 -0
  29. package/dist/506.js +2 -0
  30. package/dist/506.js.LICENSE.txt +39 -0
  31. package/dist/506.js.map +1 -0
  32. package/dist/537.js +1 -0
  33. package/dist/537.js.map +1 -0
  34. package/dist/647.js +2 -0
  35. package/dist/647.js.LICENSE.txt +5 -0
  36. package/dist/647.js.map +1 -0
  37. package/dist/7.js +1 -0
  38. package/dist/7.js.map +1 -0
  39. package/dist/719.js +2 -0
  40. package/dist/719.js.LICENSE.txt +5 -0
  41. package/dist/719.js.map +1 -0
  42. package/dist/720.js +1 -0
  43. package/dist/720.js.map +1 -0
  44. package/dist/876.js +1 -0
  45. package/dist/876.js.map +1 -0
  46. package/dist/883.js +1 -0
  47. package/dist/883.js.map +1 -0
  48. package/dist/89.js +1 -0
  49. package/dist/89.js.map +1 -0
  50. package/dist/892.js +1 -0
  51. package/dist/892.js.map +1 -0
  52. package/dist/895.js +1 -0
  53. package/dist/895.js.map +1 -0
  54. package/dist/913.js +2 -0
  55. package/dist/913.js.LICENSE.txt +32 -0
  56. package/dist/913.js.map +1 -0
  57. package/dist/924.js +1 -0
  58. package/dist/924.js.map +1 -0
  59. package/dist/943.js +1 -0
  60. package/dist/943.js.map +1 -0
  61. package/dist/99.js +2 -0
  62. package/dist/99.js.LICENSE.txt +5 -0
  63. package/dist/99.js.map +1 -0
  64. package/dist/kenyaemr-esm-procedure-orders-app.js +1 -0
  65. package/dist/kenyaemr-esm-procedure-orders-app.js.buildmanifest.json +786 -0
  66. package/dist/kenyaemr-esm-procedure-orders-app.js.map +1 -0
  67. package/dist/main.js +2 -0
  68. package/dist/main.js.LICENSE.txt +35 -0
  69. package/dist/main.js.map +1 -0
  70. package/dist/routes.json +1 -0
  71. package/jest.config.js +8 -0
  72. package/package.json +55 -0
  73. package/src/completed-list/completed-list.component.tsx +40 -0
  74. package/src/completed-list/completed-list.resource.ts +0 -0
  75. package/src/completed-list/completed-list.scss +223 -0
  76. package/src/components/create-dashboard-link.component.tsx +35 -0
  77. package/src/components/overlay/hook.ts +47 -0
  78. package/src/components/overlay/overlay.component.tsx +42 -0
  79. package/src/components/overlay/overlay.scss +92 -0
  80. package/src/config-schema.ts +78 -0
  81. package/src/constants.ts +5 -0
  82. package/src/declarations.d.ts +6 -0
  83. package/src/empty-state/empty-state-component.tsx +21 -0
  84. package/src/empty-state/empty-state.scss +23 -0
  85. package/src/form/post-procedures/post-procedure-form.component.tsx +468 -0
  86. package/src/form/post-procedures/post-procedure-form.scss +189 -0
  87. package/src/form/post-procedures/post-procedure.resource.tsx +71 -0
  88. package/src/form/procedures-orders/add-procedures-order/add-procedures-order.scss +44 -0
  89. package/src/form/procedures-orders/add-procedures-order/add-procedures-order.workspace.tsx +93 -0
  90. package/src/form/procedures-orders/add-procedures-order/procedures-order-form.component.tsx +476 -0
  91. package/src/form/procedures-orders/add-procedures-order/procedures-order-form.scss +80 -0
  92. package/src/form/procedures-orders/add-procedures-order/procedures-order.ts +17 -0
  93. package/src/form/procedures-orders/add-procedures-order/procedures-type-search.scss +115 -0
  94. package/src/form/procedures-orders/add-procedures-order/procedures-type-search.tsx +236 -0
  95. package/src/form/procedures-orders/add-procedures-order/useProceduresTypes.ts +93 -0
  96. package/src/form/procedures-orders/api.ts +282 -0
  97. package/src/form/procedures-orders/order-config.ts +48 -0
  98. package/src/form/procedures-orders/procedures-order-basket-panel/procedures-icon.component.tsx +39 -0
  99. package/src/form/procedures-orders/procedures-order-basket-panel/procedures-order-basket-item-tile.component.tsx +100 -0
  100. package/src/form/procedures-orders/procedures-order-basket-panel/procedures-order-basket-item-tile.scss +72 -0
  101. package/src/form/procedures-orders/procedures-order-basket-panel/procedures-order-basket-panel.extension.tsx +190 -0
  102. package/src/form/procedures-orders/procedures-order-basket-panel/procedures-order-basket-panel.scss +74 -0
  103. package/src/form/procedures-orders/procedures-order-basket-panel/procedures-order-basket.scss +55 -0
  104. package/src/header/procedure-header.component.tsx +32 -0
  105. package/src/header/procedure-header.scss +70 -0
  106. package/src/header/procedure-illustration.component.tsx +52 -0
  107. package/src/hooks/useOrdersWorklist.ts +70 -0
  108. package/src/hooks/useSearchGroupedResults.ts +22 -0
  109. package/src/hooks/useSearchResults.ts +39 -0
  110. package/src/index.ts +59 -0
  111. package/src/left-panel-link.tsx +40 -0
  112. package/src/not-done-list/not-done-list.component.tsx +44 -0
  113. package/src/not-done-list/not-done.scss +207 -0
  114. package/src/patient-chart/patient-procedure-order-results-table.resource.ts +43 -0
  115. package/src/patient-chart/patient-procedure-order-results.component.tsx +12 -0
  116. package/src/patient-chart/patient-procedure-order-results.resource.ts +485 -0
  117. package/src/patient-chart/patient-procedure-results.component.tsx +30 -0
  118. package/src/patient-chart/procedure-active-order/procedure-active-order-results.component.tsx +390 -0
  119. package/src/patient-chart/procedure-active-order/procedure-active-order-results.scss +78 -0
  120. package/src/patient-chart/procedure-order-referals/procedure-order-referals.component.tsx +394 -0
  121. package/src/patient-chart/procedure-order-referals/procedure-order-referals.resource.tsx +0 -0
  122. package/src/patient-chart/procedure-order-referals/procedure-order-referals.scss +78 -0
  123. package/src/patient-chart/procedure-past-test/laboratory-past-test-order-results.component.tsx +366 -0
  124. package/src/patient-chart/procedure-past-test/laboratory-past-test-order-results.scss +74 -0
  125. package/src/patient-chart/procedure-tabs/laboratory-order-tabs.component.tsx +44 -0
  126. package/src/patient-chart/procedure-tabs/laboratory-order-tabs.scss +7 -0
  127. package/src/patient-chart/procedure-workspaces/laboratory-referral.workspace.component.tsx +11 -0
  128. package/src/patient-chart/procedure-workspaces/laboratory-referral.workspace.scss +0 -0
  129. package/src/patient-chart/results-summary/print-results-summary.component.tsx +152 -0
  130. package/src/patient-chart/results-summary/print-results-summary.scss +80 -0
  131. package/src/patient-chart/results-summary/print-results-table.component.tsx +134 -0
  132. package/src/patient-chart/results-summary/results-summary.resource.tsx +174 -0
  133. package/src/patient-chart/results-summary/results-summary.scss +158 -0
  134. package/src/patient-chart/results-summary/send-email-dialog.component.tsx +59 -0
  135. package/src/patient-chart/results-summary/test-children-results.component.tsx +177 -0
  136. package/src/patient-chart/results-summary/test-print-results-table.component.tsx +105 -0
  137. package/src/patient-chart/results-summary/test-results-table.component.tsx +103 -0
  138. package/src/print/print-procedure-results.component.tsx +49 -0
  139. package/src/print/print-procedure.component.tsx +105 -0
  140. package/src/print/print-procedure.scss +98 -0
  141. package/src/procedure-tabs/completed-tab.component.tsx +12 -0
  142. package/src/procedure-tabs/not-done-tab.component.tsx +12 -0
  143. package/src/procedure-tabs/referred-tab.component.tsx +12 -0
  144. package/src/procedure-tabs/work-list-tab.component.tsx +13 -0
  145. package/src/procedure.component.tsx +24 -0
  146. package/src/procedures-ordered/_pick-procedure-request-menu.component.tsx +33 -0
  147. package/src/procedures-ordered/pick-procedure-order/add-to-worklist-dialog.component.tsx +105 -0
  148. package/src/procedures-ordered/pick-procedure-order/add-to-worklist-dialog.resource.ts +106 -0
  149. package/src/procedures-ordered/pick-procedure-order/add-to-worklist-dialog.scss +38 -0
  150. package/src/procedures-ordered/pick-procedure-request-menu.component.tsx +32 -0
  151. package/src/procedures-ordered/procedure-dialogs/add-to-worklist-dialog.component.tsx +300 -0
  152. package/src/procedures-ordered/procedure-dialogs/add-to-worklist-dialog.resource.ts +153 -0
  153. package/src/procedures-ordered/procedure-dialogs/add-to-worklist-dialog.scss +38 -0
  154. package/src/procedures-ordered/procedure-instructions/instructions.scss +24 -0
  155. package/src/procedures-ordered/procedure-instructions/procedure-instructions-menu.component.tsx +32 -0
  156. package/src/procedures-ordered/procedure-instructions/procedure-instructions.component.tsx +78 -0
  157. package/src/procedures-ordered/procedure-instructions/procedure-instructions.scss +24 -0
  158. package/src/procedures-ordered/procedure-queue.scss +211 -0
  159. package/src/procedures-ordered/procedure-tabs.component.tsx +104 -0
  160. package/src/procedures-ordered/procedure-tests/procedure-tests.component.tsx +83 -0
  161. package/src/procedures-ordered/procedure-tests/procedure-tests.resource.ts +14 -0
  162. package/src/procedures-ordered/procedure-tests/procedure-tests.scss +12 -0
  163. package/src/procedures-ordered/procedures-ordered-list.component.tsx +38 -0
  164. package/src/procedures-ordered/reject-order-dialog/reject-order-dialog.scss +14 -0
  165. package/src/procedures-ordered/reject-order-dialog/reject-procedure-order-dialog.component.tsx +98 -0
  166. package/src/procedures-ordered/reject-reason/procedure-reject-reason-menu.component.tsx +32 -0
  167. package/src/procedures-ordered/reject-reason/procedure-reject-reason.component.tsx +40 -0
  168. package/src/procedures-ordered/transition-patient-new-queue/transition-latest-queue-entry-button.component.tsx +42 -0
  169. package/src/procedures-ordered/transition-patient-new-queue/transition-latest-queue-entry-button.scss +14 -0
  170. package/src/procedures-ordered/transition-patient-new-queue/transition-latest-queue-entry-button.test.tsx +67 -0
  171. package/src/referred-procedures/referred-procedures.component.tsx +37 -0
  172. package/src/results/result-form-field.component.tsx +141 -0
  173. package/src/results/result-form.component.tsx +120 -0
  174. package/src/results/result-form.resource.ts +361 -0
  175. package/src/results/result-form.scss +22 -0
  176. package/src/root.component.tsx +16 -0
  177. package/src/routes.json +152 -0
  178. package/src/setup-tests.ts +7 -0
  179. package/src/shared/ui/common/action-button/action-button.component.tsx +68 -0
  180. package/src/shared/ui/common/action-button/action-button.scss +12 -0
  181. package/src/shared/ui/common/action-button/order-action-extension.component.tsx +21 -0
  182. package/src/shared/ui/common/grouped-orders-table.component.tsx +176 -0
  183. package/src/shared/ui/common/grouped-orders-table.scss +30 -0
  184. package/src/shared/ui/common/grouped-procedure-types.ts +47 -0
  185. package/src/shared/ui/common/list-order-details.component.tsx +171 -0
  186. package/src/shared/ui/common/list-order-details.resource.ts +41 -0
  187. package/src/shared/ui/common/list-order-details.scss +118 -0
  188. package/src/shared/ui/common/orders-date-range-picker.scss +15 -0
  189. package/src/shared/ui/common/orders-date-range-picker.tsx +38 -0
  190. package/src/summary-tiles/procedure-summary-tiles.component.tsx +36 -0
  191. package/src/summary-tiles/procedure-summary-tiles.scss +11 -0
  192. package/src/summary-tiles/procedure-summary.resource.tsx +79 -0
  193. package/src/summary-tiles/summary-tile.component.tsx +41 -0
  194. package/src/summary-tiles/summary-tile.scss +53 -0
  195. package/src/types/index.ts +661 -0
  196. package/src/types/patient-queue.ts +77 -0
  197. package/src/ui-components/overflow-menu.component.tsx +74 -0
  198. package/src/ui-components/overflow-menu.scss +39 -0
  199. package/src/utils/functions.ts +236 -0
  200. package/src/utils/orders-table/orders-data-table.component.tsx +129 -0
  201. package/src/utils/orders-table/orders-data-table.scss +50 -0
  202. package/src/work-list/work-list.component.tsx +38 -0
  203. package/src/work-list/work-list.resource.ts +26 -0
  204. package/src/work-list/work-list.scss +207 -0
  205. package/translations/en.json +141 -0
  206. package/tsconfig.json +5 -0
  207. package/webpack.config.js +1 -0
@@ -0,0 +1,83 @@
1
+ import React, { useMemo } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+
4
+ import {
5
+ DataTable,
6
+ Table,
7
+ TableBody,
8
+ TableCell,
9
+ TableContainer,
10
+ TableHead,
11
+ TableHeader,
12
+ TableRow,
13
+ } from '@carbon/react';
14
+ import { ErrorState } from '@openmrs/esm-framework';
15
+ import styles from '../procedure-queue.scss';
16
+ import PickProcedureRequestActionMenu from '../_pick-procedure-request-menu.component';
17
+ import { type Encounter } from '../../types';
18
+
19
+ interface ProceduresProps {
20
+ encounter: Encounter;
21
+ queueId: string;
22
+ }
23
+
24
+ const ProceduresTests: React.FC<ProceduresProps> = ({ encounter, queueId }) => {
25
+ const { t } = useTranslation();
26
+ const columns = [
27
+ { id: 1, header: t('order', 'Order'), key: 'order', align: 'left' },
28
+ {
29
+ id: 2,
30
+ header: t('orderType', 'OrderType'),
31
+ key: 'orderType',
32
+ align: 'center',
33
+ },
34
+ { id: 3, header: t('actions', 'Actions'), key: 'actions', align: 'center' },
35
+ ];
36
+
37
+ const tableRows = useMemo(() => {
38
+ return encounter?.orders?.map((item) => ({
39
+ ...item,
40
+ id: item?.uuid,
41
+ order: item?.display,
42
+ orderType: item?.type,
43
+ actions: <PickProcedureRequestActionMenu closeModal={() => true} order={item} />,
44
+ }));
45
+ }, [encounter]);
46
+
47
+ if (!encounter) {
48
+ return <ErrorState error={'Error Loading encounter'} headerTitle={'Tests Error'} />;
49
+ }
50
+
51
+ return (
52
+ <DataTable rows={tableRows} headers={columns} isSortable useZebraStyles>
53
+ {({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
54
+ <TableContainer className={styles.tableContainer}>
55
+ <Table {...getTableProps()} className={styles.activePatientsTable}>
56
+ <TableHead>
57
+ <TableRow>
58
+ {headers.map((header) => (
59
+ <TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
60
+ ))}
61
+ </TableRow>
62
+ </TableHead>
63
+ <TableBody>
64
+ {rows.map((row, index) => {
65
+ return (
66
+ <React.Fragment key={row.id}>
67
+ <TableRow {...getRowProps({ row })} key={row.id}>
68
+ {row.cells.map((cell) => (
69
+ <TableCell key={cell.id}>{cell.value?.content ?? cell.value}</TableCell>
70
+ ))}
71
+ </TableRow>
72
+ </React.Fragment>
73
+ );
74
+ })}
75
+ </TableBody>
76
+ </Table>
77
+ </TableContainer>
78
+ )}
79
+ </DataTable>
80
+ );
81
+ };
82
+
83
+ export default ProceduresTests;
@@ -0,0 +1,14 @@
1
+ import { FetchResponse, openmrsFetch, restBaseUrl, useConfig } from '@openmrs/esm-framework';
2
+ import useSWR from 'swr';
3
+ import { type Result } from '../../patient-chart/patient-procedure-order-results.resource';
4
+ export function useGetLabOrders(encounterUuid: string) {
5
+ const apiUrl = `${restBaseUrl}/encounter/${encounterUuid}?v=full`;
6
+
7
+ const { data, error, isLoading } = useSWR<{ data: Result }, Error>(apiUrl, openmrsFetch);
8
+
9
+ return {
10
+ labOrders: data?.data ? data?.data?.orders : [],
11
+ isLoading,
12
+ isError: error,
13
+ };
14
+ }
@@ -0,0 +1,12 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+ @use '@openmrs/esm-styleguide/src/vars' as vars;
4
+
5
+ .cardContainer {
6
+ background-color: vars.$ui-02;
7
+ display: flex;
8
+ justify-content: space-between;
9
+ padding: 0 spacing.$spacing-05 spacing.$spacing-10 spacing.$spacing-03;
10
+ flex-flow: row wrap;
11
+ margin-top: -spacing.$spacing-03;
12
+ }
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { useOrdersWorklist } from '../hooks/useOrdersWorklist';
3
+ import GroupedOrdersTable from '../shared/ui/common/grouped-orders-table.component';
4
+ import { DataTableSkeleton } from '@carbon/react';
5
+ import { useTranslation } from 'react-i18next';
6
+ interface ProcedurePatientListProps {
7
+ fulfillerStatus: string;
8
+ }
9
+
10
+ const ProcedureOrderedList: React.FC<ProcedurePatientListProps> = () => {
11
+ const { t } = useTranslation();
12
+ const { workListEntries, isLoading } = useOrdersWorklist('', '');
13
+
14
+ if (isLoading) {
15
+ return <DataTableSkeleton role="progressbar" />;
16
+ }
17
+
18
+ if (workListEntries?.length >= 0) {
19
+ return (
20
+ <GroupedOrdersTable
21
+ orders={workListEntries}
22
+ showActions={true}
23
+ showStatus={true}
24
+ showOrderType={true}
25
+ showStartButton={false}
26
+ title={t('proceduresOrdered', 'Procedures Ordered')}
27
+ actions={[
28
+ {
29
+ actionName: 'add-procedure-to-worklist-dialog',
30
+ },
31
+ { actionName: 'reject-procedure-order-dialog' },
32
+ ]}
33
+ />
34
+ );
35
+ }
36
+ };
37
+
38
+ export default ProcedureOrderedList;
@@ -0,0 +1,14 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+
4
+ .section {
5
+ margin: spacing.$spacing-03;
6
+ }
7
+
8
+ .sectionTitle {
9
+ margin-bottom: spacing.$spacing-04;
10
+ }
11
+
12
+ .modalBody {
13
+ padding-bottom: spacing.$spacing-05;
14
+ }
@@ -0,0 +1,98 @@
1
+ import React, { useState } from 'react';
2
+
3
+ import { Button, Form, ModalBody, ModalFooter, ModalHeader, TextArea } from '@carbon/react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import styles from './reject-order-dialog.scss';
6
+ import { showNotification, showSnackbar } from '@openmrs/esm-framework';
7
+ import { mutate } from 'swr';
8
+ import { updateOrder } from '../pick-procedure-order/add-to-worklist-dialog.resource';
9
+ import { type Result } from '../../types';
10
+ import capitalize from 'lodash-es/capitalize';
11
+
12
+ interface RejectProcedureOrderDialogProps {
13
+ order: Result;
14
+ closeModal: () => void;
15
+ }
16
+
17
+ const RejectProcedureOrderDialog: React.FC<RejectProcedureOrderDialogProps> = ({ order, closeModal }) => {
18
+ const { t } = useTranslation();
19
+
20
+ const [notes, setNotes] = useState('');
21
+
22
+ const rejectOrder = async (event) => {
23
+ event.preventDefault();
24
+
25
+ const payload = {
26
+ fulfillerStatus: 'DECLINED',
27
+ fulfillerComment: notes,
28
+ };
29
+ updateOrder(order.uuid, payload).then(
30
+ () => {
31
+ showSnackbar({
32
+ isLowContrast: true,
33
+ title: t('rejectOrder', 'Rejected Order'),
34
+ kind: 'success',
35
+ subtitle: t(
36
+ 'successfullyrejected',
37
+ `You have successfully rejected an Order with OrderNumber ${order.orderNumber} `,
38
+ ),
39
+ });
40
+ closeModal();
41
+ mutate((key) => typeof key === 'string' && key.startsWith('/ws/rest/v1/order'), undefined, {
42
+ revalidate: true,
43
+ });
44
+ },
45
+ (err) => {
46
+ showNotification({
47
+ title: t(`errorRejecting order', 'Error Rejecting a order`),
48
+ kind: 'error',
49
+ critical: true,
50
+ description: err?.message,
51
+ });
52
+ },
53
+ );
54
+ };
55
+ const orderName = capitalize(order?.concept?.display);
56
+ const orderNumber = order?.orderNumber;
57
+
58
+ return (
59
+ <div>
60
+ <Form onSubmit={rejectOrder}>
61
+ <div className="cds--modal-header">
62
+ <h3 className="cds--modal-header__heading">{t('rejectProcedureOrder', 'Reject Procedure Order')}</h3>
63
+ </div>
64
+ <div className="cds--modal-content">
65
+ <p>
66
+ {t('confirmationRejectMessages', `Do you want to reject this order: {{orderName}} - {{orderNumber}}?`, {
67
+ orderName,
68
+ orderNumber,
69
+ })}
70
+ </p>
71
+ <section className={styles.section}>
72
+ <TextArea
73
+ labelText={t('notes', 'Enter Comments ')}
74
+ id="nextNotes"
75
+ name="nextNotes"
76
+ invalidText="Required"
77
+ helperText="Please enter comment"
78
+ maxCount={500}
79
+ enableCounter
80
+ onChange={(e) => setNotes(e.target.value)}
81
+ />
82
+ </section>
83
+ </div>
84
+
85
+ <ModalFooter>
86
+ <Button kind="secondary" onClick={closeModal}>
87
+ {t('cancel', 'Cancel')}
88
+ </Button>
89
+ <Button kind="danger" type="submit">
90
+ {t('rejectOrder', 'Reject Order')}
91
+ </Button>
92
+ </ModalFooter>
93
+ </Form>
94
+ </div>
95
+ );
96
+ };
97
+
98
+ export default RejectProcedureOrderDialog;
@@ -0,0 +1,32 @@
1
+ import { OverflowMenuItem } from '@carbon/react';
2
+ import { showModal } from '@openmrs/esm-framework';
3
+ import React, { useCallback } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ interface ProcedureRejectionActionMenuProps {
7
+ order: any;
8
+ closeModal: () => void;
9
+ }
10
+
11
+ const ProcedureRejectionActionMenu: React.FC<ProcedureRejectionActionMenuProps> = ({ order }) => {
12
+ const { t } = useTranslation();
13
+
14
+ const launchProcedureRejectionModal = useCallback(() => {
15
+ const dispose = showModal('procedure-reject-reason-modal', {
16
+ closeModal: () => dispose(),
17
+ order,
18
+ });
19
+ }, [order]);
20
+
21
+ return (
22
+ <OverflowMenuItem
23
+ itemText={t('procedureRejectionModal', 'Procedure Rejection')}
24
+ onClick={launchProcedureRejectionModal}
25
+ style={{
26
+ maxWidth: '100vw',
27
+ }}
28
+ />
29
+ );
30
+ };
31
+
32
+ export default ProcedureRejectionActionMenu;
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { Button, ModalBody, ModalFooter, ModalHeader, Tile } from '@carbon/react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import styles from '../procedure-instructions/instructions.scss';
5
+ import { type Result } from '../../types';
6
+
7
+ interface ProcedureRejectReasonModalProps {
8
+ order: Result;
9
+ closeModal: () => void;
10
+ }
11
+
12
+ const ProcedureRejectReasonModal: React.FC<ProcedureRejectReasonModalProps> = ({ order, closeModal }) => {
13
+ const { t } = useTranslation();
14
+
15
+ return (
16
+ <div>
17
+ <ModalHeader closeModal={closeModal} title={t('reasonNotDone', 'Reason Not Done')} />
18
+ <ModalBody>
19
+ <div className={styles.modalBody}>
20
+ <section className={styles.section}>
21
+ <b />
22
+ <Tile>
23
+ <p>
24
+ <b>Rejection Reason:</b>
25
+ </p>
26
+ <p className={styles.instructions}>{order.fulfillerComment}</p>
27
+ </Tile>
28
+ </section>
29
+ </div>
30
+ </ModalBody>
31
+ <ModalFooter>
32
+ <Button kind="secondary" onClick={closeModal}>
33
+ {t('cancel', 'Cancel')}
34
+ </Button>
35
+ </ModalFooter>
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default ProcedureRejectReasonModal;
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button, InlineLoading } from '@carbon/react';
4
+ import { AirlineManageGates } from '@carbon/react/icons';
5
+ import { showModal, useVisit } from '@openmrs/esm-framework';
6
+
7
+ interface TransitionLatestQueueEntryButtonProps {
8
+ patientUuid: string;
9
+ }
10
+
11
+ const TransitionLatestQueueEntryButton: React.FC<TransitionLatestQueueEntryButtonProps> = ({ patientUuid }) => {
12
+ const { activeVisit, isLoading } = useVisit(patientUuid);
13
+ const shouldHideButton = !activeVisit;
14
+ const { t } = useTranslation();
15
+ if (shouldHideButton) {
16
+ return null;
17
+ }
18
+
19
+ const handleLaunchModal = () => {
20
+ const dispose = showModal('transition-patient-to-latest-queue-modal', {
21
+ closeModal: () => dispose(),
22
+ activeVisit,
23
+ });
24
+ };
25
+
26
+ if (isLoading) {
27
+ return <InlineLoading description={t('loading', 'Loading...')} />;
28
+ }
29
+
30
+ return (
31
+ <Button
32
+ iconDescription={t('transitionPatientToNewQueue', 'Transition patient to new queue')}
33
+ kind="tertiary"
34
+ onClick={handleLaunchModal}
35
+ renderIcon={AirlineManageGates}
36
+ size="sm">
37
+ {t('transition', 'Transition')}
38
+ </Button>
39
+ );
40
+ };
41
+
42
+ export default TransitionLatestQueueEntryButton;
@@ -0,0 +1,14 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/styles/scss/type';
3
+
4
+ // TODO: refactor to use esm-style-guide
5
+ .addPatientToQueue {
6
+ --cds-layout-size-height-context: var(--cds-layout-size-height-sm, 2rem);
7
+ --cds-layout-size-height: var(--cds-layout-size-height-context);
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ text-align: center;
12
+ padding: 0 layout.$spacing-04;
13
+ gap: layout.$spacing-05;
14
+ }
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { showModal, useVisit } from '@openmrs/esm-framework';
5
+ import TransitionLatestQueueEntryButton from './transition-latest-queue-entry-button.component';
6
+
7
+ jest.mock('@openmrs/esm-framework', () => ({
8
+ showModal: jest.fn(),
9
+ useVisit: jest.fn(),
10
+ }));
11
+
12
+ describe('TransitionLatestQueueEntryButton', () => {
13
+ const patientUuid = 'patient-uuid';
14
+ const mockActiveVisit = { uuid: 'visit-uuid', display: 'Test Visit' };
15
+
16
+ beforeEach(() => {
17
+ jest.clearAllMocks();
18
+ (useVisit as jest.Mock).mockReturnValue({
19
+ activeVisit: mockActiveVisit,
20
+ isLoading: false,
21
+ });
22
+ });
23
+
24
+ it('should render a button when an active visit exists', () => {
25
+ render(<TransitionLatestQueueEntryButton patientUuid={patientUuid} />);
26
+
27
+ expect(screen.getByRole('button', { name: /transition/i })).toBeInTheDocument();
28
+ });
29
+
30
+ it('should launch the transition queue modal when clicked', async () => {
31
+ const user = userEvent.setup();
32
+ render(<TransitionLatestQueueEntryButton patientUuid={patientUuid} />);
33
+
34
+ await user.click(screen.getByRole('button', { name: /transition/i }));
35
+
36
+ expect(showModal).toHaveBeenCalledTimes(1);
37
+ expect(showModal).toHaveBeenCalledWith(
38
+ 'transition-patient-to-latest-queue-modal',
39
+ expect.objectContaining({
40
+ closeModal: expect.any(Function),
41
+ activeVisit: mockActiveVisit,
42
+ }),
43
+ );
44
+ });
45
+
46
+ it('should show loading state when visit data is loading', () => {
47
+ (useVisit as jest.Mock).mockReturnValue({
48
+ activeVisit: null,
49
+ isLoading: true,
50
+ });
51
+
52
+ render(<TransitionLatestQueueEntryButton patientUuid={patientUuid} />);
53
+
54
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
55
+ });
56
+
57
+ it('should not render the button when no active visit exists', () => {
58
+ (useVisit as jest.Mock).mockReturnValue({
59
+ activeVisit: null,
60
+ isLoading: false,
61
+ });
62
+
63
+ render(<TransitionLatestQueueEntryButton patientUuid={patientUuid} />);
64
+
65
+ expect(screen.queryByRole('button', { name: /transition/i })).not.toBeInTheDocument();
66
+ });
67
+ });
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { useOrdersWorklist } from '../hooks/useOrdersWorklist';
3
+ import GroupedOrdersTable from '../shared/ui/common/grouped-orders-table.component';
4
+ import { DataTableSkeleton } from '@carbon/react';
5
+ import { useTranslation } from 'react-i18next';
6
+ interface WorklistProps {
7
+ fulfillerStatus: string;
8
+ }
9
+
10
+ const WorkList: React.FC<WorklistProps> = ({ fulfillerStatus }) => {
11
+ const { t } = useTranslation();
12
+ const { workListEntries, isLoading } = useOrdersWorklist('', fulfillerStatus);
13
+
14
+ if (isLoading) {
15
+ return <DataTableSkeleton role="progressbar" />;
16
+ }
17
+
18
+ if (workListEntries?.length >= 0) {
19
+ return (
20
+ <>
21
+ <div>
22
+ <GroupedOrdersTable
23
+ orders={workListEntries}
24
+ showActions={true}
25
+ showStatus={true}
26
+ showOrderType={true}
27
+ showStartButton={false}
28
+ title={t('referredProcedures', 'Referred Procedures')}
29
+ actions={[{ actionName: 'postProcedureResultForm' }, { actionName: 'reject-procedure-order-dialog' }]}
30
+ />
31
+ </div>
32
+ </>
33
+ );
34
+ }
35
+ };
36
+
37
+ export default WorkList;
@@ -0,0 +1,141 @@
1
+ import React from 'react';
2
+ import styles from './result-form.scss';
3
+ import { TextInput, Select, SelectItem } from '@carbon/react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { type ConceptReference } from './result-form.resource';
6
+ import { Controller } from 'react-hook-form';
7
+ import { min } from 'rxjs/operators';
8
+
9
+ interface ResultFormFieldProps {
10
+ concept: ConceptReference;
11
+ control: any;
12
+ register: any;
13
+ errors: any;
14
+ }
15
+ const ResultFormField: React.FC<ResultFormFieldProps> = ({ concept, control, errors }) => {
16
+ const { t } = useTranslation();
17
+ const isTextOrNumeric = (concept) => concept.datatype?.display === 'Text' || concept.datatype?.display === 'Numeric';
18
+ const isCoded = (concept) => concept.datatype?.display === 'Coded';
19
+ const isPanel = (concept) => concept.setMembers?.length > 0;
20
+
21
+ const printValueRange = (concept: ConceptReference) => {
22
+ if (concept?.datatype?.display === 'Numeric') {
23
+ const maxVal = Math.max(concept?.hiAbsolute, concept?.hiCritical, concept?.hiNormal);
24
+ const minVal = Math.min(concept?.lowAbsolute, concept?.lowCritical, concept?.lowNormal);
25
+ return ` (${minVal ?? 0} - ${maxVal > 0 ? maxVal : '--'} ${concept?.units ?? ''})`;
26
+ }
27
+ return '';
28
+ };
29
+
30
+ return (
31
+ <>
32
+ {Object.keys(errors).length > 0 && <div className={styles.errorDiv}>All fields are required</div>}
33
+ {isTextOrNumeric(concept) && (
34
+ <Controller
35
+ control={control}
36
+ rules={{
37
+ required: true,
38
+ }}
39
+ name={concept.uuid}
40
+ render={({ field }) => (
41
+ <TextInput
42
+ key={concept.uuid}
43
+ className={styles.textInput}
44
+ {...field}
45
+ type={concept.datatype.display === 'Numeric' ? 'number' : 'text'}
46
+ labelText={
47
+ concept?.display + (concept.datatype.display === 'Numeric' ? (printValueRange(concept) ?? '') : '')
48
+ }
49
+ autoFocus
50
+ />
51
+ )}
52
+ />
53
+ )}
54
+
55
+ {isCoded(concept) && (
56
+ <Controller
57
+ name={concept.uuid}
58
+ control={control}
59
+ rules={{
60
+ required: true,
61
+ }}
62
+ render={({ field }) => (
63
+ <Select
64
+ key={concept.uuid}
65
+ className={styles.textInput}
66
+ {...field}
67
+ type="text"
68
+ labelText={concept?.display}
69
+ rules={{ required: true }}>
70
+ <SelectItem text={t('option', 'Choose an Option')} value="" />
71
+
72
+ {concept?.answers?.map((answer) => (
73
+ <SelectItem key={answer.uuid} text={answer.display} value={answer.uuid}>
74
+ {answer.display}
75
+ </SelectItem>
76
+ ))}
77
+ </Select>
78
+ )}
79
+ />
80
+ )}
81
+
82
+ {isPanel(concept) &&
83
+ concept.setMembers.map((member, index) => {
84
+ if (isTextOrNumeric(member)) {
85
+ return (
86
+ <Controller
87
+ control={control}
88
+ name={member.uuid}
89
+ rules={{
90
+ required: true,
91
+ }}
92
+ render={({ field }) => (
93
+ <TextInput
94
+ key={member.uuid}
95
+ className={styles.textInput}
96
+ {...field}
97
+ type={member.datatype.display === 'Numeric' ? 'number' : 'text'}
98
+ labelText={
99
+ member?.display + (member.datatype.display === 'Numeric' ? (printValueRange(member) ?? '') : '')
100
+ }
101
+ autoFocus={index === 0}
102
+ />
103
+ )}
104
+ />
105
+ );
106
+ }
107
+
108
+ if (isCoded(member)) {
109
+ return (
110
+ <Controller
111
+ name={member.uuid}
112
+ control={control}
113
+ rules={{
114
+ required: true,
115
+ }}
116
+ render={({ field }) => (
117
+ <Select
118
+ key={member.uuid}
119
+ className={styles.textInput}
120
+ {...field}
121
+ type="text"
122
+ labelText={member?.display}
123
+ autoFocus={index === 0}>
124
+ <SelectItem text={t('option', 'Choose an Option')} value="" />
125
+
126
+ {member?.answers?.map((answer) => (
127
+ <SelectItem key={answer.uuid} text={answer.display} value={answer.uuid}>
128
+ {answer.display}
129
+ </SelectItem>
130
+ ))}
131
+ </Select>
132
+ )}
133
+ />
134
+ );
135
+ }
136
+ })}
137
+ </>
138
+ );
139
+ };
140
+
141
+ export default ResultFormField;