From 328aa2be9482f77cb1cf86c5d227fdcee9981b16 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 6 Aug 2025 15:15:52 -0500 Subject: [APP-1356] Policy update dialog (#8782) * Add blocking announcement dialog feature * WIP custom dialog * Rework dialog and add native FocusScope * Lock scroll on web, fix backdrop * Add web FocusScope * Create custom Outlet for these announcements * Clean up FocusScope native impl * Comments * Some styling fixes * Handle screen reader specifically * Clean up state, remove Portal edits * Reorg, rename * Add syncing, tests * Revert dialog updates * Revert formatting * Delete unused file * Format * Add FullWindowOverlay * remove mmkv storage in debug btn * Add debug code * fix taps passing through on iOS * Reorg * Reorg, rename everything * Complete policy update after signup * Add logger * Move context around, unmount portals on native * Move a11y prop into FocusScope * Remove useMemo * Update dates * Move debug to dev settings * Unmount web portals until policy update completed * UPdate dates --------- Co-authored-by: Samuel Newman --- .../PolicyUpdateOverlay/usePolicyUpdateState.ts | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 src/components/PolicyUpdateOverlay/usePolicyUpdateState.ts (limited to 'src/components/PolicyUpdateOverlay/usePolicyUpdateState.ts') diff --git a/src/components/PolicyUpdateOverlay/usePolicyUpdateState.ts b/src/components/PolicyUpdateOverlay/usePolicyUpdateState.ts new file mode 100644 index 000000000..29d8afe06 --- /dev/null +++ b/src/components/PolicyUpdateOverlay/usePolicyUpdateState.ts @@ -0,0 +1,135 @@ +import {useMemo} from 'react' + +import {useNux, useSaveNux} from '#/state/queries/nuxs' +import {ACTIVE_UPDATE_ID} from '#/components/PolicyUpdateOverlay/config' +import {logger} from '#/components/PolicyUpdateOverlay/logger' +import {IS_DEV} from '#/env' +import {device, useStorage} from '#/storage' + +export type PolicyUpdateState = { + completed: boolean + complete: () => void +} + +export function usePolicyUpdateState() { + const nux = useNux(ACTIVE_UPDATE_ID) + const {mutate: save, variables} = useSaveNux() + const deviceStorage = useStorage(device, [ACTIVE_UPDATE_ID]) + const debugOverride = + !!useStorage(device, ['policyUpdateDebugOverride'])[0] && IS_DEV + return useMemo(() => { + const nuxIsReady = nux.status === 'ready' + const nuxIsCompleted = nux.nux?.completed === true + const nuxIsOptimisticallyCompleted = !!variables?.completed + const [completedForDevice, setCompletedForDevice] = deviceStorage + + const completed = computeCompletedState({ + nuxIsReady, + nuxIsCompleted, + nuxIsOptimisticallyCompleted, + completedForDevice, + }) + + logger.debug(`state`, { + completed, + nux, + completedForDevice, + }) + + if (!debugOverride) { + syncCompletedState({ + nuxIsReady, + nuxIsCompleted, + nuxIsOptimisticallyCompleted, + completedForDevice, + save, + setCompletedForDevice, + }) + } + + return { + completed, + complete() { + logger.debug(`user completed`) + save({ + id: ACTIVE_UPDATE_ID, + completed: true, + data: undefined, + }) + setCompletedForDevice(true) + }, + } + }, [nux, save, variables, deviceStorage, debugOverride]) +} + +export function computeCompletedState({ + nuxIsReady, + nuxIsCompleted, + nuxIsOptimisticallyCompleted, + completedForDevice, +}: { + nuxIsReady: boolean + nuxIsCompleted: boolean + nuxIsOptimisticallyCompleted: boolean + completedForDevice: boolean | undefined +}): boolean { + /** + * Assume completed to prevent flash + */ + let completed = true + + /** + * Prefer server state, if available + */ + if (nuxIsReady) { + completed = nuxIsCompleted + } + + /** + * Override with optimistic state or device state + */ + if (nuxIsOptimisticallyCompleted || !!completedForDevice) { + completed = true + } + + return completed +} + +export function syncCompletedState({ + nuxIsReady, + nuxIsCompleted, + nuxIsOptimisticallyCompleted, + completedForDevice, + save, + setCompletedForDevice, +}: { + nuxIsReady: boolean + nuxIsCompleted: boolean + nuxIsOptimisticallyCompleted: boolean + completedForDevice: boolean | undefined + save: ReturnType['mutate'] + setCompletedForDevice: (value: boolean) => void +}) { + /* + * Sync device state to server state for this account + */ + if ( + nuxIsReady && + !nuxIsCompleted && + !nuxIsOptimisticallyCompleted && + !!completedForDevice + ) { + logger.debug(`syncing device state to server state`) + save({ + id: ACTIVE_UPDATE_ID, + completed: true, + data: undefined, + }) + } else if (nuxIsReady && nuxIsCompleted && !completedForDevice) { + logger.debug(`syncing server state to device state`) + /* + * Sync server state to device state + */ + setCompletedForDevice(true) + } +} -- cgit 1.4.1