split up registration signup tab logic to sub components

This commit is contained in:
Audric Ackermann 2021-02-26 11:27:29 +11:00
parent c55f204440
commit 01085244bd
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4
20 changed files with 482 additions and 404 deletions

View File

@ -508,7 +508,7 @@
"welcomeToYourSession": {
"message": "Willkommen bei Session"
},
"generateSessionID": {
"createSessionID": {
"message": "Session ID erstellen"
},
"yourUniqueSessionID": {
@ -1410,9 +1410,6 @@
"enterDisplayName": {
"message": "Geben Sie einen Anzeigenamen ein"
},
"enterSessionIDHere": {
"message": "Geben Sie Ihre Session ID ein."
},
"continueYourSession": {
"message": "Ihre Session fortsetzen"
},

View File

@ -2008,7 +2008,7 @@
"getStarted": {
"message": "Get started"
},
"generateSessionID": {
"createSessionID": {
"message": "Create Session ID",
"androidKey": "activity_landing_register_button_title"
},
@ -2050,10 +2050,6 @@
"devicePairingHeader_Step4": {
"message": "Enter your <strong>Session ID</strong> below to link this device to your <strong>Session ID</strong>."
},
"enterSessionIDHere": {
"message": "Enter your Session ID",
"androidKey": "fragment_enter_session_id_edit_text_hint"
},
"continueYourSession": {
"message": "Continue Your Session",
"androidKey": "activity_landing_restore_button_title"

View File

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": {
"message": "Tu ID de Session es la dirección única que las personas pueden usar para contactarte en Session. Por diseño, tu ID de Session es totalmente anónima y privada, sin vínculo con tu identidad real."
},
"generateSessionID": {
"createSessionID": {
"message": "Crear ID de Session"
},
"recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": {
"message": "Ingresa un nombre para mostrar"
},
"enterSessionIDHere": {
"message": "Ingresa tu ID de Session"
},
"continueYourSession": {
"message": "Continúa tu Session"
},

View File

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": {
"message": "Votre Session ID est l'identifiant unique que les gens utilisent pour vous contacter dans Session. Sans lien avec votre identité réelle, votre Session ID est complètement anonyme et privé."
},
"generateSessionID": {
"createSessionID": {
"message": "Créer un Session ID"
},
"recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": {
"message": "Saisissez un nom d'utilisateur"
},
"enterSessionIDHere": {
"message": "Saisissez votre Session ID"
},
"continueYourSession": {
"message": "Continuez votre Session"
},

View File

@ -1302,7 +1302,7 @@
"allUsersAreRandomly...": {
"message": "Session ID adalah alamat unik yang bisa digunakan untuk mengontak anda. Tanpa koneksi dengan identitas asli, Session ID anda didesain bersifat anonim dan rahasia."
},
"generateSessionID": {
"createSessionID": {
"message": "Buat Session ID"
},
"recoveryPhrase": {
@ -1314,9 +1314,6 @@
"enterDisplayName": {
"message": "Masukkan nama"
},
"enterSessionIDHere": {
"message": "Masuk ke Session ID"
},
"continueYourSession": {
"message": "Lanjutkan Session"
},

View File

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": {
"message": "La Sessione ID è l'indirizzo univoco che le persone possono utilizzare per contattarti su una Sessione. Senza alcuna connessione con la tua vera identità, la Sessione ID è totalmente anonimo e privato fin dal incezione."
},
"generateSessionID": {
"createSessionID": {
"message": "Crea Sessione ID"
},
"recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": {
"message": "Inserisci il nome da visualizzare"
},
"enterSessionIDHere": {
"message": "Inserisci la Sessione ID"
},
"continueYourSession": {
"message": "Continua la Sessione"
},

View File

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": {
"message": "Session ID は、Session で連絡を取るために使用できる一意のアドレスです。本当のアイデンティティに関係なく、あなたの Session ID は設計上完全に匿名でプライベートです。"
},
"generateSessionID": {
"createSessionID": {
"message": "Session ID を作成する"
},
"recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": {
"message": "表示名を入力してください"
},
"enterSessionIDHere": {
"message": "Session ID を入力してください"
},
"continueYourSession": {
"message": "Session を続ける"
},

View File

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": {
"message": "Twój identyfikator Session to unikalny adres, za pomocą którego można się z Tobą kontaktować w Sesji. Bez połączenia z twoją prawdziwą tożsamością, identyfikator Session jest z założenia całkowicie anonimowy i prywatny."
},
"generateSessionID": {
"createSessionID": {
"message": "Utwórz identyfikator Session"
},
"recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": {
"message": "Wprowadź wyświetlaną nazwe"
},
"enterSessionIDHere": {
"message": "Wpisz swój identyfikator Session"
},
"continueYourSession": {
"message": "Kontynuuj swoją sesję"
},

View File

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": {
"message": "Seu ID Session é o endereço exclusivo que as pessoas podem usar para entrar em contato com você no Session. Sem conexão com sua identidade real, seu ID Session é totalmente anônimo e privado por definição."
},
"generateSessionID": {
"createSessionID": {
"message": "Criar ID Session"
},
"recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": {
"message": "Digite um nome de exibição"
},
"enterSessionIDHere": {
"message": "Digite seu ID Session"
},
"continueYourSession": {
"message": "Continuar com seu Session"
},

View File

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": {
"message": "Ваш Session ID - это уникальный адрес, который другие пользователи могут использовать для связи с вами при помощи Session. Поскольку ваш Session ID никак не связан с вашей настоящей личностью, он по определению является полностью анонимным и конфиденциальным."
},
"generateSessionID": {
"createSessionID": {
"message": "Создать Session ID"
},
"recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": {
"message": "Введите отображаемое имя"
},
"enterSessionIDHere": {
"message": "Введите свой Session ID"
},
"continueYourSession": {
"message": "Восстановить Session ID"
},

View File

@ -1272,7 +1272,7 @@
"allUsersAreRandomly...": {
"message": "Session ID của bạn là địa chỉ duy nhất mà mọi người có thể dùng để liên lạc với bạn trên ứng dụng Session. Session ID của bạn được thiết kế đảm bảo tuyệt đối ẩn danh và riêng tư vì nó không liên kết với danh tính thật của bạn."
},
"generateSessionID": {
"createSessionID": {
"message": "Tạo Session ID"
},
"recoveryPhrase": {
@ -1284,9 +1284,6 @@
"enterDisplayName": {
"message": "Nhập một tên hiển thị"
},
"enterSessionIDHere": {
"message": "Nhập Session ID của bạn"
},
"continueYourSession": {
"message": "Tiếp tục Session của bạn"
},

View File

@ -19,7 +19,7 @@ import { SessionModal } from './session/SessionModal';
import { PillDivider } from './session/PillDivider';
import { ToastUtils, UserUtils } from '../session/utils';
import { DefaultTheme } from 'styled-components';
import { MAX_USERNAME_LENGTH } from './session/RegistrationTabs';
import { MAX_USERNAME_LENGTH } from './session/registration/RegistrationTabs';
interface Props {
i18n: any;

View File

@ -1,7 +1,7 @@
import React from 'react';
import { AccentText } from './AccentText';
import { RegistrationTabs } from './RegistrationTabs';
import { RegistrationTabs } from './registration/RegistrationTabs';
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
import { SessionToastContainer } from './SessionToastContainer';
import { lightTheme, SessionTheme } from '../../state/ducks/SessionTheme';

View File

@ -1,39 +1,23 @@
import React from 'react';
import classNames from 'classnames';
import { SessionInput } from './SessionInput';
import {
SessionButton,
SessionButtonColor,
SessionButtonType,
} from './SessionButton';
import { trigger } from '../../shims/events';
import { SessionHtmlRenderer } from './SessionHTMLRenderer';
import { SessionIdEditable } from './SessionIdEditable';
import { StringUtils, ToastUtils, UserUtils } from '../../session/utils';
import { lightTheme } from '../../state/ducks/SessionTheme';
import { ConversationController } from '../../session/conversations';
import { PasswordUtil } from '../../util';
import { removeAll } from '../../data/data';
} from '../SessionButton';
import { trigger } from '../../../shims/events';
import { StringUtils, ToastUtils, UserUtils } from '../../../session/utils';
import { ConversationController } from '../../../session/conversations';
import { PasswordUtil } from '../../../util';
import { removeAll } from '../../../data/data';
import { SignUpMode, SignUpTab } from './SignUpTab';
import { SignInMode } from './SignInTab';
import { RegistrationUserDetails } from './RegistrationUserDetails';
import { TermsAndConditions } from './TermsAndConditions';
import { TabLabel, TabType } from './TabLabel';
export const MAX_USERNAME_LENGTH = 20;
enum SignInMode {
Default,
UsingRecoveryPhrase,
}
enum SignUpMode {
Default,
SessionIDShown,
EnterDetails,
}
enum TabType {
Create,
SignIn,
}
interface State {
selectedTab: TabType;
signInMode: SignInMode;
@ -47,46 +31,11 @@ interface State {
recoveryPhrase: string;
generatedRecoveryPhrase: string;
hexGeneratedPubKey: string;
primaryDevicePubKey: string;
mnemonicError: string | undefined;
displayNameError: string | undefined;
loading: boolean;
}
const Tab = ({
isSelected,
label,
onSelect,
type,
}: {
isSelected: boolean;
label: string;
onSelect?: (event: TabType) => void;
type: TabType;
}) => {
const handleClick = onSelect
? () => {
onSelect(type);
}
: undefined;
return (
<div
className={classNames(
'session-registration__tab',
isSelected ? 'session-registration__tab--active' : null
)}
onClick={handleClick}
role="tab"
>
{label}
</div>
);
};
export class RegistrationTabs extends React.Component<any, State> {
private readonly accountManager: any;
constructor(props: any) {
super(props);
@ -94,21 +43,14 @@ export class RegistrationTabs extends React.Component<any, State> {
this.onDisplayNameChanged = this.onDisplayNameChanged.bind(this);
this.onPasswordChanged = this.onPasswordChanged.bind(this);
this.onPasswordVerifyChanged = this.onPasswordVerifyChanged.bind(this);
this.onSignUpGenerateSessionIDClick = this.onSignUpGenerateSessionIDClick.bind(
this
);
this.onSignUpGetStartedClick = this.onSignUpGetStartedClick.bind(this);
this.onSecondDeviceSessionIDChanged = this.onSecondDeviceSessionIDChanged.bind(
this
);
this.onCompleteSignUpClick = this.onCompleteSignUpClick.bind(this);
this.handlePressEnter = this.handlePressEnter.bind(this);
this.handleContinueYourSessionClick = this.handleContinueYourSessionClick.bind(
this
);
this.onCompleteSignUpClick = this.onCompleteSignUpClick.bind(this);
this.state = {
selectedTab: TabType.Create,
selectedTab: TabType.SignUp,
signInMode: SignInMode.Default,
signUpMode: SignUpMode.Default,
secretWords: undefined,
@ -120,14 +62,9 @@ export class RegistrationTabs extends React.Component<any, State> {
recoveryPhrase: '',
generatedRecoveryPhrase: '',
hexGeneratedPubKey: '',
primaryDevicePubKey: '',
mnemonicError: undefined,
displayNameError: undefined,
loading: false,
};
this.accountManager = window.getAccountManager();
// Clean status in case the app closed unexpectedly
}
public componentDidMount() {
@ -137,25 +74,19 @@ export class RegistrationTabs extends React.Component<any, State> {
public render() {
const { selectedTab } = this.state;
const createAccount = window.i18n('createAccount');
const signIn = window.i18n('signIn');
const isCreateSelected = selectedTab === TabType.Create;
const isSignInSelected = selectedTab === TabType.SignIn;
// tslint:disable: use-simple-attributes
return (
<div className="session-registration-container">
<div className="session-registration__tab-container">
<Tab
label={createAccount}
type={TabType.Create}
isSelected={isCreateSelected}
<TabLabel
type={TabType.SignUp}
isSelected={selectedTab === TabType.SignUp}
onSelect={this.handleTabSelect}
/>
<Tab
label={signIn}
<TabLabel
type={TabType.SignIn}
isSelected={isSignInSelected}
isSelected={selectedTab === TabType.SignIn}
onSelect={this.handleTabSelect}
/>
</div>
@ -167,7 +98,9 @@ export class RegistrationTabs extends React.Component<any, State> {
private async generateMnemonicAndKeyPair() {
if (this.state.generatedRecoveryPhrase === '') {
const language = 'english';
const mnemonic = await this.accountManager.generateMnemonic(language);
const mnemonic = await window
.getAccountManager()
.generateMnemonic(language);
let seedHex = window.mnemonic.mn_decode(mnemonic, language);
// handle shorter than 32 bytes seeds
@ -201,7 +134,6 @@ export class RegistrationTabs extends React.Component<any, State> {
passwordErrorString: '',
passwordFieldsMatch: false,
recoveryPhrase: '',
primaryDevicePubKey: '',
mnemonicError: undefined,
displayNameError: undefined,
});
@ -239,143 +171,54 @@ export class RegistrationTabs extends React.Component<any, State> {
private renderSections() {
const { selectedTab } = this.state;
if (selectedTab === TabType.Create) {
return this.renderSignUp();
if (selectedTab === TabType.SignUp) {
return (
<SignUpTab
signUpMode={this.state.signUpMode}
continueSignUp={() => {
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();
}
private renderSignUp() {
const { signUpMode } = this.state;
switch (signUpMode) {
case SignUpMode.Default:
return (
<div className="session-registration__content">
{this.renderSignUpHeader()}
{this.renderSignUpButton()}
</div>
);
case SignUpMode.SessionIDShown:
return (
<div className="session-registration__content">
{this.renderSignUpHeader()}
<div className="session-registration__unique-session-id">
{window.i18n('yourUniqueSessionID')}
</div>
{this.renderEnterSessionID(false)}
{this.renderSignUpButton()}
{this.getRenderTermsConditionAgreement()}
</div>
);
default:
const {
passwordErrorString,
passwordFieldsMatch,
displayNameError,
displayName,
password,
} = this.state;
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>
{this.renderRegistrationContent()}
<SessionButton
onClick={this.onCompleteSignUpClick}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('getStarted')}
disabled={!enableCompleteSignUp}
/>
</div>
);
}
}
private getRenderTermsConditionAgreement() {
const { selectedTab, signInMode, signUpMode } = this.state;
if (selectedTab === TabType.Create) {
return signUpMode !== SignUpMode.Default
? this.renderTermsConditionAgreement()
: null;
} else {
return signInMode !== SignInMode.Default
? this.renderTermsConditionAgreement()
: null;
const { selectedTab, signInMode } = this.state;
if (selectedTab !== TabType.SignUp) {
return signInMode !== SignInMode.Default ? <TermsAndConditions /> : null;
}
}
private renderSignUpHeader() {
const allUsersAreRandomly = window.i18n('allUsersAreRandomly...');
return (
<div className="session-description-long">{allUsersAreRandomly}</div>
);
}
private renderSignUpButton() {
const { signUpMode } = this.state;
let buttonType: SessionButtonType;
let buttonColor: SessionButtonColor;
let buttonText: string;
if (signUpMode !== SignUpMode.Default) {
buttonType = SessionButtonType.Brand;
buttonColor = SessionButtonColor.Green;
buttonText = window.i18n('continue');
} else {
buttonType = SessionButtonType.BrandOutline;
buttonColor = SessionButtonColor.Green;
buttonText = window.i18n('generateSessionID');
}
return (
<SessionButton
onClick={() => {
if (signUpMode === SignUpMode.Default) {
this.onSignUpGenerateSessionIDClick();
} else {
this.onSignUpGetStartedClick();
}
}}
buttonType={buttonType}
buttonColor={buttonColor}
text={buttonText}
/>
);
}
private onSignUpGenerateSessionIDClick() {
this.setState(
{
signUpMode: SignUpMode.SessionIDShown,
},
() => {
window.Session.setNewSessionID(this.state.hexGeneratedPubKey);
}
);
}
private onSignUpGetStartedClick() {
this.setState({
signUpMode: SignUpMode.EnterDetails,
});
return <></>;
}
private onCompleteSignUpClick() {
void this.register('english');
void this.register();
}
private renderSignIn() {
@ -390,133 +233,60 @@ export class RegistrationTabs extends React.Component<any, State> {
}
private renderRegistrationContent() {
const { signInMode, signUpMode } = this.state;
const { signInMode } = this.state;
if (signInMode === SignInMode.UsingRecoveryPhrase) {
return (
<div className={classNames('session-registration__entry-fields')}>
<SessionInput
label={window.i18n('recoveryPhrase')}
type="password"
autoFocus={true}
placeholder={window.i18n('enterRecoveryPhrase')}
enableShowHide={true}
onValueChanged={(val: string) => {
this.onSeedChanged(val);
}}
onEnterPressed={() => {
this.handlePressEnter();
}}
theme={lightTheme}
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}
/>
{this.renderNamePasswordAndVerifyPasswordFields(false)}
</div>
);
}
);
}
if (signUpMode === SignUpMode.EnterDetails) {
return (
<div className={classNames('session-registration__entry-fields')}>
{this.renderNamePasswordAndVerifyPasswordFields(true)}
</div>
);
if (signInMode === SignInMode.LinkDevice) {
return (
<RegistrationUserDetails
showDisplayNameField={false}
showSeedField={true}
{...sharedProps}
/>
);
}
}
return null;
}
private renderNamePasswordAndVerifyPasswordFields(
stealAutoFocus: boolean = false
) {
const { password, passwordFieldsMatch } = this.state;
const passwordsDoNotMatch =
!passwordFieldsMatch && this.state.password
? window.i18n('passwordsDoNotMatch')
: undefined;
return (
<div className="inputfields">
<SessionInput
autoFocus={stealAutoFocus}
label={window.i18n('displayName')}
type="text"
placeholder={window.i18n('enterDisplayName')}
value={this.state.displayName}
maxLength={MAX_USERNAME_LENGTH}
onValueChanged={(val: string) => {
this.onDisplayNameChanged(val);
}}
onEnterPressed={() => {
this.handlePressEnter();
}}
theme={lightTheme}
/>
<SessionInput
label={window.i18n('password')}
error={this.state.passwordErrorString}
type="password"
placeholder={window.i18n('enterOptionalPassword')}
onValueChanged={(val: string) => {
this.onPasswordChanged(val);
}}
onEnterPressed={() => {
this.handlePressEnter();
}}
theme={lightTheme}
/>
{!!password && (
<SessionInput
label={window.i18n('confirmPassword')}
error={passwordsDoNotMatch}
type="password"
placeholder={window.i18n('confirmPassword')}
onValueChanged={(val: string) => {
this.onPasswordVerifyChanged(val);
}}
onEnterPressed={() => {
this.handlePressEnter();
}}
theme={lightTheme}
/>
)}
</div>
);
}
private renderEnterSessionID(contentEditable: boolean) {
const enterSessionIDHere = window.i18n('enterSessionIDHere');
return (
<SessionIdEditable
editable={contentEditable}
placeholder={enterSessionIDHere}
onChange={(value: string) => {
this.onSecondDeviceSessionIDChanged(value);
}}
/>
);
}
private onSecondDeviceSessionIDChanged(value: string) {
this.setState({
primaryDevicePubKey: value,
});
}
private renderSignInButtons() {
const { signInMode } = this.state;
// const or = window.i18n('or');
const or = window.i18n('or');
if (signInMode === SignInMode.Default) {
return (
<div>
{this.renderRestoreUsingRecoveryPhraseButton(
SessionButtonType.BrandOutline,
SessionButtonColor.Green
)}
{this.renderRestoreUsingRecoveryPhraseButton()}
<div className="or">{or}</div>
{this.renderLinkDeviceButton()}
</div>
);
}
@ -532,41 +302,51 @@ export class RegistrationTabs extends React.Component<any, State> {
}
private renderTermsConditionAgreement() {
return (
<div className="session-terms-conditions-agreement">
<SessionHtmlRenderer html={window.i18n('ByUsingThisService...')} />
</div>
);
return <TermsAndConditions />;
}
private handleContinueYourSessionClick() {
if (this.state.signInMode === SignInMode.UsingRecoveryPhrase) {
void this.register('english');
void this.register();
}
}
private renderRestoreUsingRecoveryPhraseButton(
buttonType: SessionButtonType,
buttonColor: SessionButtonColor
) {
private renderRestoreUsingRecoveryPhraseButton() {
return (
<SessionButton
onClick={() => {
this.setState({
signInMode: SignInMode.UsingRecoveryPhrase,
primaryDevicePubKey: '',
recoveryPhrase: '',
displayName: '',
signUpMode: SignUpMode.Default,
});
}}
buttonType={buttonType}
buttonColor={buttonColor}
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) {
@ -631,17 +411,17 @@ export class RegistrationTabs extends React.Component<any, State> {
private async resetRegistration() {
await removeAll();
await window.storage.reset();
await window.storage.fetch();
ConversationController.getInstance().reset();
await ConversationController.getInstance().load();
this.setState({
loading: false,
secretWords: undefined,
});
}
private async register(language: string) {
private async register() {
const {
password,
recoveryPhrase,
@ -705,11 +485,9 @@ export class RegistrationTabs extends React.Component<any, State> {
const isRestoringFromSeed = signInMode === SignInMode.UsingRecoveryPhrase;
UserUtils.setRestoringFromSeed(isRestoringFromSeed);
await this.accountManager.registerSingleDevice(
seedToUse,
language,
trimName
);
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');

View File

@ -0,0 +1,137 @@
import classNames from 'classnames';
import React from 'react';
import { lightTheme } from '../../../state/ducks/SessionTheme';
import { SessionInput } from '../SessionInput';
import { MAX_USERNAME_LENGTH } from './RegistrationTabs';
const DisplayNameInput = (props: {
stealAutoFocus?: boolean;
displayName: string;
onDisplayNameChanged: (val: string) => any;
handlePressEnter: () => any;
}) => {
return (
// tslint:disable-next-line: use-simple-attributes
<SessionInput
autoFocus={props.stealAutoFocus || false}
label={window.i18n('displayName')}
type="text"
placeholder={window.i18n('enterDisplayName')}
value={props.displayName}
maxLength={MAX_USERNAME_LENGTH}
onValueChanged={props.onDisplayNameChanged}
onEnterPressed={props.handlePressEnter}
theme={lightTheme}
/>
);
};
const RecoveryPhraseInput = (props: {
recoveryPhrase: string;
onSeedChanged: (val: string) => any;
handlePressEnter: () => any;
}) => {
return (
<SessionInput
label={window.i18n('recoveryPhrase')}
type="password"
value={props.recoveryPhrase}
autoFocus={true}
placeholder={window.i18n('enterRecoveryPhrase')}
enableShowHide={true}
onValueChanged={props.onSeedChanged}
onEnterPressed={props.handlePressEnter}
theme={lightTheme}
/>
);
};
const PasswordAndVerifyPasswordFields = (props: {
password: string;
passwordFieldsMatch: boolean;
passwordErrorString: string;
onPasswordChanged: (val: string) => any;
onPasswordVerifyChanged: (val: string) => any;
handlePressEnter: () => any;
}) => {
const { password, passwordFieldsMatch, passwordErrorString } = props;
const passwordsDoNotMatch =
!passwordFieldsMatch && password
? window.i18n('passwordsDoNotMatch')
: undefined;
return (
<>
<SessionInput
label={window.i18n('password')}
error={passwordErrorString}
type="password"
placeholder={window.i18n('enterOptionalPassword')}
onValueChanged={props.onPasswordChanged}
onEnterPressed={props.handlePressEnter}
theme={lightTheme}
/>
{!!password && (
<SessionInput
label={window.i18n('confirmPassword')}
error={passwordsDoNotMatch}
type="password"
placeholder={window.i18n('confirmPassword')}
onValueChanged={props.onPasswordVerifyChanged}
onEnterPressed={props.handlePressEnter}
theme={lightTheme}
/>
)}
</>
);
};
export interface Props {
// tslint:disable: react-unused-props-and-state
showDisplayNameField: boolean;
showSeedField: boolean;
stealAutoFocus?: boolean;
recoveryPhrase: string;
displayName: string;
password: string;
passwordErrorString: string;
passwordFieldsMatch: boolean;
handlePressEnter: () => any;
onSeedChanged: (val: string) => any;
onDisplayNameChanged: (val: string) => any;
onPasswordChanged: (val: string) => any;
onPasswordVerifyChanged: (val: string) => any;
}
export const RegistrationUserDetails = (props: Props) => {
return (
<div className={classNames('session-registration__entry-fields')}>
{props.showSeedField && (
<RecoveryPhraseInput
recoveryPhrase={props.recoveryPhrase}
handlePressEnter={props.handlePressEnter}
onSeedChanged={props.onSeedChanged}
/>
)}
<div className="inputfields">
{props.showDisplayNameField && (
<DisplayNameInput
stealAutoFocus={props.stealAutoFocus}
displayName={props.displayName}
handlePressEnter={props.handlePressEnter}
onDisplayNameChanged={props.onDisplayNameChanged}
/>
)}
<PasswordAndVerifyPasswordFields
handlePressEnter={props.handlePressEnter}
onPasswordChanged={props.onPasswordChanged}
onPasswordVerifyChanged={props.onPasswordVerifyChanged}
passwordErrorString={props.passwordErrorString}
password={props.password}
passwordFieldsMatch={props.passwordFieldsMatch}
/>
</div>
</div>
);
};

View File

@ -0,0 +1,13 @@
import React from 'react';
export enum SignInMode {
Default,
UsingRecoveryPhrase,
LinkDevice,
}
export interface Props {
signInMode: SignInMode;
}
export const SignInTab = (props: Props) => {};

View File

@ -0,0 +1,139 @@
import React from 'react';
import {
SessionButton,
SessionButtonColor,
SessionButtonType,
} from '../SessionButton';
import { SessionIdEditable } from '../SessionIdEditable';
import { RegistrationUserDetails } from './RegistrationUserDetails';
import { TermsAndConditions } from './TermsAndConditions';
export enum SignUpMode {
Default,
SessionIDShown,
EnterDetails,
}
export interface Props {
// tslint:disable: react-unused-props-and-state
signUpMode: SignUpMode;
continueSignUp: () => any;
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 = ({
createSessionID,
}: {
createSessionID: any;
}) => {
return (
<SessionButton
onClick={createSessionID}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
text={window.i18n('createSessionID')}
/>
);
};
const ContinueSignUpButton = ({ continueSignUp }: { continueSignUp: any }) => {
return (
<SessionButton
onClick={continueSignUp}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('continue')}
/>
);
};
export const SignUpTab = (props: Props) => {
const { signUpMode, continueSignUp, createSessionID } = props;
switch (signUpMode) {
case SignUpMode.Default:
const allUsersAreRandomly = window.i18n('allUsersAreRandomly...');
return (
<div className="session-registration__content">
<div className="session-description-long">{allUsersAreRandomly}</div>
<CreateSessionIdButton createSessionID={createSessionID} />
</div>
);
case SignUpMode.SessionIDShown:
return (
<div className="session-registration__content">
<div className="session-registration__unique-session-id">
{window.i18n('yourUniqueSessionID')}
</div>
<SessionIdEditable editable={false} placeholder={undefined} />
<ContinueSignUpButton continueSignUp={continueSignUp} />
<TermsAndConditions />
</div>
);
// can only be the EnterDetails step
default:
const {
passwordErrorString,
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>
);
}
};

View File

@ -0,0 +1,42 @@
import classNames from 'classnames';
import React from 'react';
import { SignUpMode, SignUpTab } from './SignUpTab';
export enum TabType {
SignUp,
SignIn,
}
export const TabLabel = ({
isSelected,
onSelect,
type,
}: {
isSelected: boolean;
onSelect?: (event: TabType) => void;
type: TabType;
}) => {
const handleClick = onSelect
? () => {
onSelect(type);
}
: undefined;
const label =
type === TabType.SignUp
? window.i18n('createAccount')
: window.i18n('signIn');
return (
<div
className={classNames(
'session-registration__tab',
isSelected ? 'session-registration__tab--active' : null
)}
onClick={handleClick}
role="tab"
>
{label}
</div>
);
};

View File

@ -0,0 +1,10 @@
import React from 'react';
import { SessionHtmlRenderer } from '../SessionHTMLRenderer';
export const TermsAndConditions = () => {
return (
<div className="session-terms-conditions-agreement">
<SessionHtmlRenderer html={window.i18n('ByUsingThisService...')} />
</div>
);
};

View File

@ -70,15 +70,8 @@ export async function getUserED25519KeyPair(): Promise<HexKeyPair | undefined> {
return undefined;
}
/**
* Returns the public key of this current device as a STRING, or throws an error
*/
export function isRestoringFromSeed(): boolean {
const ourNumber = window.textsecure.storage.user.isRestoringFromSeed();
if (!ourNumber) {
throw new Error('ourNumber is not set');
}
return ourNumber;
return window.textsecure.storage.user.isRestoringFromSeed();
}
export function setRestoringFromSeed(isRestoring: boolean) {