Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
himanshu-malviya15 committed Feb 22, 2024
2 parents 5540d52 + 266ab0b commit 78b3e1b
Show file tree
Hide file tree
Showing 15 changed files with 73 additions and 62 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/tx-pull.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ jobs:

runs-on: ubuntu-latest
permissions:
actions: write
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Push source file using transifex client
uses: transifex/cli-action@v2
with:
token: ${{ secrets.TRANSIFEX_TOKEN }}
args: pull
args: pull --force --all
- name: Create PR if necessary
uses: peter-evans/create-pull-request@v5
with:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ interface AppointmentActionsProps {
visits: Array<any>;
appointment: Appointment;
scheduleType: string;
mutate: () => void;
}

const AppointmentActions: React.FC<AppointmentActionsProps> = ({ visits, appointment, mutate }) => {
const AppointmentActions: React.FC<AppointmentActionsProps> = ({ visits, appointment }) => {
const { t } = useTranslation();
const { mutateVisit } = useVisits();
const patientUuid = appointment.patient.uuid;
Expand Down Expand Up @@ -83,12 +82,7 @@ const AppointmentActions: React.FC<AppointmentActionsProps> = ({ visits, appoint
onClick={() =>
launchOverlay(
t('editAppointments', 'Edit Appointment'),
<AppointmentForm
appointment={appointment}
context="editing"
closeWorkspace={closeOverlay}
mutate={mutate}
/>,
<AppointmentForm appointment={appointment} context="editing" closeWorkspace={closeOverlay} />,
)
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ interface AppointmentsTableProps {
appointments: Array<Appointment>;
isLoading: boolean;
tableHeading: string;
mutate: () => void;
visits?: Array<any>;
scheduleType?: string;
}
Expand All @@ -46,7 +45,6 @@ const AppointmentsTable: React.FC<AppointmentsTableProps> = ({
appointments,
isLoading,
tableHeading,
mutate,
visits,
scheduleType,
}) => {
Expand Down Expand Up @@ -92,9 +90,7 @@ const AppointmentsTable: React.FC<AppointmentsTableProps> = ({
dateTime: formatDatetime(new Date(appointment.startDateTime)),
serviceType: appointment.service.name,
provider: appointment.provider,
actions: (
<AppointmentActions visits={visits} appointment={appointment} scheduleType={scheduleType} mutate={mutate} />
),
actions: <AppointmentActions visits={visits} appointment={appointment} scheduleType={scheduleType} />,
}));

if (isLoading) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { type AppointmentPayload } from '../../types';
import dayjs from 'dayjs';
import { omrsDateFormat } from '../../constants';

// TODO we will refactor all this stuff to use the cancel functionality from patient-chart (or vice versa, but will move into the forms directory regardless)
// TODO we should refactor all this stuff to use the cancel functionality from patient-chart (or vice versa, but should move into the forms directory regardless)

export const cancelAppointment = async (toStatus: string, appointmentUuid: string) => {
const abortController = new AbortController();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface AppointmentsByStatusProps {
date: string;
}
const AppointmentsByStatus: React.FC<AppointmentsByStatusProps> = ({ appointmentServiceType, status, title, date }) => {
const { appointmentList, isLoading, mutate } = useAppointmentList(status, date);
const { appointmentList, isLoading } = useAppointmentList(status, date);

const appointments = filterByServiceType(appointmentList, appointmentServiceType).map((appointment, index) => {
return {
Expand All @@ -19,7 +19,7 @@ const AppointmentsByStatus: React.FC<AppointmentsByStatusProps> = ({ appointment
};
});

return <AppointmentsTable appointments={appointments} isLoading={isLoading} tableHeading={title} mutate={mutate} />;
return <AppointmentsTable appointments={appointments} isLoading={isLoading} tableHeading={title} />;
};

export default AppointmentsByStatus;
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import { useTranslation } from 'react-i18next';
interface EarlyAppointmentsProps {
appointmentServiceType?: string;
date: string;
mutate: () => void;
}

/**
* Component to display early appointments
* Note that although we define this extension in routes.jsx, we currently don't wire it into the scheduled-appointments-panels-slot by default because it requests a custom endpoint (see useEarlyAppointments) not provided by the standard Bahmni Appointments module
*/
const EarlyAppointments: React.FC<EarlyAppointmentsProps> = ({ appointmentServiceType, date, mutate }) => {
const EarlyAppointments: React.FC<EarlyAppointmentsProps> = ({ appointmentServiceType, date }) => {
const { t } = useTranslation();
const { earlyAppointmentList, isLoading } = useEarlyAppointmentList(date);

Expand All @@ -26,12 +25,7 @@ const EarlyAppointments: React.FC<EarlyAppointmentsProps> = ({ appointmentServic
});

return (
<AppointmentsTable
appointments={appointments}
isLoading={isLoading}
tableHeading={t('cameEarly', 'Came Early')}
mutate={mutate}
/>
<AppointmentsTable appointments={appointments} isLoading={isLoading} tableHeading={t('cameEarly', 'Came Early')} />
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useLocations, useSession, showSnackbar, useLayoutType, useConfig } from '@openmrs/esm-framework';
import { convertTime12to24 } from '@openmrs/esm-patient-common-lib';
import { saveAppointment, saveRecurringAppointments, useAppointmentService } from './appointments-form.resource';
import {
saveAppointment,
saveRecurringAppointments,
useAppointmentService,
useMutateAppointments,
} from './appointments-form.resource';
import Workload from '../workload/workload.component';
import type { Appointment, AppointmentPayload, RecurringPattern } from '../types';
import { type ConfigObject } from '../config-schema';
Expand Down Expand Up @@ -62,7 +67,6 @@ interface AppointmentsFormProps {
patientUuid?: string;
context: string;
closeWorkspace: () => void;
mutate: () => void;
}

const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
Expand All @@ -71,8 +75,8 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
patientUuid,
context,
closeWorkspace,
mutate,
}) => {
const { mutate: mutateAppointments } = useMutateAppointments();
const editedAppointmentTimeFormat = new Date(appointment?.startDateTime).getHours() >= 12 ? 'PM' : 'AM';
const defaultTimeFormat = appointment?.startDateTime
? editedAppointmentTimeFormat
Expand Down Expand Up @@ -195,7 +199,7 @@ const AppointmentsForm: React.FC<AppointmentsFormProps> = ({
if (status === 200) {
setIsSubmitting(false);
closeWorkspace();
mutate();
mutateAppointments();

showSnackbar({
isLowContrast: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import dayjs from 'dayjs';
import useSWR from 'swr';
import useSWR, { useSWRConfig } from 'swr';
import { openmrsFetch } from '@openmrs/esm-framework';
import {
type AppointmentPayload,
Expand All @@ -8,9 +8,30 @@ import {
type RecurringAppointmentsPayload,
} from '../types';
import isToday from 'dayjs/plugin/isToday';
import { useCallback } from 'react';
dayjs.extend(isToday);

const appointmentsSearchUrl = `/ws/rest/v1/appointments/search`;
const appointmentUrlMatcher = '/ws/rest/v1/appointment';
const appointmentsSearchUrl = '/ws/rest/v1/appointments/search';

export function useMutateAppointments() {
const { mutate } = useSWRConfig();
// this mutate is intentionally broad because there may be many different keys that need to be invalidated when appointments are updated
const mutateAppointments = useCallback(
() =>
mutate((key) => {
return (
(typeof key === 'string' && key.startsWith(appointmentUrlMatcher)) ||
(Array.isArray(key) && key[0].startsWith(appointmentUrlMatcher))
);
}),
[mutate],
);

return {
mutate: mutateAppointments,
};
}

export function useAppointments(patientUuid: string, startDate: string, abortController: AbortController) {
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ import AppointmentForm from '../form/appointments-form.component';
import CancelAppointment from '../appointments/forms/cancel-form/cancel-appointment.component';
import PatientSearch from '../patient-search/patient-search.component';
import styles from './appointments-base-table.scss';
import { useMutateAppointments } from '../form/appointments-form.resource';

interface ActionMenuProps {
appointment: Appointment;
useBahmniUI?: string;
mutate: () => void;
}

export const ActionsMenu = ({ appointment, useBahmniUI, mutate }: ActionMenuProps) => {
export const ActionsMenu = ({ appointment, useBahmniUI }: ActionMenuProps) => {
const { t } = useTranslation();
const { bahmniAppointmentsUiBaseUrl } = useConfig();
const { mutate: mutateAppointments } = useMutateAppointments();

const { status } = appointment;
const disableActions = status === 'Completed' || status === 'Missed' || status === 'Cancelled';
Expand All @@ -37,7 +38,7 @@ export const ActionsMenu = ({ appointment, useBahmniUI, mutate }: ActionMenuProp
errorDescription,
successTitle,
errorTitle,
mutate,
mutateAppointments,
t,
);
};
Expand All @@ -60,12 +61,7 @@ export const ActionsMenu = ({ appointment, useBahmniUI, mutate }: ActionMenuProp
navigate({ to: `${spaHomePage}` });
launchOverlay(
t('editAppointment', 'Edit Appointment'),
<AppointmentForm
appointment={appointment}
context="editing"
closeWorkspace={closeOverlay}
mutate={mutate}
/>,
<AppointmentForm appointment={appointment} context="editing" closeWorkspace={closeOverlay} />,
);
}}
itemText={t('editAppointment', 'Edit Appointment')}>
Expand Down Expand Up @@ -117,7 +113,7 @@ export const ActionsMenu = ({ appointment, useBahmniUI, mutate }: ActionMenuProp
className={styles.menuItem}
id="#completeAppointment"
disabled={isScheduled || disableActions}
onClick={() => handleComplete(appointment.uuid, mutate, t)}
onClick={() => handleComplete(appointment.uuid, mutateAppointments, t)}
itemText={t('complete', 'Complete')}>
{t('complete', 'Complete')}
</OverflowMenuItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useMemo, useState } from 'react';
import classNames from 'classnames';
import type { KeyedMutator } from 'swr';
import { useTranslation } from 'react-i18next';
import {
Button,
Expand Down Expand Up @@ -37,6 +36,7 @@ import { useTodaysAppointments } from './home-appointments.resource';
import { type ConfigObject } from '../config-schema';
import { formatAMPM } from '../helpers';
import styles from './appointments-base-table.scss';
import { useMutateAppointments } from '../form/appointments-form.resource';

interface PaginationData {
goTo: (page: number) => void;
Expand All @@ -48,12 +48,10 @@ type RenderStatusProps = {
status: string;
t: (key: string, fallback: string) => string;
appointmentUuid: string;
mutate: KeyedMutator<{
data: Array<Appointment>;
}>;
};

const RenderStatus = ({ status, t, appointmentUuid, mutate }: RenderStatusProps) => {
const RenderStatus = ({ status, t, appointmentUuid }: RenderStatusProps) => {
const { mutate: mutateAppointments } = useMutateAppointments();
switch (status) {
case 'Completed':
return (
Expand All @@ -78,7 +76,7 @@ const RenderStatus = ({ status, t, appointmentUuid, mutate }: RenderStatusProps)
);
case 'CheckedIn':
return (
<Button kind="ghost" onClick={() => handleComplete(appointmentUuid, mutate, t)}>
<Button kind="ghost" onClick={() => handleComplete(appointmentUuid, mutateAppointments, t)}>
{t('complete', 'Complete')}
</Button>
);
Expand All @@ -100,7 +98,7 @@ const AppointmentsBaseTable = () => {
const { user } = useSession();
const { t } = useTranslation();
const { useBahmniAppointmentsUI: useBahmniUI, useFullViewPrivilege, fullViewPrivilege } = useConfig();
const { appointments, isLoading, mutate } = useTodaysAppointments();
const { appointments, isLoading } = useTodaysAppointments();

const fullView = userHasAccess(fullViewPrivilege, user) || !useFullViewPrivilege;
const { customPatientChartUrl } = useConfig<ConfigObject>();
Expand Down Expand Up @@ -199,7 +197,7 @@ const AppointmentsBaseTable = () => {
actionButton: {
content: (
<span>
<RenderStatus status={appointment.status} appointmentUuid={appointment.uuid} t={t} mutate={mutate} />
<RenderStatus status={appointment.status} appointmentUuid={appointment.uuid} t={t} />
</span>
),
},
Expand Down Expand Up @@ -304,11 +302,7 @@ const AppointmentsBaseTable = () => {
))}
{fullView && (
<TableCell className={classNames('cds--table-column-menu', styles.overflowMenu)}>
<ActionsMenu
appointment={filteredAppointments?.[index]}
useBahmniUI={useBahmniUI}
mutate={mutate}
/>
<ActionsMenu appointment={filteredAppointments?.[index]} useBahmniUI={useBahmniUI} />
</TableCell>
)}
</TableRow>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useState } from 'react';
import dayjs from 'dayjs';
import { Button, Layer, ModalBody, ModalFooter, ModalHeader, TimePicker } from '@carbon/react';
import { useSWRConfig } from 'swr';
import { useTranslation } from 'react-i18next';
import { showNotification, showActionableNotification } from '@openmrs/esm-framework';
import { updateAppointmentStatus } from '../home-appointments.resource';
import { handleUndoAction } from '../common';
import styles from './check-in-modal.scss';
import { useMutateAppointments } from '../../form/appointments-form.resource';

interface ChangeStatusDialogProps {
closeCheckInModal: () => void;
Expand All @@ -15,7 +15,7 @@ interface ChangeStatusDialogProps {

const CheckInAppointmentModal: React.FC<ChangeStatusDialogProps> = ({ closeCheckInModal, appointmentUuid }) => {
const { t } = useTranslation();
const { mutate } = useSWRConfig();
const { mutate: mutateAppointments } = useMutateAppointments();
const [checkInTime, setCheckInTime] = useState(dayjs(new Date()).format('hh:mm'));
const [isSubmitting, setIsSubmitting] = useState(false);

Expand All @@ -29,11 +29,11 @@ const CheckInAppointmentModal: React.FC<ChangeStatusDialogProps> = ({ closeCheck
kind: 'success',
actionButtonLabel: t('undo', 'Undo'),
progressActionLabel: t('revertingAppointmentStatus', 'Reverting appointment status'),
onActionButtonClick: () => handleUndoAction(appointmentUuid, mutate),
onActionButtonClick: () => handleUndoAction(appointmentUuid, mutateAppointments),
subtitle: t('appointmentSuccessfullyCheckedIn', 'It has been checked-in successfully'),
title: t('appointmentCheckedIn', 'Appointment Checked-in'),
});
mutate(`/ws/rest/v1/appointment/appointment/all`);
mutateAppointments();
} else {
showNotification({
title: t('appointmentCheckInError', 'Error checking in appointment'),
Expand Down
4 changes: 2 additions & 2 deletions packages/esm-appointments-app/src/home/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const launchCheckInAppointmentModal = (appointmentUuid: string) => {
export const handleUndoAction = async (appointmentUuid, mutate) => {
const { status } = await undoAppointmentStatus(appointmentUuid);
if (status === 200) {
mutate(`/ws/rest/v1/appointment/appointment/all`);
mutate();
} else {
showNotification({
title: 'Error Undoing',
Expand Down Expand Up @@ -43,7 +43,7 @@ export const handleUpdateStatus = async (
progressActionLabel: t('revertingAppointmentStatus', 'Reverting appointment status'),
onActionButtonClick: () => handleUndoAction(appointmentUuid, mutate),
});
mutate(`/ws/rest/v1/appointment/appointment/all`);
mutate();
} else {
showNotification({
title: errorTitle,
Expand Down
2 changes: 2 additions & 0 deletions packages/esm-appointments-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,5 @@ export const homeAppointments = getSyncLifecycle(homeAppointmentsComponent, opti
export const appointmentsByStatus = getSyncLifecycle(appointmentStatusComponent, options);

export const earlyAppointments = getSyncLifecycle(earlyAppointmentsComponent, options);

export const appointmentsFormWorkspace = getAsyncLifecycle(() => import('./form/appointments-form.component'), options);
Loading

0 comments on commit 78b3e1b

Please sign in to comment.