fix up Signup

pull/1528/head
Audric Ackermann 4 years ago
parent 683fa84970
commit 619a894b52
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -1,80 +1,139 @@
import React from 'react'; import React from 'react';
import {
SessionButton,
SessionButtonColor,
SessionButtonType,
} from '../SessionButton';
import { trigger } from '../../../shims/events';
import { StringUtils, ToastUtils, UserUtils } from '../../../session/utils'; import { StringUtils, ToastUtils, UserUtils } from '../../../session/utils';
import { ConversationController } from '../../../session/conversations'; import { ConversationController } from '../../../session/conversations';
import { PasswordUtil } from '../../../util';
import { removeAll } from '../../../data/data'; import { removeAll } from '../../../data/data';
import { SignUpMode, SignUpTab } from './SignUpTab'; import { SignUpTab } from './SignUpTab';
import { SignInMode } from './SignInTab'; import { SignInTab } from './SignInTab';
import { RegistrationUserDetails } from './RegistrationUserDetails';
import { TermsAndConditions } from './TermsAndConditions';
import { TabLabel, TabType } from './TabLabel'; import { TabLabel, TabType } from './TabLabel';
import { PasswordUtil } from '../../../util';
import { trigger } from '../../../shims/events';
export const MAX_USERNAME_LENGTH = 20; export const MAX_USERNAME_LENGTH = 20;
// tslint:disable: use-simple-attributes
interface State { interface State {
selectedTab: TabType; selectedTab: TabType;
signInMode: SignInMode;
signUpMode: SignUpMode;
secretWords: string | undefined;
displayName: string;
password: string;
validatePassword: string;
passwordErrorString: string;
passwordFieldsMatch: boolean;
recoveryPhrase: string;
generatedRecoveryPhrase: string; generatedRecoveryPhrase: string;
hexGeneratedPubKey: string; hexGeneratedPubKey: string;
mnemonicError: string | undefined;
displayNameError: string | undefined;
} }
export class RegistrationTabs extends React.Component<any, State> { export function validatePassword(password: string, verifyPassword: string) {
constructor(props: any) { const trimmedPassword = password.trim();
super(props); const trimmedVerifyPassword = verifyPassword.trim();
// If user hasn't set a value then skip
if (!trimmedPassword && !trimmedVerifyPassword) {
return {
passwordErrorString: '',
passwordFieldsMatch: true,
};
}
const error = PasswordUtil.validatePassword(trimmedPassword, window.i18n);
if (error) {
return {
passwordErrorString: error,
passwordFieldsMatch: true,
};
}
if (trimmedPassword !== trimmedVerifyPassword) {
return {
passwordErrorString: '',
passwordFieldsMatch: false,
};
}
return {
passwordErrorString: '',
passwordFieldsMatch: true,
};
}
export async function resetRegistration() {
await removeAll();
await window.storage.reset();
await window.storage.fetch();
ConversationController.getInstance().reset();
await ConversationController.getInstance().load();
}
export async function signUp(signUpDetails: {
displayName: string;
generatedRecoveryPhrase: string;
password: string;
verifyPassword: string;
}) {
const {
displayName,
password,
verifyPassword,
generatedRecoveryPhrase,
} = signUpDetails;
window.log.info('starting Signing up');
const trimName = displayName.trim();
if (!trimName) {
window.log.warn('invalid trimmed name for registration');
ToastUtils.pushToastError(
'invalidDisplayName',
window.i18n('displayNameEmpty')
);
return;
}
const passwordErrors = validatePassword(password, verifyPassword);
if (passwordErrors.passwordErrorString) {
window.log.warn('invalid password for registration');
ToastUtils.pushToastError(
'invalidPassword',
window.i18n('invalidPassword')
);
return;
}
if (!!password && !passwordErrors.passwordFieldsMatch) {
window.log.warn('passwords does not match for registration');
ToastUtils.pushToastError(
'invalidPassword',
window.i18n('passwordsDoNotMatch')
);
return;
}
this.onSeedChanged = this.onSeedChanged.bind(this); try {
this.onDisplayNameChanged = this.onDisplayNameChanged.bind(this); await resetRegistration();
this.onPasswordChanged = this.onPasswordChanged.bind(this); await window.setPassword(password);
this.onPasswordVerifyChanged = this.onPasswordVerifyChanged.bind(this); UserUtils.setRestoringFromSeed(false);
this.handlePressEnter = this.handlePressEnter.bind(this); await window
this.handleContinueYourSessionClick = this.handleContinueYourSessionClick.bind( .getAccountManager()
this .registerSingleDevice(generatedRecoveryPhrase, 'english', trimName);
// We are just creating a new account, no need to wait for a configuration message
trigger('openInbox');
} catch (e) {
ToastUtils.pushToastError(
'registrationError',
`Error: ${e.message || 'Something went wrong'}`
); );
this.onCompleteSignUpClick = this.onCompleteSignUpClick.bind(this); window.log.warn('exception during registration:', e);
}
}
export class RegistrationTabs extends React.Component<any, State> {
constructor() {
super({});
this.state = { this.state = {
selectedTab: TabType.SignUp, selectedTab: TabType.SignUp,
signInMode: SignInMode.Default,
signUpMode: SignUpMode.Default,
secretWords: undefined,
displayName: '',
password: '',
validatePassword: '',
passwordErrorString: '',
passwordFieldsMatch: false,
recoveryPhrase: '',
generatedRecoveryPhrase: '', generatedRecoveryPhrase: '',
hexGeneratedPubKey: '', hexGeneratedPubKey: '',
mnemonicError: undefined,
displayNameError: undefined,
}; };
} }
public componentDidMount() { public componentDidMount() {
void this.generateMnemonicAndKeyPair(); void this.generateMnemonicAndKeyPair();
void this.resetRegistration(); void resetRegistration();
} }
public render() { public render() {
const { selectedTab } = this.state; const { selectedTab } = this.state;
// tslint:disable: use-simple-attributes
return ( return (
<div className="session-registration-container"> <div className="session-registration-container">
@ -126,391 +185,79 @@ export class RegistrationTabs extends React.Component<any, State> {
private readonly handleTabSelect = (tabType: TabType): void => { private readonly handleTabSelect = (tabType: TabType): void => {
this.setState({ this.setState({
selectedTab: tabType, selectedTab: tabType,
signInMode: SignInMode.Default,
signUpMode: SignUpMode.Default,
displayName: '',
password: '',
validatePassword: '',
passwordErrorString: '',
passwordFieldsMatch: false,
recoveryPhrase: '',
mnemonicError: undefined,
displayNameError: undefined,
}); });
}; };
private onSeedChanged(val: string) {
this.setState({
recoveryPhrase: val,
mnemonicError: !val ? window.i18n('recoveryPhraseEmpty') : undefined,
});
}
private onDisplayNameChanged(val: string) {
const sanitizedName = this.sanitiseNameInput(val);
const trimName = sanitizedName.trim();
this.setState({
displayName: sanitizedName,
displayNameError: !trimName ? window.i18n('displayNameEmpty') : undefined,
});
}
private onPasswordChanged(val: string) {
this.setState({ password: val }, () => {
this.validatePassword();
});
}
private onPasswordVerifyChanged(val: string) {
this.setState({ validatePassword: val });
this.setState({ validatePassword: val }, () => {
this.validatePassword();
});
}
private renderSections() { private renderSections() {
const { selectedTab } = this.state; const {
selectedTab,
generatedRecoveryPhrase,
hexGeneratedPubKey,
} = this.state;
if (selectedTab === TabType.SignUp) { if (selectedTab === TabType.SignUp) {
return ( return (
<SignUpTab <SignUpTab
signUpMode={this.state.signUpMode} generatedRecoveryPhrase={generatedRecoveryPhrase}
continueSignUp={() => { hexGeneratedPubKey={hexGeneratedPubKey}
this.setState({
signUpMode: SignUpMode.EnterDetails,
});
}}
createSessionID={() => {
this.setState(
{
signUpMode: SignUpMode.SessionIDShown,
},
() => {
window.Session.setNewSessionID(this.state.hexGeneratedPubKey);
}
);
}}
onCompleteSignUpClick={this.onCompleteSignUpClick}
displayName={this.state.displayName}
password={this.state.password}
passwordErrorString={this.state.passwordErrorString}
passwordFieldsMatch={this.state.passwordFieldsMatch}
displayNameError={this.state.displayNameError}
recoveryPhrase={this.state.recoveryPhrase}
onPasswordVerifyChanged={this.onPasswordVerifyChanged}
handlePressEnter={this.handlePressEnter}
onPasswordChanged={this.onPasswordChanged}
onDisplayNameChanged={this.onDisplayNameChanged}
onSeedChanged={this.onSeedChanged}
/> />
); );
} }
return this.renderSignIn(); return <SignInTab />;
}
private getRenderTermsConditionAgreement() {
const { selectedTab, signInMode } = this.state;
if (selectedTab !== TabType.SignUp) {
return signInMode !== SignInMode.Default ? <TermsAndConditions /> : null;
}
return <></>;
}
private onCompleteSignUpClick() {
void this.register();
}
private renderSignIn() {
return (
<div className="session-registration__content">
{this.renderRegistrationContent()}
{this.renderSignInButtons()}
{this.getRenderTermsConditionAgreement()}
</div>
);
}
private renderRegistrationContent() {
const { signInMode } = this.state;
const isSignInNotDefault = signInMode !== SignInMode.Default;
if (isSignInNotDefault) {
const sharedProps = {
displayName: this.state.displayName,
handlePressEnter: this.handlePressEnter,
onDisplayNameChanged: this.onDisplayNameChanged,
onPasswordChanged: this.onPasswordChanged,
onPasswordVerifyChanged: this.onPasswordVerifyChanged,
onSeedChanged: this.onSeedChanged,
password: this.state.password,
passwordErrorString: this.state.passwordErrorString,
passwordFieldsMatch: this.state.passwordFieldsMatch,
recoveryPhrase: this.state.recoveryPhrase,
stealAutoFocus: true,
};
if (signInMode === SignInMode.UsingRecoveryPhrase) {
return (
<RegistrationUserDetails
showDisplayNameField={true}
showSeedField={true}
{...sharedProps}
/>
);
}
if (signInMode === SignInMode.LinkDevice) {
return (
<RegistrationUserDetails
showDisplayNameField={false}
showSeedField={true}
{...sharedProps}
/>
);
}
}
return null;
}
private renderSignInButtons() {
const { signInMode } = this.state;
const or = window.i18n('or');
if (signInMode === SignInMode.Default) {
return (
<div>
{this.renderRestoreUsingRecoveryPhraseButton()}
<div className="or">{or}</div>
{this.renderLinkDeviceButton()}
</div>
);
}
return (
<SessionButton
onClick={this.handleContinueYourSessionClick}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('continueYourSession')}
/>
);
}
private renderTermsConditionAgreement() {
return <TermsAndConditions />;
}
private handleContinueYourSessionClick() {
if (this.state.signInMode === SignInMode.UsingRecoveryPhrase) {
void this.register();
}
}
private renderRestoreUsingRecoveryPhraseButton() {
return (
<SessionButton
onClick={() => {
this.setState({
signInMode: SignInMode.UsingRecoveryPhrase,
recoveryPhrase: '',
displayName: '',
signUpMode: SignUpMode.Default,
});
}}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
text={window.i18n('restoreUsingRecoveryPhrase')}
/>
);
}
private renderLinkDeviceButton() {
return (
<SessionButton
onClick={() => {
this.setState({
signInMode: SignInMode.LinkDevice,
recoveryPhrase: '',
displayName: '',
signUpMode: SignUpMode.Default,
});
}}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
text={window.i18n('linkDevice')}
/>
);
}
private handlePressEnter() {
const { signInMode, signUpMode } = this.state;
if (signUpMode === SignUpMode.EnterDetails) {
this.onCompleteSignUpClick();
return;
}
if (signInMode === SignInMode.UsingRecoveryPhrase) {
this.handleContinueYourSessionClick();
return;
}
}
private trim(value: string) {
return value ? value.trim() : value;
}
private validatePassword() {
const input = this.trim(this.state.password);
const confirmationInput = this.trim(this.state.validatePassword);
// If user hasn't set a value then skip
if (!input && !confirmationInput) {
this.setState({
passwordErrorString: '',
passwordFieldsMatch: true,
});
return;
}
const error = PasswordUtil.validatePassword(input, window.i18n);
if (error) {
this.setState({
passwordErrorString: error,
passwordFieldsMatch: true,
});
return;
}
if (input !== confirmationInput) {
this.setState({
passwordErrorString: '',
passwordFieldsMatch: false,
});
return;
}
this.setState({
passwordErrorString: '',
passwordFieldsMatch: true,
});
}
private sanitiseNameInput(val: string) {
return val.replace(window.displayNameRegex, '');
}
private async resetRegistration() {
await removeAll();
await window.storage.reset();
await window.storage.fetch();
ConversationController.getInstance().reset();
await ConversationController.getInstance().load();
this.setState({
secretWords: undefined,
});
} }
private async register() { private async register() {
const { // const {
password, // password,
recoveryPhrase, // recoveryPhrase,
generatedRecoveryPhrase, // generatedRecoveryPhrase,
signInMode, // signInMode,
displayName, // displayName,
passwordErrorString, // passwordErrorString,
passwordFieldsMatch, // passwordFieldsMatch,
} = this.state; // } = this.state;
// Make sure the password is valid // if (signInMode === SignInMode.UsingRecoveryPhrase && !recoveryPhrase) {
window.log.info('starting registration'); // window.log.warn('empty mnemonic seed passed in seed restoration mode');
// return;
const trimName = displayName.trim(); // } else if (!generatedRecoveryPhrase) {
// window.log.warn('empty generated seed');
if (!trimName) { // return;
window.log.warn('invalid trimmed name for registration'); // }
ToastUtils.pushToastError( // const seedToUse =
'invalidDisplayName', // signInMode === SignInMode.UsingRecoveryPhrase
window.i18n('displayNameEmpty') // ? recoveryPhrase
); // : generatedRecoveryPhrase;
return; // try {
} // await this.resetRegistration();
// await window.setPassword(password);
if (passwordErrorString) { // const isRestoringFromSeed = signInMode === SignInMode.UsingRecoveryPhrase;
window.log.warn('invalid password for registration'); // UserUtils.setRestoringFromSeed(isRestoringFromSeed);
ToastUtils.pushToastError( // await window
'invalidPassword', // .getAccountManager()
window.i18n('invalidPassword') // .registerSingleDevice(seedToUse, 'english', trimName);
); // // if we are just creating a new account, no need to wait for a configuration message
return; // if (!isRestoringFromSeed) {
} // trigger('openInbox');
// } else {
if (!!password && !passwordFieldsMatch) { // // We have to pull for all messages of the user of this menmonic
window.log.warn('passwords does not match for registration'); // // We are looking for the most recent ConfigurationMessage he sent to himself.
ToastUtils.pushToastError( // // When we find it, we can just get the displayName, avatar and groups saved in it.
'invalidPassword', // // If we do not find one, we will need to ask for a display name.
window.i18n('passwordsDoNotMatch') // window.log.warn('isRestoringFromSeed');
); // }
return; // } catch (e) {
} // ToastUtils.pushToastError(
// 'registrationError',
if (signInMode === SignInMode.UsingRecoveryPhrase && !recoveryPhrase) { // `Error: ${e.message || 'Something went wrong'}`
window.log.warn('empty mnemonic seed passed in seed restoration mode'); // );
// let exmsg = '';
return; // if (e.message) {
} else if (!generatedRecoveryPhrase) { // exmsg += e.message;
window.log.warn('empty generated seed'); // }
// if (e.stack) {
return; // exmsg += ` | stack: + ${e.stack}`;
} // }
// window.log.warn('exception during registration:', exmsg);
const seedToUse = // }
signInMode === SignInMode.UsingRecoveryPhrase
? recoveryPhrase
: generatedRecoveryPhrase;
try {
await this.resetRegistration();
await window.setPassword(password);
const isRestoringFromSeed = signInMode === SignInMode.UsingRecoveryPhrase;
UserUtils.setRestoringFromSeed(isRestoringFromSeed);
await window
.getAccountManager()
.registerSingleDevice(seedToUse, 'english', trimName);
// if we are just creating a new account, no need to wait for a configuration message
if (!isRestoringFromSeed) {
trigger('openInbox');
} else {
// We have to pull for all messages of the user of this menmonic
// We are looking for the most recent ConfigurationMessage he sent to himself.
// When we find it, we can just get the displayName, avatar and groups saved in it.
// If we do not find one, we will need to ask for a display name.
window.log.warn('isRestoringFromSeed');
}
} catch (e) {
ToastUtils.pushToastError(
'registrationError',
`Error: ${e.message || 'Something went wrong'}`
);
let exmsg = '';
if (e.message) {
exmsg += e.message;
}
if (e.stack) {
exmsg += ` | stack: + ${e.stack}`;
}
window.log.warn('exception during registration:', exmsg);
}
} }
} }

@ -92,26 +92,32 @@ export interface Props {
showDisplayNameField: boolean; showDisplayNameField: boolean;
showSeedField: boolean; showSeedField: boolean;
stealAutoFocus?: boolean; stealAutoFocus?: boolean;
recoveryPhrase: string; recoveryPhrase?: string;
displayName: string; displayName: string;
password: string; password: string;
passwordErrorString: string; passwordErrorString: string;
passwordFieldsMatch: boolean; passwordFieldsMatch: boolean;
handlePressEnter: () => any; handlePressEnter: () => any;
onSeedChanged: (val: string) => any; onSeedChanged?: (val: string) => any;
onDisplayNameChanged: (val: string) => any; onDisplayNameChanged: (val: string) => any;
onPasswordChanged: (val: string) => any; onPasswordChanged: (val: string) => any;
onPasswordVerifyChanged: (val: string) => any; onPasswordVerifyChanged: (val: string) => any;
} }
export const RegistrationUserDetails = (props: Props) => { export const RegistrationUserDetails = (props: Props) => {
if (
props.showSeedField &&
(props.recoveryPhrase === undefined || !props.onSeedChanged)
) {
throw new Error('if show seed is true, we need callback + value');
}
return ( return (
<div className={classNames('session-registration__entry-fields')}> <div className={classNames('session-registration__entry-fields')}>
{props.showSeedField && ( {props.showSeedField && (
<RecoveryPhraseInput <RecoveryPhraseInput
recoveryPhrase={props.recoveryPhrase} recoveryPhrase={props.recoveryPhrase as string}
handlePressEnter={props.handlePressEnter} handlePressEnter={props.handlePressEnter}
onSeedChanged={props.onSeedChanged} onSeedChanged={props.onSeedChanged as any}
/> />
)} )}
<div className="inputfields"> <div className="inputfields">

@ -1,4 +1,12 @@
import React from 'react'; import React, { useState } from 'react';
import {
SessionButton,
SessionButtonColor,
SessionButtonType,
} from '../SessionButton';
import { validatePassword } from './RegistrationTabs';
import { RegistrationUserDetails } from './RegistrationUserDetails';
import { TermsAndConditions } from './TermsAndConditions';
export enum SignInMode { export enum SignInMode {
Default, Default,
@ -7,7 +15,149 @@ export enum SignInMode {
} }
export interface Props { export interface Props {
signInMode: SignInMode; // tslint:disable: react-unused-props-and-state
} }
export const SignInTab = (props: Props) => {}; const LinkDeviceButton = (props: { onLinkDeviceButtonClicked: () => any }) => {
return (
<SessionButton
onClick={props.onLinkDeviceButtonClicked}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
text={window.i18n('linkDevice')}
/>
);
};
const RestoreUsingRecoveryPhraseButton = (props: {
onRecoveryButtonClicked: () => any;
}) => {
return (
<SessionButton
onClick={props.onRecoveryButtonClicked}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
text={window.i18n('restoreUsingRecoveryPhrase')}
/>
);
};
const ContinueYourSessionButton = (props: {
handleContinueYourSessionClick: () => any;
}) => {
return (
<SessionButton
onClick={props.handleContinueYourSessionClick}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('continueYourSession')}
/>
);
};
const SignInButtons = (props: {
signInMode: SignInMode;
onRecoveryButtonClicked: () => any;
onLinkDeviceButtonClicked: () => any;
handleContinueYourSessionClick: () => any;
}) => {
if (props.signInMode === SignInMode.Default) {
return (
<div>
<RestoreUsingRecoveryPhraseButton
onRecoveryButtonClicked={props.onRecoveryButtonClicked}
/>
<div className="or">{window.i18n('or')}</div>
<LinkDeviceButton
onLinkDeviceButtonClicked={props.onLinkDeviceButtonClicked}
/>
</div>
);
}
return (
<ContinueYourSessionButton
handleContinueYourSessionClick={props.handleContinueYourSessionClick}
/>
);
};
export const SignInTab = (props: Props) => {
const [signInMode, setSignInMode] = useState(SignInMode.Default);
const [recoveryPhrase, setRecoveryPhrase] = useState('');
const [recoveryPhraseError, setRecoveryPhraseError] = useState(
undefined as string | undefined
);
const [displayName, setDisplayName] = useState('');
const [displayNameError, setDisplayNameError] = useState('');
const [password, setPassword] = useState('');
const [passwordVerify, setPasswordVerify] = useState('');
const [passwordErrorString, setPasswordErrorString] = useState('');
const [passwordFieldsMatch, setPasswordFieldsMatch] = useState(false);
const showTermsAndConditions = signInMode !== SignInMode.Default;
return (
<div className="session-registration__content">
{signInMode !== SignInMode.Default && (
// tslint:disable: use-simple-attributes
<RegistrationUserDetails
showDisplayNameField={signInMode === SignInMode.UsingRecoveryPhrase}
showSeedField={true}
displayName={displayName}
handlePressEnter={() => {
throw new Error('TODO');
}}
onDisplayNameChanged={(name: string) => {
const sanitizedName = name.replace(window.displayNameRegex, '');
const trimName = sanitizedName.trim();
setDisplayName(sanitizedName);
setDisplayNameError(
!trimName ? window.i18n('displayNameEmpty') : undefined
);
}}
onPasswordChanged={(val: string) => {
setPassword(val);
const errors = validatePassword(val, passwordVerify);
setPasswordErrorString(errors.passwordErrorString);
setPasswordFieldsMatch(errors.passwordFieldsMatch);
}}
onPasswordVerifyChanged={(val: string) => {
setPasswordVerify(val);
const errors = validatePassword(password, val);
setPasswordErrorString(errors.passwordErrorString);
setPasswordFieldsMatch(errors.passwordFieldsMatch);
}}
onSeedChanged={(seed: string) => {
setRecoveryPhrase(seed);
setRecoveryPhraseError(
!seed ? window.i18n('recoveryPhraseEmpty') : undefined
);
}}
password={password}
passwordErrorString={passwordErrorString}
passwordFieldsMatch={passwordFieldsMatch}
recoveryPhrase={recoveryPhrase}
stealAutoFocus={true}
/>
)}
<SignInButtons
signInMode={signInMode}
onRecoveryButtonClicked={() => {
setSignInMode(SignInMode.UsingRecoveryPhrase);
setRecoveryPhrase('');
setDisplayName('');
}}
onLinkDeviceButtonClicked={() => {
setSignInMode(SignInMode.LinkDevice);
setRecoveryPhrase('');
setDisplayName('');
}}
handleContinueYourSessionClick={() => {
throw new Error('TODO');
}}
/>
{showTermsAndConditions && <TermsAndConditions />}
</div>
);
};

@ -1,10 +1,11 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { import {
SessionButton, SessionButton,
SessionButtonColor, SessionButtonColor,
SessionButtonType, SessionButtonType,
} from '../SessionButton'; } from '../SessionButton';
import { SessionIdEditable } from '../SessionIdEditable'; import { SessionIdEditable } from '../SessionIdEditable';
import { signUp, validatePassword } from './RegistrationTabs';
import { RegistrationUserDetails } from './RegistrationUserDetails'; import { RegistrationUserDetails } from './RegistrationUserDetails';
import { TermsAndConditions } from './TermsAndConditions'; import { TermsAndConditions } from './TermsAndConditions';
@ -16,22 +17,8 @@ export enum SignUpMode {
export interface Props { export interface Props {
// tslint:disable: react-unused-props-and-state // tslint:disable: react-unused-props-and-state
signUpMode: SignUpMode; generatedRecoveryPhrase: string;
continueSignUp: () => any; hexGeneratedPubKey: string;
createSessionID: () => any;
onCompleteSignUpClick: () => any;
passwordErrorString: string;
passwordFieldsMatch: boolean;
displayNameError?: string;
displayName: string;
password: string;
recoveryPhrase: string;
stealAutoFocus?: boolean;
handlePressEnter: () => any;
onSeedChanged: (val: string) => any;
onDisplayNameChanged: (val: string) => any;
onPasswordChanged: (val: string) => any;
onPasswordVerifyChanged: (val: string) => any;
} }
const CreateSessionIdButton = ({ const CreateSessionIdButton = ({
@ -60,80 +47,135 @@ const ContinueSignUpButton = ({ continueSignUp }: { continueSignUp: any }) => {
); );
}; };
const SignUpDefault = (props: { createSessionID: () => void }) => {
const allUsersAreRandomly = window.i18n('allUsersAreRandomly...');
return (
<div className="session-registration__content">
<div className="session-description-long">{allUsersAreRandomly}</div>
<CreateSessionIdButton createSessionID={props.createSessionID} />
</div>
);
};
const SignUpSessionIDShown = (props: { continueSignUp: () => void }) => {
return (
<div className="session-registration__content">
<div className="session-registration__unique-session-id">
{window.i18n('yourUniqueSessionID')}
</div>
<SessionIdEditable editable={false} placeholder={undefined} />
<ContinueSignUpButton continueSignUp={props.continueSignUp} />
<TermsAndConditions />
</div>
);
};
export const SignUpTab = (props: Props) => { export const SignUpTab = (props: Props) => {
const { signUpMode, continueSignUp, createSessionID } = props; const [signUpMode, setSignUpMode] = useState(SignUpMode.Default);
switch (signUpMode) { const [displayName, setDisplayName] = useState('');
case SignUpMode.Default: const [password, setPassword] = useState('');
const allUsersAreRandomly = window.i18n('allUsersAreRandomly...'); const [passwordVerify, setPasswordVerify] = useState('');
const [passwordErrorString, setPasswordErrorString] = useState('');
return ( const [displayNameError, setDisplayNameError] = useState('');
<div className="session-registration__content"> const [passwordFieldsMatch, setPasswordFieldsMatch] = useState(false);
<div className="session-description-long">{allUsersAreRandomly}</div>
<CreateSessionIdButton createSessionID={createSessionID} /> useEffect(() => {
</div> if (signUpMode === SignUpMode.SessionIDShown) {
); window.Session.setNewSessionID(props.hexGeneratedPubKey);
}
case SignUpMode.SessionIDShown: }, [signUpMode]);
return (
<div className="session-registration__content"> if (signUpMode === SignUpMode.Default) {
<div className="session-registration__unique-session-id"> return (
{window.i18n('yourUniqueSessionID')} <SignUpDefault
</div> createSessionID={() => {
setSignUpMode(SignUpMode.SessionIDShown);
<SessionIdEditable editable={false} placeholder={undefined} /> }}
<ContinueSignUpButton continueSignUp={continueSignUp} /> />
<TermsAndConditions /> );
</div> }
);
if (signUpMode === SignUpMode.SessionIDShown) {
// can only be the EnterDetails step return (
default: <SignUpSessionIDShown
const { continueSignUp={() => {
passwordErrorString, setSignUpMode(SignUpMode.EnterDetails);
passwordFieldsMatch, }}
displayNameError, />
displayName, );
password,
} = props;
let enableCompleteSignUp = true;
const displayNameOK = !displayNameError && !!displayName; //display name required
const passwordsOK =
!password || (!passwordErrorString && passwordFieldsMatch); // password is valid if empty, or if no error and fields are matching
enableCompleteSignUp = displayNameOK && passwordsOK;
return (
<div className="session-registration__content">
<div className="session-registration__welcome-session">
{window.i18n('welcomeToYourSession')}
</div>
<RegistrationUserDetails
showDisplayNameField={true}
showSeedField={false}
displayName={props.displayName}
handlePressEnter={props.handlePressEnter}
onDisplayNameChanged={props.onDisplayNameChanged}
onPasswordChanged={props.onPasswordChanged}
onPasswordVerifyChanged={props.onPasswordVerifyChanged}
onSeedChanged={props.onSeedChanged}
password={props.password}
passwordErrorString={props.passwordErrorString}
passwordFieldsMatch={props.passwordFieldsMatch}
recoveryPhrase={props.recoveryPhrase}
stealAutoFocus={true}
/>
<SessionButton
onClick={props.onCompleteSignUpClick}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('getStarted')}
disabled={!enableCompleteSignUp}
/>
<TermsAndConditions />
</div>
);
} }
// can only be the EnterDetails step
// Display name is required
const displayNameOK = !displayNameError && !!displayName;
// Password is valid if empty, or if no error and fields are matching
const passwordsOK =
!password || (!passwordErrorString && passwordFieldsMatch);
const enableCompleteSignUp = displayNameOK && passwordsOK;
return (
<div className="session-registration__content">
<div className="session-registration__welcome-session">
{window.i18n('welcomeToYourSession')}
</div>
<RegistrationUserDetails
showDisplayNameField={true}
showSeedField={false}
displayName={displayName}
handlePressEnter={() => {
throw new Error('TODO');
}}
onDisplayNameChanged={(name: string) => {
const sanitizedName = name.replace(window.displayNameRegex, '');
const trimName = sanitizedName.trim();
setDisplayName(sanitizedName);
setDisplayNameError(
!trimName ? window.i18n('displayNameEmpty') : undefined
);
}}
onPasswordChanged={(val: string) => {
setPassword(val);
if (!val) {
setPasswordErrorString('');
setPasswordFieldsMatch(true);
setPasswordVerify('');
return;
}
const errors = validatePassword(val, passwordVerify);
setPasswordErrorString(errors.passwordErrorString);
setPasswordFieldsMatch(errors.passwordFieldsMatch);
}}
onPasswordVerifyChanged={(val: string) => {
setPasswordVerify(val);
const errors = validatePassword(password, val);
setPasswordErrorString(errors.passwordErrorString);
setPasswordFieldsMatch(errors.passwordFieldsMatch);
}}
password={password}
passwordErrorString={passwordErrorString}
passwordFieldsMatch={passwordFieldsMatch}
stealAutoFocus={true}
/>
<SessionButton
onClick={async () => {
await signUp({
displayName,
generatedRecoveryPhrase: props.generatedRecoveryPhrase,
password,
verifyPassword: passwordVerify,
});
}}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('getStarted')}
disabled={!enableCompleteSignUp}
/>
<TermsAndConditions />
</div>
);
}; };

Loading…
Cancel
Save