diff --git a/packages/framework/esm-framework/docs/API.md b/packages/framework/esm-framework/docs/API.md index f009405bb..10cbadff7 100644 --- a/packages/framework/esm-framework/docs/API.md +++ b/packages/framework/esm-framework/docs/API.md @@ -7031,7 +7031,7 @@ Function to close an opened workspace #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:282](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L282) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:288](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L288) ___ @@ -7082,7 +7082,7 @@ prop named `workspaceTitle` will override the title of the workspace. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:165](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L165) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:166](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L166) ___ @@ -7108,7 +7108,7 @@ Use this function to navigate to a new page and launch a workspace on that page. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:245](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L245) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:251](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L251) ___ @@ -7122,4 +7122,4 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:384](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L384) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:402](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L402) diff --git a/packages/framework/esm-framework/docs/interfaces/CloseWorkspaceOptions.md b/packages/framework/esm-framework/docs/interfaces/CloseWorkspaceOptions.md index cba18139c..fc45bca58 100644 --- a/packages/framework/esm-framework/docs/interfaces/CloseWorkspaceOptions.md +++ b/packages/framework/esm-framework/docs/interfaces/CloseWorkspaceOptions.md @@ -25,7 +25,7 @@ even if the `testFcn` passed to `promptBeforeClosing` returns `true`. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:18](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L18) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:19](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L19) ## Workspace Methods @@ -45,4 +45,4 @@ void #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:25](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L25) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:26](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L26) diff --git a/packages/framework/esm-framework/docs/interfaces/DefaultWorkspaceProps.md b/packages/framework/esm-framework/docs/interfaces/DefaultWorkspaceProps.md index 1fc11245f..2ccae3c3b 100644 --- a/packages/framework/esm-framework/docs/interfaces/DefaultWorkspaceProps.md +++ b/packages/framework/esm-framework/docs/interfaces/DefaultWorkspaceProps.md @@ -43,7 +43,7 @@ closed, given the user forcefully closes the workspace. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:37](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L37) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:38](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L38) ___ @@ -66,7 +66,7 @@ will directly close the workspace without any prompt #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:47](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L47) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:48](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L48) ___ @@ -89,7 +89,7 @@ this workspace is closed; e.g. if there is unsaved data. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:42](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L42) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:43](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L43) ___ @@ -117,4 +117,4 @@ title needs to be set dynamically. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:62](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L62) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:63](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L63) diff --git a/packages/framework/esm-framework/docs/interfaces/OpenWorkspace.md b/packages/framework/esm-framework/docs/interfaces/OpenWorkspace.md index 4b8c0edef..e85380c05 100644 --- a/packages/framework/esm-framework/docs/interfaces/OpenWorkspace.md +++ b/packages/framework/esm-framework/docs/interfaces/OpenWorkspace.md @@ -202,7 +202,7 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:97](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L97) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:98](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L98) ## Methods @@ -232,7 +232,7 @@ closed, given the user forcefully closes the workspace. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:37](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L37) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:38](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L38) ___ @@ -259,7 +259,7 @@ will directly close the workspace without any prompt #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:47](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L47) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:48](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L48) ___ @@ -304,7 +304,7 @@ this workspace is closed; e.g. if there is unsaved data. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:42](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L42) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:43](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L43) ___ @@ -336,4 +336,4 @@ title needs to be set dynamically. #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:62](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L62) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:63](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L63) diff --git a/packages/framework/esm-framework/docs/interfaces/Prompt.md b/packages/framework/esm-framework/docs/interfaces/Prompt.md index 4616e2b9a..318476751 100644 --- a/packages/framework/esm-framework/docs/interfaces/Prompt.md +++ b/packages/framework/esm-framework/docs/interfaces/Prompt.md @@ -23,7 +23,7 @@ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:81](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L81) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:82](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L82) ___ @@ -35,7 +35,7 @@ Defaults to "Cancel" #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:86](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L86) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:87](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L87) ___ @@ -47,7 +47,7 @@ Defaults to "Confirm" #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:83](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L83) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:84](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L84) ___ @@ -57,7 +57,7 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:80](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L80) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:81](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L81) ## Methods @@ -71,4 +71,4 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:84](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L84) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:85](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L85) diff --git a/packages/framework/esm-framework/docs/interfaces/WorkspacesInfo.md b/packages/framework/esm-framework/docs/interfaces/WorkspacesInfo.md index ef2245b51..573647531 100644 --- a/packages/framework/esm-framework/docs/interfaces/WorkspacesInfo.md +++ b/packages/framework/esm-framework/docs/interfaces/WorkspacesInfo.md @@ -19,7 +19,7 @@ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:378](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L378) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:396](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L396) ___ @@ -29,7 +29,7 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:379](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L379) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:397](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L397) ___ @@ -39,7 +39,7 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:380](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L380) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:398](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L398) ___ @@ -49,4 +49,4 @@ ___ #### Defined in -[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:381](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L381) +[packages/framework/esm-styleguide/src/workspaces/workspaces.ts:399](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces/workspaces.ts#L399) diff --git a/packages/framework/esm-styleguide/src/workspaces/container/workspace-renderer.component.tsx b/packages/framework/esm-styleguide/src/workspaces/container/workspace-renderer.component.tsx index 0c7bdb66e..ff8579bd5 100644 --- a/packages/framework/esm-styleguide/src/workspaces/container/workspace-renderer.component.tsx +++ b/packages/framework/esm-styleguide/src/workspaces/container/workspace-renderer.component.tsx @@ -5,6 +5,7 @@ import { InlineLoading } from '@carbon/react'; import { getCoreTranslation } from '@openmrs/esm-translations'; import styles from './workspace.module.scss'; import { type OpenWorkspace } from '../workspaces'; +import { useWorkspaceFamilyStore } from '../workspace-sidebar-store/useWorkspaceFamilyStore'; interface WorkspaceRendererProps { workspace: OpenWorkspace; @@ -13,6 +14,7 @@ interface WorkspaceRendererProps { export function WorkspaceRenderer({ workspace, additionalPropsFromPage }: WorkspaceRendererProps) { const [lifecycle, setLifecycle] = useState(); + const workspaceFamilyState = useWorkspaceFamilyStore(workspace.sidebarFamily); useEffect(() => { let active = true; @@ -34,6 +36,7 @@ export function WorkspaceRenderer({ workspace, additionalPropsFromPage }: Worksp promptBeforeClosing: workspace.promptBeforeClosing, setTitle: workspace.setTitle, ...additionalPropsFromPage, + ...workspaceFamilyState, ...workspace.additionalProps, }, [workspace, additionalPropsFromPage], diff --git a/packages/framework/esm-styleguide/src/workspaces/workspace-sidebar-store/useWorkspaceFamilyStore.ts b/packages/framework/esm-styleguide/src/workspaces/workspace-sidebar-store/useWorkspaceFamilyStore.ts new file mode 100644 index 000000000..c3e5d8b02 --- /dev/null +++ b/packages/framework/esm-styleguide/src/workspaces/workspace-sidebar-store/useWorkspaceFamilyStore.ts @@ -0,0 +1,40 @@ +import { useEffect, useMemo, useState } from 'react'; +import { getWorkspaceFamilyStore } from '../workspaces'; +import type { StoreApi } from 'zustand/vanilla'; + +/** + * This hook is used to interact with the store of a workspace family. + * A workspace family is defined as a group of workspaces that share the same sidebarFamilyName. + * + * In case a workspace doesn't have a sidebarFamilyName, it will be considered as a standalone workspace, and hence this hook will return an empty object and updateFunction as an empty function. + * + * @internal + * + * @param {string} sidebarFamilyName The sidebarFamilyName of the workspace used when registering the workspace in the module's routes.json file. + */ +export function useWorkspaceFamilyStore(sidebarFamilyName: string) { + const [storeState, setStoreState] = useState({}); + const [currentSidebarFamilyName, setCurrentSidebarFamilyName] = useState(sidebarFamilyName); + + useEffect(() => { + if (currentSidebarFamilyName !== sidebarFamilyName) { + setCurrentSidebarFamilyName(sidebarFamilyName); + } + }, [sidebarFamilyName]); + + useEffect(() => { + const store = getWorkspaceFamilyStore(currentSidebarFamilyName); + let unsubscribe: () => void; + if (store) { + setStoreState(store.getState()); + unsubscribe = store.subscribe(setStoreState); + } + return () => { + if (store) { + unsubscribe?.(); + } + }; + }, [currentSidebarFamilyName]); + + return storeState; +} diff --git a/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts b/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts index 13a450ad7..a2715577f 100644 --- a/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts +++ b/packages/framework/esm-styleguide/src/workspaces/workspaces.test.ts @@ -1,6 +1,14 @@ -import { type Prompt, cancelPrompt, getWorkspaceStore, launchWorkspace, resetWorkspaceStore } from './workspaces'; +import { + type Prompt, + cancelPrompt, + getWorkspaceFamilyStore, + getWorkspaceStore, + launchWorkspace, + resetWorkspaceStore, +} from './workspaces'; import { registerExtension, registerWorkspace } from '@openmrs/esm-extensions'; import { clearMockExtensionRegistry } from '@openmrs/esm-framework/mock'; +import { waitFor } from '@testing-library/dom'; describe('workspace system', () => { beforeEach(() => { @@ -429,4 +437,147 @@ describe('workspace system', () => { expect(store.getState().prompt).toBeNull(); expect(store.getState().openWorkspaces.length).toBe(0); }); + + describe('Testing `getWorkspaceFamilyStore` function', () => { + it('should return undefined if no workspace sidebar name is passed', () => { + let workspaceFamilyStore = getWorkspaceFamilyStore(undefined); + expect(workspaceFamilyStore).toBeUndefined(); + workspaceFamilyStore = getWorkspaceFamilyStore('default'); + expect(workspaceFamilyStore).toBeUndefined(); + }); + + it('should return store if workspace sidebar name is passed', () => { + const workspaceFamilyStore = getWorkspaceFamilyStore('ward-patient-sidebar', { + foo: true, + }); + expect(workspaceFamilyStore).toBeTruthy(); + expect(workspaceFamilyStore?.getState()?.['foo']).toBe(true); + }); + + it('should update the store state with new additionalProps if workspaces with same sidebarFamily name calls the function', () => { + let workspaceFamilyStore = getWorkspaceFamilyStore('ward-patient-sidebar', { + foo: true, + }); + expect(workspaceFamilyStore).toBeTruthy(); + expect(workspaceFamilyStore?.getState()?.['foo']).toBe(true); + workspaceFamilyStore = getWorkspaceFamilyStore('ward-patient-sidebar', { + bar: true, + }); + expect(workspaceFamilyStore).toBeTruthy(); + expect(workspaceFamilyStore?.getState()?.['foo']).toBe(true); + expect(workspaceFamilyStore?.getState()?.['bar']).toBe(true); + }); + }); + + describe('Testing workspace family store', () => { + it('should create store for workspaces with sidebarFamilyName', () => { + registerWorkspace({ + name: 'allergies', + title: 'Allergies', + load: jest.fn(), + moduleName: '@openmrs/foo', + }); + registerWorkspace({ + name: 'ward-patient-workspace', + title: 'Ward Patient Workspace', + load: jest.fn(), + type: 'ward-patient', + moduleName: '@openmrs/esm-ward-app', + hasOwnSidebar: true, + sidebarFamily: 'ward-patient-sidebar', + }); + launchWorkspace('ward-patient-workspace'); + const workspaceFamilyStore = getWorkspaceFamilyStore('ward-patient-sidebar'); + const workspaceStore = getWorkspaceStore(); + expect(workspaceStore.getState().openWorkspaces.length).toBe(1); + expect(workspaceStore.getState().openWorkspaces[0].name).toBe('ward-patient-workspace'); + expect(workspaceFamilyStore).toBeTruthy(); + workspaceStore.getState().openWorkspaces[0].closeWorkspace({ ignoreChanges: true }); + launchWorkspace('allergies'); + expect(workspaceStore.getState().openWorkspaces.length).toBe(1); + expect(workspaceStore.getState().openWorkspaces[0].name).toBe('allergies'); + expect(workspaceFamilyStore?.getState()).toStrictEqual({}); + }); + + it('should share the same store with different workspaces with same sidebarFamilyName', () => { + const sidebarFamily = 'ward-patient-sidebar'; + registerWorkspace({ + name: 'ward-patient-workspace', + title: 'Ward Patient Workspace', + load: jest.fn(), + type: 'ward-patient', + moduleName: '@openmrs/esm-ward-app', + hasOwnSidebar: true, + sidebarFamily, + canHide: true, + }); + registerWorkspace({ + name: 'transfer-patient-workspace', + title: 'Transfer Patient Workspace', + load: jest.fn(), + type: 'transfer-patient', + moduleName: '@openmrs/esm-ward-app', + hasOwnSidebar: true, + sidebarFamily, + }); + const workspaceStore = getWorkspaceStore(); + launchWorkspace('ward-patient-workspace', { + foo: true, + }); + const sidebarFamilyStore = getWorkspaceFamilyStore(sidebarFamily); + expect(workspaceStore.getState().openWorkspaces.length).toBe(1); + expect(sidebarFamilyStore).toBeTruthy(); + expect(sidebarFamilyStore?.getState()?.['foo']).toBe(true); + launchWorkspace('transfer-patient-workspace', { bar: false }); + expect(workspaceStore.getState().openWorkspaces.length).toBe(2); + const transferPatientWorkspace = workspaceStore.getState().openWorkspaces[0]; + const wardPatientWorkspace = workspaceStore.getState().openWorkspaces[1]; + expect(wardPatientWorkspace.name).toBe('ward-patient-workspace'); + expect(wardPatientWorkspace).toBeTruthy(); + expect(sidebarFamilyStore?.getState()?.['foo']).toBe(true); + expect(sidebarFamilyStore?.getState()?.['bar']).toBe(false); + expect(transferPatientWorkspace.name).toBe('transfer-patient-workspace'); + expect(sidebarFamilyStore?.getState()?.['foo']).toBe(true); + expect(sidebarFamilyStore?.getState()?.['bar']).toBe(false); + }); + + it('should clear workspace if all the workspaces of the same family is closed', async () => { + registerWorkspace({ + name: 'ward-patient-workspace', + title: 'Ward Patient Workspace', + load: jest.fn(), + type: 'ward-patient', + moduleName: '@openmrs/esm-ward-app', + hasOwnSidebar: true, + sidebarFamily: 'ward-patient-sidebar', + canHide: true, + }); + registerWorkspace({ + name: 'transfer-patient-workspace', + title: 'Transfer Patient Workspace', + load: jest.fn(), + type: 'transfer-patient', + moduleName: '@openmrs/esm-ward-app', + hasOwnSidebar: true, + sidebarFamily: 'ward-patient-sidebar', + }); + launchWorkspace('ward-patient-workspace', { + foo: true, + }); + launchWorkspace('transfer-patient-workspace', { bar: false }); + const workspaceStore = getWorkspaceStore(); + expect(workspaceStore.getState().openWorkspaces.length).toBe(2); + const transferPatientWorkspace = workspaceStore.getState().openWorkspaces[0]; + transferPatientWorkspace.closeWorkspace({ ignoreChanges: true }); + const wardPatientWorkspace = workspaceStore.getState().openWorkspaces[0]; + const wardPatientWorkspaceFamilyStore = getWorkspaceFamilyStore('ward-patient-sidebar'); + expect(wardPatientWorkspaceFamilyStore).toBeTruthy(); + expect(wardPatientWorkspaceFamilyStore?.getState()?.['foo']).toBe(true); + expect(wardPatientWorkspaceFamilyStore?.getState()?.['bar']).toBe(false); + // Closing the last opened workspace of the family + wardPatientWorkspace.closeWorkspace({ ignoreChanges: true }); + expect(wardPatientWorkspaceFamilyStore?.getState()?.['foo']).toBeUndefined(); + expect(wardPatientWorkspaceFamilyStore?.getState()?.['bar']).toBeUndefined(); + }); + }); }); diff --git a/packages/framework/esm-styleguide/src/workspaces/workspaces.ts b/packages/framework/esm-styleguide/src/workspaces/workspaces.ts index 3df69789f..24b10f1f3 100644 --- a/packages/framework/esm-styleguide/src/workspaces/workspaces.ts +++ b/packages/framework/esm-styleguide/src/workspaces/workspaces.ts @@ -7,6 +7,7 @@ import { navigate } from '@openmrs/esm-navigation'; import { getGlobalStore, createGlobalStore } from '@openmrs/esm-state'; import { getCoreTranslation, translateFrom } from '@openmrs/esm-translations'; import { useStore } from '@openmrs/esm-react-utils'; +import type { StoreApi } from 'zustand/vanilla'; export interface CloseWorkspaceOptions { /** @@ -167,7 +168,7 @@ export function launchWorkspace< >(name: string, additionalProps?: Omit & { workspaceTitle?: string }) { const store = getWorkspaceStore(); const workspace = getWorkspaceRegistration(name); - const newWorkspace = { + const newWorkspace: OpenWorkspace = { ...workspace, title: getWorkspaceTitle(workspace, additionalProps), closeWorkspace: (options: CloseWorkspaceOptions = {}) => closeWorkspace(name, options), @@ -188,6 +189,11 @@ export function launchWorkspace< additionalProps: additionalProps ?? {}, }; + if (newWorkspace.sidebarFamily) { + // initialize workspace family store + getWorkspaceFamilyStore(newWorkspace.sidebarFamily, additionalProps); + } + function updateStoreWithNewWorkspace(workspaceToBeAdded: OpenWorkspace, restOfTheWorkspaces?: Array) { store.setState((state) => { const openWorkspaces = [workspaceToBeAdded, ...(restOfTheWorkspaces ?? state.openWorkspaces)]; @@ -290,7 +296,19 @@ export function closeWorkspace( const updateStoreWithClosedWorkspace = () => { const state = store.getState(); + const workspaceToBeClosed = state.openWorkspaces.find((w) => w.name === name); + const workspaceSidebarFamilyName = workspaceToBeClosed?.sidebarFamily; const newOpenWorkspaces = state.openWorkspaces.filter((w) => w.name != name); + const workspaceFamilyStore = getWorkspaceFamilyStore(workspaceSidebarFamilyName); + if ( + workspaceFamilyStore && + !newOpenWorkspaces.some((workspace) => workspace.sidebarFamily === workspaceSidebarFamilyName) + ) { + // Clearing the workspace family store if there are no more workspaces with the same sidebar family name + workspaceFamilyStore.setState({}, true); + const unsubscribe = workspaceFamilyStore.subscribe(() => {}); + unsubscribe?.(); + } // ensure closed workspace will not prompt promptBeforeClosing(name, () => false); @@ -491,3 +509,30 @@ function getWorkspaceTitle(workspace: WorkspaceRegistration, additionalProps?: o export function resetWorkspaceStore() { getWorkspaceStore().setState(initialState); } + +/** + * The workspace family store is a store that is specific to the workspace sidebar family. + * If the workspace has its own sidebar, the store will be created. + * This store can be used to store data that is specific to the workspace sidebar family. + * The store will be same for all the workspaces with same sidebar family name. + * + * For workspaces with no sidebarFamilyName or sidebarFamilyName as 'default', the store will be undefined. + * + * The store will be cleared when all the workspaces with the store's sidebarFamilyName are closed. + */ +export function getWorkspaceFamilyStore( + sidebarFamilyName: string | undefined, + additionalProps: object = {}, +): StoreApi | undefined { + if (!sidebarFamilyName || sidebarFamilyName === 'default') { + return undefined; + } + const store = getGlobalStore(sidebarFamilyName, {}); + if (additionalProps) { + store.setState((prev) => ({ + ...prev, + ...additionalProps, + })); + } + return store; +}