@kenyaemr/esm-ward-app 8.5.4-pre.83 → 8.5.4-pre.9
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 +31 -0
- package/package.json +1 -1
- package/src/config-schema.ts +21 -1
- package/src/in-patient/inpatient-tabs.component.tsx +84 -3
- package/src/in-patient/labourCareGuide/alert-rules.ts +155 -41
- package/src/in-patient/labourCareGuide/components/lcg-correction-audit-banner.component.tsx +42 -0
- package/src/in-patient/labourCareGuide/constants/admission-form.constants.ts +22 -0
- package/src/in-patient/labourCareGuide/context/lcg-section-state.context.tsx +252 -0
- package/src/in-patient/labourCareGuide/forms/admission-details-form.component.tsx +71 -17
- package/src/in-patient/labourCareGuide/forms/baby-form.component.tsx +55 -179
- package/src/in-patient/labourCareGuide/forms/labour-care-guide-forms.component.tsx +74 -29
- package/src/in-patient/labourCareGuide/forms/labour-progress-form.component.tsx +163 -216
- package/src/in-patient/labourCareGuide/forms/lcg-session-correction-wizard.component.tsx +214 -0
- package/src/in-patient/labourCareGuide/forms/medication-form.component.tsx +598 -220
- package/src/in-patient/labourCareGuide/forms/shared-decision-assessment-field.component.tsx +109 -0
- package/src/in-patient/labourCareGuide/forms/shared-decision-making-form.component.tsx +206 -191
- package/src/in-patient/labourCareGuide/forms/supportive-care-form.component.tsx +33 -90
- package/src/in-patient/labourCareGuide/forms/time-form.component.tsx +12 -4
- package/src/in-patient/labourCareGuide/forms/time-picker-dropdown.component.tsx +168 -53
- package/src/in-patient/labourCareGuide/forms/woman-form.component.tsx +51 -79
- package/src/in-patient/labourCareGuide/global-cds-alerts/global-cds-alert-context.tsx +2 -2
- package/src/in-patient/labourCareGuide/graphs/labour-progress.component.tsx +188 -86
- package/src/in-patient/labourCareGuide/graphs/medication.component.tsx +15 -23
- package/src/in-patient/labourCareGuide/graphs/shared-decision-making.component.tsx +172 -79
- package/src/in-patient/labourCareGuide/graphs/supportive-care.component.tsx +4 -1
- package/src/in-patient/labourCareGuide/graphs/woman.component.tsx +3 -39
- package/src/in-patient/labourCareGuide/hooks/use-lcg-data.ts +556 -205
- package/src/in-patient/labourCareGuide/hooks/use-lcg-debounced-value.ts +17 -0
- package/src/in-patient/labourCareGuide/hooks/use-lcg-form-clock.ts +36 -0
- package/src/in-patient/labourCareGuide/hooks/use-lcg-section-autosave.ts +33 -0
- package/src/in-patient/labourCareGuide/labour-care-guide.component.tsx +693 -68
- package/src/in-patient/labourCareGuide/labour-care-guide.scss +49 -14
- package/src/in-patient/labourCareGuide/labour-care-guide.utils.ts +148 -6
- package/src/in-patient/labourCareGuide/lcg-alert-lifecycle.ts +161 -0
- package/src/in-patient/labourCareGuide/partography-data-form.scss +149 -3
- package/src/in-patient/labourCareGuide/partography.resource.ts +15 -27
- package/src/in-patient/labourCareGuide/resources/admission-details.resource.ts +26 -25
- package/src/in-patient/labourCareGuide/resources/drug-stock.resource.ts +98 -0
- package/src/in-patient/labourCareGuide/resources/labour-progress.resource.ts +34 -2
- package/src/in-patient/labourCareGuide/resources/lcg-session-correction.resource.ts +1027 -0
- package/src/in-patient/labourCareGuide/resources/medication.resource.ts +241 -37
- package/src/in-patient/labourCareGuide/resources/shared-decision-making.resource.ts +37 -3
- package/src/in-patient/labourCareGuide/resources/supportive-care.resource.ts +53 -5
- package/src/in-patient/labourCareGuide/storage/lcg-local-storage.ts +374 -0
- package/src/in-patient/labourCareGuide/time-slot-utils.ts +180 -26
- package/src/in-patient/labourCareGuide/types/concept-uuids.constants.ts +21 -0
- package/src/in-patient/labourCareGuide/types/index.ts +31 -7
- package/src/in-patient/treatmentChart/nursing-cardex-payload-builder.ts +9 -0
- package/src/in-patient/treatmentChart/nursing-cardex-plan.resource.ts +22 -6
- package/src/in-patient/treatmentChart/nursing-cardex-plan.workspace.scss +7 -1
- package/src/in-patient/treatmentChart/nursing-cardex-plan.workspace.tsx +20 -0
- package/src/in-patient/treatmentChart/nursing-treatment-sheet.resource.ts +27 -2
- package/src/in-patient/treatmentChart/treatment-chart-dashboard.component.tsx +2 -0
- package/src/in-patient/treatmentChart/use-nursing-cardex-form-schema.ts +2 -0
- package/src/index.ts +17 -0
- package/src/routes.json +20 -0
- package/src/ward-patients/ward-patients-slots.ts +21 -0
- package/src/ward-patients/ward-patients-table.test.tsx +58 -0
- package/src/ward-patients/ward-patients-table.tsx +25 -8
- package/translations/en.json +358 -26
- package/translations/fr.json +359 -26
- package/.turbo/turbo-build.log +0 -8
- package/dist/1084.js +0 -1
- package/dist/1084.js.map +0 -1
- package/dist/1189.js +0 -1
- package/dist/1189.js.map +0 -1
- package/dist/12.js +0 -17
- package/dist/12.js.map +0 -1
- package/dist/126.js +0 -1
- package/dist/1308.js +0 -1
- package/dist/1308.js.map +0 -1
- package/dist/1374.js +0 -1
- package/dist/1374.js.map +0 -1
- package/dist/1387.js +0 -1
- package/dist/1387.js.map +0 -1
- package/dist/15.js +0 -1
- package/dist/1564.js +0 -1
- package/dist/1567.js +0 -1
- package/dist/1567.js.map +0 -1
- package/dist/1739.js +0 -1
- package/dist/1739.js.map +0 -1
- package/dist/1845.js +0 -1
- package/dist/1972.js +0 -1
- package/dist/1972.js.map +0 -1
- package/dist/2016.js +0 -1
- package/dist/2016.js.map +0 -1
- package/dist/2117.js +0 -1
- package/dist/2117.js.map +0 -1
- package/dist/215.js +0 -1
- package/dist/2178.js +0 -1
- package/dist/239.js +0 -1
- package/dist/239.js.map +0 -1
- package/dist/2486.js +0 -1
- package/dist/2486.js.map +0 -1
- package/dist/2566.js +0 -1
- package/dist/2710.js +0 -1
- package/dist/2710.js.map +0 -1
- package/dist/2759.js +0 -1
- package/dist/2823.js +0 -15
- package/dist/2823.js.map +0 -1
- package/dist/3089.js +0 -1
- package/dist/3089.js.map +0 -1
- package/dist/3230.js +0 -1
- package/dist/3261.js +0 -1
- package/dist/3261.js.map +0 -1
- package/dist/3321.js +0 -1
- package/dist/3321.js.map +0 -1
- package/dist/3350.js +0 -1
- package/dist/3399.js +0 -1
- package/dist/3399.js.map +0 -1
- package/dist/3441.js +0 -1
- package/dist/3547.js +0 -1
- package/dist/3547.js.map +0 -1
- package/dist/3548.js +0 -1
- package/dist/3548.js.map +0 -1
- package/dist/3565.js +0 -1
- package/dist/3571.js +0 -1
- package/dist/3571.js.map +0 -1
- package/dist/364.js +0 -1
- package/dist/364.js.map +0 -1
- package/dist/3746.js +0 -1
- package/dist/3925.js +0 -1
- package/dist/3946.js +0 -1
- package/dist/401.js +0 -1
- package/dist/401.js.map +0 -1
- package/dist/4032.js +0 -1
- package/dist/4032.js.map +0 -1
- package/dist/4206.js +0 -1
- package/dist/4206.js.map +0 -1
- package/dist/4480.js +0 -1
- package/dist/4480.js.map +0 -1
- package/dist/4635.js +0 -1
- package/dist/4635.js.map +0 -1
- package/dist/4684.js +0 -1
- package/dist/4684.js.map +0 -1
- package/dist/4735.js +0 -1
- package/dist/4735.js.map +0 -1
- package/dist/4744.js +0 -1
- package/dist/4744.js.map +0 -1
- package/dist/4894.js +0 -1
- package/dist/4970.js +0 -1
- package/dist/4970.js.map +0 -1
- package/dist/5069.js +0 -1
- package/dist/5069.js.map +0 -1
- package/dist/5090.js +0 -1
- package/dist/5090.js.map +0 -1
- package/dist/5130.js +0 -1
- package/dist/5187.js +0 -1
- package/dist/5411.js +0 -1
- package/dist/5411.js.map +0 -1
- package/dist/5441.js +0 -1
- package/dist/5441.js.map +0 -1
- package/dist/5491.js +0 -1
- package/dist/5491.js.map +0 -1
- package/dist/5496.js +0 -1
- package/dist/5496.js.map +0 -1
- package/dist/5595.js +0 -1
- package/dist/5659.js +0 -1
- package/dist/5659.js.map +0 -1
- package/dist/5706.js +0 -1
- package/dist/5706.js.map +0 -1
- package/dist/5961.js +0 -1
- package/dist/6061.js +0 -1
- package/dist/6061.js.map +0 -1
- package/dist/6133.js +0 -1
- package/dist/6180.js +0 -1
- package/dist/6180.js.map +0 -1
- package/dist/6296.js +0 -1
- package/dist/6296.js.map +0 -1
- package/dist/6322.js +0 -1
- package/dist/6322.js.map +0 -1
- package/dist/6381.js +0 -1
- package/dist/6381.js.map +0 -1
- package/dist/6455.js +0 -1
- package/dist/6455.js.map +0 -1
- package/dist/6456.js +0 -1
- package/dist/6466.js +0 -1
- package/dist/6613.js +0 -1
- package/dist/6783.js +0 -1
- package/dist/6925.js +0 -1
- package/dist/6925.js.map +0 -1
- package/dist/7091.js +0 -1
- package/dist/7091.js.map +0 -1
- package/dist/7263.js +0 -1
- package/dist/7263.js.map +0 -1
- package/dist/7348.js +0 -1
- package/dist/7431.js +0 -1
- package/dist/7431.js.map +0 -1
- package/dist/7543.js +0 -1
- package/dist/7607.js +0 -1
- package/dist/762.js +0 -1
- package/dist/762.js.map +0 -1
- package/dist/772.js +0 -1
- package/dist/775.js +0 -1
- package/dist/775.js.map +0 -1
- package/dist/8171.js +0 -1
- package/dist/8171.js.map +0 -1
- package/dist/8488.js +0 -1
- package/dist/8488.js.map +0 -1
- package/dist/8727.js +0 -1
- package/dist/8736.js +0 -1
- package/dist/8736.js.map +0 -1
- package/dist/8847.js +0 -1
- package/dist/9009.js +0 -1
- package/dist/9009.js.map +0 -1
- package/dist/9015.js +0 -1
- package/dist/906.js +0 -1
- package/dist/9065.js +0 -1
- package/dist/9182.js +0 -1
- package/dist/9314.js +0 -1
- package/dist/9314.js.map +0 -1
- package/dist/9339.js +0 -1
- package/dist/9361.js +0 -1
- package/dist/9361.js.map +0 -1
- package/dist/9453.js +0 -1
- package/dist/9465.js +0 -1
- package/dist/9465.js.map +0 -1
- package/dist/9535.js +0 -22
- package/dist/9535.js.map +0 -1
- package/dist/9610.js +0 -1
- package/dist/9610.js.map +0 -1
- package/dist/9668.js +0 -1
- package/dist/9668.js.map +0 -1
- package/dist/9727.js +0 -1
- package/dist/9727.js.map +0 -1
- package/dist/9734.js +0 -1
- package/dist/9734.js.map +0 -1
- package/dist/9833.js +0 -1
- package/dist/9833.js.map +0 -1
- package/dist/9848.js +0 -1
- package/dist/9848.js.map +0 -1
- package/dist/9876.js +0 -1
- package/dist/9876.js.map +0 -1
- package/dist/9920.js +0 -1
- package/dist/9938.js +0 -1
- package/dist/kenyaemr-esm-ward-app.js +0 -5
- package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +0 -2723
- package/dist/kenyaemr-esm-ward-app.js.map +0 -1
- package/dist/main.js +0 -5
- package/dist/main.js.map +0 -1
- package/dist/routes.json +0 -1
package/README.md
CHANGED
|
@@ -22,6 +22,37 @@ Please see the [EMR API README](https://github.com/openmrs/openmrs-module-emrapi
|
|
|
22
22
|
|
|
23
23
|
See the [config-schema](./src/config-schema.ts) for details on the configuration options available to the ward app.
|
|
24
24
|
|
|
25
|
+
## Ward Patient Table Tab Extension Slots
|
|
26
|
+
|
|
27
|
+
The default ward table view renders four fixed tabs (Awaiting Admission, Admitted, Discharge In, Discharged). Each tab panel is backed by an extension slot so implementers can replace the default table UI without forking the ward app.
|
|
28
|
+
|
|
29
|
+
| Tab | Slot name | Default extension name |
|
|
30
|
+
|-----|-----------|------------------------|
|
|
31
|
+
| Awaiting Admission | `ward-patients-awaiting-admission-slot` | `ward-patients-awaiting-admission` |
|
|
32
|
+
| Admitted | `ward-patients-admitted-slot` | `ward-patients-admitted` |
|
|
33
|
+
| Discharge In | `ward-patients-discharge-in-slot` | `ward-patients-discharge-in` |
|
|
34
|
+
| Discharged | `ward-patients-discharged-slot` | `ward-patients-discharged` |
|
|
35
|
+
|
|
36
|
+
### Custom component requirements
|
|
37
|
+
|
|
38
|
+
- Render under `DefaultWardView` so `useAppContext('ward-view-context')` provides ward patient data.
|
|
39
|
+
- Reuse types from [`src/types/index.ts`](./src/types/index.ts): `WardViewContext`, `WardPatient`, etc.
|
|
40
|
+
- Optional shared UI helpers: `HyperLinkPatientCell`, `EmptyState`, `ErrorState`, `getOpenmrsId`.
|
|
41
|
+
|
|
42
|
+
### Replacing a default table
|
|
43
|
+
|
|
44
|
+
In your module's `routes.json`, register the replacement extension:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"name": "my-custom-awaiting-admission",
|
|
49
|
+
"component": "myAwaitingAdmissionTable",
|
|
50
|
+
"slot": "ward-patients-awaiting-admission-slot"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The default table components are exported from this module (`wardPatientsAwaitingAdmissionTable`, `wardPatientsAdmittedTable`, `wardPatientsDischargeInTable`, `wardPatientsDischargedTable`) if you need to wrap or extend them.
|
|
55
|
+
|
|
25
56
|
## Bed Management
|
|
26
57
|
|
|
27
58
|
The ward app is designed to support patient bed assignments and to be used in conjunction with the bedmanagement module and the bed-management-app ESM. However, bed management is entirely optional. Patients will appear on a ward if they:
|
package/package.json
CHANGED
package/src/config-schema.ts
CHANGED
|
@@ -45,6 +45,7 @@ export const labourCareGuideConceptUuids = {
|
|
|
45
45
|
UUID_URINE_ONE_PLUS: '1362AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
46
46
|
UUID_URINE_TWO_PLUS: '1363AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
47
47
|
UUID_URINE_THREE_PLUS: '1364AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
48
|
+
UUID_URINE_NOT_DONE: '1118AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
48
49
|
UUID_URINE_TEST_TIME_SLOT: 'bb3724c9-fbcc-49c5-9702-6cde0be325ca',
|
|
49
50
|
UUID_PARTOGRAPHY_ENCOUNTER: '022d62af-e2a5-4282-953b-52dd5cba3296',
|
|
50
51
|
UUID_MEDICATION_OXYTOCIN_ADMINISTERED: '82580974-ff46-41c5-b218-4bea7f53bf7e',
|
|
@@ -83,6 +84,19 @@ export const labourCareGuideConceptUuids = {
|
|
|
83
84
|
UUID_URGE_TO_PUSH: '9ad5b56d-597c-4a40-ade6-387802daa44a',
|
|
84
85
|
UUID_EMERGENCY_OVERRIDE: '1670AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
85
86
|
UUID_EMERGENCY_REASON: '163761AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
87
|
+
UUID_SHARED_DECISION_TERMINATE_ONGOING_PROGRESS: '737fa73a-509f-40d8-9e84-91dc71db7f4c',
|
|
88
|
+
UUID_LCG_TERMINATION_REASON_TYPE: '6098AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
89
|
+
UUID_LCG_TERMINATION_REASON_WRONG_PATIENT: '164144AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
90
|
+
UUID_LCG_TERMINATION_REASON_OTHER: '5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
91
|
+
UUID_LCG_CORRECTION_ENCOUNTER_TYPE: 'b2c4d5e6-7f8a-4e9b-8c1d-2e3f8e4a3b8f',
|
|
92
|
+
UUID_LCG_CORRECTION_TYPE: '4b3eb27b-43c0-4862-bd83-be06beb3d699',
|
|
93
|
+
UUID_LCG_CORRECTION_TYPE_WRONG_PATIENT_TRANSFER: '1286AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
94
|
+
UUID_LCG_CORRECTION_SOURCE_PATIENT_UUID: '162720AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
95
|
+
UUID_LCG_CORRECTION_SOURCE_TERMINATE_ENCOUNTER_UUID: '1671AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
96
|
+
UUID_LCG_CORRECTION_TERMINATION_REASON: '162704AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
97
|
+
UUID_LCG_CORRECTION_SOURCE_PATIENT_DISPLAY: '850a960b-e8b5-4775-ba74-aaddb2abbf51',
|
|
98
|
+
UUID_LCG_CORRECTION_TERMINATED_AT: '163286AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
99
|
+
UUID_LCG_CORRECTION_TRANSFER_NOTES: '1056dc03-ce4d-45cb-a1eb-87707162e6ee',
|
|
86
100
|
FETAL_HEART_RATE_CONCEPT: '1440AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
87
101
|
FETAL_HEART_RATE_TIME_CONCEPT: 'bb3724c9-fbcc-49c5-9702-6cde0be325ca',
|
|
88
102
|
FETAL_HEART_RATE_HOUR_CONCEPT: '160632AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
@@ -98,7 +112,7 @@ export const labourCareGuideConceptUuids = {
|
|
|
98
112
|
CONTRACTION_LEVEL_MODERATE_CONCEPT: '1499AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
99
113
|
CONTRACTION_LEVEL_STRONG_CONCEPT: '166788AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
100
114
|
UTERINE_CONTRACTION_FREQUENCY_CONCEPT: 'd266dee4-bbe8-4736-b94d-c33300f55bca',
|
|
101
|
-
UTERINE_CONTRACTION_DURATION_CONCEPT: '
|
|
115
|
+
UTERINE_CONTRACTION_DURATION_CONCEPT: '159368AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
102
116
|
OXYTOCIN_TIME_CONCEPT: 'bb3724c9-fbcc-49c5-9702-6cde0be325ca',
|
|
103
117
|
OXYTOCIN_DROPS_PER_MINUTE_CONCEPT: '1d109b10-7b30-4bfa-8a7c-6ecb73357fc2',
|
|
104
118
|
OXYTOCIN_DOSE_CONCEPT: '81369AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
@@ -920,6 +934,11 @@ export const configSchema: ConfigSchema = {
|
|
|
920
934
|
_description: 'Labour care guide partography module configuration',
|
|
921
935
|
_default: labourCareGuidePartographyConfig,
|
|
922
936
|
},
|
|
937
|
+
lcgSessionCorrectionPrivilege: {
|
|
938
|
+
_type: Type.String,
|
|
939
|
+
_description: 'OpenMRS privilege required to open the LCG wrong-patient correction wizard',
|
|
940
|
+
_default: 'Correct LCG Wrong Patient',
|
|
941
|
+
},
|
|
923
942
|
} as const;
|
|
924
943
|
|
|
925
944
|
export interface WardConfigObject {
|
|
@@ -1030,6 +1049,7 @@ export interface WardConfigObject {
|
|
|
1030
1049
|
treatmentChartNameConceptUuid: string;
|
|
1031
1050
|
treatmentChartTimeConceptUuid: string;
|
|
1032
1051
|
partography: LabourCareGuidePartographyConfig;
|
|
1052
|
+
lcgSessionCorrectionPrivilege: string;
|
|
1033
1053
|
}
|
|
1034
1054
|
export interface PendingItemsElementConfig {
|
|
1035
1055
|
id: string;
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ExtensionSlot,
|
|
7
7
|
type FHIRResource,
|
|
8
8
|
useAssignedExtensions,
|
|
9
|
+
useConfig,
|
|
9
10
|
usePatient,
|
|
10
11
|
useRenderableExtensions,
|
|
11
12
|
} from '@openmrs/esm-framework';
|
|
@@ -14,14 +15,71 @@ import { useTranslation } from 'react-i18next';
|
|
|
14
15
|
import { ComponentContext, translateFrom } from '@openmrs/esm-framework/src/internal';
|
|
15
16
|
import styles from './inpatient.scss';
|
|
16
17
|
import { moduleName } from '../constant';
|
|
18
|
+
import useCurrentPatientAdmissionEncounter from '../hooks/useCurrentPatientAdmissionEncounter';
|
|
19
|
+
import { useAdmissionLocationTags } from './in-patient.resource';
|
|
20
|
+
import type { WardConfigObject } from '../config-schema';
|
|
17
21
|
|
|
18
22
|
type InpatientTabsProps = {
|
|
19
23
|
patientUuid: string;
|
|
20
24
|
};
|
|
21
25
|
const INPATIENT_TABS_EXTENSION_SLOT = 'inpatient-dashboard-tabs-slot';
|
|
26
|
+
const LABOUR_CARE_GUIDE_EXTENSION_NAME = 'maternal-and-child-health-labour-care-guide';
|
|
27
|
+
|
|
28
|
+
const getPatientGenderValue = (patient: any): string => {
|
|
29
|
+
const gender = patient?.gender;
|
|
30
|
+
if (typeof gender === 'string') {
|
|
31
|
+
return gender;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (gender && typeof gender === 'object') {
|
|
35
|
+
return String(gender.display ?? gender.name ?? gender.value ?? '');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return '';
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const isFemalePatient = (patient: any): boolean => {
|
|
42
|
+
const gender = getPatientGenderValue(patient).trim().toLowerCase();
|
|
43
|
+
return gender === 'f' || gender === 'female' || gender.startsWith('female ');
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getPatientAge = (patient: any): number => {
|
|
47
|
+
const ageFromPatient = Number(patient?.age);
|
|
48
|
+
if (Number.isFinite(ageFromPatient)) {
|
|
49
|
+
return ageFromPatient;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const birthDate = patient?.birthDate;
|
|
53
|
+
if (!birthDate) {
|
|
54
|
+
return NaN;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const birth = new Date(birthDate);
|
|
58
|
+
if (Number.isNaN(birth.getTime())) {
|
|
59
|
+
return NaN;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const now = new Date();
|
|
63
|
+
let age = now.getFullYear() - birth.getFullYear();
|
|
64
|
+
const hasNotHadBirthdayYet =
|
|
65
|
+
now.getMonth() < birth.getMonth() || (now.getMonth() === birth.getMonth() && now.getDate() < birth.getDate());
|
|
66
|
+
if (hasNotHadBirthdayYet) {
|
|
67
|
+
age -= 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return age;
|
|
71
|
+
};
|
|
72
|
+
|
|
22
73
|
const InpatientTabs: FC<InpatientTabsProps> = ({ patientUuid }) => {
|
|
23
74
|
const { t } = useTranslation();
|
|
24
75
|
const { patient, isLoading, error } = usePatient(patientUuid);
|
|
76
|
+
const { inpatientLocationTags } = useConfig<WardConfigObject>();
|
|
77
|
+
const {
|
|
78
|
+
admissionEncounter,
|
|
79
|
+
isLoading: isLoadingAdmission,
|
|
80
|
+
isPatientAdmitted,
|
|
81
|
+
} = useCurrentPatientAdmissionEncounter(patientUuid);
|
|
82
|
+
const { tags, isLoading: isLoadingTags } = useAdmissionLocationTags(admissionEncounter?.location?.uuid);
|
|
25
83
|
const state = useMemo(() => ({ patientUuid, patient }), [patientUuid, patient]);
|
|
26
84
|
const assignedExtensions = useAssignedExtensions(INPATIENT_TABS_EXTENSION_SLOT);
|
|
27
85
|
const extensions = useRenderableExtensions(INPATIENT_TABS_EXTENSION_SLOT);
|
|
@@ -32,7 +90,30 @@ const InpatientTabs: FC<InpatientTabsProps> = ({ patientUuid }) => {
|
|
|
32
90
|
(a.order ?? Infinity) - (b.order ?? Infinity),
|
|
33
91
|
);
|
|
34
92
|
}, [assignedExtensions]);
|
|
35
|
-
|
|
93
|
+
|
|
94
|
+
const isAdmittedToAllowedWard = useMemo(() => {
|
|
95
|
+
const allowedWardTags = [
|
|
96
|
+
inpatientLocationTags?.labourWard,
|
|
97
|
+
inpatientLocationTags?.antenatalWard,
|
|
98
|
+
inpatientLocationTags?.maternityWard,
|
|
99
|
+
].filter(Boolean);
|
|
100
|
+
return allowedWardTags.some((tagUuid) => tags.some((tag) => tag.uuid === tagUuid));
|
|
101
|
+
}, [inpatientLocationTags, tags]);
|
|
102
|
+
|
|
103
|
+
const canShowLabourCareGuideTab = useMemo(() => {
|
|
104
|
+
const age = getPatientAge(patient);
|
|
105
|
+
return isFemalePatient(patient) && Number.isFinite(age) && age > 9 && isPatientAdmitted && isAdmittedToAllowedWard;
|
|
106
|
+
}, [patient, isPatientAdmitted, isAdmittedToAllowedWard]);
|
|
107
|
+
|
|
108
|
+
const visibleExtensions = useMemo(
|
|
109
|
+
() =>
|
|
110
|
+
sortedExtensions.filter(
|
|
111
|
+
(extension) => extension.name !== LABOUR_CARE_GUIDE_EXTENSION_NAME || canShowLabourCareGuideTab,
|
|
112
|
+
),
|
|
113
|
+
[sortedExtensions, canShowLabourCareGuideTab],
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
if (isLoading || isLoadingAdmission || isLoadingTags) {
|
|
36
117
|
return <TabsSkeleton />;
|
|
37
118
|
}
|
|
38
119
|
|
|
@@ -43,14 +124,14 @@ const InpatientTabs: FC<InpatientTabsProps> = ({ patientUuid }) => {
|
|
|
43
124
|
<Layer>
|
|
44
125
|
<Tabs>
|
|
45
126
|
<TabList contained>
|
|
46
|
-
{
|
|
127
|
+
{visibleExtensions.map((ext) => (
|
|
47
128
|
<Tab key={ext.name}>{translateFrom(ext.moduleName, ext.meta.title, ext.meta.title)}</Tab>
|
|
48
129
|
))}
|
|
49
130
|
</TabList>
|
|
50
131
|
<TabPanels
|
|
51
132
|
data-extension-slot-name={INPATIENT_TABS_EXTENSION_SLOT}
|
|
52
133
|
data-extension-slot-module-name={moduleName}>
|
|
53
|
-
{
|
|
134
|
+
{visibleExtensions.map((ext) => (
|
|
54
135
|
<TabPanel key={ext.name}>
|
|
55
136
|
<ComponentContext.Provider
|
|
56
137
|
key={ext.id}
|
|
@@ -29,13 +29,15 @@ export const isSupportiveAlertValue = (rowKey: SupportiveAlertKey, rawValue: str
|
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
const isNoValue = value === 'N' || value === 'NO' || value.includes('1066');
|
|
33
|
+
|
|
32
34
|
switch (rowKey) {
|
|
33
35
|
case 'posture':
|
|
34
|
-
return value === 'SP';
|
|
36
|
+
return value === 'SP' || value.includes('SUPINE');
|
|
35
37
|
case 'companion':
|
|
36
38
|
case 'painRelief':
|
|
37
39
|
case 'oralFluid':
|
|
38
|
-
return
|
|
40
|
+
return isNoValue;
|
|
39
41
|
default:
|
|
40
42
|
return false;
|
|
41
43
|
}
|
|
@@ -46,22 +48,22 @@ export const getSupportiveAlertGuidance = (t: TFunction, rowKey: SupportiveAlert
|
|
|
46
48
|
case 'companion':
|
|
47
49
|
return t(
|
|
48
50
|
'supportiveCompanionAlertGuidance',
|
|
49
|
-
|
|
51
|
+
"Companion N: Immediately facilitate the woman's chosen companion to be present and oriented in the room. If unavailable, assign a dedicated midwife, nurse, or doula for continuous one-on-one support.",
|
|
50
52
|
);
|
|
51
53
|
case 'painRelief':
|
|
52
54
|
return t(
|
|
53
55
|
'supportivePainReliefAlertGuidance',
|
|
54
|
-
'Pain relief N:
|
|
56
|
+
'Pain relief N: Assess pain using a standard scale, offer non-pharmacological options first (breathing, massage, warm compress, position changes), and give prescribed pharmacological analgesia if needed per protocol.',
|
|
55
57
|
);
|
|
56
58
|
case 'oralFluid':
|
|
57
59
|
return t(
|
|
58
60
|
'supportiveOralFluidAlertGuidance',
|
|
59
|
-
'Oral fluid N:
|
|
61
|
+
'Oral fluid N: Encourage oral hydration and energy fluids (water, clear juice, isotonic drinks) unless there is a clear documented contraindication such as imminent general anesthesia.',
|
|
60
62
|
);
|
|
61
63
|
case 'posture':
|
|
62
64
|
return t(
|
|
63
65
|
'supportivePostureAlertGuidance',
|
|
64
|
-
|
|
66
|
+
'Posture SP: Encourage walking or upright mobility; if in bed, support lateral, upright, or semi-recumbent positions. Avoid prolonged supine position to reduce aortocaval compression risk.',
|
|
65
67
|
);
|
|
66
68
|
default:
|
|
67
69
|
return '';
|
|
@@ -94,32 +96,32 @@ export const getSupportiveAlertTokenGuidance = (t: TFunction, token: string) =>
|
|
|
94
96
|
if (normalized.includes('COMPANION')) {
|
|
95
97
|
return t(
|
|
96
98
|
'supportiveCompanionTokenHoverGuidance',
|
|
97
|
-
|
|
99
|
+
"Companion N: Immediately facilitate the woman's chosen companion to be present and oriented in the room. If unavailable, assign a dedicated midwife, nurse, or doula for continuous one-on-one support.",
|
|
98
100
|
);
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
if (normalized.includes('PAIN RELIEF')) {
|
|
102
104
|
return t(
|
|
103
105
|
'supportivePainReliefTokenHoverGuidance',
|
|
104
|
-
'Pain relief N:
|
|
106
|
+
'Pain relief N: Assess pain using a standard scale, offer non-pharmacological options first (breathing, massage, warm compress, position changes), and give prescribed pharmacological analgesia if needed per protocol.',
|
|
105
107
|
);
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
if (normalized.includes('ORAL FLUID')) {
|
|
109
111
|
return t(
|
|
110
112
|
'supportiveOralFluidTokenHoverGuidance',
|
|
111
|
-
'Oral fluid N:
|
|
113
|
+
'Oral fluid N: Encourage oral hydration and energy fluids (water, clear juice, isotonic drinks) unless there is a clear documented contraindication such as imminent general anesthesia.',
|
|
112
114
|
);
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
if (normalized.startsWith('SP')) {
|
|
116
118
|
return t(
|
|
117
119
|
'supportivePostureTokenHoverGuidance',
|
|
118
|
-
|
|
120
|
+
'Posture SP: Encourage walking or upright mobility; if in bed, support lateral, upright, or semi-recumbent positions. Avoid prolonged supine position to reduce aortocaval compression risk.',
|
|
119
121
|
);
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
return t('supportiveTokenHoverPlaceholder', '
|
|
124
|
+
return t('supportiveTokenHoverPlaceholder', 'Supportive-care alert: correct the identified care gap immediately.');
|
|
123
125
|
};
|
|
124
126
|
|
|
125
127
|
export const getBabyAlertTokenGuidance = (t: TFunction, _token: string) => {
|
|
@@ -131,40 +133,49 @@ export const getBabyAlertTokenGuidance = (t: TFunction, _token: string) => {
|
|
|
131
133
|
if (normalized.includes('BASELINE FHR')) {
|
|
132
134
|
return t(
|
|
133
135
|
'babyBaselineFhrTokenHoverGuidance',
|
|
134
|
-
`Baseline FHR ${code}:
|
|
136
|
+
`Baseline FHR ${code}: Reposition mother to left lateral, give IV fluids if hypotensive, and reduce/stop oxytocin if hyperstimulation is present. Reassess FHR promptly; if persistent, start continuous fetal monitoring and prepare for expedited delivery if distress is confirmed.`,
|
|
135
137
|
);
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
if (normalized.includes('FHR DECELERATION')) {
|
|
139
|
-
return t(
|
|
141
|
+
return t(
|
|
142
|
+
'babyFhrDecelerationTokenHoverGuidance',
|
|
143
|
+
'FHR deceleration: optimize maternal position and perfusion, reassess immediately, and escalate to continuous monitoring. Prepare expedited delivery if abnormal tracing persists.',
|
|
144
|
+
);
|
|
140
145
|
}
|
|
141
146
|
|
|
142
147
|
if (normalized.includes('AMNIOTIC FLUID')) {
|
|
143
148
|
return t(
|
|
144
149
|
'babyAmnioticFluidTokenHoverGuidance',
|
|
145
|
-
`Amniotic fluid ${code}:
|
|
150
|
+
`Amniotic fluid ${code}: For thick meconium, increase FHR surveillance or initiate continuous CTG. For foul-smelling liquor, start broad-spectrum IV antibiotics for suspected chorioamnionitis, monitor maternal temperature closely, and prepare neonatal resuscitation support.`,
|
|
146
151
|
);
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
if (normalized.includes('FETAL POSITION')) {
|
|
150
155
|
return t(
|
|
151
156
|
'babyFetalPositionTokenHoverGuidance',
|
|
152
|
-
`Fetal position ${code}:
|
|
157
|
+
`Fetal position ${code}: reassess position and descent trend, support corrective maternal positioning, and escalate obstetric review if persistent malposition is associated with poor progress.`,
|
|
153
158
|
);
|
|
154
159
|
}
|
|
155
160
|
|
|
156
161
|
if (normalized.includes('CAPUT')) {
|
|
157
|
-
return t(
|
|
162
|
+
return t(
|
|
163
|
+
'babyCaputTokenHoverGuidance',
|
|
164
|
+
'Caput +++: reassess for possible cephalopelvic disproportion or malposition, correlate with cervical progress/descent, and prepare operative delivery if labour is not progressing safely.',
|
|
165
|
+
);
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
if (normalized.includes('MOULDING')) {
|
|
161
169
|
return t(
|
|
162
170
|
'babyMouldingTokenHoverGuidance',
|
|
163
|
-
'Moulding +++:
|
|
171
|
+
'Moulding +++: reassess for possible cephalopelvic disproportion or malposition, correlate with cervical progress/descent, and prepare operative delivery if labour is not progressing safely.',
|
|
164
172
|
);
|
|
165
173
|
}
|
|
166
174
|
|
|
167
|
-
return t(
|
|
175
|
+
return t(
|
|
176
|
+
'babyTokenHoverPlaceholder',
|
|
177
|
+
'Baby alert: optimize fetal condition and escalate monitoring/intervention promptly.',
|
|
178
|
+
);
|
|
168
179
|
};
|
|
169
180
|
|
|
170
181
|
export const isBabyAlertValue = (rowKey: BabyAlertKey, rawValue: string) => {
|
|
@@ -181,9 +192,16 @@ export const isBabyAlertValue = (rowKey: BabyAlertKey, rawValue: string) => {
|
|
|
181
192
|
return Number.isFinite(numericValue) && (numericValue < 110 || numericValue >= 160);
|
|
182
193
|
}
|
|
183
194
|
case 'fhrDeceleration':
|
|
184
|
-
return value === 'L';
|
|
195
|
+
return value === 'L' || value.includes('LATE');
|
|
185
196
|
case 'amnioticFluid':
|
|
186
|
-
return
|
|
197
|
+
return (
|
|
198
|
+
value === 'B' ||
|
|
199
|
+
value === 'M' ||
|
|
200
|
+
value === 'M+' ||
|
|
201
|
+
value === 'M++' ||
|
|
202
|
+
value === 'M+++' ||
|
|
203
|
+
value.startsWith('M+')
|
|
204
|
+
);
|
|
187
205
|
case 'fetalPosition':
|
|
188
206
|
return value === 'P' || value === 'T';
|
|
189
207
|
case 'caput':
|
|
@@ -199,29 +217,32 @@ export const getBabyAlertGuidance = (t: TFunction, rowKey: BabyAlertKey) => {
|
|
|
199
217
|
case 'baselineFhr':
|
|
200
218
|
return t(
|
|
201
219
|
'babyBaselineFhrAlertGuidance',
|
|
202
|
-
'Baseline FHR:
|
|
220
|
+
'Baseline FHR alert: reposition left lateral, optimize perfusion, stop/reduce oxytocin if needed, reassess quickly, and escalate to continuous monitoring with expedited delivery preparation when persistent.',
|
|
203
221
|
);
|
|
204
222
|
case 'fhrDeceleration':
|
|
205
223
|
return t(
|
|
206
224
|
'babyFhrDecelerationAlertGuidance',
|
|
207
|
-
'FHR deceleration
|
|
225
|
+
'FHR deceleration alert: optimize maternal condition and monitor continuously; prepare for expedited delivery if recurrent or persistent.',
|
|
208
226
|
);
|
|
209
227
|
case 'amnioticFluid':
|
|
210
228
|
return t(
|
|
211
229
|
'babyAmnioticFluidAlertGuidance',
|
|
212
|
-
'Amniotic fluid
|
|
230
|
+
'Amniotic fluid alert: increase fetal surveillance for meconium and start broad-spectrum IV antibiotics for suspected infection when foul odor is present.',
|
|
213
231
|
);
|
|
214
232
|
case 'fetalPosition':
|
|
215
233
|
return t(
|
|
216
234
|
'babyFetalPositionAlertGuidance',
|
|
217
|
-
'Fetal position
|
|
235
|
+
'Fetal position alert: reassess fetal position and descent, use corrective maternal positioning, and escalate review if persistent with poor progress.',
|
|
218
236
|
);
|
|
219
237
|
case 'caput':
|
|
220
|
-
return t(
|
|
238
|
+
return t(
|
|
239
|
+
'babyCaputAlertGuidance',
|
|
240
|
+
'Caput +++ alert: evaluate for cephalopelvic disproportion or malposition and prepare operative delivery if progress is halted.',
|
|
241
|
+
);
|
|
221
242
|
case 'moulding':
|
|
222
243
|
return t(
|
|
223
244
|
'babyMouldingAlertGuidance',
|
|
224
|
-
'Moulding
|
|
245
|
+
'Moulding +++ alert: evaluate for cephalopelvic disproportion or malposition and prepare operative delivery if progress is halted.',
|
|
225
246
|
);
|
|
226
247
|
default:
|
|
227
248
|
return '';
|
|
@@ -286,26 +307,29 @@ export const isWomanAlertValue = (rowKey: WomanAlertKey, rawValue: string) => {
|
|
|
286
307
|
export const getWomanAlertGuidance = (t: TFunction, rowKey: WomanAlertKey) => {
|
|
287
308
|
switch (rowKey) {
|
|
288
309
|
case 'pulse':
|
|
289
|
-
return t(
|
|
310
|
+
return t(
|
|
311
|
+
'womanPulseAlertGuidance',
|
|
312
|
+
'Pulse alert: assess for dehydration, pain, anxiety, fever, or bleeding; optimize hydration and pain control, then recheck promptly and manage hemorrhage urgently when suspected.',
|
|
313
|
+
);
|
|
290
314
|
case 'systolicBp':
|
|
291
315
|
return t(
|
|
292
316
|
'womanSystolicAlertGuidance',
|
|
293
|
-
'Systolic BP alert:
|
|
317
|
+
'Systolic BP alert: for elevated BP, evaluate pre-eclampsia signs and urine protein; treat severe hypertension per protocol including antihypertensives and magnesium sulfate when indicated. For low BP, left lateral tilt, rapid IV fluids, and assess for bleeding.',
|
|
294
318
|
);
|
|
295
319
|
case 'diastolicBp':
|
|
296
320
|
return t(
|
|
297
321
|
'womanDiastolicAlertGuidance',
|
|
298
|
-
'Diastolic BP alert:
|
|
322
|
+
'Diastolic BP alert: evaluate and manage hypertensive disease urgently, including proteinuria screening and severe-feature assessment; escalate treatment per protocol.',
|
|
299
323
|
);
|
|
300
324
|
case 'temperature':
|
|
301
325
|
return t(
|
|
302
326
|
'womanTemperatureAlertGuidance',
|
|
303
|
-
'Temperature alert:
|
|
327
|
+
'Temperature alert: confirm hydration, institute cooling and infection assessment, check liquor odor and maternal pulse, start empirical IV antibiotics when intrapartum infection is suspected, and increase FHR monitoring frequency.',
|
|
304
328
|
);
|
|
305
329
|
case 'urine':
|
|
306
330
|
return t(
|
|
307
331
|
'womanUrineAlertGuidance',
|
|
308
|
-
'Urine alert:
|
|
332
|
+
'Urine alert: correlate proteinuria with BP for pre-eclampsia assessment; treat ketonuria with oral intake support or IV dextrose where indicated.',
|
|
309
333
|
);
|
|
310
334
|
default:
|
|
311
335
|
return '';
|
|
@@ -329,7 +353,7 @@ export const getLabourContractionAlertInfo = (
|
|
|
329
353
|
guidance: isAlert
|
|
330
354
|
? t(
|
|
331
355
|
'contractionsPer10AlertGuidance',
|
|
332
|
-
'Contractions per 10 min alert:
|
|
356
|
+
'Contractions per 10 min alert: if >5 (hyperstimulation), stop/reduce oxytocin, left-lateral position, and consider tocolysis when fetal distress is present. If <2 (inadequate), consider amniotomy or oxytocin augmentation after confirming fetal well-being.',
|
|
333
357
|
)
|
|
334
358
|
: '',
|
|
335
359
|
};
|
|
@@ -341,7 +365,7 @@ export const getLabourContractionAlertInfo = (
|
|
|
341
365
|
guidance: isAlert
|
|
342
366
|
? t(
|
|
343
367
|
'contractionDurationAlertGuidance',
|
|
344
|
-
'
|
|
368
|
+
'Contraction duration alert: reassess labour powers and fetal condition; if contractions are inadequate support augmentation, if excessive with distress reduce stimulation and stabilize mother/fetus.',
|
|
345
369
|
)
|
|
346
370
|
: '',
|
|
347
371
|
};
|
|
@@ -367,23 +391,29 @@ export const getWomanAlertTokenGuidance = (t: TFunction, token: string): string
|
|
|
367
391
|
.trim()
|
|
368
392
|
.toUpperCase();
|
|
369
393
|
if (normalized.includes('PULSE'))
|
|
370
|
-
return t(
|
|
394
|
+
return t(
|
|
395
|
+
'womanPulseTokenGuidance',
|
|
396
|
+
'Pulse alert: assess cause (dehydration, pain, anxiety, fever, hemorrhage), optimize hydration and pain control, and recheck promptly.',
|
|
397
|
+
);
|
|
371
398
|
if (normalized.includes('SYSTOLIC'))
|
|
372
399
|
return t(
|
|
373
400
|
'womanSystolicTokenGuidance',
|
|
374
|
-
'Systolic BP
|
|
401
|
+
'Systolic BP alert: for high values evaluate pre-eclampsia and severe features; for low values position left lateral, give IV fluids, and assess for bleeding.',
|
|
375
402
|
);
|
|
376
403
|
if (normalized.includes('DIASTOLIC'))
|
|
377
|
-
return t(
|
|
404
|
+
return t(
|
|
405
|
+
'womanDiastolicTokenGuidance',
|
|
406
|
+
'Diastolic BP alert: evaluate hypertensive disease urgently with proteinuria and danger-sign review; escalate treatment per protocol.',
|
|
407
|
+
);
|
|
378
408
|
if (normalized.includes('TEMPERATURE'))
|
|
379
409
|
return t(
|
|
380
410
|
'womanTemperatureTokenGuidance',
|
|
381
|
-
'Temperature
|
|
411
|
+
'Temperature alert: evaluate for intrapartum infection, hydrate/cool, start empirical IV antibiotics when indicated, and increase fetal monitoring.',
|
|
382
412
|
);
|
|
383
413
|
if (normalized.includes('URINE'))
|
|
384
414
|
return t(
|
|
385
415
|
'womanUrineTokenGuidance',
|
|
386
|
-
'Urine
|
|
416
|
+
'Urine protein/ketone alert: correlate proteinuria with BP for pre-eclampsia, and manage ketonuria with nutrition support or IV dextrose as indicated.',
|
|
387
417
|
);
|
|
388
418
|
return t('womanAlertTokenGuidancePlaceholder', 'Woman vital-sign alert: review and act.');
|
|
389
419
|
};
|
|
@@ -420,12 +450,12 @@ export const getContractionAlertTokenGuidance = (t: TFunction, token: string): s
|
|
|
420
450
|
if (normalized.includes('CONTRACTIONS/10MIN'))
|
|
421
451
|
return t(
|
|
422
452
|
'contractionCountTokenGuidance',
|
|
423
|
-
'Contractions
|
|
453
|
+
'Contractions <=2 or >5 per 10 min: for hyperstimulation stop/reduce oxytocin and stabilize; for inadequate contractions consider amniotomy/oxytocin after fetal safety check.',
|
|
424
454
|
);
|
|
425
455
|
if (normalized.includes('CONTRACTION DURATION'))
|
|
426
456
|
return t(
|
|
427
457
|
'contractionDurationTokenGuidance',
|
|
428
|
-
'Contraction duration <20s or >60s:
|
|
458
|
+
'Contraction duration <20s or >60s: reassess powers, passenger, and passage; optimize uterine activity while maintaining fetal safety.',
|
|
429
459
|
);
|
|
430
460
|
return t('contractionAlertTokenGuidancePlaceholder', 'Contraction alert: review and act.');
|
|
431
461
|
};
|
|
@@ -439,7 +469,91 @@ export const getCervixStallTokenGuidance = (t: TFunction, token: string): string
|
|
|
439
469
|
if (normalized.includes('CM') && normalized.includes('NO PROGRESS'))
|
|
440
470
|
return t(
|
|
441
471
|
'cervixStallTokenGuidance',
|
|
442
|
-
'Cervical dilation stall:
|
|
472
|
+
'Cervical dilation stall: perform a full three-P assessment (powers, passenger, passage). If contractions are inadequate consider amniotomy/oxytocin; if adequate but no progress, evaluate for CPD and prepare for operative delivery.',
|
|
443
473
|
);
|
|
444
474
|
return t('cervixStallTokenGuidancePlaceholder', 'Labour progress alert: review and act.');
|
|
445
475
|
};
|
|
476
|
+
|
|
477
|
+
// ─── Shared Decision Making assessment prefill ───────────────────────────────
|
|
478
|
+
|
|
479
|
+
export type SharedDecisionAlertItem = {
|
|
480
|
+
id?: string;
|
|
481
|
+
section: string;
|
|
482
|
+
code: string;
|
|
483
|
+
guidance: string;
|
|
484
|
+
timestampCreatedMs?: number;
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
export type SharedDecisionAssessmentLine = {
|
|
488
|
+
label: string;
|
|
489
|
+
comment: string;
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
export const formatAlertItemAsAssessmentLabel = (item: SharedDecisionAlertItem): string => {
|
|
493
|
+
const code = String(item.code ?? '').trim();
|
|
494
|
+
if (!code) {
|
|
495
|
+
return '';
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const parenMatch = code.match(/^(.+?)\s+\((.+)\)$/);
|
|
499
|
+
if (parenMatch) {
|
|
500
|
+
return `${parenMatch[2].trim()} ${parenMatch[1].trim()}`;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const guidancePrefix = item.guidance.match(/^([^:\n]+):/);
|
|
504
|
+
if (guidancePrefix?.[1]) {
|
|
505
|
+
return guidancePrefix[1].trim();
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return code;
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
export const buildAssessmentPrefillFromAlerts = (items: SharedDecisionAlertItem[]): string => {
|
|
512
|
+
const seen = new Set<string>();
|
|
513
|
+
const lines: string[] = [];
|
|
514
|
+
|
|
515
|
+
for (const item of items) {
|
|
516
|
+
if (!item?.code) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const label = formatAlertItemAsAssessmentLabel(item);
|
|
521
|
+
const dedupeKey = label.toLowerCase();
|
|
522
|
+
if (!label || seen.has(dedupeKey)) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
seen.add(dedupeKey);
|
|
527
|
+
lines.push(`${label}: `);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return lines.join('\n');
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
export const parseAssessmentValue = (value: string): SharedDecisionAssessmentLine[] => {
|
|
534
|
+
if (!value.trim()) {
|
|
535
|
+
return [];
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return value
|
|
539
|
+
.split('\n')
|
|
540
|
+
.map((line) => {
|
|
541
|
+
const colonIndex = line.indexOf(':');
|
|
542
|
+
if (colonIndex === -1) {
|
|
543
|
+
return { label: line.trim(), comment: '' };
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
label: line.slice(0, colonIndex).trim(),
|
|
548
|
+
comment: line.slice(colonIndex + 1).replace(/^\s/, ''),
|
|
549
|
+
};
|
|
550
|
+
})
|
|
551
|
+
.filter((line) => line.label);
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
export const serializeAssessmentLines = (lines: SharedDecisionAssessmentLine[]): string => {
|
|
555
|
+
return lines
|
|
556
|
+
.map(({ label, comment }) => (label ? `${label}: ${comment}` : ''))
|
|
557
|
+
.filter(Boolean)
|
|
558
|
+
.join('\n');
|
|
559
|
+
};
|