@digihmis/esm-triage-app 1.0.0
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/README.md +4 -0
- package/dist/117.js +1 -0
- package/dist/117.js.map +1 -0
- package/dist/132.js +1 -0
- package/dist/132.js.map +1 -0
- package/dist/152.js +1 -0
- package/dist/152.js.map +1 -0
- package/dist/183.js +66 -0
- package/dist/183.js.map +1 -0
- package/dist/209.js +1 -0
- package/dist/209.js.map +1 -0
- package/dist/22.js +1 -0
- package/dist/22.js.map +1 -0
- package/dist/222.js +1 -0
- package/dist/222.js.map +1 -0
- package/dist/317.js +1 -0
- package/dist/317.js.map +1 -0
- package/dist/349.js +1 -0
- package/dist/349.js.map +1 -0
- package/dist/371.js +1 -0
- package/dist/371.js.map +1 -0
- package/dist/378.js +1 -0
- package/dist/378.js.map +1 -0
- package/dist/442.js +1 -0
- package/dist/442.js.map +1 -0
- package/dist/45.js +1 -0
- package/dist/45.js.map +1 -0
- package/dist/466.js +1 -0
- package/dist/466.js.map +1 -0
- package/dist/508.js +1 -0
- package/dist/508.js.map +1 -0
- package/dist/61.js +1 -0
- package/dist/61.js.map +1 -0
- package/dist/640.js +1 -0
- package/dist/640.js.map +1 -0
- package/dist/689.js +1 -0
- package/dist/689.js.map +1 -0
- package/dist/709.js +1 -0
- package/dist/709.js.map +1 -0
- package/dist/712.js +1 -0
- package/dist/712.js.map +1 -0
- package/dist/720.js +1 -0
- package/dist/720.js.map +1 -0
- package/dist/737.js +12 -0
- package/dist/737.js.map +1 -0
- package/dist/742.js +1 -0
- package/dist/742.js.map +1 -0
- package/dist/771.js +1 -0
- package/dist/771.js.map +1 -0
- package/dist/806.js +1 -0
- package/dist/806.js.map +1 -0
- package/dist/809.js +1 -0
- package/dist/809.js.map +1 -0
- package/dist/9.js +15 -0
- package/dist/9.js.map +1 -0
- package/dist/912.js +1 -0
- package/dist/912.js.map +1 -0
- package/dist/913.js +1 -0
- package/dist/913.js.map +1 -0
- package/dist/940.js +1 -0
- package/dist/940.js.map +1 -0
- package/dist/974.js +1 -0
- package/dist/974.js.map +1 -0
- package/dist/976.js +1 -0
- package/dist/976.js.map +1 -0
- package/dist/digihmis-esm-triage-app.js +6 -0
- package/dist/digihmis-esm-triage-app.js.buildmanifest.json +905 -0
- package/dist/digihmis-esm-triage-app.js.map +1 -0
- package/dist/main.js +90 -0
- package/dist/main.js.map +1 -0
- package/dist/routes.json +1 -0
- package/jest.config.js +26 -0
- package/package.json +51 -0
- package/rspack.config.js +1 -0
- package/src/config-schema.ts +142 -0
- package/src/dashboard.meta.ts +16 -0
- package/src/declarations.d.ts +6 -0
- package/src/icon-wrapper/icon-wrapper.extension.tsx +17 -0
- package/src/index.ts +41 -0
- package/src/left-panel/left-panel.component.tsx +100 -0
- package/src/left-panel/left-panel.scss +13 -0
- package/src/page-header/page-header.component.tsx +35 -0
- package/src/page-header/page-header.scss +76 -0
- package/src/past-vitals/action-menu/vitals-anthropometrics.component.tsx +44 -0
- package/src/past-vitals/action-menu/vitals-anthropometrics.scss +0 -0
- package/src/past-vitals/paginated-antropometrics/paginated-antropometrics.component.tsx +132 -0
- package/src/past-vitals/paginated-antropometrics/paginated-antropometrics.scss +9 -0
- package/src/past-vitals/paginated-vitals/paginated-vitals.component.tsx +157 -0
- package/src/past-vitals/paginated-vitals/paginated-vitals.scss +94 -0
- package/src/past-vitals/paginated-vitals/type/index.ts +1 -0
- package/src/past-vitals/patient-banner/patient-banner.component.tsx +60 -0
- package/src/past-vitals/patient-banner/patient-banner.scss +72 -0
- package/src/past-vitals/patient-vitals-history.component.tsx +85 -0
- package/src/past-vitals/patient-vitals-history.resource.ts +30 -0
- package/src/past-vitals/patient-vitals-history.scss +75 -0
- package/src/past-vitals/triage-anthropometrics/antropometrics-chart.component.tsx +170 -0
- package/src/past-vitals/triage-anthropometrics/antropometrics-chart.scss +70 -0
- package/src/past-vitals/triage-anthropometrics/triage-antropometrics.component.tsx +124 -0
- package/src/past-vitals/triage-anthropometrics/triage-antropometrics.scss +37 -0
- package/src/past-vitals/triage-anthropometrics/type/index.ts +17 -0
- package/src/past-vitals/triage-notes/triage-note.scss +94 -0
- package/src/past-vitals/triage-notes/triage-notes.component.tsx +75 -0
- package/src/past-vitals/triage-notes/triage-notes.resource.ts +72 -0
- package/src/past-vitals/triage-notes/type/index.ts +50 -0
- package/src/past-vitals/triage-vitals/triage-vitals-history.component.tsx +229 -0
- package/src/past-vitals/triage-vitals/triage-vitals-history.scss +48 -0
- package/src/past-vitals/triage-vitals/type/index.ts +32 -0
- package/src/past-vitals/triage-vitals/vital-chart.component.tsx +198 -0
- package/src/past-vitals/triage-vitals/vitals-chart.scss +70 -0
- package/src/past-vitals/utils/index.ts +5 -0
- package/src/past-vitals/vitals-and-biometrics-header/vitals-header-item.component.tsx +61 -0
- package/src/past-vitals/vitals-and-biometrics-header/vitals-header-item.scss +171 -0
- package/src/past-vitals/vitals-and-biometrics-header/vitals-header-item.test.tsx +31 -0
- package/src/past-vitals/vitals-and-biometrics-header/vitals-header.extension.tsx +225 -0
- package/src/past-vitals/vitals-and-biometrics-header/vitals-header.scss +233 -0
- package/src/queue-room-table/queue-room-table.component.tsx +380 -0
- package/src/queue-room-table/queue-room-table.resource.ts +73 -0
- package/src/queue-room-table/queue-room-table.scss +193 -0
- package/src/queue-room-table/type/index.ts +30 -0
- package/src/queue-room-table/useQueueActions.ts +24 -0
- package/src/record-vitals-workspace/common/index.ts +19 -0
- package/src/record-vitals-workspace/component/vitals-biometrics-input.component.tsx +433 -0
- package/src/record-vitals-workspace/component/vitals-biometrics-input.scss +358 -0
- package/src/record-vitals-workspace/helper/index.ts +200 -0
- package/src/record-vitals-workspace/record-vitals.resource.ts +570 -0
- package/src/record-vitals-workspace/record-vitals.scss +140 -0
- package/src/record-vitals-workspace/record-vitals.workspace.tsx +612 -0
- package/src/record-vitals-workspace/schema/index.ts +28 -0
- package/src/record-vitals-workspace/type/index.ts +170 -0
- package/src/record-vitals-workspace/utils/index.ts +100 -0
- package/src/routes.json +70 -0
- package/src/setup-tests.ts +1 -0
- package/src/triage-queue-dashboard/triage-dashboard.resource.ts +75 -0
- package/src/triage-queue-dashboard/triage-queue-dashboard.component.tsx +261 -0
- package/src/triage-queue-dashboard/triage-queue-dashboard.scss +166 -0
- package/src/triage-queue-dashboard/type/index.ts +31 -0
- package/translations/am.json +92 -0
- package/translations/ar.json +92 -0
- package/translations/en.json +92 -0
- package/translations/es.json +92 -0
- package/translations/fr.json +92 -0
- package/translations/he.json +92 -0
- package/translations/km.json +92 -0
- package/translations/pt.json +92 -0
- package/translations/sw.json +92 -0
- package/translations/vi.json +92 -0
- package/translations/zh.json +92 -0
- package/tsconfig.json +5 -0
package/dist/routes.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.24.0"},"extensions":[{"name":"triage-dashboard-header","slot":"triage-sidebar-slot","component":"triageDashboardHeader","order":0,"online":true,"offline":true},{"name":"triage-db-link","slot":"triage-dashboard-slot","component":"leftPanelLink","meta":{"name":"triage","slot":"triage-homepage-dashboard-slot","title":"Triage Queue"},"order":1,"online":true,"offline":true},{"name":"triage-queue-dashboard","slot":"triage-homepage-dashboard-slot","component":"triageQueueDashboard"},{"name":"patient-vitals-link","slot":"triage-dashboard-slot","component":"patientVitalsLink","meta":{"name":"triage/:patientUuid/vitals","slot":"triage-vitals-dashboard-slot","title":"Patient Vitals","showOnlyOnRoute":"/vitals"},"order":2,"online":true,"offline":true},{"name":"patient-vitals-history","slot":"triage-vitals-dashboard-slot","component":"patientVitalsHistory"},{"name":"vitals-header","slot":"patient-vitals-header-slot","component":"vitalsHeader","online":true,"offline":true}],"workspaces":[{"name":"record-vitals-workspace","component":"recordVitalsWorkspace","title":"Record Vitals","type":"other-form","canMaximize":true,"width":"extra-wide"}],"version":"1.0.0"}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
clearMocks: true,
|
|
4
|
+
transform: {
|
|
5
|
+
'^.+\\.[jt]sx?$': ['@swc/jest'],
|
|
6
|
+
},
|
|
7
|
+
transformIgnorePatterns: ['/node_modules/(?!@openmrs|.+\\.pnp\\.[^\\/]+$)'],
|
|
8
|
+
moduleNameMapper: {
|
|
9
|
+
'\\.(s?css)$': 'identity-obj-proxy',
|
|
10
|
+
'@openmrs/esm-framework': '@openmrs/esm-framework/mock',
|
|
11
|
+
'lodash-es': 'lodash',
|
|
12
|
+
'^dexie$': require.resolve('dexie'),
|
|
13
|
+
},
|
|
14
|
+
collectCoverageFrom: [
|
|
15
|
+
'**/src/**/*.tsx',
|
|
16
|
+
'!**/node_modules/**',
|
|
17
|
+
'!**/vendor/**',
|
|
18
|
+
'!**/src/**/*.test.*',
|
|
19
|
+
'!**/src/declarations.d.ts',
|
|
20
|
+
],
|
|
21
|
+
setupFilesAfterEnv: ['<rootDir>/setupTests.ts'],
|
|
22
|
+
testEnvironment: 'jsdom',
|
|
23
|
+
testEnvironmentOptions: {
|
|
24
|
+
url: 'http://localhost/',
|
|
25
|
+
},
|
|
26
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@digihmis/esm-triage-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Triage microfrontend for the OpenMRS SPA",
|
|
5
|
+
"browser": "dist/digihmis-esm-triage-app.js",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"source": true,
|
|
8
|
+
"license": "MPL-2.0",
|
|
9
|
+
"homepage": "https://github.com/its-kios09/DigiHMIS-apps#readme",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"analyze": "rspack --mode=production --env analyze=true",
|
|
12
|
+
"build": "rspack --mode=production",
|
|
13
|
+
"coverage": "yarn test --coverage",
|
|
14
|
+
"debug": "npm run serve",
|
|
15
|
+
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js",
|
|
16
|
+
"lint": "eslint src --ext ts,tsx",
|
|
17
|
+
"serve": "rspack serve --mode=development",
|
|
18
|
+
"start": "openmrs develop",
|
|
19
|
+
"test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests",
|
|
20
|
+
"test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js",
|
|
21
|
+
"typescript": "tsc"
|
|
22
|
+
},
|
|
23
|
+
"browserslist": [
|
|
24
|
+
"extends browserslist-config-openmrs"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"openmrs"
|
|
28
|
+
],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/its-kios09/DigiHMIS-apps.git#readme"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/its-kios09/DigiHMIS-apps/issues"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"lodash-es": "^4.17.15",
|
|
41
|
+
"react-to-print": "2.14.13"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@carbon/react": "1.x",
|
|
45
|
+
"@openmrs/esm-framework": "8.x",
|
|
46
|
+
"react": "^18.1.0",
|
|
47
|
+
"react-i18next": "16.x",
|
|
48
|
+
"react-router-dom": "6.x",
|
|
49
|
+
"swr": "2.x"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/rspack.config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('../../tools/rs-pack-code-spliting');
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { ConfigSchema, Type, validators } from '@openmrs/esm-framework';
|
|
2
|
+
|
|
3
|
+
export const configSchema: ConfigSchema = {
|
|
4
|
+
triageIcon: {
|
|
5
|
+
src: {
|
|
6
|
+
_type: Type.String,
|
|
7
|
+
_default: '/openmrs/spa/triage_2.svg',
|
|
8
|
+
_description:
|
|
9
|
+
'The path or URL to the logo image. If set to an empty string, the default OpenMRS SVG sprite will be used.',
|
|
10
|
+
_validators: [validators.isUrl],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
triageQueueUuid: {
|
|
14
|
+
_type: Type.String,
|
|
15
|
+
_description: 'The UUID of the queue room to be used for triage.',
|
|
16
|
+
_default: 'd692a223-e140-11ee-bad2-0242ac120002',
|
|
17
|
+
},
|
|
18
|
+
concepts: {
|
|
19
|
+
waitingStatusUuid: {
|
|
20
|
+
_type: Type.UUID,
|
|
21
|
+
_default: '167407AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
22
|
+
_description: 'UUID for waiting status concept',
|
|
23
|
+
},
|
|
24
|
+
inServiceStatusUuid: {
|
|
25
|
+
_type: Type.UUID,
|
|
26
|
+
_default: '167408AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
27
|
+
_description: 'UUID for in-service status concept',
|
|
28
|
+
},
|
|
29
|
+
completedStatusUuid: {
|
|
30
|
+
_type: Type.UUID,
|
|
31
|
+
_default: '167409AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
32
|
+
_description: 'UUID for completed status concept',
|
|
33
|
+
},
|
|
34
|
+
systolicBloodPressureUuid: {
|
|
35
|
+
_type: Type.ConceptUuid,
|
|
36
|
+
_default: '5085AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
37
|
+
},
|
|
38
|
+
diastolicBloodPressureUuid: {
|
|
39
|
+
_type: Type.ConceptUuid,
|
|
40
|
+
_default: '5086AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
41
|
+
},
|
|
42
|
+
pulseUuid: {
|
|
43
|
+
_type: Type.ConceptUuid,
|
|
44
|
+
_default: '5087AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
45
|
+
},
|
|
46
|
+
temperatureUuid: {
|
|
47
|
+
_type: Type.ConceptUuid,
|
|
48
|
+
_default: '5088AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
49
|
+
},
|
|
50
|
+
oxygenSaturationUuid: {
|
|
51
|
+
_type: Type.ConceptUuid,
|
|
52
|
+
_default: '5092AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
53
|
+
},
|
|
54
|
+
heightUuid: {
|
|
55
|
+
_type: Type.ConceptUuid,
|
|
56
|
+
_default: '5090AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
57
|
+
},
|
|
58
|
+
weightUuid: {
|
|
59
|
+
_type: Type.ConceptUuid,
|
|
60
|
+
_default: '5089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
61
|
+
},
|
|
62
|
+
respiratoryRateUuid: {
|
|
63
|
+
_type: Type.ConceptUuid,
|
|
64
|
+
_default: '5242AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
65
|
+
},
|
|
66
|
+
generalPatientNoteUuid: {
|
|
67
|
+
_type: Type.ConceptUuid,
|
|
68
|
+
_default: '159395AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
69
|
+
},
|
|
70
|
+
midUpperArmCircumferenceUuid: {
|
|
71
|
+
_type: Type.ConceptUuid,
|
|
72
|
+
_default: '1343AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
73
|
+
},
|
|
74
|
+
vitalSignsConceptSetUuid: {
|
|
75
|
+
_type: Type.ConceptUuid,
|
|
76
|
+
_default: '1114AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
weightStatusUuid: {
|
|
80
|
+
_type: Type.UUID,
|
|
81
|
+
_default: '163515AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
82
|
+
_description: 'UUID for weight status concept',
|
|
83
|
+
},
|
|
84
|
+
OpenmrsIdentifierTypeUuid: {
|
|
85
|
+
_type: Type.UUID,
|
|
86
|
+
_default: 'dfacd928-0370-4315-99d7-6ec1c9f7ae76',
|
|
87
|
+
_description: 'UUID for OpenMRS Identifier Type',
|
|
88
|
+
},
|
|
89
|
+
vitals: {
|
|
90
|
+
encounterTypeUuid: {
|
|
91
|
+
_type: Type.UUID,
|
|
92
|
+
_default: 'd1059fb9-a079-4feb-a749-eedd709ae542',
|
|
93
|
+
},
|
|
94
|
+
vitalsOverdueThresholdHours: {
|
|
95
|
+
_type: Type.Number,
|
|
96
|
+
_default: 12,
|
|
97
|
+
_description: 'Hours at or above which vitals are considered overdue',
|
|
98
|
+
},
|
|
99
|
+
useMuacColors: {
|
|
100
|
+
_type: Type.Boolean,
|
|
101
|
+
_default: true,
|
|
102
|
+
_description: 'Whether to show/use MUAC color codes. If set to true, the input will show status colors.',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
biometrics: {
|
|
106
|
+
bmiUnit: {
|
|
107
|
+
_type: Type.String,
|
|
108
|
+
_default: 'kg / m²',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export type ConfigObject = {
|
|
114
|
+
triageIcon: { src: string; alt: string };
|
|
115
|
+
triageQueueUuid: string;
|
|
116
|
+
weightStatusUuid: string;
|
|
117
|
+
OpenmrsIdentifierTypeUuid: string;
|
|
118
|
+
concepts: {
|
|
119
|
+
waitingStatusUuid: string;
|
|
120
|
+
inServiceStatusUuid: string;
|
|
121
|
+
completedStatusUuid: string;
|
|
122
|
+
systolicBloodPressureUuid: string;
|
|
123
|
+
diastolicBloodPressureUuid: string;
|
|
124
|
+
pulseUuid: string;
|
|
125
|
+
temperatureUuid: string;
|
|
126
|
+
oxygenSaturationUuid: string;
|
|
127
|
+
heightUuid: string;
|
|
128
|
+
weightUuid: string;
|
|
129
|
+
respiratoryRateUuid: string;
|
|
130
|
+
generalPatientNoteUuid: string;
|
|
131
|
+
midUpperArmCircumferenceUuid: string;
|
|
132
|
+
vitalSignsConceptSetUuid: string;
|
|
133
|
+
};
|
|
134
|
+
vitals: {
|
|
135
|
+
encounterTypeUuid: string;
|
|
136
|
+
vitalsOverdueThresholdHours: number;
|
|
137
|
+
useMuacColors: boolean;
|
|
138
|
+
};
|
|
139
|
+
biometrics: {
|
|
140
|
+
bmiUnit: string;
|
|
141
|
+
};
|
|
142
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IbmLpa, TemperatureFeelsLike } from '@carbon/react/icons';
|
|
2
|
+
|
|
3
|
+
export const dashboardMeta = {
|
|
4
|
+
name: 'triage',
|
|
5
|
+
slot: 'triage-dashboard-slot',
|
|
6
|
+
title: 'Triage queue',
|
|
7
|
+
icon: TemperatureFeelsLike,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const patientVitalsMeta = {
|
|
11
|
+
name: 'triage/patient/:patientUuid/vitals',
|
|
12
|
+
slot: 'triage-vitals-dashboard-slot',
|
|
13
|
+
title: 'Patient Vitals',
|
|
14
|
+
icon: IbmLpa,
|
|
15
|
+
showOnlyOnRoute: '/vitals',
|
|
16
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface IconWrapperProps {
|
|
4
|
+
src: string;
|
|
5
|
+
alt?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
style?: React.CSSProperties;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const IconWrapper: React.FC<IconWrapperProps> = ({
|
|
11
|
+
src,
|
|
12
|
+
alt = 'Icon',
|
|
13
|
+
className,
|
|
14
|
+
style = { width: '100px', height: '148px' },
|
|
15
|
+
}) => {
|
|
16
|
+
return <img src={src} alt={alt} className={className} style={style} />;
|
|
17
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getAsyncLifecycle, defineConfigSchema, getSyncLifecycle } from '@openmrs/esm-framework';
|
|
2
|
+
import { configSchema } from './config-schema';
|
|
3
|
+
import { dashboardMeta, patientVitalsMeta } from './dashboard.meta';
|
|
4
|
+
import { createDashboardLink } from './left-panel/left-panel.component';
|
|
5
|
+
import { TriageQueueDashboard } from './triage-queue-dashboard/triage-queue-dashboard.component';
|
|
6
|
+
import PatientVitalsHistory from './past-vitals/patient-vitals-history.component';
|
|
7
|
+
import PatientBanner from './past-vitals/patient-banner/patient-banner.component';
|
|
8
|
+
import VitalsHeader from './past-vitals/vitals-and-biometrics-header/vitals-header.extension';
|
|
9
|
+
const moduleName = '@digihmis/esm-triage-app';
|
|
10
|
+
const pageName = 'triage';
|
|
11
|
+
|
|
12
|
+
const options = {
|
|
13
|
+
featureName: pageName,
|
|
14
|
+
moduleName,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
|
|
18
|
+
|
|
19
|
+
export const leftPanelLink = getSyncLifecycle(createDashboardLink(dashboardMeta), options);
|
|
20
|
+
export const patientVitalsLink = getSyncLifecycle(createDashboardLink(patientVitalsMeta), options);
|
|
21
|
+
|
|
22
|
+
export const triageQueueDashboard = getSyncLifecycle(TriageQueueDashboard, options);
|
|
23
|
+
|
|
24
|
+
// t('patientVitals', 'Patient Vitals')
|
|
25
|
+
export const patientVitalsHistory = getSyncLifecycle(PatientVitalsHistory, options);
|
|
26
|
+
// t('recordVitals', 'Record Vitals')
|
|
27
|
+
export const recordVitalsWorkspace = getAsyncLifecycle(
|
|
28
|
+
() => import('./record-vitals-workspace/record-vitals.workspace'),
|
|
29
|
+
{
|
|
30
|
+
featureName: 'record-vitals-workspace',
|
|
31
|
+
moduleName,
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export const vitalsHeader = getSyncLifecycle(VitalsHeader, options);
|
|
36
|
+
|
|
37
|
+
export const patientBanner = getSyncLifecycle(PatientBanner, options);
|
|
38
|
+
|
|
39
|
+
export function startupApp() {
|
|
40
|
+
defineConfigSchema(moduleName, configSchema);
|
|
41
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { ConfigurableLink, MaybeIcon } from '@openmrs/esm-framework';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { BrowserRouter, useLocation, useParams } from 'react-router-dom';
|
|
5
|
+
import { type CarbonIconType } from '@carbon/react/icons';
|
|
6
|
+
import last from 'lodash-es/last';
|
|
7
|
+
import styles from './left-panel.scss';
|
|
8
|
+
|
|
9
|
+
export interface DashboardLinkConfig {
|
|
10
|
+
name: string;
|
|
11
|
+
title: string;
|
|
12
|
+
icon?: string | CarbonIconType;
|
|
13
|
+
showOnlyOnRoute?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const DashboardLink = ({ dashboardLinkConfig }: { dashboardLinkConfig: DashboardLinkConfig }) => {
|
|
17
|
+
const { t } = useTranslation();
|
|
18
|
+
const { name, title, icon, showOnlyOnRoute } = dashboardLinkConfig;
|
|
19
|
+
const location = useLocation();
|
|
20
|
+
const params = useParams();
|
|
21
|
+
const spaBasePath = window.getOpenmrsSpaBase() + 'home';
|
|
22
|
+
|
|
23
|
+
// Extract patientUuid from the current URL path if params.patientUuid is not available
|
|
24
|
+
const patientUuid = useMemo(() => {
|
|
25
|
+
if (params.patientUuid) {
|
|
26
|
+
return params.patientUuid;
|
|
27
|
+
}
|
|
28
|
+
// Extract UUID from path like /triage/UUID/vitals or /triage/patient/UUID/vitals
|
|
29
|
+
const pathParts = location.pathname.split('/');
|
|
30
|
+
const triageIndex = pathParts.indexOf('triage');
|
|
31
|
+
if (triageIndex !== -1 && pathParts.length > triageIndex + 1) {
|
|
32
|
+
const nextPart = pathParts[triageIndex + 1];
|
|
33
|
+
// Check if it's a UUID pattern (basic check)
|
|
34
|
+
if (nextPart && nextPart.length > 20 && nextPart.includes('-')) {
|
|
35
|
+
return nextPart;
|
|
36
|
+
}
|
|
37
|
+
// Check if path is /triage/patient/UUID/vitals
|
|
38
|
+
if (nextPart === 'patient' && pathParts.length > triageIndex + 2) {
|
|
39
|
+
const uuidPart = pathParts[triageIndex + 2];
|
|
40
|
+
if (uuidPart && uuidPart.length > 20 && uuidPart.includes('-')) {
|
|
41
|
+
return uuidPart;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}, [params.patientUuid, location.pathname]);
|
|
47
|
+
|
|
48
|
+
const shouldShow = useMemo(() => {
|
|
49
|
+
if (!showOnlyOnRoute) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return location.pathname.includes(showOnlyOnRoute);
|
|
53
|
+
}, [showOnlyOnRoute, location.pathname]);
|
|
54
|
+
|
|
55
|
+
const linkPath = useMemo(() => {
|
|
56
|
+
let path = name;
|
|
57
|
+
if (name.includes(':patientUuid') && patientUuid) {
|
|
58
|
+
path = name.replace(':patientUuid', patientUuid);
|
|
59
|
+
}
|
|
60
|
+
return path;
|
|
61
|
+
}, [name, patientUuid]);
|
|
62
|
+
|
|
63
|
+
const isActive = useMemo(() => {
|
|
64
|
+
if (name.includes(':patientUuid')) {
|
|
65
|
+
return location.pathname.includes('/vitals');
|
|
66
|
+
}
|
|
67
|
+
const urlSegment = decodeURIComponent(last(location.pathname.split('/')));
|
|
68
|
+
const nameSegment = name.split('/').at(-1);
|
|
69
|
+
return nameSegment === urlSegment;
|
|
70
|
+
}, [location.pathname, name]);
|
|
71
|
+
|
|
72
|
+
if (!shouldShow) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const IconComp = typeof icon !== 'string' ? (icon as CarbonIconType) : null;
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<ConfigurableLink
|
|
80
|
+
to={`${spaBasePath}/${linkPath}`}
|
|
81
|
+
className={`cds--side-nav__link ${isActive && 'active-left-nav-link'}`}>
|
|
82
|
+
{typeof icon === 'string' ? (
|
|
83
|
+
<MaybeIcon icon={icon} className={styles.icon} size={16} />
|
|
84
|
+
) : (
|
|
85
|
+
IconComp && <IconComp className={styles.icon} />
|
|
86
|
+
)}
|
|
87
|
+
{t(title)}
|
|
88
|
+
</ConfigurableLink>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const createDashboardLink = (dashboardLinkConfig: DashboardLinkConfig) => () => {
|
|
93
|
+
return (
|
|
94
|
+
<BrowserRouter>
|
|
95
|
+
<DashboardLink dashboardLinkConfig={dashboardLinkConfig} />
|
|
96
|
+
</BrowserRouter>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export default DashboardLink;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Calendar } from '@carbon/react/icons';
|
|
4
|
+
import { useSession, formatDate, ExtensionSlot, useConfig } from '@openmrs/esm-framework';
|
|
5
|
+
import styles from './page-header.scss';
|
|
6
|
+
import { ConfigObject } from '../config-schema';
|
|
7
|
+
import { IconWrapper } from '../icon-wrapper/icon-wrapper.extension';
|
|
8
|
+
|
|
9
|
+
export const PageHeader: React.FC = () => {
|
|
10
|
+
const { t } = useTranslation();
|
|
11
|
+
const userSession = useSession();
|
|
12
|
+
const { triageIcon } = useConfig<ConfigObject>();
|
|
13
|
+
const userLocation = userSession?.sessionLocation?.display;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className={styles.header}>
|
|
17
|
+
<div className={styles['left-justified-items']}>
|
|
18
|
+
<IconWrapper src={triageIcon.src} alt={triageIcon.alt} />
|
|
19
|
+
<div className={styles['page-labels']}>
|
|
20
|
+
<p className={styles['page-name']}>{userLocation}</p>
|
|
21
|
+
<p className={styles['page-subtitle']}>{t('triage', 'Triage')}</p>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
<div className={styles['right-justified-items']}>
|
|
25
|
+
<div className={styles.extensionSlot}>
|
|
26
|
+
<ExtensionSlot name={'provider-banner-slot'} />
|
|
27
|
+
<div className={styles['date-and-location']}>
|
|
28
|
+
<Calendar size={16} />
|
|
29
|
+
<span className={styles.value}>{formatDate(new Date(), { mode: 'wide', noToday: true })}</span>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '@carbon/colors';
|
|
4
|
+
|
|
5
|
+
.header {
|
|
6
|
+
@include type.type-style('body-compact-02');
|
|
7
|
+
height: layout.$spacing-12;
|
|
8
|
+
border: 1px solid colors.$gray-20;
|
|
9
|
+
border-left: 0px;
|
|
10
|
+
display: flex;
|
|
11
|
+
background: var(--cds-field);
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
margin-top: 1.5rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.left-justified-items {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: row;
|
|
19
|
+
align-items: center;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.right-justified-items {
|
|
23
|
+
@include type.type-style('body-01');
|
|
24
|
+
color: colors.$gray-80;
|
|
25
|
+
padding-top: layout.$spacing-05;
|
|
26
|
+
padding-bottom: layout.$spacing-07;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.page-subtitle {
|
|
30
|
+
@include type.type-style('caption-01');
|
|
31
|
+
color: colors.$gray-70;
|
|
32
|
+
font-size: layout.$spacing-06;
|
|
33
|
+
}
|
|
34
|
+
.page-name {
|
|
35
|
+
@include type.type-style('caption-01');
|
|
36
|
+
color: colors.$gray-80;
|
|
37
|
+
font-size: layout.$spacing-05;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.page-labels {
|
|
41
|
+
p:first-of-type {
|
|
42
|
+
margin-bottom: layout.$spacing-02;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.date-and-location {
|
|
47
|
+
margin-top: layout.$spacing-03;
|
|
48
|
+
display: flex;
|
|
49
|
+
justify-content: flex-end;
|
|
50
|
+
align-items: center;
|
|
51
|
+
margin-right: layout.$spacing-05;
|
|
52
|
+
@include type.type-style('caption-01');
|
|
53
|
+
font-size: 0.83rem;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.value {
|
|
57
|
+
margin-left: layout.$spacing-02;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.middot {
|
|
61
|
+
margin: 0 layout.$spacing-03;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.view {
|
|
65
|
+
@include type.type-style('caption-01');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
svg.iconOverrides {
|
|
69
|
+
width: 72 !important;
|
|
70
|
+
height: 72 !important;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.svgContainer svg {
|
|
74
|
+
width: 72px;
|
|
75
|
+
height: 72px;
|
|
76
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { Layer, OverflowMenu, OverflowMenuItem } from '@carbon/react';
|
|
4
|
+
import { launchWorkspace, showModal, useLayoutType } from '@openmrs/esm-framework';
|
|
5
|
+
import styles from './vitals-anthropometrics.scss';
|
|
6
|
+
|
|
7
|
+
interface VitalsAndBiometricsActionMenuProps {
|
|
8
|
+
patient: fhir.Patient;
|
|
9
|
+
encounterUuid: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const VitalsAndBiometricsActionMenu = ({ encounterUuid, patient }: VitalsAndBiometricsActionMenuProps) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const patientUuid = patient.id;
|
|
15
|
+
const isTablet = useLayoutType() === 'tablet';
|
|
16
|
+
|
|
17
|
+
const handleLaunchVitalsAndBiometricsForm = useCallback(() => {
|
|
18
|
+
launchWorkspace('record-vitals-workspace', {
|
|
19
|
+
workspaceTitle: t('editVitalsAndBiometrics', 'Edit Vitals and Biometrics'),
|
|
20
|
+
editEncounterUuid: encounterUuid,
|
|
21
|
+
patientUuid,
|
|
22
|
+
formContext: 'editing',
|
|
23
|
+
});
|
|
24
|
+
}, [encounterUuid, patientUuid, t]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Layer className={styles.layer}>
|
|
28
|
+
<OverflowMenu
|
|
29
|
+
aria-label={t('editOrDeleteVitalsAndBiometrics', 'Edit or delete Vitals and Biometrics')}
|
|
30
|
+
size={isTablet ? 'lg' : 'sm'}
|
|
31
|
+
flipped
|
|
32
|
+
iconDescription=""
|
|
33
|
+
id={encounterUuid}
|
|
34
|
+
align="end">
|
|
35
|
+
<OverflowMenuItem
|
|
36
|
+
className={styles.menuItem}
|
|
37
|
+
id="editVitalsAndBiometrics"
|
|
38
|
+
onClick={handleLaunchVitalsAndBiometricsForm}
|
|
39
|
+
itemText={t('edit', 'Edit')}
|
|
40
|
+
/>
|
|
41
|
+
</OverflowMenu>
|
|
42
|
+
</Layer>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
File without changes
|