Skip to content

Commit

Permalink
(feat) O3-4023 Ward App - force patient to be admitted before being a…
Browse files Browse the repository at this point in the history
…ble to transfer (#1375)
  • Loading branch information
chibongho authored Nov 15, 2024
1 parent 920348e commit 38d415f
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
}

.lightBlueBackground {
background-color: white;
border-left:4px solid $color-blue-60-2;
background-color: $color-blue-10;
border-left: 4px solid $color-blue-60-2;
color: #393939;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
import { Button } from '@carbon/react';
import {
ArrowRightIcon,
launchWorkspace,
showSnackbar,
useAppContext,
useFeatureFlag,
useLayoutType,
} from '@openmrs/esm-framework';
import { launchWorkspace, useAppContext, useLayoutType } from '@openmrs/esm-framework';
import React, { useCallback, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import useWardLocation from '../../hooks/useWardLocation';
import type { WardPatientCardType, WardPatientWorkspaceProps, WardViewContext } from '../../types';
import { useAdmitPatient } from '../../ward.resource';
import { AdmissionRequestsWorkspaceContext } from '../admission-request-workspace/admission-requests.workspace';
import AdmissionPatientButton from '../admit-patient-button.component';
import styles from './admission-request-card.scss';

const AdmissionRequestCardActions: WardPatientCardType = ({ wardPatient }) => {
const { patient, inpatientRequest } = wardPatient;
const { dispositionType } = inpatientRequest;
const { t } = useTranslation();
const { location } = useWardLocation();
const responsiveSize = useLayoutType() === 'tablet' ? 'lg' : 'md';
const { WardPatientHeader, wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
const { admitPatient, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useAdmitPatient();

const launchPatientAdmissionForm = () =>
launchWorkspace<WardPatientWorkspaceProps>('admit-patient-form-workspace', { wardPatient, WardPatientHeader });
const { WardPatientHeader } = useAppContext<WardViewContext>('ward-view-context') ?? {};

const launchPatientTransferForm = useCallback(() => {
launchWorkspace<WardPatientWorkspaceProps>('patient-transfer-request-workspace', {
Expand All @@ -41,43 +27,8 @@ const AdmissionRequestCardActions: WardPatientCardType = ({ wardPatient }) => {
});
};

const isBedManagementModuleInstalled = useFeatureFlag('bedmanagement-module');
const { closeWorkspaceWithSavedChanges } = useContext(AdmissionRequestsWorkspaceContext);

// If bed management module is installed, open the next form
// for bed selection. If not, admit patient directly
const onAdmit = () => {
if (isBedManagementModuleInstalled) {
launchPatientAdmissionForm();
} else {
admitPatient(patient, dispositionType)
.then(
(response) => {
if (response && response?.ok) {
showSnackbar({
kind: 'success',
title: t('patientAdmittedSuccessfully', 'Patient admitted successfully'),
subtitle: t('patientAdmittedWoBed', 'Patient admitted successfully to {{location}}', {
location: location?.display,
}),
});
}
},
(err: Error) => {
showSnackbar({
kind: 'error',
title: t('errorCreatingEncounter', 'Failed to admit patient'),
subtitle: err.message,
});
},
)
.finally(() => {
wardPatientGroupDetails?.mutate?.();
closeWorkspaceWithSavedChanges();
});
}
};

return (
<div className={styles.admissionRequestActionBar}>
<Button kind="ghost" size={responsiveSize} onClick={launchPatientTransferForm}>
Expand All @@ -86,14 +37,10 @@ const AdmissionRequestCardActions: WardPatientCardType = ({ wardPatient }) => {
<Button kind="ghost" size={responsiveSize} onClick={launchCancelAdmissionForm}>
{t('cancel', 'Cancel')}
</Button>
<Button
kind="ghost"
renderIcon={ArrowRightIcon}
size={responsiveSize}
disabled={isLoadingEmrConfiguration || errorFetchingEmrConfiguration}
onClick={onAdmit}>
{t('admitPatient', 'Admit patient')}
</Button>
<AdmissionPatientButton
wardPatient={wardPatient}
onAdmitPatientSuccess={() => closeWorkspaceWithSavedChanges()}
/>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Button } from '@carbon/react';
import {
ArrowRightIcon,
launchWorkspace,
showSnackbar,
useAppContext,
useFeatureFlag,
useLayoutType,
} from '@openmrs/esm-framework';
import React from 'react';
import { useTranslation } from 'react-i18next';
import useWardLocation from '../hooks/useWardLocation';
import type { WardPatient, WardPatientWorkspaceProps, WardViewContext } from '../types';
import { useAdmitPatient } from '../ward.resource';

interface AdmissionPatientButtonProps {
wardPatient: WardPatient;
onAdmitPatientSuccess();
}

const AdmissionPatientButton: React.FC<AdmissionPatientButtonProps> = ({ wardPatient, onAdmitPatientSuccess }) => {
const { patient, inpatientRequest, bed } = wardPatient ?? {};
const dispositionType = inpatientRequest?.dispositionType ?? 'ADMIT';
const { t } = useTranslation();
const { location } = useWardLocation();
const responsiveSize = useLayoutType() === 'tablet' ? 'lg' : 'md';
const { WardPatientHeader, wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
const { admitPatient, isLoadingEmrConfiguration, errorFetchingEmrConfiguration } = useAdmitPatient();

const launchPatientAdmissionForm = () =>
launchWorkspace<WardPatientWorkspaceProps>('admit-patient-form-workspace', { wardPatient, WardPatientHeader });

const isBedManagementModuleInstalled = useFeatureFlag('bedmanagement-module');

// If bed management module is installed and the patient does not currently assigned a bed,
// open the next form for bed selection. If not, admit patient directly
// (Note that it is possible, albeit an edge case, for a patient to have a bed assigned while not admitted)
const onAdmit = () => {
if (isBedManagementModuleInstalled && !bed) {
launchPatientAdmissionForm();
} else {
admitPatient(patient, dispositionType)
.then(
(response) => {
if (response && response?.ok) {
showSnackbar({
kind: 'success',
title: t('patientAdmittedSuccessfully', 'Patient admitted successfully'),
subtitle: t('patientAdmittedWoBed', 'Patient admitted successfully to {{location}}', {
location: location?.display,
}),
});
}
},
(err: Error) => {
showSnackbar({
kind: 'error',
title: t('errorCreatingEncounter', 'Failed to admit patient'),
subtitle: err.message,
});
},
)
.finally(() => {
wardPatientGroupDetails?.mutate?.();
onAdmitPatientSuccess();
});
}
};

return (
<Button
kind="ghost"
renderIcon={ArrowRightIcon}
size={responsiveSize}
disabled={isLoadingEmrConfiguration || errorFetchingEmrConfiguration}
onClick={onAdmit}>
{t('admitPatient', 'Admit patient')}
</Button>
);
};

export default AdmissionPatientButton;
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const AdmitPatientFormWorkspace: React.FC<WardPatientWorkspaceProps> = ({
closeWorkspaceWithSavedChanges,
promptBeforeClosing,
}) => {
const { patient, inpatientRequest } = wardPatient;
const { dispositionType } = inpatientRequest;
const { patient, inpatientRequest } = wardPatient ?? {};
const dispositionType = inpatientRequest?.dispositionType ?? 'ADMIT';

const { t } = useTranslation();
const { location } = useWardLocation();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { Button, ButtonSet, Form, InlineNotification, RadioButton, RadioButtonGroup, TextArea } from '@carbon/react';
import { zodResolver } from '@hookform/resolvers/zod';
import { ResponsiveWrapper, showSnackbar, useAppContext, useSession } from '@openmrs/esm-framework';
import {
ArrowRightIcon,
ResponsiveWrapper,
showSnackbar,
useAppContext,
useLayoutType,
useSession,
} from '@openmrs/esm-framework';
import classNames from 'classnames';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
Expand All @@ -11,13 +18,14 @@ import LocationSelector from '../../location-selector/location-selector.componen
import type { ObsPayload, WardPatientWorkspaceProps, WardViewContext } from '../../types';
import { useCreateEncounter } from '../../ward.resource';
import styles from './patient-transfer-swap.scss';
import AdmissionPatientButton from '../admit-patient-button.component';

export default function PatientTransferForm({
closeWorkspaceWithSavedChanges,
wardPatient,
promptBeforeClosing,
}: WardPatientWorkspaceProps) {
const { patient } = wardPatient ?? {};
const { patient, inpatientAdmission } = wardPatient ?? {};
const { t } = useTranslation();
const [showErrorNotifications, setShowErrorNotifications] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
Expand All @@ -30,6 +38,8 @@ export default function PatientTransferForm({
[emrConfiguration],
);
const { wardPatientGroupDetails } = useAppContext<WardViewContext>('ward-view-context') ?? {};
const responsiveSize = useLayoutType() === 'tablet' ? 'lg' : 'md';
const isAdmitted = inpatientAdmission != null;

const zodSchema = useMemo(
() =>
Expand Down Expand Up @@ -139,7 +149,28 @@ export default function PatientTransferForm({
setShowErrorNotifications(true);
}, []);

if (!wardPatientGroupDetails) return <></>;
if (!wardPatientGroupDetails) {
return <></>;
}
if (!isAdmitted) {
return (
<div className={styles.workspaceContent}>
<div className={styles.formError}>
<InlineNotification
kind="info"
title={t('unableToTransferPatient', 'Unable to transfer patient')}
subtitle={t(
'unableToTransferPatientNotYetAdmitted',
'This patient is not admitted to this ward. Admit this patient before transferring them to a different location.',
)}
lowContrast
hideCloseButton
/>
</div>
<AdmissionPatientButton wardPatient={wardPatient} onAdmitPatientSuccess={closeWorkspaceWithSavedChanges} />
</div>
);
}
return (
<Form
onSubmit={handleSubmit(onSubmit, onError)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
color: #393939;
}

.formError {
margin-bottom: layout.$spacing-05;
}

.workspaceContent {
padding: layout.$spacing-05;
height: 100%;
Expand Down
2 changes: 2 additions & 0 deletions packages/esm-ward-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@
"transfers": "Transfers",
"transferType": "Transfer type",
"typeOfTransfer": "Type of transfer",
"unableToTransferPatient": "Unable to transfer patient",
"unableToTransferPatientNotYetAdmitted": "This patient is not admitted to this ward. Admit this patient before transferring them to a different location.",
"unknown": "Unknown",
"visitNoteSaved": "Patient note saved",
"wardClinicalNotePlaceholder": "Write any notes here",
Expand Down

0 comments on commit 38d415f

Please sign in to comment.