@kenyaemr/esm-ward-app 7.0.3-pre.89 → 8.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/.turbo/turbo-build.log +24 -16
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/169.js +1 -0
- package/dist/169.js.map +1 -0
- package/dist/269.js +1 -0
- package/dist/269.js.map +1 -0
- package/dist/346.js +1 -0
- package/dist/346.js.map +1 -0
- package/dist/348.js +1 -0
- package/dist/348.js.map +1 -0
- package/dist/466.js +1 -0
- package/dist/466.js.map +1 -0
- package/dist/501.js +1 -0
- package/dist/501.js.map +1 -0
- package/dist/574.js +1 -1
- package/dist/577.js +1 -0
- package/dist/577.js.map +1 -0
- package/dist/659.js +1 -0
- package/dist/659.js.map +1 -0
- package/dist/749.js +1 -0
- package/dist/749.js.map +1 -0
- package/dist/76.js +1 -0
- package/dist/76.js.map +1 -0
- package/dist/767.js +1 -0
- package/dist/767.js.map +1 -0
- package/dist/793.js +2 -0
- package/dist/793.js.map +1 -0
- package/dist/803.js +1 -0
- package/dist/803.js.map +1 -0
- package/dist/940.js +1 -0
- package/dist/940.js.map +1 -0
- package/dist/960.js +1 -0
- package/dist/960.js.map +1 -0
- package/dist/kenyaemr-esm-ward-app.js +1 -1
- package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +330 -42
- package/dist/kenyaemr-esm-ward-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 +3 -4
- package/src/action-menu-buttons/transfer-workspace-siderail.component.tsx +27 -0
- package/src/beds/empty-bed.component.tsx +1 -1
- package/src/beds/empty-bed.scss +6 -6
- package/src/beds/occupied-bed.component.tsx +5 -5
- package/src/beds/occupied-bed.scss +2 -3
- package/src/beds/occupied-bed.test.tsx +37 -21
- package/src/beds/unassigned-patient.component.tsx +20 -0
- package/src/beds/unassigned-patient.scss +6 -0
- package/src/config-schema-admission-request-note.ts +9 -0
- package/src/config-schema-extension-colored-obs-tags.ts +91 -0
- package/src/config-schema.ts +165 -231
- package/src/createDashboardLink.component.tsx +42 -0
- package/src/hooks/useAdmissionLocation.ts +12 -7
- package/src/hooks/useCurrentWardCardConfig.ts +32 -0
- package/src/hooks/useEmrConfiguration.ts +112 -0
- package/src/hooks/useInpatientAdmission.ts +28 -0
- package/src/hooks/useInpatientRequest.ts +39 -9
- package/src/hooks/useLocation.test.ts +38 -0
- package/src/hooks/useLocation.ts +9 -0
- package/src/hooks/useLocations.ts +54 -0
- package/src/hooks/useMostRecentObs.ts +27 -0
- package/src/hooks/useRestPatient.ts +18 -0
- package/src/hooks/useWardLocation.test.ts +108 -0
- package/src/hooks/useWardLocation.ts +26 -0
- package/src/index.ts +71 -4
- package/src/location-selector/location-selector.component.tsx +118 -0
- package/src/location-selector/location-selector.scss +48 -0
- package/src/root.component.tsx +2 -1
- package/src/routes.json +79 -12
- package/src/types/index.ts +87 -46
- package/src/ward-patient-card/card-rows/admission-request-note.extension.tsx +27 -0
- package/src/ward-patient-card/card-rows/colored-obs-tags-card-row.extension.tsx +13 -0
- package/src/ward-patient-card/row-elements/ward-patient-age.tsx +7 -13
- package/src/ward-patient-card/row-elements/ward-patient-bed-number.tsx +2 -2
- package/src/ward-patient-card/row-elements/ward-patient-coded-obs-tags.tsx +51 -50
- package/src/ward-patient-card/row-elements/ward-patient-gender.component.tsx +27 -0
- package/src/ward-patient-card/row-elements/ward-patient-header-address.tsx +16 -15
- package/src/ward-patient-card/row-elements/ward-patient-identifier.tsx +53 -0
- package/src/ward-patient-card/row-elements/ward-patient-name.tsx +7 -7
- package/src/ward-patient-card/row-elements/ward-patient-obs.resource.ts +4 -4
- package/src/ward-patient-card/row-elements/ward-patient-obs.tsx +45 -44
- package/src/ward-patient-card/row-elements/ward-patient-time-on-ward.tsx +22 -0
- package/src/ward-patient-card/row-elements/ward-patient-time-since-admission.tsx +22 -0
- package/src/ward-patient-card/ward-patient-card-element.component.tsx +65 -0
- package/src/ward-patient-card/ward-patient-card.component.tsx +64 -0
- package/src/ward-patient-card/ward-patient-card.scss +61 -12
- package/src/ward-patient-workspace/ward-patient-action-button.extension.tsx +18 -0
- package/src/ward-patient-workspace/ward-patient.style.scss +11 -0
- package/src/ward-patient-workspace/ward-patient.workspace.tsx +51 -0
- package/src/ward-view/ward-bed.component.tsx +0 -1
- package/src/ward-view/ward-view.component.tsx +114 -76
- package/src/ward-view/ward-view.resource.ts +2 -2
- package/src/ward-view/ward-view.scss +4 -4
- package/src/ward-view/ward-view.test.tsx +76 -49
- package/src/ward-view-header/admission-requests-bar.component.tsx +29 -28
- package/src/ward-view-header/admission-requests-bar.test.tsx +11 -15
- package/src/ward-view-header/admission-requests.scss +20 -25
- package/src/ward-view-header/ward-view-header.component.tsx +7 -7
- package/src/ward-view-header/ward-view-header.scss +2 -2
- package/src/ward-workspace/admission-request-card/admission-request-card-actions.component.tsx +29 -0
- package/src/ward-workspace/admission-request-card/admission-request-card-header.component.tsx +51 -0
- package/src/ward-workspace/admission-request-card/admission-request-card.component.tsx +16 -0
- package/src/ward-workspace/admission-request-card/admission-request-card.scss +49 -0
- package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.scss +12 -0
- package/src/ward-workspace/admission-request-workspace/admission-requests-workspace.test.tsx +48 -0
- package/src/ward-workspace/admission-request-workspace/admission-requests.workspace.tsx +61 -0
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.scss +35 -0
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.test.tsx +341 -0
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +267 -0
- package/src/ward-workspace/admit-patient-form-workspace/types.ts +7 -0
- package/src/ward-workspace/patient-banner/patient-banner.component.tsx +29 -0
- package/src/ward-workspace/patient-banner/style.scss +23 -0
- package/src/ward-workspace/patient-transfer-bed-swap/patient-bed-swap-form.component.tsx +210 -0
- package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-request-form.component.tsx +238 -0
- package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.scss +73 -0
- package/src/ward-workspace/patient-transfer-bed-swap/patient-transfer-swap.workspace.tsx +44 -0
- package/src/ward-workspace/ward-patient-notes/form/notes-form.component.tsx +180 -0
- package/src/ward-workspace/ward-patient-notes/form/notes-form.scss +30 -0
- package/src/ward-workspace/ward-patient-notes/form/notes-form.test.tsx +116 -0
- package/src/ward-workspace/ward-patient-notes/history/note.component.tsx +53 -0
- package/src/ward-workspace/ward-patient-notes/history/notes-container.component.tsx +55 -0
- package/src/ward-workspace/ward-patient-notes/history/notes-container.test.tsx +84 -0
- package/src/ward-workspace/ward-patient-notes/history/styles.scss +61 -0
- package/src/ward-workspace/ward-patient-notes/notes-action-button.extension.tsx +18 -0
- package/src/ward-workspace/ward-patient-notes/notes.resource.ts +71 -0
- package/src/ward-workspace/ward-patient-notes/notes.workspace.tsx +25 -0
- package/src/ward-workspace/ward-patient-notes/types.ts +44 -0
- package/src/ward.resource.ts +25 -0
- package/translations/en.json +63 -2
- package/dist/443.js +0 -1
- package/dist/443.js.map +0 -1
- package/dist/589.js +0 -1
- package/dist/589.js.map +0 -1
- package/dist/695.js +0 -2
- package/dist/695.js.map +0 -1
- package/src/hooks/useAdmittedPatients.ts +0 -13
- package/src/ward-patient-card/row-elements/row-elements.scss +0 -16
- package/src/ward-patient-card/ward-patient-card-row.resources.tsx +0 -92
- package/src/ward-patient-card/ward-patient-card.tsx +0 -20
- package/src/ward-workspace/admission-request-card.component.tsx +0 -23
- package/src/ward-workspace/admission-request-card.scss +0 -34
- package/src/ward-workspace/admission-request-workspace.test.tsx +0 -38
- package/src/ward-workspace/admission-requests-workspace.component.tsx +0 -21
- package/src/ward-workspace/admission-requests-workspace.scss +0 -13
- /package/dist/{695.js.LICENSE.txt → 793.js.LICENSE.txt} +0 -0
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
import { SkeletonText
|
|
2
|
-
import { type OpenmrsResource, translateFrom } from '@openmrs/esm-framework';
|
|
1
|
+
import { SkeletonText } from '@carbon/react';
|
|
2
|
+
import { type OpenmrsResource, type Patient, translateFrom, type Visit } from '@openmrs/esm-framework';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import { type
|
|
5
|
+
import { type ObsElementDefinition } from '../../config-schema';
|
|
6
6
|
import { useObs } from '../../hooks/useObs';
|
|
7
|
-
import { type WardPatientCardElement } from '../../types';
|
|
8
7
|
import styles from '../ward-patient-card.scss';
|
|
9
8
|
import { moduleName } from '../../constant';
|
|
10
9
|
import { obsCustomRepresentation } from './ward-patient-obs.resource';
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
export interface WardPatientObsProps {
|
|
12
|
+
config: ObsElementDefinition;
|
|
13
|
+
patient: Patient;
|
|
14
|
+
visit: Visit;
|
|
15
|
+
}
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
?.filter((o) => {
|
|
23
|
-
const matchVisit = !onlyWithinCurrentVisit || o.encounter.visit?.uuid == visit?.uuid;
|
|
24
|
-
return matchVisit;
|
|
25
|
-
})
|
|
26
|
-
?.sort((obsA, obsB) => {
|
|
27
|
-
return (orderBy == 'descending' ? -1 : 1) * obsA.obsDatetime.localeCompare(obsB.obsDatetime);
|
|
28
|
-
})
|
|
29
|
-
?.slice(0, limit ?? Number.MAX_VALUE);
|
|
17
|
+
const WardPatientObs: React.FC<WardPatientObsProps> = ({ config, patient, visit }) => {
|
|
18
|
+
const { conceptUuid, onlyWithinCurrentVisit, orderBy, limit, label, labelI18nModule: labelModule } = config;
|
|
19
|
+
const { data, isLoading } = useObs({ patient: patient.uuid, concept: conceptUuid }, obsCustomRepresentation);
|
|
20
|
+
const { t } = useTranslation();
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
if (isLoading) {
|
|
23
|
+
return <SkeletonText />;
|
|
24
|
+
} else {
|
|
25
|
+
const obsToDisplay = data?.data?.results
|
|
26
|
+
?.filter((o) => {
|
|
27
|
+
const matchVisit = !onlyWithinCurrentVisit || o.encounter.visit?.uuid == visit?.uuid;
|
|
28
|
+
return matchVisit;
|
|
29
|
+
})
|
|
30
|
+
?.sort((obsA, obsB) => {
|
|
31
|
+
return (orderBy == 'descending' ? -1 : 1) * obsA.obsDatetime.localeCompare(obsB.obsDatetime);
|
|
32
|
+
})
|
|
33
|
+
?.slice(0, limit == 0 ? Number.MAX_VALUE : limit);
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const display: any = (value as OpenmrsResource)?.display ?? o.value;
|
|
37
|
-
return <span key={o.uuid}> {display} </span>;
|
|
38
|
-
});
|
|
35
|
+
const labelToDisplay =
|
|
36
|
+
label != null ? translateFrom(labelModule ?? moduleName, label) : obsToDisplay?.[0]?.concept?.display;
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
</span>
|
|
46
|
-
{obsNodes}
|
|
47
|
-
</div>
|
|
48
|
-
);
|
|
49
|
-
} else {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
};
|
|
38
|
+
const obsNodes = obsToDisplay?.map((o) => {
|
|
39
|
+
const { value } = o;
|
|
40
|
+
const display: any = (value as OpenmrsResource)?.display ?? o.value;
|
|
41
|
+
return <span key={o.uuid}> {display} </span>;
|
|
42
|
+
});
|
|
54
43
|
|
|
55
|
-
|
|
44
|
+
if (obsNodes?.length > 0) {
|
|
45
|
+
return (
|
|
46
|
+
<div>
|
|
47
|
+
<span className={styles.wardPatientObsLabel}>
|
|
48
|
+
{labelToDisplay ? t('labelColon', '{{label}}:', { label: labelToDisplay }) : ''}
|
|
49
|
+
</span>
|
|
50
|
+
{obsNodes}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
} else {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
56
57
|
};
|
|
57
58
|
|
|
58
|
-
export default
|
|
59
|
+
export default WardPatientObs;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { age } from '@openmrs/esm-framework';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { type Encounter } from '../../types';
|
|
5
|
+
|
|
6
|
+
export interface WardPatientTimeOnWardProps {
|
|
7
|
+
encounterAssigningToCurrentInpatientLocation: Encounter;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const WardPatientTimeOnWard: React.FC<WardPatientTimeOnWardProps> = ({
|
|
11
|
+
encounterAssigningToCurrentInpatientLocation,
|
|
12
|
+
}) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
if (encounterAssigningToCurrentInpatientLocation) {
|
|
15
|
+
const timeOnWard = age(encounterAssigningToCurrentInpatientLocation.encounterDatetime);
|
|
16
|
+
return <div>{t('timeOnWard', 'Time on this ward: {{timeOnWard}}', { timeOnWard })}</div>;
|
|
17
|
+
} else {
|
|
18
|
+
return <></>;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default WardPatientTimeOnWard;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { age } from '@openmrs/esm-framework';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { type Encounter } from '../../types';
|
|
5
|
+
|
|
6
|
+
export interface WardPatientTimeSinceAdmissionProps {
|
|
7
|
+
firstAdmissionOrTransferEncounter: Encounter;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const WardPatientTimeSinceAdmission: React.FC<WardPatientTimeSinceAdmissionProps> = ({
|
|
11
|
+
firstAdmissionOrTransferEncounter,
|
|
12
|
+
}) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
if (firstAdmissionOrTransferEncounter) {
|
|
15
|
+
const timeSinceAdmission = age(firstAdmissionOrTransferEncounter.encounterDatetime);
|
|
16
|
+
return <div>{t('timeSinceAdmission', 'Admitted: {{timeSinceAdmission}} ago', { timeSinceAdmission })}</div>;
|
|
17
|
+
} else {
|
|
18
|
+
return <></>;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default WardPatientTimeSinceAdmission;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { InlineNotification } from '@carbon/react';
|
|
2
|
+
import { useConfig } from '@openmrs/esm-framework';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { type WardConfigObject } from '../config-schema';
|
|
6
|
+
import { type WardPatient } from '../types';
|
|
7
|
+
import WardPatientAge from './row-elements/ward-patient-age';
|
|
8
|
+
import WardPatientAddress from './row-elements/ward-patient-header-address';
|
|
9
|
+
import WardPatientIdentifier from './row-elements/ward-patient-identifier';
|
|
10
|
+
import WardPatientObs from './row-elements/ward-patient-obs';
|
|
11
|
+
import WardPatientTimeOnWard from './row-elements/ward-patient-time-on-ward';
|
|
12
|
+
import WardPatientTimeSinceAdmission from './row-elements/ward-patient-time-since-admission';
|
|
13
|
+
|
|
14
|
+
export interface WardPatientCardElementProps extends WardPatient {
|
|
15
|
+
elementId: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const WardPatientCardElement: React.FC<WardPatientCardElementProps> = ({
|
|
19
|
+
elementId,
|
|
20
|
+
patient,
|
|
21
|
+
visit,
|
|
22
|
+
inpatientAdmission,
|
|
23
|
+
}) => {
|
|
24
|
+
const { obsElementDefinitions, identifierElementDefinitions, addressElementDefinitions } =
|
|
25
|
+
useConfig<WardConfigObject>().wardPatientCards;
|
|
26
|
+
const { t } = useTranslation();
|
|
27
|
+
const { encounterAssigningToCurrentInpatientLocation, firstAdmissionOrTransferEncounter } = inpatientAdmission ?? {};
|
|
28
|
+
|
|
29
|
+
switch (elementId) {
|
|
30
|
+
case 'patient-age':
|
|
31
|
+
return <WardPatientAge patient={patient} />;
|
|
32
|
+
case 'time-on-ward': {
|
|
33
|
+
return (
|
|
34
|
+
<WardPatientTimeOnWard
|
|
35
|
+
encounterAssigningToCurrentInpatientLocation={encounterAssigningToCurrentInpatientLocation}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
case 'time-since-admission': {
|
|
40
|
+
return <WardPatientTimeSinceAdmission firstAdmissionOrTransferEncounter={firstAdmissionOrTransferEncounter} />;
|
|
41
|
+
}
|
|
42
|
+
default: {
|
|
43
|
+
const obsConfig = obsElementDefinitions.find((elementDef) => elementDef.id === elementId);
|
|
44
|
+
const idConfig = identifierElementDefinitions.find((elementDef) => elementDef.id === elementId);
|
|
45
|
+
const addressConfig = addressElementDefinitions.find((elementDef) => elementDef.id === elementId);
|
|
46
|
+
if (obsConfig) {
|
|
47
|
+
return <WardPatientObs patient={patient} visit={visit} config={obsConfig} />;
|
|
48
|
+
} else if (idConfig) {
|
|
49
|
+
return <WardPatientIdentifier patient={patient} config={idConfig} />;
|
|
50
|
+
} else if (addressConfig) {
|
|
51
|
+
return <WardPatientAddress patient={patient} config={addressConfig} />;
|
|
52
|
+
} else {
|
|
53
|
+
return (
|
|
54
|
+
<InlineNotification kind="error">
|
|
55
|
+
{t(
|
|
56
|
+
'invalidElementIdCopy',
|
|
57
|
+
'The configuration provided is invalid. It contains the following unknown element ID:',
|
|
58
|
+
)}{' '}
|
|
59
|
+
{elementId}
|
|
60
|
+
</InlineNotification>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ExtensionSlot, getPatientName, launchWorkspace } from '@openmrs/esm-framework';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useCurrentWardCardConfig } from '../hooks/useCurrentWardCardConfig';
|
|
5
|
+
import { type WardPatientCard, type WardPatientWorkspaceProps } from '../types';
|
|
6
|
+
import WardPatientBedNumber from './row-elements/ward-patient-bed-number';
|
|
7
|
+
import WardPatientName from './row-elements/ward-patient-name';
|
|
8
|
+
import { WardPatientCardElement } from './ward-patient-card-element.component';
|
|
9
|
+
import styles from './ward-patient-card.scss';
|
|
10
|
+
|
|
11
|
+
const WardPatientCard: WardPatientCard = (wardPatient) => {
|
|
12
|
+
const { patient, bed } = wardPatient;
|
|
13
|
+
const { id, headerRowElements, footerRowElements } = useCurrentWardCardConfig();
|
|
14
|
+
|
|
15
|
+
const headerExtensionSlotName =
|
|
16
|
+
id == 'default' ? 'ward-patient-card-header-slot' : `ward-patient-card-header-${id}-slot`;
|
|
17
|
+
const rowsExtensionSlotName = id == 'default' ? 'ward-patient-card-slot' : `ward-patient-card-${id}-slot`;
|
|
18
|
+
const footerExtensionSlotName =
|
|
19
|
+
id == 'default' ? 'ward-patient-card-footer-slot' : `ward-patient-card-footer-${id}-slot`;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div className={styles.wardPatientCard}>
|
|
23
|
+
<div className={classNames(styles.wardPatientCardRow, styles.wardPatientCardHeader)}>
|
|
24
|
+
{bed ? <WardPatientBedNumber bed={bed} /> : null}
|
|
25
|
+
<WardPatientName patient={patient} />
|
|
26
|
+
{headerRowElements.map((elementId, i) => (
|
|
27
|
+
<WardPatientCardElement
|
|
28
|
+
key={`ward-card-${patient.uuid}-header-${i}`}
|
|
29
|
+
elementId={elementId}
|
|
30
|
+
{...wardPatient}
|
|
31
|
+
/>
|
|
32
|
+
))}
|
|
33
|
+
<ExtensionSlot name={headerExtensionSlotName} state={wardPatient} />
|
|
34
|
+
</div>
|
|
35
|
+
<ExtensionSlot
|
|
36
|
+
name={rowsExtensionSlotName}
|
|
37
|
+
state={wardPatient}
|
|
38
|
+
className={classNames(styles.wardPatientCardRow, styles.wardPatientCardExtensionSlot)}
|
|
39
|
+
/>
|
|
40
|
+
<div className={styles.wardPatientCardRow}>
|
|
41
|
+
{footerRowElements.map((elementId, i) => (
|
|
42
|
+
<WardPatientCardElement
|
|
43
|
+
key={`ward-card-${patient.uuid}-footer-${i}`}
|
|
44
|
+
elementId={elementId}
|
|
45
|
+
{...wardPatient}
|
|
46
|
+
/>
|
|
47
|
+
))}
|
|
48
|
+
<ExtensionSlot name={footerExtensionSlotName} state={wardPatient} />
|
|
49
|
+
</div>
|
|
50
|
+
<button
|
|
51
|
+
className={styles.wardPatientCardButton}
|
|
52
|
+
onClick={() => {
|
|
53
|
+
launchWorkspace<WardPatientWorkspaceProps>('ward-patient-workspace', {
|
|
54
|
+
wardPatient,
|
|
55
|
+
});
|
|
56
|
+
}}>
|
|
57
|
+
{/* Name will not be displayed; just there for a11y */}
|
|
58
|
+
{getPatientName(patient.person)}
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export default WardPatientCard;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
@use '@carbon/styles/scss/spacing';
|
|
2
|
-
@use '@carbon/styles/scss/type';
|
|
3
1
|
@use '@carbon/colors';
|
|
4
|
-
@
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
5
5
|
|
|
6
6
|
.wardPatientCard {
|
|
7
7
|
@include type.type-style('body-compact-01');
|
|
@@ -10,23 +10,69 @@
|
|
|
10
10
|
display: flex;
|
|
11
11
|
flex-wrap: wrap;
|
|
12
12
|
align-items: center;
|
|
13
|
-
gap:
|
|
13
|
+
gap: layout.$spacing-02;
|
|
14
14
|
background-color: $ui-02;
|
|
15
15
|
|
|
16
|
+
position: relative; // this allows positioning the button correctly
|
|
17
|
+
|
|
16
18
|
> .wardPatientCardRow:not(:first-child) {
|
|
17
19
|
border-top: 1px colors.$gray-20 solid;
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
.wardPatientCardButton {
|
|
24
|
+
border: none;
|
|
25
|
+
padding: 0;
|
|
26
|
+
|
|
27
|
+
&::before {
|
|
28
|
+
content: '';
|
|
29
|
+
position: absolute;
|
|
30
|
+
inset: 0;
|
|
31
|
+
z-index: 1;
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
border: 2px solid transparent;
|
|
34
|
+
transition: border-color 200ms;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&:hover::before,
|
|
38
|
+
&:focus::before {
|
|
39
|
+
border-color: $interactive-01;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&:focus {
|
|
43
|
+
outline: none;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.activeWardPatientCardButton {
|
|
48
|
+
&::before {
|
|
49
|
+
content: '';
|
|
50
|
+
position: absolute;
|
|
51
|
+
inset: 0;
|
|
52
|
+
z-index: 1;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
border: 2px solid $interactive-01;
|
|
55
|
+
transition: border-color 200ms;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
21
59
|
.wardPatientCardRow {
|
|
22
60
|
width: 100%;
|
|
23
|
-
padding:
|
|
61
|
+
padding: layout.$spacing-04;
|
|
24
62
|
}
|
|
25
63
|
|
|
26
64
|
.wardPatientCardRow:empty {
|
|
27
65
|
display: none;
|
|
28
66
|
}
|
|
29
67
|
|
|
68
|
+
.wardPatientCardExtensionSlot {
|
|
69
|
+
display: none;
|
|
70
|
+
|
|
71
|
+
&:has(div:not(:empty)) {
|
|
72
|
+
display: block;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
30
76
|
.wardPatientCardHeader {
|
|
31
77
|
@extend .dotSeparatedChildren;
|
|
32
78
|
display: flex;
|
|
@@ -36,6 +82,7 @@
|
|
|
36
82
|
.wardPatientName {
|
|
37
83
|
@include type.type-style('heading-compact-02');
|
|
38
84
|
color: $text-02;
|
|
85
|
+
|
|
39
86
|
&::before {
|
|
40
87
|
content: '' !important;
|
|
41
88
|
}
|
|
@@ -46,12 +93,13 @@
|
|
|
46
93
|
border-radius: 50%;
|
|
47
94
|
color: $ui-02;
|
|
48
95
|
background-color: $color-blue-60-2;
|
|
49
|
-
padding:
|
|
50
|
-
width:
|
|
51
|
-
height:
|
|
96
|
+
padding: layout.$spacing-04;
|
|
97
|
+
width: layout.$spacing-04;
|
|
98
|
+
height: layout.$spacing-04;
|
|
52
99
|
display: flex;
|
|
53
100
|
justify-content: center;
|
|
54
101
|
align-items: center;
|
|
102
|
+
|
|
55
103
|
&.empty {
|
|
56
104
|
background-color: $color-blue-10;
|
|
57
105
|
color: $color-blue-60-2;
|
|
@@ -69,20 +117,21 @@
|
|
|
69
117
|
display: flex;
|
|
70
118
|
flex-wrap: wrap;
|
|
71
119
|
align-items: center;
|
|
72
|
-
gap:
|
|
120
|
+
gap: layout.$spacing-02;
|
|
73
121
|
}
|
|
74
122
|
|
|
75
123
|
.wardPatientObsLabel {
|
|
76
|
-
padding-right:
|
|
124
|
+
padding-right: layout.$spacing-02;
|
|
77
125
|
}
|
|
78
126
|
|
|
79
127
|
.dotSeparatedChildren {
|
|
80
|
-
> div:not(div:first-of-type) {
|
|
128
|
+
> div:not(div:first-of-type):not(:empty) {
|
|
81
129
|
display: flex;
|
|
82
130
|
align-items: center;
|
|
131
|
+
|
|
83
132
|
&::before {
|
|
84
133
|
content: '·';
|
|
85
|
-
padding: 0
|
|
134
|
+
padding: 0 layout.$spacing-02;
|
|
86
135
|
}
|
|
87
136
|
}
|
|
88
137
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { UserAvatarIcon } from '@openmrs/esm-framework';
|
|
4
|
+
import { ActionMenuButton, launchWorkspace } from '@openmrs/esm-framework';
|
|
5
|
+
|
|
6
|
+
export default function WardPatientActionButton() {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<ActionMenuButton
|
|
11
|
+
getIcon={(props) => <UserAvatarIcon {...props} />}
|
|
12
|
+
label={t('Patient', 'patient')}
|
|
13
|
+
iconDescription={t('Patient', 'patient')}
|
|
14
|
+
handler={() => launchWorkspace('ward-patient-workspace')}
|
|
15
|
+
type={'ward'}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { age, attach, ExtensionSlot, type Patient } from '@openmrs/esm-framework';
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
3
|
+
import { type WardPatientWorkspaceProps } from '../types';
|
|
4
|
+
import styles from './ward-patient.style.scss';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { getGender } from '../ward-patient-card/row-elements/ward-patient-gender.component';
|
|
7
|
+
|
|
8
|
+
attach('ward-patient-workspace-header-slot', 'patient-vitals-info');
|
|
9
|
+
|
|
10
|
+
export default function WardPatientWorkspace({ setTitle, wardPatient: { patient } }: WardPatientWorkspaceProps) {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
setTitle(patient.person.display, <PatientWorkspaceTitle patient={patient} />);
|
|
13
|
+
}, []);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className={styles.workspaceContainer}>
|
|
17
|
+
<WardPatientWorkspaceView patient={patient} />
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface WardPatientWorkspaceViewProps {
|
|
23
|
+
patient: Patient;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const WardPatientWorkspaceView: React.FC<WardPatientWorkspaceViewProps> = ({ patient }) => {
|
|
27
|
+
const extensionSlotState = { patient, patientUuid: patient.uuid };
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
<div>
|
|
32
|
+
<ExtensionSlot name="ward-patient-workspace-header-slot" state={extensionSlotState} />
|
|
33
|
+
</div>
|
|
34
|
+
<div>
|
|
35
|
+
<ExtensionSlot name="ward-patient-workspace-content-slot" state={extensionSlotState} />
|
|
36
|
+
</div>
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const PatientWorkspaceTitle: React.FC<WardPatientWorkspaceViewProps> = ({ patient }) => {
|
|
42
|
+
const { t } = useTranslation();
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<div>{patient.person.display} </div>
|
|
47
|
+
<div className={styles.headerPatientDetail}>· {getGender(t, patient.person?.gender)}</div>
|
|
48
|
+
<div className={styles.headerPatientDetail}>· {age(patient.person?.birthdate)}</div>
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
};
|