From c8314343ffe88d8ca8efd48ec0acbdc85e0f0979 Mon Sep 17 00:00:00 2001 From: jwnasambu Date: Fri, 3 Nov 2023 16:06:51 +0300 Subject: [PATCH 1/5] (fix)03-2426: Closing drug search panel should send user back to order basket if they previously had it open --- .../src/workspace/workspace-window.component.tsx | 11 ++++++++--- .../drug-order-basket-panel.extension.tsx | 11 +++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx b/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx index c61c84fe13..43d4f9d53b 100644 --- a/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx +++ b/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx @@ -36,6 +36,7 @@ const WorkspaceWindow: React.FC = () => { }, [workspaces, patientUuid]); const workspaceTitle = workspaces[0]?.additionalProps?.['workspaceTitle'] ?? workspaces[0]?.title ?? ''; + const onCloseWorkspace = workspaces[0]?.additionalProps?.['onCloseWorkspace'] ?? null; const { canHide = false, canMaximize = false, @@ -59,7 +60,7 @@ const WorkspaceWindow: React.FC = () => { className={`${styles.header} ${maximized ? `${styles.fullWidth}` : `${styles.dynamicWidth}`}`} > {layout === 'tablet' && !canHide && ( - } onClick={closeWorkspace} /> + } onClick={onCloseWorkspace ?? closeWorkspace} /> )} {workspaceTitle} @@ -89,7 +90,7 @@ const WorkspaceWindow: React.FC = () => { closeWorkspace?.()} + onClick={() => onCloseWorkspace?.() ?? closeWorkspace?.()} size="lg" > @@ -98,7 +99,11 @@ const WorkspaceWindow: React.FC = () => { )} {layout === 'tablet' && canHide && ( - closeWorkspace?.()}> + onCloseWorkspace?.() ?? closeWorkspace?.()} + > )} diff --git a/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx b/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx index 6eca3f7e08..f1d60f7840 100644 --- a/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx +++ b/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'; import { Button, Tile } from '@carbon/react'; import { Add, ChevronDown, ChevronUp } from '@carbon/react/icons'; import { useLayoutType } from '@openmrs/esm-framework'; -import { launchPatientWorkspace, useOrderBasket } from '@openmrs/esm-patient-common-lib'; +import { closeWorkspace, launchPatientWorkspace, useOrderBasket } from '@openmrs/esm-patient-common-lib'; import { prepMedicationOrderPostData } from '../api/api'; import type { DrugOrderBasketItem } from '../types'; import OrderBasketItemTile from './order-basket-item-tile.component'; @@ -23,8 +23,15 @@ export default function DrugOrderBasketPanelExtension() { const revisedOrderBasketItems = orders.filter((x) => x.action === 'REVISE'); const discontinuedOrderBasketItems = orders.filter((x) => x.action === 'DISCONTINUE'); + const onClose = useCallback(() => { + closeWorkspace('add-drug-order', true); + launchPatientWorkspace('order-basket'); + }, []); + const openDrugSearch = () => { - launchPatientWorkspace('add-drug-order'); + launchPatientWorkspace('add-drug-order', { + onCloseWorkspace: onClose, + }); }; const openDrugForm = (order: DrugOrderBasketItem) => { From 5bae1fc91b18c06d038c063b9a6edf15fe3e0e8b Mon Sep 17 00:00:00 2001 From: Vineet Sharma Date: Mon, 20 Nov 2023 09:06:51 +0530 Subject: [PATCH 2/5] Closing workspace should call the onCloseWorkspace --- .../workspace/workspace-window.component.tsx | 13 +++----- .../src/workspaces/workspaces.test.ts | 19 +++++++++-- .../src/workspaces/workspaces.ts | 32 +++++++++++++++---- .../drug-order-basket-panel.extension.tsx | 1 - 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx b/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx index 43d4f9d53b..e84878b360 100644 --- a/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx +++ b/packages/esm-patient-chart-app/src/workspace/workspace-window.component.tsx @@ -36,7 +36,6 @@ const WorkspaceWindow: React.FC = () => { }, [workspaces, patientUuid]); const workspaceTitle = workspaces[0]?.additionalProps?.['workspaceTitle'] ?? workspaces[0]?.title ?? ''; - const onCloseWorkspace = workspaces[0]?.additionalProps?.['onCloseWorkspace'] ?? null; const { canHide = false, canMaximize = false, @@ -60,7 +59,7 @@ const WorkspaceWindow: React.FC = () => { className={`${styles.header} ${maximized ? `${styles.fullWidth}` : `${styles.dynamicWidth}`}`} > {layout === 'tablet' && !canHide && ( - } onClick={onCloseWorkspace ?? closeWorkspace} /> + } onClick={closeWorkspace} /> )} {workspaceTitle} @@ -74,7 +73,7 @@ const WorkspaceWindow: React.FC = () => { onClick={toggleWindowState} size="lg" > - {maximized ? : } + {maximized ? : } )} {canHide ? ( @@ -90,7 +89,7 @@ const WorkspaceWindow: React.FC = () => { onCloseWorkspace?.() ?? closeWorkspace?.()} + onClick={() => closeWorkspace?.()} size="lg" > @@ -99,11 +98,7 @@ const WorkspaceWindow: React.FC = () => { )} {layout === 'tablet' && canHide && ( - onCloseWorkspace?.() ?? closeWorkspace?.()} - > + closeWorkspace?.()}> )} diff --git a/packages/esm-patient-common-lib/src/workspaces/workspaces.test.ts b/packages/esm-patient-common-lib/src/workspaces/workspaces.test.ts index 66f526f0b9..af7821a093 100644 --- a/packages/esm-patient-common-lib/src/workspaces/workspaces.test.ts +++ b/packages/esm-patient-common-lib/src/workspaces/workspaces.test.ts @@ -28,13 +28,15 @@ describe('workspace system', () => { test('registering, launching, and closing a workspace', () => { const store = getWorkspaceStore(); + const mockedOnCloseWorkspace = jest.fn(); registerWorkspace({ name: 'allergies', title: 'Allergies', load: jest.fn() }); - launchPatientWorkspace('allergies', { foo: true }); + launchPatientWorkspace('allergies', { foo: true, onCloseWorkspace: mockedOnCloseWorkspace }); expect(store.getState().openWorkspaces.length).toEqual(1); const allergies = store.getState().openWorkspaces[0]; expect(allergies.name).toBe('allergies'); expect(allergies.additionalProps['foo']).toBe(true); allergies.closeWorkspace(); + expect(mockedOnCloseWorkspace).toHaveBeenCalled(); expect(store.getState().openWorkspaces.length).toEqual(0); }); @@ -304,11 +306,14 @@ describe('workspace system', () => { test('respects promptBeforeClosing function', () => { const store = getWorkspaceStore(); + const mockedOnCloseWorkspace = jest.fn(); registerWorkspace({ name: 'hiv', title: 'HIV', load: jest.fn() }); registerWorkspace({ name: 'diabetes', title: 'Diabetes', load: jest.fn() }); launchPatientWorkspace('hiv'); store.getState().openWorkspaces[0].promptBeforeClosing(() => false); - launchPatientWorkspace('diabetes'); + launchPatientWorkspace('diabetes', { + onCloseWorkspace: mockedOnCloseWorkspace, + }); expect(store.getState().prompt).toBeNull(); expect(store.getState().openWorkspaces[0].name).toBe('diabetes'); store.getState().openWorkspaces[0].promptBeforeClosing(() => true); @@ -316,6 +321,8 @@ describe('workspace system', () => { expect(store.getState().openWorkspaces[0].name).toBe('diabetes'); expect(store.getState().prompt.title).toBe('You have unsaved changes'); store.getState().prompt.onConfirm(); + // Should call the `onCloseWorkspace` function if passed + expect(mockedOnCloseWorkspace).toHaveBeenCalled(); expect(store.getState().openWorkspaces[0].name).toBe('hiv'); }); @@ -343,8 +350,11 @@ describe('workspace system', () => { test('respects promptBeforeClosing function before closing workspace, with unsaved changes', () => { const store = getWorkspaceStore(); + const mockedOnCloseWorkspace = jest.fn(); registerWorkspace({ name: 'hiv', title: 'HIV', load: jest.fn() }); - launchPatientWorkspace('hiv'); + launchPatientWorkspace('hiv', { + onCloseWorkspace: mockedOnCloseWorkspace, + }); store.getState().openWorkspaces[0].promptBeforeClosing(() => true); store.getState().openWorkspaces[0].closeWorkspace(false); expect(store.getState().prompt.title).toBe('Unsaved Changes'); @@ -353,6 +363,9 @@ describe('workspace system', () => { ); expect(store.getState().prompt.confirmText).toBe('Discard'); store.getState().prompt.onConfirm(); + expect(store.getState().prompt).toBeNull(); + // Should call the `onCloseWorkspace` function if passed + expect(mockedOnCloseWorkspace).toHaveBeenCalled(); expect(store.getState().openWorkspaces.length).toBe(0); }); }); diff --git a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts index c865568c03..0efc98029e 100644 --- a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts +++ b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts @@ -41,6 +41,12 @@ export interface WorkspaceRegistration { preferredWindowSize?: WorkspaceWindowState; } +interface WorkspaceAdditionalProps { + workspaceTitle?: string; + onCloseWorkspace?: () => void; + [x: string]: any; +} + let registeredWorkspaces: Record = {}; /** @@ -154,12 +160,12 @@ function promptBeforeLaunchingWorkspace( * @param name The name of the workspace to launch * @param additionalProps Props to pass to the workspace component being launched */ -export function launchPatientWorkspace(name: string, additionalProps?: object) { +export function launchPatientWorkspace(name: string, additionalProps?: WorkspaceAdditionalProps) { const store = getWorkspaceStore(); const workspace = getWorkspaceRegistration(name); const newWorkspace = { ...workspace, - closeWorkspace: (ignoreChanges = true) => closeWorkspace(name, ignoreChanges), + closeWorkspace: (ignoreChanges = true) => closeWorkspace(name, ignoreChanges, additionalProps?.onCloseWorkspace), promptBeforeClosing: (testFcn) => promptBeforeClosing(name, testFcn), additionalProps, }; @@ -239,9 +245,23 @@ export function cancelPrompt() { store.setState({ ...state, prompt: null }); } -export function closeWorkspace(name: string, ignoreChanges: boolean) { +export function closeWorkspace(name: string, ignoreChanges: boolean, onCloseWorkspace?: () => void) { const store = getWorkspaceStore(); const promptCheckFcn = getPromptBeforeClosingFcn(name); + const updateStoreWithClosedWorkspace = () => { + const state = store.getState(); + const newOpenWorkspaces = state.openWorkspaces.filter((w) => w.name !== name); + + store.setState({ + ...state, + prompt: null, + openWorkspaces: newOpenWorkspaces, + }); + + if (onCloseWorkspace && typeof onCloseWorkspace === 'function') { + onCloseWorkspace?.(); + } + }; if (!ignoreChanges && promptCheckFcn && promptCheckFcn()) { const prompt: Prompt = { title: translateFrom('@openmrs/esm-patient-chart-app', 'unsavedChangesTitleText', 'Unsaved Changes'), @@ -251,15 +271,13 @@ export function closeWorkspace(name: string, ignoreChanges: boolean) { `You have unsaved changes in the side panel. Do you want to discard these changes?`, ), onConfirm: () => { - const state = store.getState(); - store.setState({ ...state, prompt: null, openWorkspaces: state.openWorkspaces.filter((w) => w.name != name) }); + updateStoreWithClosedWorkspace(); }, confirmText: translateFrom('@openmrs/esm-patient-chart-app', 'discard', 'Discard'), }; store.setState({ ...store.getState(), prompt }); } else { - const state = store.getState(); - store.setState({ ...state, openWorkspaces: state.openWorkspaces.filter((w) => w.name != name) }); + updateStoreWithClosedWorkspace(); } } diff --git a/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx b/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx index f1d60f7840..6ec85cadfb 100644 --- a/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx +++ b/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx @@ -24,7 +24,6 @@ export default function DrugOrderBasketPanelExtension() { const discontinuedOrderBasketItems = orders.filter((x) => x.action === 'DISCONTINUE'); const onClose = useCallback(() => { - closeWorkspace('add-drug-order', true); launchPatientWorkspace('order-basket'); }, []); From de1baf462a642e02e3d49b62af9ba20a56a6f237 Mon Sep 17 00:00:00 2001 From: Ian Date: Tue, 21 Nov 2023 14:03:43 -0500 Subject: [PATCH 3/5] PR review follow-ups --- .../esm-patient-common-lib/src/workspaces/workspaces.ts | 8 ++++---- .../drug-order-basket-panel.extension.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts index 0efc98029e..36180dc7cc 100644 --- a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts +++ b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts @@ -249,6 +249,10 @@ export function closeWorkspace(name: string, ignoreChanges: boolean, onCloseWork const store = getWorkspaceStore(); const promptCheckFcn = getPromptBeforeClosingFcn(name); const updateStoreWithClosedWorkspace = () => { + if (onCloseWorkspace && typeof onCloseWorkspace === 'function') { + onCloseWorkspace?.(); + } + const state = store.getState(); const newOpenWorkspaces = state.openWorkspaces.filter((w) => w.name !== name); @@ -257,10 +261,6 @@ export function closeWorkspace(name: string, ignoreChanges: boolean, onCloseWork prompt: null, openWorkspaces: newOpenWorkspaces, }); - - if (onCloseWorkspace && typeof onCloseWorkspace === 'function') { - onCloseWorkspace?.(); - } }; if (!ignoreChanges && promptCheckFcn && promptCheckFcn()) { const prompt: Prompt = { diff --git a/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx b/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx index 3d70b9c55d..6fd7e0ab4a 100644 --- a/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx +++ b/packages/esm-patient-medications-app/src/drug-order-basket-panel/drug-order-basket-panel.extension.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import { Button, Tile } from '@carbon/react'; import { Add, ChevronDown, ChevronUp } from '@carbon/react/icons'; import { useLayoutType } from '@openmrs/esm-framework'; -import { closeWorkspace, launchPatientWorkspace, useOrderBasket } from '@openmrs/esm-patient-common-lib'; +import { launchPatientWorkspace, useOrderBasket } from '@openmrs/esm-patient-common-lib'; import { prepMedicationOrderPostData } from '../api/api'; import type { DrugOrderBasketItem } from '../types'; import OrderBasketItemTile from './order-basket-item-tile.component'; From b9460a466515fed59cfed7962c19f47fe923d577 Mon Sep 17 00:00:00 2001 From: Ian <52504170+ibacher@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:37:49 -0500 Subject: [PATCH 4/5] Add some error handling --- .../esm-patient-common-lib/src/workspaces/workspaces.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts index 36180dc7cc..83dc6f16f4 100644 --- a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts +++ b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts @@ -250,7 +250,11 @@ export function closeWorkspace(name: string, ignoreChanges: boolean, onCloseWork const promptCheckFcn = getPromptBeforeClosingFcn(name); const updateStoreWithClosedWorkspace = () => { if (onCloseWorkspace && typeof onCloseWorkspace === 'function') { - onCloseWorkspace?.(); + try { + onCloseWorkspace(); + } catch (e) { + console.error(`Custom 'onCloseWorkspace' for workspace ${name} caused an error`, e); + } } const state = store.getState(); From d59dc6daa13064a8fbe827102e413342242f1bb9 Mon Sep 17 00:00:00 2001 From: Ian <52504170+ibacher@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:40:04 -0500 Subject: [PATCH 5/5] Call onCloseWorkspace at end to allow launching workspace --- .../src/workspaces/workspaces.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts index 83dc6f16f4..496353d3d3 100644 --- a/packages/esm-patient-common-lib/src/workspaces/workspaces.ts +++ b/packages/esm-patient-common-lib/src/workspaces/workspaces.ts @@ -249,14 +249,6 @@ export function closeWorkspace(name: string, ignoreChanges: boolean, onCloseWork const store = getWorkspaceStore(); const promptCheckFcn = getPromptBeforeClosingFcn(name); const updateStoreWithClosedWorkspace = () => { - if (onCloseWorkspace && typeof onCloseWorkspace === 'function') { - try { - onCloseWorkspace(); - } catch (e) { - console.error(`Custom 'onCloseWorkspace' for workspace ${name} caused an error`, e); - } - } - const state = store.getState(); const newOpenWorkspaces = state.openWorkspaces.filter((w) => w.name !== name); @@ -265,6 +257,14 @@ export function closeWorkspace(name: string, ignoreChanges: boolean, onCloseWork prompt: null, openWorkspaces: newOpenWorkspaces, }); + + if (onCloseWorkspace && typeof onCloseWorkspace === 'function') { + try { + onCloseWorkspace(); + } catch (e) { + console.error(`Custom 'onCloseWorkspace' for workspace ${name} caused an error`, e); + } + } }; if (!ignoreChanges && promptCheckFcn && promptCheckFcn()) { const prompt: Prompt = {