new approach, new design
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 309 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
@@ -2,11 +2,15 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'ForgotPassword'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'ForgotPassword'>
|
||||||
export function ForgotPasswordScreen({}: Props) {
|
export function ForgotPasswordScreen({}: Props) {
|
||||||
|
return <ForgotPasswordScreenInner />
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ForgotPasswordScreenInner() {
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="ForgotPasswordScreen">
|
<Layout.Screen testID="ForgotPasswordScreen">
|
||||||
<Layout.Header.Outer noBottomBorder>
|
<Layout.Header.Outer noBottomBorder>
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import {useSession} from '#/state/session'
|
import {isNative} from '#/platform/detection'
|
||||||
|
import {type SessionAccount, useSession} from '#/state/session'
|
||||||
import {
|
import {
|
||||||
useLoggedOutView,
|
useLoggedOutView,
|
||||||
useLoggedOutViewControls,
|
useLoggedOutViewControls,
|
||||||
@@ -18,11 +19,29 @@ import {atoms as a, useTheme} from '#/alf'
|
|||||||
import {AppLanguageDropdown} from '#/components/AppLanguageDropdown'
|
import {AppLanguageDropdown} from '#/components/AppLanguageDropdown'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as CloseIcon} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as CloseIcon} from '#/components/icons/Times'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'Landing'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'Landing'>
|
||||||
export function LandingScreen({navigation}: Props) {
|
export function LandingScreen({navigation}: Props) {
|
||||||
|
return (
|
||||||
|
<LandingScreenInner
|
||||||
|
signUp={() => navigation.navigate('SignUpInfo')}
|
||||||
|
selectAccount={() => navigation.navigate('SelectAccount')}
|
||||||
|
signIn={account => navigation.navigate('SignIn', {account})}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LandingScreenInner({
|
||||||
|
signUp,
|
||||||
|
selectAccount,
|
||||||
|
signIn,
|
||||||
|
}: {
|
||||||
|
signUp: () => void
|
||||||
|
selectAccount: () => void
|
||||||
|
signIn: (account?: SessionAccount) => void
|
||||||
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
@@ -38,7 +57,7 @@ export function LandingScreen({navigation}: Props) {
|
|||||||
<Layout.Screen
|
<Layout.Screen
|
||||||
testID="LandingScreen"
|
testID="LandingScreen"
|
||||||
style={{paddingBottom: insets.bottom}}>
|
style={{paddingBottom: insets.bottom}}>
|
||||||
{showLoggedOut && (
|
{isNative && showLoggedOut && (
|
||||||
<Layout.Header.Outer noBottomBorder>
|
<Layout.Header.Outer noBottomBorder>
|
||||||
<Layout.Header.Slot />
|
<Layout.Header.Slot />
|
||||||
<Layout.Header.Content />
|
<Layout.Header.Content />
|
||||||
@@ -71,7 +90,7 @@ export function LandingScreen({navigation}: Props) {
|
|||||||
style={[a.px_xl, a.gap_md, a.pb_2xl]}>
|
style={[a.px_xl, a.gap_md, a.pb_2xl]}>
|
||||||
<Button
|
<Button
|
||||||
testID="createAccountButton"
|
testID="createAccountButton"
|
||||||
onPress={() => navigation.push('SignUpInfo')}
|
onPress={signUp}
|
||||||
label={_(msg`Create new account`)}
|
label={_(msg`Create new account`)}
|
||||||
size="large"
|
size="large"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
@@ -84,9 +103,11 @@ export function LandingScreen({navigation}: Props) {
|
|||||||
testID="signInButton"
|
testID="signInButton"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (requestedAccount) {
|
if (requestedAccount) {
|
||||||
navigation.push('SignIn', {account: requestedAccount})
|
signIn(requestedAccount)
|
||||||
|
} else if (accounts.length > 0) {
|
||||||
|
selectAccount()
|
||||||
} else {
|
} else {
|
||||||
navigation.push(accounts.length > 0 ? 'SelectAccount' : 'SignIn')
|
signIn()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
label={_(msg`Sign in`)}
|
label={_(msg`Sign in`)}
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'PasswordUpdated'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'PasswordUpdated'>
|
||||||
export function PasswordUpdatedScreen({}: Props) {
|
export function PasswordUpdatedScreen({}: Props) {
|
||||||
|
return <PasswordUpdatedScreenInner />
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PasswordUpdatedScreenInner() {
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="PasswordUpdatedScreen">
|
<Layout.Screen testID="PasswordUpdatedScreen">
|
||||||
<Layout.Header.Outer noBottomBorder>
|
<Layout.Header.Outer noBottomBorder>
|
||||||
|
|||||||
@@ -10,13 +10,25 @@ import {logger} from '#/logger'
|
|||||||
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
|
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
|
||||||
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 {atoms as a, native} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {AccountList} from '#/components/AccountList'
|
import {AccountList} from '#/components/AccountList'
|
||||||
import * as TextField from '#/components/forms/TextField'
|
import * as TextField from '#/components/forms/TextField'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SelectAccount'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SelectAccount'>
|
||||||
export function SelectAccountScreen({navigation}: Props) {
|
export function SelectAccountScreen({navigation}: Props) {
|
||||||
|
return (
|
||||||
|
<SelectAccountScreenInner
|
||||||
|
signIn={account => navigation.navigate('SignIn', {account})}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectAccountScreenInner({
|
||||||
|
signIn,
|
||||||
|
}: {
|
||||||
|
signIn: (account?: SessionAccount) => void
|
||||||
|
}) {
|
||||||
const [pendingDid, setPendingDid] = useState<string | null>(null)
|
const [pendingDid, setPendingDid] = useState<string | null>(null)
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
@@ -30,7 +42,7 @@ export function SelectAccountScreen({navigation}: Props) {
|
|||||||
}
|
}
|
||||||
if (!account.accessJwt) {
|
if (!account.accessJwt) {
|
||||||
// Move to login form.
|
// Move to login form.
|
||||||
navigation.push('SignIn', {account})
|
signIn(account)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (account.did === currentAccount?.did) {
|
if (account.did === currentAccount?.did) {
|
||||||
@@ -50,7 +62,7 @@ export function SelectAccountScreen({navigation}: Props) {
|
|||||||
message: e.message,
|
message: e.message,
|
||||||
})
|
})
|
||||||
// Move to login form.
|
// Move to login form.
|
||||||
navigation.push('SignIn', {account})
|
signIn(account)
|
||||||
} finally {
|
} finally {
|
||||||
setPendingDid(null)
|
setPendingDid(null)
|
||||||
}
|
}
|
||||||
@@ -63,13 +75,13 @@ export function SelectAccountScreen({navigation}: Props) {
|
|||||||
<Layout.Header.Content />
|
<Layout.Header.Content />
|
||||||
<Layout.Header.Slot />
|
<Layout.Header.Slot />
|
||||||
</Layout.Header.Outer>
|
</Layout.Header.Outer>
|
||||||
<Layout.Content contentContainerStyle={[a.py_xl, native(a.px_xl)]}>
|
<Layout.Content contentContainerStyle={[a.p_xl]}>
|
||||||
<TextField.LabelText>
|
<TextField.LabelText>
|
||||||
<Trans>Sign in as...</Trans>
|
<Trans>Sign in as...</Trans>
|
||||||
</TextField.LabelText>
|
</TextField.LabelText>
|
||||||
<AccountList
|
<AccountList
|
||||||
onSelectAccount={onSelect}
|
onSelectAccount={onSelect}
|
||||||
onSelectOther={() => navigation.push('SignIn')}
|
onSelectOther={signIn}
|
||||||
pendingDid={pendingDid}
|
pendingDid={pendingDid}
|
||||||
/>
|
/>
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SetNewPassword'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SetNewPassword'>
|
||||||
export function SetNewPasswordScreen({}: Props) {
|
export function SetNewPasswordScreen({}: Props) {
|
||||||
|
return <SetNewPasswordScreenInner />
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SetNewPasswordScreenInner() {
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="SetNewPasswordScreen">
|
<Layout.Screen testID="SetNewPasswordScreen">
|
||||||
<Layout.Header.Outer noBottomBorder>
|
<Layout.Header.Outer noBottomBorder>
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import {
|
|||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useServiceQuery} from '#/state/queries/service'
|
import {useServiceQuery} from '#/state/queries/service'
|
||||||
|
import {type SessionAccount} from '#/state/session'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
import {SignInForm} from './components/SignInForm'
|
import {SignInForm} from './components/SignInForm'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignIn'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignIn'>
|
||||||
@@ -19,6 +20,24 @@ export function SignInScreen({
|
|||||||
navigation,
|
navigation,
|
||||||
route: {params: {account: requestedAccount} = {}},
|
route: {params: {account: requestedAccount} = {}},
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
return (
|
||||||
|
<SignInScreenInner
|
||||||
|
requestedAccount={requestedAccount}
|
||||||
|
forgotPassword={() => navigation.navigate('ForgotPassword')}
|
||||||
|
signUp={() => navigation.navigate('SignUpInfo')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignInScreenInner({
|
||||||
|
requestedAccount,
|
||||||
|
forgotPassword,
|
||||||
|
signUp,
|
||||||
|
}: {
|
||||||
|
requestedAccount?: SessionAccount
|
||||||
|
forgotPassword: () => void
|
||||||
|
signUp: () => void
|
||||||
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const failedAttemptCountRef = useRef(0)
|
const failedAttemptCountRef = useRef(0)
|
||||||
@@ -51,7 +70,7 @@ export function SignInScreen({
|
|||||||
}, [serviceError, serviceUrl, _])
|
}, [serviceError, serviceUrl, _])
|
||||||
|
|
||||||
const onPressForgotPassword = () => {
|
const onPressForgotPassword = () => {
|
||||||
navigation.push('ForgotPassword')
|
forgotPassword()
|
||||||
logger.metric('signin:forgotPasswordPressed', {})
|
logger.metric('signin:forgotPasswordPressed', {})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +112,7 @@ export function SignInScreen({
|
|||||||
New to Bluesky?{' '}
|
New to Bluesky?{' '}
|
||||||
<Text
|
<Text
|
||||||
role="link"
|
role="link"
|
||||||
onPress={() => navigation.push('SignUpInfo')}
|
onPress={signUp}
|
||||||
style={[a.text_md, {color: t.palette.primary_500}]}>
|
style={[a.text_md, {color: t.palette.primary_500}]}>
|
||||||
Create account
|
Create account
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignUpCaptcha'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignUpCaptcha'>
|
||||||
export function SignUpCaptchaScreen({}: Props) {
|
export function SignUpCaptchaScreen({}: Props) {
|
||||||
|
return <SignUpCaptchaScreenInner />
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpCaptchaScreenInner() {
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="SignUpCaptchaScreen">
|
<Layout.Screen testID="SignUpCaptchaScreen">
|
||||||
<Layout.Header.Outer noBottomBorder>
|
<Layout.Header.Outer noBottomBorder>
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignUpHandle'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignUpHandle'>
|
||||||
export function SignUpHandleScreen({}: Props) {
|
export function SignUpHandleScreen({}: Props) {
|
||||||
|
return <SignUpHandleScreenInner />
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpHandleScreenInner() {
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="SignUpHandleScreen">
|
<Layout.Screen testID="SignUpHandleScreen">
|
||||||
<Layout.Header.Outer noBottomBorder>
|
<Layout.Header.Outer noBottomBorder>
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignUpInfo'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'SignUpInfo'>
|
||||||
export function SignUpInfoScreen({}: Props) {
|
export function SignUpInfoScreen({}: Props) {
|
||||||
|
return <SignUpInfoScreenInner />
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUpInfoScreenInner() {
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="SignUpInfoScreen">
|
<Layout.Screen testID="SignUpInfoScreen">
|
||||||
<Layout.Header.Outer noBottomBorder>
|
<Layout.Header.Outer noBottomBorder>
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import {
|
|||||||
type AuthNavigatorParams,
|
type AuthNavigatorParams,
|
||||||
type NativeStackScreenProps,
|
type NativeStackScreenProps,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import * as Layout from '#/components/Layout'
|
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as Layout from './components/Layout'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<AuthNavigatorParams, 'StarterPackLanding'>
|
type Props = NativeStackScreenProps<AuthNavigatorParams, 'StarterPackLanding'>
|
||||||
export function StarterPackLandingScreen({}: Props) {
|
export function StarterPackLandingScreen({}: Props) {
|
||||||
|
return <StarterPackLandingScreenInner />
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StarterPackLandingScreenInner() {
|
||||||
return (
|
return (
|
||||||
<Layout.Screen testID="StarterPackLandingScreen">
|
<Layout.Screen testID="StarterPackLandingScreen">
|
||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export function AuthenticationFlow() {
|
||||||
|
throw new Error(
|
||||||
|
'AuthenticationFlow is only available on web. Navigate to the auth screens instead.',
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
import {useReducer} from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {ImageBackground} from 'expo-image'
|
||||||
|
import {msg} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {type SessionAccount} from '#/state/session'
|
||||||
|
import {Logo} from '#/view/icons/Logo'
|
||||||
|
import {Logotype} from '#/view/icons/Logotype'
|
||||||
|
import {atoms as a, tokens, useTheme, web} from '#/alf'
|
||||||
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
|
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||||
|
import {ForgotPasswordScreenInner} from '../../ForgotPasswordScreen'
|
||||||
|
import {LandingScreenInner} from '../../LandingScreen'
|
||||||
|
import {PasswordUpdatedScreenInner} from '../../PasswordUpdatedScreen'
|
||||||
|
import {SelectAccountScreenInner} from '../../SelectAccountScreen'
|
||||||
|
import {SetNewPasswordScreenInner} from '../../SetNewPasswordScreen'
|
||||||
|
import {SignInScreenInner} from '../../SignInScreen'
|
||||||
|
import {SignUpCaptchaScreenInner} from '../../SignUpCaptchaScreen'
|
||||||
|
import {SignUpHandleScreenInner} from '../../SignUpHandleScreen'
|
||||||
|
import {SignUpInfoScreenInner} from '../../SignUpInfoScreen'
|
||||||
|
import {StarterPackLandingScreenInner} from '../../StarterPackLandingScreen'
|
||||||
|
|
||||||
|
type State =
|
||||||
|
| {
|
||||||
|
screen: 'Landing'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'ForgotPassword'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'PasswordUpdated'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'SelectAccount'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'SetNewPassword'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'SignIn'
|
||||||
|
requestedAccount?: SessionAccount
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'SignUpCaptcha'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'SignUpHandle'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'SignUpInfo'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
screen: 'StarterPackLanding'
|
||||||
|
}
|
||||||
|
|
||||||
|
type Action =
|
||||||
|
| {
|
||||||
|
type: 'NAVIGATE_TO_SIGN_IN'
|
||||||
|
account?: SessionAccount
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'NAVIGATE_TO_SIGN_UP'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'NAVIGATE_TO_SELECT_ACCOUNT'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'NAVIGATE_TO_FORGOT_PASSWORD'
|
||||||
|
}
|
||||||
|
|
||||||
|
function reducer(state: State, action: Action): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'NAVIGATE_TO_SIGN_IN':
|
||||||
|
return {screen: 'SignIn', requestedAccount: action.account}
|
||||||
|
case 'NAVIGATE_TO_SIGN_UP':
|
||||||
|
return {screen: 'SignUpHandle'}
|
||||||
|
case 'NAVIGATE_TO_SELECT_ACCOUNT':
|
||||||
|
return {screen: 'SelectAccount'}
|
||||||
|
case 'NAVIGATE_TO_FORGOT_PASSWORD':
|
||||||
|
return {screen: 'ForgotPassword'}
|
||||||
|
default:
|
||||||
|
// @ts-expect-error this will stop throwing an error if we miss a case
|
||||||
|
throw new Error(`Unhandled action type: ${action.type}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AuthenticationFlow({onDismiss}: {onDismiss?: () => void}) {
|
||||||
|
const [state, dispatch] = useReducer(reducer, {screen: 'Landing'})
|
||||||
|
|
||||||
|
let content
|
||||||
|
switch (state.screen) {
|
||||||
|
case 'ForgotPassword':
|
||||||
|
content = <ForgotPasswordScreenInner />
|
||||||
|
break
|
||||||
|
case 'Landing':
|
||||||
|
content = (
|
||||||
|
<LandingScreenInner
|
||||||
|
signIn={account => dispatch({type: 'NAVIGATE_TO_SIGN_IN', account})}
|
||||||
|
selectAccount={() => dispatch({type: 'NAVIGATE_TO_SELECT_ACCOUNT'})}
|
||||||
|
signUp={() => dispatch({type: 'NAVIGATE_TO_SIGN_UP'})}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
break
|
||||||
|
case 'PasswordUpdated':
|
||||||
|
content = <PasswordUpdatedScreenInner />
|
||||||
|
break
|
||||||
|
case 'SelectAccount':
|
||||||
|
content = (
|
||||||
|
<SelectAccountScreenInner
|
||||||
|
signIn={account => dispatch({type: 'NAVIGATE_TO_SIGN_IN', account})}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
break
|
||||||
|
case 'SetNewPassword':
|
||||||
|
content = <SetNewPasswordScreenInner />
|
||||||
|
break
|
||||||
|
case 'SignIn':
|
||||||
|
content = (
|
||||||
|
<SignInScreenInner
|
||||||
|
requestedAccount={state.requestedAccount}
|
||||||
|
signUp={() => dispatch({type: 'NAVIGATE_TO_SIGN_UP'})}
|
||||||
|
forgotPassword={() => dispatch({type: 'NAVIGATE_TO_FORGOT_PASSWORD'})}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
break
|
||||||
|
case 'SignUpCaptcha':
|
||||||
|
content = <SignUpCaptchaScreenInner />
|
||||||
|
break
|
||||||
|
case 'SignUpHandle':
|
||||||
|
content = <SignUpHandleScreenInner />
|
||||||
|
break
|
||||||
|
case 'SignUpInfo':
|
||||||
|
content = <SignUpInfoScreenInner />
|
||||||
|
break
|
||||||
|
case 'StarterPackLanding':
|
||||||
|
content = <StarterPackLandingScreenInner />
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Shell onDismiss={onDismiss}>{content}</Shell>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Shell({
|
||||||
|
children,
|
||||||
|
onDismiss,
|
||||||
|
}: {
|
||||||
|
children?: React.ReactNode
|
||||||
|
onDismiss?: () => void
|
||||||
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
|
||||||
|
const image =
|
||||||
|
t.scheme === 'light'
|
||||||
|
? require('../../../../../assets/background-light.webp')
|
||||||
|
: require('../../../../../assets/background-dark.webp')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ImageBackground
|
||||||
|
style={[
|
||||||
|
a.w_full,
|
||||||
|
a.h_full,
|
||||||
|
web({minHeight: '100vh'}),
|
||||||
|
a.align_center,
|
||||||
|
a.justify_center,
|
||||||
|
a.gap_md,
|
||||||
|
a.px_md,
|
||||||
|
]}
|
||||||
|
source={image}>
|
||||||
|
{onDismiss && (
|
||||||
|
<Button
|
||||||
|
label={_(msg`Close`)}
|
||||||
|
onPress={onDismiss}
|
||||||
|
variant="solid"
|
||||||
|
color="secondary_inverted"
|
||||||
|
shape="round"
|
||||||
|
size="small"
|
||||||
|
style={[a.absolute, {top: tokens.space.xl, right: tokens.space.xl}]}>
|
||||||
|
<ButtonIcon icon={XIcon} />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<View
|
||||||
|
style={[a.px_lg, a.justify_center, a.align_center, {height: '20%'}]}>
|
||||||
|
<View style={[a.align_end, a.flex_row, a.gap_xl]}>
|
||||||
|
<Logo fill="white" width={65} />
|
||||||
|
<Logotype fill="white" width={180} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.rounded_lg,
|
||||||
|
t.atoms.bg,
|
||||||
|
web({height: 440, maxHeight: 'calc(60% - 32px)'}),
|
||||||
|
a.w_full,
|
||||||
|
{maxWidth: 480},
|
||||||
|
a.overflow_auto,
|
||||||
|
]}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</ImageBackground>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from '#/components/Layout'
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import {memo} from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
|
||||||
|
import {atoms as a} from '#/alf'
|
||||||
|
import {type ContentProps, type ScreenProps} from '#/components/Layout'
|
||||||
|
|
||||||
|
export * as Header from '#/components/Layout/Header'
|
||||||
|
|
||||||
|
export const Screen = memo(function Screen({style, ...props}: ScreenProps) {
|
||||||
|
return <View style={[a.w_full, a.h_full, style]} {...props} />
|
||||||
|
})
|
||||||
|
|
||||||
|
export const Content = memo(function Content({
|
||||||
|
style,
|
||||||
|
contentContainerStyle,
|
||||||
|
children,
|
||||||
|
}: React.PropsWithChildren<ContentProps>) {
|
||||||
|
return (
|
||||||
|
<View style={[a.flex_1, style, contentContainerStyle]}>{children}</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
@@ -34,7 +34,7 @@ import {
|
|||||||
useLoggedOutView,
|
useLoggedOutView,
|
||||||
useLoggedOutViewControls,
|
useLoggedOutViewControls,
|
||||||
} from '#/state/shell/logged-out'
|
} from '#/state/shell/logged-out'
|
||||||
import {LoggedOut} from '#/view/com/auth/LoggedOut'
|
import {AuthenticationFlow} from '#/screens/Authentication/components/Flow'
|
||||||
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 {SignupQueued} from '#/screens/SignupQueued'
|
||||||
@@ -114,7 +114,7 @@ function NativeStackNavigator({
|
|||||||
const {leftNavMinimal} = useLayoutBreakpoints()
|
const {leftNavMinimal} = useLayoutBreakpoints()
|
||||||
// Temp: use old system for web. TODO: unify
|
// Temp: use old system for web. TODO: unify
|
||||||
if (isWeb && !hasSession && (!PWI_ENABLED || activeRouteRequiresAuth)) {
|
if (isWeb && !hasSession && (!PWI_ENABLED || activeRouteRequiresAuth)) {
|
||||||
return <LoggedOut />
|
return <AuthenticationFlow />
|
||||||
}
|
}
|
||||||
if (hasSession && currentAccount?.signupQueued) {
|
if (hasSession && currentAccount?.signupQueued) {
|
||||||
return <SignupQueued />
|
return <SignupQueued />
|
||||||
@@ -123,7 +123,7 @@ function NativeStackNavigator({
|
|||||||
return <Takendown />
|
return <Takendown />
|
||||||
}
|
}
|
||||||
if (isWeb && showLoggedOut) {
|
if (isWeb && showLoggedOut) {
|
||||||
return <LoggedOut onDismiss={() => setShowLoggedOut(false)} />
|
return <AuthenticationFlow onDismiss={() => setShowLoggedOut(false)} />
|
||||||
}
|
}
|
||||||
if (currentAccount?.status === 'deactivated') {
|
if (currentAccount?.status === 'deactivated') {
|
||||||
return <Deactivated />
|
return <Deactivated />
|
||||||
|
|||||||
Reference in New Issue
Block a user