@ampath/esm-reports-app 1.0.0-next.8 → 1.0.0-next.80
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.
- package/dist/0.css +1 -0
- package/dist/0.css.map +1 -0
- package/dist/0.js +1 -0
- package/dist/0.js.map +1 -0
- package/dist/197.js +1 -1
- package/dist/282.js +1 -1
- package/dist/282.js.map +1 -1
- package/dist/295.css +1 -0
- package/dist/295.css.map +1 -0
- package/dist/295.js +1 -0
- package/dist/295.js.map +1 -0
- package/dist/299.js +2 -0
- package/dist/299.js.LICENSE.txt +3 -0
- package/dist/299.js.map +1 -0
- package/dist/300.js +1 -1
- package/dist/311.js +1 -1
- package/dist/311.js.map +1 -1
- package/dist/335.js +1 -1
- package/dist/353.js +1 -1
- package/dist/353.js.map +1 -1
- package/dist/354.js +2 -0
- package/dist/354.js.LICENSE.txt +20 -0
- package/dist/354.js.map +1 -0
- package/dist/410.js +1 -0
- package/dist/410.js.map +1 -0
- package/dist/457.js +2 -0
- package/dist/457.js.LICENSE.txt +261 -0
- package/dist/457.js.map +1 -0
- package/dist/478.js +1 -1
- package/dist/478.js.map +1 -1
- package/dist/480.js +1 -0
- package/dist/540.js +1 -1
- package/dist/540.js.map +1 -1
- package/dist/55.js +1 -1
- package/dist/600.js +2 -0
- package/dist/600.js.LICENSE.txt +35 -0
- package/dist/600.js.map +1 -0
- package/dist/652.js +1 -1
- package/dist/757.js +1 -0
- package/dist/757.js.map +1 -0
- package/dist/781.js +1 -0
- package/dist/781.js.map +1 -0
- package/dist/961.js +1 -1
- package/dist/961.js.map +1 -1
- package/dist/99.js +1 -1
- package/dist/99.js.map +1 -0
- package/dist/ampath-esm-reports-app.js +1 -1
- package/dist/ampath-esm-reports-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +4 -2
- package/src/common/daily-summary-table.tsx +55 -0
- package/src/common/linelist-table/index.ts +3 -0
- package/src/common/linelist-table/linelist-columns.ts +48 -0
- package/src/common/linelist-table/linelist-table.component.tsx +442 -0
- package/src/common/linelist-table/linelist-table.scss +306 -0
- package/src/common/linelist-table/linelist-table.test.tsx +120 -0
- package/src/common/linelist-table/use-all-rows.ts +93 -0
- package/src/common/linelist-table/use-column-layout.ts +123 -0
- package/src/common/report-error/index.ts +1 -0
- package/src/common/report-error/show-report-error.ts +25 -0
- package/src/common/report-filters/date-range.ts +137 -0
- package/src/common/report-filters/index.ts +4 -0
- package/src/common/report-filters/report-filters.component.tsx +317 -99
- package/src/common/report-filters/report-filters.scss +264 -32
- package/src/common/report-filters/types.ts +79 -0
- package/src/common/report-filters/use-restore-period.ts +43 -0
- package/src/common/report-header/index.ts +1 -0
- package/src/common/report-header/use-location-details.ts +58 -0
- package/src/common/report-page/download-sheet-pdf.ts +225 -0
- package/src/common/report-page/index.ts +3 -0
- package/src/common/report-page/report-page.component.tsx +32 -0
- package/src/common/report-page/report-page.scss +45 -0
- package/src/common/report-page/use-page-scale.ts +60 -0
- package/src/common/report-placeholder/has-report-data.ts +15 -0
- package/src/common/report-placeholder/index.ts +3 -0
- package/src/common/report-placeholder/report-placeholder.component.tsx +81 -0
- package/src/common/report-placeholder/report-placeholder.scss +48 -0
- package/src/common/report-placeholder/use-generated-location.ts +62 -0
- package/src/common/report-register/index.ts +6 -0
- package/src/common/report-register/register-columns.ts +46 -0
- package/src/common/report-register/register-layout.component.tsx +265 -0
- package/src/common/report-register/register-layout.scss +150 -0
- package/src/common/report-register/register-table.scss +71 -0
- package/src/common/report-register/report-parents.ts +29 -0
- package/src/common/report-register/rows-to-csv.ts +89 -0
- package/src/common/report-register/use-location-name.ts +54 -0
- package/src/common/report-register/use-patient-list.ts +92 -0
- package/src/common/report-skeleton/index.ts +1 -0
- package/src/common/report-skeleton/report-skeleton.component.tsx +46 -0
- package/src/common/report-skeleton/report-skeleton.scss +29 -0
- package/src/config-schema.ts +9 -1
- package/src/dashboard/report-catalog.ts +191 -0
- package/src/dashboard/reports-dasboard.tsx +189 -18
- package/src/dashboard/reports-dashboard.module.scss +357 -14
- package/src/index.ts +13 -1
- package/src/registers/moh-240/moh-240-register.scss +41 -0
- package/src/registers/moh-240/moh-240.component.test.tsx +166 -0
- package/src/registers/moh-240/moh-240.component.tsx +164 -0
- package/src/registers/moh-267/moh-267-register.component.tsx +407 -0
- package/src/registers/moh-267/moh-267-register.scss +298 -0
- package/src/registers/moh-267/moh-267-summary.ts +102 -0
- package/src/registers/moh-267/moh-267.component.tsx +94 -0
- package/src/registers/moh-267/moh-267.types.ts +47 -0
- package/src/registers/moh-362/moh-362-lab-register.component.tsx +551 -0
- package/src/registers/moh-362/moh-362-lab-register.scss +412 -0
- package/src/registers/moh-362/moh-362-linkage-register.component.tsx +215 -0
- package/src/registers/moh-362/moh-362-linkage-register.scss +91 -0
- package/src/registers/moh-362/moh-362.component.tsx +117 -0
- package/src/registers/moh-362/moh-362.scss +11 -0
- package/src/registers/moh-362/moh-362.types.ts +87 -0
- package/src/registers/presumptive-tb/presumptive-tb-register.component.tsx +391 -0
- package/src/registers/presumptive-tb/presumptive-tb-register.scss +262 -0
- package/src/registers/presumptive-tb/presumptive-tb.component.tsx +92 -0
- package/src/registers/presumptive-tb/presumptive-tb.types.ts +88 -0
- package/src/registers/register-catalog.ts +202 -0
- package/src/registers/register-file-name.ts +18 -0
- package/src/registers/tb-lab-register/tb-lab-register-table.component.tsx +116 -0
- package/src/registers/tb-lab-register/tb-lab-register-table.scss +123 -0
- package/src/registers/tb-lab-register/tb-lab-register.columns.ts +164 -0
- package/src/registers/tb-lab-register/tb-lab-register.component.test.tsx +232 -0
- package/src/registers/tb-lab-register/tb-lab-register.component.tsx +153 -0
- package/src/registers/tb4/tb4-parts.tsx +164 -0
- package/src/registers/tb4/tb4-patient-sheet.component.tsx +418 -0
- package/src/registers/tb4/tb4-register.scss +282 -0
- package/src/registers/tb4/tb4-treatment-sheet.component.tsx +349 -0
- package/src/registers/tb4/tb4.component.tsx +120 -0
- package/src/registers/tb4/tb4.types.ts +129 -0
- package/src/reports/acf-summary/acf-summary-form.component.tsx +176 -0
- package/src/reports/acf-summary/acf-summary-linelist.component.tsx +86 -0
- package/src/reports/acf-summary/acf-summary.component.tsx +97 -0
- package/src/reports/acf-summary/acf-summary.counts.ts +37 -0
- package/src/reports/acf-summary/acf-summary.scss +162 -0
- package/src/reports/datatable-wrapper/datatable-wrapper.component.tsx +63 -48
- package/src/reports/moh-240/moh-240-header.component.tsx +62 -0
- package/src/reports/moh-240/moh-240.columns.ts +113 -0
- package/src/reports/moh-240/moh-240.component.tsx +72 -9
- package/src/reports/moh-240/moh-240.scss +40 -0
- package/src/reports/moh-240/sub-reports/moh-240-register.component.tsx +31 -37
- package/src/reports/moh-240/sub-reports/page-summary.component.tsx +143 -106
- package/src/reports/moh-505/moh-505-header.component.tsx +67 -0
- package/src/reports/moh-505/moh-505.component.tsx +441 -0
- package/src/reports/moh-505/moh-505.scss +117 -0
- package/src/reports/moh-705B/moh-204b-register.component.tsx +246 -0
- package/src/reports/moh-705B/moh-204b.columns.ts +39 -0
- package/src/reports/moh-705B/moh-705b.component.tsx +659 -0
- package/src/reports/moh-705B/moh-705b.scss +172 -0
- package/src/reports/moh-705a/moh-705a.component.tsx +661 -0
- package/src/reports/moh-705a/moh-705a.scss +172 -0
- package/src/reports/moh-705a/registers/moh-204a-register.component.tsx +331 -0
- package/src/reports/moh-705a/registers/moh-204a.columns.ts +57 -0
- package/src/reports/moh-705a/type.ts +6 -0
- package/src/reports/moh-706/moh-706-header.component.tsx +66 -0
- package/src/reports/moh-706/moh-706.component.tsx +150 -24
- package/src/reports/moh-706/moh-706.scss +119 -11
- package/src/reports/moh-706/sub-reports/bacteriology/bacteriology.component.tsx +35 -28
- package/src/reports/moh-706/sub-reports/blood-chemistry/blood-chemistry.component.tsx +229 -305
- package/src/reports/moh-706/sub-reports/haematology/haematology.component.tsx +26 -19
- package/src/reports/moh-706/sub-reports/histology-and-cytology/histology-and-cytology.component.tsx +23 -23
- package/src/reports/moh-706/sub-reports/parasitology/parasitology.component.tsx +25 -18
- package/src/reports/moh-706/sub-reports/serology/serology.component.tsx +21 -14
- package/src/reports/moh-706/sub-reports/specimen-referral-to-higher-levels/specimen-referral-to-higher-levels.component.tsx +2 -2
- package/src/reports/moh-706/sub-reports/urine-analysis/urine-analysis.component.tsx +27 -20
- package/src/reports/moh-710/moh-710.component.tsx +815 -632
- package/src/reports/moh-710/moh-710.scss +142 -21
- package/src/reports/moh-710/registers/moh-413/moh-413-columns.ts +22 -0
- package/src/reports/moh-710/registers/moh-413/moh-413.component.tsx +140 -0
- package/src/reports/moh-710/registers/moh-413/moh-413.scss +64 -0
- package/src/reports/moh-710/registers/moh-510/moh-510.columns.ts +40 -0
- package/src/reports/moh-710/registers/moh-510/moh-510.component.tsx +191 -0
- package/src/reports/moh-710/registers/moh-510/moh-510.scss +130 -0
- package/src/reports/moh-710/registers/moh-511-710-register.component.tsx +268 -0
- package/src/reports/moh-710/registers/moh-511-710.columns.ts +52 -0
- package/src/reports/moh-710/registers/type.ts +31 -0
- package/src/reports/moh-711/moh-711.component.tsx +153 -1269
- package/src/reports/moh-711/moh711.scss +135 -20
- package/src/reports/moh-711/registers/moh-333-register.component.tsx +680 -0
- package/src/reports/moh-711/registers/moh-333.columns.ts +119 -0
- package/src/reports/moh-711/registers/moh-405-register.component.tsx +566 -0
- package/src/reports/moh-711/registers/moh-405.columns.ts +120 -0
- package/src/reports/moh-711/registers/moh-406-register.component.tsx +581 -0
- package/src/reports/moh-711/registers/moh-406.columns.ts +133 -0
- package/src/reports/moh-711/registers/moh-407-register.component.tsx +157 -0
- package/src/reports/moh-711/registers/moh-407.columns.ts +24 -0
- package/src/reports/moh-711/registers/moh-407.scss +64 -0
- package/src/reports/moh-711/registers/moh-510-register.component.tsx +55 -0
- package/src/reports/moh-711/registers/moh-511-register.component.tsx +270 -0
- package/src/reports/moh-711/registers/moh-511.columns.ts +59 -0
- package/src/reports/moh-711/registers/moh-512-columns.ts +94 -0
- package/src/reports/moh-711/registers/moh-512.component.tsx +191 -0
- package/src/reports/moh-711/registers/moh-512.scss +64 -0
- package/src/reports/moh-711/registers/tb-register-columns.ts +17 -0
- package/src/reports/moh-711/registers/tb-register.component.tsx +96 -0
- package/src/reports/moh-711/registers/tb-register.scss +64 -0
- package/src/reports/moh-711/registers/type.ts +192 -0
- package/src/reports/moh-711/sections/anc.component.tsx +159 -0
- package/src/reports/moh-711/sections/cervical-cancer.component.tsx +148 -0
- package/src/reports/moh-711/sections/chanis.component.tsx +389 -0
- package/src/reports/moh-711/sections/family-planning.component.tsx +299 -0
- package/src/reports/moh-711/sections/gbv.component.tsx +115 -0
- package/src/reports/moh-711/sections/maternity.component.tsx +321 -0
- package/src/reports/moh-711/sections/medical-social-work.component.tsx +73 -0
- package/src/reports/moh-711/sections/other.component.tsx +47 -0
- package/src/reports/moh-711/sections/physiotherapy.component.tsx +61 -0
- package/src/reports/moh-711/sections/pnc.component.tsx +127 -0
- package/src/reports/moh-711/sections/post-abortion.component.tsx +42 -0
- package/src/reports/moh-711/sections/rehabilitation.component.tsx +57 -0
- package/src/reports/moh-711/sections/report-compiled-by.component.tsx +50 -0
- package/src/reports/moh-711/sections/tb-screening.component.tsx +94 -0
- package/src/reports/moh-717/moh-717.component.tsx +149 -985
- package/src/reports/moh-717/moh717.scss +217 -21
- package/src/reports/moh-717/registers/nutrition-register.component.tsx +48 -0
- package/src/reports/moh-717/sections/finance.component.tsx +42 -0
- package/src/reports/moh-717/sections/inpatient.component.tsx +374 -0
- package/src/reports/moh-717/sections/maternity.component.tsx +126 -0
- package/src/reports/moh-717/sections/medical-records.component.tsx +35 -0
- package/src/reports/moh-717/sections/mortuary.component.tsx +43 -0
- package/src/reports/moh-717/sections/operations.component.tsx +53 -0
- package/src/reports/moh-717/sections/orthopaedic-trauma.component.tsx +98 -0
- package/src/reports/moh-717/sections/outpatient.component.tsx +597 -0
- package/src/reports/moh-717/sections/pharmacy.component.tsx +43 -0
- package/src/reports/moh-717/sections/preparedby.component.tsx +52 -0
- package/src/reports/moh-717/sections/special-services.component.tsx +114 -0
- package/src/reports/moh-729b/moh-729b-form.component.tsx +385 -0
- package/src/reports/moh-729b/moh-729b-linelist.component.tsx +205 -0
- package/src/reports/moh-729b/moh-729b-summary.component.tsx +258 -0
- package/src/reports/moh-729b/moh-729b-summary.config.ts +229 -0
- package/src/reports/moh-729b/moh-729b.component.tsx +157 -0
- package/src/reports/moh-729b/moh-729b.config.ts +235 -0
- package/src/reports/moh-729b/moh-729b.scss +276 -0
- package/src/reports/moh-729b/moh-729b.types.ts +111 -0
- package/src/reports/moh-731/linelist/moh-731-indicators.ts +1122 -0
- package/src/reports/moh-731/linelist/moh-731-linelist-sections.ts +472 -0
- package/src/reports/moh-731/linelist/moh-731-linelist.component.tsx +102 -0
- package/src/reports/moh-731/linelist/use-open-moh-731-linelist.ts +50 -0
- package/src/reports/moh-731/moh-731.component.tsx +269 -0
- package/src/reports/moh-731/moh-731.scss +496 -0
- package/src/reports/moh-731/registers/moh-366.columns.ts +38 -0
- package/src/reports/moh-731/registers/moh-366.component.tsx +471 -0
- package/src/reports/moh-731/registers/prep-register.component.tsx +284 -0
- package/src/reports/moh-731/registers/prep.columns.ts +34 -0
- package/src/reports/moh-731/sections/hiv-and-tb-treatment.component.tsx +1206 -0
- package/src/reports/moh-731/sections/hiv-testing-and-pre-exposure.component.tsx +727 -0
- package/src/reports/moh-731/sections/pmtct.component.tsx +572 -0
- package/src/reports/moh-731/summary/moh-731-summary.component.tsx +313 -0
- package/src/reports/moh-731/summary/moh-731-summary.config.ts +527 -0
- package/src/reports/moh-731/summary/moh-731-summary.scss +247 -0
- package/src/reports/moh-740/moh-740.component.scss +202 -0
- package/src/reports/moh-740/moh-740.component.tsx +1332 -0
- package/src/reports/moh-740/moh-740.resource.ts +54 -0
- package/src/reports/moh-740/registers/moh-222-daily-register/moh-222-daily-register.tsx +149 -0
- package/src/reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register.tsx +123 -0
- package/src/reports/moh-740/registers/moh-740-patient-list.scss +0 -0
- package/src/reports/moh-740/registers/moh-740-patient-list.tsx +60 -0
- package/src/reports/moh-740/registers/moh-740.columns.ts +54 -0
- package/src/reports/moh-740/shared/data-cell/data-cell.scss +6 -0
- package/src/reports/moh-740/shared/data-cell/data-cell.tsx +23 -0
- package/src/reports/moh-740/shared/utils/indicator-register-map.ts +159 -0
- package/src/reports/moh-740/types/index.ts +223 -0
- package/src/reports/moh-745/moh-745.component.tsx +2058 -0
- package/src/reports/moh-745/moh-745.scss +142 -0
- package/src/reports/moh-745/registers/moh-412-register.component.tsx +249 -0
- package/src/reports/moh-745/registers/moh-412.columns.ts +52 -0
- package/src/reports/moh-745/registers/type.ts +223 -0
- package/src/reports/table-wrapper/table-row-mapper.component.tsx +20 -5
- package/src/reports/table-wrapper/table-wrapper.component.tsx +23 -14
- package/src/reports/table-wrapper/table-wrapper.scss +1 -16
- package/src/resources/moh-267.resource.ts +27 -0
- package/src/resources/moh-362.resource.ts +27 -0
- package/src/resources/moh-505.resource.ts +69 -0
- package/src/resources/moh-705.resource.ts +118 -0
- package/src/resources/moh-706.resource.ts +80 -0
- package/src/resources/moh-710.resource.ts +60 -9
- package/src/resources/moh-711.resource.ts +206 -9
- package/src/resources/moh-717.resource.ts +26 -9
- package/src/resources/moh-729b.resource.ts +25 -0
- package/src/resources/moh-731.resource.ts +90 -0
- package/src/resources/moh-745.resource.ts +76 -0
- package/src/resources/patient-list-page.ts +66 -0
- package/src/resources/presumptive-tb.resource.ts +27 -0
- package/src/root.component.tsx +79 -8
- package/src/root.scss +36 -0
- package/src/routes.json +3 -1
- package/src/utils/format-indicator.ts +39 -0
- package/src/utils/get-base-url.ts +39 -7
- package/src/utils/utils.ts +30 -1
- package/tsconfig.json +1 -1
- package/webpack.config.js +22 -1
- package/dist/138.js +0 -2
- package/dist/138.js.LICENSE.txt +0 -20
- package/dist/138.js.map +0 -1
- package/dist/184.js +0 -2
- package/dist/184.js.LICENSE.txt +0 -14
- package/dist/184.js.map +0 -1
- package/dist/205.js +0 -1
- package/dist/205.js.map +0 -1
- package/dist/812.js +0 -1
- package/dist/812.js.map +0 -1
- package/dist/879.js +0 -1
- package/dist/879.js.map +0 -1
- package/dist/ampath-esm-reports-app.js.buildmanifest.json +0 -539
- package/dist/main.js +0 -1
- package/dist/main.js.map +0 -1
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { usePageScale } from '../../common/report-page';
|
|
4
|
+
import { AGE_BANDS, clientName, formDate, inBand, text, type Moh362Row } from './moh-362.types';
|
|
5
|
+
import styles from './moh-362-lab-register.scss';
|
|
6
|
+
|
|
7
|
+
interface Moh362LabRegisterProps {
|
|
8
|
+
rows: Moh362Row[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Rows ruled on the last page, which also holds the summary, as on the paper form */
|
|
12
|
+
const ROWS_ON_LAST_PAGE = 15;
|
|
13
|
+
|
|
14
|
+
/** Rows on every page before it: the summary's space ruled as further rows */
|
|
15
|
+
const ROWS_PER_FULL_PAGE = 23;
|
|
16
|
+
|
|
17
|
+
/** A4 landscape less its 8mm margins: the page as drawn on screen, inside the report card */
|
|
18
|
+
const PAGE_WIDTH_MM = 297 - 2 * 8;
|
|
19
|
+
|
|
20
|
+
const COLUMN_IDS = 'abcdefghijklmnopqr'.split('');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Column widths, measured off page 5 of the form, as fractions of the sheet --
|
|
24
|
+
* except the three HIV tests, widened from the remarks and provider columns to
|
|
25
|
+
* fit each client's kit, lot and expiry under the result, the ID column, to fit
|
|
26
|
+
* a whole Client Registry ID, and the final result, to fit "Inconclusive".
|
|
27
|
+
*/
|
|
28
|
+
const COLUMN_WIDTHS = [72, 114, 104, 238, 52, 48, 138, 71, 95, 83, 111, 111, 101, 78, 76, 79, 133, 99];
|
|
29
|
+
const COLUMN_TOTAL = COLUMN_WIDTHS.reduce((sum, width) => sum + width, 0);
|
|
30
|
+
|
|
31
|
+
type TestField = 'hiv_test1' | 'hiv_test2' | 'hiv_test3';
|
|
32
|
+
|
|
33
|
+
const TESTS: Array<{
|
|
34
|
+
field: TestField;
|
|
35
|
+
label: string;
|
|
36
|
+
codes: string;
|
|
37
|
+
kit: keyof Moh362Row;
|
|
38
|
+
lot: keyof Moh362Row;
|
|
39
|
+
expiry: keyof Moh362Row;
|
|
40
|
+
}> = [
|
|
41
|
+
{ field: 'hiv_test1', label: 'HIV Test 1', codes: '(N,P,I)', kit: 'kit1_name', lot: 'lot1', expiry: 'expiry1' },
|
|
42
|
+
{ field: 'hiv_test2', label: 'HIV Test 2', codes: '(N,P,I,NA)', kit: 'kit2_name', lot: 'lot2', expiry: 'expiry2' },
|
|
43
|
+
{ field: 'hiv_test3', label: 'HIV Test 3', codes: '(N,P,I,NA)', kit: 'kit3_name', lot: 'lot3', expiry: 'expiry3' },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const count = (rows: Moh362Row[], test: (row: Moh362Row) => boolean) => rows.filter(test).length;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Full pages of rows, then a last page of at most 15 rows that carries the
|
|
50
|
+
* summary. A full page never takes every remaining row, so the last page always
|
|
51
|
+
* has at least one client on it.
|
|
52
|
+
*/
|
|
53
|
+
const paginate = (rows: Moh362Row[]) => {
|
|
54
|
+
const pages: Moh362Row[][] = [];
|
|
55
|
+
let start = 0;
|
|
56
|
+
while (rows.length - start > ROWS_ON_LAST_PAGE) {
|
|
57
|
+
const size = Math.min(ROWS_PER_FULL_PAGE, rows.length - start - 1);
|
|
58
|
+
pages.push(rows.slice(start, start + size));
|
|
59
|
+
start += size;
|
|
60
|
+
}
|
|
61
|
+
pages.push(rows.slice(start));
|
|
62
|
+
return pages;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* One HIV test's header cell, ruled as on the form: the test, then the kit
|
|
67
|
+
* name, lot number and expiry date lines, then its result codes. Each client's
|
|
68
|
+
* own kit, lot and expiry are written under their result.
|
|
69
|
+
*/
|
|
70
|
+
const TestHeader: React.FC<{ test: (typeof TESTS)[number] }> = ({ test }) => (
|
|
71
|
+
<th className={styles.testHeader}>
|
|
72
|
+
<div className={styles.headerStack}>
|
|
73
|
+
<span className={styles.testName}>{test.label}</span>
|
|
74
|
+
<span className={styles.kit}>Kit Name:</span>
|
|
75
|
+
<span>Lot No.</span>
|
|
76
|
+
<span>
|
|
77
|
+
Expiry Date
|
|
78
|
+
<em>___/___/___</em>
|
|
79
|
+
</span>
|
|
80
|
+
<span className={styles.codes}>{test.codes}</span>
|
|
81
|
+
</div>
|
|
82
|
+
</th>
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
/** One client's HIV test: the result in full, with the kit, lot and expiry used beneath it */
|
|
86
|
+
const TestCell: React.FC<{ row: Moh362Row; test: (typeof TESTS)[number] }> = ({ row, test }) => {
|
|
87
|
+
const detail = [text(row[test.kit]), text(row[test.lot]), formDate(row[test.expiry])].filter(Boolean).join(' · ');
|
|
88
|
+
return (
|
|
89
|
+
<td rowSpan={2} className={styles.testCell} title={detail || undefined}>
|
|
90
|
+
{/* a box of the row's own height, so wrapping never makes the row taller */}
|
|
91
|
+
<div className={styles.testBox}>
|
|
92
|
+
<strong>{text(row[test.field])}</strong>
|
|
93
|
+
{detail && <span className={styles.testDetail}>{detail}</span>}
|
|
94
|
+
</div>
|
|
95
|
+
</td>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/** A heading with a dotted entry line above its result codes (n, o) */
|
|
100
|
+
const CodedHeader: React.FC<{ label: React.ReactNode; codes: string }> = ({ label, codes }) => (
|
|
101
|
+
<th>
|
|
102
|
+
<div className={styles.codedStack}>
|
|
103
|
+
<span>{label}</span>
|
|
104
|
+
<span className={styles.codes}>{codes}</span>
|
|
105
|
+
</div>
|
|
106
|
+
</th>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
/** A heading holding two labels: upper cell above lower cell */
|
|
110
|
+
const SplitHeader: React.FC<{ upper: string; lower: string }> = ({ upper, lower }) => (
|
|
111
|
+
<th className={styles.splitHeader}>
|
|
112
|
+
<div className={styles.splitStack}>
|
|
113
|
+
<span>{upper}</span>
|
|
114
|
+
<span>{lower}</span>
|
|
115
|
+
</div>
|
|
116
|
+
</th>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
/** A Tests (n) / Positive (n) block: age bands by sex, with totals */
|
|
120
|
+
const AgeSexSummary: React.FC<{ title: string; rows: Moh362Row[] }> = ({ title, rows }) => {
|
|
121
|
+
const sexes = [
|
|
122
|
+
{ label: 'Male', code: 'M' },
|
|
123
|
+
{ label: 'Female', code: 'F' },
|
|
124
|
+
];
|
|
125
|
+
return (
|
|
126
|
+
<table className={styles.summaryTable}>
|
|
127
|
+
<thead>
|
|
128
|
+
<tr>
|
|
129
|
+
<th className={styles.titleCell}>{title}</th>
|
|
130
|
+
{AGE_BANDS.map((band) => (
|
|
131
|
+
<th key={band.label}>{band.label}</th>
|
|
132
|
+
))}
|
|
133
|
+
<th>Total</th>
|
|
134
|
+
</tr>
|
|
135
|
+
</thead>
|
|
136
|
+
<tbody>
|
|
137
|
+
{sexes.map((sex) => {
|
|
138
|
+
const ofSex = rows.filter((row) => row.sex === sex.code);
|
|
139
|
+
return (
|
|
140
|
+
<tr key={sex.code}>
|
|
141
|
+
<th className={styles.rowLabel}>{sex.label}</th>
|
|
142
|
+
{AGE_BANDS.map((band) => (
|
|
143
|
+
<td key={band.label}>{count(ofSex, (row) => inBand(row, band))}</td>
|
|
144
|
+
))}
|
|
145
|
+
<td>{ofSex.length}</td>
|
|
146
|
+
</tr>
|
|
147
|
+
);
|
|
148
|
+
})}
|
|
149
|
+
<tr>
|
|
150
|
+
<th className={styles.rowLabel}>Total</th>
|
|
151
|
+
{AGE_BANDS.map((band) => (
|
|
152
|
+
<td key={band.label}>{count(rows, (row) => inBand(row, band))}</td>
|
|
153
|
+
))}
|
|
154
|
+
<td>{rows.length}</td>
|
|
155
|
+
</tr>
|
|
156
|
+
</tbody>
|
|
157
|
+
</table>
|
|
158
|
+
);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/** A labelled single figure: Tests Facility (j), Discordant (o) ... */
|
|
162
|
+
const FigureRows: React.FC<{ figures: Array<[React.ReactNode, number]> }> = ({ figures }) => (
|
|
163
|
+
<table className={styles.summaryTable}>
|
|
164
|
+
<tbody>
|
|
165
|
+
{figures.map(([label, value], index) => (
|
|
166
|
+
<tr key={index}>
|
|
167
|
+
<th className={styles.figureLabel}>{label}</th>
|
|
168
|
+
<td className={styles.figure}>{value}</td>
|
|
169
|
+
</tr>
|
|
170
|
+
))}
|
|
171
|
+
</tbody>
|
|
172
|
+
</table>
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
/** A titled box holding one figure: Total Negative (n), Inconclusive test (n) */
|
|
176
|
+
const FigureBox: React.FC<{ title: string; value: number }> = ({ title, value }) => (
|
|
177
|
+
<table className={`${styles.summaryTable} ${styles.figureBox}`}>
|
|
178
|
+
<thead>
|
|
179
|
+
<tr>
|
|
180
|
+
<th>{title}</th>
|
|
181
|
+
</tr>
|
|
182
|
+
</thead>
|
|
183
|
+
<tbody>
|
|
184
|
+
<tr>
|
|
185
|
+
<td>{value}</td>
|
|
186
|
+
</tr>
|
|
187
|
+
</tbody>
|
|
188
|
+
</table>
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
/** The summary blocks at the foot of the last page, counting every client in the register */
|
|
192
|
+
const PageSummary: React.FC<{ rows: Moh362Row[] }> = ({ rows }) => {
|
|
193
|
+
const positives = rows.filter((row) => row.final_result === 'Positive');
|
|
194
|
+
const isKvp = (row: Moh362Row) => row.population_type === 'KVP';
|
|
195
|
+
const tests = TESTS.map((test, index) => {
|
|
196
|
+
const by = (result: string) => count(rows, (row) => row[test.field] === result);
|
|
197
|
+
const n = by('Negative');
|
|
198
|
+
const p = by('Positive');
|
|
199
|
+
const i = by('Inconclusive');
|
|
200
|
+
return { label: `${test.label} (${'klm'[index]})`, n, p, i, total: n + p + i };
|
|
201
|
+
});
|
|
202
|
+
const lines: Array<[string, 'n' | 'p' | 'i' | 'total' | null]> = [
|
|
203
|
+
['N: Negative', 'n'],
|
|
204
|
+
['P: Positive', 'p'],
|
|
205
|
+
['I: Invalid', 'i'],
|
|
206
|
+
['Wastage:', null],
|
|
207
|
+
['Total:', 'total'],
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<div className={styles.summary}>
|
|
212
|
+
<div className={styles.summaryColumn}>
|
|
213
|
+
<AgeSexSummary title="Tests (n )" rows={rows} />
|
|
214
|
+
<AgeSexSummary title="Positive (n)" rows={positives} />
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
<div className={styles.summaryColumn}>
|
|
218
|
+
<FigureBox title="Total Negative (n)" value={count(rows, (row) => row.final_result === 'Negative')} />
|
|
219
|
+
<FigureBox title="Inconclusive test (n)" value={count(rows, (row) => row.final_result === 'Inconclusive')} />
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
<div className={styles.summaryColumn}>
|
|
223
|
+
<FigureRows
|
|
224
|
+
figures={[
|
|
225
|
+
['Tests Facility (j)', count(rows, (row) => row.setting === 'Facility')],
|
|
226
|
+
['Tests Community (j)', count(rows, (row) => row.setting === 'Community')],
|
|
227
|
+
]}
|
|
228
|
+
/>
|
|
229
|
+
<FigureRows figures={[['Discordant (o)', count(rows, (row) => row.discordant_couple === 'Yes')]]} />
|
|
230
|
+
<FigureRows
|
|
231
|
+
figures={[
|
|
232
|
+
['Tests Key pops (i)', count(rows, isKvp)],
|
|
233
|
+
[
|
|
234
|
+
<>
|
|
235
|
+
Positive Key pops
|
|
236
|
+
<br />
|
|
237
|
+
(i) & (n)
|
|
238
|
+
</>,
|
|
239
|
+
count(positives, isKvp),
|
|
240
|
+
],
|
|
241
|
+
]}
|
|
242
|
+
/>
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<div className={styles.summaryColumn}>
|
|
246
|
+
<table className={styles.summaryTable}>
|
|
247
|
+
<thead>
|
|
248
|
+
<tr>
|
|
249
|
+
{tests.map((test) => (
|
|
250
|
+
<React.Fragment key={test.label}>
|
|
251
|
+
<th className={styles.titleCell}>{test.label}</th>
|
|
252
|
+
<th>Number</th>
|
|
253
|
+
</React.Fragment>
|
|
254
|
+
))}
|
|
255
|
+
</tr>
|
|
256
|
+
</thead>
|
|
257
|
+
<tbody>
|
|
258
|
+
{lines.map(([label, key]) => (
|
|
259
|
+
<tr key={label}>
|
|
260
|
+
{tests.map((test) => (
|
|
261
|
+
<React.Fragment key={test.label}>
|
|
262
|
+
<th className={styles.rowLabel}>{label}</th>
|
|
263
|
+
{/* wastage is counted on the kits, not recorded per client */}
|
|
264
|
+
<td>{key ? test[key] : ''}</td>
|
|
265
|
+
</React.Fragment>
|
|
266
|
+
))}
|
|
267
|
+
</tr>
|
|
268
|
+
))}
|
|
269
|
+
</tbody>
|
|
270
|
+
</table>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
);
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/** One client: two ruled lines, columns (b) and (i) split into upper and lower cells */
|
|
277
|
+
const ClientRows: React.FC<{ row?: Moh362Row; serial?: number }> = ({ row, serial }) => {
|
|
278
|
+
if (!row) {
|
|
279
|
+
return (
|
|
280
|
+
<>
|
|
281
|
+
<tr className={styles.upperLine}>
|
|
282
|
+
{COLUMN_IDS.map((id) => (
|
|
283
|
+
<td
|
|
284
|
+
key={id}
|
|
285
|
+
rowSpan={id === 'b' || id === 'i' ? 1 : 2}
|
|
286
|
+
className={id === 'b' || id === 'i' ? styles.upperCell : undefined}
|
|
287
|
+
/>
|
|
288
|
+
))}
|
|
289
|
+
</tr>
|
|
290
|
+
<tr className={styles.lowerLine}>
|
|
291
|
+
<td className={styles.lowerCell} />
|
|
292
|
+
<td className={styles.lowerCell} />
|
|
293
|
+
</tr>
|
|
294
|
+
</>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<>
|
|
300
|
+
<tr className={styles.upperLine}>
|
|
301
|
+
<td rowSpan={2}>{text(row.serial_number) || serial}</td>
|
|
302
|
+
<td className={`${styles.upperCell} ${styles.idCell}`}>{text(row.id_number)}</td>
|
|
303
|
+
<td rowSpan={2}>{formDate(row.date_of_visit)}</td>
|
|
304
|
+
<td rowSpan={2} className={styles.left}>
|
|
305
|
+
<span className={styles.clamp}>{clientName(row)}</span>
|
|
306
|
+
</td>
|
|
307
|
+
<td rowSpan={2}>{text(row.age)}</td>
|
|
308
|
+
<td rowSpan={2}>{text(row.sex)}</td>
|
|
309
|
+
<td rowSpan={2}>{text(row.telephone)}</td>
|
|
310
|
+
<td rowSpan={2}>{text(row.marital_status)}</td>
|
|
311
|
+
<td className={styles.upperCell}>{text(row.population_type)}</td>
|
|
312
|
+
<td rowSpan={2}>{text(row.setting)}</td>
|
|
313
|
+
{TESTS.map((test) => (
|
|
314
|
+
<TestCell key={test.field} row={row} test={test} />
|
|
315
|
+
))}
|
|
316
|
+
<td rowSpan={2} className={styles.finalResult}>
|
|
317
|
+
{text(row.final_result)}
|
|
318
|
+
</td>
|
|
319
|
+
<td rowSpan={2}>{text(row.discordant_couple)}</td>
|
|
320
|
+
<td rowSpan={2}>
|
|
321
|
+
<span className={styles.clamp}>{text(row.referral_services)}</span>
|
|
322
|
+
</td>
|
|
323
|
+
<td rowSpan={2} className={styles.left}>
|
|
324
|
+
<span className={styles.clamp}>{text(row.hts_provider)}</span>
|
|
325
|
+
</td>
|
|
326
|
+
<td rowSpan={2} className={styles.left}>
|
|
327
|
+
<span className={styles.clamp}>{text(row.initial_remarks)}</span>
|
|
328
|
+
</td>
|
|
329
|
+
</tr>
|
|
330
|
+
<tr className={styles.lowerLine}>
|
|
331
|
+
<td className={`${styles.lowerCell} ${styles.idCell}`}>{text(row.nupi)}</td>
|
|
332
|
+
<td className={styles.lowerCell}>{text(row.sub_population)}</td>
|
|
333
|
+
</tr>
|
|
334
|
+
</>
|
|
335
|
+
);
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* One A4 landscape page of the register. Pages before the last are ruled with
|
|
340
|
+
* client rows to the foot; the last has 15 rows with the summary of the whole
|
|
341
|
+
* register beneath them, in one frame.
|
|
342
|
+
*/
|
|
343
|
+
const LabRegisterPage: React.FC<{
|
|
344
|
+
rows: Moh362Row[];
|
|
345
|
+
firstSerial: number;
|
|
346
|
+
page: number;
|
|
347
|
+
pages: number;
|
|
348
|
+
scale: number;
|
|
349
|
+
/** every client in the register, given only to the last page */
|
|
350
|
+
summaryRows?: Moh362Row[];
|
|
351
|
+
}> = ({ rows, firstSerial, page, pages, scale, summaryRows }) => (
|
|
352
|
+
<section className={styles.page} data-register-page style={{ '--page-zoom': scale } as React.CSSProperties}>
|
|
353
|
+
<div className={styles.runningHead}>
|
|
354
|
+
<span>Ministry Of Health</span>
|
|
355
|
+
<span>MOH 362 HTS LAB, REFERRAL AND LINKAGE REGISTER</span>
|
|
356
|
+
<span>Ver. July 2023</span>
|
|
357
|
+
</div>
|
|
358
|
+
<h4 className={styles.title}>MOH 362: HTS LAB REGISTER</h4>
|
|
359
|
+
|
|
360
|
+
<div className={summaryRows ? `${styles.frame} ${styles.lastFrame}` : styles.frame}>
|
|
361
|
+
<table className={styles.register}>
|
|
362
|
+
<colgroup>
|
|
363
|
+
{COLUMN_WIDTHS.map((width, index) => (
|
|
364
|
+
<col key={index} style={{ width: `${(width / COLUMN_TOTAL) * 100}%` }} />
|
|
365
|
+
))}
|
|
366
|
+
</colgroup>
|
|
367
|
+
<thead>
|
|
368
|
+
<tr className={styles.headings}>
|
|
369
|
+
<th>
|
|
370
|
+
Serial
|
|
371
|
+
<br />
|
|
372
|
+
Number
|
|
373
|
+
</th>
|
|
374
|
+
<SplitHeader
|
|
375
|
+
upper="National Identification Number"
|
|
376
|
+
lower="National Unique Patient Identifier (NUPI) Number"
|
|
377
|
+
/>
|
|
378
|
+
<th>
|
|
379
|
+
Date of visit
|
|
380
|
+
<br />
|
|
381
|
+
(DD/MM/YYYY)
|
|
382
|
+
</th>
|
|
383
|
+
<th>
|
|
384
|
+
Client Name
|
|
385
|
+
<br />
|
|
386
|
+
(First, Middle, Last)
|
|
387
|
+
</th>
|
|
388
|
+
<th>Age</th>
|
|
389
|
+
<th>
|
|
390
|
+
Sex
|
|
391
|
+
<br />
|
|
392
|
+
(M/F)
|
|
393
|
+
</th>
|
|
394
|
+
<th>Telephone Number</th>
|
|
395
|
+
<th className={styles.codeList}>
|
|
396
|
+
Marital
|
|
397
|
+
<br />
|
|
398
|
+
Status
|
|
399
|
+
<br />
|
|
400
|
+
1=Married
|
|
401
|
+
<br />
|
|
402
|
+
2=Widowed
|
|
403
|
+
<br />
|
|
404
|
+
3=Single
|
|
405
|
+
<br />
|
|
406
|
+
4=Divorced
|
|
407
|
+
<br />
|
|
408
|
+
5=Separated
|
|
409
|
+
</th>
|
|
410
|
+
<th className={styles.codeList}>
|
|
411
|
+
Population Type
|
|
412
|
+
<br />
|
|
413
|
+
1. Gen Pop
|
|
414
|
+
<br />
|
|
415
|
+
2. Key and Vulnerable Pop.
|
|
416
|
+
<br />
|
|
417
|
+
<br />
|
|
418
|
+
Codes for KVP
|
|
419
|
+
<br />- DC
|
|
420
|
+
<br />- MSM/MSW
|
|
421
|
+
<br />- FSW
|
|
422
|
+
<br />- PWID/PWUD
|
|
423
|
+
<br />- VP
|
|
424
|
+
</th>
|
|
425
|
+
<th className={styles.codeList}>
|
|
426
|
+
Setting
|
|
427
|
+
<br />
|
|
428
|
+
(1=Facility
|
|
429
|
+
<br />
|
|
430
|
+
2=Community)
|
|
431
|
+
</th>
|
|
432
|
+
{TESTS.map((test) => (
|
|
433
|
+
<TestHeader key={test.field} test={test} />
|
|
434
|
+
))}
|
|
435
|
+
<CodedHeader
|
|
436
|
+
label={
|
|
437
|
+
<>
|
|
438
|
+
Final HIV
|
|
439
|
+
<br />
|
|
440
|
+
Result
|
|
441
|
+
</>
|
|
442
|
+
}
|
|
443
|
+
codes="(N,P,Ic,NA)"
|
|
444
|
+
/>
|
|
445
|
+
<CodedHeader
|
|
446
|
+
label={
|
|
447
|
+
<>
|
|
448
|
+
Discordant
|
|
449
|
+
<br />
|
|
450
|
+
Couple
|
|
451
|
+
</>
|
|
452
|
+
}
|
|
453
|
+
codes="(Y/N/NA)"
|
|
454
|
+
/>
|
|
455
|
+
<th>
|
|
456
|
+
<div className={styles.referralStack}>
|
|
457
|
+
<span>
|
|
458
|
+
Referred for
|
|
459
|
+
<br />
|
|
460
|
+
Prevention
|
|
461
|
+
<br />
|
|
462
|
+
Services
|
|
463
|
+
</span>
|
|
464
|
+
<span>
|
|
465
|
+
1. PrEP
|
|
466
|
+
<br />
|
|
467
|
+
2. PEP
|
|
468
|
+
<br />
|
|
469
|
+
3. VMMC
|
|
470
|
+
<br />
|
|
471
|
+
4. PMTCT
|
|
472
|
+
<br />
|
|
473
|
+
5.NA
|
|
474
|
+
</span>
|
|
475
|
+
</div>
|
|
476
|
+
</th>
|
|
477
|
+
<th>
|
|
478
|
+
HTS Provider
|
|
479
|
+
<br />
|
|
480
|
+
(Name)
|
|
481
|
+
</th>
|
|
482
|
+
<th>Remarks</th>
|
|
483
|
+
</tr>
|
|
484
|
+
<tr className={styles.columnIds}>
|
|
485
|
+
{COLUMN_IDS.map((id) => (
|
|
486
|
+
<th key={id}>({id})</th>
|
|
487
|
+
))}
|
|
488
|
+
</tr>
|
|
489
|
+
</thead>
|
|
490
|
+
<tbody>
|
|
491
|
+
{Array.from({ length: summaryRows ? ROWS_ON_LAST_PAGE : ROWS_PER_FULL_PAGE }, (_, index) => (
|
|
492
|
+
<ClientRows key={index} row={rows[index]} serial={firstSerial + index} />
|
|
493
|
+
))}
|
|
494
|
+
</tbody>
|
|
495
|
+
</table>
|
|
496
|
+
|
|
497
|
+
{summaryRows && (
|
|
498
|
+
<>
|
|
499
|
+
<PageSummary rows={summaryRows} />
|
|
500
|
+
|
|
501
|
+
<div className={styles.signOff}>
|
|
502
|
+
<span>
|
|
503
|
+
Supervisor's Name: <span className={styles.rule} />
|
|
504
|
+
</span>
|
|
505
|
+
<span>
|
|
506
|
+
Signature: <span className={styles.rule} />
|
|
507
|
+
</span>
|
|
508
|
+
</div>
|
|
509
|
+
</>
|
|
510
|
+
)}
|
|
511
|
+
</div>
|
|
512
|
+
|
|
513
|
+
<div className={styles.pageFoot}>
|
|
514
|
+
<span>
|
|
515
|
+
Page {page} of {pages}
|
|
516
|
+
</span>
|
|
517
|
+
<span>Ver. July 2023</span>
|
|
518
|
+
</div>
|
|
519
|
+
</section>
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* MOH 362: HTS LAB REGISTER (Ver. July 2023), page 5 of the MOH 362 form, as
|
|
524
|
+
* A4 landscape pages of clients, columns (a) to (r). The summary blocks sum
|
|
525
|
+
* the whole register, so they appear once, at the foot of the last page.
|
|
526
|
+
*/
|
|
527
|
+
const Moh362LabRegister: React.FC<Moh362LabRegisterProps> = ({ rows }) => {
|
|
528
|
+
const { ref, scale } = usePageScale<HTMLDivElement>(PAGE_WIDTH_MM);
|
|
529
|
+
const pages = paginate(rows);
|
|
530
|
+
const serials = pages.map((_, index) => pages.slice(0, index).reduce((sum, page) => sum + page.length, 0) + 1);
|
|
531
|
+
|
|
532
|
+
return (
|
|
533
|
+
<div className={styles.reportFrame}>
|
|
534
|
+
<div className={styles.viewport} ref={ref}>
|
|
535
|
+
{pages.map((pageRows, index) => (
|
|
536
|
+
<LabRegisterPage
|
|
537
|
+
key={index}
|
|
538
|
+
rows={pageRows}
|
|
539
|
+
firstSerial={serials[index]}
|
|
540
|
+
page={index + 1}
|
|
541
|
+
pages={pages.length}
|
|
542
|
+
scale={scale}
|
|
543
|
+
summaryRows={index === pages.length - 1 ? rows : undefined}
|
|
544
|
+
/>
|
|
545
|
+
))}
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
);
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
export default Moh362LabRegister;
|