[🙅] Disambiguation of the deactivation (#4267)
* Disambiguation of the deactivation * Snapshot crackle pop * Change log context * [🙅] Add status to session state (#4269) * Add status to session state * [🙅] Add new deactivated screen (#4270) * Add new deactivated screen * Update copy, handle logout * Remove icons, adjust padding * [🙅] Add deactivate account dialog (#4290) * Deactivate dialog (cherry picked from commit 33940e2dfe0d710c0665a7f68b198b46f54db4a2) * Factor out dialog, add to delete modal too (cherry picked from commit 47d70f6b74e7d2ea7330fd172499fe91ba41062d) * Update copy, icon (cherry picked from commit e6efabbe78c3f3d9f0f8fb0a06a6a1c4fbfb70a9) * Update copy (cherry picked from commit abb0ce26f6747ab0548f6f12df0dee3c64464852) * Sizing tweaks (cherry picked from commit fc716d5716873f0fddef56496fc48af0614b2e55) * Add a11y labelzio/stable
parent
de93e8de74
commit
3e1f076891
|
@ -13,7 +13,7 @@ export type LogEvents = {
|
||||||
withPassword: boolean
|
withPassword: boolean
|
||||||
}
|
}
|
||||||
'account:loggedOut': {
|
'account:loggedOut': {
|
||||||
logContext: 'SwitchAccount' | 'Settings' | 'Deactivated'
|
logContext: 'SwitchAccount' | 'Settings' | 'SignupQueued' | 'Deactivated'
|
||||||
}
|
}
|
||||||
'notifications:openApp': {}
|
'notifications:openApp': {}
|
||||||
'notifications:request': {
|
'notifications:request': {
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import {msg, plural, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
import {isSessionDeactivated, useAgent, useSessionApi} from '#/state/session'
|
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
|
||||||
import {useOnboardingDispatch} from '#/state/shell'
|
import {useSetMinimalShellMode} from '#/state/shell'
|
||||||
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
import {ScrollView} from '#/view/com/util/Views'
|
import {ScrollView} from '#/view/com/util/Views'
|
||||||
import {Logo} from '#/view/icons/Logo'
|
import {Logo} from '#/view/icons/Logo'
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {AccountList} from '#/components/AccountList'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import {P, Text} from '#/components/Typography'
|
import {Divider} from '#/components/Divider'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
const COL_WIDTH = 400
|
const COL_WIDTH = 400
|
||||||
|
|
||||||
|
@ -21,199 +24,151 @@ export function Deactivated() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {currentAccount, accounts} = useSession()
|
||||||
const onboardingDispatch = useOnboardingDispatch()
|
const {onPressSwitchAccount, pendingDid} = useAccountSwitcher()
|
||||||
|
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||||
|
const hasOtherAccounts = accounts.length > 1
|
||||||
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {logout} = useSessionApi()
|
const {logout} = useSessionApi()
|
||||||
const agent = useAgent()
|
|
||||||
|
|
||||||
const [isProcessing, setProcessing] = React.useState(false)
|
useFocusEffect(
|
||||||
const [estimatedTime, setEstimatedTime] = React.useState<string | undefined>(
|
React.useCallback(() => {
|
||||||
undefined,
|
setMinimalShellMode(true)
|
||||||
)
|
}, [setMinimalShellMode]),
|
||||||
const [placeInQueue, setPlaceInQueue] = React.useState<number | undefined>(
|
|
||||||
undefined,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const checkStatus = React.useCallback(async () => {
|
const onSelectAccount = React.useCallback(
|
||||||
setProcessing(true)
|
(account: SessionAccount) => {
|
||||||
try {
|
if (account.did !== currentAccount?.did) {
|
||||||
const res = await agent.com.atproto.temp.checkSignupQueue()
|
onPressSwitchAccount(account, 'SwitchAccount')
|
||||||
if (res.data.activated) {
|
|
||||||
// ready to go, exchange the access token for a usable one and kick off onboarding
|
|
||||||
await agent.refreshSession()
|
|
||||||
if (!isSessionDeactivated(agent.session?.accessJwt)) {
|
|
||||||
onboardingDispatch({type: 'start'})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// not ready, update UI
|
|
||||||
setEstimatedTime(msToString(res.data.estimatedTimeMs))
|
|
||||||
if (typeof res.data.placeInQueue !== 'undefined') {
|
|
||||||
setPlaceInQueue(Math.max(res.data.placeInQueue, 1))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
},
|
||||||
logger.error('Failed to check signup queue', {err: e.toString()})
|
[currentAccount, onPressSwitchAccount],
|
||||||
} finally {
|
|
||||||
setProcessing(false)
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
setProcessing,
|
|
||||||
setEstimatedTime,
|
|
||||||
setPlaceInQueue,
|
|
||||||
onboardingDispatch,
|
|
||||||
agent,
|
|
||||||
])
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
checkStatus()
|
|
||||||
const interval = setInterval(checkStatus, 60e3)
|
|
||||||
return () => clearInterval(interval)
|
|
||||||
}, [checkStatus])
|
|
||||||
|
|
||||||
const checkBtn = (
|
|
||||||
<Button
|
|
||||||
variant="solid"
|
|
||||||
color="primary"
|
|
||||||
size="large"
|
|
||||||
label={_(msg`Check my status`)}
|
|
||||||
onPress={checkStatus}
|
|
||||||
disabled={isProcessing}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Check my status</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
{isProcessing && <ButtonIcon icon={Loader} />}
|
|
||||||
</Button>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const onPressAddAccount = React.useCallback(() => {
|
||||||
|
setShowLoggedOut(true)
|
||||||
|
}, [setShowLoggedOut])
|
||||||
|
|
||||||
|
const onPressLogout = React.useCallback(() => {
|
||||||
|
if (isWeb) {
|
||||||
|
// We're switching accounts, which remounts the entire app.
|
||||||
|
// On mobile, this gets us Home, but on the web we also need reset the URL.
|
||||||
|
// We can't change the URL via a navigate() call because the navigator
|
||||||
|
// itself is about to unmount, and it calls pushState() too late.
|
||||||
|
// So we change the URL ourselves. The navigator will pick it up on remount.
|
||||||
|
history.pushState(null, '', '/')
|
||||||
|
}
|
||||||
|
logout('Deactivated')
|
||||||
|
}, [logout])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View style={[a.h_full_vh, a.flex_1, t.atoms.bg]}>
|
||||||
aria-modal
|
|
||||||
role="dialog"
|
|
||||||
aria-role="dialog"
|
|
||||||
aria-label={_(msg`You're in line`)}
|
|
||||||
accessibilityLabel={_(msg`You're in line`)}
|
|
||||||
accessibilityHint=""
|
|
||||||
style={[a.absolute, a.inset_0, a.flex_1, t.atoms.bg]}>
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={[a.h_full, a.w_full]}
|
style={[a.h_full, a.w_full]}
|
||||||
contentContainerStyle={{borderWidth: 0}}>
|
contentContainerStyle={{borderWidth: 0}}>
|
||||||
<View
|
|
||||||
style={[a.flex_row, a.justify_center, gtMobile ? a.pt_4xl : a.px_xl]}>
|
|
||||||
<View style={[a.flex_1, {maxWidth: COL_WIDTH}]}>
|
|
||||||
<View
|
|
||||||
style={[a.w_full, a.justify_center, a.align_center, a.my_4xl]}>
|
|
||||||
<Logo width={120} />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={[a.text_4xl, a.font_bold, a.pb_sm]}>
|
|
||||||
<Trans>You're in line</Trans>
|
|
||||||
</Text>
|
|
||||||
<P style={[t.atoms.text_contrast_medium]}>
|
|
||||||
<Trans>
|
|
||||||
There's been a rush of new users to Bluesky! We'll activate your
|
|
||||||
account as soon as we can.
|
|
||||||
</Trans>
|
|
||||||
</P>
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
a.rounded_sm,
|
|
||||||
a.px_2xl,
|
|
||||||
a.py_4xl,
|
|
||||||
a.mt_2xl,
|
|
||||||
t.atoms.bg_contrast_50,
|
|
||||||
]}>
|
|
||||||
{typeof placeInQueue === 'number' && (
|
|
||||||
<Text
|
|
||||||
style={[a.text_5xl, a.text_center, a.font_bold, a.mb_2xl]}>
|
|
||||||
{placeInQueue}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
<P style={[a.text_center]}>
|
|
||||||
{typeof placeInQueue === 'number' ? (
|
|
||||||
<Trans>left to go.</Trans>
|
|
||||||
) : (
|
|
||||||
<Trans>You are in line.</Trans>
|
|
||||||
)}{' '}
|
|
||||||
{estimatedTime ? (
|
|
||||||
<Trans>
|
|
||||||
We estimate {estimatedTime} until your account is ready.
|
|
||||||
</Trans>
|
|
||||||
) : (
|
|
||||||
<Trans>
|
|
||||||
We will let you know when your account is ready.
|
|
||||||
</Trans>
|
|
||||||
)}
|
|
||||||
</P>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{isWeb && gtMobile && (
|
|
||||||
<View style={[a.w_full, a.flex_row, a.justify_between, a.pt_5xl]}>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="large"
|
|
||||||
label={_(msg`Log out`)}
|
|
||||||
onPress={() => logout('Deactivated')}>
|
|
||||||
<ButtonText style={[{color: t.palette.primary_500}]}>
|
|
||||||
<Trans>Log out</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
{checkBtn}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{height: 200}} />
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
{(!isWeb || !gtMobile) && (
|
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
a.align_center,
|
a.px_2xl,
|
||||||
gtMobile ? a.px_5xl : a.px_xl,
|
|
||||||
{
|
{
|
||||||
paddingBottom: Math.max(insets.bottom, a.pb_5xl.paddingBottom),
|
paddingTop: isWeb ? 64 : insets.top,
|
||||||
|
paddingBottom: isWeb ? 64 : insets.bottom,
|
||||||
},
|
},
|
||||||
]}>
|
]}>
|
||||||
<View style={[a.w_full, a.gap_sm, {maxWidth: COL_WIDTH}]}>
|
<View style={[a.flex_row, a.justify_center]}>
|
||||||
{checkBtn}
|
<View style={[a.w_full, {maxWidth: COL_WIDTH}]}>
|
||||||
<Button
|
<View
|
||||||
variant="ghost"
|
style={[a.w_full, a.justify_center, a.align_center, a.pb_5xl]}>
|
||||||
size="large"
|
<Logo width={40} />
|
||||||
label={_(msg`Log out`)}
|
</View>
|
||||||
onPress={() => logout('Deactivated')}>
|
|
||||||
<ButtonText style={[{color: t.palette.primary_500}]}>
|
<View style={[a.gap_xs, a.pb_3xl]}>
|
||||||
<Trans>Log out</Trans>
|
<Text style={[a.text_xl, a.font_bold, a.leading_snug]}>
|
||||||
</ButtonText>
|
<Trans>Welcome back!</Trans>
|
||||||
</Button>
|
</Text>
|
||||||
|
<Text style={[a.text_sm, a.leading_snug]}>
|
||||||
|
<Trans>
|
||||||
|
You previously deactivated @{currentAccount?.handle}.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text style={[a.text_sm, a.leading_snug, a.pb_md]}>
|
||||||
|
<Trans>
|
||||||
|
You can reactivate your account to continue logging in. Your
|
||||||
|
profile and posts will be visible to other users.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<View style={[a.gap_sm]}>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Reactivate your account`)}
|
||||||
|
size="medium"
|
||||||
|
variant="solid"
|
||||||
|
color="primary"
|
||||||
|
onPress={() => setShowLoggedOut(true)}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Yes, reactivate my account</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Cancel reactivation and log out`)}
|
||||||
|
size="medium"
|
||||||
|
variant="solid"
|
||||||
|
color="secondary"
|
||||||
|
onPress={onPressLogout}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Cancel</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={[a.pb_3xl]}>
|
||||||
|
<Divider />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{hasOtherAccounts ? (
|
||||||
|
<>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
t.atoms.text_contrast_medium,
|
||||||
|
a.pb_md,
|
||||||
|
a.leading_snug,
|
||||||
|
]}>
|
||||||
|
<Trans>Or, log into one of your other accounts.</Trans>
|
||||||
|
</Text>
|
||||||
|
<AccountList
|
||||||
|
onSelectAccount={onSelectAccount}
|
||||||
|
onSelectOther={onPressAddAccount}
|
||||||
|
otherLabel={_(msg`Add account`)}
|
||||||
|
pendingDid={pendingDid}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
t.atoms.text_contrast_medium,
|
||||||
|
a.pb_md,
|
||||||
|
a.leading_snug,
|
||||||
|
]}>
|
||||||
|
<Trans>Or, continue with another account.</Trans>
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Log in or sign up`)}
|
||||||
|
size="medium"
|
||||||
|
variant="solid"
|
||||||
|
color="secondary"
|
||||||
|
onPress={() => setShowLoggedOut(true)}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Log in or sign up</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function msToString(ms: number | undefined): string | undefined {
|
|
||||||
if (ms && ms > 0) {
|
|
||||||
const estimatedTimeMins = Math.ceil(ms / 60e3)
|
|
||||||
if (estimatedTimeMins > 59) {
|
|
||||||
const estimatedTimeHrs = Math.round(estimatedTimeMins / 60)
|
|
||||||
if (estimatedTimeHrs > 6) {
|
|
||||||
// dont even bother
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
// hours
|
|
||||||
return `${estimatedTimeHrs} ${plural(estimatedTimeHrs, {
|
|
||||||
one: 'hour',
|
|
||||||
other: 'hours',
|
|
||||||
})}`
|
|
||||||
}
|
|
||||||
// minutes
|
|
||||||
return `${estimatedTimeMins} ${plural(estimatedTimeMins, {
|
|
||||||
one: 'minute',
|
|
||||||
other: 'minutes',
|
|
||||||
})}`
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {DialogOuterProps} from '#/components/Dialog'
|
||||||
|
import {Divider} from '#/components/Divider'
|
||||||
|
import * as Prompt from '#/components/Prompt'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
|
export function DeactivateAccountDialog({
|
||||||
|
control,
|
||||||
|
}: {
|
||||||
|
control: DialogOuterProps['control']
|
||||||
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Prompt.Outer control={control} testID="confirmModal">
|
||||||
|
<Prompt.TitleText>{_(msg`Deactivate account`)}</Prompt.TitleText>
|
||||||
|
<Prompt.DescriptionText>
|
||||||
|
<Trans>
|
||||||
|
Your profile, posts, feeds, and lists will no longer be visible to
|
||||||
|
other Bluesky users. You can reactivate your account at any time by
|
||||||
|
logging in.
|
||||||
|
</Trans>
|
||||||
|
</Prompt.DescriptionText>
|
||||||
|
|
||||||
|
<View style={[a.pb_xl]}>
|
||||||
|
<Divider />
|
||||||
|
<View style={[a.gap_sm, a.pt_lg, a.pb_xl]}>
|
||||||
|
<Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
|
||||||
|
<Trans>
|
||||||
|
There is no time limit for account deactivation, come back any
|
||||||
|
time.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
|
||||||
|
<Trans>
|
||||||
|
If you're trying to change your handle or email, do so before you
|
||||||
|
deactivate.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
</View>
|
||||||
|
<Prompt.Actions>
|
||||||
|
<Prompt.Action
|
||||||
|
cta={_(msg`Yes, deactivate`)}
|
||||||
|
onPress={() => {}}
|
||||||
|
color="negative"
|
||||||
|
/>
|
||||||
|
<Prompt.Cancel />
|
||||||
|
</Prompt.Actions>
|
||||||
|
</Prompt.Outer>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
|
import {msg, plural, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {logger} from '#/logger'
|
||||||
|
import {isWeb} from '#/platform/detection'
|
||||||
|
import {isSignupQueued, useAgent, useSessionApi} from '#/state/session'
|
||||||
|
import {useOnboardingDispatch} from '#/state/shell'
|
||||||
|
import {ScrollView} from '#/view/com/util/Views'
|
||||||
|
import {Logo} from '#/view/icons/Logo'
|
||||||
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
|
import {Loader} from '#/components/Loader'
|
||||||
|
import {P, Text} from '#/components/Typography'
|
||||||
|
|
||||||
|
const COL_WIDTH = 400
|
||||||
|
|
||||||
|
export function SignupQueued() {
|
||||||
|
const {_} = useLingui()
|
||||||
|
const t = useTheme()
|
||||||
|
const insets = useSafeAreaInsets()
|
||||||
|
const {gtMobile} = useBreakpoints()
|
||||||
|
const onboardingDispatch = useOnboardingDispatch()
|
||||||
|
const {logout} = useSessionApi()
|
||||||
|
const agent = useAgent()
|
||||||
|
|
||||||
|
const [isProcessing, setProcessing] = React.useState(false)
|
||||||
|
const [estimatedTime, setEstimatedTime] = React.useState<string | undefined>(
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
|
const [placeInQueue, setPlaceInQueue] = React.useState<number | undefined>(
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
|
|
||||||
|
const checkStatus = React.useCallback(async () => {
|
||||||
|
setProcessing(true)
|
||||||
|
try {
|
||||||
|
const res = await agent.com.atproto.temp.checkSignupQueue()
|
||||||
|
if (res.data.activated) {
|
||||||
|
// ready to go, exchange the access token for a usable one and kick off onboarding
|
||||||
|
await agent.refreshSession()
|
||||||
|
if (!isSignupQueued(agent.session?.accessJwt)) {
|
||||||
|
onboardingDispatch({type: 'start'})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not ready, update UI
|
||||||
|
setEstimatedTime(msToString(res.data.estimatedTimeMs))
|
||||||
|
if (typeof res.data.placeInQueue !== 'undefined') {
|
||||||
|
setPlaceInQueue(Math.max(res.data.placeInQueue, 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
logger.error('Failed to check signup queue', {err: e.toString()})
|
||||||
|
} finally {
|
||||||
|
setProcessing(false)
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
setProcessing,
|
||||||
|
setEstimatedTime,
|
||||||
|
setPlaceInQueue,
|
||||||
|
onboardingDispatch,
|
||||||
|
agent,
|
||||||
|
])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
checkStatus()
|
||||||
|
const interval = setInterval(checkStatus, 60e3)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [checkStatus])
|
||||||
|
|
||||||
|
const checkBtn = (
|
||||||
|
<Button
|
||||||
|
variant="solid"
|
||||||
|
color="primary"
|
||||||
|
size="large"
|
||||||
|
label={_(msg`Check my status`)}
|
||||||
|
onPress={checkStatus}
|
||||||
|
disabled={isProcessing}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Check my status</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
{isProcessing && <ButtonIcon icon={Loader} />}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
aria-modal
|
||||||
|
role="dialog"
|
||||||
|
aria-role="dialog"
|
||||||
|
aria-label={_(msg`You're in line`)}
|
||||||
|
accessibilityLabel={_(msg`You're in line`)}
|
||||||
|
accessibilityHint=""
|
||||||
|
style={[a.absolute, a.inset_0, a.flex_1, t.atoms.bg]}>
|
||||||
|
<ScrollView
|
||||||
|
style={[a.h_full, a.w_full]}
|
||||||
|
contentContainerStyle={{borderWidth: 0}}>
|
||||||
|
<View
|
||||||
|
style={[a.flex_row, a.justify_center, gtMobile ? a.pt_4xl : a.px_xl]}>
|
||||||
|
<View style={[a.flex_1, {maxWidth: COL_WIDTH}]}>
|
||||||
|
<View
|
||||||
|
style={[a.w_full, a.justify_center, a.align_center, a.my_4xl]}>
|
||||||
|
<Logo width={120} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text style={[a.text_4xl, a.font_bold, a.pb_sm]}>
|
||||||
|
<Trans>You're in line</Trans>
|
||||||
|
</Text>
|
||||||
|
<P style={[t.atoms.text_contrast_medium]}>
|
||||||
|
<Trans>
|
||||||
|
There's been a rush of new users to Bluesky! We'll activate your
|
||||||
|
account as soon as we can.
|
||||||
|
</Trans>
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.rounded_sm,
|
||||||
|
a.px_2xl,
|
||||||
|
a.py_4xl,
|
||||||
|
a.mt_2xl,
|
||||||
|
t.atoms.bg_contrast_50,
|
||||||
|
]}>
|
||||||
|
{typeof placeInQueue === 'number' && (
|
||||||
|
<Text
|
||||||
|
style={[a.text_5xl, a.text_center, a.font_bold, a.mb_2xl]}>
|
||||||
|
{placeInQueue}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
<P style={[a.text_center]}>
|
||||||
|
{typeof placeInQueue === 'number' ? (
|
||||||
|
<Trans>left to go.</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>You are in line.</Trans>
|
||||||
|
)}{' '}
|
||||||
|
{estimatedTime ? (
|
||||||
|
<Trans>
|
||||||
|
We estimate {estimatedTime} until your account is ready.
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>
|
||||||
|
We will let you know when your account is ready.
|
||||||
|
</Trans>
|
||||||
|
)}
|
||||||
|
</P>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{isWeb && gtMobile && (
|
||||||
|
<View style={[a.w_full, a.flex_row, a.justify_between, a.pt_5xl]}>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="large"
|
||||||
|
label={_(msg`Log out`)}
|
||||||
|
onPress={() => logout('SignupQueued')}>
|
||||||
|
<ButtonText style={[{color: t.palette.primary_500}]}>
|
||||||
|
<Trans>Log out</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
{checkBtn}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={{height: 200}} />
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
{(!isWeb || !gtMobile) && (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.align_center,
|
||||||
|
gtMobile ? a.px_5xl : a.px_xl,
|
||||||
|
{
|
||||||
|
paddingBottom: Math.max(insets.bottom, a.pb_5xl.paddingBottom),
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<View style={[a.w_full, a.gap_sm, {maxWidth: COL_WIDTH}]}>
|
||||||
|
{checkBtn}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="large"
|
||||||
|
label={_(msg`Log out`)}
|
||||||
|
onPress={() => logout('SignupQueued')}>
|
||||||
|
<ButtonText style={[{color: t.palette.primary_500}]}>
|
||||||
|
<Trans>Log out</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function msToString(ms: number | undefined): string | undefined {
|
||||||
|
if (ms && ms > 0) {
|
||||||
|
const estimatedTimeMins = Math.ceil(ms / 60e3)
|
||||||
|
if (estimatedTimeMins > 59) {
|
||||||
|
const estimatedTimeHrs = Math.round(estimatedTimeMins / 60)
|
||||||
|
if (estimatedTimeHrs > 6) {
|
||||||
|
// dont even bother
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
// hours
|
||||||
|
return `${estimatedTimeHrs} ${plural(estimatedTimeHrs, {
|
||||||
|
one: 'hour',
|
||||||
|
other: 'hours',
|
||||||
|
})}`
|
||||||
|
}
|
||||||
|
// minutes
|
||||||
|
return `${estimatedTimeMins} ${plural(estimatedTimeMins, {
|
||||||
|
one: 'minute',
|
||||||
|
other: 'minutes',
|
||||||
|
})}`
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
|
@ -17,7 +17,10 @@ const accountSchema = z.object({
|
||||||
emailAuthFactor: z.boolean().optional(),
|
emailAuthFactor: z.boolean().optional(),
|
||||||
refreshJwt: z.string().optional(), // optional because it can expire
|
refreshJwt: z.string().optional(), // optional because it can expire
|
||||||
accessJwt: z.string().optional(), // optional because it can expire
|
accessJwt: z.string().optional(), // optional because it can expire
|
||||||
deactivated: z.boolean().optional(),
|
signupQueued: z.boolean().optional(),
|
||||||
|
status: z
|
||||||
|
.enum(['active', 'takendown', 'suspended', 'deactivated'])
|
||||||
|
.optional(),
|
||||||
pdsUrl: z.string().optional(),
|
pdsUrl: z.string().optional(),
|
||||||
})
|
})
|
||||||
export type PersistedAccount = z.infer<typeof accountSchema>
|
export type PersistedAccount = z.infer<typeof accountSchema>
|
||||||
|
|
|
@ -50,7 +50,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-1",
|
"accessJwt": "alice-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -59,6 +58,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-1",
|
"refreshJwt": "alice-refresh-jwt-1",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -87,7 +88,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": undefined,
|
"accessJwt": undefined,
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -96,6 +96,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": undefined,
|
"refreshJwt": undefined,
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -136,7 +138,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-1",
|
"accessJwt": "alice-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -145,6 +146,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-1",
|
"refreshJwt": "alice-refresh-jwt-1",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -183,7 +186,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "bob-access-jwt-1",
|
"accessJwt": "bob-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -192,10 +194,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "bob-refresh-jwt-1",
|
"refreshJwt": "bob-refresh-jwt-1",
|
||||||
"service": "https://bob.com/",
|
"service": "https://bob.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-1",
|
"accessJwt": "alice-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -204,6 +207,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-1",
|
"refreshJwt": "alice-refresh-jwt-1",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -242,7 +247,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-2",
|
"accessJwt": "alice-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -251,10 +255,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-2",
|
"refreshJwt": "alice-refresh-jwt-2",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": "bob-access-jwt-1",
|
"accessJwt": "bob-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -263,6 +268,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "bob-refresh-jwt-1",
|
"refreshJwt": "bob-refresh-jwt-1",
|
||||||
"service": "https://bob.com/",
|
"service": "https://bob.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -299,7 +306,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "jay-access-jwt-1",
|
"accessJwt": "jay-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "jay-did",
|
"did": "jay-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -308,10 +314,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "jay-refresh-jwt-1",
|
"refreshJwt": "jay-refresh-jwt-1",
|
||||||
"service": "https://jay.com/",
|
"service": "https://jay.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-2",
|
"accessJwt": "alice-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -320,10 +327,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-2",
|
"refreshJwt": "alice-refresh-jwt-2",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": "bob-access-jwt-1",
|
"accessJwt": "bob-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -332,6 +340,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "bob-refresh-jwt-1",
|
"refreshJwt": "bob-refresh-jwt-1",
|
||||||
"service": "https://bob.com/",
|
"service": "https://bob.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -364,7 +374,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": undefined,
|
"accessJwt": undefined,
|
||||||
"deactivated": false,
|
|
||||||
"did": "jay-did",
|
"did": "jay-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -373,10 +382,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": undefined,
|
"refreshJwt": undefined,
|
||||||
"service": "https://jay.com/",
|
"service": "https://jay.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": undefined,
|
"accessJwt": undefined,
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -385,10 +395,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": undefined,
|
"refreshJwt": undefined,
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": undefined,
|
"accessJwt": undefined,
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -397,6 +408,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": undefined,
|
"refreshJwt": undefined,
|
||||||
"service": "https://bob.com/",
|
"service": "https://bob.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -446,7 +459,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": undefined,
|
"accessJwt": undefined,
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -455,6 +467,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": undefined,
|
"refreshJwt": undefined,
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -490,7 +504,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-2",
|
"accessJwt": "alice-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -499,6 +512,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-2",
|
"refreshJwt": "alice-refresh-jwt-2",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -601,7 +616,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "bob-access-jwt-1",
|
"accessJwt": "bob-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -610,6 +624,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "bob-refresh-jwt-1",
|
"refreshJwt": "bob-refresh-jwt-1",
|
||||||
"service": "https://bob.com/",
|
"service": "https://bob.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -681,7 +697,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-2",
|
"accessJwt": "alice-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": "alice@foo.bar",
|
"email": "alice@foo.bar",
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -690,6 +705,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-2",
|
"refreshJwt": "alice-refresh-jwt-2",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -731,7 +748,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-3",
|
"accessJwt": "alice-access-jwt-3",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": "alice@foo.baz",
|
"email": "alice@foo.baz",
|
||||||
"emailAuthFactor": true,
|
"emailAuthFactor": true,
|
||||||
|
@ -740,6 +756,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-3",
|
"refreshJwt": "alice-refresh-jwt-3",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -781,7 +799,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-4",
|
"accessJwt": "alice-access-jwt-4",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": "alice@foo.baz",
|
"email": "alice@foo.baz",
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -790,6 +807,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-4",
|
"refreshJwt": "alice-refresh-jwt-4",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -937,7 +956,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "bob-access-jwt-1",
|
"accessJwt": "bob-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -946,10 +964,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "bob-refresh-jwt-1",
|
"refreshJwt": "bob-refresh-jwt-1",
|
||||||
"service": "https://bob.com/",
|
"service": "https://bob.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-2",
|
"accessJwt": "alice-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": "alice@foo.bar",
|
"email": "alice@foo.bar",
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -958,6 +977,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-2",
|
"refreshJwt": "alice-refresh-jwt-2",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -997,7 +1018,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "bob-access-jwt-2",
|
"accessJwt": "bob-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1006,10 +1026,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "bob-refresh-jwt-2",
|
"refreshJwt": "bob-refresh-jwt-2",
|
||||||
"service": "https://bob.com/",
|
"service": "https://bob.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-2",
|
"accessJwt": "alice-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": "alice@foo.bar",
|
"email": "alice@foo.bar",
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1018,6 +1039,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-2",
|
"refreshJwt": "alice-refresh-jwt-2",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -1156,7 +1179,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "alice-access-jwt-1",
|
"accessJwt": "alice-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1165,6 +1187,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "alice-refresh-jwt-1",
|
"refreshJwt": "alice-refresh-jwt-1",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -1218,7 +1242,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": undefined,
|
"accessJwt": undefined,
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1227,6 +1250,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": undefined,
|
"refreshJwt": undefined,
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -1280,7 +1305,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": undefined,
|
"accessJwt": undefined,
|
||||||
"deactivated": false,
|
|
||||||
"did": "alice-did",
|
"did": "alice-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1289,6 +1313,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": undefined,
|
"refreshJwt": undefined,
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -1371,7 +1397,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "jay-access-jwt-1",
|
"accessJwt": "jay-access-jwt-1",
|
||||||
"deactivated": false,
|
|
||||||
"did": "jay-did",
|
"did": "jay-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1380,10 +1405,11 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "jay-refresh-jwt-1",
|
"refreshJwt": "jay-refresh-jwt-1",
|
||||||
"service": "https://jay.com/",
|
"service": "https://jay.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"accessJwt": "bob-access-jwt-2",
|
"accessJwt": "bob-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "bob-did",
|
"did": "bob-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1392,6 +1418,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "bob-refresh-jwt-2",
|
"refreshJwt": "bob-refresh-jwt-2",
|
||||||
"service": "https://alice.com/",
|
"service": "https://alice.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
@ -1429,7 +1457,6 @@ describe('session', () => {
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"accessJwt": "clarence-access-jwt-2",
|
"accessJwt": "clarence-access-jwt-2",
|
||||||
"deactivated": false,
|
|
||||||
"did": "clarence-did",
|
"did": "clarence-did",
|
||||||
"email": undefined,
|
"email": undefined,
|
||||||
"emailAuthFactor": false,
|
"emailAuthFactor": false,
|
||||||
|
@ -1438,6 +1465,8 @@ describe('session', () => {
|
||||||
"pdsUrl": undefined,
|
"pdsUrl": undefined,
|
||||||
"refreshJwt": "clarence-refresh-jwt-2",
|
"refreshJwt": "clarence-refresh-jwt-2",
|
||||||
"service": "https://clarence.com/",
|
"service": "https://clarence.com/",
|
||||||
|
"signupQueued": false,
|
||||||
|
"status": "active",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"currentAgentState": {
|
"currentAgentState": {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
configureModerationForGuest,
|
configureModerationForGuest,
|
||||||
} from './moderation'
|
} from './moderation'
|
||||||
import {SessionAccount} from './types'
|
import {SessionAccount} from './types'
|
||||||
import {isSessionDeactivated, isSessionExpired} from './util'
|
import {isSessionExpired, isSignupQueued} from './util'
|
||||||
|
|
||||||
export function createPublicAgent() {
|
export function createPublicAgent() {
|
||||||
configureModerationForGuest() // Side effect but only relevant for tests
|
configureModerationForGuest() // Side effect but only relevant for tests
|
||||||
|
@ -51,7 +51,7 @@ export async function createAgentAndResume(
|
||||||
await networkRetry(1, () => agent.resumeSession(prevSession))
|
await networkRetry(1, () => agent.resumeSession(prevSession))
|
||||||
} else {
|
} else {
|
||||||
agent.session = prevSession
|
agent.session = prevSession
|
||||||
if (!storedAccount.deactivated) {
|
if (!storedAccount.signupQueued) {
|
||||||
// Intentionally not awaited to unblock the UI:
|
// Intentionally not awaited to unblock the UI:
|
||||||
networkRetry(3, () => agent.resumeSession(prevSession)).catch(
|
networkRetry(3, () => agent.resumeSession(prevSession)).catch(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
|
@ -135,7 +135,7 @@ export async function createAgentAndCreateAccount(
|
||||||
const account = agentToSessionAccountOrThrow(agent)
|
const account = agentToSessionAccountOrThrow(agent)
|
||||||
const gates = tryFetchGates(account.did, 'prefer-fresh-gates')
|
const gates = tryFetchGates(account.did, 'prefer-fresh-gates')
|
||||||
const moderation = configureModerationForAccount(agent, account)
|
const moderation = configureModerationForAccount(agent, account)
|
||||||
if (!account.deactivated) {
|
if (!account.signupQueued) {
|
||||||
/*dont await*/ agent.upsertProfile(_existing => {
|
/*dont await*/ agent.upsertProfile(_existing => {
|
||||||
return {
|
return {
|
||||||
displayName: '',
|
displayName: '',
|
||||||
|
@ -234,7 +234,9 @@ export function agentToSessionAccount(
|
||||||
emailAuthFactor: agent.session.emailAuthFactor || false,
|
emailAuthFactor: agent.session.emailAuthFactor || false,
|
||||||
refreshJwt: agent.session.refreshJwt,
|
refreshJwt: agent.session.refreshJwt,
|
||||||
accessJwt: agent.session.accessJwt,
|
accessJwt: agent.session.accessJwt,
|
||||||
deactivated: isSessionDeactivated(agent.session.accessJwt),
|
signupQueued: isSignupQueued(agent.session.accessJwt),
|
||||||
|
// @ts-expect-error TODO remove when backend is ready
|
||||||
|
status: agent.session.status || 'active',
|
||||||
pdsUrl: agent.pdsUrl?.toString(),
|
pdsUrl: agent.pdsUrl?.toString(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
} from './agent'
|
} from './agent'
|
||||||
import {getInitialState, reducer} from './reducer'
|
import {getInitialState, reducer} from './reducer'
|
||||||
|
|
||||||
export {isSessionDeactivated} from './util'
|
export {isSignupQueued} from './util'
|
||||||
export type {SessionAccount} from '#/state/session/types'
|
export type {SessionAccount} from '#/state/session/types'
|
||||||
import {SessionApiContext, SessionStateContext} from '#/state/session/types'
|
import {SessionApiContext, SessionStateContext} from '#/state/session/types'
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,12 @@ export function readLastActiveAccount() {
|
||||||
return accounts.find(a => a.did === currentAccount?.did)
|
return accounts.find(a => a.did === currentAccount?.did)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSessionDeactivated(accessJwt: string | undefined) {
|
export function isSignupQueued(accessJwt: string | undefined) {
|
||||||
if (accessJwt) {
|
if (accessJwt) {
|
||||||
const sessData = jwtDecode(accessJwt)
|
const sessData = jwtDecode(accessJwt)
|
||||||
return (
|
return (
|
||||||
hasProp(sessData, 'scope') && sessData.scope === 'com.atproto.deactivated'
|
hasProp(sessData, 'scope') &&
|
||||||
|
sessData.scope === 'com.atproto.signupQueued'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -18,7 +18,13 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {cleanError} from 'lib/strings/errors'
|
import {cleanError} from 'lib/strings/errors'
|
||||||
import {colors, gradients, s} from 'lib/styles'
|
import {colors, gradients, s} from 'lib/styles'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {isAndroid} from 'platform/detection'
|
import {isAndroid, isWeb} from 'platform/detection'
|
||||||
|
import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateAccountDialog'
|
||||||
|
import {atoms as a, useTheme as useNewTheme} from '#/alf'
|
||||||
|
import {useDialogControl} from '#/components/Dialog'
|
||||||
|
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
||||||
|
import {InlineLinkText} from '#/components/Link'
|
||||||
|
import {Text as NewText} from '#/components/Typography'
|
||||||
import {resetToTab} from '../../../Navigation'
|
import {resetToTab} from '../../../Navigation'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
|
@ -30,6 +36,7 @@ export const snapPoints = isAndroid ? ['90%'] : ['55%']
|
||||||
export function Component({}: {}) {
|
export function Component({}: {}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const t = useNewTheme()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const {removeAccount} = useSessionApi()
|
const {removeAccount} = useSessionApi()
|
||||||
|
@ -41,6 +48,7 @@ export function Component({}: {}) {
|
||||||
const [password, setPassword] = React.useState<string>('')
|
const [password, setPassword] = React.useState<string>('')
|
||||||
const [isProcessing, setIsProcessing] = React.useState<boolean>(false)
|
const [isProcessing, setIsProcessing] = React.useState<boolean>(false)
|
||||||
const [error, setError] = React.useState<string>('')
|
const [error, setError] = React.useState<string>('')
|
||||||
|
const deactivateAccountControl = useDialogControl()
|
||||||
const onPressSendEmail = async () => {
|
const onPressSendEmail = async () => {
|
||||||
setError('')
|
setError('')
|
||||||
setIsProcessing(true)
|
setIsProcessing(true)
|
||||||
|
@ -168,6 +176,50 @@ export function Component({}: {}) {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<View style={[!isWeb && a.px_xl]}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.w_full,
|
||||||
|
a.flex_row,
|
||||||
|
a.gap_sm,
|
||||||
|
a.mt_lg,
|
||||||
|
a.p_lg,
|
||||||
|
a.rounded_sm,
|
||||||
|
t.atoms.bg_contrast_25,
|
||||||
|
]}>
|
||||||
|
<CircleInfo
|
||||||
|
size="md"
|
||||||
|
style={[
|
||||||
|
a.relative,
|
||||||
|
{
|
||||||
|
top: -1,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NewText style={[a.leading_snug, a.flex_1]}>
|
||||||
|
<Trans>
|
||||||
|
You can also temporarily deactivate your account instead,
|
||||||
|
and reactivate it at any time.
|
||||||
|
</Trans>{' '}
|
||||||
|
<InlineLinkText
|
||||||
|
label={_(
|
||||||
|
msg`Click here for more information on deactivating your account`,
|
||||||
|
)}
|
||||||
|
to="#"
|
||||||
|
onPress={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
deactivateAccountControl.open()
|
||||||
|
return false
|
||||||
|
}}>
|
||||||
|
<Trans>Click here for more information.</Trans>
|
||||||
|
</InlineLinkText>
|
||||||
|
</NewText>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<DeactivateAccountDialog control={deactivateAccountControl} />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -60,6 +60,7 @@ import {Text} from 'view/com/util/text/Text'
|
||||||
import * as Toast from 'view/com/util/Toast'
|
import * as Toast from 'view/com/util/Toast'
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
import {ScrollView} from 'view/com/util/Views'
|
import {ScrollView} from 'view/com/util/Views'
|
||||||
|
import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateAccountDialog'
|
||||||
import {useTheme} from '#/alf'
|
import {useTheme} from '#/alf'
|
||||||
import {useDialogControl} from '#/components/Dialog'
|
import {useDialogControl} from '#/components/Dialog'
|
||||||
import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
|
import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
|
||||||
|
@ -307,6 +308,11 @@ export function SettingsScreen({}: Props) {
|
||||||
Toast.show(_(msg`Legacy storage cleared, you need to restart the app now.`))
|
Toast.show(_(msg`Legacy storage cleared, you need to restart the app now.`))
|
||||||
}, [_])
|
}, [_])
|
||||||
|
|
||||||
|
const deactivateAccountControl = useDialogControl()
|
||||||
|
const onPressDeactivateAccount = React.useCallback(() => {
|
||||||
|
deactivateAccountControl.open()
|
||||||
|
}, [deactivateAccountControl])
|
||||||
|
|
||||||
const {mutate: onPressDeleteChatDeclaration} = useDeleteActorDeclaration()
|
const {mutate: onPressDeleteChatDeclaration} = useDeleteActorDeclaration()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -791,6 +797,29 @@ export function SettingsScreen({}: Props) {
|
||||||
<Trans>Export My Data</Trans>
|
<Trans>Export My Data</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[pal.view, styles.linkCard]}
|
||||||
|
onPress={onPressDeactivateAccount}
|
||||||
|
accessible={true}
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={_(msg`Deactivate account`)}
|
||||||
|
accessibilityHint={_(
|
||||||
|
msg`Opens modal for account deactivation confirmation`,
|
||||||
|
)}>
|
||||||
|
<View style={[styles.iconContainer, dangerBg]}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={'users-slash'}
|
||||||
|
style={dangerText as FontAwesomeIconStyle}
|
||||||
|
size={18}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text type="lg" style={dangerText}>
|
||||||
|
<Trans>Deactivate my account</Trans>
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<DeactivateAccountDialog control={deactivateAccountControl} />
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[pal.view, styles.linkCard]}
|
style={[pal.view, styles.linkCard]}
|
||||||
onPress={onPressDeleteAccount}
|
onPress={onPressDeleteAccount}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import {
|
||||||
import {isWeb} from 'platform/detection'
|
import {isWeb} from 'platform/detection'
|
||||||
import {Deactivated} from '#/screens/Deactivated'
|
import {Deactivated} from '#/screens/Deactivated'
|
||||||
import {Onboarding} from '#/screens/Onboarding'
|
import {Onboarding} from '#/screens/Onboarding'
|
||||||
|
import {SignupQueued} from '#/screens/SignupQueued'
|
||||||
import {LoggedOut} from '../com/auth/LoggedOut'
|
import {LoggedOut} from '../com/auth/LoggedOut'
|
||||||
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
||||||
import {DesktopLeftNav} from './desktop/LeftNav'
|
import {DesktopLeftNav} from './desktop/LeftNav'
|
||||||
|
@ -102,12 +103,15 @@ function NativeStackNavigator({
|
||||||
if ((!PWI_ENABLED || activeRouteRequiresAuth) && !hasSession) {
|
if ((!PWI_ENABLED || activeRouteRequiresAuth) && !hasSession) {
|
||||||
return <LoggedOut />
|
return <LoggedOut />
|
||||||
}
|
}
|
||||||
if (hasSession && currentAccount?.deactivated) {
|
if (hasSession && currentAccount?.signupQueued) {
|
||||||
return <Deactivated />
|
return <SignupQueued />
|
||||||
}
|
}
|
||||||
if (showLoggedOut) {
|
if (showLoggedOut) {
|
||||||
return <LoggedOut onDismiss={() => setShowLoggedOut(false)} />
|
return <LoggedOut onDismiss={() => setShowLoggedOut(false)} />
|
||||||
}
|
}
|
||||||
|
if (currentAccount?.status === 'deactivated') {
|
||||||
|
return <Deactivated />
|
||||||
|
}
|
||||||
if (onboardingState.isActive) {
|
if (onboardingState.isActive) {
|
||||||
return <Onboarding />
|
return <Onboarding />
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue