@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,177 @@
1
+ import React, { type AnchorHTMLAttributes, useMemo } from 'react';
2
+ import { type GroupMember, type Value } from '../patient-procedure-order-results.resource';
3
+ import { useTranslation } from 'react-i18next';
4
+ import {
5
+ DataTable,
6
+ Table,
7
+ TableBody,
8
+ TableCell,
9
+ TableContainer,
10
+ TableHead,
11
+ TableHeader,
12
+ TableRow,
13
+ Tile,
14
+ InlineLoading,
15
+ } from '@carbon/react';
16
+ import styles from './results-summary.scss';
17
+ import { useGetConceptById } from './results-summary.resource';
18
+
19
+ interface TestsResultsChildrenProps {
20
+ members: GroupMember[];
21
+ }
22
+
23
+ interface ReferenceRangeProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
24
+ conceptUuid: string;
25
+ }
26
+
27
+ interface ColorRangeIndicatorProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
28
+ value: number | Value;
29
+ conceptUuid: string;
30
+ }
31
+
32
+ const TestResultsChildren: React.FC<TestsResultsChildrenProps> = ({ members }) => {
33
+ const { t } = useTranslation();
34
+
35
+ const columns = [
36
+ { id: 1, header: t('test', 'Test'), key: 'test' },
37
+
38
+ {
39
+ id: 2,
40
+ header: t('results', 'Results'),
41
+ key: 'value',
42
+ },
43
+ {
44
+ id: 3,
45
+ header: t('range', 'Reference Range'),
46
+ key: 'range',
47
+ },
48
+ ];
49
+
50
+ const results = useMemo(() => {
51
+ return members?.map((member) => ({
52
+ id: member.uuid,
53
+ test: {
54
+ content: <span>{member?.concept?.display}</span>,
55
+ },
56
+ value: {
57
+ content: <span>{typeof member?.value === 'number' ? member?.value : member?.display}</span>,
58
+ },
59
+ }));
60
+ }, [members]);
61
+
62
+ const ReferenceRange: React.FC<ReferenceRangeProps> = ({ conceptUuid }) => {
63
+ const { concept: concept, isLoading, isError } = useGetConceptById(conceptUuid);
64
+
65
+ if (isLoading) {
66
+ return <TableCell>{<InlineLoading status="active" />}</TableCell>;
67
+ }
68
+ if (isError) {
69
+ return <TableCell>{<span>Error</span>}</TableCell>;
70
+ }
71
+ return (
72
+ <TableCell>
73
+ {concept?.hiNormal === undefined || concept?.lowNormal === undefined ? (
74
+ 'N/A'
75
+ ) : (
76
+ <div>
77
+ <span>{concept?.lowNormal}</span> : <span>{concept?.hiNormal}</span>
78
+ <span style={{ marginLeft: '10px' }}>{concept?.units}</span>
79
+ </div>
80
+ )}
81
+ </TableCell>
82
+ );
83
+ };
84
+
85
+ const ColorRangeIndicator: React.FC<ColorRangeIndicatorProps> = ({ value, conceptUuid }) => {
86
+ const { concept: concept, isLoading, isError } = useGetConceptById(conceptUuid);
87
+ if (isLoading) {
88
+ return <TableCell>{<InlineLoading status="active" />}</TableCell>;
89
+ }
90
+
91
+ if (isError) {
92
+ return <TableCell>{<span>Error</span>}</TableCell>;
93
+ }
94
+
95
+ if (concept?.datatype?.display === 'coded') {
96
+ return <TableCell>{typeof value === 'object' ? value?.display : value}</TableCell>;
97
+ }
98
+
99
+ let range = '';
100
+ if (typeof value === 'number') {
101
+ if (concept?.hiCritical && value >= concept?.hiCritical) {
102
+ range = styles.criticallyHigh;
103
+ }
104
+
105
+ if (concept?.hiNormal && value > concept?.hiNormal) {
106
+ range = styles.high;
107
+ }
108
+
109
+ if (concept?.lowCritical && value <= concept?.lowCritical) {
110
+ range = styles.criticallyLow;
111
+ }
112
+
113
+ if (concept?.lowNormal && value < concept?.lowNormal) {
114
+ range = styles.low;
115
+ }
116
+ return <TableCell className={range}>{value}</TableCell>;
117
+ }
118
+ return <TableCell>{value.display}</TableCell>;
119
+ };
120
+
121
+ if (results?.length >= 0) {
122
+ return (
123
+ <div>
124
+ <DataTable rows={results} headers={columns} useZebraStyles>
125
+ {({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
126
+ <TableContainer className={styles.tableContainer}>
127
+ <Table {...getTableProps()} className={styles.activePatientsTable}>
128
+ <TableHead>
129
+ <TableRow>
130
+ {headers.map((header) => (
131
+ <TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
132
+ ))}
133
+ </TableRow>
134
+ </TableHead>
135
+ <TableBody>
136
+ {rows.map((row, index) => {
137
+ return (
138
+ <React.Fragment key={row.id}>
139
+ <TableRow {...getRowProps({ row })}>
140
+ {row.cells.map((cell) =>
141
+ cell.info.header === 'range' ? (
142
+ <ReferenceRange conceptUuid={members[index]?.concept?.uuid}>
143
+ {cell.value?.content}
144
+ </ReferenceRange>
145
+ ) : cell.info.header === 'value' ? (
146
+ <ColorRangeIndicator
147
+ conceptUuid={members[index]?.concept.uuid}
148
+ value={members[index]?.value}
149
+ />
150
+ ) : (
151
+ <TableCell key={cell.id}>{cell.value?.content ?? cell?.value}</TableCell>
152
+ ),
153
+ )}
154
+ </TableRow>
155
+ </React.Fragment>
156
+ );
157
+ })}
158
+ </TableBody>
159
+ </Table>
160
+ {rows.length === 0 ? (
161
+ <div className={styles.tileContainer}>
162
+ <Tile className={styles.tile}>
163
+ <div className={styles.tileContent}>
164
+ <p className={styles.content}>{t('noTestOrdersToDisplay', 'No test orders to display')}</p>
165
+ </div>
166
+ </Tile>
167
+ </div>
168
+ ) : null}
169
+ </TableContainer>
170
+ )}
171
+ </DataTable>
172
+ </div>
173
+ );
174
+ }
175
+ };
176
+
177
+ export default TestResultsChildren;
@@ -0,0 +1,105 @@
1
+ import React, { useMemo } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import {
4
+ DataTable,
5
+ Table,
6
+ TableBody,
7
+ TableCell,
8
+ TableContainer,
9
+ TableHead,
10
+ TableHeader,
11
+ TableRow,
12
+ Tile,
13
+ TableExpandHeader,
14
+ TableExpandRow,
15
+ TableExpandedRow,
16
+ } from '@carbon/react';
17
+ import styles from './results-summary.scss';
18
+ import TestResultsChildren from './test-children-results.component';
19
+ import { type Ob } from '../patient-procedure-order-results.resource';
20
+
21
+ interface TestOrdersProps {
22
+ obs: Ob[];
23
+ }
24
+
25
+ const TestsPrintResults: React.FC<TestOrdersProps> = ({ obs }) => {
26
+ const { t } = useTranslation();
27
+
28
+ const columns = [
29
+ { id: 1, header: t('order', 'Order'), key: 'order' },
30
+ { id: 2, header: t('results', 'Results'), key: 'result' },
31
+ ];
32
+
33
+ const filteredItems = obs.filter((ob) => ob?.order?.type === 'testorder' && ob?.groupMembers?.length > 0);
34
+
35
+ const tableRows = useMemo(() => {
36
+ return filteredItems?.map((entry) => ({
37
+ ...entry,
38
+ id: entry.uuid,
39
+ members: entry?.groupMembers,
40
+ order: {
41
+ content: <span>{entry.display}</span>,
42
+ },
43
+ result: {
44
+ content: <span>--</span>,
45
+ },
46
+ }));
47
+ }, [filteredItems]);
48
+
49
+ if (filteredItems?.length >= 0) {
50
+ return (
51
+ <div>
52
+ <DataTable rows={tableRows} headers={columns} useZebraStyles expanded={false}>
53
+ {({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
54
+ <TableContainer className={styles.tableContainer}>
55
+ <Table {...getTableProps()} className={styles.activePatientsTable}>
56
+ <TableHead>
57
+ <TableRow>
58
+ <TableExpandHeader />
59
+ {headers.map((header) => (
60
+ <TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
61
+ ))}
62
+ </TableRow>
63
+ </TableHead>
64
+ <TableBody>
65
+ {rows.map((row, index) => {
66
+ return (
67
+ <React.Fragment key={row.id}>
68
+ <TableExpandRow {...getRowProps({ row })}>
69
+ {row.cells.map((cell) => (
70
+ <TableCell key={cell.id}>{cell.value?.content ?? cell?.value}</TableCell>
71
+ ))}
72
+ </TableExpandRow>
73
+ {row.isExpanded ? (
74
+ <TableExpandedRow className={styles.expandedActiveVisitRow} colSpan={headers.length + 2}>
75
+ {filteredItems[index]?.groupMembers !== null &&
76
+ filteredItems[index]?.groupMembers?.length > 0 && (
77
+ <TestResultsChildren members={filteredItems[index]?.groupMembers} />
78
+ )}
79
+ </TableExpandedRow>
80
+ ) : (
81
+ <TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 2} />
82
+ )}
83
+ </React.Fragment>
84
+ );
85
+ })}
86
+ </TableBody>
87
+ </Table>
88
+ {rows.length === 0 ? (
89
+ <div className={styles.tileContainer}>
90
+ <Tile className={styles.tile}>
91
+ <div className={styles.tileContent}>
92
+ <p className={styles.content}>{t('noTestResultsToDisplay', 'No test results to display')}</p>
93
+ </div>
94
+ </Tile>
95
+ </div>
96
+ ) : null}
97
+ </TableContainer>
98
+ )}
99
+ </DataTable>
100
+ </div>
101
+ );
102
+ }
103
+ };
104
+
105
+ export default TestsPrintResults;
@@ -0,0 +1,103 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import {
4
+ DataTable,
5
+ Table,
6
+ TableBody,
7
+ TableCell,
8
+ TableContainer,
9
+ TableHead,
10
+ TableHeader,
11
+ TableRow,
12
+ Tile,
13
+ TableExpandHeader,
14
+ TableExpandRow,
15
+ TableExpandedRow,
16
+ } from '@carbon/react';
17
+ import styles from './results-summary.scss';
18
+ import TestResultsChildren from './test-children-results.component';
19
+ import { formatDate, parseDate } from '@openmrs/esm-framework';
20
+ import { type Ob } from '../patient-procedure-order-results.resource';
21
+
22
+ interface TestOrdersProps {
23
+ obs: Ob[];
24
+ }
25
+
26
+ const TestsResults: React.FC<TestOrdersProps> = ({ obs }) => {
27
+ const { t } = useTranslation();
28
+
29
+ const columns = [
30
+ { id: 0, header: t('order', 'Order'), key: 'order', align: 'center' },
31
+ { id: 1, header: t('date', 'Date'), key: 'date' },
32
+ { id: 2, header: t('result', 'Results'), key: 'result' },
33
+ ];
34
+
35
+ const formatDateColumn = (obsDatetime) => formatDate(parseDate(obsDatetime), { time: false });
36
+
37
+ const obsList = obs?.filter((ob) => ob?.order?.type === 'testorder');
38
+
39
+ const obsRows = useMemo(
40
+ () =>
41
+ obsList.map((ob, index) => ({
42
+ id: ob.uuid,
43
+ order: { content: <span>{ob?.concept?.display}</span> },
44
+ date: { content: <span>{formatDateColumn(ob?.obsDatetime)}</span> },
45
+ result: {
46
+ content: <span>{ob[index]?.groupMembers === null ? ob?.display : ob?.value?.display}</span>,
47
+ },
48
+ })),
49
+ [obsList],
50
+ );
51
+
52
+ return (
53
+ <div>
54
+ <DataTable rows={obsRows} headers={columns} useZebraStyles>
55
+ {({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
56
+ <TableContainer className={styles.tableContainer}>
57
+ <Table {...getTableProps()} className={styles.activePatientsTable}>
58
+ <TableHead>
59
+ <TableRow>
60
+ <TableExpandHeader />
61
+ {headers.map((header) => (
62
+ <TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
63
+ ))}
64
+ </TableRow>
65
+ </TableHead>
66
+ <TableBody>
67
+ {rows.map((row, index) => (
68
+ <React.Fragment key={row.id}>
69
+ <TableExpandRow {...getRowProps({ row })}>
70
+ {row.cells.map((cell) => (
71
+ <TableCell key={cell.id}>{cell.value?.content ?? cell.value}</TableCell>
72
+ ))}
73
+ </TableExpandRow>
74
+ {row.isExpanded ? (
75
+ <TableExpandedRow className={styles.expandedActiveVisitRow} colSpan={headers.length + 2}>
76
+ {obsList[index]?.groupMembers !== null && obsList[index]?.groupMembers?.length > 0 && (
77
+ <TestResultsChildren members={obsList[index]?.groupMembers} />
78
+ )}
79
+ </TableExpandedRow>
80
+ ) : (
81
+ <TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 2} />
82
+ )}
83
+ </React.Fragment>
84
+ ))}
85
+ </TableBody>
86
+ </Table>
87
+ {rows.length === 0 && (
88
+ <div className={styles.tileContainer}>
89
+ <Tile className={styles.tile}>
90
+ <div className={styles.tileContent}>
91
+ <p className={styles.content}>{t('noTestResultsToDisplay', 'No test results to display')}</p>
92
+ </div>
93
+ </Tile>
94
+ </div>
95
+ )}
96
+ </TableContainer>
97
+ )}
98
+ </DataTable>
99
+ </div>
100
+ );
101
+ };
102
+
103
+ export default TestsResults;
@@ -0,0 +1,49 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button, ButtonSet, ModalBody, ModalFooter, InlineNotification } from '@carbon/react';
4
+ import ReactToPrint, { useReactToPrint } from 'react-to-print';
5
+ import styles from './print-procedure.scss';
6
+ import { Order, type Result } from '../types';
7
+ import PrintableReport from './print-procedure.component';
8
+
9
+ type PrintPreviewModalProps = {
10
+ onClose: () => void;
11
+ completedOrder: Result;
12
+ };
13
+
14
+ const PrintPreviewModal: React.FC<PrintPreviewModalProps> = ({ onClose, completedOrder }) => {
15
+ const ordererName = completedOrder?.orderer;
16
+ const { t } = useTranslation();
17
+ const [printError, setPrintError] = useState<string | null>(null);
18
+ const [isLoading, setIsLoading] = useState<boolean>(false);
19
+ const ref = useRef<HTMLDivElement>(null);
20
+ const handlePrint = useReactToPrint({
21
+ content: () => ref.current,
22
+ });
23
+
24
+ return (
25
+ <>
26
+ <ModalBody>
27
+ <div ref={ref}>
28
+ <PrintableReport completedOrder={completedOrder} ordererName={ordererName?.toString()} />
29
+ </div>
30
+ </ModalBody>
31
+ <ModalFooter>
32
+ <ButtonSet className={styles.btnSet}>
33
+ <Button kind="secondary" onClick={onClose} type="button">
34
+ {t('cancel', 'Cancel')}
35
+ </Button>
36
+ <Button kind="primary" type="button" disabled={isLoading} onClick={handlePrint}>
37
+ {t('print', 'Print')}
38
+ </Button>
39
+ </ButtonSet>
40
+ </ModalFooter>
41
+
42
+ {printError && (
43
+ <InlineNotification kind="error" title={t('printError', 'Error')} subtitle={printError} hideCloseButton />
44
+ )}
45
+ </>
46
+ );
47
+ };
48
+
49
+ export default PrintPreviewModal;
@@ -0,0 +1,105 @@
1
+ import React from 'react';
2
+ import styles from './print-procedure.scss';
3
+ import { useConfig, useSession, formatDate } from '@openmrs/esm-framework';
4
+ import { useTranslation } from 'react-i18next';
5
+ import startCase from 'lodash-es/startCase';
6
+ import dayjs from 'dayjs';
7
+ import { Order, type Result } from '../types';
8
+
9
+ interface PrintableReportProps {
10
+ completedOrder: Result;
11
+ ordererName: string;
12
+ }
13
+
14
+ const PrintableReport: React.FC<PrintableReportProps> = ({ completedOrder, ordererName }) => {
15
+ const { t } = useTranslation();
16
+ const { sessionLocation, user } = useSession();
17
+ const location = sessionLocation?.display;
18
+
19
+ return (
20
+ <div className={styles.container}>
21
+ <div className={styles.mainContent}>
22
+ <div className={styles.printableHeader}>
23
+ <p className={styles.heading}>
24
+ {t('procedureReport', 'Procedure Report')} - {completedOrder?.orderNumber}
25
+ </p>
26
+ </div>
27
+ <div className={styles.printableBody}>
28
+ <div className={styles.billDetails}>
29
+ <p className={styles.itemHeading}>{t('reportSummaryTo', 'Report summary to')}</p>
30
+ <p className={styles.itemLabel}>
31
+ {t('name', 'Name')}: {startCase(completedOrder?.patient?.person?.display)}
32
+ </p>
33
+ <p className={styles.itemLabel}>
34
+ {t('identifier', 'Identifier')}: {completedOrder?.patient?.identifiers[0]?.identifier}
35
+ </p>
36
+ <p className={styles.itemLabel}>
37
+ {t('age', 'Age')}: {completedOrder?.patient?.person?.age}
38
+ </p>
39
+ <p className={styles.itemLabel}>
40
+ {t('gender', 'Gender')}:
41
+ {completedOrder?.patient?.person?.gender === 'M'
42
+ ? ' Male'
43
+ : completedOrder?.patient?.person?.gender === 'F'
44
+ ? ' Female'
45
+ : ' Unknown'}
46
+ </p>
47
+ <p className={styles.itemLabel}>
48
+ {t('orderDate', 'Order date')}:{' '}
49
+ {completedOrder?.dateActivated ? dayjs(completedOrder.dateActivated).format('YYYY-MM-DD hh:mm A') : '--'}
50
+ </p>
51
+ <p className={styles.itemLabel}>
52
+ {t('orderer', 'Orderer')}: {ordererName}
53
+ </p>
54
+ </div>
55
+
56
+ <div className={styles.facilityDetails}>
57
+ <p className={styles.facilityName}>{location}</p>
58
+ <p className={styles.facilityName}>{completedOrder?.careSetting?.name}</p>
59
+ <p className={styles.facilityName}>{t('kenya', 'Kenya')}</p>
60
+ </div>
61
+ </div>
62
+ <div className={styles.printResults}>
63
+ <p className={styles.itemHeading}>{t('procedure', 'Procedure')}</p>
64
+ <div className={styles.reportSection}>
65
+ <p className={styles.itemLabel}>{startCase(completedOrder?.concept?.display)}</p>
66
+ </div>
67
+ </div>
68
+ <div className={styles.printResults}>
69
+ <p className={styles.itemHeading}>{t('complications', 'Complications')}</p>
70
+ <div className={styles.reportSection}>
71
+ <p className={styles.itemLabel}>{completedOrder?.procedures[0]?.encounters[0]?.obs[0]?.display}</p>
72
+ </div>
73
+ </div>
74
+ <div className={styles.printResults}>
75
+ <p className={styles.itemHeading}>{t('findings', 'Findings')}</p>
76
+ <div className={styles.reportSection}>
77
+ <p className={styles.itemLabel}>{completedOrder?.procedures[0]?.procedureReport}</p>
78
+ </div>
79
+ </div>
80
+ <div className={styles.printResults}>
81
+ <p className={styles.itemHeading}>{t('impressions', 'Impressions')}</p>
82
+ <div className={styles.reportSection}>
83
+ <p className={styles.itemLabel}>{completedOrder?.procedures[0]?.procedureReason}</p>
84
+ </div>
85
+ </div>
86
+ </div>
87
+
88
+ <section className={styles.sectionFooter}>
89
+ <div
90
+ style={{
91
+ margin: '10px',
92
+ display: 'flex',
93
+ width: '500px',
94
+ flexDirection: 'row',
95
+ }}>
96
+ <span style={{ fontSize: '14px', marginBottom: '10px' }}>
97
+ Results Reviewed / Authorized by :<span style={{ marginLeft: '50px' }}>{user?.display}</span>
98
+ </span>
99
+ </div>
100
+ </section>
101
+ </div>
102
+ );
103
+ };
104
+
105
+ export default PrintableReport;
@@ -0,0 +1,98 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/type';
4
+
5
+ .container {
6
+ padding: 0 1rem 2rem;
7
+ margin-bottom: 2rem;
8
+ padding: layout.$spacing-08;
9
+ }
10
+
11
+ .printableBody {
12
+ display: flex;
13
+ flex-direction: row;
14
+ justify-content: space-between;
15
+ }
16
+
17
+ .printableHeader {
18
+ display: flex;
19
+ flex-direction: row;
20
+ }
21
+
22
+ .img {
23
+ display: flex;
24
+ margin-left: auto;
25
+ }
26
+
27
+ .billDetails {
28
+ display: flex;
29
+ width: 50%;
30
+ flex-direction: column;
31
+ }
32
+
33
+ .facilityDetails {
34
+ display: flex;
35
+ flex-flow: column wrap;
36
+ text-align: right;
37
+ }
38
+
39
+ .heading {
40
+ font-size: 20px;
41
+ text-transform: uppercase;
42
+ margin-bottom: layout.$spacing-05;
43
+ }
44
+
45
+ .facilityName {
46
+ @include type.type-style('heading-compact-02');
47
+ font-weight: bold;
48
+ color: colors.$green-70;
49
+ }
50
+
51
+ .itemHeading {
52
+ @include type.type-style('body-compact-02');
53
+ margin-bottom: 0.25rem;
54
+ font-weight: bold;
55
+ color: colors.$cool-gray-90;
56
+ }
57
+
58
+ .itemLabel {
59
+ @include type.type-style('body-compact-02');
60
+ color: colors.$cool-gray-90;
61
+ color: colors.$cool-gray-90;
62
+ }
63
+ .printResults {
64
+ margin-top: layout.$spacing-05;
65
+ }
66
+ .btnSet {
67
+ width: 100%;
68
+ }
69
+
70
+ .itemFooter {
71
+ padding: layout.$spacing-01 layout.$spacing-05;
72
+ @include type.type-style('body-compact-02');
73
+ color: colors.$cool-gray-90;
74
+ }
75
+
76
+ .footDescription {
77
+ @include type.type-style('legal-01');
78
+ padding: layout.$spacing-01 layout.$spacing-05;
79
+ color: colors.$cool-gray-70;
80
+ position: absolute;
81
+ }
82
+ .itemHeadingGroup {
83
+ @include type.type-style('body-compact-02');
84
+ margin-bottom: layout.$spacing-07;
85
+ font-weight: bold;
86
+ color: colors.$cool-gray-90;
87
+ }
88
+ .sectionFooter {
89
+ position: absolute;
90
+ bottom: 0;
91
+ width: 100%;
92
+ padding: layout.$spacing-05;
93
+ display: flex;
94
+ flex-direction: column;
95
+ justify-content: center;
96
+ align-items: flex-start;
97
+ z-index: 100;
98
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { CompletedList } from '../completed-list/completed-list.component';
3
+
4
+ const CompletedComponent = () => {
5
+ return (
6
+ <div>
7
+ <CompletedList fulfillerStatus={'COMPLETED'} />
8
+ </div>
9
+ );
10
+ };
11
+
12
+ export default CompletedComponent;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import NotDoneList from '../not-done-list/not-done-list.component';
3
+
4
+ const NotDoneComponent = () => {
5
+ return (
6
+ <div>
7
+ <NotDoneList fulfillerStatus={'DECLINED'} />
8
+ </div>
9
+ );
10
+ };
11
+
12
+ export default NotDoneComponent;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import ReferredProcedures from '../referred-procedures/referred-procedures.component';
3
+
4
+ const ReferredComponent = () => {
5
+ return (
6
+ <div>
7
+ <ReferredProcedures fulfillerStatus={'EXCEPTION'} />
8
+ </div>
9
+ );
10
+ };
11
+
12
+ export default ReferredComponent;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import WorkList from '../work-list/work-list.component';
3
+ import styles from '../queue-list/procedure-queue.scss';
4
+
5
+ const WorkListComponent = () => {
6
+ return (
7
+ <div>
8
+ <WorkList fulfillerStatus={'IN_PROGRESS'} />
9
+ </div>
10
+ );
11
+ };
12
+
13
+ export default WorkListComponent;