Skip to content

Commit

Permalink
Merge branch 'main' into fix-O3-4180
Browse files Browse the repository at this point in the history
  • Loading branch information
usamaidrsk authored Dec 13, 2024
2 parents f02a846 + 0b3e877 commit 0e50e2c
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const testProps = {

const mockOpenmrsFetch = jest.mocked(openmrsFetch);

describe('AppointmensOverview', () => {
describe('AppointmentsOverview', () => {
it('renders an empty state if appointments data is unavailable', async () => {
mockOpenmrsFetch.mockResolvedValueOnce({
data: [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
InlineLoading,
Expand All @@ -18,9 +18,13 @@ import dayjs from 'dayjs';
import { type Appointment } from '../types';
import { useMutateAppointments } from '../form/appointments-form.resource';

interface VisitFormCallbacks {
onVisitCreatedOrUpdated: (visit: Visit) => Promise<any>;
}

// See VisitFormExtensionState in esm-patient-chart-app
export interface PatientUpcomingAppointmentsProps {
setOnVisitCreatedOrUpdated(onSubmit: (visit: Visit) => Promise<any>);
setVisitFormCallbacks(callbacks: VisitFormCallbacks);
visitFormOpenedFrom: string;
patientChartConfig?: {
showUpcomingAppointments: boolean;
Expand All @@ -36,45 +40,53 @@ export interface PatientUpcomingAppointmentsProps {
*/
const PatientUpcomingAppointmentsCard: React.FC<PatientUpcomingAppointmentsProps> = ({
patientUuid,
setOnVisitCreatedOrUpdated,
setVisitFormCallbacks,
patientChartConfig,
}) => {
const { t } = useTranslation();
const startDate = dayjs(new Date().toISOString()).subtract(6, 'month').toISOString();
const headerTitle = t('upcomingAppointments', 'Upcoming appointments');
const [selectedAppointment, setSelectedAppointment] = useState<Appointment>(null);
const { mutateAppointments } = useMutateAppointments();
const memoMutateAppointments = useMemo(() => mutateAppointments, [mutateAppointments]);

const ac = useMemo<AbortController>(() => new AbortController(), []);
useEffect(() => () => ac.abort(), [ac]);
const { data: appointmentsData, error, isLoading } = usePatientAppointments(patientUuid, startDate, ac);

useEffect(() => {
setOnVisitCreatedOrUpdated(() => {
if (selectedAppointment) {
return changeAppointmentStatus('CheckedIn', selectedAppointment.uuid)
.then(() => {
mutateAppointments();
showSnackbar({
isLowContrast: true,
kind: 'success',
subtitle: t('appointmentMarkedChecked', 'Appointment marked as Checked In'),
title: t('appointmentCheckedIn', 'Appointment Checked In'),
});
})
.catch((error) => {
showSnackbar({
title: t('updateError', 'Error updating upcoming appointment'),
kind: 'error',
isLowContrast: false,
subtitle: error?.message,
const onVisitCreatedOrUpdated = useMemo(
() => ({
onVisitCreatedOrUpdated: () => {
if (selectedAppointment) {
return changeAppointmentStatus('CheckedIn', selectedAppointment.uuid)
.then(() => {
memoMutateAppointments();
showSnackbar({
isLowContrast: true,
kind: 'success',
subtitle: t('appointmentMarkedChecked', 'Appointment marked as Checked In'),
title: t('appointmentCheckedIn', 'Appointment Checked In'),
});
})
.catch((error) => {
showSnackbar({
title: t('updateError', 'Error updating upcoming appointment'),
kind: 'error',
isLowContrast: false,
subtitle: error?.message,
});
});
});
} else {
return Promise.resolve();
}
});
}, [selectedAppointment, mutateAppointments, setOnVisitCreatedOrUpdated, t]);
} else {
return Promise.resolve();
}
},
}),
[selectedAppointment, memoMutateAppointments, t],
);

useEffect(() => {
setVisitFormCallbacks(onVisitCreatedOrUpdated);
}, [onVisitCreatedOrUpdated, setVisitFormCallbacks]);

const todaysAppointments = appointmentsData?.todaysAppointments?.length ? appointmentsData?.todaysAppointments : [];
const futureAppointments = appointmentsData?.upcomingAppointments?.length
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,26 @@ const ExistingVisitForm: React.FC<ExistingVisitFormProps> = ({ visit, closeWorks
const [isSubmitting, setIsSubmitting] = useState(false);

const { mutateQueueEntries } = useMutateQueueEntries();
const [submitQueueEntry, setSubmitQueueEntry] = useState<(visit: Visit, patientUuid: string) => Promise<any>>(null);
const [callback, setCallback] = useState<{
submitQueueEntry: (visit: Visit) => Promise<any>;
}>(null);

const handleSubmit = useCallback(
(event) => {
event.preventDefault();
setIsSubmitting(true);

submitQueueEntry?.(visit, visit.patient.uuid)
callback
?.submitQueueEntry?.(visit)
?.then(() => {
closeWorkspace();
mutateQueueEntries();
})
?.finally(() => {
setIsSubmitting(false);
});
},
[closeWorkspace, submitQueueEntry, visit],
[closeWorkspace, callback, visit, mutateQueueEntries],
);

return visit ? (
Expand All @@ -52,7 +56,7 @@ const ExistingVisitForm: React.FC<ExistingVisitFormProps> = ({ visit, closeWorks
</Row>
)}
<Form className={classNames(styles.form, styles.container)} onSubmit={handleSubmit}>
<QueueFields setOnSubmit={setSubmitQueueEntry} />
<QueueFields setOnSubmit={(onSubmit) => setCallback({ submitQueueEntry: onSubmit })} />
<ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
<Button className={styles.button} kind="secondary" onClick={closeWorkspace}>
{t('discard', 'Discard')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import React, { useContext, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import classNames from 'classnames';
import {
InlineNotification,
RadioButton,
Expand All @@ -9,16 +6,17 @@ import {
Select,
SelectItem,
SelectSkeleton,
TextInput,
} from '@carbon/react';
import { useConfig, ResponsiveWrapper, useSession, type Visit, showSnackbar } from '@openmrs/esm-framework';
import { ResponsiveWrapper, showSnackbar, useConfig, useSession, type Visit } from '@openmrs/esm-framework';
import React, { useCallback, useContext, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { type ConfigObject } from '../../config-schema';
import { useMutateQueueEntries } from '../../hooks/useQueueEntries';
import { useQueues } from '../../hooks/useQueues';
import { useQueueLocations } from '../hooks/useQueueLocations';
import { AddPatientToQueueContext } from '../create-queue-entry.workspace';
import styles from './queue-fields.scss';
import { useMutateQueueEntries } from '../../hooks/useQueueEntries';
import { useQueueLocations } from '../hooks/useQueueLocations';
import { postQueueEntry } from './queue-fields.resource';
import styles from './queue-fields.scss';

export interface QueueFieldsProps {
setOnSubmit(onSubmit: (visit: Visit) => Promise<any>);
Expand All @@ -42,11 +40,12 @@ const QueueFields: React.FC<QueueFieldsProps> = ({ setOnSubmit }) => {
const [priority, setPriority] = useState(defaultPriorityConceptUuid);
const priorities = queues.find((q) => q.uuid === selectedService)?.allowedPriorities ?? [];
const { mutateQueueEntries } = useMutateQueueEntries();
const memoMutateQueueEntries = useCallback(mutateQueueEntries, [mutateQueueEntries]);

const sortWeight = priority === emergencyPriorityConceptUuid ? 1 : 0;

useEffect(() => {
setOnSubmit?.((visit: Visit) => {
const onSubmit = useCallback(
(visit: Visit) => {
if (selectedQueueLocation && selectedService && priority) {
return postQueueEntry(
visit.uuid,
Expand All @@ -65,7 +64,7 @@ const QueueFields: React.FC<QueueFieldsProps> = ({ setOnSubmit }) => {
title: t('addedPatientToQueue', 'Added patient to queue'),
subtitle: t('queueEntryAddedSuccessfully', 'Queue entry added successfully'),
});
mutateQueueEntries();
memoMutateQueueEntries();
})
.catch((error) => {
showSnackbar({
Expand All @@ -79,18 +78,22 @@ const QueueFields: React.FC<QueueFieldsProps> = ({ setOnSubmit }) => {
} else {
return Promise.resolve();
}
});
}, [
selectedQueueLocation,
selectedService,
priority,
sortWeight,
defaultStatusConceptUuid,
visitQueueNumberAttributeUuid,
mutateQueueEntries,
setOnSubmit,
t,
]);
},
[
selectedQueueLocation,
selectedService,
priority,
sortWeight,
defaultStatusConceptUuid,
visitQueueNumberAttributeUuid,
memoMutateQueueEntries,
t,
],
);

useEffect(() => {
setOnSubmit?.(onSubmit);
}, [onSubmit, setOnSubmit]);

useEffect(() => {
if (currentServiceQueueUuid) {
Expand Down Expand Up @@ -201,16 +204,6 @@ const QueueFields: React.FC<QueueFieldsProps> = ({ setOnSubmit }) => {
) : null}
</section>
) : null}

<section className={classNames(styles.section, styles.sectionHidden)}>
<TextInput
type="number"
id="sortWeight"
name="sortWeight"
labelText={t('sortWeight', 'Sort weight')}
value={sortWeight}
/>
</section>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,3 @@
.section {
margin: layout.$spacing-07 layout.$spacing-05 0;
}

.sectionHidden {
display: none;
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ describe('QueueFields', () => {
it('renders the form fields and returns the set values', async () => {
const user = userEvent.setup();
let onSubmit: (visit: Visit) => Promise<any> = null;
const setOnSubmit = (callback) => (onSubmit = callback);
const setOnSubmit = (callback) => {
onSubmit = callback;
};
render(<QueueFields setOnSubmit={setOnSubmit} />);

expect(screen.getByLabelText('Select a queue location')).toBeInTheDocument();
expect(screen.getByLabelText('Select a service')).toBeInTheDocument();
expect(screen.getByLabelText('Sort weight')).toBeInTheDocument();

const queueUuid = 'e2ec9cf0-ec38-4d2b-af6c-59c82fa30b90';
const serviceSelect = screen.getByLabelText('Select a service').closest('select');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { type Visit } from '@openmrs/esm-framework';
import React from 'react';
import QueueFields from './queue-fields.component';

interface VisitFormCallbacks {
onVisitCreatedOrUpdated: (visit: Visit) => Promise<any>;
}
// See VisitFormExtensionState in esm-patient-chart-app
export interface VisitFormQueueFieldsProps {
setOnVisitCreatedOrUpdated(onSubmit: (visit: Visit) => Promise<any>);
setVisitFormCallbacks: (callbacks: VisitFormCallbacks) => void;
visitFormOpenedFrom: string;
patientChartConfig?: {
showServiceQueueFields: boolean;
Expand All @@ -17,9 +20,9 @@ export interface VisitFormQueueFieldsProps {
* It is used slotted into the patient-chart's start visit form
*/
const VisitFormQueueFields: React.FC<VisitFormQueueFieldsProps> = (props) => {
const { setOnVisitCreatedOrUpdated, visitFormOpenedFrom, patientChartConfig } = props;
const { setVisitFormCallbacks, visitFormOpenedFrom, patientChartConfig } = props;
if (patientChartConfig.showServiceQueueFields || visitFormOpenedFrom == 'service-queues-add-patient') {
return <QueueFields setOnSubmit={setOnVisitCreatedOrUpdated} />;
return <QueueFields setOnSubmit={(onSubmit) => setVisitFormCallbacks({ onVisitCreatedOrUpdated: onSubmit })} />;
} else {
return <></>;
}
Expand Down
1 change: 0 additions & 1 deletion packages/esm-service-queues-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@
"serviceIsRequired": "Service is required",
"serviceQueue": "Service queue",
"serviceQueues": "Service queues",
"sortWeight": "Sort weight",
"sp02": "Sp02",
"startAgeRangeInvalid": "Start age range is not valid",
"status": "Status",
Expand Down

0 comments on commit 0e50e2c

Please sign in to comment.