@ampath/esm-reports-app 1.0.0-next.62 → 1.0.0-next.64

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 (54) hide show
  1. package/dist/299.js +2 -0
  2. package/dist/299.js.LICENSE.txt +3 -0
  3. package/dist/299.js.map +1 -0
  4. package/dist/354.js +2 -0
  5. package/dist/354.js.LICENSE.txt +20 -0
  6. package/dist/354.js.map +1 -0
  7. package/dist/410.js +1 -1
  8. package/dist/410.js.map +1 -1
  9. package/dist/457.js +2 -0
  10. package/dist/457.js.LICENSE.txt +261 -0
  11. package/dist/457.js.map +1 -0
  12. package/dist/480.js +1 -0
  13. package/dist/781.js +1 -0
  14. package/dist/781.js.map +1 -0
  15. package/dist/907.js +1 -1
  16. package/dist/907.js.map +1 -1
  17. package/dist/953.css +1 -0
  18. package/dist/953.css.map +1 -0
  19. package/dist/953.js +1 -0
  20. package/dist/953.js.map +1 -0
  21. package/dist/99.js +1 -1
  22. package/dist/99.js.map +1 -0
  23. package/dist/ampath-esm-reports-app.js +1 -1
  24. package/dist/routes.json +1 -1
  25. package/package.json +3 -1
  26. package/src/common/linelist-table/linelist-table.component.tsx +1 -1
  27. package/src/common/report-filters/report-filters.component.tsx +25 -4
  28. package/src/common/report-filters/types.ts +13 -0
  29. package/src/common/report-page/download-sheet-pdf.ts +59 -0
  30. package/src/common/report-page/index.ts +1 -0
  31. package/src/dashboard/reports-dasboard.tsx +156 -69
  32. package/src/dashboard/reports-dashboard.module.scss +144 -59
  33. package/src/registers/moh-362/moh-362-lab-register.component.tsx +392 -0
  34. package/src/registers/moh-362/moh-362-linkage-register.component.tsx +120 -0
  35. package/src/registers/moh-362/moh-362-register.scss +222 -0
  36. package/src/registers/moh-362/moh-362.component.tsx +99 -0
  37. package/src/registers/moh-362/moh-362.scss +11 -0
  38. package/src/registers/moh-362/moh-362.types.ts +97 -0
  39. package/src/registers/register-catalog.ts +30 -0
  40. package/src/reports/moh-731/linelist/moh-731-indicators.ts +82 -0
  41. package/src/reports/moh-731/linelist/moh-731-linelist-sections.ts +51 -2
  42. package/src/reports/moh-731/moh-731.component.tsx +18 -3
  43. package/src/reports/moh-731/moh-731.scss +6 -0
  44. package/src/reports/moh-731/sections/hiv-and-tb-treatment.component.tsx +49 -52
  45. package/src/reports/moh-731/summary/moh-731-summary.config.ts +25 -16
  46. package/src/reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register.tsx +2 -0
  47. package/src/reports/moh-740/registers/moh-740.columns.ts +2 -0
  48. package/src/reports/moh-740/types/index.ts +1 -0
  49. package/src/resources/moh-362.resource.ts +27 -0
  50. package/src/root.component.tsx +2 -0
  51. package/dist/876.css +0 -1
  52. package/dist/876.css.map +0 -1
  53. package/dist/876.js +0 -1
  54. package/dist/876.js.map +0 -1
@@ -0,0 +1,120 @@
1
+ import React from 'react';
2
+
3
+ import { clientName, formDate, text, type Moh362Row } from './moh-362.types';
4
+ import styles from './moh-362-register.scss';
5
+
6
+ interface Moh362LinkageRegisterProps {
7
+ rows: Moh362Row[];
8
+ }
9
+
10
+ const COLUMN_IDS = 'abcdefghij'.split('');
11
+
12
+ /**
13
+ * REFERRAL AND LINKAGE REGISTER (Ver. July 2023), page 6 of the MOH 362 form:
14
+ * the clients who tested HIV positive and were linked to care (started on ART),
15
+ * columns (a) to (j), with the total linked at the foot.
16
+ */
17
+ const Moh362LinkageRegister: React.FC<Moh362LinkageRegisterProps> = ({ rows }) => {
18
+ const linked = rows.length;
19
+
20
+ return (
21
+ <div className={styles.sheet}>
22
+ <div className={styles.runningHead}>
23
+ <span>Ministry Of Health</span>
24
+ <span>MOH 362 HTS LAB, REFERRAL AND LINKAGE REGISTER</span>
25
+ <span>Ver. July 2023</span>
26
+ </div>
27
+ <h4 className={`${styles.sheetTitle} ${styles.serifTitle}`}>REFERRAL AND LINKAGE REGISTER</h4>
28
+
29
+ <div className={styles.tableScroll}>
30
+ <table className={styles.register}>
31
+ <thead>
32
+ <tr>
33
+ <th>
34
+ Serial
35
+ <br />
36
+ Number
37
+ </th>
38
+ <th className={styles.splitHeader}>
39
+ <span>National Identification Number</span>
40
+ <span>National Unique Patient Identifier (NUPI) Number</span>
41
+ </th>
42
+ <th className={styles.wide}>Client Names</th>
43
+ <th className={styles.splitHeader}>
44
+ <span>Telephone Number</span>
45
+ <span>Residence</span>
46
+ </th>
47
+ <th>
48
+ Identification
49
+ <br />
50
+ Strategy
51
+ <br />
52
+ (VCT/IT/HIVST
53
+ <br />
54
+ /SNS)
55
+ </th>
56
+ <th className={styles.wide}>Patient referred to</th>
57
+ <th className={styles.wide}>
58
+ Handed over to:
59
+ <br />
60
+ (Indicate Name (upper cell)
61
+ <br />
62
+ and Cadre (lower cell)
63
+ </th>
64
+ <th>
65
+ Date started on
66
+ <br />
67
+ ART
68
+ </th>
69
+ <th>CCC Number</th>
70
+ <th className={styles.wide}>Remarks</th>
71
+ </tr>
72
+ <tr className={styles.columnIds}>
73
+ {COLUMN_IDS.map((id) => (
74
+ <th key={id}>({id})</th>
75
+ ))}
76
+ </tr>
77
+ </thead>
78
+ <tbody>
79
+ {rows.map((row, index) => (
80
+ <React.Fragment key={`${row.patient_id}-${row.serial_number}-${index}`}>
81
+ <tr>
82
+ <td rowSpan={2}>{index + 1}</td>
83
+ <td className={styles.upperCell}>{text(row.id_number)}</td>
84
+ <td rowSpan={2} className={styles.left}>
85
+ {clientName(row)}
86
+ </td>
87
+ <td className={styles.upperCell}>{text(row.telephone)}</td>
88
+ <td rowSpan={2}>{text(row.client_tested_as)}</td>
89
+ <td rowSpan={2} className={styles.left}>
90
+ {text(row.referral_to)}
91
+ </td>
92
+ <td className={`${styles.upperCell} ${styles.left}`}>{text(row.handed_to)}</td>
93
+ <td rowSpan={2}>{formDate(row.art_start_date)}</td>
94
+ <td rowSpan={2}>{text(row.ccc_number)}</td>
95
+ <td rowSpan={2} className={styles.left}>
96
+ {text(row.screening_remarks)}
97
+ </td>
98
+ </tr>
99
+ <tr>
100
+ <td className={styles.lowerCell}>{text(row.nupi)}</td>
101
+ <td className={styles.lowerCell}>{text(row.residence)}</td>
102
+ {/* the receiving health worker's cadre is not recorded */}
103
+ <td className={styles.lowerCell} />
104
+ </tr>
105
+ </React.Fragment>
106
+ ))}
107
+ <tr className={styles.totalRow}>
108
+ <th colSpan={9} className={styles.left}>
109
+ Totals Clients Linked
110
+ </th>
111
+ <td>{linked}</td>
112
+ </tr>
113
+ </tbody>
114
+ </table>
115
+ </div>
116
+ </div>
117
+ );
118
+ };
119
+
120
+ export default Moh362LinkageRegister;
@@ -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,30 @@
1
+ import { 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
+
30
+ export const totalRegisterCount = registerCategories.reduce((count, category) => count + category.reports.length, 0);
@@ -421,6 +421,24 @@ export const MOH_731_INDICATORS: Record<string, Moh731Indicator> = {
421
421
  section: 'hivTests',
422
422
  showColumns: ['Delivery Date'],
423
423
  },
424
+ /* Not on the form: PNC tests with no delivery date (or one after the test),
425
+ which fit neither PNC box. The Summary lists them for data cleanup. */
426
+ 'PNC-NODD-I': {
427
+ indicator: 'initial_test_pnc_no_delivery_date',
428
+ gender: 'F',
429
+ label: 'Tested at PNC, no delivery date',
430
+ block: '2.1 Maternal HIV Testing',
431
+ section: 'hivTests',
432
+ showColumns: ['Delivery Date'],
433
+ },
434
+ 'PNC-NODD-R': {
435
+ indicator: 'retest_pnc_no_delivery_date',
436
+ gender: 'F',
437
+ label: 'Tested at PNC, no delivery date',
438
+ block: '2.1 Maternal HIV Testing',
439
+ section: 'hivTests',
440
+ showColumns: ['Delivery Date'],
441
+ },
424
442
 
425
443
  // 2.2 HIV Positive Results
426
444
  'HV02-10': {
@@ -850,6 +868,42 @@ export const MOH_731_INDICATORS: Record<string, Moh731Indicator> = {
850
868
  block: '3.5 Differentiated Service Delivery',
851
869
  section: 'tbDsd',
852
870
  },
871
+ /* Not on the form: HV03-034 split into clients recorded as not established
872
+ and clients with no stability recorded. The Summary lists them so that,
873
+ with Established, they add up to 3.2 Currently on ART. */
874
+ 'DSD-NE': {
875
+ indicator: 'not_established_recorded',
876
+ label: 'Not Established (recorded)',
877
+ block: '3.5 Differentiated Service Delivery',
878
+ section: 'tbDsd',
879
+ },
880
+ 'DSD-NC': {
881
+ indicator: 'dsd_not_categorized',
882
+ label: 'Not Categorized',
883
+ block: '3.5 Differentiated Service Delivery',
884
+ section: 'tbDsd',
885
+ },
886
+ /* Not on the form: the clients on ART (3.2) by their latest DSD model. The
887
+ form's Community and Facility (HV03-035/036) count anyone whose latest model
888
+ was recorded at the facility, on ART or not. */
889
+ 'DSD-CO': {
890
+ indicator: 'dsd_community_on_art',
891
+ label: 'Community (on ART)',
892
+ block: '3.5 Differentiated Service Delivery',
893
+ section: 'tbDsd',
894
+ },
895
+ 'DSD-FA': {
896
+ indicator: 'dsd_facility_on_art',
897
+ label: 'Facility (on ART)',
898
+ block: '3.5 Differentiated Service Delivery',
899
+ section: 'tbDsd',
900
+ },
901
+ 'DSD-MNC': {
902
+ indicator: 'dsd_model_not_categorized',
903
+ label: 'DSD Model Not Categorized',
904
+ block: '3.5 Differentiated Service Delivery',
905
+ section: 'tbDsd',
906
+ },
853
907
  'HV03-035': {
854
908
  indicator: 'community',
855
909
  label: 'Community',
@@ -894,6 +948,13 @@ export const MOH_731_INDICATORS: Record<string, Moh731Indicator> = {
894
948
  block: '3.6 Nutrition and HIV',
895
949
  section: 'nutrition',
896
950
  },
951
+ 'HV03-042': {
952
+ indicator: 'has_sam_preg_lact',
953
+ gender: 'F',
954
+ label: 'Pregnant & Lactating',
955
+ block: '3.6 Nutrition and HIV',
956
+ section: 'nutrition',
957
+ },
897
958
  'HV03-043': {
898
959
  indicator: 'has_smm_0_5_months',
899
960
  label: '0-5Months',
@@ -924,6 +985,13 @@ export const MOH_731_INDICATORS: Record<string, Moh731Indicator> = {
924
985
  block: '3.6 Nutrition and HIV',
925
986
  section: 'nutrition',
926
987
  },
988
+ 'HV03-048': {
989
+ indicator: 'has_smm_preg_lact',
990
+ gender: 'F',
991
+ label: 'Pregnant & Lactating',
992
+ block: '3.6 Nutrition and HIV',
993
+ section: 'nutrition',
994
+ },
927
995
  'HV03-049': {
928
996
  indicator: 'severe_acute_supp_0_5_months',
929
997
  label: '0-5Months',
@@ -954,6 +1022,13 @@ export const MOH_731_INDICATORS: Record<string, Moh731Indicator> = {
954
1022
  block: '3.6 Nutrition and HIV',
955
1023
  section: 'nutrition',
956
1024
  },
1025
+ 'HV03-054': {
1026
+ indicator: 'severe_acute_supp_preg_lact',
1027
+ gender: 'F',
1028
+ label: 'Pregnant & Lactating',
1029
+ block: '3.6 Nutrition and HIV',
1030
+ section: 'nutrition',
1031
+ },
957
1032
  'HV03-055': {
958
1033
  indicator: 'severe_moderate_supp_0_5_months',
959
1034
  label: '0-5Months',
@@ -984,6 +1059,13 @@ export const MOH_731_INDICATORS: Record<string, Moh731Indicator> = {
984
1059
  block: '3.6 Nutrition and HIV',
985
1060
  section: 'nutrition',
986
1061
  },
1062
+ 'HV03-060': {
1063
+ indicator: 'severe_moderate_supp_preg_lact',
1064
+ gender: 'F',
1065
+ label: 'Pregnant & Lactating',
1066
+ block: '3.6 Nutrition and HIV',
1067
+ section: 'nutrition',
1068
+ },
987
1069
 
988
1070
  // 3.7 HIV in TB Clinic
989
1071
  'HV03-061': { indicator: 'start_tb', label: 'TB cases_New', block: '3.7 HIV in TB Clinic', section: 'tb' },