@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,222 @@
1
+ @use '@carbon/layout';
2
+ @use '@openmrs/esm-styleguide/src/vars' as *;
3
+
4
+ /* The two MOH 362 sheets (HTS lab register; referral and linkage register),
5
+ drawn as on the printed form: black rules, small type, two-line cells split
6
+ by a dotted rule. Both are wide landscape sheets, so each scrolls sideways
7
+ inside its frame rather than widening the page. */
8
+
9
+ $ink: #000;
10
+ $rule: 1px solid $ink;
11
+ $dotted: 1px dotted $ink;
12
+ $shade: #e8e8e8; // the grey label cells of the summary blocks
13
+ $text: 0.6875rem; // 11px body
14
+ $small: 0.625rem; // 10px codes and kit details
15
+
16
+ .sheet {
17
+ margin-top: layout.$spacing-05;
18
+ padding: layout.$spacing-05;
19
+ color: $ink;
20
+ font-size: $text;
21
+ line-height: 1.25;
22
+ background-color: $ui-02;
23
+ border: 1px solid $ui-03;
24
+ }
25
+
26
+ .runningHead {
27
+ display: grid;
28
+ grid-template-columns: 1fr auto 1fr;
29
+ gap: layout.$spacing-05;
30
+ font-size: $small;
31
+
32
+ span:nth-child(2) {
33
+ text-align: center;
34
+ }
35
+
36
+ span:last-child {
37
+ text-align: right;
38
+ }
39
+ }
40
+
41
+ .sheetTitle {
42
+ margin: layout.$spacing-02 0 layout.$spacing-03;
43
+ font-size: 0.8125rem;
44
+ font-weight: 700;
45
+ text-align: center;
46
+ }
47
+
48
+ /* the referral and linkage register's title is set in a serif on the form */
49
+ .serifTitle {
50
+ font-family: Georgia, 'Times New Roman', serif;
51
+ }
52
+
53
+ .tableScroll {
54
+ overflow-x: auto;
55
+ }
56
+
57
+ .register {
58
+ width: 100%;
59
+ min-width: 70rem;
60
+ border-collapse: collapse;
61
+
62
+ th,
63
+ td {
64
+ padding: layout.$spacing-02 layout.$spacing-02;
65
+ text-align: center;
66
+ vertical-align: middle;
67
+ border: $rule;
68
+ }
69
+
70
+ th {
71
+ font-weight: 400;
72
+ vertical-align: top;
73
+ }
74
+
75
+ td {
76
+ height: 1.125rem;
77
+ }
78
+ }
79
+
80
+ /* (a), (b) ... under the headings */
81
+ .columnIds th {
82
+ padding-top: 1px;
83
+ padding-bottom: 1px;
84
+ font-weight: 700;
85
+ vertical-align: middle;
86
+ }
87
+
88
+ /* Columns of code lists and wide text keep a readable width */
89
+ .codes {
90
+ min-width: 6.5rem;
91
+ text-align: left !important;
92
+ font-size: $small;
93
+ }
94
+
95
+ .wide {
96
+ min-width: 8rem;
97
+ }
98
+
99
+ .left {
100
+ text-align: left !important;
101
+ }
102
+
103
+ /* A heading holding two labels: upper cell above lower cell */
104
+ .splitHeader {
105
+ min-width: 8rem;
106
+ padding: 0 !important;
107
+
108
+ span {
109
+ display: block;
110
+ padding: layout.$spacing-02;
111
+ }
112
+
113
+ span:first-child {
114
+ border-bottom: $dotted;
115
+ }
116
+ }
117
+
118
+ /* The two halves of a two-line cell */
119
+ .upperCell {
120
+ border-bottom: $dotted !important;
121
+ }
122
+
123
+ .lowerCell {
124
+ border-top: $dotted !important;
125
+ }
126
+
127
+ /* An HIV test heading: kit, lot and expiry lines, then the result codes */
128
+ .testHeader {
129
+ min-width: 6rem;
130
+ text-align: left !important;
131
+
132
+ span {
133
+ display: block;
134
+ }
135
+
136
+ span:not(:first-child) {
137
+ margin-top: layout.$spacing-02;
138
+ }
139
+ }
140
+
141
+ .dateRule {
142
+ letter-spacing: 1px;
143
+ }
144
+
145
+ .testCell {
146
+ strong {
147
+ display: block;
148
+ font-weight: 700;
149
+ }
150
+ }
151
+
152
+ .testDetail {
153
+ display: block;
154
+ margin-top: 1px;
155
+ font-size: $small;
156
+ color: $text-02;
157
+ }
158
+
159
+ /* Totals Clients Linked */
160
+ .totalRow th,
161
+ .totalRow td {
162
+ font-weight: 700;
163
+ background-color: $shade;
164
+ }
165
+
166
+ /* Summary blocks at the foot of the HTS lab register */
167
+
168
+ .summary {
169
+ display: flex;
170
+ flex-wrap: wrap;
171
+ align-items: flex-start;
172
+ /* one row on a wide screen, as on the form; wraps on a narrow one */
173
+ gap: layout.$spacing-04;
174
+ margin-top: layout.$spacing-05;
175
+ }
176
+
177
+ .summaryColumn {
178
+ display: flex;
179
+ flex-direction: column;
180
+ gap: layout.$spacing-04;
181
+ }
182
+
183
+ .summaryTable {
184
+ border-collapse: collapse;
185
+
186
+ th,
187
+ td {
188
+ min-width: 2.5rem;
189
+ padding: layout.$spacing-02 layout.$spacing-02;
190
+ text-align: center;
191
+ border: $rule;
192
+ }
193
+
194
+ th {
195
+ font-weight: 700;
196
+ background-color: $shade;
197
+ }
198
+ }
199
+
200
+ .summaryLabel {
201
+ text-align: right !important;
202
+ white-space: nowrap;
203
+ }
204
+
205
+ .bigFigure {
206
+ height: 3rem;
207
+ font-size: 0.875rem;
208
+ font-weight: 700;
209
+ }
210
+
211
+ .signOff {
212
+ display: flex;
213
+ justify-content: center;
214
+ gap: layout.$spacing-09;
215
+ margin-top: layout.$spacing-05;
216
+ }
217
+
218
+ .rule {
219
+ display: inline-block;
220
+ width: 12rem;
221
+ border-bottom: $rule;
222
+ }
@@ -0,0 +1,99 @@
1
+ import React, { useState } from 'react';
2
+ import { useSearchParams } from 'react-router-dom';
3
+ import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
4
+ import { useSession } from '@openmrs/esm-framework';
5
+
6
+ import { ReportFiltersComponent, type ReportPeriod, useRestorePeriod } from '../../common/report-filters';
7
+ import { showReportError } from '../../common/report-error';
8
+ import { ReportPlaceholder, useGeneratedLocation } from '../../common/report-placeholder';
9
+ import { ReportSkeleton } from '../../common/report-skeleton';
10
+ import { getMoh362 } from '../../resources/moh-362.resource';
11
+ import Moh362LabRegister from './moh-362-lab-register.component';
12
+ import Moh362LinkageRegister from './moh-362-linkage-register.component';
13
+ import { isLinked, type Moh362Row } from './moh-362.types';
14
+ import styles from './moh-362.scss';
15
+
16
+ /**
17
+ * MOH 362 HTS Lab, Referral & Linkage Register, opened from the landing page's
18
+ * Registers tab. It shares the reports' filter bar. Unlike the other registers
19
+ * the form holds two sheets, shown as tabs: the HTS lab register (every test,
20
+ * the same tests as MOH 731 1.1 HIV Tests) and the referral and linkage
21
+ * register (those who tested positive and were linked to care, i.e. have an ART
22
+ * start date).
23
+ */
24
+ const Moh362Register: React.FC = () => {
25
+ const [rows, setRows] = useState<Moh362Row[] | null>(null);
26
+ const [isLoading, setIsLoading] = useState(false);
27
+ const [period, setPeriod] = useState<{ startDate: string; endDate: string }>({ startDate: '', endDate: '' });
28
+
29
+ const session = useSession();
30
+ const locationUuids = session?.sessionLocation?.uuid ?? '';
31
+ /* Only a register for the current location counts */
32
+ const { isForCurrentLocation, hasLocationChanged, markGenerated } = useGeneratedLocation('moh362Location');
33
+ const isGenerated = rows !== null && isForCurrentLocation;
34
+
35
+ const generate = async ({ startDate, endDate }: ReportPeriod) => {
36
+ setIsLoading(true);
37
+ setPeriod({ startDate, endDate });
38
+ try {
39
+ setRows(await getMoh362({ locationUuids, startDate, endDate }));
40
+ markGenerated(locationUuids);
41
+ } catch (error) {
42
+ showReportError('the MOH 362 register', error);
43
+ } finally {
44
+ setIsLoading(false);
45
+ }
46
+ };
47
+
48
+ useRestorePeriod(generate);
49
+
50
+ /* the open sheet is kept in the URL */
51
+ const [searchParams, setSearchParams] = useSearchParams();
52
+ const selectedSheet = searchParams.get('sheet') === 'linkage' ? 1 : 0;
53
+ const selectSheet = ({ selectedIndex }: { selectedIndex: number }) => {
54
+ const next = new URLSearchParams(searchParams);
55
+ if (selectedIndex === 1) {
56
+ next.set('sheet', 'linkage');
57
+ } else {
58
+ next.delete('sheet');
59
+ }
60
+ setSearchParams(next, { replace: true });
61
+ };
62
+
63
+ return (
64
+ <>
65
+ <ReportFiltersComponent
66
+ reportName="MOH 362 HTS Lab, Referral & Linkage Register"
67
+ mode="both"
68
+ onGenerate={generate}
69
+ isLoading={isLoading}
70
+ isReportGenerated={isGenerated}
71
+ generatedPeriod={period}
72
+ defaultTab="custom"
73
+ backLink={{ label: 'All registers', to: '/?tab=registers' }}
74
+ />
75
+ {isLoading && <ReportSkeleton />}
76
+ {!isLoading && !isGenerated && (
77
+ <ReportPlaceholder reportName="MOH 362 register" isLocationChanged={rows !== null && hasLocationChanged} />
78
+ )}
79
+ {!isLoading && isGenerated && (
80
+ <Tabs selectedIndex={selectedSheet} onChange={selectSheet}>
81
+ <TabList aria-label="MOH 362 registers" className={styles.sheetTabs}>
82
+ <Tab>HTS Lab Register</Tab>
83
+ <Tab>Referral and Linkage Register</Tab>
84
+ </TabList>
85
+ <TabPanels>
86
+ <TabPanel className={styles.sheetPanel}>
87
+ <Moh362LabRegister rows={rows} />
88
+ </TabPanel>
89
+ <TabPanel className={styles.sheetPanel}>
90
+ <Moh362LinkageRegister rows={rows.filter(isLinked)} />
91
+ </TabPanel>
92
+ </TabPanels>
93
+ </Tabs>
94
+ )}
95
+ </>
96
+ );
97
+ };
98
+
99
+ export default Moh362Register;
@@ -0,0 +1,11 @@
1
+ @use '@carbon/layout';
2
+
3
+ /* HTS Lab Register / Referral and Linkage Register tabs, under the filters */
4
+ .sheetTabs {
5
+ margin-top: layout.$spacing-05;
6
+ }
7
+
8
+ /* each sheet brings its own frame */
9
+ .sheetPanel {
10
+ padding: 0;
11
+ }
@@ -0,0 +1,97 @@
1
+ import dayjs from 'dayjs';
2
+
3
+ /**
4
+ * One test in the MOH 362 register, as the ETL returns it (/moh-362-register):
5
+ * the same tests as MOH 731 1.1 HIV Tests, with the register's details.
6
+ */
7
+ export interface Moh362Row {
8
+ serial_number?: number | string;
9
+ patient_id?: number;
10
+ nupi?: string | null;
11
+ amrsID?: string | null;
12
+ id_number?: string | null;
13
+ full_name?: string | null;
14
+ first_name?: string | null;
15
+ middle_name?: string | null;
16
+ last_name?: string | null;
17
+ age?: number | string | null;
18
+ sex?: string | null;
19
+ telephone?: string | null;
20
+ date_of_visit?: string | null;
21
+ hts_provider?: string | null;
22
+ marital_status?: number | string | null;
23
+ population_type?: number | string | null;
24
+ sub_population?: string | null;
25
+ setting?: number | string | null;
26
+ hiv_test1?: number | string | null;
27
+ kit1_name?: string | null;
28
+ lot1?: string | null;
29
+ expiry1?: string | null;
30
+ hiv_test2?: number | string | null;
31
+ kit2_name?: string | null;
32
+ lot2?: string | null;
33
+ expiry2?: string | null;
34
+ hiv_test3?: number | string | null;
35
+ kit3_name?: string | null;
36
+ lot3?: string | null;
37
+ expiry3?: string | null;
38
+ final_result?: string | null;
39
+ discordant_couple?: string | null;
40
+ referral_services?: number | string | null;
41
+ client_tested_as?: string | null;
42
+ referral_to?: string | null;
43
+ residence?: string | null;
44
+ handed_to?: string | null;
45
+ art_start_date?: string | null;
46
+ ccc_number?: string | null;
47
+ screening_remarks?: string | null;
48
+ initial_remarks?: string | null;
49
+ }
50
+
51
+ /** Blank rather than "null" / "undefined" in a cell */
52
+ export const text = (value: unknown) => (value === null || value === undefined ? '' : String(value));
53
+
54
+ /** DD/MM/YYYY, as the form asks */
55
+ export const formDate = (value: unknown) => (value ? dayjs(String(value)).format('DD/MM/YYYY') : '');
56
+
57
+ export const clientName = (row: Moh362Row) =>
58
+ row.full_name || [row.first_name, row.middle_name, row.last_name].filter(Boolean).join(' ');
59
+
60
+ /** Tested positive and linked to care: started on ART */
61
+ export const isLinked = (row: Moh362Row) => row.final_result === 'P' && Boolean(row.art_start_date);
62
+
63
+ /** An HIV test result (the concept the ETL returns) as the form's code: N, P, I */
64
+ export const testResult = (value: unknown) => {
65
+ switch (String(value ?? '')) {
66
+ case '664':
67
+ return 'N';
68
+ case '703':
69
+ return 'P';
70
+ case '1138':
71
+ return 'I';
72
+ default:
73
+ return text(value);
74
+ }
75
+ };
76
+
77
+ /** The final result as the form's code: N, P, Ic (inconclusive), NA */
78
+ export const finalResult = (value: unknown) => (String(value ?? '') === 'I' ? 'Ic' : text(value));
79
+
80
+ export const ageOf = (row: Moh362Row) => {
81
+ const age = Number(row.age);
82
+ return Number.isFinite(age) && row.age !== null && row.age !== '' ? age : null;
83
+ };
84
+
85
+ /** The form's age bands for the Tests (n) and Positive (n) summaries */
86
+ export const AGE_BANDS: Array<{ label: string; min: number; max?: number }> = [
87
+ { label: '1-9 yrs', min: 1, max: 9 },
88
+ { label: '10-14 yrs', min: 10, max: 14 },
89
+ { label: '15-19 yrs', min: 15, max: 19 },
90
+ { label: '20-24 yrs', min: 20, max: 24 },
91
+ { label: '25+ yrs', min: 25 },
92
+ ];
93
+
94
+ export const inBand = (row: Moh362Row, band: { min: number; max?: number }) => {
95
+ const age = ageOf(row);
96
+ return age !== null && age >= band.min && (band.max === undefined || age <= band.max);
97
+ };
@@ -0,0 +1,80 @@
1
+ import { Activity, Chemistry, Microscope } from '@carbon/react/icons';
2
+
3
+ import { type ReportCategory } from '../dashboard/report-catalog';
4
+
5
+ /**
6
+ * The registers listed on the landing page's Registers tab, grouped as the
7
+ * reports are. Each opens on its own route (root.component.tsx) with the same
8
+ * filter bar as the reports, opening on a custom range of today
9
+ * (`defaultTab="custom"`), where the reports open on last month.
10
+ */
11
+ export const registerCategories: ReportCategory[] = [
12
+ {
13
+ id: 'hiv-testing',
14
+ title: 'HIV testing services',
15
+ description: 'HTS daily registers',
16
+ tone: 'violet',
17
+ reports: [
18
+ {
19
+ code: 'MOH 362',
20
+ name: 'HTS lab, referral & linkage',
21
+ description: 'Clients tested for HIV, their test kits and results, and referral and linkage to care.',
22
+ path: '/moh-362',
23
+ icon: Microscope,
24
+ keywords: ['hts', 'hiv testing', 'lab', 'referral', 'linkage', 'kits'],
25
+ },
26
+ ],
27
+ },
28
+ {
29
+ id: 'diabetes-and-hypertension',
30
+ title: 'MOH-740',
31
+ description: 'Diabetes and Hypertension comprehensive care',
32
+ tone: 'violet',
33
+ reports: [
34
+ {
35
+ code: 'MOH 222',
36
+ name: 'Diabetes and Hypertension Comprehensive Care Daily Register',
37
+ description: 'Diabetes and Hypertension Comprehensive Care Daily Register',
38
+ path: '/moh-222',
39
+ icon: Activity,
40
+ keywords: ['cdm', 'ncd', 'diabetes', 'hypertetion'],
41
+ },
42
+ {
43
+ code: 'MOH 270',
44
+ name: 'Diabetes & Hypertension Comprehensive Care Permanent register',
45
+ description: 'Diabetes & Hypertension Comprehensive Care Permanent register',
46
+ path: '/moh-270',
47
+ icon: Activity,
48
+ keywords: ['cdm', 'ncd', 'diabetes', 'hypertetion'],
49
+ },
50
+ ],
51
+ },
52
+ {
53
+ id: 'laboratory',
54
+ title: 'Laboratory',
55
+ description: 'Laboratory specimen and testing registers',
56
+ tone: 'blue',
57
+ reports: [
58
+ {
59
+ code: 'MOH 240',
60
+ name: 'Laboratory (LAB) Register',
61
+ description:
62
+ 'Specimens collected and analysed by the laboratory: investigations, results, billing and referral.',
63
+ path: '/moh-240-register',
64
+ icon: Chemistry,
65
+ keywords: ['lab', 'laboratory', 'specimen', 'results', 'malaria', 'referral'],
66
+ },
67
+ {
68
+ code: 'TB LAB',
69
+ name: 'TB Laboratory Register',
70
+ description:
71
+ 'TB specimens tested: microscopy (AFB), TB-LAMP, LF-LAM and GeneXpert/Truenat results with turnaround.',
72
+ path: '/tb-lab-register',
73
+ icon: Chemistry,
74
+ keywords: ['tb', 'tuberculosis', 'afb', 'microscopy', 'sputum', 'genexpert', 'truenat', 'lamp', 'tat'],
75
+ },
76
+ ],
77
+ },
78
+ ];
79
+
80
+ export const totalRegisterCount = registerCategories.reduce((count, category) => count + category.reports.length, 0);
@@ -0,0 +1,116 @@
1
+ import React from 'react';
2
+
3
+ import { TB_LAB_COLUMNS, type TbLabColumn, type TbLabRow, text } from './tb-lab-register.columns';
4
+ import styles from './tb-lab-register-table.scss';
5
+
6
+ interface TbLabRegisterTableProps {
7
+ rows: TbLabRow[];
8
+ facility?: string;
9
+ startDate?: string;
10
+ endDate?: string;
11
+ }
12
+
13
+ interface HeaderCell {
14
+ /** A two-tier group spanning its member columns; undefined for a tall column */
15
+ group?: string;
16
+ /** The column's own label, repeated once per member under a group */
17
+ label: string;
18
+ /** Columns the header spans */
19
+ span: number;
20
+ /** 2 for a column that stands alone across both header rows */
21
+ height: number;
22
+ }
23
+
24
+ /**
25
+ * The printed template's two-tier header, rebuilt from the column spec:
26
+ * consecutive members of a group sit under one spanning group cell, standalone
27
+ * columns stand two rows tall.
28
+ */
29
+ export function headerCellsFor(columns: TbLabColumn[]): HeaderCell[][] {
30
+ const top: HeaderCell[] = [];
31
+ const bottom: HeaderCell[] = [];
32
+
33
+ columns.forEach((column, index) => {
34
+ if (!column.group) {
35
+ top.push({ group: undefined, label: column.header, span: 1, height: 2 });
36
+ return;
37
+ }
38
+ const previous = columns[index - 1];
39
+ if (previous?.group === column.group) {
40
+ top[top.length - 1].span += 1;
41
+ } else {
42
+ top.push({ group: column.group, label: column.group, span: 1, height: 1 });
43
+ }
44
+ bottom.push({ group: undefined, label: column.header, span: 1, height: 1 });
45
+ });
46
+
47
+ return [top, bottom];
48
+ }
49
+
50
+ /**
51
+ * The TB Laboratory Register as the printed template lays it out: one row per
52
+ * specimen tested, the two-tier header over the appearance and microscopy
53
+ * columns, drawn as a landscape sheet that scrolls sideways in its frame.
54
+ */
55
+ const TbLabRegisterTable: React.FC<TbLabRegisterTableProps> = ({ rows, facility = '', startDate, endDate }) => {
56
+ const [topRow, bottomRow] = headerCellsFor(TB_LAB_COLUMNS);
57
+ const period = [startDate, endDate]
58
+ .filter(Boolean)
59
+ .map((value) => asDay(value))
60
+ .join(' to ');
61
+
62
+ return (
63
+ <div className={styles.sheet}>
64
+ <div className={styles.runningHead}>
65
+ <span>Ministry of Health</span>
66
+ <span>TB LABORATORY REGISTER</span>
67
+ <span>{facility}</span>
68
+ </div>
69
+ {period && <div className={styles.period}>{period}</div>}
70
+
71
+ <div className={styles.tableScroll}>
72
+ <table className={styles.register}>
73
+ <thead>
74
+ <tr>
75
+ {topRow.map((cell, index) =>
76
+ cell.group ? (
77
+ <th key={index} colSpan={cell.span}>
78
+ {cell.label}
79
+ </th>
80
+ ) : (
81
+ <th key={index} rowSpan={2} className={styles.tall}>
82
+ {cell.label}
83
+ </th>
84
+ ),
85
+ )}
86
+ </tr>
87
+ <tr>
88
+ {bottomRow.map((cell, index) => (
89
+ <th key={index}>{cell.label}</th>
90
+ ))}
91
+ </tr>
92
+ </thead>
93
+ <tbody>
94
+ {rows.map((row, index) => (
95
+ <tr key={text(row.lab_no) || index}>
96
+ {TB_LAB_COLUMNS.map((column, cellIndex) => (
97
+ <td key={cellIndex} className={column.align === 'left' ? styles.left : undefined}>
98
+ {text(column.value(row, index))}
99
+ </td>
100
+ ))}
101
+ </tr>
102
+ ))}
103
+ </tbody>
104
+ </table>
105
+ </div>
106
+ </div>
107
+ );
108
+ };
109
+
110
+ /** Renders a filter-bar period (YYYY-MM-DD) the way the register reads it */
111
+ function asDay(value: string): string {
112
+ const parts = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
113
+ return parts ? `${parts[3]}/${parts[2]}/${parts[1]}` : value;
114
+ }
115
+
116
+ export default TbLabRegisterTable;