@ampath/esm-reports-app 1.0.0-next.41 → 1.0.0-next.42

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 (147) hide show
  1. package/dist/110.js +2 -1
  2. package/dist/110.js.LICENSE.txt +35 -0
  3. package/dist/110.js.map +1 -1
  4. package/dist/205.js +1 -1
  5. package/dist/441.js +1 -0
  6. package/dist/441.js.map +1 -0
  7. package/dist/738.js +1 -0
  8. package/dist/738.js.map +1 -0
  9. package/dist/812.js +1 -1
  10. package/dist/812.js.map +1 -1
  11. package/dist/ampath-esm-reports-app.js +1 -1
  12. package/dist/ampath-esm-reports-app.js.buildmanifest.json +66 -39
  13. package/dist/main.js +1 -1
  14. package/dist/main.js.map +1 -1
  15. package/dist/routes.json +1 -1
  16. package/package.json +1 -1
  17. package/src/common/report-error/index.ts +1 -0
  18. package/src/common/report-error/show-report-error.ts +25 -0
  19. package/src/common/report-filters/date-range.ts +137 -0
  20. package/src/common/report-filters/index.ts +4 -0
  21. package/src/common/report-filters/report-filters.component.tsx +281 -151
  22. package/src/common/report-filters/report-filters.scss +180 -55
  23. package/src/common/report-filters/types.ts +66 -0
  24. package/src/common/report-filters/use-restore-period.ts +43 -0
  25. package/src/common/report-page/index.ts +2 -0
  26. package/src/common/report-page/report-page.component.tsx +32 -0
  27. package/src/common/report-page/report-page.scss +45 -0
  28. package/src/common/report-page/use-page-scale.ts +50 -0
  29. package/src/common/report-placeholder/has-report-data.ts +15 -0
  30. package/src/common/report-placeholder/index.ts +2 -0
  31. package/src/common/report-placeholder/report-placeholder.component.tsx +56 -0
  32. package/src/common/report-placeholder/report-placeholder.scss +46 -0
  33. package/src/common/report-register/index.ts +5 -0
  34. package/src/common/report-register/register-columns.ts +34 -0
  35. package/src/common/report-register/register-layout.component.tsx +237 -0
  36. package/src/common/report-register/register-layout.scss +140 -0
  37. package/src/common/report-register/register-table.scss +62 -0
  38. package/src/common/report-register/report-parents.ts +27 -0
  39. package/src/common/report-register/rows-to-csv.ts +59 -0
  40. package/src/common/report-register/use-patient-list.ts +92 -0
  41. package/src/common/report-skeleton/index.ts +1 -0
  42. package/src/common/report-skeleton/report-skeleton.component.tsx +46 -0
  43. package/src/common/report-skeleton/report-skeleton.scss +29 -0
  44. package/src/config-schema.ts +9 -1
  45. package/src/dashboard/report-catalog.ts +173 -0
  46. package/src/dashboard/reports-dasboard.tsx +101 -35
  47. package/src/dashboard/reports-dashboard.module.scss +269 -11
  48. package/src/index.ts +13 -1
  49. package/src/reports/datatable-wrapper/datatable-wrapper.component.tsx +50 -48
  50. package/src/reports/moh-240/moh-240-header.component.tsx +54 -56
  51. package/src/reports/moh-240/moh-240.columns.ts +64 -0
  52. package/src/reports/moh-240/moh-240.component.tsx +65 -84
  53. package/src/reports/moh-240/moh-240.scss +36 -7
  54. package/src/reports/moh-240/sub-reports/moh-240-register.component.tsx +27 -65
  55. package/src/reports/moh-240/sub-reports/page-summary.component.tsx +2 -2
  56. package/src/reports/moh-505/moh-505-header.component.tsx +59 -57
  57. package/src/reports/moh-505/moh-505.component.tsx +51 -56
  58. package/src/reports/moh-505/moh-505.scss +116 -2
  59. package/src/reports/moh-705B/moh-204b-register.component.tsx +41 -42
  60. package/src/reports/moh-705B/moh-204b.columns.ts +39 -0
  61. package/src/reports/moh-705B/moh-705b.component.tsx +492 -473
  62. package/src/reports/moh-705B/moh-705b.scss +110 -24
  63. package/src/reports/moh-705a/moh-705a.component.tsx +496 -476
  64. package/src/reports/moh-705a/moh-705a.scss +109 -24
  65. package/src/reports/moh-705a/registers/moh-204a-register.component.tsx +41 -42
  66. package/src/reports/moh-705a/registers/moh-204a.columns.ts +57 -0
  67. package/src/reports/moh-706/moh-706-header.component.tsx +58 -56
  68. package/src/reports/moh-706/moh-706.component.tsx +84 -55
  69. package/src/reports/moh-706/moh-706.scss +115 -19
  70. package/src/reports/moh-710/moh-710.component.tsx +743 -727
  71. package/src/reports/moh-710/moh-710.scss +140 -23
  72. package/src/reports/moh-710/registers/moh-511-710-register.component.tsx +48 -43
  73. package/src/reports/moh-710/registers/moh-511-710.columns.ts +52 -0
  74. package/src/reports/moh-711/moh-711.component.tsx +94 -106
  75. package/src/reports/moh-711/moh711.scss +95 -64
  76. package/src/reports/moh-711/registers/moh-333-register.component.tsx +92 -94
  77. package/src/reports/moh-711/registers/moh-333.columns.ts +119 -0
  78. package/src/reports/moh-711/registers/moh-405-register.component.tsx +88 -89
  79. package/src/reports/moh-711/registers/moh-405.columns.ts +120 -0
  80. package/src/reports/moh-711/registers/moh-406-register.component.tsx +85 -88
  81. package/src/reports/moh-711/registers/moh-406.columns.ts +133 -0
  82. package/src/reports/moh-711/registers/moh-510-register.component.tsx +38 -44
  83. package/src/reports/moh-711/registers/moh-511-register.component.tsx +42 -43
  84. package/src/reports/moh-711/registers/moh-511.columns.ts +59 -0
  85. package/src/reports/moh-711/sections/anc.component.tsx +3 -3
  86. package/src/reports/moh-711/sections/cervical-cancer.component.tsx +3 -3
  87. package/src/reports/moh-711/sections/chanis.component.tsx +2 -3
  88. package/src/reports/moh-711/sections/family-planning.component.tsx +2 -2
  89. package/src/reports/moh-711/sections/gbv.component.tsx +2 -2
  90. package/src/reports/moh-711/sections/maternity.component.tsx +3 -8
  91. package/src/reports/moh-711/sections/medical-social-work.component.tsx +2 -12
  92. package/src/reports/moh-711/sections/other.component.tsx +2 -2
  93. package/src/reports/moh-711/sections/physiotherapy.component.tsx +2 -2
  94. package/src/reports/moh-711/sections/pnc.component.tsx +7 -5
  95. package/src/reports/moh-711/sections/post-abortion.component.tsx +2 -2
  96. package/src/reports/moh-711/sections/rehabilitation.component.tsx +2 -2
  97. package/src/reports/moh-711/sections/report-compiled-by.component.tsx +12 -4
  98. package/src/reports/moh-711/sections/tb-screening.component.tsx +2 -2
  99. package/src/reports/moh-717/moh-717.component.tsx +100 -121
  100. package/src/reports/moh-717/moh717.scss +163 -102
  101. package/src/reports/moh-717/sections/maternity.component.tsx +1 -1
  102. package/src/reports/moh-717/sections/orthopaedic-trauma.component.tsx +1 -1
  103. package/src/reports/moh-717/sections/outpatient.component.tsx +23 -23
  104. package/src/reports/moh-717/sections/preparedby.component.tsx +7 -2
  105. package/src/reports/moh-717/sections/special-services.component.tsx +1 -1
  106. package/src/reports/moh-731/moh-731.component.tsx +127 -110
  107. package/src/reports/moh-731/moh-731.scss +396 -68
  108. package/src/reports/moh-731/registers/moh-366.columns.ts +38 -0
  109. package/src/reports/moh-731/registers/moh-366.component.tsx +76 -83
  110. package/src/reports/moh-731/registers/prep-register.component.tsx +70 -78
  111. package/src/reports/moh-731/registers/prep.columns.ts +34 -0
  112. package/src/reports/moh-731/sections/hiv-and-tb-treatment.component.tsx +1031 -751
  113. package/src/reports/moh-731/sections/hiv-testing-and-pre-exposure.component.tsx +230 -86
  114. package/src/reports/moh-731/sections/pmtct.component.tsx +185 -64
  115. package/src/reports/moh-740/moh-740.component.scss +159 -79
  116. package/src/reports/moh-740/moh-740.component.tsx +258 -227
  117. package/src/reports/moh-740/moh-740.resource.ts +17 -10
  118. package/src/reports/moh-740/registers/moh-222-daily-register/moh-222-daily-register.tsx +77 -96
  119. package/src/reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register.tsx +50 -70
  120. package/src/reports/moh-740/registers/moh-740-patient-list.tsx +61 -32
  121. package/src/reports/moh-740/registers/moh-740.columns.ts +52 -0
  122. package/src/reports/moh-745/moh-745.component.tsx +897 -877
  123. package/src/reports/moh-745/moh-745.scss +104 -46
  124. package/src/reports/moh-745/registers/moh-412-register.component.tsx +42 -43
  125. package/src/reports/moh-745/registers/moh-412.columns.ts +52 -0
  126. package/src/reports/table-wrapper/table-wrapper.component.tsx +23 -14
  127. package/src/reports/table-wrapper/table-wrapper.scss +1 -16
  128. package/src/resources/moh-505.resource.ts +18 -35
  129. package/src/resources/moh-705.resource.ts +28 -39
  130. package/src/resources/moh-706.resource.ts +17 -30
  131. package/src/resources/moh-710.resource.ts +7 -17
  132. package/src/resources/moh-711.resource.ts +46 -64
  133. package/src/resources/moh-717.resource.ts +7 -17
  134. package/src/resources/moh-731.resource.ts +26 -32
  135. package/src/resources/moh-745.resource.ts +18 -20
  136. package/src/resources/patient-list-page.ts +66 -0
  137. package/src/root.component.tsx +28 -26
  138. package/src/root.scss +39 -0
  139. package/src/utils/get-base-url.ts +39 -7
  140. package/dist/822.js +0 -2
  141. package/dist/822.js.LICENSE.txt +0 -20
  142. package/dist/822.js.map +0 -1
  143. package/src/reports/moh-731/registers/moh-366.scss +0 -45
  144. package/src/reports/moh-731/registers/prep-registers.scss +0 -45
  145. package/src/reports/moh-740/registers/moh-222-daily-register/moh-222-daily-register.scss +0 -18
  146. package/src/reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register.scss +0 -18
  147. /package/src/{reports/moh-740/shared/utils → utils}/format-indicator.ts +0 -0
@@ -1,74 +1,132 @@
1
+ /* MOH-745 laid out for A4, matching MOH-711 and MOH-740: geometry in
2
+ millimetres, type in points, one rule weight. Its 33 rows fit one page. */
1
3
 
2
- h3 {
3
- text-align: center;
4
+ $ink: #000;
5
+ $rule: 1px solid $ink;
6
+
7
+ $text: 7pt;
8
+ $title: 7.5pt;
9
+ $meta: 6.5pt;
10
+
11
+ /* The blocks below stack flush and share their edges, so the sheet reads as one
12
+ continuous form rather than a title, two loose tables and a footer. */
13
+
14
+ .reportTitle {
15
+ padding: 3mm;
16
+ font-size: $title;
17
+ font-weight: 700;
18
+ text-align: center;
19
+ border: $rule;
4
20
  }
5
- .tableContainer {
6
- margin-left: 2rem;
7
- margin-bottom: 2rem;
8
- margin-top: 1rem;
21
+
22
+ /* Facility / county / period strip, and the sign-off at the foot: both are one
23
+ line of fields separated by spacing, with rules to write on. */
24
+
25
+ .location {
26
+ display: flex;
27
+ flex-wrap: nowrap;
28
+ align-items: baseline;
29
+ justify-content: space-between;
30
+ /* Six fields rather than the five the other reports carry, so the rules are
31
+ a little shorter to keep the row on one line. */
32
+ gap: 2.5mm;
33
+ padding: 2mm 3mm;
34
+ font-size: $meta;
35
+ white-space: nowrap;
36
+ border: $rule;
37
+ border-top: none;
9
38
  }
10
39
 
11
- .sectionTitle {
12
- margin-left: 1rem ;
40
+ .line,
41
+ .shortLine {
42
+ display: inline-block;
43
+ padding: 0 0.5mm;
44
+ margin-left: 1mm;
45
+ overflow: hidden;
46
+ font-weight: 600;
47
+ text-align: center;
48
+ text-overflow: ellipsis;
49
+ vertical-align: bottom;
50
+ border-bottom: $rule;
13
51
  }
14
52
 
15
- .table {
16
- width: auto;
17
- border-collapse: collapse;
18
-
53
+ .line {
54
+ width: 24mm;
19
55
  }
20
56
 
57
+ .shortLine {
58
+ width: 12mm;
59
+ }
21
60
 
61
+ .tableContainer {
62
+ width: 100%;
63
+ overflow-x: auto;
64
+
65
+ /* pulls the second table onto the first one's edge instead of doubling it */
66
+ & + & {
67
+ margin-top: -1px;
68
+ }
69
+ }
70
+
71
+ .table {
72
+ width: 100%;
73
+ border-collapse: collapse;
74
+ }
22
75
 
23
76
  .tableBordered td,
24
77
  .tableBordered th {
25
- border: 1px solid #ccc;
26
- padding: 0.3rem;
27
- font-size: small;
78
+ padding: 1mm 1.5mm;
79
+ font-size: $text;
80
+ text-align: center;
81
+ border: $rule;
28
82
  }
29
83
 
30
84
  .tableBordered th {
31
- font-weight: bold;
32
- }
85
+ font-weight: 700;
86
+ background-color: #f4f4f4;
87
+ }
33
88
 
34
89
  .tableStriped tbody tr:nth-of-type(odd) {
35
- background-color: #f9f9f9;
90
+ background-color: #fafafa;
36
91
  }
37
92
 
38
- .rotateUp {
39
- writing-mode: vertical-rl;
40
- transform: rotate(180deg);
93
+ /* Sign-off, enclosed by the form rather than floating beneath it.
94
+
95
+ Its rules are wider than the header strip's: four fields across the sheet
96
+ leave about 133mm for them, where the header has to fit six. At the shared
97
+ 12mm a date like "29-Jul-2026" needs 13.6mm and was being ellipsised. Sized
98
+ to leave headroom rather than to fill the row exactly. */
99
+
100
+ .signOff .line {
101
+ width: 36mm;
41
102
  }
42
103
 
43
- /*
44
- span {
45
- font-weight: normal;
46
- padding: 2px;
104
+ .signOff .shortLine {
105
+ width: 22mm;
47
106
  }
48
- */
49
- .location {
50
- margin: 2rem;
107
+
108
+ .signOff {
51
109
  display: flex;
52
- flex-wrap: nowrap;
53
- align-items: center;
54
- gap: 12px;
55
- white-space: nowrap;
110
+ flex-wrap: nowrap;
111
+ align-items: baseline;
112
+ justify-content: space-between;
113
+ gap: 2.5mm;
114
+ padding: 3mm;
115
+ font-size: $meta;
116
+ white-space: nowrap;
117
+ border: $rule;
118
+ border-top: none;
56
119
  }
57
120
 
58
-
59
- .line {
60
- display: inline-block;
61
- width: 150px;
62
- border-bottom: 1px solid #000;
63
- margin-left: 4px;
121
+ .rotateUp {
122
+ writing-mode: vertical-rl;
123
+ transform: rotate(180deg);
64
124
  }
65
125
 
66
- .shortLine {
67
- display: inline-block;
68
- width: 90px;
69
- border-bottom: 1px solid #000;
70
- margin-left: 4px;
126
+ /* On paper the striping is screen affordance that prints as grey noise */
127
+
128
+ @media print {
129
+ .tableStriped tbody tr:nth-of-type(odd) {
130
+ background-color: transparent;
131
+ }
71
132
  }
72
- .buttonContainer {
73
- margin: 2rem;
74
- }
@@ -1,17 +1,15 @@
1
- import { Button, Loading, Table, TableBody, TableHead, TableHeader, TableRow } from '@carbon/react';
2
- import React, { useEffect, useState } from 'react';
1
+ import { Table, TableBody, TableHead, TableHeader, TableRow } from '@carbon/react';
2
+ import React from 'react';
3
3
 
4
- import styles from '../moh-745.scss';
4
+ import styles from '../../../common/report-register/register-table.scss';
5
5
  import classNames from 'classnames';
6
- import { useNavigate, useSearchParams } from 'react-router-dom';
6
+ import { useSearchParams } from 'react-router-dom';
7
7
  import { moh412Columns } from './type';
8
8
  import { getMoh412PatientList } from '../../../resources/moh-745.resource';
9
+ import { moh412ExportColumns } from './moh-412.columns';
10
+ import { RegisterLayout, usePatientList } from '../../../common/report-register';
9
11
 
10
12
  const Moh412Register: React.FC = () => {
11
- const navigate = useNavigate();
12
- const [patientlist, setPatientList] = useState<any[]>([]);
13
- const [isLoading, setIsLoading] = useState(false);
14
-
15
13
  const [searchParams] = useSearchParams();
16
14
 
17
15
  const startDate = searchParams.get('startDate');
@@ -19,42 +17,43 @@ const Moh412Register: React.FC = () => {
19
17
  const locationUuids = searchParams.get('locationUuids');
20
18
  const indicator = searchParams.get('indicator');
21
19
 
22
- useEffect(() => {
23
- const fetchData = async () => {
24
- if (!startDate || !endDate || !locationUuids || !indicator) return;
25
-
26
- setIsLoading(true);
27
-
28
- try {
29
- const params = {
30
- startDate,
31
- endDate,
32
- locationUuids,
33
- indicator,
34
- };
35
-
36
- const data = await getMoh412PatientList(params);
37
-
38
- setPatientList(data?.results.results || []);
39
- } catch (error) {
40
- console.error('Failed to fetch register data', error);
41
- } finally {
42
- setIsLoading(false);
43
- }
44
- };
45
-
46
- fetchData();
47
- }, [startDate, endDate, locationUuids, indicator]);
20
+ const {
21
+ rows: patientlist,
22
+ total,
23
+ isTotalExact,
24
+ isLoading,
25
+ page,
26
+ pageSize,
27
+ onPageChange,
28
+ fetchAll,
29
+ } = usePatientList(
30
+ ({ startIndex, limit }) =>
31
+ getMoh412PatientList({
32
+ startDate,
33
+ endDate,
34
+ locationUuids,
35
+ indicator,
36
+ startIndex,
37
+ limit,
38
+ }),
39
+ [startDate, endDate, locationUuids, indicator],
40
+ );
48
41
 
49
- function navigateBack() {
50
- navigate('/moh-745');
51
- }
52
42
  return (
53
- <>
54
- <div className={styles.buttonContainer}>
55
- <Button onClick={navigateBack}>Back</Button>
56
- </div>
57
- <div>{isLoading && <Loading />}</div>
43
+ <RegisterLayout
44
+ parentLabel="MOH-745 Report"
45
+ parentPath="/moh-745"
46
+ title="MOH 412 Cancer Screening Register"
47
+ isLoading={isLoading}
48
+ isEmpty={patientlist.length === 0}
49
+ page={page}
50
+ pageSize={pageSize}
51
+ total={total}
52
+ isTotalExact={isTotalExact}
53
+ onPageChange={onPageChange}
54
+ fetchAll={fetchAll}
55
+ columns={moh412ExportColumns}
56
+ >
58
57
  <div className={styles.tableContainer}>
59
58
  <Table className={classNames(`${styles.table}`, `${styles.tableBordered}`, `${styles.tableStriped}`)}>
60
59
  <TableHead>
@@ -185,7 +184,7 @@ const Moh412Register: React.FC = () => {
185
184
  </TableBody>
186
185
  </Table>
187
186
  </div>
188
- </>
187
+ </RegisterLayout>
189
188
  );
190
189
  };
191
190
  export default Moh412Register;
@@ -0,0 +1,52 @@
1
+ import { type RegisterColumn } from '../../../common/report-register';
2
+
3
+ /**
4
+ * MOH 412 as the register prints it: one column per cell, in the order they appear.
5
+ *
6
+ * One column is rendered by the table but has no heading above it -- the
7
+ * header row is 24 columns wide against 25 of data. It carries its field name
8
+ * rather than a heading borrowed from a neighbouring column.
9
+ */
10
+ export const moh412ExportColumns: RegisterColumn[] = [
11
+ { header: 'Client Details - a)S/No No', value: (row) => row.serial_no ?? '' },
12
+ { header: 'Client Details - b)Visit Date', value: (row) => row.visit_date ?? '' },
13
+ { header: 'Client Details - c)Visit Type', value: (row) => row.visit_type ?? '' },
14
+ { header: 'Client Details - d)Client No', value: (row) => row.client_no ?? '' },
15
+ { header: 'Client Details - e)Client Names', value: (row) => row.full_names ?? '' },
16
+ { header: "Client Details - f)Client's Phone Number", value: (row) => row.phone_number ?? '' },
17
+ { header: "Client Details - g)Client's Age", value: (row) => row.age ?? '' },
18
+ { header: 'Client Details - h)Location Residence', value: (row) => row.location_residence ?? '' },
19
+ {
20
+ header: "Client Details - i)Treatment Suppoter's Phone Number",
21
+ value: (row) => row.treatment_supporter_phone_number ?? '',
22
+ },
23
+ {
24
+ header: 'CERVICAL CANCER - Screening Methods and Results - j)Via or VIA/VILLI',
25
+ value: (row) => row.via_villi ?? '',
26
+ },
27
+ { header: 'CERVICAL CANCER - Screening Methods and Results - k)Pap Smear', value: (row) => row.pap_smear ?? '' },
28
+ {
29
+ header: 'CERVICAL CANCER - Screening Methods and Results - l)HPV Test (over 30 years)',
30
+ value: (row) => row.hpv ?? '',
31
+ },
32
+ { header: 'CERVICAL CANCER - Pre-Cancer Treatment - m)cryotherapy', value: (row) => row.cryotherapy ?? '' },
33
+ {
34
+ header: 'CERVICAL CANCER - Pre-Cancer Treatment - n)Thermo- ablation',
35
+ value: (row) => row.thermocoagulation ?? '',
36
+ },
37
+ { header: 'CERVICAL CANCER - Pre-Cancer Treatment - o)LEEP', value: (row) => row.leep ?? '' },
38
+ { header: 'Breast Cancer - Methods and Results - p)CBE', value: (row) => row.cbe ?? '' },
39
+ { header: 'Breast Cancer - Methods and Results - q)Ultrasound', value: (row) => row.ultrasound ?? '' },
40
+ { header: 'Breast Cancer - Methods and Results - r)Mammogram', value: (row) => row.mammogram ?? '' },
41
+ { header: 'Colorectal Cancer - Methods and Results - s)Colonoscopy', value: (row) => row.colonoscopy ?? '' },
42
+ { header: 'Colorectal Cancer - Methods and Results - t)FOBT', value: (row) => row.fobt ?? '' },
43
+ { header: 'u)HIV Status', value: (row) => row.hiv_status ?? '' },
44
+ { header: 'v)Referral To/From', value: (row) => row.referral_from ?? '' },
45
+ { header: 'w)Follow- up Date', value: (row) => row.referral_to ?? '' },
46
+ {
47
+ header:
48
+ 'Remarks(e.g Colposcopy done, Cervicography results, Call Client for follow up, Return for post-treatment screening, Communicate with the referral site)',
49
+ value: (row) => row.follow_up_date ?? '',
50
+ },
51
+ { header: 'Remarks', value: (row) => row.remarks ?? '' },
52
+ ];
@@ -1,21 +1,30 @@
1
1
  import React from 'react';
2
- import { Table, TableBody } from '@carbon/react';
2
+ import classNames from 'classnames';
3
3
  import styles from './table-wrapper.scss';
4
4
 
5
5
  interface TableWrapperProps {
6
- children: React.ReactNode;
6
+ children: React.ReactNode;
7
+ /** Applied to the wrapper, so a report can use its own stylesheet */
8
+ className?: string;
7
9
  }
8
10
 
9
- const TableWrapper: React.FC<TableWrapperProps> = ({ children }) => {
10
- return <>
11
- <div className={styles.tableWrapper}>
12
- <Table size="sm" className={styles.tableComponent}>
13
- <TableBody>
14
- {children}
15
- </TableBody>
16
- </Table>
17
- </div>
18
- </>
19
- }
11
+ /**
12
+ * The frame the form-shaped reports render their tables in.
13
+ *
14
+ * This used to be Carbon's `<Table>`, but every report that uses it is a
15
+ * printed form rather than a data grid: Carbon sizes its rows to 2rem and pads
16
+ * its cells to 1rem, at a specificity no report stylesheet can reasonably
17
+ * outrank. A plain table carries none of those rules, so the reports size their
18
+ * own cells for A4.
19
+ */
20
+ const TableWrapper: React.FC<TableWrapperProps> = ({ children, className }) => {
21
+ return (
22
+ <div className={classNames(styles.tableWrapper, className)}>
23
+ <table>
24
+ <tbody>{children}</tbody>
25
+ </table>
26
+ </div>
27
+ );
28
+ };
20
29
 
21
- export default TableWrapper;
30
+ export default TableWrapper;
@@ -1,20 +1,5 @@
1
1
  .tableWrapper {
2
2
  overflow-x: auto;
3
- border-radius: 4px;
4
- padding: 5px;
5
- }
6
-
7
- .tableContainer {
8
- width: 100%;
9
- border-collapse: collapse;
10
-
11
- thead {
12
- background-color: #f4f4f4;
13
- }
14
-
15
- tbody {
16
- background-color: white;
17
- }
18
3
  }
19
4
 
20
5
  .dataCell {
@@ -28,4 +13,4 @@
28
13
  &:hover {
29
14
  background-color: #f0f7ff;
30
15
  }
31
- }
16
+ }
@@ -1,5 +1,12 @@
1
1
  import { openmrsFetch } from '@openmrs/esm-framework';
2
- import { getEtlBaseUrl } from '../utils/get-base-url';
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';
3
10
 
4
11
  interface Moh505Params {
5
12
  locationUuids: string;
@@ -11,30 +18,14 @@ interface Moh505Response {
11
18
  result: Array<Record<string, unknown>>;
12
19
  }
13
20
 
14
- interface Moh505PatientListParams {
15
- locationUuids: string;
16
- startDate?: string;
17
- endDate?: string;
18
- indicators: string;
19
- }
20
-
21
- interface Moh505PatientListResponse {
22
- result: Array<Record<string, unknown>>;
23
- }
24
-
25
21
  export async function getMoh505(params: Moh505Params): Promise<Array<Record<string, unknown>>> {
26
- const etlBaseUrl = await getEtlBaseUrl();
27
- const url = `${etlBaseUrl}/moh-505`;
28
- const queryparams = {
22
+ const url = await buildEtlUrl('moh-505', {
29
23
  locationUuids: params.locationUuids || '',
30
24
  startDate: params.startDate || '',
31
25
  endDate: params.endDate || '',
32
- };
33
- const queryString = new URLSearchParams(
34
- Object.fromEntries(Object.entries(queryparams).filter(([_, v]) => v !== undefined && v !== null)),
35
- ).toString();
26
+ });
36
27
  try {
37
- const response = await openmrsFetch(`${url}?${queryString}`);
28
+ const response = await openmrsFetch(url);
38
29
 
39
30
  if (!response.ok) {
40
31
  const errorText = await response.text();
@@ -53,20 +44,16 @@ export async function getMoh505(params: Moh505Params): Promise<Array<Record<stri
53
44
  }
54
45
  }
55
46
 
56
- export async function getMoh505PatientList(params: Moh505PatientListParams): Promise<Array<Record<string, unknown>>> {
57
- const etlBaseUrl = await getEtlBaseUrl();
58
- const url = `${etlBaseUrl}/moh-505/patient-list`;
59
- const queryparams = {
47
+ export async function getMoh505PatientList(params: PatientListParams): Promise<PatientListPage> {
48
+ const url = await buildEtlUrl('moh-505/patient-list', {
60
49
  locationUuids: params.locationUuids || '',
61
50
  startDate: params.startDate || '',
62
51
  endDate: params.endDate || '',
63
52
  indicators: params.indicators || '',
64
- };
65
- const queryString = new URLSearchParams(
66
- Object.fromEntries(Object.entries(queryparams).filter(([_, v]) => v !== undefined && v !== null)),
67
- ).toString();
53
+ ...pageParams(params),
54
+ });
68
55
  try {
69
- const response = await openmrsFetch(`${url}?${queryString}`);
56
+ const response = await openmrsFetch(url);
70
57
 
71
58
  if (!response.ok) {
72
59
  const errorText = await response.text();
@@ -75,12 +62,8 @@ export async function getMoh505PatientList(params: Moh505PatientListParams): Pro
75
62
 
76
63
  const data = await response.json();
77
64
 
78
- if (!Array.isArray(data.result)) {
79
- throw new Error('Invalid MOH-505 patient list response format: missing result array.');
80
- }
81
-
82
- return data.result;
65
+ return toPatientListPage(data, params.startIndex ?? 0, params.limit ?? PAGE_SIZE);
83
66
  } catch (error: any) {
84
67
  throw new Error(`An error occurred while fetching the MOH-505 patient list: ${error.message}`);
85
68
  }
86
- }
69
+ }
@@ -1,5 +1,12 @@
1
1
  import { openmrsFetch } from '@openmrs/esm-framework';
2
- import { getEtlBaseUrl } from '../utils/get-base-url';
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';
3
10
 
4
11
  interface Moh710Params {
5
12
  locationUuids: string;
@@ -9,18 +16,13 @@ interface Moh710Params {
9
16
  }
10
17
 
11
18
  export async function getMoh705a(params: Moh710Params): Promise<any> {
12
- const etlBaseUrl = await getEtlBaseUrl();
13
- const url = `${etlBaseUrl}/moh-705a`;
14
- const queryparams = {
19
+ const url = await buildEtlUrl('moh-705a', {
15
20
  locationUuids: params.locationUuids || '',
16
21
  startDate: params.startDate || '',
17
22
  endDate: params.endDate || '',
18
- };
19
- const queryString = new URLSearchParams(
20
- Object.fromEntries(Object.entries(queryparams).filter(([_, v]) => v !== undefined && v !== null)),
21
- ).toString();
23
+ });
22
24
  try {
23
- const response = await openmrsFetch(`${url}?${queryString}`);
25
+ const response = await openmrsFetch(url);
24
26
 
25
27
  if (!response.ok) {
26
28
  const errorText = await response.text();
@@ -34,21 +36,16 @@ export async function getMoh705a(params: Moh710Params): Promise<any> {
34
36
  }
35
37
  }
36
38
 
37
- export async function getMoh705aPatientList(params: Moh710Params): Promise<any> {
38
- const etlBaseUrl = await getEtlBaseUrl();
39
- const url = `${etlBaseUrl}/moh-705a-patient-list`;
40
- const queryparams = {
39
+ export async function getMoh705aPatientList(params: PatientListParams): Promise<PatientListPage> {
40
+ const url = await buildEtlUrl('moh-705a-patient-list', {
41
41
  locationUuids: params.locationUuids || '',
42
42
  startDate: params.startDate || '',
43
43
  endDate: params.endDate || '',
44
44
  indicator: Array.isArray(params.indicator) ? params.indicator.join(',') : params.indicator || '',
45
- limit: '300',
46
- };
47
- const queryString = new URLSearchParams(
48
- Object.fromEntries(Object.entries(queryparams).filter(([_, v]) => v !== undefined && v !== null)),
49
- ).toString();
45
+ ...pageParams(params),
46
+ });
50
47
  try {
51
- const response = await openmrsFetch(`${url}?${queryString}`);
48
+ const response = await openmrsFetch(url);
52
49
 
53
50
  if (!response.ok) {
54
51
  const errorText = await response.text();
@@ -56,25 +53,21 @@ export async function getMoh705aPatientList(params: Moh710Params): Promise<any>
56
53
  }
57
54
 
58
55
  const data = await response.json();
59
- return data;
56
+
57
+ return toPatientListPage(data, params.startIndex ?? 0, params.limit ?? PAGE_SIZE);
60
58
  } catch (error: any) {
61
59
  throw new Error(`An error occurred while fetching the MOH-705 patient list: ${error.message}`);
62
60
  }
63
61
  }
64
62
 
65
63
  export async function getMoh705b(params: Moh710Params): Promise<any> {
66
- const etlBaseUrl = await getEtlBaseUrl();
67
- const url = `${etlBaseUrl}/moh-705b`;
68
- const queryparams = {
64
+ const url = await buildEtlUrl('moh-705b', {
69
65
  locationUuids: params.locationUuids || '',
70
66
  startDate: params.startDate || '',
71
67
  endDate: params.endDate || '',
72
- };
73
- const queryString = new URLSearchParams(
74
- Object.fromEntries(Object.entries(queryparams).filter(([_, v]) => v !== undefined && v !== null)),
75
- ).toString();
68
+ });
76
69
  try {
77
- const response = await openmrsFetch(`${url}?${queryString}`);
70
+ const response = await openmrsFetch(url);
78
71
 
79
72
  if (!response.ok) {
80
73
  const errorText = await response.text();
@@ -88,21 +81,16 @@ export async function getMoh705b(params: Moh710Params): Promise<any> {
88
81
  }
89
82
  }
90
83
 
91
- export async function getMoh705bPatientList(params: Moh710Params): Promise<any> {
92
- const etlBaseUrl = await getEtlBaseUrl();
93
- const url = `${etlBaseUrl}/moh-705b-patient-list`;
94
- const queryparams = {
84
+ export async function getMoh705bPatientList(params: PatientListParams): Promise<PatientListPage> {
85
+ const url = await buildEtlUrl('moh-705b-patient-list', {
95
86
  locationUuids: params.locationUuids || '',
96
87
  startDate: params.startDate || '',
97
88
  endDate: params.endDate || '',
98
89
  indicator: Array.isArray(params.indicator) ? params.indicator.join(',') : params.indicator || '',
99
- limit: '300',
100
- };
101
- const queryString = new URLSearchParams(
102
- Object.fromEntries(Object.entries(queryparams).filter(([_, v]) => v !== undefined && v !== null)),
103
- ).toString();
90
+ ...pageParams(params),
91
+ });
104
92
  try {
105
- const response = await openmrsFetch(`${url}?${queryString}`);
93
+ const response = await openmrsFetch(url);
106
94
 
107
95
  if (!response.ok) {
108
96
  const errorText = await response.text();
@@ -110,7 +98,8 @@ export async function getMoh705bPatientList(params: Moh710Params): Promise<any>
110
98
  }
111
99
 
112
100
  const data = await response.json();
113
- return data;
101
+
102
+ return toPatientListPage(data, params.startIndex ?? 0, params.limit ?? PAGE_SIZE);
114
103
  } catch (error: any) {
115
104
  throw new Error(`An error occurred while fetching the MOH-705 patient list: ${error.message}`);
116
105
  }