Clean up state, remove Portal edits

This commit is contained in:
Eric Bailey
2025-08-05 10:37:33 -05:00
parent 7e75f40379
commit 5db709cba6
7 changed files with 91 additions and 160 deletions
+1 -1
View File
@@ -73,7 +73,7 @@ export function createPortalGroup() {
return null
}
return {Provider, Outlet, Portal, Context}
return {Provider, Outlet, Portal}
}
const DefaultPortal = createPortalGroup()
@@ -0,0 +1,38 @@
import {View} from 'react-native'
import {Trans} from '@lingui/macro'
import {Logo} from '#/view/icons/Logo'
import {atoms as a, useTheme} from '#/alf'
import {Text} from '#/components/Typography'
export function AnnouncementBadge() {
const t = useTheme()
return (
<View style={[a.align_start]}>
<View
style={[
a.pl_md,
a.pr_lg,
a.py_sm,
a.rounded_full,
a.flex_row,
a.align_center,
a.gap_xs,
{
backgroundColor: t.palette.primary_25,
},
]}>
<Logo fill={t.palette.primary_600} width={14} />
<Text
style={[
a.font_bold,
{
color: t.palette.primary_600,
},
]}>
<Trans>Announcement</Trans>
</Text>
</View>
</View>
)
}
@@ -1,10 +1,4 @@
import {
createContext,
type ReactNode,
useContext,
useMemo,
useState,
} from 'react'
import {type ReactNode} from 'react'
import {ScrollView, View} from 'react-native'
import {
useSafeAreaFrame,
@@ -21,29 +15,6 @@ import {LockScroll} from '#/components/LockScroll'
const GUTTER = 24
export const Context = createContext({
close: () => {},
})
export function useAnnouncementDialogContext() {
return useContext(Context)
}
export function AnnouncementDialogOuter({children}: {children: ReactNode}) {
const [open, setOpen] = useState(true)
const ctx = useMemo(
() => ({
close() {
setOpen(false)
},
}),
[setOpen],
)
return <Context.Provider value={ctx}>{open && children}</Context.Provider>
}
export function AnnouncementDialog({
children,
label,
@@ -4,37 +4,23 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isAndroid} from '#/platform/detection'
import {Nux} from '#/state/queries/nuxs'
import {useA11y} from '#/state/a11y'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {
AnnouncementBadge,
useAnnouncementState,
} from '#/components/dialogs/BlockingAnnouncements/common'
import {AnnouncementBadge} from '#/components/dialogs/BlockingAnnouncements/AnnouncementBadge'
import {AnnouncementDialog} from '#/components/dialogs/BlockingAnnouncements/AnnouncementDialog'
import {type AnnouncementState} from '#/components/dialogs/BlockingAnnouncements/useAnnouncementState'
import {InlineLinkText, Link} from '#/components/Link'
import {Text} from '#/components/Typography'
import {
AnnouncementDialog,
useAnnouncementDialogContext,
} from '#/components/dialogs/BlockingAnnouncements/AnnouncementDialog'
import {useA11y} from '#/state/a11y'
export function useLocalState() {
return useAnnouncementState({
id: Nux.BlockingAnnouncementPolicyUpdate20250801,
})
}
export function Announcement() {
export function Announcement({state}: {state: AnnouncementState}) {
const t = useTheme()
const {_} = useLingui()
const {complete} = useLocalState()
const {close} = useAnnouncementDialogContext()
const {screenReaderEnabled} = useA11y()
const handleClose = useCallback(() => {
close()
}, [close, complete])
state.complete()
}, [state])
const linkStyle = [a.text_md]
const links = {
@@ -1,94 +0,0 @@
import {type ReactNode, useCallback, useMemo} from 'react'
import {View} from 'react-native'
import {Trans} from '@lingui/macro'
import {type Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
import {Logo} from '#/view/icons/Logo'
import {atoms as a, useTheme} from '#/alf'
import * as Dialog from '#/components/Dialog'
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
import {Text} from '#/components/Typography'
export function useForceClose() {
const {close} = Dialog.useDialogContext()
return useCallback(
(cb?: () => void) => {
close(cb, true)
},
[close],
)
}
export function useAnnouncementState({id}: {id: Nux}) {
const nux = useNux(id)
const {mutate: save, variables} = useSaveNux()
const optimisticallyCompleted = !!variables?.completed
return useMemo(
() => ({
/**
* Until data has loaded, assumed completed
*/
completed:
optimisticallyCompleted || nux.status === 'ready'
? nux.nux?.completed === true
: true,
complete() {
save({
id,
completed: true,
data: undefined,
})
},
}),
[id, nux, save, optimisticallyCompleted],
)
}
export function BlockingAnnouncementDialogOuter({
children,
}: {
children: ReactNode
}) {
const {signinDialogControl: control} = useGlobalDialogsControlContext()
Dialog.useAutoOpen(control, 1e3)
return (
<Dialog.Outer preventDismiss control={control}>
<Dialog.Handle />
{children}
</Dialog.Outer>
)
}
export function AnnouncementBadge() {
const t = useTheme()
return (
<View style={[a.align_start]}>
<View
style={[
a.pl_md,
a.pr_lg,
a.py_sm,
a.rounded_full,
a.flex_row,
a.align_center,
a.gap_xs,
{
backgroundColor: t.palette.primary_25,
},
]}>
<Logo fill={t.palette.primary_600} width={14} />
<Text
style={[
a.font_bold,
{
color: t.palette.primary_600,
},
]}>
<Trans>Announcement</Trans>
</Text>
</View>
</View>
)
}
@@ -1,38 +1,34 @@
import {useContext} from 'react'
import {View} from 'react-native'
import {Nux} from '#/state/queries/nuxs'
import {atoms as a} from '#/alf'
import {AnnouncementDialogOuter} from '#/components/dialogs/BlockingAnnouncements/AnnouncementDialog'
import * as PolicyUpdate20250801 from '#/components/dialogs/BlockingAnnouncements/PolicyUpdate20250801'
import {useAnnouncementState} from '#/components/dialogs/BlockingAnnouncements/useAnnouncementState'
import {createPortalGroup} from '#/components/Portal'
const portalGroup = createPortalGroup()
export const Provider = portalGroup.Provider
export const Portal = portalGroup.Portal
export function Outlet() {
const {outlet} = useContext(portalGroup.Context)
return outlet ? (
<View style={[a.fixed, a.inset_0, {zIndex: 9999}]}>{outlet}</View>
) : null
}
export const Outlet = portalGroup.Outlet
export function BlockingAnnouncements() {
const policyUpdate20250801 = PolicyUpdate20250801.useLocalState()
const state = useAnnouncementState({
id: Nux.BlockingAnnouncementPolicyUpdate20250801,
})
/*
* See `window.clearNux` example in `/state/queries/nuxs` for a way to clear
* NUX state for local testing and debugging.
*/
if (policyUpdate20250801.completed) return null
if (state.completed) return null
return (
<Portal>
<AnnouncementDialogOuter>
<PolicyUpdate20250801.Announcement />
</AnnouncementDialogOuter>
<View style={[a.fixed, a.inset_0, {zIndex: 9999}]}>
<PolicyUpdate20250801.Announcement state={state} />
</View>
</Portal>
)
}
@@ -0,0 +1,34 @@
import {useMemo} from 'react'
import {type Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
export type AnnouncementState = {
completed: boolean
complete: () => void
}
export function useAnnouncementState({id}: {id: Nux}) {
const nux = useNux(id)
const {mutate: save, variables} = useSaveNux()
return useMemo(() => {
/**
* Until data has loaded, assumed completed
*/
let completed = nux.status === 'ready' ? nux.nux?.completed === true : true
if (variables?.completed) {
completed = true
}
return {
completed,
complete() {
save({
id,
completed: true,
data: undefined,
})
},
}
}, [id, nux, save, variables])
}