add button + dialog
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import {useCallback} from 'react'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {Bell_Stroke2_Corner0_Rounded as NotificationIcon} from '../icons/Bell'
|
||||
import {SubscribeProfileDialog} from './SubscribeProfileDialog'
|
||||
|
||||
export function SubscribeProfileButton({
|
||||
profile,
|
||||
}: {
|
||||
profile: bsky.profile.AnyProfileView
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const requireEmailVerification = useRequireEmailVerification()
|
||||
const subscribeDialogControl = useDialogControl()
|
||||
|
||||
const onPress = useCallback(() => {
|
||||
subscribeDialogControl.open()
|
||||
}, [subscribeDialogControl])
|
||||
|
||||
const name = createSanitizedDisplayName(profile, true)
|
||||
|
||||
const wrappedOnPress = requireEmailVerification(onPress, {
|
||||
instructions: [
|
||||
<Trans key="message">
|
||||
Before you can subscribe to {name}'s posts, you must first verify your
|
||||
email.
|
||||
</Trans>,
|
||||
],
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
accessibilityRole="button"
|
||||
testID="dmBtn"
|
||||
size="small"
|
||||
color="secondary"
|
||||
variant="solid"
|
||||
shape="round"
|
||||
label={_(msg`Subscribe to ${name}'s posts`)}
|
||||
style={[a.justify_center]}
|
||||
onPress={wrappedOnPress}>
|
||||
<ButtonIcon icon={NotificationIcon} size="md" />
|
||||
</Button>
|
||||
|
||||
<SubscribeProfileDialog
|
||||
control={subscribeDialogControl}
|
||||
profile={profile}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import {useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {useTheme, web} from '#/alf'
|
||||
import {atoms as a} from '#/alf'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
import {Text} from '#/components/Typography'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function SubscribeProfileDialog({
|
||||
control,
|
||||
profile,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
profile: bsky.profile.AnyProfileView
|
||||
}) {
|
||||
return (
|
||||
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
|
||||
<Dialog.Handle />
|
||||
<DialogInner profile={profile} />
|
||||
</Dialog.Outer>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogInner({profile}: {profile: bsky.profile.AnyProfileView}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const [state, setState] = useState({posts: false, replies: false})
|
||||
|
||||
const values = useMemo(() => {
|
||||
const {posts, replies} = state
|
||||
const res = []
|
||||
if (posts) res.push('posts')
|
||||
if (replies) res.push('replies')
|
||||
return res
|
||||
}, [state])
|
||||
|
||||
const onChange = (newValues: string[]) =>
|
||||
setState({
|
||||
posts: newValues.includes('posts'),
|
||||
replies: newValues.includes('replies'),
|
||||
})
|
||||
|
||||
const name = createSanitizedDisplayName(profile, false)
|
||||
|
||||
return (
|
||||
<Dialog.ScrollableInner
|
||||
style={web({maxWidth: 400})}
|
||||
label={_(msg`Subscribe to posts`)}>
|
||||
<View style={[a.gap_md]}>
|
||||
<View style={[a.gap_xs]}>
|
||||
<Text style={[a.font_heavy, a.text_2xl]}>
|
||||
<Trans>Subscribe to {name}</Trans>
|
||||
</Text>
|
||||
<Text style={[t.atoms.text_contrast_medium, a.text_md]}>
|
||||
<Trans>Get notifications for account activity</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Toggle.Group
|
||||
label={_(msg`Subscribe to account`)}
|
||||
values={values}
|
||||
onChange={onChange}>
|
||||
<View style={[a.gap_sm]}>
|
||||
<Toggle.Item
|
||||
label={_(msg`Posts`)}
|
||||
name="posts"
|
||||
style={[a.justify_between, a.py_xs]}>
|
||||
<Toggle.LabelText
|
||||
style={[t.atoms.text, a.font_normal, a.text_md]}>
|
||||
<Trans>Posts</Trans>
|
||||
</Toggle.LabelText>
|
||||
<Toggle.Platform />
|
||||
</Toggle.Item>
|
||||
<Toggle.Item
|
||||
label={_(msg`Replies`)}
|
||||
name="replies"
|
||||
style={[a.justify_between, a.py_xs]}>
|
||||
<Toggle.LabelText
|
||||
style={[t.atoms.text, a.font_normal, a.text_md]}>
|
||||
<Trans>Replies</Trans>
|
||||
</Toggle.LabelText>
|
||||
<Toggle.Platform />
|
||||
</Toggle.Item>
|
||||
</View>
|
||||
</Toggle.Group>
|
||||
</View>
|
||||
|
||||
<Dialog.Close />
|
||||
</Dialog.ScrollableInner>
|
||||
)
|
||||
}
|
||||
@@ -30,6 +30,12 @@ export function useGlobalLabelStrings(): GlobalLabelStrings {
|
||||
msg`This user has requested that their content only be shown to signed-in users.`,
|
||||
),
|
||||
},
|
||||
'!no-subscriptions': {
|
||||
name: _(msg`No subscriptions allowed`),
|
||||
description: _(
|
||||
msg`This user has requested that they cannot be subscribed to for post notifications.`,
|
||||
),
|
||||
},
|
||||
porn: {
|
||||
name: _(msg`Adult Content`),
|
||||
description: _(msg`Explicit sexual images.`),
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
KnownFollowers,
|
||||
shouldShowKnownFollowers,
|
||||
} from '#/components/KnownFollowers'
|
||||
import {SubscribeProfileButton} from '#/components/post-subscriptions/SubscribeProfileButton'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import {Text} from '#/components/Typography'
|
||||
@@ -134,13 +135,17 @@ let ProfileHeaderStandard = ({
|
||||
}
|
||||
}, [_, queueUnblock])
|
||||
|
||||
const isMe = React.useMemo(
|
||||
const isMe = useMemo(
|
||||
() => currentAccount?.did === profile.did,
|
||||
[currentAccount, profile],
|
||||
)
|
||||
|
||||
const {isActive: live} = useActorStatus(profile)
|
||||
|
||||
const subscriptionsDisallowed = useMemo(() => {
|
||||
return !!profile.labels?.find(label => label.val === '!no-subscriptions')
|
||||
}, [profile])
|
||||
|
||||
return (
|
||||
<ProfileHeaderShell
|
||||
profile={profile}
|
||||
@@ -198,6 +203,9 @@ let ProfileHeaderStandard = ({
|
||||
)
|
||||
) : !profile.viewer?.blockedBy ? (
|
||||
<>
|
||||
{hasSession && !subscriptionsDisallowed && (
|
||||
<SubscribeProfileButton profile={profile} />
|
||||
)}
|
||||
{hasSession && <MessageProfileButton profile={profile} />}
|
||||
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user