@ampath/esm-reports-app 1.0.0-next.7 → 1.0.0-next.70

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 (258) hide show
  1. package/dist/197.js +1 -1
  2. package/dist/282.js +1 -1
  3. package/dist/282.js.map +1 -1
  4. package/dist/295.css +1 -0
  5. package/dist/295.css.map +1 -0
  6. package/dist/295.js +1 -0
  7. package/dist/295.js.map +1 -0
  8. package/dist/299.js +2 -0
  9. package/dist/299.js.LICENSE.txt +3 -0
  10. package/dist/299.js.map +1 -0
  11. package/dist/300.js +1 -1
  12. package/dist/311.js +1 -1
  13. package/dist/311.js.map +1 -1
  14. package/dist/335.js +1 -1
  15. package/dist/353.js +1 -1
  16. package/dist/353.js.map +1 -1
  17. package/dist/354.js +2 -0
  18. package/dist/354.js.LICENSE.txt +20 -0
  19. package/dist/354.js.map +1 -0
  20. package/dist/410.js +1 -0
  21. package/dist/410.js.map +1 -0
  22. package/dist/457.js +2 -0
  23. package/dist/457.js.LICENSE.txt +261 -0
  24. package/dist/457.js.map +1 -0
  25. package/dist/478.js +1 -1
  26. package/dist/478.js.map +1 -1
  27. package/dist/480.js +1 -0
  28. package/dist/540.js +1 -1
  29. package/dist/540.js.map +1 -1
  30. package/dist/55.js +1 -1
  31. package/dist/580.js +1 -0
  32. package/dist/580.js.map +1 -0
  33. package/dist/600.js +2 -0
  34. package/dist/600.js.LICENSE.txt +35 -0
  35. package/dist/600.js.map +1 -0
  36. package/dist/652.js +1 -1
  37. package/dist/781.js +1 -0
  38. package/dist/781.js.map +1 -0
  39. package/dist/919.css +1 -0
  40. package/dist/919.css.map +1 -0
  41. package/dist/919.js +1 -0
  42. package/dist/919.js.map +1 -0
  43. package/dist/961.js +1 -1
  44. package/dist/961.js.map +1 -1
  45. package/dist/99.js +1 -1
  46. package/dist/99.js.map +1 -0
  47. package/dist/ampath-esm-reports-app.js +1 -1
  48. package/dist/ampath-esm-reports-app.js.map +1 -1
  49. package/dist/routes.json +1 -1
  50. package/package.json +4 -2
  51. package/src/common/daily-summary-table.tsx +55 -0
  52. package/src/common/linelist-table/index.ts +3 -0
  53. package/src/common/linelist-table/linelist-columns.ts +48 -0
  54. package/src/common/linelist-table/linelist-table.component.tsx +442 -0
  55. package/src/common/linelist-table/linelist-table.scss +306 -0
  56. package/src/common/linelist-table/linelist-table.test.tsx +120 -0
  57. package/src/common/linelist-table/use-all-rows.ts +93 -0
  58. package/src/common/linelist-table/use-column-layout.ts +123 -0
  59. package/src/common/report-error/index.ts +1 -0
  60. package/src/common/report-error/show-report-error.ts +25 -0
  61. package/src/common/report-filters/date-range.ts +137 -0
  62. package/src/common/report-filters/index.ts +4 -0
  63. package/src/common/report-filters/report-filters.component.tsx +317 -99
  64. package/src/common/report-filters/report-filters.scss +255 -32
  65. package/src/common/report-filters/types.ts +79 -0
  66. package/src/common/report-filters/use-restore-period.ts +43 -0
  67. package/src/common/report-header/index.ts +1 -0
  68. package/src/common/report-header/use-location-details.ts +58 -0
  69. package/src/common/report-page/download-sheet-pdf.ts +59 -0
  70. package/src/common/report-page/index.ts +3 -0
  71. package/src/common/report-page/report-page.component.tsx +32 -0
  72. package/src/common/report-page/report-page.scss +45 -0
  73. package/src/common/report-page/use-page-scale.ts +60 -0
  74. package/src/common/report-placeholder/has-report-data.ts +15 -0
  75. package/src/common/report-placeholder/index.ts +3 -0
  76. package/src/common/report-placeholder/report-placeholder.component.tsx +81 -0
  77. package/src/common/report-placeholder/report-placeholder.scss +48 -0
  78. package/src/common/report-placeholder/use-generated-location.ts +62 -0
  79. package/src/common/report-register/index.ts +6 -0
  80. package/src/common/report-register/register-columns.ts +46 -0
  81. package/src/common/report-register/register-layout.component.tsx +265 -0
  82. package/src/common/report-register/register-layout.scss +150 -0
  83. package/src/common/report-register/register-table.scss +71 -0
  84. package/src/common/report-register/report-parents.ts +27 -0
  85. package/src/common/report-register/rows-to-csv.ts +89 -0
  86. package/src/common/report-register/use-location-name.ts +54 -0
  87. package/src/common/report-register/use-patient-list.ts +92 -0
  88. package/src/common/report-skeleton/index.ts +1 -0
  89. package/src/common/report-skeleton/report-skeleton.component.tsx +46 -0
  90. package/src/common/report-skeleton/report-skeleton.scss +29 -0
  91. package/src/config-schema.ts +9 -1
  92. package/src/dashboard/report-catalog.ts +173 -0
  93. package/src/dashboard/reports-dasboard.tsx +189 -18
  94. package/src/dashboard/reports-dashboard.module.scss +357 -14
  95. package/src/index.ts +13 -1
  96. package/src/registers/moh-240/moh-240-register.scss +41 -0
  97. package/src/registers/moh-240/moh-240.component.test.tsx +166 -0
  98. package/src/registers/moh-240/moh-240.component.tsx +164 -0
  99. package/src/registers/moh-362/moh-362-lab-register.component.tsx +392 -0
  100. package/src/registers/moh-362/moh-362-linkage-register.component.tsx +120 -0
  101. package/src/registers/moh-362/moh-362-register.scss +222 -0
  102. package/src/registers/moh-362/moh-362.component.tsx +99 -0
  103. package/src/registers/moh-362/moh-362.scss +11 -0
  104. package/src/registers/moh-362/moh-362.types.ts +97 -0
  105. package/src/registers/register-catalog.ts +80 -0
  106. package/src/registers/tb-lab-register/tb-lab-register-table.component.tsx +116 -0
  107. package/src/registers/tb-lab-register/tb-lab-register-table.scss +123 -0
  108. package/src/registers/tb-lab-register/tb-lab-register.columns.ts +164 -0
  109. package/src/registers/tb-lab-register/tb-lab-register.component.test.tsx +232 -0
  110. package/src/registers/tb-lab-register/tb-lab-register.component.tsx +153 -0
  111. package/src/reports/datatable-wrapper/datatable-wrapper.component.tsx +63 -48
  112. package/src/reports/moh-240/moh-240-header.component.tsx +62 -0
  113. package/src/reports/moh-240/moh-240.columns.ts +113 -0
  114. package/src/reports/moh-240/moh-240.component.tsx +72 -9
  115. package/src/reports/moh-240/moh-240.scss +40 -0
  116. package/src/reports/moh-240/sub-reports/moh-240-register.component.tsx +31 -37
  117. package/src/reports/moh-240/sub-reports/page-summary.component.tsx +143 -106
  118. package/src/reports/moh-505/moh-505-header.component.tsx +67 -0
  119. package/src/reports/moh-505/moh-505.component.tsx +441 -0
  120. package/src/reports/moh-505/moh-505.scss +117 -0
  121. package/src/reports/moh-705B/moh-204b-register.component.tsx +244 -0
  122. package/src/reports/moh-705B/moh-204b.columns.ts +39 -0
  123. package/src/reports/moh-705B/moh-705b.component.tsx +659 -0
  124. package/src/reports/moh-705B/moh-705b.scss +172 -0
  125. package/src/reports/moh-705a/moh-705a.component.tsx +661 -0
  126. package/src/reports/moh-705a/moh-705a.scss +172 -0
  127. package/src/reports/moh-705a/registers/moh-204a-register.component.tsx +329 -0
  128. package/src/reports/moh-705a/registers/moh-204a.columns.ts +57 -0
  129. package/src/reports/moh-705a/type.ts +6 -0
  130. package/src/reports/moh-706/moh-706-header.component.tsx +66 -0
  131. package/src/reports/moh-706/moh-706.component.tsx +150 -24
  132. package/src/reports/moh-706/moh-706.scss +119 -11
  133. package/src/reports/moh-706/sub-reports/bacteriology/bacteriology.component.tsx +54 -62
  134. package/src/reports/moh-706/sub-reports/blood-chemistry/blood-chemistry.component.tsx +228 -317
  135. package/src/reports/moh-706/sub-reports/drug-susceptibility-testing/drug-susceptibility-testing.component.tsx +31 -46
  136. package/src/reports/moh-706/sub-reports/haematology/haematology.component.tsx +47 -55
  137. package/src/reports/moh-706/sub-reports/histology-and-cytology/histology-and-cytology.component.tsx +43 -58
  138. package/src/reports/moh-706/sub-reports/parasitology/parasitology.component.tsx +31 -39
  139. package/src/reports/moh-706/sub-reports/serology/serology.component.tsx +26 -34
  140. package/src/reports/moh-706/sub-reports/specimen-referral-to-higher-levels/specimen-referral-to-higher-levels.component.tsx +9 -24
  141. package/src/reports/moh-706/sub-reports/urine-analysis/urine-analysis.component.tsx +43 -51
  142. package/src/reports/moh-710/moh-710.component.tsx +799 -632
  143. package/src/reports/moh-710/moh-710.scss +142 -21
  144. package/src/reports/moh-710/registers/moh-510/moh-510.columns.ts +40 -0
  145. package/src/reports/moh-710/registers/moh-510/moh-510.component.tsx +144 -0
  146. package/src/reports/moh-710/registers/moh-510/moh-510.scss +130 -0
  147. package/src/reports/moh-710/registers/moh-511-710-register.component.tsx +268 -0
  148. package/src/reports/moh-710/registers/moh-511-710.columns.ts +52 -0
  149. package/src/reports/moh-710/registers/type.ts +31 -0
  150. package/src/reports/moh-711/moh-711.component.tsx +138 -1269
  151. package/src/reports/moh-711/moh711.scss +135 -20
  152. package/src/reports/moh-711/registers/moh-333-register.component.tsx +637 -0
  153. package/src/reports/moh-711/registers/moh-333.columns.ts +119 -0
  154. package/src/reports/moh-711/registers/moh-405-register.component.tsx +520 -0
  155. package/src/reports/moh-711/registers/moh-405.columns.ts +120 -0
  156. package/src/reports/moh-711/registers/moh-406-register.component.tsx +530 -0
  157. package/src/reports/moh-711/registers/moh-406.columns.ts +133 -0
  158. package/src/reports/moh-711/registers/moh-510-register.component.tsx +55 -0
  159. package/src/reports/moh-711/registers/moh-511-register.component.tsx +270 -0
  160. package/src/reports/moh-711/registers/moh-511.columns.ts +59 -0
  161. package/src/reports/moh-711/registers/type.ts +192 -0
  162. package/src/reports/moh-711/sections/anc.component.tsx +159 -0
  163. package/src/reports/moh-711/sections/cervical-cancer.component.tsx +148 -0
  164. package/src/reports/moh-711/sections/chanis.component.tsx +366 -0
  165. package/src/reports/moh-711/sections/family-planning.component.tsx +221 -0
  166. package/src/reports/moh-711/sections/gbv.component.tsx +115 -0
  167. package/src/reports/moh-711/sections/maternity.component.tsx +321 -0
  168. package/src/reports/moh-711/sections/medical-social-work.component.tsx +73 -0
  169. package/src/reports/moh-711/sections/other.component.tsx +47 -0
  170. package/src/reports/moh-711/sections/physiotherapy.component.tsx +61 -0
  171. package/src/reports/moh-711/sections/pnc.component.tsx +127 -0
  172. package/src/reports/moh-711/sections/post-abortion.component.tsx +42 -0
  173. package/src/reports/moh-711/sections/rehabilitation.component.tsx +57 -0
  174. package/src/reports/moh-711/sections/report-compiled-by.component.tsx +50 -0
  175. package/src/reports/moh-711/sections/tb-screening.component.tsx +57 -0
  176. package/src/reports/moh-717/moh-717.component.tsx +149 -985
  177. package/src/reports/moh-717/moh717.scss +217 -21
  178. package/src/reports/moh-717/registers/nutrition-register.component.tsx +48 -0
  179. package/src/reports/moh-717/sections/finance.component.tsx +42 -0
  180. package/src/reports/moh-717/sections/inpatient.component.tsx +374 -0
  181. package/src/reports/moh-717/sections/maternity.component.tsx +126 -0
  182. package/src/reports/moh-717/sections/medical-records.component.tsx +35 -0
  183. package/src/reports/moh-717/sections/mortuary.component.tsx +43 -0
  184. package/src/reports/moh-717/sections/operations.component.tsx +53 -0
  185. package/src/reports/moh-717/sections/orthopaedic-trauma.component.tsx +98 -0
  186. package/src/reports/moh-717/sections/outpatient.component.tsx +597 -0
  187. package/src/reports/moh-717/sections/pharmacy.component.tsx +43 -0
  188. package/src/reports/moh-717/sections/preparedby.component.tsx +52 -0
  189. package/src/reports/moh-717/sections/special-services.component.tsx +114 -0
  190. package/src/reports/moh-731/linelist/moh-731-indicators.ts +1122 -0
  191. package/src/reports/moh-731/linelist/moh-731-linelist-sections.ts +472 -0
  192. package/src/reports/moh-731/linelist/moh-731-linelist.component.tsx +102 -0
  193. package/src/reports/moh-731/linelist/use-open-moh-731-linelist.ts +50 -0
  194. package/src/reports/moh-731/moh-731.component.tsx +266 -0
  195. package/src/reports/moh-731/moh-731.scss +499 -0
  196. package/src/reports/moh-731/registers/moh-366.columns.ts +38 -0
  197. package/src/reports/moh-731/registers/moh-366.component.tsx +471 -0
  198. package/src/reports/moh-731/registers/prep-register.component.tsx +284 -0
  199. package/src/reports/moh-731/registers/prep.columns.ts +34 -0
  200. package/src/reports/moh-731/sections/hiv-and-tb-treatment.component.tsx +1206 -0
  201. package/src/reports/moh-731/sections/hiv-testing-and-pre-exposure.component.tsx +727 -0
  202. package/src/reports/moh-731/sections/pmtct.component.tsx +572 -0
  203. package/src/reports/moh-731/summary/moh-731-summary.component.tsx +313 -0
  204. package/src/reports/moh-731/summary/moh-731-summary.config.ts +529 -0
  205. package/src/reports/moh-731/summary/moh-731-summary.scss +242 -0
  206. package/src/reports/moh-740/moh-740.component.scss +202 -0
  207. package/src/reports/moh-740/moh-740.component.tsx +1332 -0
  208. package/src/reports/moh-740/moh-740.resource.ts +54 -0
  209. package/src/reports/moh-740/registers/moh-222-daily-register/moh-222-daily-register.tsx +149 -0
  210. package/src/reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register.tsx +123 -0
  211. package/src/reports/moh-740/registers/moh-740-patient-list.scss +0 -0
  212. package/src/reports/moh-740/registers/moh-740-patient-list.tsx +60 -0
  213. package/src/reports/moh-740/registers/moh-740.columns.ts +54 -0
  214. package/src/reports/moh-740/shared/data-cell/data-cell.scss +6 -0
  215. package/src/reports/moh-740/shared/data-cell/data-cell.tsx +23 -0
  216. package/src/reports/moh-740/shared/utils/indicator-register-map.ts +159 -0
  217. package/src/reports/moh-740/types/index.ts +223 -0
  218. package/src/reports/moh-745/moh-745.component.tsx +1021 -0
  219. package/src/reports/moh-745/moh-745.scss +132 -0
  220. package/src/reports/moh-745/registers/moh-412-register.component.tsx +199 -0
  221. package/src/reports/moh-745/registers/moh-412.columns.ts +52 -0
  222. package/src/reports/moh-745/registers/type.ts +181 -0
  223. package/src/reports/table-wrapper/table-row-mapper.component.tsx +57 -0
  224. package/src/reports/table-wrapper/table-wrapper.component.tsx +23 -14
  225. package/src/reports/table-wrapper/table-wrapper.scss +1 -16
  226. package/src/resources/moh-362.resource.ts +27 -0
  227. package/src/resources/moh-505.resource.ts +69 -0
  228. package/src/resources/moh-705.resource.ts +106 -0
  229. package/src/resources/moh-706.resource.ts +80 -0
  230. package/src/resources/moh-710.resource.ts +32 -9
  231. package/src/resources/moh-711.resource.ts +137 -9
  232. package/src/resources/moh-717.resource.ts +26 -9
  233. package/src/resources/moh-731.resource.ts +90 -0
  234. package/src/resources/moh-745.resource.ts +76 -0
  235. package/src/resources/patient-list-page.ts +65 -0
  236. package/src/root.component.tsx +59 -8
  237. package/src/root.scss +36 -0
  238. package/src/routes.json +3 -1
  239. package/src/utils/format-indicator.ts +39 -0
  240. package/src/utils/get-base-url.ts +39 -7
  241. package/src/utils/utils.ts +36 -0
  242. package/tsconfig.json +1 -1
  243. package/webpack.config.js +22 -1
  244. package/dist/138.js +0 -2
  245. package/dist/138.js.LICENSE.txt +0 -20
  246. package/dist/138.js.map +0 -1
  247. package/dist/184.js +0 -2
  248. package/dist/184.js.LICENSE.txt +0 -14
  249. package/dist/184.js.map +0 -1
  250. package/dist/205.js +0 -1
  251. package/dist/205.js.map +0 -1
  252. package/dist/711.js +0 -1
  253. package/dist/711.js.map +0 -1
  254. package/dist/812.js +0 -1
  255. package/dist/812.js.map +0 -1
  256. package/dist/ampath-esm-reports-app.js.buildmanifest.json +0 -539
  257. package/dist/main.js +0 -1
  258. package/dist/main.js.map +0 -1
@@ -0,0 +1,76 @@
1
+ import { openmrsFetch } from '@openmrs/esm-framework';
2
+ import { buildEtlUrl } from '../utils/get-base-url';
3
+ import {
4
+ PAGE_SIZE,
5
+ pageParams,
6
+ toPatientListPage,
7
+ type PatientListPage,
8
+ type PatientListParams,
9
+ } from './patient-list-page';
10
+ import {type Moh745reponse, type CancerScreeningResult } from '../reports/moh-745/registers/type';
11
+
12
+ interface Moh745Params {
13
+ locationUuids: string;
14
+ startDate?: string;
15
+ endDate?: string;
16
+ indicator?: string | string[];
17
+ }
18
+
19
+ export async function getMoh745(params: Moh745Params): Promise<CancerScreeningResult> {
20
+ const url = await buildEtlUrl('moh-745', {
21
+ locationUuids: params.locationUuids || '',
22
+ startDate: params.startDate || '',
23
+ endDate: params.endDate || '',
24
+ });
25
+ try {
26
+ const response = await openmrsFetch(url);
27
+
28
+ const data = await response.json() as Moh745reponse;
29
+ return data?.result[0] ?? null;
30
+ } catch (error: any) {
31
+ throw new Error(`An error occurred while fetching the MOH-710 report: ${error.message}`);
32
+ }
33
+ }
34
+
35
+ export async function getMoh412PatientList(params: PatientListParams): Promise<PatientListPage> {
36
+ const url = await buildEtlUrl('moh-412-patient-list', {
37
+ locationUuids: params.locationUuids || '',
38
+ startDate: params.startDate || '',
39
+ endDate: params.endDate || '',
40
+ indicator: Array.isArray(params.indicator) ? params.indicator.join(',') : params.indicator || '',
41
+ ...pageParams(params),
42
+ });
43
+ try {
44
+ const response = await openmrsFetch(url);
45
+
46
+ if (!response.ok) {
47
+ const errorText = await response.text();
48
+ throw new Error(`Failed to fetch patient list: ${response.status} - ${errorText}`);
49
+ }
50
+
51
+ const data = await response.json();
52
+
53
+ return toPatientListPage(data, params.startIndex ?? 0, params.limit ?? PAGE_SIZE);
54
+ } catch (error: any) {
55
+ console.error('Failed to fetch MOH 412 PATIENT LIST data', error);
56
+ throw new Error(`An error occurred while fetching the MOH-705 patient list: ${error.message}`);
57
+ }
58
+ }
59
+
60
+ export async function fetchMoh745PatientList(params: PatientListParams): Promise<any[]> {
61
+ const url = await buildEtlUrl('moh-412-patient-list', {
62
+ locationUuids: params.locationUuids || '',
63
+ startDate: params.startDate || '',
64
+ endDate: params.endDate || '',
65
+ indicators: Array.isArray(params.indicators) ? params.indicators.join(',') : params.indicators || '',
66
+ limit:1000
67
+ });
68
+ try {
69
+ const response = await openmrsFetch(url);
70
+ const data = await response.json();
71
+ return data?.result ?? [];
72
+ } catch (error: any) {
73
+ console.error('Failed to fetch MOH 412 PATIENT LIST data', error);
74
+ throw new Error(`An error occurred while fetching the MOH-705 patient list: ${error.message}`);
75
+ }
76
+ }
@@ -0,0 +1,65 @@
1
+ /** How many rows a register asks for at a time */
2
+ export const PAGE_SIZE = 50;
3
+
4
+ export interface PatientListParams {
5
+ locationUuids: string;
6
+ startDate?: string;
7
+ endDate?: string;
8
+ indicator?: string;
9
+ indicators?: string;
10
+ gender?: string;
11
+ /** MOH-711 endpoints scope the list by report */
12
+ reportName?: string;
13
+ /** Row to start at, 0-based, as the ETL expects */
14
+ startIndex?: number;
15
+ limit?: number;
16
+ }
17
+
18
+ export interface PatientListPage {
19
+ results: Array<Record<string, any>>;
20
+ /** Rows across every page */
21
+ total: number;
22
+ /** `false` when the total had to be inferred rather than read from the response */
23
+ isTotalExact: boolean;
24
+ }
25
+
26
+ /** The paging arguments every patient-list endpoint takes */
27
+ export function pageParams(params: PatientListParams) {
28
+ return {
29
+ startIndex: String(params.startIndex ?? 0),
30
+ limit: String(params.limit ?? PAGE_SIZE),
31
+ };
32
+ }
33
+
34
+ /**
35
+ * Normalises a patient-list response into a page of rows plus a total.
36
+ *
37
+ * The endpoints nest their payload differently and do not all report a count,
38
+ * so the total is read from whichever field carries it and inferred otherwise:
39
+ * a short page means we are on the last one, a full page means there is at
40
+ * least one more. Inferring keeps the pager usable without ever overstating
41
+ * what we know -- `isTotalExact` says which it is.
42
+ */
43
+ export function toPatientListPage(data: any, startIndex: number, limit: number): PatientListPage {
44
+ const container = data?.results ?? data ?? {};
45
+ const results: Array<Record<string, any>> = Array.isArray(container?.results)
46
+ ? container.results
47
+ : Array.isArray(container)
48
+ ? container
49
+ : [];
50
+ const reported = [container?.total, container?.totalCount, container?.count, data?.total, data?.totalCount].find(
51
+ (value) => typeof value === 'number',
52
+ );
53
+
54
+ if (typeof reported === 'number') {
55
+ return { results, total: reported, isTotalExact: true };
56
+ }
57
+
58
+ const isLastPage = results.length < limit;
59
+
60
+ return {
61
+ results,
62
+ total: isLastPage ? startIndex + results.length : startIndex + results.length + 1,
63
+ isTotalExact: isLastPage,
64
+ };
65
+ }
@@ -6,20 +6,71 @@ import Moh711Report from './reports/moh-711/moh-711.component';
6
6
  import Moh717Report from './reports/moh-717/moh-717.component';
7
7
  import MoH706Report from './reports/moh-706/moh-706.component';
8
8
  import Moh240Report from './reports/moh-240/moh-240.component';
9
+ import Moh505Report from './reports/moh-505/moh-505.component';
10
+ import Moh705BComponent from './reports/moh-705B/moh-705b.component';
11
+ import Moh705AComponent from './reports/moh-705a/moh-705a.component';
12
+ import Moh745Component from './reports/moh-745/moh-745.component';
13
+ import Moh740Report from './reports/moh-740/moh-740.component';
14
+ import Moh204ARegisterComponent from './reports/moh-705a/registers/moh-204a-register.component';
15
+ import Moh204BRegisterComponent from './reports/moh-705B/moh-204b-register.component';
16
+ import Moh412Register from './reports/moh-745/registers/moh-412-register.component';
17
+ import Moh405Register from './reports/moh-711/registers/moh-405-register.component';
18
+ import Moh406Register from './reports/moh-711/registers/moh-406-register.component';
19
+ import Moh333Register from './reports/moh-711/registers/moh-333-register.component';
20
+ import Moh511Register from './reports/moh-711/registers/moh-511-register.component';
21
+ import Moh510Register from './reports/moh-711/registers/moh-510-register.component';
22
+ import Moh511710Register from './reports/moh-710/registers/moh-511-710-register.component';
23
+ import Moh731Report from './reports/moh-731/moh-731.component';
24
+ import Moh366Register from './reports/moh-731/registers/moh-366.component';
25
+ import PrepRegisterComponent from './reports/moh-731/registers/prep-register.component';
26
+ import Moh731Linelist from './reports/moh-731/linelist/moh-731-linelist.component';
27
+ import Moh362Register from './registers/moh-362/moh-362.component';
28
+ import Moh240LabRegister from './registers/moh-240/moh-240.component';
29
+ import TbLabRegister from './registers/tb-lab-register/tb-lab-register.component';
30
+ import styles from './root.scss';
31
+ import Moh510RegisterComponent from './reports/moh-710/registers/moh-510/moh-510.component';
32
+ import Moh222DailyRegister from './reports/moh-740/registers/moh-222-daily-register/moh-222-daily-register';
33
+ import Moh270DailyRegister from './reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register';
9
34
 
10
35
  const RootComponent: React.FC = () => {
11
36
  const baseName = window.getOpenmrsSpaBase() + 'home/reports';
12
37
 
13
38
  return (
14
39
  <BrowserRouter basename={baseName}>
15
- <Routes>
16
- <Route path="/" element={<ReportsDashboard />} />
17
- <Route path="/moh-710" element={<Moh710Report />} />
18
- <Route path="/moh-711" element={<Moh711Report />} />
19
- <Route path="/moh-717" element={<Moh717Report />} />
20
- <Route path="/moh-706" element={<MoH706Report />} />
21
- <Route path="/moh-240" element={<Moh240Report />} />
22
- </Routes>
40
+ <div className={styles.page}>
41
+ <Routes>
42
+ <Route path="/" element={<ReportsDashboard />} />
43
+ <Route path="/moh-710" element={<Moh710Report />} />
44
+ <Route path="/moh-711" element={<Moh711Report />} />
45
+ <Route path="/moh-717" element={<Moh717Report />} />
46
+ <Route path="/moh-706" element={<MoH706Report />} />
47
+ <Route path="/moh-240" element={<Moh240Report />} />
48
+ <Route path="/moh-505" element={<Moh505Report />} />
49
+ <Route path="/moh-705a" element={<Moh705AComponent />} />
50
+ <Route path="/moh-705b" element={<Moh705BComponent />} />
51
+ <Route path="/moh-745" element={<Moh745Component />} />
52
+ <Route path="/moh-740" element={<Moh740Report />} />
53
+ <Route path="/moh-412-register" element={<Moh412Register />} />
54
+ <Route path="/moh-204b" element={<Moh204BRegisterComponent />} />
55
+ <Route path="/moh-204a" element={<Moh204ARegisterComponent />} />
56
+ <Route path="/moh-405-register" element={<Moh405Register />} />
57
+ <Route path="/moh-406-register" element={<Moh406Register />} />
58
+ <Route path="/moh-333-register" element={<Moh333Register />} />
59
+ <Route path="/moh-511-register" element={<Moh511Register />} />
60
+ <Route path="/moh-510-register" element={<Moh510Register />} />
61
+ <Route path="/moh-511-710-register" element={<Moh511710Register />} />
62
+ <Route path="/moh-731" element={<Moh731Report />} />
63
+ <Route path="/moh-731-linelist" element={<Moh731Linelist />} />
64
+ <Route path="/moh-366-register" element={<Moh366Register />} />
65
+ <Route path="/prep-register" element={<PrepRegisterComponent />} />
66
+ <Route path="/moh-510-register" element={<Moh510RegisterComponent />} />
67
+ <Route path="/moh-362" element={<Moh362Register />} />
68
+ <Route path="/moh-222" element={<Moh222DailyRegister />} />
69
+ <Route path="/moh-270" element={<Moh270DailyRegister />} />
70
+ <Route path="/moh-240-register" element={<Moh240LabRegister />} />
71
+ <Route path="/tb-lab-register" element={<TbLabRegister />} />
72
+ </Routes>
73
+ </div>
23
74
  </BrowserRouter>
24
75
  );
25
76
  };
package/src/root.scss CHANGED
@@ -1,10 +1,25 @@
1
1
  @use '@carbon/layout';
2
2
  @use '@carbon/type';
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
4
+
5
+ /* Single gutter for every route, so the dashboard and the individual reports
6
+ all clear the left nav by the same amount. */
7
+ .page {
8
+ box-sizing: border-box;
9
+ min-height: 100%;
10
+ padding: 0 layout.$spacing-06;
11
+ }
3
12
 
4
13
  .container {
5
14
  padding: layout.$spacing-07;
6
15
  }
7
16
 
17
+ @media (max-width: $breakpoint-tablet-max) {
18
+ .page {
19
+ padding: 0 layout.$spacing-05;
20
+ }
21
+ }
22
+
8
23
  .welcome {
9
24
  @include type.type-style('heading-04');
10
25
  margin: layout.$spacing-05 0;
@@ -13,3 +28,24 @@
13
28
  .explainer {
14
29
  margin-bottom: layout.$spacing-07;
15
30
  }
31
+
32
+ /* Printing a report should put the report on the paper, not the application
33
+ around it. Every route renders inside `.page`, so the chrome is hidden once
34
+ here; the filter bar hides itself (see report-filters.scss), and a report
35
+ with its own sheet geometry (MOH-731) refines this further. */
36
+
37
+ @media print {
38
+
39
+ .page,
40
+ .page * {
41
+ visibility: visible;
42
+ }
43
+
44
+ .page {
45
+ position: absolute;
46
+ top: 0;
47
+ left: 0;
48
+ width: 100%;
49
+ padding: 0;
50
+ }
51
+ }
package/src/routes.json CHANGED
@@ -9,6 +9,7 @@
9
9
  "name": "ampath-reports-dashboard-link",
10
10
  "component": "reportsDashboardLink",
11
11
  "slot": "homepage-dashboard-slot",
12
+ "privileges": ["O3 View Reports Dashboard"],
12
13
  "meta": {
13
14
  "name": "reports",
14
15
  "slot": "ampath-reports-dashboard-slot",
@@ -20,7 +21,8 @@
20
21
  {
21
22
  "component": "root",
22
23
  "name": "ampath-reports-dashboard-root",
23
- "slot": "ampath-reports-dashboard-slot"
24
+ "slot": "ampath-reports-dashboard-slot",
25
+ "privileges": ["O3 View Reports Dashboard"]
24
26
  }
25
27
  ],
26
28
  "pages": []
@@ -0,0 +1,39 @@
1
+ const PREFIX_LABELS: Record<string, string> = {
2
+ total: 'total',
3
+ positive: 'positive',
4
+ min: 'lowest',
5
+ max: 'highest',
6
+ };
7
+
8
+ /** Reads like the form row it was drilled from: `positive_urine_ketones_with_members`
9
+ becomes "Urine Ketones (positive)" rather than the raw indicator key. */
10
+ export function formatIndicatorName(indicator: string): string {
11
+ if (!indicator) {
12
+ return '';
13
+ }
14
+
15
+ const parts = indicator.includes("__")
16
+ ? indicator.split("__").slice(1)
17
+ : [indicator];
18
+
19
+ return parts
20
+ .map(part => {
21
+ // the retrieval-layer suffixes carry no meaning for the reader
22
+ part = part.replace(/_with_members$/, "");
23
+ const prefix = part.split("_")[0];
24
+ const qualifier = PREFIX_LABELS[prefix];
25
+ if (qualifier) {
26
+ part = part.slice(prefix.length + 1);
27
+ }
28
+ const name = part
29
+ .split("_")
30
+ .map(word =>
31
+ word.length === 1
32
+ ? word.toUpperCase()
33
+ : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
34
+ )
35
+ .join(" ");
36
+ return qualifier ? `${name} (${qualifier})` : name;
37
+ })
38
+ .join(" ");
39
+ }
@@ -1,12 +1,44 @@
1
1
  import { getConfig } from '@openmrs/esm-framework';
2
- import { moduleName } from '../index';
2
+ import { configSectionName } from '../index';
3
3
 
4
- export async function getEtlBaseUrl() {
5
- const { etlBaseUrl } = await getConfig(moduleName);
6
- return etlBaseUrl ?? null;
4
+ /**
5
+ * The ETL host every report reads from, taken from this module's frontend
6
+ * configuration (`etlBaseUrl`).
7
+ *
8
+ * Throws when it is unset rather than returning an empty string: an empty base
9
+ * collapses every report URL onto the OpenMRS root, which surfaces as a bare
10
+ * 404 that reads like a missing endpoint instead of missing configuration.
11
+ */
12
+ export async function getEtlBaseUrl(): Promise<string> {
13
+ const { etlBaseUrl } = await getConfig(configSectionName);
14
+ const baseUrl = typeof etlBaseUrl === 'string' ? etlBaseUrl.trim() : '';
15
+
16
+ if (!baseUrl) {
17
+ throw new Error(
18
+ `The ETL base URL is not configured. Set "etlBaseUrl" for ${configSectionName} in the frontend configuration.`,
19
+ );
20
+ }
21
+
22
+ // trailing slash trimmed so callers can join with a leading slash safely
23
+ return baseUrl.replace(/\/+$/, '');
7
24
  }
8
25
 
9
- export async function getSubDomain() {
10
- const { subDomain } = await getConfig(moduleName);
11
- return subDomain ?? null;
26
+ export type EtlQueryParams = Record<string, string | number | undefined | null>;
27
+
28
+ /**
29
+ * Builds a report URL from the configured ETL base, a path and its query
30
+ * parameters. Blank parameters are dropped rather than sent as empty values.
31
+ */
32
+ export async function buildEtlUrl(path: string, params: EtlQueryParams = {}): Promise<string> {
33
+ const baseUrl = await getEtlBaseUrl();
34
+
35
+ const query = new URLSearchParams(
36
+ Object.entries(params)
37
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
38
+ .map(([key, value]) => [key, String(value)]),
39
+ ).toString();
40
+
41
+ const url = `${baseUrl}/${path.replace(/^\/+/, '')}`;
42
+
43
+ return query ? `${url}?${query}` : url;
12
44
  }
@@ -0,0 +1,36 @@
1
+ import { openmrsFetch } from '@openmrs/esm-framework';
2
+
3
+ export const getCell = (key = "", label = "", colSpan = 1, rowSpan = 1, strong = false) => ({
4
+ key,
5
+ label,
6
+ strong,
7
+ colSpan,
8
+ rowSpan
9
+ });
10
+
11
+ export async function getJson<T>(url: string, payload: Record<string, unknown> | null = null): Promise<T> {
12
+ let requestUrl = url;
13
+
14
+ if (payload && Object.keys(payload).length > 0) {
15
+ const queryString = new URLSearchParams(
16
+ Object.entries(payload).filter(([, value]) => value !== undefined && value !== null) as Array<[string, string]>,
17
+ ).toString();
18
+
19
+ if (queryString) {
20
+ requestUrl = `${url}?${queryString}`;
21
+ }
22
+ }
23
+
24
+ const response = await openmrsFetch(requestUrl);
25
+
26
+ if (!response.ok) {
27
+ const errorText = await response.text();
28
+ throw new Error(`Request failed with ${response.status}: ${errorText}`);
29
+ }
30
+
31
+ if (response.status === 204 || response.headers.get('content-length') === '0') {
32
+ return Promise.resolve({} as T);
33
+ }
34
+
35
+ return response.json() as Promise<T>;
36
+ }
package/tsconfig.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "allowSyntheticDefaultImports": true,
6
6
  "jsx": "react",
7
7
  "skipLibCheck": true,
8
- "moduleResolution": "node",
8
+ "moduleResolution": "bundler",
9
9
  "lib": [
10
10
  "dom",
11
11
  "es5",
package/webpack.config.js CHANGED
@@ -1 +1,22 @@
1
- module.exports = require('openmrs/default-webpack-config');
1
+ const path = require('path');
2
+ const config = (module.exports = require('openmrs/default-webpack-config'));
3
+ config.watchConfig.ignored = ['.git', 'test-results', `${path.resolve(__dirname, 'dist')}/**`];
4
+ config.overrides.resolve = {
5
+ fallback: {
6
+ crypto: false,
7
+ stream: false,
8
+ os: false,
9
+ path: false,
10
+ zlib: false,
11
+ https: false,
12
+ http: false,
13
+ util: false,
14
+ url: false,
15
+ },
16
+ extensions: ['.tsx', '.ts', '.jsx', '.js', '.scss'],
17
+ alias: {
18
+ '@openmrs/esm-framework': '@openmrs/esm-framework/src/internal',
19
+ },
20
+ };
21
+
22
+ module.exports = config;