Add email verification prompts throughout the app (#6174)
This commit is contained in:
@@ -14,6 +14,7 @@ import {InfiniteData, UseInfiniteQueryResult} from '@tanstack/react-query'
|
||||
|
||||
import {useGenerateStarterPackMutation} from '#/lib/generate-starterpack'
|
||||
import {useBottomBarOffset} from '#/lib/hooks/useBottomBarOffset'
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {parseStarterPackUri} from '#/lib/strings/starter-pack'
|
||||
@@ -27,6 +28,7 @@ import {LinearGradientBackground} from '#/components/LinearGradientBackground'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {Default as StarterPackCard} from '#/components/StarterPack/StarterPackCard'
|
||||
import {VerifyEmailDialog} from '../dialogs/VerifyEmailDialog'
|
||||
import {PlusSmall_Stroke2_Corner0_Rounded as Plus} from '../icons/Plus'
|
||||
|
||||
interface SectionRef {
|
||||
@@ -186,6 +188,9 @@ function Empty() {
|
||||
const followersDialogControl = useDialogControl()
|
||||
const errorDialogControl = useDialogControl()
|
||||
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const verifyEmailControl = useDialogControl()
|
||||
|
||||
const [isGenerating, setIsGenerating] = React.useState(false)
|
||||
|
||||
const {mutate: generateStarterPack} = useGenerateStarterPackMutation({
|
||||
@@ -249,7 +254,13 @@ function Empty() {
|
||||
color="primary"
|
||||
size="small"
|
||||
disabled={isGenerating}
|
||||
onPress={confirmDialogControl.open}
|
||||
onPress={() => {
|
||||
if (needsEmailVerification) {
|
||||
verifyEmailControl.open()
|
||||
} else {
|
||||
confirmDialogControl.open()
|
||||
}
|
||||
}}
|
||||
style={{backgroundColor: 'transparent'}}>
|
||||
<ButtonText style={{color: 'white'}}>
|
||||
<Trans>Make one for me</Trans>
|
||||
@@ -262,7 +273,13 @@ function Empty() {
|
||||
color="primary"
|
||||
size="small"
|
||||
disabled={isGenerating}
|
||||
onPress={() => navigation.navigate('StarterPackWizard')}
|
||||
onPress={() => {
|
||||
if (needsEmailVerification) {
|
||||
verifyEmailControl.open()
|
||||
} else {
|
||||
navigation.navigate('StarterPackWizard')
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
borderColor: 'white',
|
||||
@@ -318,6 +335,12 @@ function Empty() {
|
||||
onConfirm={generate}
|
||||
confirmButtonCta={_(msg`Retry`)}
|
||||
/>
|
||||
<VerifyEmailDialog
|
||||
reasonText={_(
|
||||
msg`Before creating a starter pack, you must first verify your email.`,
|
||||
)}
|
||||
control={verifyEmailControl}
|
||||
/>
|
||||
</LinearGradientBackground>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,8 +18,14 @@ import {Text} from '#/components/Typography'
|
||||
|
||||
export function VerifyEmailDialog({
|
||||
control,
|
||||
onCloseWithoutVerifying,
|
||||
onCloseAfterVerifying,
|
||||
reasonText,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
onCloseWithoutVerifying?: () => void
|
||||
onCloseAfterVerifying?: () => void
|
||||
reasonText?: string
|
||||
}) {
|
||||
const agent = useAgent()
|
||||
|
||||
@@ -30,18 +36,24 @@ export function VerifyEmailDialog({
|
||||
control={control}
|
||||
onClose={async () => {
|
||||
if (!didVerify) {
|
||||
onCloseWithoutVerifying?.()
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await agent.resumeSession(agent.session!)
|
||||
onCloseAfterVerifying?.()
|
||||
} catch (e: unknown) {
|
||||
logger.error(String(e))
|
||||
return
|
||||
}
|
||||
}}>
|
||||
<Dialog.Handle />
|
||||
<Inner control={control} setDidVerify={setDidVerify} />
|
||||
<Inner
|
||||
control={control}
|
||||
setDidVerify={setDidVerify}
|
||||
reasonText={reasonText}
|
||||
/>
|
||||
</Dialog.Outer>
|
||||
)
|
||||
}
|
||||
@@ -49,9 +61,11 @@ export function VerifyEmailDialog({
|
||||
export function Inner({
|
||||
control,
|
||||
setDidVerify,
|
||||
reasonText,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
setDidVerify: (value: boolean) => void
|
||||
reasonText?: string
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const {currentAccount} = useSession()
|
||||
@@ -135,26 +149,32 @@ export function Inner({
|
||||
<Text style={[a.text_md, a.leading_snug]}>
|
||||
{currentStep === 'StepOne' ? (
|
||||
<>
|
||||
<Trans>
|
||||
You'll receive an email at{' '}
|
||||
<Text style={[a.text_md, a.leading_snug, a.font_bold]}>
|
||||
{currentAccount?.email}
|
||||
</Text>{' '}
|
||||
to verify it's you.
|
||||
</Trans>{' '}
|
||||
<InlineLinkText
|
||||
to="#"
|
||||
label={_(msg`Change email address`)}
|
||||
style={[a.text_md, a.leading_snug]}
|
||||
onPress={e => {
|
||||
e.preventDefault()
|
||||
control.close(() => {
|
||||
openModal({name: 'change-email'})
|
||||
})
|
||||
return false
|
||||
}}>
|
||||
<Trans>Need to change it?</Trans>
|
||||
</InlineLinkText>
|
||||
{!reasonText ? (
|
||||
<>
|
||||
<Trans>
|
||||
You'll receive an email at{' '}
|
||||
<Text style={[a.text_md, a.leading_snug, a.font_bold]}>
|
||||
{currentAccount?.email}
|
||||
</Text>{' '}
|
||||
to verify it's you.
|
||||
</Trans>{' '}
|
||||
<InlineLinkText
|
||||
to="#"
|
||||
label={_(msg`Change email address`)}
|
||||
style={[a.text_md, a.leading_snug]}
|
||||
onPress={e => {
|
||||
e.preventDefault()
|
||||
control.close(() => {
|
||||
openModal({name: 'change-email'})
|
||||
})
|
||||
return false
|
||||
}}>
|
||||
<Trans>Need to change it?</Trans>
|
||||
</InlineLinkText>
|
||||
</>
|
||||
) : (
|
||||
reasonText
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
uiStrings[currentStep].message
|
||||
|
||||
@@ -3,14 +3,18 @@ import {View} from 'react-native'
|
||||
import {AppBskyActorDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {useMaybeConvoForUser} from '#/state/queries/messages/get-convo-for-members'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {ButtonIcon} from '#/components/Button'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {canBeMessaged} from '#/components/dms/util'
|
||||
import {Message_Stroke2_Corner0_Rounded as Message} from '#/components/icons/Message'
|
||||
import {Link} from '#/components/Link'
|
||||
import {useDialogControl} from '../Dialog'
|
||||
import {VerifyEmailDialog} from '../dialogs/VerifyEmailDialog'
|
||||
|
||||
export function MessageProfileButton({
|
||||
profile,
|
||||
@@ -19,15 +23,29 @@ export function MessageProfileButton({
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const verifyEmailControl = useDialogControl()
|
||||
|
||||
const {data: convo, isPending} = useMaybeConvoForUser(profile.did)
|
||||
|
||||
const onPress = React.useCallback(() => {
|
||||
if (!convo?.id) {
|
||||
return
|
||||
}
|
||||
|
||||
if (needsEmailVerification) {
|
||||
verifyEmailControl.open()
|
||||
return
|
||||
}
|
||||
|
||||
if (convo && !convo.lastMessage) {
|
||||
logEvent('chat:create', {logContext: 'ProfileHeader'})
|
||||
}
|
||||
logEvent('chat:open', {logContext: 'ProfileHeader'})
|
||||
}, [convo])
|
||||
|
||||
navigation.navigate('MessagesConversation', {conversation: convo.id})
|
||||
}, [needsEmailVerification, verifyEmailControl, convo, navigation])
|
||||
|
||||
if (isPending) {
|
||||
// show pending state based on declaration
|
||||
@@ -53,18 +71,26 @@ export function MessageProfileButton({
|
||||
|
||||
if (convo) {
|
||||
return (
|
||||
<Link
|
||||
testID="dmBtn"
|
||||
size="small"
|
||||
color="secondary"
|
||||
variant="solid"
|
||||
shape="round"
|
||||
label={_(msg`Message ${profile.handle}`)}
|
||||
to={`/messages/${convo.id}`}
|
||||
style={[a.justify_center]}
|
||||
onPress={onPress}>
|
||||
<ButtonIcon icon={Message} size="md" />
|
||||
</Link>
|
||||
<>
|
||||
<Button
|
||||
accessibilityRole="button"
|
||||
testID="dmBtn"
|
||||
size="small"
|
||||
color="secondary"
|
||||
variant="solid"
|
||||
shape="round"
|
||||
label={_(msg`Message ${profile.handle}`)}
|
||||
style={[a.justify_center]}
|
||||
onPress={onPress}>
|
||||
<ButtonIcon icon={Message} size="md" />
|
||||
</Button>
|
||||
<VerifyEmailDialog
|
||||
reasonText={_(
|
||||
msg`Before you may message another user, you must first verify your email.`,
|
||||
)}
|
||||
control={verifyEmailControl}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, {useCallback} from 'react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {logger} from '#/logger'
|
||||
import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members'
|
||||
@@ -9,6 +10,8 @@ import {FAB} from '#/view/com/util/fab/FAB'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {useTheme} from '#/alf'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
|
||||
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
||||
import {SearchablePeopleList} from './SearchablePeopleList'
|
||||
|
||||
@@ -21,6 +24,8 @@ export function NewChat({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const verifyEmailControl = useDialogControl()
|
||||
|
||||
const {mutate: createChat} = useGetConvoForMembers({
|
||||
onSuccess: data => {
|
||||
@@ -48,7 +53,13 @@ export function NewChat({
|
||||
<>
|
||||
<FAB
|
||||
testID="newChatFAB"
|
||||
onPress={control.open}
|
||||
onPress={() => {
|
||||
if (needsEmailVerification) {
|
||||
verifyEmailControl.open()
|
||||
} else {
|
||||
control.open()
|
||||
}
|
||||
}}
|
||||
icon={<Plus size="lg" fill={t.palette.white} />}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={_(msg`New chat`)}
|
||||
@@ -62,6 +73,13 @@ export function NewChat({
|
||||
onSelectChat={onCreateChat}
|
||||
/>
|
||||
</Dialog.Outer>
|
||||
|
||||
<VerifyEmailDialog
|
||||
reasonText={_(
|
||||
msg`Before you may message another user, you must first verify your email.`,
|
||||
)}
|
||||
control={verifyEmailControl}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import {useServiceConfigQuery} from '#/state/queries/email-verification-required'
|
||||
import {useSession} from '#/state/session'
|
||||
import {BSKY_SERVICE} from '../constants'
|
||||
import {getHostnameFromUrl} from '../strings/url-helpers'
|
||||
|
||||
export function useEmail() {
|
||||
const {currentAccount} = useSession()
|
||||
|
||||
const {data: serviceConfig} = useServiceConfigQuery()
|
||||
|
||||
const isSelfHost =
|
||||
serviceConfig?.checkEmailConfirmed &&
|
||||
currentAccount &&
|
||||
getHostnameFromUrl(currentAccount.service) !==
|
||||
getHostnameFromUrl(BSKY_SERVICE)
|
||||
const needsEmailVerification = !isSelfHost && !currentAccount?.emailConfirmed
|
||||
|
||||
return {needsEmailVerification}
|
||||
}
|
||||
@@ -4,10 +4,11 @@ import {useKeyboardController} from 'react-native-keyboard-controller'
|
||||
import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
||||
import {CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {ConvoProvider, isConvoActive, useConvo} from '#/state/messages/convo'
|
||||
@@ -19,6 +20,8 @@ import {useSetMinimalShellMode} from '#/state/shell'
|
||||
import {CenteredView} from '#/view/com/util/Views'
|
||||
import {MessagesList} from '#/screens/Messages/components/MessagesList'
|
||||
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
|
||||
import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter'
|
||||
import {MessagesListHeader} from '#/components/dms/MessagesListHeader'
|
||||
import {Error} from '#/components/Error'
|
||||
@@ -161,8 +164,12 @@ function InnerReady({
|
||||
hasScrolled: boolean
|
||||
setHasScrolled: React.Dispatch<React.SetStateAction<boolean>>
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const convoState = useConvo()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const recipient = useProfileShadow(recipientUnshadowed)
|
||||
const verifyEmailControl = useDialogControl()
|
||||
const {needsEmailVerification} = useEmail()
|
||||
|
||||
const moderation = React.useMemo(() => {
|
||||
return moderateProfile(recipient, moderationOpts)
|
||||
@@ -179,6 +186,12 @@ function InnerReady({
|
||||
}
|
||||
}, [moderation])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (needsEmailVerification) {
|
||||
verifyEmailControl.open()
|
||||
}
|
||||
}, [needsEmailVerification, verifyEmailControl])
|
||||
|
||||
return (
|
||||
<>
|
||||
<MessagesListHeader
|
||||
@@ -201,6 +214,15 @@ function InnerReady({
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<VerifyEmailDialog
|
||||
reasonText={_(
|
||||
msg`Before you may message another user, you must first verify your email.`,
|
||||
)}
|
||||
control={verifyEmailControl}
|
||||
onCloseWithoutVerifying={() => {
|
||||
navigation.navigate('Home')
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import Graphemer from 'graphemer'
|
||||
|
||||
import {HITSLOP_10, MAX_DM_GRAPHEME_LENGTH} from '#/lib/constants'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {isIOS} from '#/platform/detection'
|
||||
import {
|
||||
useMessageDraft,
|
||||
@@ -61,10 +62,15 @@ export function MessageInput({
|
||||
const [message, setMessage] = React.useState(getDraft)
|
||||
const inputRef = useAnimatedRef<TextInput>()
|
||||
|
||||
const {needsEmailVerification} = useEmail()
|
||||
|
||||
useSaveMessageDraft(message)
|
||||
useExtractEmbedFromFacets(message, setEmbed)
|
||||
|
||||
const onSubmit = React.useCallback(() => {
|
||||
if (needsEmailVerification) {
|
||||
return
|
||||
}
|
||||
if (!hasEmbed && message.trim() === '') {
|
||||
return
|
||||
}
|
||||
@@ -84,6 +90,7 @@ export function MessageInput({
|
||||
inputRef.current?.focus()
|
||||
}, 100)
|
||||
}, [
|
||||
needsEmailVerification,
|
||||
hasEmbed,
|
||||
message,
|
||||
clearDraft,
|
||||
@@ -159,6 +166,7 @@ export function MessageInput({
|
||||
ref={inputRef}
|
||||
hitSlop={HITSLOP_10}
|
||||
animatedProps={animatedProps}
|
||||
editable={!needsEmailVerification}
|
||||
/>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
@@ -171,7 +179,8 @@ export function MessageInput({
|
||||
a.justify_center,
|
||||
{height: 30, width: 30, backgroundColor: t.palette.primary_500},
|
||||
]}
|
||||
onPress={onSubmit}>
|
||||
onPress={onSubmit}
|
||||
disabled={needsEmailVerification}>
|
||||
<PaperPlane fill={t.palette.white} style={[a.relative, {left: 1}]} />
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
|
||||
interface ServiceConfig {
|
||||
checkEmailConfirmed: boolean
|
||||
}
|
||||
|
||||
export function useServiceConfigQuery() {
|
||||
return useQuery({
|
||||
queryKey: ['service-config'],
|
||||
queryFn: async () => {
|
||||
const res = await fetch(
|
||||
'https://api.bsky.app/xrpc/app.bsky.unspecced.getConfig',
|
||||
)
|
||||
if (!res.ok) {
|
||||
return {
|
||||
checkEmailConfirmed: false,
|
||||
}
|
||||
}
|
||||
|
||||
const json = await res.json()
|
||||
return json as ServiceConfig
|
||||
},
|
||||
staleTime: 5 * 60 * 1000,
|
||||
})
|
||||
}
|
||||
@@ -58,6 +58,7 @@ import {EmbeddingDisabledError} from '#/lib/api/resolve'
|
||||
import {until} from '#/lib/async/until'
|
||||
import {MAX_GRAPHEME_LENGTH} from '#/lib/constants'
|
||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {useIsKeyboardVisible} from '#/lib/hooks/useIsKeyboardVisible'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
@@ -110,6 +111,8 @@ import * as Toast from '#/view/com/util/Toast'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, native, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
|
||||
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
||||
import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
@@ -297,6 +300,15 @@ export const ComposePost = ({
|
||||
}
|
||||
}, [onPressCancel, closeAllDialogs, closeAllModals])
|
||||
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const emailVerificationControl = useDialogControl()
|
||||
|
||||
useEffect(() => {
|
||||
if (needsEmailVerification) {
|
||||
emailVerificationControl.open()
|
||||
}
|
||||
}, [needsEmailVerification, emailVerificationControl])
|
||||
|
||||
const missingAltError = useMemo(() => {
|
||||
if (!requireAltTextEnabled) {
|
||||
return
|
||||
@@ -570,6 +582,15 @@ export const ComposePost = ({
|
||||
const isWebFooterSticky = !isNative && thread.posts.length > 1
|
||||
return (
|
||||
<BottomSheetPortalProvider>
|
||||
<VerifyEmailDialog
|
||||
control={emailVerificationControl}
|
||||
onCloseWithoutVerifying={() => {
|
||||
onClose()
|
||||
}}
|
||||
reasonText={_(
|
||||
msg`Before creating a post, you must first verify your email.`,
|
||||
)}
|
||||
/>
|
||||
<KeyboardAvoidingView
|
||||
testID="composePostView"
|
||||
behavior={isIOS ? 'padding' : 'height'}
|
||||
|
||||
@@ -2,9 +2,11 @@ import React from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {Trans} from '@lingui/macro'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
|
||||
@@ -16,15 +18,20 @@ import {MyLists} from '#/view/com/lists/MyLists'
|
||||
import {Button} from '#/view/com/util/forms/Button'
|
||||
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
|
||||
import * as Layout from '#/components/Layout'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'>
|
||||
export function ListsScreen({}: Props) {
|
||||
const {_} = useLingui()
|
||||
const pal = usePalette('default')
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {openModal} = useModalControls()
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const control = useDialogControl()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
@@ -33,6 +40,11 @@ export function ListsScreen({}: Props) {
|
||||
)
|
||||
|
||||
const onPressNewList = React.useCallback(() => {
|
||||
if (needsEmailVerification) {
|
||||
control.open()
|
||||
return
|
||||
}
|
||||
|
||||
openModal({
|
||||
name: 'create-or-edit-list',
|
||||
purpose: 'app.bsky.graph.defs#curatelist',
|
||||
@@ -46,7 +58,7 @@ export function ListsScreen({}: Props) {
|
||||
} catch {}
|
||||
},
|
||||
})
|
||||
}, [openModal, navigation])
|
||||
}, [needsEmailVerification, control, openModal, navigation])
|
||||
|
||||
return (
|
||||
<Layout.Screen testID="listsScreen">
|
||||
@@ -87,6 +99,12 @@ export function ListsScreen({}: Props) {
|
||||
</View>
|
||||
</SimpleViewHeader>
|
||||
<MyLists filter="curate" style={s.flexGrow1} />
|
||||
<VerifyEmailDialog
|
||||
reasonText={_(
|
||||
msg`Before creating a list, you must first verify your email.`,
|
||||
)}
|
||||
control={control}
|
||||
/>
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {Trans} from '@lingui/macro'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
|
||||
@@ -16,15 +18,20 @@ import {MyLists} from '#/view/com/lists/MyLists'
|
||||
import {Button} from '#/view/com/util/forms/Button'
|
||||
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
|
||||
import * as Layout from '#/components/Layout'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ModerationModlists'>
|
||||
export function ModerationModlistsScreen({}: Props) {
|
||||
const {_} = useLingui()
|
||||
const pal = usePalette('default')
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {openModal} = useModalControls()
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const control = useDialogControl()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
@@ -33,6 +40,11 @@ export function ModerationModlistsScreen({}: Props) {
|
||||
)
|
||||
|
||||
const onPressNewList = React.useCallback(() => {
|
||||
if (needsEmailVerification) {
|
||||
control.open()
|
||||
return
|
||||
}
|
||||
|
||||
openModal({
|
||||
name: 'create-or-edit-list',
|
||||
purpose: 'app.bsky.graph.defs#modlist',
|
||||
@@ -46,7 +58,7 @@ export function ModerationModlistsScreen({}: Props) {
|
||||
} catch {}
|
||||
},
|
||||
})
|
||||
}, [openModal, navigation])
|
||||
}, [needsEmailVerification, control, openModal, navigation])
|
||||
|
||||
return (
|
||||
<Layout.Screen testID="moderationModlistsScreen">
|
||||
@@ -83,6 +95,12 @@ export function ModerationModlistsScreen({}: Props) {
|
||||
</View>
|
||||
</SimpleViewHeader>
|
||||
<MyLists filter="mod" style={s.flexGrow1} />
|
||||
<VerifyEmailDialog
|
||||
reasonText={_(
|
||||
msg`Before creating a list, you must first verify your email.`,
|
||||
)}
|
||||
control={control}
|
||||
/>
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user