diff --git a/CHANGELOG.md b/CHANGELOG.md index 97094a03a..26229d1a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [3.10.0](https://github.com/dhis2/app-runtime/compare/v3.9.4...v3.10.0) (2023-12-12) + + +### Features + +* add value-independent hook for setting online status message [LIBS-369] ([#1363](https://github.com/dhis2/app-runtime/issues/1363)) ([a2831e6](https://github.com/dhis2/app-runtime/commit/a2831e6eefef94dd2c81721d40a98ca89c53fee6)) + ## [3.9.4](https://github.com/dhis2/app-runtime/compare/v3.9.3...v3.9.4) (2023-06-19) diff --git a/docs/advanced/offline/CustomOnlineStatusMessage.md b/docs/advanced/offline/CustomOnlineStatusMessage.md new file mode 100644 index 000000000..c70b0b805 --- /dev/null +++ b/docs/advanced/offline/CustomOnlineStatusMessage.md @@ -0,0 +1,46 @@ +# Custom Connection Status Message + +By default, the header bar shows either an "Online" or "Offline" message based on whether the app can connect to the DHIS2 server. If it's useful for an app to share other relevant info in that badge, for example "3 changes saved locally", then it's possible to set a custom message there: + +![Custom online status message](custom-online-status-message.png) + +## Hooks + +```ts +import { + useSetOnlineStatusMessage, + useOnlineStatusMessageValue, + useOnlineStatusMessage, +} from '@dhis2/app-runtime' +``` + +### `useSetOnlineStatusMessage` + +It's most likely that you'll only use `useSetOnlineStatusMessage()`, a hook that returns a `setState` function. It can set the value in the Header Bar without causing a rerender for itself. + +`setOnlineStatusMessage()` accepts a `ReactNode`-type object, so icons or other components can be added to the badge, but don't go crazy. A simple string is also a valid `ReactNode`: + +```ts +const setOnlineStatusMessage: (message: ReactNode) => void = + useSetOnlineStatusMessage() +``` + +### `useOnlineStatusMessageValue` + +This hook returns just the value: + +```ts +const onlineStatusMessage: ReactNode = useOnlineStatusMessageValue() +``` + +### `useOnlineStatusMessage` + +This hook returns both the value and the `set` function: + +```ts +const { onlineMessage, setOnlineStatusMessage } = useOnlineStatusMessage() +``` + +## Example + +You can see an example in use in the [Aggregate Data Entry app](https://github.com/dhis2/aggregate-data-entry-app/blob/dadd61392ea010a8017a19a25eaf76f885d9eea7/src/data-workspace/use-handle-headerbar-status.js) diff --git a/docs/advanced/offline/custom-online-status-message.png b/docs/advanced/offline/custom-online-status-message.png new file mode 100644 index 000000000..ac8841614 Binary files /dev/null and b/docs/advanced/offline/custom-online-status-message.png differ diff --git a/docs/advanced/offline/useDhis2ConnectionStatus.md b/docs/advanced/offline/useDhis2ConnectionStatus.md index 6d7ede27f..e9f4ae0bd 100644 --- a/docs/advanced/offline/useDhis2ConnectionStatus.md +++ b/docs/advanced/offline/useDhis2ConnectionStatus.md @@ -6,6 +6,8 @@ This hook is used to detect whether or not the app can connect to the DHIS2 serv It's designed to detect server connection because checking just the internet connection can lead to problems on DHIS2 instances that are implemented offline, where features or actions might be blocked because the device is offline, even though the app can connect to the DHIS2 server just fine. In these cases, what matters is whether or not the app can connect to the DHIS2 server. +This what the DHIS2 Header Bar uses to show an "Online" or "Offline" badge. + ```ts import { useDhis2ConnectionStatus } from '@dhis2/app-runtime' diff --git a/package.json b/package.json index 8093f3ff4..14339183f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "3.9.4", + "version": "3.10.0", "description": "A singular runtime dependency for applications on the DHIS2 platform", "repository": "https://github.com/dhis2/app-runtime.git", "author": "Austin McGee ", diff --git a/runtime/package.json b/runtime/package.json index 6c32d836d..b8bdb9d17 100644 --- a/runtime/package.json +++ b/runtime/package.json @@ -1,7 +1,7 @@ { "name": "@dhis2/app-runtime", "description": "A singular runtime dependency for applications on the DHIS2 platform", - "version": "3.9.4", + "version": "3.10.0", "main": "./build/cjs/index.js", "module": "./build/es/index.js", "types": "./build/types/index.d.ts", @@ -23,10 +23,10 @@ "build/**" ], "dependencies": { - "@dhis2/app-service-config": "3.9.4", - "@dhis2/app-service-data": "3.9.4", - "@dhis2/app-service-alerts": "3.9.4", - "@dhis2/app-service-offline": "3.9.4" + "@dhis2/app-service-config": "3.10.0", + "@dhis2/app-service-data": "3.10.0", + "@dhis2/app-service-alerts": "3.10.0", + "@dhis2/app-service-offline": "3.10.0" }, "peerDependencies": { "prop-types": "^15.7.2", diff --git a/runtime/src/index.ts b/runtime/src/index.ts index 5bf44ba37..1ae215aa2 100644 --- a/runtime/src/index.ts +++ b/runtime/src/index.ts @@ -17,6 +17,8 @@ export { useOnlineStatus, useDhis2ConnectionStatus, useOnlineStatusMessage, + useSetOnlineStatusMessage, + useOnlineStatusMessageValue, useCacheableSection, CacheableSection, useCachedSections, diff --git a/services/alerts/package.json b/services/alerts/package.json index 20486ee19..b7d12d8ee 100644 --- a/services/alerts/package.json +++ b/services/alerts/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/app-service-alerts", - "version": "3.9.4", + "version": "3.10.0", "main": "./build/cjs/index.js", "module": "./build/es/index.js", "types": "./build/types/index.d.ts", diff --git a/services/config/package.json b/services/config/package.json index f5675e573..f09e12a11 100644 --- a/services/config/package.json +++ b/services/config/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/app-service-config", - "version": "3.9.4", + "version": "3.10.0", "main": "./build/cjs/index.js", "module": "./build/es/index.js", "types": "build/types/index.d.ts", diff --git a/services/data/package.json b/services/data/package.json index bc783c446..d9d2c7cad 100644 --- a/services/data/package.json +++ b/services/data/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/app-service-data", - "version": "3.9.4", + "version": "3.10.0", "main": "./build/cjs/index.js", "module": "./build/es/index.js", "types": "build/types/index.d.ts", @@ -22,7 +22,7 @@ "build/**" ], "peerDependencies": { - "@dhis2/app-service-config": "3.9.4", + "@dhis2/app-service-config": "3.10.0", "@dhis2/cli-app-scripts": "^7.1.1", "prop-types": "^15.7.2", "react": "^16.8", diff --git a/services/offline/package.json b/services/offline/package.json index dc86f3008..ff9050b01 100644 --- a/services/offline/package.json +++ b/services/offline/package.json @@ -1,7 +1,7 @@ { "name": "@dhis2/app-service-offline", "description": "A runtime service for online/offline detection and offline caching", - "version": "3.9.4", + "version": "3.10.0", "main": "./build/cjs/index.js", "module": "./build/es/index.js", "types": "build/types/index.d.ts", @@ -33,7 +33,7 @@ "coverage": "yarn test --coverage" }, "peerDependencies": { - "@dhis2/app-service-config": "3.9.4", + "@dhis2/app-service-config": "3.10.0", "prop-types": "^15.7.2", "react": "^16.8.6", "react-dom": "^16.8.6" diff --git a/services/offline/src/index.ts b/services/offline/src/index.ts index ef2fbf915..5d7411f1b 100644 --- a/services/offline/src/index.ts +++ b/services/offline/src/index.ts @@ -3,6 +3,10 @@ export { CacheableSection, useCacheableSection } from './lib/cacheable-section' export { useCachedSections } from './lib/cacheable-section-state' // Use "useOnlineStatus" name for backwards compatibility export { useNetworkStatus as useOnlineStatus } from './lib/network-status' -export { useOnlineStatusMessage } from './lib/online-status-message' +export { + useOnlineStatusMessage, + useSetOnlineStatusMessage, + useOnlineStatusMessageValue, +} from './lib/online-status-message' export { clearSensitiveCaches } from './lib/clear-sensitive-caches' export { useDhis2ConnectionStatus } from './lib/dhis2-connection-status' diff --git a/services/offline/src/lib/online-status-message.tsx b/services/offline/src/lib/online-status-message.tsx index 478d668b3..726b41a5e 100644 --- a/services/offline/src/lib/online-status-message.tsx +++ b/services/offline/src/lib/online-status-message.tsx @@ -1,39 +1,47 @@ import React, { ReactElement, ReactNode, useContext, useState } from 'react' -import { OnlineStatusMessageContextAPI } from '../types' -const defaultApi: OnlineStatusMessageContextAPI = { - onlineStatusMessage: undefined, - setOnlineStatusMessage: () => undefined, -} - -const OnlineStatusMessageContext = - React.createContext(defaultApi) - -export const useOnlineStatusMessage = (): OnlineStatusMessageContextAPI => { - const { onlineStatusMessage, setOnlineStatusMessage } = - useContext(OnlineStatusMessageContext) +type SetOnlineStatusMessage = (message: ReactNode) => void - return { - onlineStatusMessage, - setOnlineStatusMessage, - } -} +// 'get' and 'set' contexts are separated so 'setter' consumers that don't +// actually need the value don't have to rerender when the value changes: +const OnlineStatusMessageValueContext = + React.createContext(undefined) +const SetOnlineStatusMessageContext = + React.createContext(() => undefined) export const OnlineStatusMessageProvider = ({ children, }: { children: ReactNode }): ReactElement => { - const [onlineStatusMessage, setOnlineStatusMessage] = useState() + const [onlineStatusMessage, setOnlineStatusMessage] = useState() // note: not undefined return ( - - {children} - + + + {children} + + ) } + +export const useOnlineStatusMessageValue = () => { + return useContext(OnlineStatusMessageValueContext) +} + +export const useSetOnlineStatusMessage = () => { + return useContext(SetOnlineStatusMessageContext) +} + +// combination of both getter and setter (also provides backward compatability) +export const useOnlineStatusMessage = () => { + const onlineStatusMessage = useOnlineStatusMessageValue() + const setOnlineStatusMessage = useSetOnlineStatusMessage() + + return { + onlineStatusMessage, + setOnlineStatusMessage, + } +} diff --git a/services/offline/src/types.ts b/services/offline/src/types.ts index 730d9f13c..37580b406 100644 --- a/services/offline/src/types.ts +++ b/services/offline/src/types.ts @@ -1,5 +1,3 @@ -import { ReactNode } from 'react' - // Cacheable Section types export type RecordingState = 'default' | 'pending' | 'error' | 'recording' @@ -66,10 +64,3 @@ export interface OfflineInterface { getCachedSections: () => Promise removeSection: (id: string) => Promise } - -// Online status types - -export type OnlineStatusMessageContextAPI = { - onlineStatusMessage?: ReactNode - setOnlineStatusMessage: (additionalInfo: ReactNode) => void -}