remove some more unnecessary stuff
This commit is contained in:
@@ -1,184 +0,0 @@
|
|||||||
import React, {useEffect, useState} from 'react'
|
|
||||||
import {ActivityIndicator, Keyboard, View} from 'react-native'
|
|
||||||
import {ComAtprotoServerDescribeServer} from '@atproto/api'
|
|
||||||
import {BskyAgent} from '@atproto/api'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import * as EmailValidator from 'email-validator'
|
|
||||||
|
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
|
||||||
import {isNetworkError} from '#/lib/strings/errors'
|
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
|
||||||
import {FormError} from '#/components/forms/FormError'
|
|
||||||
import {HostingProvider} from '#/components/forms/HostingProvider'
|
|
||||||
import * as TextField from '#/components/forms/TextField'
|
|
||||||
import {At_Stroke2_Corner0_Rounded as At} from '#/components/icons/At'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
import {FormContainer} from './FormContainer'
|
|
||||||
|
|
||||||
type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema
|
|
||||||
|
|
||||||
export const ForgotPasswordForm = ({
|
|
||||||
error,
|
|
||||||
serviceUrl,
|
|
||||||
serviceDescription,
|
|
||||||
setError,
|
|
||||||
setServiceUrl,
|
|
||||||
onPressBack,
|
|
||||||
onEmailSent,
|
|
||||||
}: {
|
|
||||||
error: string
|
|
||||||
serviceUrl: string
|
|
||||||
serviceDescription: ServiceDescription | undefined
|
|
||||||
setError: (v: string) => void
|
|
||||||
setServiceUrl: (v: string) => void
|
|
||||||
onPressBack: () => void
|
|
||||||
onEmailSent: () => void
|
|
||||||
}) => {
|
|
||||||
const t = useTheme()
|
|
||||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
|
||||||
const [email, setEmail] = useState<string>('')
|
|
||||||
const {screen} = useAnalytics()
|
|
||||||
const {_} = useLingui()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
screen('Signin:ForgotPassword')
|
|
||||||
}, [screen])
|
|
||||||
|
|
||||||
const onPressSelectService = React.useCallback(() => {
|
|
||||||
Keyboard.dismiss()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const onPressNext = async () => {
|
|
||||||
if (!EmailValidator.validate(email)) {
|
|
||||||
return setError(_(msg`Your email appears to be invalid.`))
|
|
||||||
}
|
|
||||||
|
|
||||||
setError('')
|
|
||||||
setIsProcessing(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const agent = new BskyAgent({service: serviceUrl})
|
|
||||||
await agent.com.atproto.server.requestPasswordReset({email})
|
|
||||||
onEmailSent()
|
|
||||||
} catch (e: any) {
|
|
||||||
const errMsg = e.toString()
|
|
||||||
logger.warn('Failed to request password reset', {error: e})
|
|
||||||
setIsProcessing(false)
|
|
||||||
if (isNetworkError(e)) {
|
|
||||||
setError(
|
|
||||||
_(
|
|
||||||
msg`Unable to contact your service. Please check your Internet connection.`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
setError(cleanError(errMsg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormContainer
|
|
||||||
testID="forgotPasswordForm"
|
|
||||||
title={<Trans>Reset password</Trans>}>
|
|
||||||
<View>
|
|
||||||
<TextField.Label>
|
|
||||||
<Trans>Hosting provider</Trans>
|
|
||||||
</TextField.Label>
|
|
||||||
<HostingProvider
|
|
||||||
serviceUrl={serviceUrl}
|
|
||||||
onSelectServiceUrl={setServiceUrl}
|
|
||||||
onOpenDialog={onPressSelectService}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<View>
|
|
||||||
<TextField.Label>
|
|
||||||
<Trans>Email address</Trans>
|
|
||||||
</TextField.Label>
|
|
||||||
<TextField.Root>
|
|
||||||
<TextField.Icon icon={At} />
|
|
||||||
<TextField.Input
|
|
||||||
testID="forgotPasswordEmail"
|
|
||||||
label={_(msg`Enter your email address`)}
|
|
||||||
autoCapitalize="none"
|
|
||||||
autoFocus
|
|
||||||
autoCorrect={false}
|
|
||||||
autoComplete="email"
|
|
||||||
value={email}
|
|
||||||
onChangeText={setEmail}
|
|
||||||
editable={!isProcessing}
|
|
||||||
accessibilityHint={_(msg`Sets email for password reset`)}
|
|
||||||
/>
|
|
||||||
</TextField.Root>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={[t.atoms.text_contrast_high, a.leading_snug]}>
|
|
||||||
<Trans>
|
|
||||||
Enter the email you used to create your account. We'll send you a
|
|
||||||
"reset code" so you can set a new password.
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<FormError error={error} />
|
|
||||||
|
|
||||||
<View style={[a.flex_row, a.align_center, a.pt_md]}>
|
|
||||||
<Button
|
|
||||||
label={_(msg`Back`)}
|
|
||||||
variant="solid"
|
|
||||||
color="secondary"
|
|
||||||
size="medium"
|
|
||||||
onPress={onPressBack}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Back</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
<View style={a.flex_1} />
|
|
||||||
{!serviceDescription || isProcessing ? (
|
|
||||||
<ActivityIndicator />
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
label={_(msg`Next`)}
|
|
||||||
variant="solid"
|
|
||||||
color={'primary'}
|
|
||||||
size="medium"
|
|
||||||
onPress={onPressNext}
|
|
||||||
disabled={!email}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Next</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{!serviceDescription || isProcessing ? (
|
|
||||||
<Text style={[t.atoms.text_contrast_high, a.pl_md]}>
|
|
||||||
<Trans>Processing...</Trans>
|
|
||||||
</Text>
|
|
||||||
) : undefined}
|
|
||||||
</View>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
t.atoms.border_contrast_medium,
|
|
||||||
a.border_t,
|
|
||||||
a.pt_2xl,
|
|
||||||
a.mt_md,
|
|
||||||
a.flex_row,
|
|
||||||
a.justify_center,
|
|
||||||
]}>
|
|
||||||
<Button
|
|
||||||
testID="skipSendEmailButton"
|
|
||||||
onPress={onEmailSent}
|
|
||||||
label={_(msg`Go to next`)}
|
|
||||||
accessibilityHint={_(msg`Navigates to the next screen`)}
|
|
||||||
size="medium"
|
|
||||||
variant="ghost"
|
|
||||||
color="secondary">
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Already have a code?</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</FormContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,31 +1,17 @@
|
|||||||
import React, {useRef, useState} from 'react'
|
import React from 'react'
|
||||||
import {
|
import {Keyboard, View} from 'react-native'
|
||||||
ActivityIndicator,
|
|
||||||
Keyboard,
|
|
||||||
LayoutAnimation,
|
|
||||||
TextInput,
|
|
||||||
View,
|
|
||||||
} from 'react-native'
|
|
||||||
import * as Browser from 'expo-web-browser'
|
import * as Browser from 'expo-web-browser'
|
||||||
import {ComAtprotoServerDescribeServer} from '@atproto/api'
|
import {ComAtprotoServerDescribeServer} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
import {isNetworkError} from '#/lib/strings/errors'
|
import {isAndroid} from 'platform/detection'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {atoms as a} from '#/alf'
|
||||||
import {createFullHandle} from '#/lib/strings/handles'
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {useSessionApi} from '#/state/session'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
|
||||||
import {FormError} from '#/components/forms/FormError'
|
import {FormError} from '#/components/forms/FormError'
|
||||||
import {HostingProvider} from '#/components/forms/HostingProvider'
|
import {HostingProvider} from '#/components/forms/HostingProvider'
|
||||||
import * as TextField from '#/components/forms/TextField'
|
import * as TextField from '#/components/forms/TextField'
|
||||||
import {At_Stroke2_Corner0_Rounded as At} from '#/components/icons/At'
|
|
||||||
import {Lock_Stroke2_Corner0_Rounded as Lock} from '#/components/icons/Lock'
|
|
||||||
import {Loader} from '#/components/Loader'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
import {FormContainer} from './FormContainer'
|
import {FormContainer} from './FormContainer'
|
||||||
|
|
||||||
type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema
|
type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema
|
||||||
@@ -34,17 +20,14 @@ export const LoginForm = ({
|
|||||||
error,
|
error,
|
||||||
serviceUrl,
|
serviceUrl,
|
||||||
serviceDescription,
|
serviceDescription,
|
||||||
initialHandle,
|
|
||||||
setError,
|
setError,
|
||||||
setServiceUrl,
|
setServiceUrl,
|
||||||
onPressRetryConnect,
|
onPressRetryConnect,
|
||||||
onPressBack,
|
onPressBack,
|
||||||
onPressForgotPassword,
|
|
||||||
}: {
|
}: {
|
||||||
error: string
|
error: string
|
||||||
serviceUrl: string
|
serviceUrl: string
|
||||||
serviceDescription: ServiceDescription | undefined
|
serviceDescription: ServiceDescription | undefined
|
||||||
initialHandle: string
|
|
||||||
setError: (v: string) => void
|
setError: (v: string) => void
|
||||||
setServiceUrl: (v: string) => void
|
setServiceUrl: (v: string) => void
|
||||||
onPressRetryConnect: () => void
|
onPressRetryConnect: () => void
|
||||||
@@ -52,15 +35,13 @@ export const LoginForm = ({
|
|||||||
onPressForgotPassword: () => void
|
onPressForgotPassword: () => void
|
||||||
}) => {
|
}) => {
|
||||||
const {track} = useAnalytics()
|
const {track} = useAnalytics()
|
||||||
const t = useTheme()
|
|
||||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
|
||||||
const passwordInputRef = useRef<TextInput>(null)
|
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {login} = useSessionApi()
|
|
||||||
|
|
||||||
// This improves speed at which the browser presents itself on Android
|
// This improves speed at which the browser presents itself on Android
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
Browser.warmUpAsync()
|
if (isAndroid) {
|
||||||
|
Browser.warmUpAsync()
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onPressSelectService = React.useCallback(() => {
|
const onPressSelectService = React.useCallback(() => {
|
||||||
@@ -73,9 +54,7 @@ export const LoginForm = ({
|
|||||||
'https://bsky.app/login', // Replace this with the PDS auth url
|
'https://bsky.app/login', // Replace this with the PDS auth url
|
||||||
'bsky://login', // Replace this as well with the appropriate link
|
'bsky://login', // Replace this as well with the appropriate link
|
||||||
{
|
{
|
||||||
// Similar to how Google auth works. Sessions will be remembered so that we can
|
windowFeatures: {},
|
||||||
// usually proceed without needing credentials
|
|
||||||
preferEphemeralSession: true,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -86,6 +65,8 @@ export const LoginForm = ({
|
|||||||
// Handle session storage here
|
// Handle session storage here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(serviceDescription)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer testID="loginForm" title={<Trans>Sign in</Trans>}>
|
<FormContainer testID="loginForm" title={<Trans>Sign in</Trans>}>
|
||||||
<View>
|
<View>
|
||||||
@@ -115,9 +96,10 @@ export const LoginForm = ({
|
|||||||
variant="solid"
|
variant="solid"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="medium"
|
size="medium"
|
||||||
onPress={onPressBack}>
|
onPress={onPressNext}
|
||||||
|
disabled={!serviceDescription}>
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans>Login</Trans>
|
<Trans>Sign In</Trans>
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
import React, {useEffect} from 'react'
|
|
||||||
import {View} from 'react-native'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
|
||||||
import {atoms as a, useBreakpoints} from '#/alf'
|
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
import {FormContainer} from './FormContainer'
|
|
||||||
|
|
||||||
export const PasswordUpdatedForm = ({
|
|
||||||
onPressNext,
|
|
||||||
}: {
|
|
||||||
onPressNext: () => void
|
|
||||||
}) => {
|
|
||||||
const {screen} = useAnalytics()
|
|
||||||
const {_} = useLingui()
|
|
||||||
const {gtMobile} = useBreakpoints()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
screen('Signin:PasswordUpdatedForm')
|
|
||||||
}, [screen])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormContainer
|
|
||||||
testID="passwordUpdatedForm"
|
|
||||||
style={[a.gap_2xl, !gtMobile && a.mt_5xl]}>
|
|
||||||
<Text style={[a.text_3xl, a.font_bold, a.text_center]}>
|
|
||||||
<Trans>Password updated!</Trans>
|
|
||||||
</Text>
|
|
||||||
<Text style={[a.text_center, a.mx_auto, {maxWidth: '80%'}]}>
|
|
||||||
<Trans>You can now sign in with your new password.</Trans>
|
|
||||||
</Text>
|
|
||||||
<View style={[a.flex_row, a.justify_center]}>
|
|
||||||
<Button
|
|
||||||
onPress={onPressNext}
|
|
||||||
label={_(msg`Close alert`)}
|
|
||||||
accessibilityHint={_(msg`Closes password update alert`)}
|
|
||||||
variant="solid"
|
|
||||||
color="primary"
|
|
||||||
size="medium">
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Okay</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</FormContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
import React, {useEffect, useState} from 'react'
|
|
||||||
import {ActivityIndicator, View} from 'react-native'
|
|
||||||
import {BskyAgent} from '@atproto/api'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
|
||||||
import {isNetworkError} from '#/lib/strings/errors'
|
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
|
||||||
import {checkAndFormatResetCode} from '#/lib/strings/password'
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
|
||||||
import {FormError} from '#/components/forms/FormError'
|
|
||||||
import * as TextField from '#/components/forms/TextField'
|
|
||||||
import {Lock_Stroke2_Corner0_Rounded as Lock} from '#/components/icons/Lock'
|
|
||||||
import {Ticket_Stroke2_Corner0_Rounded as Ticket} from '#/components/icons/Ticket'
|
|
||||||
import {Text} from '#/components/Typography'
|
|
||||||
import {FormContainer} from './FormContainer'
|
|
||||||
|
|
||||||
export const SetNewPasswordForm = ({
|
|
||||||
error,
|
|
||||||
serviceUrl,
|
|
||||||
setError,
|
|
||||||
onPressBack,
|
|
||||||
onPasswordSet,
|
|
||||||
}: {
|
|
||||||
error: string
|
|
||||||
serviceUrl: string
|
|
||||||
setError: (v: string) => void
|
|
||||||
onPressBack: () => void
|
|
||||||
onPasswordSet: () => void
|
|
||||||
}) => {
|
|
||||||
const {screen} = useAnalytics()
|
|
||||||
const {_} = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
screen('Signin:SetNewPasswordForm')
|
|
||||||
}, [screen])
|
|
||||||
|
|
||||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
|
||||||
const [resetCode, setResetCode] = useState<string>('')
|
|
||||||
const [password, setPassword] = useState<string>('')
|
|
||||||
|
|
||||||
const onPressNext = async () => {
|
|
||||||
// Check that the code is correct. We do this again just incase the user enters the code after their pw and we
|
|
||||||
// don't get to call onBlur first
|
|
||||||
const formattedCode = checkAndFormatResetCode(resetCode)
|
|
||||||
// TODO Better password strength check
|
|
||||||
if (!formattedCode || !password) {
|
|
||||||
setError(
|
|
||||||
_(
|
|
||||||
msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setError('')
|
|
||||||
setIsProcessing(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const agent = new BskyAgent({service: serviceUrl})
|
|
||||||
await agent.com.atproto.server.resetPassword({
|
|
||||||
token: formattedCode,
|
|
||||||
password,
|
|
||||||
})
|
|
||||||
onPasswordSet()
|
|
||||||
} catch (e: any) {
|
|
||||||
const errMsg = e.toString()
|
|
||||||
logger.warn('Failed to set new password', {error: e})
|
|
||||||
setIsProcessing(false)
|
|
||||||
if (isNetworkError(e)) {
|
|
||||||
setError(
|
|
||||||
_(
|
|
||||||
msg`Unable to contact your service. Please check your Internet connection.`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
setError(cleanError(errMsg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onBlur = () => {
|
|
||||||
const formattedCode = checkAndFormatResetCode(resetCode)
|
|
||||||
if (!formattedCode) {
|
|
||||||
setError(
|
|
||||||
_(
|
|
||||||
msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setResetCode(formattedCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormContainer
|
|
||||||
testID="setNewPasswordForm"
|
|
||||||
title={<Trans>Set new password</Trans>}>
|
|
||||||
<Text style={[a.leading_snug, a.mb_sm]}>
|
|
||||||
<Trans>
|
|
||||||
You will receive an email with a "reset code." Enter that code here,
|
|
||||||
then enter your new password.
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<View>
|
|
||||||
<TextField.Label>Reset code</TextField.Label>
|
|
||||||
<TextField.Root>
|
|
||||||
<TextField.Icon icon={Ticket} />
|
|
||||||
<TextField.Input
|
|
||||||
testID="resetCodeInput"
|
|
||||||
label={_(msg`Looks like XXXXX-XXXXX`)}
|
|
||||||
autoCapitalize="none"
|
|
||||||
autoFocus={true}
|
|
||||||
autoCorrect={false}
|
|
||||||
autoComplete="off"
|
|
||||||
value={resetCode}
|
|
||||||
onChangeText={setResetCode}
|
|
||||||
onFocus={() => setError('')}
|
|
||||||
onBlur={onBlur}
|
|
||||||
editable={!isProcessing}
|
|
||||||
accessibilityHint={_(
|
|
||||||
msg`Input code sent to your email for password reset`,
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</TextField.Root>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View>
|
|
||||||
<TextField.Label>New password</TextField.Label>
|
|
||||||
<TextField.Root>
|
|
||||||
<TextField.Icon icon={Lock} />
|
|
||||||
<TextField.Input
|
|
||||||
testID="newPasswordInput"
|
|
||||||
label={_(msg`Enter a password`)}
|
|
||||||
autoCapitalize="none"
|
|
||||||
autoCorrect={false}
|
|
||||||
autoComplete="password"
|
|
||||||
returnKeyType="done"
|
|
||||||
secureTextEntry={true}
|
|
||||||
textContentType="password"
|
|
||||||
clearButtonMode="while-editing"
|
|
||||||
value={password}
|
|
||||||
onChangeText={setPassword}
|
|
||||||
onSubmitEditing={onPressNext}
|
|
||||||
editable={!isProcessing}
|
|
||||||
accessibilityHint={_(msg`Input new password`)}
|
|
||||||
/>
|
|
||||||
</TextField.Root>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<FormError error={error} />
|
|
||||||
|
|
||||||
<View style={[a.flex_row, a.align_center, a.pt_lg]}>
|
|
||||||
<Button
|
|
||||||
label={_(msg`Back`)}
|
|
||||||
variant="solid"
|
|
||||||
color="secondary"
|
|
||||||
size="medium"
|
|
||||||
onPress={onPressBack}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Back</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
<View style={a.flex_1} />
|
|
||||||
{isProcessing ? (
|
|
||||||
<ActivityIndicator />
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
label={_(msg`Next`)}
|
|
||||||
variant="solid"
|
|
||||||
color="primary"
|
|
||||||
size="medium"
|
|
||||||
onPress={onPressNext}>
|
|
||||||
<ButtonText>
|
|
||||||
<Trans>Next</Trans>
|
|
||||||
</ButtonText>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{isProcessing ? (
|
|
||||||
<Text style={[t.atoms.text_contrast_high, a.pl_md]}>
|
|
||||||
<Trans>Updating...</Trans>
|
|
||||||
</Text>
|
|
||||||
) : undefined}
|
|
||||||
</View>
|
|
||||||
</FormContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -4,17 +4,13 @@ import {LayoutAnimationConfig} from 'react-native-reanimated'
|
|||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
|
||||||
import {DEFAULT_SERVICE} from '#/lib/constants'
|
import {DEFAULT_SERVICE} from '#/lib/constants'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useServiceQuery} from '#/state/queries/service'
|
import {useServiceQuery} from '#/state/queries/service'
|
||||||
import {SessionAccount, useSession} from '#/state/session'
|
import {SessionAccount, useSession} from '#/state/session'
|
||||||
import {useLoggedOutView} from '#/state/shell/logged-out'
|
import {useLoggedOutView} from '#/state/shell/logged-out'
|
||||||
import {LoggedOutLayout} from '#/view/com/util/layouts/LoggedOutLayout'
|
import {LoggedOutLayout} from '#/view/com/util/layouts/LoggedOutLayout'
|
||||||
import {ForgotPasswordForm} from '#/screens/Login/ForgotPasswordForm'
|
|
||||||
import {LoginForm} from '#/screens/Login/LoginForm'
|
import {LoginForm} from '#/screens/Login/LoginForm'
|
||||||
import {PasswordUpdatedForm} from '#/screens/Login/PasswordUpdatedForm'
|
|
||||||
import {SetNewPasswordForm} from '#/screens/Login/SetNewPasswordForm'
|
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {ChooseAccountForm} from './ChooseAccountForm'
|
import {ChooseAccountForm} from './ChooseAccountForm'
|
||||||
import {ScreenTransition} from './ScreenTransition'
|
import {ScreenTransition} from './ScreenTransition'
|
||||||
@@ -22,16 +18,12 @@ import {ScreenTransition} from './ScreenTransition'
|
|||||||
enum Forms {
|
enum Forms {
|
||||||
Login,
|
Login,
|
||||||
ChooseAccount,
|
ChooseAccount,
|
||||||
ForgotPassword,
|
|
||||||
SetNewPassword,
|
|
||||||
PasswordUpdated,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|
||||||
const {accounts} = useSession()
|
const {accounts} = useSession()
|
||||||
const {track} = useAnalytics()
|
|
||||||
const {requestedAccountSwitchTo} = useLoggedOutView()
|
const {requestedAccountSwitchTo} = useLoggedOutView()
|
||||||
const requestedAccount = accounts.find(
|
const requestedAccount = accounts.find(
|
||||||
acc => acc.did === requestedAccountSwitchTo,
|
acc => acc.did === requestedAccountSwitchTo,
|
||||||
@@ -41,9 +33,6 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
|||||||
const [serviceUrl, setServiceUrl] = React.useState<string>(
|
const [serviceUrl, setServiceUrl] = React.useState<string>(
|
||||||
requestedAccount?.service || DEFAULT_SERVICE,
|
requestedAccount?.service || DEFAULT_SERVICE,
|
||||||
)
|
)
|
||||||
const [initialHandle, setInitialHandle] = React.useState<string>(
|
|
||||||
requestedAccount?.handle || '',
|
|
||||||
)
|
|
||||||
const [currentForm, setCurrentForm] = React.useState<Forms>(
|
const [currentForm, setCurrentForm] = React.useState<Forms>(
|
||||||
requestedAccount
|
requestedAccount
|
||||||
? Forms.Login
|
? Forms.Login
|
||||||
@@ -62,7 +51,7 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
|||||||
if (account?.service) {
|
if (account?.service) {
|
||||||
setServiceUrl(account.service)
|
setServiceUrl(account.service)
|
||||||
}
|
}
|
||||||
setInitialHandle(account?.handle || '')
|
// TODO set the service URL. We really need to fix this though in general
|
||||||
setCurrentForm(Forms.Login)
|
setCurrentForm(Forms.Login)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,11 +75,6 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
|||||||
}
|
}
|
||||||
}, [serviceError, serviceUrl, _])
|
}, [serviceError, serviceUrl, _])
|
||||||
|
|
||||||
const onPressForgotPassword = () => {
|
|
||||||
track('Signin:PressedForgotPassword')
|
|
||||||
setCurrentForm(Forms.ForgotPassword)
|
|
||||||
}
|
|
||||||
|
|
||||||
let content = null
|
let content = null
|
||||||
let title = ''
|
let title = ''
|
||||||
let description = ''
|
let description = ''
|
||||||
@@ -104,13 +88,11 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
|||||||
error={error}
|
error={error}
|
||||||
serviceUrl={serviceUrl}
|
serviceUrl={serviceUrl}
|
||||||
serviceDescription={serviceDescription}
|
serviceDescription={serviceDescription}
|
||||||
initialHandle={initialHandle}
|
|
||||||
setError={setError}
|
setError={setError}
|
||||||
setServiceUrl={setServiceUrl}
|
setServiceUrl={setServiceUrl}
|
||||||
onPressBack={() =>
|
onPressBack={() =>
|
||||||
accounts.length ? gotoForm(Forms.ChooseAccount) : onPressBack()
|
accounts.length ? gotoForm(Forms.ChooseAccount) : onPressBack()
|
||||||
}
|
}
|
||||||
onPressForgotPassword={onPressForgotPassword}
|
|
||||||
onPressRetryConnect={refetchService}
|
onPressRetryConnect={refetchService}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -125,41 +107,6 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case Forms.ForgotPassword:
|
|
||||||
title = _(msg`Forgot Password`)
|
|
||||||
description = _(msg`Let's get your password reset!`)
|
|
||||||
content = (
|
|
||||||
<ForgotPasswordForm
|
|
||||||
error={error}
|
|
||||||
serviceUrl={serviceUrl}
|
|
||||||
serviceDescription={serviceDescription}
|
|
||||||
setError={setError}
|
|
||||||
setServiceUrl={setServiceUrl}
|
|
||||||
onPressBack={() => gotoForm(Forms.Login)}
|
|
||||||
onEmailSent={() => gotoForm(Forms.SetNewPassword)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
break
|
|
||||||
case Forms.SetNewPassword:
|
|
||||||
title = _(msg`Forgot Password`)
|
|
||||||
description = _(msg`Let's get your password reset!`)
|
|
||||||
content = (
|
|
||||||
<SetNewPasswordForm
|
|
||||||
error={error}
|
|
||||||
serviceUrl={serviceUrl}
|
|
||||||
setError={setError}
|
|
||||||
onPressBack={() => gotoForm(Forms.ForgotPassword)}
|
|
||||||
onPasswordSet={() => gotoForm(Forms.PasswordUpdated)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
break
|
|
||||||
case Forms.PasswordUpdated:
|
|
||||||
title = _(msg`Password updated`)
|
|
||||||
description = _(msg`You can now sign in with your new password.`)
|
|
||||||
content = (
|
|
||||||
<PasswordUpdatedForm onPressNext={() => gotoForm(Forms.Login)} />
|
|
||||||
)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user