@ampath/esm-reports-app 1.0.0-next.41 → 1.0.0-next.45
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/143.css +1 -0
- package/dist/143.css.map +1 -0
- package/dist/143.js +1 -0
- package/dist/143.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/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/410.js +1 -0
- package/dist/410.js.map +1 -0
- package/dist/427.js +2 -0
- package/dist/427.js.LICENSE.txt +35 -0
- package/dist/427.js.map +1 -0
- package/dist/441.js +1 -0
- package/dist/441.js.map +1 -0
- package/dist/478.js +1 -1
- package/dist/478.js.map +1 -1
- package/dist/540.js +1 -1
- package/dist/540.js.map +1 -1
- package/dist/55.js +1 -1
- package/dist/652.js +1 -1
- package/dist/961.js +1 -1
- package/dist/961.js.map +1 -1
- package/dist/99.js +1 -1
- 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 +2 -2
- 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 +281 -151
- package/src/common/report-filters/report-filters.scss +180 -55
- package/src/common/report-filters/types.ts +66 -0
- package/src/common/report-filters/use-restore-period.ts +43 -0
- package/src/common/report-page/index.ts +2 -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 +50 -0
- package/src/common/report-placeholder/has-report-data.ts +15 -0
- package/src/common/report-placeholder/index.ts +2 -0
- package/src/common/report-placeholder/report-placeholder.component.tsx +56 -0
- package/src/common/report-placeholder/report-placeholder.scss +46 -0
- package/src/common/report-register/index.ts +5 -0
- package/src/common/report-register/register-columns.ts +34 -0
- package/src/common/report-register/register-layout.component.tsx +237 -0
- package/src/common/report-register/register-layout.scss +140 -0
- package/src/common/report-register/register-table.scss +62 -0
- package/src/common/report-register/report-parents.ts +27 -0
- package/src/common/report-register/rows-to-csv.ts +59 -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 +173 -0
- package/src/dashboard/reports-dasboard.tsx +101 -35
- package/src/dashboard/reports-dashboard.module.scss +269 -11
- package/src/index.ts +13 -1
- package/src/reports/datatable-wrapper/datatable-wrapper.component.tsx +50 -48
- package/src/reports/moh-240/moh-240-header.component.tsx +54 -56
- package/src/reports/moh-240/moh-240.columns.ts +64 -0
- package/src/reports/moh-240/moh-240.component.tsx +65 -84
- package/src/reports/moh-240/moh-240.scss +36 -7
- package/src/reports/moh-240/sub-reports/moh-240-register.component.tsx +27 -65
- package/src/reports/moh-240/sub-reports/page-summary.component.tsx +2 -2
- package/src/reports/moh-505/moh-505-header.component.tsx +59 -57
- package/src/reports/moh-505/moh-505.component.tsx +51 -56
- package/src/reports/moh-505/moh-505.scss +116 -2
- package/src/reports/moh-705B/moh-204b-register.component.tsx +41 -42
- package/src/reports/moh-705B/moh-204b.columns.ts +39 -0
- package/src/reports/moh-705B/moh-705b.component.tsx +492 -473
- package/src/reports/moh-705B/moh-705b.scss +110 -24
- package/src/reports/moh-705a/moh-705a.component.tsx +496 -476
- package/src/reports/moh-705a/moh-705a.scss +109 -24
- package/src/reports/moh-705a/registers/moh-204a-register.component.tsx +41 -42
- package/src/reports/moh-705a/registers/moh-204a.columns.ts +57 -0
- package/src/reports/moh-706/moh-706-header.component.tsx +58 -56
- package/src/reports/moh-706/moh-706.component.tsx +84 -55
- package/src/reports/moh-706/moh-706.scss +115 -19
- package/src/reports/moh-710/moh-710.component.tsx +743 -727
- package/src/reports/moh-710/moh-710.scss +140 -23
- package/src/reports/moh-710/registers/moh-511-710-register.component.tsx +48 -43
- package/src/reports/moh-710/registers/moh-511-710.columns.ts +52 -0
- package/src/reports/moh-711/moh-711.component.tsx +94 -106
- package/src/reports/moh-711/moh711.scss +95 -64
- package/src/reports/moh-711/registers/moh-333-register.component.tsx +92 -94
- package/src/reports/moh-711/registers/moh-333.columns.ts +119 -0
- package/src/reports/moh-711/registers/moh-405-register.component.tsx +88 -89
- package/src/reports/moh-711/registers/moh-405.columns.ts +120 -0
- package/src/reports/moh-711/registers/moh-406-register.component.tsx +85 -88
- package/src/reports/moh-711/registers/moh-406.columns.ts +133 -0
- package/src/reports/moh-711/registers/moh-510-register.component.tsx +38 -44
- package/src/reports/moh-711/registers/moh-511-register.component.tsx +42 -43
- package/src/reports/moh-711/registers/moh-511.columns.ts +59 -0
- package/src/reports/moh-711/sections/anc.component.tsx +3 -3
- package/src/reports/moh-711/sections/cervical-cancer.component.tsx +3 -3
- package/src/reports/moh-711/sections/chanis.component.tsx +2 -3
- package/src/reports/moh-711/sections/family-planning.component.tsx +2 -2
- package/src/reports/moh-711/sections/gbv.component.tsx +2 -2
- package/src/reports/moh-711/sections/maternity.component.tsx +3 -8
- package/src/reports/moh-711/sections/medical-social-work.component.tsx +2 -12
- package/src/reports/moh-711/sections/other.component.tsx +2 -2
- package/src/reports/moh-711/sections/physiotherapy.component.tsx +2 -2
- package/src/reports/moh-711/sections/pnc.component.tsx +7 -5
- package/src/reports/moh-711/sections/post-abortion.component.tsx +2 -2
- package/src/reports/moh-711/sections/rehabilitation.component.tsx +2 -2
- package/src/reports/moh-711/sections/report-compiled-by.component.tsx +12 -4
- package/src/reports/moh-711/sections/tb-screening.component.tsx +2 -2
- package/src/reports/moh-717/moh-717.component.tsx +100 -121
- package/src/reports/moh-717/moh717.scss +163 -102
- package/src/reports/moh-717/sections/maternity.component.tsx +1 -1
- package/src/reports/moh-717/sections/orthopaedic-trauma.component.tsx +1 -1
- package/src/reports/moh-717/sections/outpatient.component.tsx +23 -23
- package/src/reports/moh-717/sections/preparedby.component.tsx +7 -2
- package/src/reports/moh-717/sections/special-services.component.tsx +1 -1
- package/src/reports/moh-731/moh-731.component.tsx +127 -110
- package/src/reports/moh-731/moh-731.scss +396 -68
- package/src/reports/moh-731/registers/moh-366.columns.ts +38 -0
- package/src/reports/moh-731/registers/moh-366.component.tsx +76 -83
- package/src/reports/moh-731/registers/prep-register.component.tsx +70 -78
- package/src/reports/moh-731/registers/prep.columns.ts +34 -0
- package/src/reports/moh-731/sections/hiv-and-tb-treatment.component.tsx +1031 -751
- package/src/reports/moh-731/sections/hiv-testing-and-pre-exposure.component.tsx +230 -86
- package/src/reports/moh-731/sections/pmtct.component.tsx +185 -64
- package/src/reports/moh-740/moh-740.component.scss +159 -79
- package/src/reports/moh-740/moh-740.component.tsx +261 -230
- package/src/reports/moh-740/moh-740.resource.ts +17 -10
- package/src/reports/moh-740/registers/moh-222-daily-register/moh-222-daily-register.tsx +77 -96
- package/src/reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register.tsx +50 -70
- package/src/reports/moh-740/registers/moh-740-patient-list.tsx +61 -32
- package/src/reports/moh-740/registers/moh-740.columns.ts +52 -0
- package/src/reports/moh-740/shared/utils/indicator-register-map.ts +3 -3
- package/src/reports/moh-740/types/index.ts +3 -3
- package/src/reports/moh-745/moh-745.component.tsx +897 -877
- package/src/reports/moh-745/moh-745.scss +104 -46
- package/src/reports/moh-745/registers/moh-412-register.component.tsx +42 -43
- package/src/reports/moh-745/registers/moh-412.columns.ts +52 -0
- 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-505.resource.ts +18 -35
- package/src/resources/moh-705.resource.ts +28 -39
- package/src/resources/moh-706.resource.ts +17 -30
- package/src/resources/moh-710.resource.ts +7 -17
- package/src/resources/moh-711.resource.ts +46 -64
- package/src/resources/moh-717.resource.ts +7 -17
- package/src/resources/moh-731.resource.ts +26 -32
- package/src/resources/moh-745.resource.ts +18 -20
- package/src/resources/patient-list-page.ts +66 -0
- package/src/root.component.tsx +28 -26
- package/src/root.scss +36 -0
- package/src/utils/get-base-url.ts +39 -7
- package/tsconfig.json +1 -1
- package/dist/110.js +0 -1
- package/dist/110.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/822.js +0 -2
- package/dist/822.js.LICENSE.txt +0 -20
- package/dist/822.js.map +0 -1
- package/dist/ampath-esm-reports-app.js.buildmanifest.json +0 -560
- package/dist/main.js +0 -1
- package/dist/main.js.map +0 -1
- package/src/reports/moh-731/registers/moh-366.scss +0 -45
- package/src/reports/moh-731/registers/prep-registers.scss +0 -45
- package/src/reports/moh-740/registers/moh-222-daily-register/moh-222-daily-register.scss +0 -18
- package/src/reports/moh-740/registers/moh-270-permanent-register/moh-270-permanent-register.scss +0 -18
- /package/src/{reports/moh-740/shared/utils → utils}/format-indicator.ts +0 -0
package/src/config-schema.ts
CHANGED
|
@@ -3,10 +3,18 @@ export const configSchema = {
|
|
|
3
3
|
etlBaseUrl: {
|
|
4
4
|
_type: Type.String,
|
|
5
5
|
_default: '',
|
|
6
|
-
_description: 'ETL
|
|
6
|
+
_description: 'Base URL of the ETL service every report reads from, e.g. "/etl"',
|
|
7
|
+
},
|
|
8
|
+
/* Declared because the deployment sets it in this section. Nothing reads it
|
|
9
|
+
yet; without it the config validator reports it as an unknown key. */
|
|
10
|
+
subDomainUrl: {
|
|
11
|
+
_type: Type.String,
|
|
12
|
+
_default: '',
|
|
13
|
+
_description: 'Origin this instance is served from',
|
|
7
14
|
},
|
|
8
15
|
};
|
|
9
16
|
|
|
10
17
|
export type Config = {
|
|
11
18
|
etlBaseUrl: string;
|
|
19
|
+
subDomainUrl: string;
|
|
12
20
|
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Activity,
|
|
3
|
+
ChartColumn,
|
|
4
|
+
Document,
|
|
5
|
+
DocumentTasks,
|
|
6
|
+
GenderFemale,
|
|
7
|
+
Growth,
|
|
8
|
+
HealthCross,
|
|
9
|
+
Microscope,
|
|
10
|
+
UserMultiple,
|
|
11
|
+
Warning,
|
|
12
|
+
type CarbonIconType,
|
|
13
|
+
} from '@carbon/react/icons';
|
|
14
|
+
|
|
15
|
+
export type ReportTone = 'violet' | 'magenta' | 'teal' | 'blue';
|
|
16
|
+
|
|
17
|
+
export interface ReportDefinition {
|
|
18
|
+
/** The MOH form number, e.g. `MOH 731` */
|
|
19
|
+
code: string;
|
|
20
|
+
/** Human readable name of the form */
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
/** Route registered in root.component.tsx */
|
|
24
|
+
path: string;
|
|
25
|
+
icon: CarbonIconType;
|
|
26
|
+
/** Extra terms matched by the search field */
|
|
27
|
+
keywords: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ReportCategory {
|
|
31
|
+
id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
description: string;
|
|
34
|
+
tone: ReportTone;
|
|
35
|
+
reports: ReportDefinition[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const reportCategories: ReportCategory[] = [
|
|
39
|
+
{
|
|
40
|
+
id: 'hiv-and-chronic-care',
|
|
41
|
+
title: 'HIV & chronic care',
|
|
42
|
+
description: 'Comprehensive care programme summaries',
|
|
43
|
+
tone: 'violet',
|
|
44
|
+
reports: [
|
|
45
|
+
{
|
|
46
|
+
code: 'MOH 731',
|
|
47
|
+
name: 'Comprehensive HIV/AIDS',
|
|
48
|
+
description: 'NASCOP monthly summary for HIV testing, EMTCT, care and treatment.',
|
|
49
|
+
path: '/moh-731',
|
|
50
|
+
icon: HealthCross,
|
|
51
|
+
keywords: ['hiv', 'nascop', 'art', 'prep', 'emtct', 'pmtct', 'tb'],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
code: 'MOH 740',
|
|
55
|
+
name: 'Diabetes & hypertension',
|
|
56
|
+
description: 'Monthly summary for the NCD comprehensive care clinic.',
|
|
57
|
+
path: '/moh-740',
|
|
58
|
+
icon: Activity,
|
|
59
|
+
keywords: ['ncd', 'diabetes', 'hypertension', 'chronic'],
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'reproductive-and-child-health',
|
|
65
|
+
title: 'Reproductive & child health',
|
|
66
|
+
description: 'RMNCAH service delivery summaries',
|
|
67
|
+
tone: 'magenta',
|
|
68
|
+
reports: [
|
|
69
|
+
{
|
|
70
|
+
code: 'MOH 710',
|
|
71
|
+
name: 'Immunization',
|
|
72
|
+
description: 'Child immunization and vitamin A supplementation summary.',
|
|
73
|
+
path: '/moh-710',
|
|
74
|
+
icon: Growth,
|
|
75
|
+
keywords: ['immunization', 'vaccine', 'child', 'khis', 'bcg', 'polio'],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
code: 'MOH 711',
|
|
79
|
+
name: 'Integrated programme summary',
|
|
80
|
+
description: 'Reproductive and child health, medical and rehabilitation services.',
|
|
81
|
+
path: '/moh-711',
|
|
82
|
+
icon: UserMultiple,
|
|
83
|
+
keywords: ['rmncah', 'anc', 'pnc', 'maternity', 'family planning', 'gbv', 'physiotherapy'],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
code: 'MOH 745',
|
|
87
|
+
name: 'Cancer screening',
|
|
88
|
+
description: 'Monthly cervical and breast cancer screening summary.',
|
|
89
|
+
path: '/moh-745',
|
|
90
|
+
icon: GenderFemale,
|
|
91
|
+
keywords: ['cancer', 'cervical', 'screening', 'via', 'hpv'],
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'outpatient-and-workload',
|
|
97
|
+
title: 'Outpatient & workload',
|
|
98
|
+
description: 'Morbidity and facility workload returns',
|
|
99
|
+
tone: 'teal',
|
|
100
|
+
reports: [
|
|
101
|
+
{
|
|
102
|
+
code: 'MOH 705A',
|
|
103
|
+
name: 'Outpatient morbidity, under 5',
|
|
104
|
+
description: 'Summary of diagnoses for children under five years.',
|
|
105
|
+
path: '/moh-705a',
|
|
106
|
+
icon: DocumentTasks,
|
|
107
|
+
keywords: ['morbidity', 'outpatient', 'under five', 'children', 'khis'],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
code: 'MOH 705B',
|
|
111
|
+
name: 'Outpatient morbidity, over 5',
|
|
112
|
+
description: 'Summary of diagnoses for clients aged five years and above.',
|
|
113
|
+
path: '/moh-705b',
|
|
114
|
+
icon: Document,
|
|
115
|
+
keywords: ['morbidity', 'outpatient', 'above five', 'adults', 'khis'],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
code: 'MOH 717',
|
|
119
|
+
name: 'Service workload',
|
|
120
|
+
description: 'Monthly service workload across facility departments.',
|
|
121
|
+
path: '/moh-717',
|
|
122
|
+
icon: ChartColumn,
|
|
123
|
+
keywords: ['workload', 'inpatient', 'pharmacy', 'mortuary', 'theatre', 'maternity'],
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: 'diagnostics-and-surveillance',
|
|
129
|
+
title: 'Diagnostics & surveillance',
|
|
130
|
+
description: 'Laboratory and disease surveillance returns',
|
|
131
|
+
tone: 'blue',
|
|
132
|
+
reports: [
|
|
133
|
+
{
|
|
134
|
+
code: 'MOH 706',
|
|
135
|
+
name: 'Laboratory services',
|
|
136
|
+
description: 'Monthly summary of laboratory investigations and results.',
|
|
137
|
+
path: '/moh-706',
|
|
138
|
+
icon: Microscope,
|
|
139
|
+
keywords: ['laboratory', 'lab', 'urine', 'parasitology', 'blood chemistry'],
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
code: 'MOH 505',
|
|
143
|
+
name: 'IDSR epidemic monitoring',
|
|
144
|
+
description: 'Weekly monitoring form for priority notifiable diseases.',
|
|
145
|
+
path: '/moh-505',
|
|
146
|
+
icon: Warning,
|
|
147
|
+
keywords: ['idsr', 'surveillance', 'epidemic', 'notifiable', 'outbreak'],
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
export const totalReportCount = reportCategories.reduce((count, category) => count + category.reports.length, 0);
|
|
154
|
+
|
|
155
|
+
export function filterCategories(categories: ReportCategory[], searchTerm: string): ReportCategory[] {
|
|
156
|
+
const term = searchTerm.trim().toLowerCase();
|
|
157
|
+
|
|
158
|
+
if (!term) {
|
|
159
|
+
return categories;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return categories
|
|
163
|
+
.map((category) => ({
|
|
164
|
+
...category,
|
|
165
|
+
reports: category.reports.filter((report) =>
|
|
166
|
+
[report.code, report.name, report.description, category.title, ...report.keywords]
|
|
167
|
+
.join(' ')
|
|
168
|
+
.toLowerCase()
|
|
169
|
+
.includes(term),
|
|
170
|
+
),
|
|
171
|
+
}))
|
|
172
|
+
.filter((category) => category.reports.length > 0);
|
|
173
|
+
}
|
|
@@ -1,46 +1,112 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
2
|
import { useNavigate } from 'react-router-dom';
|
|
3
|
-
import { ClickableTile } from '@carbon/react';
|
|
3
|
+
import { Button, ClickableTile, Layer, Search, Tag } from '@carbon/react';
|
|
4
|
+
import { ArrowRight, Calendar, Location, Report } from '@carbon/react/icons';
|
|
5
|
+
import { formatDate, useSession } from '@openmrs/esm-framework';
|
|
4
6
|
|
|
7
|
+
import { filterCategories, reportCategories, totalReportCount, type ReportDefinition } from './report-catalog';
|
|
5
8
|
import styles from './reports-dashboard.module.scss';
|
|
9
|
+
|
|
6
10
|
interface ReportsDashboardProps {}
|
|
11
|
+
|
|
7
12
|
const ReportsDashboard: React.FC<ReportsDashboardProps> = () => {
|
|
8
13
|
const navigate = useNavigate();
|
|
14
|
+
const session = useSession();
|
|
15
|
+
const [searchTerm, setSearchTerm] = useState<string>('');
|
|
16
|
+
|
|
17
|
+
const facilityName = session?.sessionLocation?.display;
|
|
18
|
+
const today = formatDate(new Date(), { mode: 'standard', time: false, noToday: true });
|
|
19
|
+
|
|
20
|
+
const visibleCategories = useMemo(() => filterCategories(reportCategories, searchTerm), [searchTerm]);
|
|
21
|
+
const matchCount = visibleCategories.reduce((count, category) => count + category.reports.length, 0);
|
|
22
|
+
const isSearching = searchTerm.trim().length > 0;
|
|
23
|
+
|
|
24
|
+
const renderReportTile = (report: ReportDefinition, tone: string) => {
|
|
25
|
+
const Icon = report.icon;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<ClickableTile
|
|
29
|
+
key={report.path}
|
|
30
|
+
className={styles.tile}
|
|
31
|
+
data-tone={tone}
|
|
32
|
+
onClick={() => navigate(report.path)}
|
|
33
|
+
aria-label={`${report.code} ${report.name}`}
|
|
34
|
+
>
|
|
35
|
+
<div className={styles.tileIcon}>
|
|
36
|
+
<Icon size={20} />
|
|
37
|
+
</div>
|
|
38
|
+
<div className={styles.tileCopy}>
|
|
39
|
+
<p className={styles.tileCode}>{report.code}</p>
|
|
40
|
+
<h4 className={styles.tileName}>{report.name}</h4>
|
|
41
|
+
</div>
|
|
42
|
+
<ArrowRight size={16} className={styles.tileArrow} />
|
|
43
|
+
</ClickableTile>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
9
47
|
return (
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
</
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
</
|
|
48
|
+
<div className={styles.dashboard}>
|
|
49
|
+
<header className={styles.header}>
|
|
50
|
+
<div className={styles.headerIcon}>
|
|
51
|
+
<Report size={20} />
|
|
52
|
+
</div>
|
|
53
|
+
<h3 className={styles.headerTitle}>Reports</h3>
|
|
54
|
+
<div className={styles.headerMeta}>
|
|
55
|
+
{facilityName && (
|
|
56
|
+
<span className={styles.metaItem}>
|
|
57
|
+
<Location size={16} />
|
|
58
|
+
{facilityName}
|
|
59
|
+
</span>
|
|
60
|
+
)}
|
|
61
|
+
<span className={styles.metaItem}>
|
|
62
|
+
<Calendar size={16} />
|
|
63
|
+
{today}
|
|
64
|
+
</span>
|
|
65
|
+
</div>
|
|
66
|
+
</header>
|
|
67
|
+
|
|
68
|
+
<div className={styles.toolbar}>
|
|
69
|
+
<Layer className={styles.searchLayer}>
|
|
70
|
+
<Search
|
|
71
|
+
id="reports-search"
|
|
72
|
+
labelText="Search reports"
|
|
73
|
+
placeholder="Search reports"
|
|
74
|
+
size="sm"
|
|
75
|
+
value={searchTerm}
|
|
76
|
+
onChange={(event) => setSearchTerm(event.target.value)}
|
|
77
|
+
onClear={() => setSearchTerm('')}
|
|
78
|
+
/>
|
|
79
|
+
</Layer>
|
|
80
|
+
<p className={styles.resultCount}>
|
|
81
|
+
{isSearching ? `${matchCount} of ${totalReportCount} reports` : `${totalReportCount} reports available`}
|
|
82
|
+
</p>
|
|
42
83
|
</div>
|
|
43
|
-
|
|
84
|
+
|
|
85
|
+
{visibleCategories.length > 0 ? (
|
|
86
|
+
visibleCategories.map((category) => (
|
|
87
|
+
<section key={category.id} className={styles.category}>
|
|
88
|
+
<div className={styles.categoryHeader} data-tone={category.tone}>
|
|
89
|
+
<h5 className={styles.categoryTitle}>{category.title}</h5>
|
|
90
|
+
<Tag size="sm" type="outline">
|
|
91
|
+
{category.reports.length}
|
|
92
|
+
</Tag>
|
|
93
|
+
</div>
|
|
94
|
+
<div className={styles.grid}>
|
|
95
|
+
{category.reports.map((report) => renderReportTile(report, category.tone))}
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
))
|
|
99
|
+
) : (
|
|
100
|
+
<Layer className={styles.emptyState}>
|
|
101
|
+
<Report size={32} className={styles.emptyStateIcon} />
|
|
102
|
+
<h5>No reports match “{searchTerm}”</h5>
|
|
103
|
+
<p>Try a form number such as 731, or a service such as immunization.</p>
|
|
104
|
+
<Button kind="ghost" size="sm" onClick={() => setSearchTerm('')}>
|
|
105
|
+
Clear search
|
|
106
|
+
</Button>
|
|
107
|
+
</Layer>
|
|
108
|
+
)}
|
|
109
|
+
</div>
|
|
44
110
|
);
|
|
45
111
|
};
|
|
46
112
|
|
|
@@ -1,14 +1,272 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
@use 'sass:list';
|
|
2
|
+
@use '@carbon/colors';
|
|
3
|
+
@use '@carbon/layout';
|
|
4
|
+
@use '@carbon/motion';
|
|
5
|
+
@use '@carbon/type';
|
|
6
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
7
|
+
|
|
8
|
+
$tones: (
|
|
9
|
+
'violet': (
|
|
10
|
+
colors.$purple-60,
|
|
11
|
+
colors.$purple-10,
|
|
12
|
+
),
|
|
13
|
+
'magenta': (
|
|
14
|
+
colors.$magenta-60,
|
|
15
|
+
colors.$magenta-10,
|
|
16
|
+
),
|
|
17
|
+
'teal': (
|
|
18
|
+
colors.$teal-60,
|
|
19
|
+
colors.$teal-10,
|
|
20
|
+
),
|
|
21
|
+
'blue': (
|
|
22
|
+
colors.$blue-60,
|
|
23
|
+
colors.$blue-10,
|
|
24
|
+
),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
.dashboard {
|
|
28
|
+
/* Horizontal gutter comes from `.page` in root.scss */
|
|
29
|
+
padding: layout.$spacing-05 0 layout.$spacing-07;
|
|
30
|
+
background-color: $openmrs-background-grey;
|
|
31
|
+
min-height: 100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Header */
|
|
35
|
+
|
|
36
|
+
.header {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
flex-wrap: wrap;
|
|
40
|
+
gap: layout.$spacing-03 layout.$spacing-04;
|
|
41
|
+
padding: layout.$spacing-03 layout.$spacing-05;
|
|
42
|
+
margin-bottom: layout.$spacing-04;
|
|
43
|
+
background-color: $ui-02;
|
|
44
|
+
border: 1px solid $ui-03;
|
|
45
|
+
border-left: layout.$spacing-02 solid var(--brand-01);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.headerIcon {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
flex-shrink: 0;
|
|
53
|
+
width: layout.$spacing-06;
|
|
54
|
+
height: layout.$spacing-06;
|
|
55
|
+
color: var(--brand-01);
|
|
56
|
+
background-color: $brand-primary-10;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.headerTitle {
|
|
60
|
+
@include type.type-style('productive-heading-03');
|
|
61
|
+
color: $color-gray-100;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.headerMeta {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: layout.$spacing-05;
|
|
68
|
+
margin-left: auto;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.metaItem {
|
|
72
|
+
@include type.type-style('label-01');
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: layout.$spacing-02;
|
|
76
|
+
color: $text-02;
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
|
|
79
|
+
svg {
|
|
80
|
+
fill: var(--brand-01);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Toolbar */
|
|
85
|
+
|
|
86
|
+
.toolbar {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: layout.$spacing-05;
|
|
90
|
+
margin-bottom: layout.$spacing-05;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.searchLayer {
|
|
94
|
+
flex: 1 1 auto;
|
|
95
|
+
max-width: 24rem;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.resultCount {
|
|
99
|
+
@include type.type-style('label-01');
|
|
100
|
+
color: $text-02;
|
|
101
|
+
white-space: nowrap;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Categories */
|
|
105
|
+
|
|
106
|
+
.category {
|
|
107
|
+
margin-bottom: layout.$spacing-06;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.categoryHeader {
|
|
111
|
+
display: flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: layout.$spacing-03;
|
|
114
|
+
padding-left: layout.$spacing-03;
|
|
115
|
+
margin-bottom: layout.$spacing-04;
|
|
116
|
+
border-left: layout.$spacing-02 solid $ui-04;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.categoryTitle {
|
|
120
|
+
@include type.type-style('productive-heading-01');
|
|
121
|
+
color: $color-gray-100;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.grid {
|
|
125
|
+
display: grid;
|
|
126
|
+
grid-template-columns: repeat(3, 1fr);
|
|
127
|
+
gap: layout.$spacing-04;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Report tiles. Selectors are nested under `.grid` so they win over the
|
|
131
|
+
Carbon tile styles the app shell loads globally. */
|
|
132
|
+
|
|
133
|
+
.grid .tile {
|
|
134
|
+
position: relative;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: layout.$spacing-04;
|
|
138
|
+
min-height: 0;
|
|
139
|
+
padding: layout.$spacing-04;
|
|
140
|
+
background-color: $ui-02;
|
|
141
|
+
border: 1px solid $ui-03;
|
|
142
|
+
border-left: layout.$spacing-02 solid $ui-04;
|
|
143
|
+
text-decoration: none;
|
|
144
|
+
transition: all motion.$duration-fast-02 motion.motion(standard, productive);
|
|
145
|
+
|
|
146
|
+
&:hover {
|
|
147
|
+
background-color: $ui-02;
|
|
148
|
+
border-color: $ui-04;
|
|
149
|
+
box-shadow: 0 layout.$spacing-02 layout.$spacing-05 rgba(0, 0, 0, 0.1);
|
|
150
|
+
|
|
151
|
+
.tileArrow {
|
|
152
|
+
transform: translateX(layout.$spacing-02);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.tileIcon {
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
justify-content: center;
|
|
161
|
+
flex-shrink: 0;
|
|
162
|
+
width: layout.$spacing-07;
|
|
163
|
+
height: layout.$spacing-07;
|
|
164
|
+
background-color: $ui-01;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.tileCopy {
|
|
168
|
+
min-width: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.tileCode {
|
|
172
|
+
@include type.type-style('label-01');
|
|
173
|
+
color: $text-02;
|
|
174
|
+
letter-spacing: 0.04em;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.tileName {
|
|
178
|
+
@include type.type-style('productive-heading-01');
|
|
179
|
+
color: $color-gray-100;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.tileArrow {
|
|
183
|
+
flex-shrink: 0;
|
|
184
|
+
margin-left: auto;
|
|
185
|
+
fill: $text-02;
|
|
186
|
+
transition: transform motion.$duration-fast-02 motion.motion(standard, productive);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Tone accents, applied per category */
|
|
190
|
+
|
|
191
|
+
@each $name, $tone in $tones {
|
|
192
|
+
$accent: list.nth($tone, 1);
|
|
193
|
+
$tint: list.nth($tone, 2);
|
|
194
|
+
|
|
195
|
+
.categoryHeader[data-tone='#{$name}'] {
|
|
196
|
+
border-left-color: $accent;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.grid .tile[data-tone='#{$name}'] {
|
|
200
|
+
border-left-color: $accent;
|
|
201
|
+
|
|
202
|
+
.tileIcon {
|
|
203
|
+
color: $accent;
|
|
204
|
+
background-color: $tint;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
&:hover {
|
|
208
|
+
border-color: $accent;
|
|
209
|
+
|
|
210
|
+
.tileArrow {
|
|
211
|
+
fill: $accent;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Empty state */
|
|
218
|
+
|
|
219
|
+
.emptyState {
|
|
220
|
+
display: flex;
|
|
221
|
+
flex-direction: column;
|
|
222
|
+
align-items: center;
|
|
223
|
+
gap: layout.$spacing-03;
|
|
224
|
+
padding: layout.$spacing-07 layout.$spacing-05;
|
|
225
|
+
text-align: center;
|
|
226
|
+
background-color: $ui-02;
|
|
227
|
+
border: 1px solid $ui-03;
|
|
228
|
+
|
|
229
|
+
h5 {
|
|
230
|
+
@include type.type-style('productive-heading-02');
|
|
231
|
+
color: $color-gray-100;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
p {
|
|
235
|
+
@include type.type-style('body-long-01');
|
|
236
|
+
color: $text-02;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.emptyStateIcon {
|
|
241
|
+
fill: $ui-04;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@media (max-width: $breakpoint-tablet-max) {
|
|
245
|
+
.dashboard {
|
|
246
|
+
padding: layout.$spacing-05 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.headerMeta {
|
|
250
|
+
align-items: flex-start;
|
|
251
|
+
flex-wrap: wrap;
|
|
252
|
+
margin-left: 0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.toolbar {
|
|
3
256
|
flex-wrap: wrap;
|
|
4
|
-
|
|
5
|
-
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.searchLayer {
|
|
260
|
+
max-width: none;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.grid {
|
|
264
|
+
grid-template-columns: repeat(2, 1fr);
|
|
265
|
+
}
|
|
6
266
|
}
|
|
7
267
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
text-align: center;
|
|
14
|
-
}
|
|
268
|
+
@media (max-width: $breakpoint-phone-max) {
|
|
269
|
+
.grid {
|
|
270
|
+
grid-template-columns: 1fr;
|
|
271
|
+
}
|
|
272
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,18 @@ import { reportsDashboardMeta } from './dashboard-meta/reports-dashboard.meta';
|
|
|
5
5
|
|
|
6
6
|
export const moduleName = '@ampath/esm-reports-app';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* The section this app's configuration is declared under.
|
|
10
|
+
*
|
|
11
|
+
* Not the package name: the AMPATH deployment's `o3-config.json` declares
|
|
12
|
+
* `@ampath/esm-reporting`, and there is no `@ampath/esm-reports-app` section in
|
|
13
|
+
* it. Registering the schema under the package name left `etlBaseUrl` on its
|
|
14
|
+
* empty default no matter what the deployment set, so every report failed with
|
|
15
|
+
* "the ETL base URL is not configured". Keep this in step with the config, not
|
|
16
|
+
* with `package.json`.
|
|
17
|
+
*/
|
|
18
|
+
export const configSectionName = '@ampath/esm-reporting';
|
|
19
|
+
|
|
8
20
|
const options = {
|
|
9
21
|
featureName: 'ampath-esm-reports',
|
|
10
22
|
moduleName,
|
|
@@ -13,7 +25,7 @@ const options = {
|
|
|
13
25
|
export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
|
|
14
26
|
|
|
15
27
|
export function startupApp() {
|
|
16
|
-
defineConfigSchema(
|
|
28
|
+
defineConfigSchema(configSectionName, configSchema);
|
|
17
29
|
}
|
|
18
30
|
export const root = getAsyncLifecycle(() => import('./root.component'), options);
|
|
19
31
|
|