alf the login form
parent
f5b39f2755
commit
9f5289a101
|
@ -14,6 +14,7 @@ import {useTheme, atoms as a, web, android} from '#/alf'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||||
import {Props as SVGIconProps} from '#/components/icons/common'
|
import {Props as SVGIconProps} from '#/components/icons/common'
|
||||||
|
import {mergeRefs} from '#/lib/merge-refs'
|
||||||
|
|
||||||
const Context = React.createContext<{
|
const Context = React.createContext<{
|
||||||
inputRef: React.RefObject<TextInput> | null
|
inputRef: React.RefObject<TextInput> | null
|
||||||
|
@ -128,6 +129,7 @@ export type InputProps = Omit<TextInputProps, 'value' | 'onChangeText'> & {
|
||||||
value: string
|
value: string
|
||||||
onChangeText: (value: string) => void
|
onChangeText: (value: string) => void
|
||||||
isInvalid?: boolean
|
isInvalid?: boolean
|
||||||
|
inputRef?: React.RefObject<TextInput>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createInput(Component: typeof TextInput) {
|
export function createInput(Component: typeof TextInput) {
|
||||||
|
@ -137,6 +139,7 @@ export function createInput(Component: typeof TextInput) {
|
||||||
value,
|
value,
|
||||||
onChangeText,
|
onChangeText,
|
||||||
isInvalid,
|
isInvalid,
|
||||||
|
inputRef,
|
||||||
...rest
|
...rest
|
||||||
}: InputProps) {
|
}: InputProps) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
@ -161,19 +164,22 @@ export function createInput(Component: typeof TextInput) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refs = mergeRefs([ctx.inputRef, inputRef!].filter(Boolean))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Component
|
<Component
|
||||||
accessibilityHint={undefined}
|
accessibilityHint={undefined}
|
||||||
{...rest}
|
{...rest}
|
||||||
accessibilityLabel={label}
|
accessibilityLabel={label}
|
||||||
ref={ctx.inputRef}
|
ref={refs}
|
||||||
value={value}
|
value={value}
|
||||||
onChangeText={onChangeText}
|
onChangeText={onChangeText}
|
||||||
onFocus={ctx.onFocus}
|
onFocus={ctx.onFocus}
|
||||||
onBlur={ctx.onBlur}
|
onBlur={ctx.onBlur}
|
||||||
placeholder={placeholder || label}
|
placeholder={placeholder || label}
|
||||||
placeholderTextColor={t.palette.contrast_500}
|
placeholderTextColor={t.palette.contrast_500}
|
||||||
|
keyboardAppearance={t.name === 'light' ? 'light' : 'dark'}
|
||||||
hitSlop={HITSLOP_20}
|
hitSlop={HITSLOP_20}
|
||||||
style={[
|
style={[
|
||||||
a.relative,
|
a.relative,
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import {createSinglePathSVG} from './TEMPLATE'
|
||||||
|
|
||||||
|
export const Lock_Stroke2_Corner0_Rounded = createSinglePathSVG({
|
||||||
|
path: 'M7 7a5 5 0 0 1 10 0v2h1a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2h1V7Zm-1 4v9h12v-9H6Zm9-2H9V7a3 3 0 1 1 6 0v2Zm-3 4a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0v-3a1 1 0 0 1 1-1Z',
|
||||||
|
})
|
|
@ -0,0 +1,5 @@
|
||||||
|
import {createSinglePathSVG} from './TEMPLATE'
|
||||||
|
|
||||||
|
export const Pencil_Stroke2_Corner0_Rounded = createSinglePathSVG({
|
||||||
|
path: 'M13.586 1.5a2 2 0 0 1 2.828 0L19.5 4.586a2 2 0 0 1 0 2.828l-13 13A2 2 0 0 1 5.086 21H1a1 1 0 0 1-1-1v-4.086A2 2 0 0 1 .586 14.5l13-13ZM15 2.914l-13 13V19h3.086l13-13L15 2.914ZM11 20a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Z',
|
||||||
|
})
|
|
@ -13,7 +13,7 @@ import {useProfileQuery} from '#/state/queries/profile'
|
||||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {Button} from '#/components/Button'
|
import {Button} from '#/components/Button'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {ChevronRight_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron'
|
import {ChevronRight_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron'
|
||||||
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||||
|
@ -106,6 +106,7 @@ export const ChooseAccountForm = ({
|
||||||
const {accounts, currentAccount} = useSession()
|
const {accounts, currentAccount} = useSession()
|
||||||
const {initSession} = useSessionApi()
|
const {initSession} = useSessionApi()
|
||||||
const {setShowLoggedOut} = useLoggedOutViewControls()
|
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||||
|
const {gtMobile} = useBreakpoints()
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
screen('Choose Account')
|
screen('Choose Account')
|
||||||
|
@ -133,50 +134,54 @@ export const ChooseAccountForm = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView testID="chooseAccountForm" style={styles.maxHeight}>
|
<ScrollView testID="chooseAccountForm" style={styles.maxHeight}>
|
||||||
<Text style={[a.mt_md, a.mb_lg, a.font_bold]}>
|
<View style={!gtMobile && a.px_lg}>
|
||||||
<Trans>Sign in as...</Trans>
|
<Text
|
||||||
</Text>
|
style={[a.mt_md, a.mb_lg, a.font_bold, t.atoms.text_contrast_medium]}>
|
||||||
<Group>
|
<Trans>Sign in as...</Trans>
|
||||||
{accounts.map(account => (
|
</Text>
|
||||||
<AccountItem
|
<Group>
|
||||||
key={account.did}
|
{accounts.map(account => (
|
||||||
account={account}
|
<AccountItem
|
||||||
onSelect={onSelect}
|
key={account.did}
|
||||||
isCurrentAccount={account.did === currentAccount?.did}
|
account={account}
|
||||||
/>
|
onSelect={onSelect}
|
||||||
))}
|
isCurrentAccount={account.did === currentAccount?.did}
|
||||||
<TouchableOpacity
|
/>
|
||||||
testID="chooseNewAccountBtn"
|
))}
|
||||||
style={[a.flex_1]}
|
<TouchableOpacity
|
||||||
onPress={() => onSelectAccount(undefined)}
|
testID="chooseNewAccountBtn"
|
||||||
accessibilityRole="button"
|
style={[a.flex_1]}
|
||||||
accessibilityLabel={_(msg`Login to account that is not listed`)}
|
onPress={() => onSelectAccount(undefined)}
|
||||||
accessibilityHint="">
|
accessibilityRole="button"
|
||||||
<View style={[a.flex_row, a.flex_row, a.align_center, {height: 48}]}>
|
accessibilityLabel={_(msg`Login to account that is not listed`)}
|
||||||
<Text
|
accessibilityHint="">
|
||||||
style={[
|
<View
|
||||||
a.align_baseline,
|
style={[a.flex_row, a.flex_row, a.align_center, {height: 48}]}>
|
||||||
a.flex_1,
|
<Text
|
||||||
a.flex_row,
|
style={[
|
||||||
a.py_sm,
|
a.align_baseline,
|
||||||
{paddingLeft: 48},
|
a.flex_1,
|
||||||
]}>
|
a.flex_row,
|
||||||
<Trans>Other account</Trans>
|
a.py_sm,
|
||||||
</Text>
|
{paddingLeft: 48},
|
||||||
<Chevron size="sm" style={[t.atoms.text, a.mr_md]} />
|
]}>
|
||||||
</View>
|
<Trans>Other account</Trans>
|
||||||
</TouchableOpacity>
|
</Text>
|
||||||
</Group>
|
<Chevron size="sm" style={[t.atoms.text, a.mr_md]} />
|
||||||
<View style={[a.flex_row, a.mt_lg]}>
|
</View>
|
||||||
<Button
|
</TouchableOpacity>
|
||||||
label={_(msg`Back`)}
|
</Group>
|
||||||
variant="solid"
|
<View style={[a.flex_row, a.mt_lg]}>
|
||||||
color="secondary"
|
<Button
|
||||||
size="small"
|
label={_(msg`Back`)}
|
||||||
onPress={onPressBack}>
|
variant="solid"
|
||||||
<Trans>Back</Trans>
|
color="secondary"
|
||||||
</Button>
|
size="small"
|
||||||
<View style={[a.flex_1]} />
|
onPress={onPressBack}>
|
||||||
|
{_(msg`Back`)}
|
||||||
|
</Button>
|
||||||
|
<View style={[a.flex_1]} />
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,28 +6,31 @@ import {
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {
|
|
||||||
FontAwesomeIcon,
|
|
||||||
FontAwesomeIconStyle,
|
|
||||||
} from '@fortawesome/react-native-fontawesome'
|
|
||||||
import {ComAtprotoServerDescribeServer} from '@atproto/api'
|
import {ComAtprotoServerDescribeServer} from '@atproto/api'
|
||||||
|
import {Trans, msg} from '@lingui/macro'
|
||||||
|
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
import {Text} from '../../util/text/Text'
|
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
import {createFullHandle} from 'lib/strings/handles'
|
import {createFullHandle} from 'lib/strings/handles'
|
||||||
import {toNiceDomain} from 'lib/strings/url-helpers'
|
import {toNiceDomain} from 'lib/strings/url-helpers'
|
||||||
import {isNetworkError} from 'lib/strings/errors'
|
import {isNetworkError} from 'lib/strings/errors'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
|
||||||
import {useSessionApi} from '#/state/session'
|
import {useSessionApi} from '#/state/session'
|
||||||
import {cleanError} from 'lib/strings/errors'
|
import {cleanError} from 'lib/strings/errors'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {Trans, msg} from '@lingui/macro'
|
import {styles} from '../../view/com/auth/login/styles'
|
||||||
import {styles} from './styles'
|
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useDialogControl} from '#/components/Dialog'
|
import {useDialogControl} from '#/components/Dialog'
|
||||||
|
import {ServerInputDialog} from '../../view/com/auth/server-input'
|
||||||
import {ServerInputDialog} from '../server-input'
|
import {Button} from '#/components/Button'
|
||||||
|
import {isAndroid} from '#/platform/detection'
|
||||||
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
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 {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
||||||
|
import {Pencil_Stroke2_Corner0_Rounded as Pencil} from '#/components/icons/Pencil'
|
||||||
|
import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning'
|
||||||
|
|
||||||
type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema
|
type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema
|
||||||
|
|
||||||
|
@ -40,7 +43,6 @@ export const LoginForm = ({
|
||||||
setServiceUrl,
|
setServiceUrl,
|
||||||
onPressRetryConnect,
|
onPressRetryConnect,
|
||||||
onPressBack,
|
onPressBack,
|
||||||
onPressForgotPassword,
|
|
||||||
}: {
|
}: {
|
||||||
error: string
|
error: string
|
||||||
serviceUrl: string
|
serviceUrl: string
|
||||||
|
@ -53,8 +55,7 @@ export const LoginForm = ({
|
||||||
onPressForgotPassword: () => void
|
onPressForgotPassword: () => void
|
||||||
}) => {
|
}) => {
|
||||||
const {track} = useAnalytics()
|
const {track} = useAnalytics()
|
||||||
const pal = usePalette('default')
|
const t = useTheme()
|
||||||
const theme = useTheme()
|
|
||||||
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
const [isProcessing, setIsProcessing] = useState<boolean>(false)
|
||||||
const [identifier, setIdentifier] = useState<string>(initialHandle)
|
const [identifier, setIdentifier] = useState<string>(initialHandle)
|
||||||
const [password, setPassword] = useState<string>('')
|
const [password, setPassword] = useState<string>('')
|
||||||
|
@ -62,6 +63,7 @@ export const LoginForm = ({
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {login} = useSessionApi()
|
const {login} = useSessionApi()
|
||||||
const serverInputControl = useDialogControl()
|
const serverInputControl = useDialogControl()
|
||||||
|
const {gtMobile} = useBreakpoints()
|
||||||
|
|
||||||
const onPressSelectService = () => {
|
const onPressSelectService = () => {
|
||||||
serverInputControl.open()
|
serverInputControl.open()
|
||||||
|
@ -127,55 +129,54 @@ export const LoginForm = ({
|
||||||
|
|
||||||
const isReady = !!serviceDescription && !!identifier && !!password
|
const isReady = !!serviceDescription && !!identifier && !!password
|
||||||
return (
|
return (
|
||||||
<View testID="loginForm">
|
<View testID="loginForm" style={[a.gap_lg, !gtMobile && a.px_lg]}>
|
||||||
<ServerInputDialog
|
<ServerInputDialog
|
||||||
control={serverInputControl}
|
control={serverInputControl}
|
||||||
onSelect={setServiceUrl}
|
onSelect={setServiceUrl}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Text type="sm-bold" style={[pal.text, styles.groupLabel]}>
|
<View>
|
||||||
<Trans>Sign into</Trans>
|
<TextField.Label>
|
||||||
</Text>
|
<Trans>Hosting provider</Trans>
|
||||||
<View style={[pal.borderDark, styles.group]}>
|
</TextField.Label>
|
||||||
<View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}>
|
<TouchableOpacity
|
||||||
<FontAwesomeIcon
|
accessibilityRole="button"
|
||||||
icon="globe"
|
style={[
|
||||||
style={[pal.textLight, styles.groupContentIcon]}
|
a.w_full,
|
||||||
/>
|
a.flex_row,
|
||||||
<TouchableOpacity
|
a.align_center,
|
||||||
testID="loginSelectServiceButton"
|
a.rounded_sm,
|
||||||
style={styles.textBtn}
|
a.px_md,
|
||||||
onPress={onPressSelectService}
|
a.gap_xs,
|
||||||
accessibilityRole="button"
|
{paddingVertical: isAndroid ? 14 : 9},
|
||||||
accessibilityLabel={_(msg`Select service`)}
|
t.atoms.bg_contrast_25,
|
||||||
accessibilityHint={_(msg`Sets server for the Bluesky client`)}>
|
]}
|
||||||
<Text type="xl" style={[pal.text, styles.textBtnLabel]}>
|
onPress={onPressSelectService}>
|
||||||
{toNiceDomain(serviceUrl)}
|
<TextField.Icon icon={Globe} />
|
||||||
</Text>
|
<Text style={[a.text_md]}>{toNiceDomain(serviceUrl)}</Text>
|
||||||
<View style={[pal.btn, styles.textBtnFakeInnerBtn]}>
|
<View
|
||||||
<FontAwesomeIcon
|
style={[
|
||||||
icon="pen"
|
a.rounded_sm,
|
||||||
size={12}
|
t.atoms.bg_contrast_100,
|
||||||
style={pal.textLight as FontAwesomeIconStyle}
|
{marginLeft: 'auto', left: 6, padding: 6},
|
||||||
/>
|
]}>
|
||||||
</View>
|
<Pencil
|
||||||
</TouchableOpacity>
|
style={{color: t.palette.contrast_500}}
|
||||||
</View>
|
height={18}
|
||||||
|
width={18}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<Text type="sm-bold" style={[pal.text, styles.groupLabel]}>
|
<View>
|
||||||
<Trans>Account</Trans>
|
<TextField.Label>
|
||||||
</Text>
|
<Trans>Account</Trans>
|
||||||
<View style={[pal.borderDark, styles.group]}>
|
</TextField.Label>
|
||||||
<View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}>
|
<TextField.Root>
|
||||||
<FontAwesomeIcon
|
<TextField.Icon icon={At} />
|
||||||
icon="at"
|
<TextField.Input
|
||||||
style={[pal.textLight, styles.groupContentIcon]}
|
|
||||||
/>
|
|
||||||
<TextInput
|
|
||||||
testID="loginUsernameInput"
|
testID="loginUsernameInput"
|
||||||
style={[pal.text, styles.textInput]}
|
label={_(msg`Username or email address`)}
|
||||||
placeholder={_(msg`Username or email address`)}
|
|
||||||
placeholderTextColor={pal.colors.textLight}
|
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoFocus
|
autoFocus
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
|
@ -186,35 +187,29 @@ export const LoginForm = ({
|
||||||
passwordInputRef.current?.focus()
|
passwordInputRef.current?.focus()
|
||||||
}}
|
}}
|
||||||
blurOnSubmit={false} // prevents flickering due to onSubmitEditing going to next field
|
blurOnSubmit={false} // prevents flickering due to onSubmitEditing going to next field
|
||||||
keyboardAppearance={theme.colorScheme}
|
|
||||||
value={identifier}
|
value={identifier}
|
||||||
onChangeText={str =>
|
onChangeText={str =>
|
||||||
setIdentifier((str || '').toLowerCase().trim())
|
setIdentifier((str || '').toLowerCase().trim())
|
||||||
}
|
}
|
||||||
editable={!isProcessing}
|
editable={!isProcessing}
|
||||||
accessibilityLabel={_(msg`Username or email address`)}
|
|
||||||
accessibilityHint={_(
|
accessibilityHint={_(
|
||||||
msg`Input the username or email address you used at signup`,
|
msg`Input the username or email address you used at signup`,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</TextField.Root>
|
||||||
<View style={[pal.borderDark, styles.groupContent]}>
|
</View>
|
||||||
<FontAwesomeIcon
|
<View>
|
||||||
icon="lock"
|
<TextField.Root>
|
||||||
style={[pal.textLight, styles.groupContentIcon]}
|
<TextField.Icon icon={Lock} />
|
||||||
/>
|
<TextField.Input
|
||||||
<TextInput
|
|
||||||
testID="loginPasswordInput"
|
testID="loginPasswordInput"
|
||||||
ref={passwordInputRef}
|
inputRef={passwordInputRef}
|
||||||
style={[pal.text, styles.textInput]}
|
label={_(msg`Password`)}
|
||||||
placeholder="Password"
|
|
||||||
placeholderTextColor={pal.colors.textLight}
|
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
autoComplete="password"
|
autoComplete="password"
|
||||||
returnKeyType="done"
|
returnKeyType="done"
|
||||||
enablesReturnKeyAutomatically={true}
|
enablesReturnKeyAutomatically={true}
|
||||||
keyboardAppearance={theme.colorScheme}
|
|
||||||
secureTextEntry={true}
|
secureTextEntry={true}
|
||||||
textContentType="password"
|
textContentType="password"
|
||||||
clearButtonMode="while-editing"
|
clearButtonMode="while-editing"
|
||||||
|
@ -223,14 +218,13 @@ export const LoginForm = ({
|
||||||
onSubmitEditing={onPressNext}
|
onSubmitEditing={onPressNext}
|
||||||
blurOnSubmit={false} // HACK: https://github.com/facebook/react-native/issues/21911#issuecomment-558343069 Keyboard blur behavior is now handled in onSubmitEditing
|
blurOnSubmit={false} // HACK: https://github.com/facebook/react-native/issues/21911#issuecomment-558343069 Keyboard blur behavior is now handled in onSubmitEditing
|
||||||
editable={!isProcessing}
|
editable={!isProcessing}
|
||||||
accessibilityLabel={_(msg`Password`)}
|
|
||||||
accessibilityHint={
|
accessibilityHint={
|
||||||
identifier === ''
|
identifier === ''
|
||||||
? _(msg`Input your password`)
|
? _(msg`Input your password`)
|
||||||
: _(msg`Input the password tied to ${identifier}`)
|
: _(msg`Input the password tied to ${identifier}`)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity
|
{/* <TouchableOpacity
|
||||||
testID="forgotPasswordButton"
|
testID="forgotPasswordButton"
|
||||||
style={styles.textInputInnerBtn}
|
style={styles.textInputInnerBtn}
|
||||||
onPress={onPressForgotPassword}
|
onPress={onPressForgotPassword}
|
||||||
|
@ -240,57 +234,57 @@ export const LoginForm = ({
|
||||||
<Text style={pal.link}>
|
<Text style={pal.link}>
|
||||||
<Trans>Forgot</Trans>
|
<Trans>Forgot</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity> */}
|
||||||
</View>
|
</TextField.Root>
|
||||||
</View>
|
</View>
|
||||||
{error ? (
|
{error ? (
|
||||||
<View style={styles.error}>
|
<View style={[styles.error, {marginHorizontal: 0}]}>
|
||||||
<View style={styles.errorIcon}>
|
<Warning style={s.white} size="sm" />
|
||||||
<FontAwesomeIcon icon="exclamation" style={s.white} size={10} />
|
<View style={(a.flex_1, a.ml_sm)}>
|
||||||
</View>
|
|
||||||
<View style={s.flex1}>
|
|
||||||
<Text style={[s.white, s.bold]}>{error}</Text>
|
<Text style={[s.white, s.bold]}>{error}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<View style={[s.flexRow, s.alignCenter, s.pl20, s.pr20]}>
|
<View style={[a.flex_row, a.align_center]}>
|
||||||
<TouchableOpacity onPress={onPressBack} accessibilityRole="button">
|
<Button
|
||||||
<Text type="xl" style={[pal.link, s.pl5]}>
|
label={_(msg`Back`)}
|
||||||
<Trans>Back</Trans>
|
variant="solid"
|
||||||
</Text>
|
color="secondary"
|
||||||
</TouchableOpacity>
|
size="small"
|
||||||
|
onPress={onPressBack}>
|
||||||
|
{_(msg`Back`)}
|
||||||
|
</Button>
|
||||||
<View style={s.flex1} />
|
<View style={s.flex1} />
|
||||||
{!serviceDescription && error ? (
|
{!serviceDescription && error ? (
|
||||||
<TouchableOpacity
|
<Button
|
||||||
testID="loginRetryButton"
|
testID="loginRetryButton"
|
||||||
onPress={onPressRetryConnect}
|
label={_(msg`Retry`)}
|
||||||
accessibilityRole="button"
|
accessibilityHint={_(msg`Retries login`)}
|
||||||
accessibilityLabel={_(msg`Retry`)}
|
variant="solid"
|
||||||
accessibilityHint={_(msg`Retries login`)}>
|
color="secondary"
|
||||||
<Text type="xl-bold" style={[pal.link, s.pr5]}>
|
size="small"
|
||||||
<Trans>Retry</Trans>
|
onPress={onPressRetryConnect}>
|
||||||
</Text>
|
{_(msg`Retry`)}
|
||||||
</TouchableOpacity>
|
</Button>
|
||||||
) : !serviceDescription ? (
|
) : !serviceDescription ? (
|
||||||
<>
|
<>
|
||||||
<ActivityIndicator />
|
<ActivityIndicator />
|
||||||
<Text type="xl" style={[pal.textLight, s.pl10]}>
|
<Text style={[t.atoms.text_contrast_high, a.pl_md]}>
|
||||||
<Trans>Connecting...</Trans>
|
<Trans>Connecting...</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
) : isProcessing ? (
|
) : isProcessing ? (
|
||||||
<ActivityIndicator />
|
<ActivityIndicator />
|
||||||
) : isReady ? (
|
) : isReady ? (
|
||||||
<TouchableOpacity
|
<Button
|
||||||
testID="loginNextButton"
|
label={_(msg`Next`)}
|
||||||
onPress={onPressNext}
|
accessibilityHint={_(msg`Navigates to the next screen`)}
|
||||||
accessibilityRole="button"
|
variant="solid"
|
||||||
accessibilityLabel={_(msg`Go to next`)}
|
color="primary"
|
||||||
accessibilityHint={_(msg`Navigates to the next screen`)}>
|
size="small"
|
||||||
<Text type="xl-bold" style={[pal.link, s.pr5]}>
|
onPress={onPressNext}>
|
||||||
<Trans>Next</Trans>
|
{_(msg`Next`)}
|
||||||
</Text>
|
</Button>
|
||||||
</TouchableOpacity>
|
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import {KeyboardAvoidingView} from 'react-native'
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {LoggedOutLayout} from '#/view/com/util/layouts/LoggedOutLayout'
|
import {LoggedOutLayout} from '#/view/com/util/layouts/LoggedOutLayout'
|
||||||
|
@ -9,12 +10,11 @@ import {useServiceQuery} from '#/state/queries/service'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {KeyboardAvoidingView} from 'react-native'
|
|
||||||
import {ChooseAccountForm} from './ChooseAccountForm'
|
import {ChooseAccountForm} from './ChooseAccountForm'
|
||||||
import {ForgotPasswordForm} from '#/view/com/auth/login/ForgotPasswordForm'
|
import {ForgotPasswordForm} from '#/view/com/auth/login/ForgotPasswordForm'
|
||||||
import {SetNewPasswordForm} from '#/view/com/auth/login/SetNewPasswordForm'
|
import {SetNewPasswordForm} from '#/view/com/auth/login/SetNewPasswordForm'
|
||||||
import {PasswordUpdatedForm} from '#/view/com/auth/login/PasswordUpdatedForm'
|
import {PasswordUpdatedForm} from '#/view/com/auth/login/PasswordUpdatedForm'
|
||||||
import {LoginForm} from '#/view/com/auth/login/LoginForm'
|
import {LoginForm} from '#/screens/Login/LoginForm'
|
||||||
|
|
||||||
enum Forms {
|
enum Forms {
|
||||||
Login,
|
Login,
|
||||||
|
|
|
@ -67,7 +67,7 @@ export function ServerInputDialog({
|
||||||
return (
|
return (
|
||||||
<Dialog.Outer
|
<Dialog.Outer
|
||||||
control={control}
|
control={control}
|
||||||
nativeOptions={{sheet: {snapPoints: ['100%']}}}
|
nativeOptions={{sheet: {snapPoints: ['80', '100%']}}}
|
||||||
onClose={onClose}>
|
onClose={onClose}>
|
||||||
<Dialog.Handle />
|
<Dialog.Handle />
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue