@kenyaemr/esm-active-visits-app 7.0.3-pre.89 → 8.0.1-pre.95
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/.turbo/turbo-build.log +22 -16
- package/dist/106.js +1 -0
- package/dist/106.js.map +1 -0
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/271.js +1 -1
- package/dist/319.js +1 -1
- package/dist/460.js +1 -1
- package/dist/574.js +1 -1
- package/dist/6.js +1 -0
- package/dist/6.js.map +1 -0
- package/dist/644.js +1 -1
- package/dist/725.js +1 -0
- package/dist/725.js.map +1 -0
- package/dist/757.js +1 -1
- package/dist/788.js +1 -1
- package/dist/807.js +1 -1
- package/dist/833.js +1 -1
- package/dist/966.js +2 -0
- package/dist/966.js.map +1 -0
- package/dist/967.js +1 -0
- package/dist/967.js.map +1 -0
- package/dist/kenyaemr-esm-active-visits-app.js +1 -1
- package/dist/kenyaemr-esm-active-visits-app.js.buildmanifest.json +127 -54
- package/dist/kenyaemr-esm-active-visits-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +2 -2
- package/src/active-visits-widget/active-visits.scss +20 -20
- package/src/active-visits-widget/active-visits.test.tsx +101 -32
- package/src/config-schema.ts +10 -10
- package/src/home-page-tiles/active-visits-metric-tile/active-visits-tile.component.tsx +23 -0
- package/src/home-page-tiles/active-visits-metric-tile/active-visits.resource.ts +28 -0
- package/src/home-page-tiles/homepage-tiles.scss +39 -0
- package/src/home-page-tiles/total-visits-metric-tile/total-visits-tile.component.tsx +23 -0
- package/src/home-page-tiles/total-visits-metric-tile/total-visits.resource.ts +21 -0
- package/src/index.ts +11 -1
- package/src/routes.json +10 -0
- package/src/types/index.ts +2 -0
- package/src/visits-summary/visit-detail-overview.scss +61 -38
- package/src/visits-summary/visit-detail.test.tsx +48 -52
- package/src/visits-summary/visit.resource.ts +2 -2
- package/src/visits-summary/visits-components/encounter-observations.test.tsx +2 -1
- package/translations/am.json +3 -1
- package/translations/ar.json +2 -0
- package/translations/en.json +2 -0
- package/translations/es.json +3 -1
- package/translations/fr.json +3 -1
- package/translations/he.json +2 -0
- package/translations/km.json +2 -0
- package/translations/zh.json +2 -0
- package/translations/zh_CN.json +2 -0
- package/dist/835.js +0 -1
- package/dist/835.js.map +0 -1
- package/dist/875.js +0 -2
- package/dist/875.js.map +0 -1
- package/src/root.scss +0 -30
- /package/dist/{875.js.LICENSE.txt → 966.js.LICENSE.txt} +0 -0
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.2.0"},"extensions":[{"name":"active-visits-widget","slot":"homepage-widgets-slot","component":"activeVisits","order":0},{"name":"visit-summary-widget","slot":"visit-summary-slot","component":"visitDetail"}],"pages":[],"version":"
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":"^2.2.0"},"extensions":[{"name":"active-visits-widget","slot":"homepage-widgets-slot","component":"activeVisits","order":0},{"name":"visit-summary-widget","slot":"visit-summary-slot","component":"visitDetail"},{"name":"active-visits-tile","slot":"home-metrics-tiles-slot","component":"homeActiveVisitsTile"},{"name":"total-visits-tile","slot":"home-metrics-tiles-slot","component":"homeTotalVisitsTile"}],"pages":[],"version":"8.0.1-pre.95"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenyaemr/esm-active-visits-app",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1-pre.95",
|
|
4
4
|
"description": "Active visits widget microfrontend for the OpenMRS SPA",
|
|
5
5
|
"browser": "dist/kenyaemr-esm-active-visits-app.js",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"webpack": "^5.74.0"
|
|
53
53
|
},
|
|
54
|
-
"stableVersion": "
|
|
54
|
+
"stableVersion": "8.0.0"
|
|
55
55
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
@use '@carbon/
|
|
2
|
-
@use '@carbon/
|
|
3
|
-
@
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
4
4
|
|
|
5
5
|
.container {
|
|
6
|
-
margin:
|
|
6
|
+
margin: 0 layout.$spacing-05;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.activeVisitsContainer {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
display: flex;
|
|
20
20
|
justify-content: space-between;
|
|
21
21
|
align-items: center;
|
|
22
|
-
padding:
|
|
22
|
+
padding: layout.$spacing-04 0 layout.$spacing-04 layout.$spacing-05;
|
|
23
23
|
background-color: $ui-02;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -60,20 +60,20 @@
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
.emptyRow {
|
|
63
|
-
padding: 0
|
|
63
|
+
padding: 0 layout.$spacing-05;
|
|
64
64
|
display: flex;
|
|
65
65
|
align-items: center;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
.visitSummaryContainer {
|
|
69
69
|
width: 100%;
|
|
70
|
-
max-width:
|
|
71
|
-
margin:
|
|
70
|
+
max-width: 48rem;
|
|
71
|
+
margin: layout.$spacing-05 auto;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
.expandedActiveVisitRow {
|
|
75
75
|
td {
|
|
76
|
-
padding: 0
|
|
76
|
+
padding: 0 layout.$spacing-07;
|
|
77
77
|
|
|
78
78
|
> div {
|
|
79
79
|
max-height: max-content !important;
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
th[colspan] td[colspan] > div:first-child {
|
|
84
|
-
padding: 0
|
|
84
|
+
padding: 0 layout.$spacing-05;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
&:last-of-type th[colspan]:last-child {
|
|
@@ -90,14 +90,14 @@
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
.action {
|
|
93
|
-
margin-bottom:
|
|
93
|
+
margin-bottom: layout.$spacing-03;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
.content {
|
|
97
97
|
@include type.type-style('heading-compact-01');
|
|
98
98
|
color: $text-02;
|
|
99
|
-
margin-top:
|
|
100
|
-
margin-bottom:
|
|
99
|
+
margin-top: layout.$spacing-05;
|
|
100
|
+
margin-bottom: layout.$spacing-03;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
.desktopHeading,
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
&:after {
|
|
113
113
|
content: '';
|
|
114
114
|
display: block;
|
|
115
|
-
width:
|
|
115
|
+
width: layout.$spacing-07;
|
|
116
116
|
padding-top: 3px;
|
|
117
117
|
border-bottom: 0.375rem solid;
|
|
118
118
|
@include brand-03(border-bottom-color);
|
|
@@ -128,8 +128,8 @@
|
|
|
128
128
|
display: flex;
|
|
129
129
|
justify-content: center;
|
|
130
130
|
align-items: center;
|
|
131
|
-
padding:
|
|
132
|
-
margin:
|
|
131
|
+
padding: layout.$spacing-05;
|
|
132
|
+
margin: layout.$spacing-11;
|
|
133
133
|
text-align: center;
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
.filterEmptyStateContent {
|
|
141
141
|
@include type.type-style('heading-compact-02');
|
|
142
142
|
color: $text-02;
|
|
143
|
-
margin-bottom:
|
|
143
|
+
margin-bottom: layout.$spacing-03;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
.filterEmptyStateHelper {
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
html[dir='rtl'] {
|
|
153
153
|
.activeVisitsContainer {
|
|
154
154
|
.activeVisitsDetailHeaderContainer {
|
|
155
|
-
padding:
|
|
155
|
+
padding: layout.$spacing-04 layout.$spacing-05 layout.$spacing-04 0;
|
|
156
156
|
}
|
|
157
157
|
.desktopHeading,
|
|
158
158
|
.tabletHeading {
|
|
@@ -164,7 +164,7 @@ html[dir='rtl'] {
|
|
|
164
164
|
& :first-child {
|
|
165
165
|
svg {
|
|
166
166
|
left: unset;
|
|
167
|
-
right:
|
|
167
|
+
right: layout.$spacing-03;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
& :last-child {
|
|
@@ -180,7 +180,7 @@ html[dir='rtl'] {
|
|
|
180
180
|
text-align: right;
|
|
181
181
|
.serviceColor {
|
|
182
182
|
margin-right: 0;
|
|
183
|
-
margin-left:
|
|
183
|
+
margin-left: layout.$spacing-03;
|
|
184
184
|
}
|
|
185
185
|
button {
|
|
186
186
|
text-align: right;
|
|
@@ -1,29 +1,49 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import { render, screen } from '@testing-library/react';
|
|
4
|
-
import { useConfig } from '@openmrs/esm-framework';
|
|
4
|
+
import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
|
|
5
|
+
import { mockPatient, mockSession } from '__mocks__';
|
|
6
|
+
import { configSchema, type SectionDefinition } from '../config-schema';
|
|
5
7
|
import { useActiveVisits } from './active-visits.resource';
|
|
6
8
|
import ActiveVisitsTable from './active-visits.component';
|
|
7
9
|
|
|
8
|
-
const mockUseActiveVisits =
|
|
10
|
+
const mockUseActiveVisits = jest.mocked(useActiveVisits);
|
|
11
|
+
const mockUseConfig = jest.mocked(useConfig<SectionDefinition>);
|
|
9
12
|
|
|
10
13
|
jest.mock('./active-visits.resource', () => ({
|
|
11
14
|
...jest.requireActual('./active-visits.resource'),
|
|
12
15
|
useActiveVisits: jest.fn(),
|
|
13
16
|
}));
|
|
14
17
|
|
|
15
|
-
const mockUseConfig = useConfig as jest.Mock;
|
|
16
|
-
|
|
17
18
|
describe('ActiveVisitsTable', () => {
|
|
18
|
-
beforeEach(() =>
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
mockUseConfig.mockReturnValue({
|
|
21
|
+
...getDefaultsFromConfigSchema(configSchema),
|
|
22
|
+
});
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
mockUseActiveVisits.mockReturnValue({
|
|
25
|
+
activeVisits: [
|
|
26
|
+
{
|
|
27
|
+
age: '20',
|
|
28
|
+
gender: 'male',
|
|
29
|
+
id: '1',
|
|
30
|
+
idNumber: mockPatient.uuid,
|
|
31
|
+
location: mockSession.data.sessionLocation.uuid,
|
|
32
|
+
name: 'John Doe',
|
|
33
|
+
patientUuid: 'uuid1',
|
|
34
|
+
visitStartTime: '',
|
|
35
|
+
visitType: 'Checkup',
|
|
36
|
+
visitUuid: 'visit-uuid-1',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
23
39
|
isLoading: false,
|
|
24
40
|
isValidating: false,
|
|
25
|
-
error:
|
|
26
|
-
|
|
41
|
+
error: undefined,
|
|
42
|
+
totalResults: 1,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('renders data table with active visits', () => {
|
|
27
47
|
render(<ActiveVisitsTable />);
|
|
28
48
|
|
|
29
49
|
expect(screen.getByText('Visit Time')).toBeInTheDocument();
|
|
@@ -41,15 +61,38 @@ describe('ActiveVisitsTable', () => {
|
|
|
41
61
|
it('filters active visits based on search input', async () => {
|
|
42
62
|
const user = userEvent.setup();
|
|
43
63
|
|
|
44
|
-
mockUseActiveVisits.
|
|
64
|
+
mockUseActiveVisits.mockReturnValue({
|
|
45
65
|
activeVisits: [
|
|
46
|
-
{
|
|
47
|
-
|
|
66
|
+
{
|
|
67
|
+
age: '20',
|
|
68
|
+
gender: 'male',
|
|
69
|
+
id: '1',
|
|
70
|
+
idNumber: '000001A',
|
|
71
|
+
location: mockSession.data.sessionLocation.uuid,
|
|
72
|
+
name: 'John Doe',
|
|
73
|
+
patientUuid: 'uuid1',
|
|
74
|
+
visitStartTime: '',
|
|
75
|
+
visitType: 'Checkup',
|
|
76
|
+
visitUuid: 'visit-uuid-1',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
age: '25',
|
|
80
|
+
gender: 'female',
|
|
81
|
+
id: '2',
|
|
82
|
+
idNumber: '000001B',
|
|
83
|
+
location: mockSession.data.sessionLocation.uuid,
|
|
84
|
+
name: 'Some One',
|
|
85
|
+
patientUuid: 'uuid2',
|
|
86
|
+
visitStartTime: '',
|
|
87
|
+
visitType: 'Checkup',
|
|
88
|
+
visitUuid: 'visit-uuid-2',
|
|
89
|
+
},
|
|
48
90
|
],
|
|
49
91
|
isLoading: false,
|
|
50
92
|
isValidating: false,
|
|
51
|
-
error:
|
|
52
|
-
|
|
93
|
+
error: undefined,
|
|
94
|
+
totalResults: 2,
|
|
95
|
+
});
|
|
53
96
|
|
|
54
97
|
render(<ActiveVisitsTable />);
|
|
55
98
|
|
|
@@ -57,16 +100,17 @@ describe('ActiveVisitsTable', () => {
|
|
|
57
100
|
await user.type(searchInput, 'John');
|
|
58
101
|
|
|
59
102
|
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
|
60
|
-
expect(screen.queryByText('Some One')).
|
|
103
|
+
expect(screen.queryByText('Some One')).not.toBeInTheDocument();
|
|
61
104
|
});
|
|
62
105
|
|
|
63
106
|
it('displays empty state when there are no active visits', () => {
|
|
64
|
-
mockUseActiveVisits.
|
|
107
|
+
mockUseActiveVisits.mockReturnValue({
|
|
65
108
|
activeVisits: [],
|
|
66
109
|
isLoading: false,
|
|
67
110
|
isValidating: false,
|
|
68
|
-
error:
|
|
69
|
-
|
|
111
|
+
error: undefined,
|
|
112
|
+
totalResults: 0,
|
|
113
|
+
});
|
|
70
114
|
|
|
71
115
|
render(<ActiveVisitsTable />);
|
|
72
116
|
|
|
@@ -74,12 +118,13 @@ describe('ActiveVisitsTable', () => {
|
|
|
74
118
|
});
|
|
75
119
|
|
|
76
120
|
it('should not display the table when the data is loading', () => {
|
|
77
|
-
mockUseActiveVisits.
|
|
78
|
-
activeVisits:
|
|
121
|
+
mockUseActiveVisits.mockReturnValue({
|
|
122
|
+
activeVisits: [],
|
|
79
123
|
isLoading: true,
|
|
80
124
|
isValidating: false,
|
|
81
|
-
error:
|
|
82
|
-
|
|
125
|
+
error: undefined,
|
|
126
|
+
totalResults: 0,
|
|
127
|
+
});
|
|
83
128
|
|
|
84
129
|
render(<ActiveVisitsTable />);
|
|
85
130
|
|
|
@@ -90,12 +135,13 @@ describe('ActiveVisitsTable', () => {
|
|
|
90
135
|
});
|
|
91
136
|
|
|
92
137
|
it('should display the error state when there is error', () => {
|
|
93
|
-
mockUseActiveVisits.
|
|
94
|
-
activeVisits:
|
|
138
|
+
mockUseActiveVisits.mockReturnValue({
|
|
139
|
+
activeVisits: [],
|
|
95
140
|
isLoading: false,
|
|
96
141
|
isValidating: false,
|
|
97
|
-
error: 'Error
|
|
98
|
-
|
|
142
|
+
error: new Error('Error fetching data'),
|
|
143
|
+
totalResults: 0,
|
|
144
|
+
});
|
|
99
145
|
|
|
100
146
|
render(<ActiveVisitsTable />);
|
|
101
147
|
|
|
@@ -104,15 +150,38 @@ describe('ActiveVisitsTable', () => {
|
|
|
104
150
|
});
|
|
105
151
|
|
|
106
152
|
it('should display the pagination when pagination is true', () => {
|
|
107
|
-
mockUseActiveVisits.
|
|
153
|
+
mockUseActiveVisits.mockReturnValue({
|
|
108
154
|
activeVisits: [
|
|
109
|
-
{
|
|
110
|
-
|
|
155
|
+
{
|
|
156
|
+
age: '20',
|
|
157
|
+
gender: 'male',
|
|
158
|
+
id: '1',
|
|
159
|
+
idNumber: '000001A',
|
|
160
|
+
location: mockSession.data.sessionLocation.uuid,
|
|
161
|
+
name: 'John Doe',
|
|
162
|
+
patientUuid: 'uuid1',
|
|
163
|
+
visitStartTime: '',
|
|
164
|
+
visitType: 'Checkup',
|
|
165
|
+
visitUuid: 'visit-uuid-1',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
age: '25',
|
|
169
|
+
gender: 'female',
|
|
170
|
+
id: '2',
|
|
171
|
+
idNumber: '000001B',
|
|
172
|
+
location: mockSession.data.sessionLocation.uuid,
|
|
173
|
+
name: 'Some One',
|
|
174
|
+
patientUuid: 'uuid2',
|
|
175
|
+
visitStartTime: '',
|
|
176
|
+
visitType: 'Checkup',
|
|
177
|
+
visitUuid: 'visit-uuid-2',
|
|
178
|
+
},
|
|
111
179
|
],
|
|
112
180
|
isLoading: false,
|
|
113
181
|
isValidating: false,
|
|
114
|
-
error:
|
|
115
|
-
|
|
182
|
+
error: undefined,
|
|
183
|
+
totalResults: 2,
|
|
184
|
+
});
|
|
116
185
|
|
|
117
186
|
render(<ActiveVisitsTable />);
|
|
118
187
|
});
|
package/src/config-schema.ts
CHANGED
|
@@ -19,16 +19,6 @@ export interface IdentifiersDefinition {
|
|
|
19
19
|
|
|
20
20
|
export const configSchema = {
|
|
21
21
|
activeVisits: {
|
|
22
|
-
pageSize: {
|
|
23
|
-
_type: Type.Number,
|
|
24
|
-
_description: 'Count of active visits to be shown in a single page.',
|
|
25
|
-
_default: 10,
|
|
26
|
-
},
|
|
27
|
-
pageSizes: {
|
|
28
|
-
_type: Type.Array,
|
|
29
|
-
_description: 'Customizable page sizes that user can choose',
|
|
30
|
-
_default: [10, 20, 50],
|
|
31
|
-
},
|
|
32
22
|
identifiers: {
|
|
33
23
|
_type: Type.Array,
|
|
34
24
|
_description: 'Customizable list of identifiers to display on active visits table',
|
|
@@ -53,5 +43,15 @@ export const configSchema = {
|
|
|
53
43
|
},
|
|
54
44
|
_default: null,
|
|
55
45
|
},
|
|
46
|
+
pageSize: {
|
|
47
|
+
_type: Type.Number,
|
|
48
|
+
_description: 'Count of active visits to be shown in a single page.',
|
|
49
|
+
_default: 10,
|
|
50
|
+
},
|
|
51
|
+
pageSizes: {
|
|
52
|
+
_type: Type.Array,
|
|
53
|
+
_description: 'Customizable page sizes that user can choose',
|
|
54
|
+
_default: [10, 20, 50],
|
|
55
|
+
},
|
|
56
56
|
},
|
|
57
57
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tile } from '@carbon/react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import useActiveVisits from './active-visits.resource';
|
|
5
|
+
import styles from '../homepage-tiles.scss';
|
|
6
|
+
|
|
7
|
+
const ActiveVisitsTile: React.FC = () => {
|
|
8
|
+
const { count } = useActiveVisits();
|
|
9
|
+
|
|
10
|
+
const { t } = useTranslation();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Tile className={styles.tileContainer}>
|
|
14
|
+
<header className={styles.tileHeader}>{t('activeVisits', 'Active Visits')}</header>
|
|
15
|
+
<div className={styles.displayDetails}>
|
|
16
|
+
<div className={styles.countLabel}>{t('patients', 'Patients')}</div>
|
|
17
|
+
<div className={styles.displayData}>{count ?? 0}</div>
|
|
18
|
+
</div>
|
|
19
|
+
</Tile>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default ActiveVisitsTile;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { openmrsFetch, restBaseUrl, useSession, type Visit } from '@openmrs/esm-framework';
|
|
2
|
+
import useSWR from 'swr';
|
|
3
|
+
|
|
4
|
+
export default function useActiveVisits() {
|
|
5
|
+
const session = useSession();
|
|
6
|
+
const sessionLocation = session?.sessionLocation?.uuid;
|
|
7
|
+
|
|
8
|
+
const customRepresentation = 'custom:(uuid,startDatetime,stopDatetime)';
|
|
9
|
+
|
|
10
|
+
const getUrl = () => {
|
|
11
|
+
let url = `${restBaseUrl}/visit?v=${customRepresentation}&`;
|
|
12
|
+
let urlSearchParams = new URLSearchParams();
|
|
13
|
+
|
|
14
|
+
urlSearchParams.append('includeInactive', 'false');
|
|
15
|
+
urlSearchParams.append('totalCount', 'true');
|
|
16
|
+
urlSearchParams.append('location', `${sessionLocation}`);
|
|
17
|
+
|
|
18
|
+
return url + urlSearchParams.toString();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const { data, error, isLoading } = useSWR<{ data: { totalCount: number } }>(getUrl, openmrsFetch);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
count: data?.data.totalCount,
|
|
25
|
+
error,
|
|
26
|
+
isLoading,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '@carbon/colors';
|
|
4
|
+
@use '@carbon/layout';
|
|
5
|
+
|
|
6
|
+
.tileContainer {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
align-items: space-between;
|
|
10
|
+
background-color: colors.$white;
|
|
11
|
+
border: 1px solid colors.$gray-20;
|
|
12
|
+
height: 7.875rem;
|
|
13
|
+
padding: layout.$spacing-05;
|
|
14
|
+
margin: layout.$spacing-03;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tileHeader {
|
|
18
|
+
@include type.type-style('heading-01');
|
|
19
|
+
font-weight: 600;
|
|
20
|
+
line-height: 1.28572;
|
|
21
|
+
letter-spacing: 0.16px;
|
|
22
|
+
color: colors.$gray-70;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.displayDetails {
|
|
26
|
+
margin-top: layout.$spacing-06;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.displayData {
|
|
30
|
+
font-size: 1.75rem;
|
|
31
|
+
font-weight: 400;
|
|
32
|
+
line-height: 1.28572;
|
|
33
|
+
color: colors.$black;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.countLabel {
|
|
37
|
+
@include type.type-style('label-01');
|
|
38
|
+
color: $text-02;
|
|
39
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tile } from '@carbon/react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import useTotalVisits from './total-visits.resource';
|
|
5
|
+
import styles from '../homepage-tiles.scss';
|
|
6
|
+
|
|
7
|
+
const TotalVisitsTile: React.FC = () => {
|
|
8
|
+
const { data: visitsData } = useTotalVisits();
|
|
9
|
+
|
|
10
|
+
const { t } = useTranslation();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Tile className={styles.tileContainer}>
|
|
14
|
+
<header className={styles.tileHeader}>{t('totalVisits', 'Total Visits Today')}</header>
|
|
15
|
+
<div className={styles.displayDetails}>
|
|
16
|
+
<div className={styles.countLabel}>{t('patients', 'Patients')}</div>
|
|
17
|
+
<div className={styles.displayData}>{visitsData?.length ?? 0}</div>
|
|
18
|
+
</div>
|
|
19
|
+
</Tile>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default TotalVisitsTile;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { openmrsFetch, restBaseUrl, type Visit } from '@openmrs/esm-framework';
|
|
2
|
+
import useSWR from 'swr';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
|
|
5
|
+
const useTotalVisits = () => {
|
|
6
|
+
const customRepresentation = 'custom:(uuid,startDatetime,stopDatetime)';
|
|
7
|
+
|
|
8
|
+
const visitsUrl = `${restBaseUrl}/visit?includeInactive=true&v=${customRepresentation}&fromStartDate=${dayjs().format(
|
|
9
|
+
'YYYY-MM-DD',
|
|
10
|
+
)}`;
|
|
11
|
+
|
|
12
|
+
const { data, error, isLoading } = useSWR<{ data: { results: Array<Visit> } }>(visitsUrl, openmrsFetch);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
data: data?.data.results,
|
|
16
|
+
error,
|
|
17
|
+
isLoading,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default useTotalVisits;
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineConfigSchema, getSyncLifecycle } from '@openmrs/esm-framework';
|
|
1
|
+
import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle } from '@openmrs/esm-framework';
|
|
2
2
|
import { configSchema } from './config-schema';
|
|
3
3
|
import activeVisitsComponent from './active-visits-widget/active-visits.component';
|
|
4
4
|
import visitDetailComponent from './visits-summary/visit-detail.component';
|
|
@@ -19,3 +19,13 @@ export function startupApp() {
|
|
|
19
19
|
export const activeVisits = getSyncLifecycle(activeVisitsComponent, options);
|
|
20
20
|
|
|
21
21
|
export const visitDetail = getSyncLifecycle(visitDetailComponent, options);
|
|
22
|
+
|
|
23
|
+
export const homeActiveVisitsTile = getAsyncLifecycle(
|
|
24
|
+
() => import('./home-page-tiles/active-visits-metric-tile/active-visits-tile.component'),
|
|
25
|
+
options,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export const homeTotalVisitsTile = getAsyncLifecycle(
|
|
29
|
+
() => import('./home-page-tiles/total-visits-metric-tile/total-visits-tile.component'),
|
|
30
|
+
options,
|
|
31
|
+
);
|
package/src/routes.json
CHANGED
|
@@ -14,6 +14,16 @@
|
|
|
14
14
|
"name": "visit-summary-widget",
|
|
15
15
|
"slot": "visit-summary-slot",
|
|
16
16
|
"component": "visitDetail"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "active-visits-tile",
|
|
20
|
+
"slot": "home-metrics-tiles-slot",
|
|
21
|
+
"component": "homeActiveVisitsTile"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "total-visits-tile",
|
|
25
|
+
"slot": "home-metrics-tiles-slot",
|
|
26
|
+
"component": "homeTotalVisitsTile"
|
|
17
27
|
}
|
|
18
28
|
],
|
|
19
29
|
"pages": []
|