diff --git a/src/components/LabelsOnMe.tsx b/src/components/LabelsOnMe.tsx new file mode 100644 index 0000000000..3af3d8fe34 --- /dev/null +++ b/src/components/LabelsOnMe.tsx @@ -0,0 +1,94 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {ComAtprotoLabelDefs} from '@atproto/api' + +import {atoms as a, useBreakpoints} from '#/alf' +import {Text} from '#/components/Typography' +import * as Dialog from '#/components/Dialog' +import {Button} from '#/components/Button' + +export {useDialogControl as useLabelsOnMeDialogControl} from '#/components/Dialog' + +type Subject = + | { + uri: string + cid: string + } + | { + did: string + } + +export interface LabelsOnMeDialogProps { + control: Dialog.DialogOuterProps['control'] + subject: Subject + labels: ComAtprotoLabelDefs.Label[] +} + +export function LabelsOnMeDialogInner(props: LabelsOnMeDialogProps) { + const {_} = useLingui() + const control = Dialog.useDialogControl() + const {gtMobile} = useBreakpoints() + const {subject, labels} = props + const isAccount = 'did' in subject + + // TODO + // const submit = async () => { + // try { + // const $type = !isAccountReport + // ? 'com.atproto.repo.strongRef' + // : 'com.atproto.admin.defs#repoRef' + // await getAgent().createModerationReport({ + // reasonType: ComAtprotoModerationDefs.REASONAPPEAL, + // subject: { + // $type, + // ...props, + // }, + // reason: details, + // }) + // Toast.show(_(msg`We'll look into your appeal promptly.`)) + // } finally { + // closeModal() + // } + // } + + return ( + + + Labels on my {isAccount ? 'account' : 'content'} + + + + You may appeal these labels if you feel they were placed in error. + + + {labels.map(label => ( + {label.val} TODO + ))} + + + + + ) +} + +export function LabelsOnMeDialog(props: LabelsOnMeDialogProps) { + return ( + + + + + + ) +} diff --git a/src/components/dialogs/LabelsOnMe/index.tsx b/src/components/dialogs/LabelsOnMe/index.tsx deleted file mode 100644 index efc8019bda..0000000000 --- a/src/components/dialogs/LabelsOnMe/index.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react' -import {View} from 'react-native' -import {msg, Trans} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {ComAtprotoLabelDefs} from '@atproto/api' - -import {atoms as a, useBreakpoints} from '#/alf' -import {Text} from '#/components/Typography' -import * as Dialog from '#/components/Dialog' -import {GlobalDialogProps} from '#/components/dialogs' -import {Button} from '#/components/Button' - -type Subject = - | { - uri: string - cid: string - } - | { - did: string - } - -export interface LabelsOnMeDialogProps { - subject: Subject - labels: ComAtprotoLabelDefs.Label[] -} - -export function LabelsOnMeDialog({ - params, - cleanup, -}: GlobalDialogProps) { - const {_} = useLingui() - const control = Dialog.useDialogControl() - const {gtMobile} = useBreakpoints() - const {subject, labels} = params - const isAccount = 'did' in subject - - // REQUIRED CLEANUP - const onClose = React.useCallback(() => cleanup(), [cleanup]) - - // TODO - // const submit = async () => { - // try { - // const $type = !isAccountReport - // ? 'com.atproto.repo.strongRef' - // : 'com.atproto.admin.defs#repoRef' - // await getAgent().createModerationReport({ - // reasonType: ComAtprotoModerationDefs.REASONAPPEAL, - // subject: { - // $type, - // ...props, - // }, - // reason: details, - // }) - // Toast.show(_(msg`We'll look into your appeal promptly.`)) - // } finally { - // closeModal() - // } - // } - - return ( - - - - - - Labels on my {isAccount ? 'account' : 'content'} - - - - You may appeal these labels if you feel they were placed in error. - - - {labels.map(label => ( - {label.val} TODO - ))} - - - - - - ) -} diff --git a/src/components/dialogs/README.md b/src/components/dialogs/README.md deleted file mode 100644 index cda1242bc6..0000000000 --- a/src/components/dialogs/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Global Dialogs - -The dialogs and utils contained in this directory are intended to be "global" in -the sense that they are very common. - -A good example: the report dialog. We need to be able to open one from every -post, but if every post had its own `Dialog`, performance would suffer. -Previously the solution was to use the same modal/sheet via `Modal`, and just -swap out the content. - -The solution here is to only render the dialog when it's opened, and to enable -programmatic opening of said dialog e.g. from a context menu. - -**For other dialogs that can be rendered _in situ_, use `Dialog` directly.** -Only use this abstraction for instances that either aren't possible or would be -performance intensive when defining a `Dialog` in situ. diff --git a/src/components/dialogs/index.tsx b/src/components/dialogs/index.tsx deleted file mode 100644 index 8118f5f5a1..0000000000 --- a/src/components/dialogs/index.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import React from 'react' - -import * as Dialog from '#/components/Dialog' - -/** - * Type util for global dialog components. Wrap individual dialog component - * types with this to get types for the additional properties applied by the - * the global dialon controller. - */ -export type GlobalDialogProps = { - params: T - cleanup(): void - options?: Dialog.DialogControlOpenOptions -} - -type ActiveDialog> = { - component: T - props: React.ComponentProps - options?: Dialog.DialogControlOpenOptions -} - -type ContextProps = { - activeDialogs: ActiveDialog[] - open>( - component: T, - props: React.ComponentProps['params'], - options?: Dialog.DialogControlOpenOptions, - ): void - popTopDialog(): void -} - -export const Context = React.createContext({ - activeDialogs: [], - open() {}, - popTopDialog() {}, -}) - -/** - * Hook to open a "global" dialog. - * - * @example - * ```tsx - * const openGlobalDialog = useOpenGlobalDialog() - * openGlobalDialog( - * MyDialog, - * // component props - * {foo: 'bar'}, - * // base Dialog options - * { index: 1 } - * ) - * ``` - */ -export function useOpenGlobalDialog() { - return React.useContext(Context).open -} - -/** - * Provider for "global" dialogs _only_. ALL dialogs are still registered by - * `#/state/dialogs` as well. - */ -export function Provider({children}: React.PropsWithChildren<{}>) { - const [activeDialogs, setActiveDialogs] = React.useState[]>( - [], - ) - const ctx = React.useMemo( - () => ({ - activeDialogs, - open(component, props, options) { - setActiveDialogs(s => [...s, {component, props, options}]) - }, - popTopDialog() { - setActiveDialogs(s => s.slice(0, -1)) - }, - }), - [activeDialogs, setActiveDialogs], - ) - - return {children} -} - -/** - * Outlet for any active "global" dialogs. Since these are rendered into a - * portal in the root, this is technically not their final resting place. - */ -export function GlobalDialog() { - const {activeDialogs, popTopDialog} = React.useContext(Context) - - const cleanup = React.useCallback(() => { - popTopDialog() - }, [popTopDialog]) - - return React.useMemo( - () => - activeDialogs.map(({component: Comp, props, options}, i) => { - return ( - - ) - }), - [activeDialogs, cleanup], - ) -} diff --git a/src/state/dialogs/index.tsx b/src/state/dialogs/index.tsx index 1808ef5152..ae762bd97e 100644 --- a/src/state/dialogs/index.tsx +++ b/src/state/dialogs/index.tsx @@ -1,7 +1,6 @@ import React from 'react' import {DialogControlProps} from '#/components/Dialog' -import {Provider as GlobalDialogsProvider} from '#/components/dialogs' -import {Provider as GlobalDialogsProviderV2} from '#/components/dialogs/Context' +import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context' const DialogContext = React.createContext<{ activeDialogs: React.MutableRefObject< @@ -39,9 +38,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { return ( - - {children} - + {children} ) diff --git a/src/view/com/util/moderation/LabelsOnMe.tsx b/src/view/com/util/moderation/LabelsOnMe.tsx index 900ceb26ac..4c8b8e0223 100644 --- a/src/view/com/util/moderation/LabelsOnMe.tsx +++ b/src/view/com/util/moderation/LabelsOnMe.tsx @@ -8,8 +8,10 @@ import {useSession} from '#/state/session' import {atoms as a} from '#/alf' import {Button, ButtonText, ButtonIcon, ButtonSize} from '#/components/Button' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' -import {useOpenGlobalDialog} from '#/components/dialogs' -import {LabelsOnMeDialog} from '#/components/dialogs/LabelsOnMe' +import { + LabelsOnMeDialog, + useLabelsOnMeDialogControl, +} from '#/components/LabelsOnMe' export function LabelsOnMe({ details, @@ -25,7 +27,7 @@ export function LabelsOnMe({ const {_} = useLingui() const {currentAccount} = useSession() const isAccount = 'did' in details - const openDialog = useOpenGlobalDialog() + const control = useLabelsOnMeDialogControl() if (!labels || !currentAccount) { return null @@ -39,16 +41,15 @@ export function LabelsOnMe({ return ( + +