diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/state/models/ui/create-account.ts | 9 | ||||
-rw-r--r-- | src/view/com/auth/LoggedOut.tsx | 39 | ||||
-rw-r--r-- | src/view/com/auth/create/CreateAccount.tsx | 106 | ||||
-rw-r--r-- | src/view/com/auth/create/Policies.tsx | 1 | ||||
-rw-r--r-- | src/view/com/auth/login/Login.tsx | 102 | ||||
-rw-r--r-- | src/view/com/util/layouts/LoggedOutLayout.tsx | 102 |
6 files changed, 239 insertions, 120 deletions
diff --git a/src/state/models/ui/create-account.ts b/src/state/models/ui/create-account.ts index d9d4f51b9..c5d9f6d9b 100644 --- a/src/state/models/ui/create-account.ts +++ b/src/state/models/ui/create-account.ts @@ -109,13 +109,8 @@ export class CreateAccountModel { this.setError('') this.setIsProcessing(true) - // open the onboarding screens after the session is created - const sessionReadySub = this.rootStore.onSessionReady(() => { - sessionReadySub.remove() - this.rootStore.onboarding.start() - }) - try { + this.rootStore.onboarding.start() // start now to avoid flashing the wrong view await this.rootStore.session.createAccount({ service: this.serviceUrl, email: this.email, @@ -125,7 +120,7 @@ export class CreateAccountModel { }) track('Create Account') } catch (e: any) { - sessionReadySub.remove() + this.rootStore.onboarding.skip() // undo starting the onboard let errMsg = e.toString() if (e instanceof ComAtprotoServerCreateAccount.InvalidInviteCodeError) { errMsg = diff --git a/src/view/com/auth/LoggedOut.tsx b/src/view/com/auth/LoggedOut.tsx index e35706466..6d3b87dd3 100644 --- a/src/view/com/auth/LoggedOut.tsx +++ b/src/view/com/auth/LoggedOut.tsx @@ -9,7 +9,6 @@ import {usePalette} from 'lib/hooks/usePalette' import {useStores} from 'state/index' import {useAnalytics} from 'lib/analytics/analytics' import {SplashScreen} from './SplashScreen' -import {CenteredView} from '../util/Views' enum ScreenState { S_LoginOrCreateAccount, @@ -43,25 +42,23 @@ export const LoggedOut = observer(() => { } return ( - <CenteredView style={[s.hContentRegion, pal.view]}> - <SafeAreaView testID="noSessionView" style={s.hContentRegion}> - <ErrorBoundary> - {screenState === ScreenState.S_Login ? ( - <Login - onPressBack={() => - setScreenState(ScreenState.S_LoginOrCreateAccount) - } - /> - ) : undefined} - {screenState === ScreenState.S_CreateAccount ? ( - <CreateAccount - onPressBack={() => - setScreenState(ScreenState.S_LoginOrCreateAccount) - } - /> - ) : undefined} - </ErrorBoundary> - </SafeAreaView> - </CenteredView> + <SafeAreaView testID="noSessionView" style={[s.hContentRegion, pal.view]}> + <ErrorBoundary> + {screenState === ScreenState.S_Login ? ( + <Login + onPressBack={() => + setScreenState(ScreenState.S_LoginOrCreateAccount) + } + /> + ) : undefined} + {screenState === ScreenState.S_CreateAccount ? ( + <CreateAccount + onPressBack={() => + setScreenState(ScreenState.S_LoginOrCreateAccount) + } + /> + ) : undefined} + </ErrorBoundary> + </SafeAreaView> ) }) diff --git a/src/view/com/auth/create/CreateAccount.tsx b/src/view/com/auth/create/CreateAccount.tsx index d6cb1a0a7..8cf1cfaf5 100644 --- a/src/view/com/auth/create/CreateAccount.tsx +++ b/src/view/com/auth/create/CreateAccount.tsx @@ -10,6 +10,7 @@ import { import {observer} from 'mobx-react-lite' import {useAnalytics} from 'lib/analytics/analytics' import {Text} from '../../util/text/Text' +import {LoggedOutLayout} from 'view/com/util/layouts/LoggedOutLayout' import {s} from 'lib/styles' import {useStores} from 'state/index' import {CreateAccountModel} from 'state/models/ui/create-account' @@ -65,60 +66,65 @@ export const CreateAccount = observer( }, [model, track]) return ( - <ScrollView testID="createAccount" style={pal.view}> - <KeyboardAvoidingView behavior="padding"> - <View style={styles.stepContainer}> - {model.step === 1 && <Step1 model={model} />} - {model.step === 2 && <Step2 model={model} />} - {model.step === 3 && <Step3 model={model} />} - </View> - <View style={[s.flexRow, s.pl20, s.pr20]}> - <TouchableOpacity - onPress={onPressBackInner} - testID="backBtn" - accessibilityRole="button"> - <Text type="xl" style={pal.link}> - Back - </Text> - </TouchableOpacity> - <View style={s.flex1} /> - {model.canNext ? ( + <LoggedOutLayout + leadin={`Step ${model.step}`} + title="Create Account" + description="We're so excited to have you join us!"> + <ScrollView testID="createAccount" style={pal.view}> + <KeyboardAvoidingView behavior="padding"> + <View style={styles.stepContainer}> + {model.step === 1 && <Step1 model={model} />} + {model.step === 2 && <Step2 model={model} />} + {model.step === 3 && <Step3 model={model} />} + </View> + <View style={[s.flexRow, s.pl20, s.pr20]}> <TouchableOpacity - testID="nextBtn" - onPress={onPressNext} + onPress={onPressBackInner} + testID="backBtn" accessibilityRole="button"> - {model.isProcessing ? ( - <ActivityIndicator /> - ) : ( - <Text type="xl-bold" style={[pal.link, s.pr5]}> - Next - </Text> - )} - </TouchableOpacity> - ) : model.didServiceDescriptionFetchFail ? ( - <TouchableOpacity - testID="retryConnectBtn" - onPress={onPressRetryConnect} - accessibilityRole="button" - accessibilityLabel="Retry" - accessibilityHint="Retries account creation" - accessibilityLiveRegion="polite"> - <Text type="xl-bold" style={[pal.link, s.pr5]}> - Retry + <Text type="xl" style={pal.link}> + Back </Text> </TouchableOpacity> - ) : model.isFetchingServiceDescription ? ( - <> - <ActivityIndicator color="#fff" /> - <Text type="xl" style={[pal.text, s.pr5]}> - Connecting... - </Text> - </> - ) : undefined} - </View> - <View style={s.footerSpacer} /> - </KeyboardAvoidingView> - </ScrollView> + <View style={s.flex1} /> + {model.canNext ? ( + <TouchableOpacity + testID="nextBtn" + onPress={onPressNext} + accessibilityRole="button"> + {model.isProcessing ? ( + <ActivityIndicator /> + ) : ( + <Text type="xl-bold" style={[pal.link, s.pr5]}> + Next + </Text> + )} + </TouchableOpacity> + ) : model.didServiceDescriptionFetchFail ? ( + <TouchableOpacity + testID="retryConnectBtn" + onPress={onPressRetryConnect} + accessibilityRole="button" + accessibilityLabel="Retry" + accessibilityHint="Retries account creation" + accessibilityLiveRegion="polite"> + <Text type="xl-bold" style={[pal.link, s.pr5]}> + Retry + </Text> + </TouchableOpacity> + ) : model.isFetchingServiceDescription ? ( + <> + <ActivityIndicator color="#fff" /> + <Text type="xl" style={[pal.text, s.pr5]}> + Connecting... + </Text> + </> + ) : undefined} + </View> + <View style={s.footerSpacer} /> + </KeyboardAvoidingView> + </ScrollView> + </LoggedOutLayout> ) }, ) diff --git a/src/view/com/auth/create/Policies.tsx b/src/view/com/auth/create/Policies.tsx index a3943d8cc..8eb669bcf 100644 --- a/src/view/com/auth/create/Policies.tsx +++ b/src/view/com/auth/create/Policies.tsx @@ -93,6 +93,7 @@ function validWebLink(url?: string): string | undefined { const styles = StyleSheet.create({ policies: { + flexDirection: 'row', gap: 8, }, errorIcon: { diff --git a/src/view/com/auth/login/Login.tsx b/src/view/com/auth/login/Login.tsx index c277bfb9e..fac923393 100644 --- a/src/view/com/auth/login/Login.tsx +++ b/src/view/com/auth/login/Login.tsx @@ -17,6 +17,7 @@ import {BskyAgent} from '@atproto/api' import {useAnalytics} from 'lib/analytics/analytics' import {Text} from '../../util/text/Text' import {UserAvatar} from '../../util/UserAvatar' +import {LoggedOutLayout} from 'view/com/util/layouts/LoggedOutLayout' import {s, colors} from 'lib/styles' import {createFullHandle} from 'lib/strings/handles' import {toNiceDomain} from 'lib/strings/url-helpers' @@ -99,52 +100,69 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => { } return ( - <KeyboardAvoidingView - testID="signIn" - behavior="padding" - style={[pal.view, s.pt10]}> + <KeyboardAvoidingView testID="signIn" behavior="padding" style={pal.view}> {currentForm === Forms.Login ? ( - <LoginForm - store={store} - error={error} - serviceUrl={serviceUrl} - serviceDescription={serviceDescription} - initialHandle={initialHandle} - setError={setError} - setServiceUrl={setServiceUrl} - onPressBack={onPressBack} - onPressForgotPassword={onPressForgotPassword} - onPressRetryConnect={onPressRetryConnect} - /> + <LoggedOutLayout + leadin="" + title="Sign in" + description="Enter your username and password"> + <LoginForm + store={store} + error={error} + serviceUrl={serviceUrl} + serviceDescription={serviceDescription} + initialHandle={initialHandle} + setError={setError} + setServiceUrl={setServiceUrl} + onPressBack={onPressBack} + onPressForgotPassword={onPressForgotPassword} + onPressRetryConnect={onPressRetryConnect} + /> + </LoggedOutLayout> ) : undefined} {currentForm === Forms.ChooseAccount ? ( - <ChooseAccountForm - store={store} - onSelectAccount={onSelectAccount} - onPressBack={onPressBack} - /> + <LoggedOutLayout + leadin="" + title="Sign in as..." + description="Select from an existing account"> + <ChooseAccountForm + store={store} + onSelectAccount={onSelectAccount} + onPressBack={onPressBack} + /> + </LoggedOutLayout> ) : undefined} {currentForm === Forms.ForgotPassword ? ( - <ForgotPasswordForm - store={store} - error={error} - serviceUrl={serviceUrl} - serviceDescription={serviceDescription} - setError={setError} - setServiceUrl={setServiceUrl} - onPressBack={gotoForm(Forms.Login)} - onEmailSent={gotoForm(Forms.SetNewPassword)} - /> + <LoggedOutLayout + leadin="" + title="Forgot Password" + description="Let's get your password reset!"> + <ForgotPasswordForm + store={store} + error={error} + serviceUrl={serviceUrl} + serviceDescription={serviceDescription} + setError={setError} + setServiceUrl={setServiceUrl} + onPressBack={gotoForm(Forms.Login)} + onEmailSent={gotoForm(Forms.SetNewPassword)} + /> + </LoggedOutLayout> ) : undefined} {currentForm === Forms.SetNewPassword ? ( - <SetNewPasswordForm - store={store} - error={error} - serviceUrl={serviceUrl} - setError={setError} - onPressBack={gotoForm(Forms.ForgotPassword)} - onPasswordSet={gotoForm(Forms.PasswordUpdated)} - /> + <LoggedOutLayout + leadin="" + title="Forgot Password" + description="Let's get your password reset!"> + <SetNewPasswordForm + store={store} + error={error} + serviceUrl={serviceUrl} + setError={setError} + onPressBack={gotoForm(Forms.ForgotPassword)} + onPasswordSet={gotoForm(Forms.PasswordUpdated)} + /> + </LoggedOutLayout> ) : undefined} {currentForm === Forms.PasswordUpdated ? ( <PasswordUpdatedForm onPressNext={gotoForm(Forms.Login)} /> @@ -834,9 +852,9 @@ const SetNewPasswordForm = ({ const PasswordUpdatedForm = ({onPressNext}: {onPressNext: () => void}) => { const {screen} = useAnalytics() - // useEffect(() => { - screen('Signin:PasswordUpdatedForm') - // }, [screen]) + useEffect(() => { + screen('Signin:PasswordUpdatedForm') + }, [screen]) const pal = usePalette('default') return ( diff --git a/src/view/com/util/layouts/LoggedOutLayout.tsx b/src/view/com/util/layouts/LoggedOutLayout.tsx new file mode 100644 index 000000000..daa33cece --- /dev/null +++ b/src/view/com/util/layouts/LoggedOutLayout.tsx @@ -0,0 +1,102 @@ +import React from 'react' +import {StyleSheet, View} from 'react-native' +import {Text} from '../text/Text' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle' + +export const LoggedOutLayout = ({ + leadin, + title, + description, + children, +}: React.PropsWithChildren<{ + leadin: string + title: string + description: string +}>) => { + const {isMobile, isTabletOrMobile} = useWebMediaQueries() + const pal = usePalette('default') + const sideBg = useColorSchemeStyle(pal.viewLight, pal.view) + const contentBg = useColorSchemeStyle(pal.view, { + backgroundColor: pal.colors.background, + borderColor: pal.colors.border, + borderLeftWidth: 1, + }) + + if (isMobile) { + return <View style={{paddingTop: 10}}>{children}</View> + } + return ( + <View style={styles.container}> + <View style={[styles.side, sideBg]}> + <Text + style={[ + pal.textLight, + styles.leadinText, + isTabletOrMobile && styles.leadinTextSmall, + ]}> + {leadin} + </Text> + <Text + style={[ + pal.link, + styles.titleText, + isTabletOrMobile && styles.titleTextSmall, + ]}> + {title} + </Text> + <Text type="2xl-medium" style={[pal.textLight, styles.descriptionText]}> + {description} + </Text> + </View> + <View style={[styles.content, contentBg]}> + <View style={styles.contentWrapper}>{children}</View> + </View> + </View> + ) +} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + height: '100vh', + }, + side: { + flex: 1, + paddingHorizontal: 40, + paddingBottom: 80, + justifyContent: 'center', + }, + content: { + flex: 2, + paddingHorizontal: 40, + justifyContent: 'center', + }, + + leadinText: { + fontSize: 36, + fontWeight: '800', + textAlign: 'right', + }, + leadinTextSmall: { + fontSize: 24, + }, + titleText: { + fontSize: 58, + fontWeight: '800', + textAlign: 'right', + }, + titleTextSmall: { + fontSize: 36, + }, + descriptionText: { + maxWidth: 400, + marginTop: 10, + marginLeft: 'auto', + textAlign: 'right', + }, + contentWrapper: { + maxWidth: 600, + }, +}) |