From 9c17a6cf3106ddd25b72307dc972bae8769f5472 Mon Sep 17 00:00:00 2001 From: jabahum Date: Tue, 15 Oct 2024 14:33:06 +0300 Subject: [PATCH 1/3] initial commit --- .../active-visits-table.component.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx b/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx index 0a823aaa..d980ff26 100644 --- a/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx +++ b/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx @@ -193,15 +193,14 @@ const ActiveVisitsTable: React.FC = ({ status }) => { actions: { content: (
- {entry.status === 'COMPLETED' || - (entry.status === 'PENDING' && ( - <> - true} /> - {session?.user && userHasAccess(PRIVILEGE_ENABLE_EDIT_DEMOGRAPHICS, session.user) && ( - - )} - - ))} + {entry.status === 'PENDING' && ( + <> + true} /> + {session?.user && userHasAccess(PRIVILEGE_ENABLE_EDIT_DEMOGRAPHICS, session.user) && ( + + )} + + )}
From 6734fbbfbc992952fd743a1e613a5ed7d76fd409 Mon Sep 17 00:00:00 2001 From: jabahum Date: Tue, 15 Oct 2024 14:47:30 +0300 Subject: [PATCH 2/3] check for status completed to show view patient --- .../src/active-visits/active-visits-table.component.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx b/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx index d980ff26..8ac61faa 100644 --- a/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx +++ b/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx @@ -201,7 +201,10 @@ const ActiveVisitsTable: React.FC = ({ status }) => { )} )} - + + {entry.status === 'COMPLETED' && ( + + )} ), From e541a00823f525977b67937fb37c74ca3a5b0f69 Mon Sep 17 00:00:00 2001 From: jabahum Date: Tue, 15 Oct 2024 16:15:16 +0300 Subject: [PATCH 3/3] add action to move to next service point --- .../active-visits-table.component.tsx | 11 +- .../active-visits/active-visits-table.scss | 6 +- ...patient-to-next-action-menu.components.tsx | 30 ++ .../active-visits/notes-dialog.component.tsx | 3 - ...ue-table-move-to-next-dialog.component.tsx | 488 ++++++++++++++++++ packages/esm-patient-queues-app/src/index.ts | 8 +- .../esm-patient-queues-app/src/routes.json | 4 + 7 files changed, 539 insertions(+), 11 deletions(-) create mode 100644 packages/esm-patient-queues-app/src/active-visits/move-patient-to-next-action-menu.components.tsx create mode 100644 packages/esm-patient-queues-app/src/active-visits/queue-table-move-to-next-dialog.component.tsx diff --git a/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx b/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx index 8ac61faa..998a50cc 100644 --- a/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx +++ b/packages/esm-patient-queues-app/src/active-visits/active-visits-table.component.tsx @@ -15,6 +15,7 @@ import { TableToolbarSearch, Tag, Tile, + Toggle, } from '@carbon/react'; import { isDesktop, useLayoutType, usePagination, userHasAccess, useSession } from '@openmrs/esm-framework'; @@ -38,6 +39,7 @@ import NotesActionsMenu from './notes-action-menu.components'; import { PRIVILEGE_ENABLE_EDIT_DEMOGRAPHICS } from '../constants'; import PatientSearch from '../patient-search/patient-search.component'; import { QueueStatus } from '../utils/utils'; +import MovetoNextPointAction from './move-patient-to-next-action-menu.components'; interface ActiveVisitsTableProps { status: string; @@ -202,10 +204,11 @@ const ActiveVisitsTable: React.FC = ({ status }) => { )} - {entry.status === 'COMPLETED' && ( - - )} + + + {entry.status === 'SERVING' || + (entry.status === 'PENDING' && )} ), }, @@ -229,7 +232,7 @@ const ActiveVisitsTable: React.FC = ({ status }) => { - + div { + >div { max-height: max-content !important; background-color: $ui-02; } } - th[colspan] td[colspan] > div:first-child { + th[colspan] td[colspan]>div:first-child { padding: 0 1rem; } } @@ -273,4 +273,4 @@ color: $interactive-01; margin-top: 0.5rem; cursor: pointer; -} +} \ No newline at end of file diff --git a/packages/esm-patient-queues-app/src/active-visits/move-patient-to-next-action-menu.components.tsx b/packages/esm-patient-queues-app/src/active-visits/move-patient-to-next-action-menu.components.tsx new file mode 100644 index 00000000..162ad8dd --- /dev/null +++ b/packages/esm-patient-queues-app/src/active-visits/move-patient-to-next-action-menu.components.tsx @@ -0,0 +1,30 @@ +import { Button } from '@carbon/react'; +import { ArrowRight } from '@carbon/react/icons'; +import React, { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; +import { showModal } from '@openmrs/esm-framework'; + +interface MovetoNextPointActionProps { + patientUuid: string; +} + +const MovetoNextPointAction: React.FC = ({ patientUuid }) => { + const { t } = useTranslation(); + + const openModal = useCallback(() => { + const dispose = showModal('queue-table-move-to-next-service-point-modal', { + patientUuid, + closeModal: () => dispose(), + }); + }, [patientUuid]); + + return ( + - diff --git a/packages/esm-patient-queues-app/src/active-visits/queue-table-move-to-next-dialog.component.tsx b/packages/esm-patient-queues-app/src/active-visits/queue-table-move-to-next-dialog.component.tsx new file mode 100644 index 00000000..73e13967 --- /dev/null +++ b/packages/esm-patient-queues-app/src/active-visits/queue-table-move-to-next-dialog.component.tsx @@ -0,0 +1,488 @@ +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { + Button, + ContentSwitcher, + Form, + ModalBody, + ModalFooter, + ModalHeader, + Select, + SelectItem, + Switch, + TextArea, + InlineLoading, +} from '@carbon/react'; +import { useTranslation } from 'react-i18next'; +import { getSessionStore, navigate, showNotification, showToast, useSession, useVisit } from '@openmrs/esm-framework'; +import { addQueueEntry, getCareProvider, updateQueueEntry } from './active-visits-table.resource'; +import { useQueueRoomLocations } from '../hooks/useQueueRooms'; +import { getCurrentPatientQueueByPatientUuid, useProviders } from '../visit-form/queue.resource'; +import styles from './change-status-dialog.scss'; +import { QueueStatus, extractErrorMessagesFromResponse } from '../utils/utils'; + +interface ChangeStatusDialogProps { + patientUuid: string; + closeModal: () => void; +} + +const QueueTableMoveToNext: React.FC = ({ patientUuid, closeModal }) => { + const { t } = useTranslation(); + + const sessionUser = useSession(); + + const { providers } = useProviders(); + + const [isLoading, setIsLoading] = useState(true); + + const [contentSwitcherIndex, setContentSwitcherIndex] = useState(1); + + const [statusSwitcherIndex, setStatusSwitcherIndex] = useState(1); + + const [status, setStatus] = useState(''); + + const { queueRoomLocations, mutate } = useQueueRoomLocations(sessionUser?.sessionLocation?.uuid); + + const [selectedNextQueueLocation, setSelectedNextQueueLocation] = useState(queueRoomLocations[0]?.uuid); + + const [provider, setProvider] = useState(''); + + const [priorityComment, setPriorityComment] = useState(''); + + const [selectedProvider, setSelectedProvider] = useState(''); + + // Memoize the function to fetch the provider using useCallback + const fetchProvider = useCallback(() => { + if (!sessionUser?.user?.uuid) return; + + setIsLoading(true); + + getCareProvider(sessionUser?.user?.uuid).then( + (response) => { + const uuid = response?.data?.results[0].uuid; + setIsLoading(false); + setProvider(uuid); + mutate(); + }, + (error) => { + const errorMessages = extractErrorMessagesFromResponse(error); + setIsLoading(false); + showNotification({ + title: "Couldn't get provider", + kind: 'error', + critical: true, + description: errorMessages.join(','), + }); + }, + ); + }, [sessionUser?.user?.uuid, mutate]); + + useEffect(() => fetchProvider(), [fetchProvider]); + + useMemo(() => { + switch (statusSwitcherIndex) { + case 0: { + setStatus(QueueStatus.Pending); + break; + } + case 1: { + setStatus(QueueStatus.Completed); + break; + } + } + }, [statusSwitcherIndex]); + + useMemo(() => { + switch (contentSwitcherIndex) { + case 0: { + setPriorityComment('Not Urgent'); + break; + } + case 1: { + setPriorityComment('Urgent'); + break; + } + case 2: { + setPriorityComment('Emergency'); + break; + } + } + }, [contentSwitcherIndex]); + + const filteredlocations = queueRoomLocations?.filter((location) => location?.uuid != null); + + const filteredProviders = providers?.flatMap((provider) => + provider.attributes.filter( + (item) => + item.attributeType.display === 'Default Location' && + typeof item.value === 'object' && + item?.value?.uuid === selectedNextQueueLocation, + ).length > 0 + ? provider + : [], + ); + + // change to picked + const changeQueueStatus = useCallback( + (event: { preventDefault: () => void; target: { [x: string]: { value: string } } }) => { + event.preventDefault(); + + // check status + if (status === QueueStatus.Pending) { + const comment = event?.target['nextNotes']?.value ?? 'Not Set'; + getCurrentPatientQueueByPatientUuid(patientUuid, sessionUser?.sessionLocation?.uuid).then( + (res) => { + const queues = res.data?.results[0]?.patientQueues; + const queueEntry = queues?.filter((item) => item?.patient?.uuid === patientUuid); + + if (queueEntry.length > 0) { + updateQueueEntry(status, provider, queueEntry[0]?.uuid, 0, priorityComment, comment).then(() => { + showToast({ + critical: true, + title: t('moveToNextServicePoint', 'Move back your service point'), + kind: 'success', + description: t('backToQueue', 'Successfully moved back patient to your service point'), + }); + closeModal(); + mutate(); + }); + } else if (queueEntry.length === 1) { + updateQueueEntry(status, provider, queueEntry[0]?.uuid, 0, priorityComment, comment).then(() => { + showToast({ + critical: true, + title: t('moveToNextServicePoint', 'Move back your service point'), + kind: 'success', + description: t('backToQueue', 'Successfully moved back patient to your service point'), + }); + closeModal(); + mutate(); + }); + } + }, + (error) => { + const errorMessages = extractErrorMessagesFromResponse(error); + showNotification({ + title: t('errorMovinPatientToNextServicePoint', 'Error Moving Patient to next service point'), + kind: 'error', + critical: true, + description: errorMessages.join(','), + }); + }, + ); + } else if (status === QueueStatus.Completed) { + const comment = event?.target['nextNotes']?.value ?? 'Not Set'; + + getCurrentPatientQueueByPatientUuid(patientUuid, sessionUser?.sessionLocation?.uuid).then( + (res) => { + const queues = res.data?.results[0]?.patientQueues; + const queueEntry = queues?.filter((item) => item?.patient?.uuid === patientUuid); + + if (queueEntry.length > 0) { + updateQueueEntry( + QueueStatus.Completed, + provider, + queueEntry[0]?.uuid, + contentSwitcherIndex, + priorityComment, + comment, + ).then( + () => { + mutate(); + addQueueEntry( + selectedNextQueueLocation, + patientUuid, + selectedProvider, + contentSwitcherIndex, + QueueStatus.Pending, + sessionUser?.sessionLocation?.uuid, + priorityComment, + comment, + ).then( + (res) => { + mutate(); + updateQueueEntry( + QueueStatus.Pending, + selectedProvider, + res.data?.uuid, + contentSwitcherIndex, + priorityComment, + comment, + ).then( + () => { + showToast({ + critical: true, + title: t('moveToNextServicePoint', 'Move to next service point'), + kind: 'success', + description: t('movetonextservicepoint', 'Moved to next service point successfully'), + }); + // view patient summary + // navigate({ to: `\${openmrsSpaBase}/home` }); + const roles = getSessionStore().getState().session?.user?.roles; + const roleName = roles[0]?.display; + if (roles && roles?.length > 0) { + if (roles?.filter((item) => item?.display === 'Organizational: Clinician').length > 0) { + navigate({ + to: `${window.getOpenmrsSpaBase()}home/clinical-room-patient-queues`, + }); + } else if (roleName === 'Triage') { + navigate({ + to: `${window.getOpenmrsSpaBase()}home/triage-patient-queues`, + }); + } else { + navigate({ to: `${window.getOpenmrsSpaBase()}home` }); + } + } + + mutate(); + closeModal(); + }, + (error) => { + const errorMessages = extractErrorMessagesFromResponse(error); + showNotification({ + title: t('queueEntryUpdateFailed', 'Error updating next service point'), + kind: 'error', + critical: true, + description: errorMessages.join(','), + }); + }, + ); + closeModal(); + mutate(); + }, + (error) => { + const errorMessages = extractErrorMessagesFromResponse(error); + + showNotification({ + title: t('queueEntryUpdateFailed', 'Error updating next service point'), + kind: 'error', + critical: true, + description: errorMessages.join(','), + }); + }, + ); + }, + () => { + mutate(); + }, + ); + } else if (queueEntry.length === 1) { + updateQueueEntry( + QueueStatus.Completed, + provider, + queueEntry[0]?.uuid, + contentSwitcherIndex, + priorityComment, + comment, + ).then( + () => { + mutate(); + addQueueEntry( + selectedNextQueueLocation, + patientUuid, + selectedProvider, + contentSwitcherIndex, + QueueStatus.Pending, + sessionUser?.sessionLocation?.uuid, + priorityComment, + comment, + ).then( + (res) => { + mutate(); + updateQueueEntry( + QueueStatus.Pending, + selectedProvider, + res.data?.uuid, + contentSwitcherIndex, + priorityComment, + comment, + ).then( + () => { + showToast({ + critical: true, + title: t('successfullyMovedToNextServicePoint', 'Moved to Next Service Point'), + kind: 'success', + description: t('movetonextservicepoint', 'Successfully moved to next service point'), + }); + // view patient summary + const roles = getSessionStore().getState().session?.user?.roles; + const roleName = roles[0]?.display; + if (roles && roles?.length > 0) { + if (roles?.filter((item) => item?.display === 'Organizational: Clinician').length > 0) { + navigate({ + to: `${window.getOpenmrsSpaBase()}home/clinical-room-patient-queues`, + }); + } else if (roleName === 'Triage') { + navigate({ + to: `${window.getOpenmrsSpaBase()}home/triage-patient-queues`, + }); + } else { + navigate({ to: `${window.getOpenmrsSpaBase()}home` }); + } + } + mutate(); + closeModal(); + }, + (error) => { + const errorMessages = extractErrorMessagesFromResponse(error); + showNotification({ + title: t('errorGettingPatientQueueEntry', 'Error Moving Patient to next service point'), + kind: 'error', + critical: true, + description: errorMessages.join(','), + }); + }, + ); + closeModal(); + mutate(); + }, + (error) => { + const errorMessages = extractErrorMessagesFromResponse(error); + + showNotification({ + title: t('errorUpdatingServicePoint', 'Error updating next service point status'), + kind: 'error', + critical: true, + description: errorMessages.join(','), + }); + }, + ); + }, + () => { + mutate(); + }, + ); + } + }, + (error) => { + const errorMessages = extractErrorMessagesFromResponse(error); + showNotification({ + title: t('errorUpdatingServicePoint', 'Error updating next service point status'), + kind: 'error', + critical: true, + description: errorMessages.join(','), + }); + }, + ); + } + }, + [ + closeModal, + contentSwitcherIndex, + mutate, + patientUuid, + priorityComment, + provider, + selectedNextQueueLocation, + selectedProvider, + sessionUser?.sessionLocation?.uuid, + status, + t, + ], + ); + + return ( +
+
+ + +
+
+

Queue to next service area

+
+
+
+
{t('priority', 'Priority')}
+ setContentSwitcherIndex(index)} + > + + + + +
+ +
+
{t('status', 'Status')}
+ setStatusSwitcherIndex(index)} + > + + + +
+ + {status === QueueStatus.Completed && ( +
+ +
+ )} + + {status === QueueStatus.Completed && ( +
+ +
+ )} + + {status === QueueStatus.Completed && ( +
+