[APP-1158] Refactor email-related dialogs (#8296)
* WIP * Update email * Fire off confirmation email after change * Verify step, integrate stateful control * Remove tentative EnterCode step * Handle token step * Handle instructions and integrate into 2FA setting * Fix load state when reusing same email * Add new state * Add 2FA screens * Clean up state in Update step * Clean up verify state, handle normal callback * Normalize convetions * Add verification reminder screen * Improve session refresh * Handle verification requirements for composer and convo * Fix lint * Do better * Couple missing translations * Format * Use listeners for easier to grok logic * Clean errors * Move to global context * [APP-1158] Gate features by email verification state (#8305) * Use new hook in all locations * Format * Seems to work, not great duplication * Wrap all open composer calls * Remove unneeded spans * Missed one * Fix handler on Conversation * Gate new chat in header * Add comment * Remove whoopsie * Format * add hackfix for dialog not showing * add prompt to accept chat btn * navigation not necessary * send back one screen, rather than home * Update comment --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com> * Clear dialog state Co-authored-by: Samuel Newman <mozzius@protonmail.com> * Update icon * Check color * Add 2FA warning * Update instructions * Fix X button * Use an effect silly goose * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update src/components/dialaUpdate copyogs/EmailDialog/screens/Update.tsx Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy * Update copy * Update copy * Update copy * Update copy Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * Update copy * Add link back to update email from verify email dialog * Handle token field validation --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com> Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import {useCallback} from 'react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
type CleanedError = {
|
||||
raw: string | undefined
|
||||
clean: string | undefined
|
||||
}
|
||||
|
||||
export function useCleanError() {
|
||||
const {_} = useLingui()
|
||||
|
||||
return useCallback<(error?: any) => CleanedError>(
|
||||
error => {
|
||||
if (!error)
|
||||
return {
|
||||
raw: undefined,
|
||||
clean: undefined,
|
||||
}
|
||||
|
||||
let raw = error.toString()
|
||||
|
||||
if (isNetworkError(raw)) {
|
||||
return {
|
||||
raw,
|
||||
clean: _(
|
||||
msg`Unable to connect. Please check your internet connection and try again.`,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
raw.includes('Upstream Failure') ||
|
||||
raw.includes('NotEnoughResources') ||
|
||||
raw.includes('pipethrough network error')
|
||||
) {
|
||||
return {
|
||||
raw,
|
||||
clean: _(
|
||||
msg`The server appears to be experiencing issues. Please try again in a few moments.`,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if (raw.includes('Bad token scope')) {
|
||||
return {
|
||||
raw,
|
||||
clean: _(
|
||||
msg`This feature is not available while using an app password. Please sign in with your main password.`,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if (raw.includes('Rate Limit Exceeded')) {
|
||||
return {
|
||||
raw,
|
||||
clean: _(
|
||||
msg`You've reached the maximum number of requests allowed. Please try again later.`,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if (raw.startsWith('Error: ')) {
|
||||
raw = raw.slice('Error: '.length)
|
||||
}
|
||||
|
||||
return {
|
||||
raw,
|
||||
clean: undefined,
|
||||
}
|
||||
},
|
||||
[_],
|
||||
)
|
||||
}
|
||||
|
||||
const NETWORK_ERRORS = [
|
||||
'Abort',
|
||||
'Network request failed',
|
||||
'Failed to fetch',
|
||||
'Load failed',
|
||||
]
|
||||
|
||||
export function isNetworkError(e: unknown) {
|
||||
const str = String(e)
|
||||
for (const err of NETWORK_ERRORS) {
|
||||
if (str.includes(err)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import React from 'react'
|
||||
import * as Linking from 'expo-linking'
|
||||
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useComposerControls} from '#/state/shell'
|
||||
import {useCloseAllActiveElements} from '#/state/util'
|
||||
import {useIntentDialogs} from '#/components/intents/IntentDialogs'
|
||||
import {Referrer} from '../../../modules/expo-bluesky-swiss-army'
|
||||
@@ -83,7 +83,7 @@ export function useIntentHandler() {
|
||||
|
||||
export function useComposeIntent() {
|
||||
const closeAllActiveElements = useCloseAllActiveElements()
|
||||
const {openComposer} = useComposerControls()
|
||||
const {openComposer} = useOpenComposer()
|
||||
const {hasSession} = useSession()
|
||||
|
||||
return React.useCallback(
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import {useMemo} from 'react'
|
||||
import {Trans} from '@lingui/macro'
|
||||
|
||||
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
|
||||
import {useOpenComposer as rootUseOpenComposer} from '#/state/shell/composer'
|
||||
|
||||
export function useOpenComposer() {
|
||||
const {openComposer} = rootUseOpenComposer()
|
||||
const requireEmailVerification = useRequireEmailVerification()
|
||||
return useMemo(() => {
|
||||
return {
|
||||
openComposer: requireEmailVerification(openComposer, {
|
||||
instructions: [
|
||||
<Trans key="pre-compose">
|
||||
Before creating a post or replying, you must first verify your
|
||||
email.
|
||||
</Trans>,
|
||||
],
|
||||
}),
|
||||
}
|
||||
}, [openComposer, requireEmailVerification])
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import {useCallback} from 'react'
|
||||
import {Keyboard} from 'react-native'
|
||||
|
||||
import {useEmail} from '#/lib/hooks/useEmail'
|
||||
import {useRequireAuth, useSession} from '#/state/session'
|
||||
import {useCloseAllActiveElements} from '#/state/util'
|
||||
import {
|
||||
EmailDialogScreenID,
|
||||
type Screen,
|
||||
useEmailDialogControl,
|
||||
} from '#/components/dialogs/EmailDialog'
|
||||
|
||||
export function useRequireEmailVerification() {
|
||||
const {currentAccount} = useSession()
|
||||
const {needsEmailVerification} = useEmail()
|
||||
const requireAuth = useRequireAuth()
|
||||
const emailDialogControl = useEmailDialogControl()
|
||||
const closeAll = useCloseAllActiveElements()
|
||||
|
||||
return useCallback(
|
||||
<T extends (...args: any[]) => any>(
|
||||
cb: T,
|
||||
config: Omit<
|
||||
Extract<Screen, {id: EmailDialogScreenID.Verify}>,
|
||||
'id'
|
||||
> = {},
|
||||
): ((...args: Parameters<T>) => ReturnType<T>) => {
|
||||
return (...args: Parameters<T>): ReturnType<T> => {
|
||||
if (!currentAccount) {
|
||||
return requireAuth(() => cb(...args)) as ReturnType<T>
|
||||
}
|
||||
if (needsEmailVerification) {
|
||||
Keyboard.dismiss()
|
||||
closeAll()
|
||||
emailDialogControl.open({
|
||||
id: EmailDialogScreenID.Verify,
|
||||
...config,
|
||||
})
|
||||
return undefined as ReturnType<T>
|
||||
} else {
|
||||
return cb(...args)
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
needsEmailVerification,
|
||||
currentAccount,
|
||||
emailDialogControl,
|
||||
closeAll,
|
||||
requireAuth,
|
||||
],
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user