split up registration signup tab logic to sub components

pull/1528/head
Audric Ackermann 4 years ago
parent c55f204440
commit 01085244bd
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

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

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

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": { "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." "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" "message": "Crear ID de Session"
}, },
"recoveryPhrase": { "recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": { "enterDisplayName": {
"message": "Ingresa un nombre para mostrar" "message": "Ingresa un nombre para mostrar"
}, },
"enterSessionIDHere": {
"message": "Ingresa tu ID de Session"
},
"continueYourSession": { "continueYourSession": {
"message": "Continúa tu Session" "message": "Continúa tu Session"
}, },

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": { "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é." "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" "message": "Créer un Session ID"
}, },
"recoveryPhrase": { "recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": { "enterDisplayName": {
"message": "Saisissez un nom d'utilisateur" "message": "Saisissez un nom d'utilisateur"
}, },
"enterSessionIDHere": {
"message": "Saisissez votre Session ID"
},
"continueYourSession": { "continueYourSession": {
"message": "Continuez votre Session" "message": "Continuez votre Session"
}, },

@ -1302,7 +1302,7 @@
"allUsersAreRandomly...": { "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." "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" "message": "Buat Session ID"
}, },
"recoveryPhrase": { "recoveryPhrase": {
@ -1314,9 +1314,6 @@
"enterDisplayName": { "enterDisplayName": {
"message": "Masukkan nama" "message": "Masukkan nama"
}, },
"enterSessionIDHere": {
"message": "Masuk ke Session ID"
},
"continueYourSession": { "continueYourSession": {
"message": "Lanjutkan Session" "message": "Lanjutkan Session"
}, },

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": { "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." "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" "message": "Crea Sessione ID"
}, },
"recoveryPhrase": { "recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": { "enterDisplayName": {
"message": "Inserisci il nome da visualizzare" "message": "Inserisci il nome da visualizzare"
}, },
"enterSessionIDHere": {
"message": "Inserisci la Sessione ID"
},
"continueYourSession": { "continueYourSession": {
"message": "Continua la Sessione" "message": "Continua la Sessione"
}, },

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

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": { "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." "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" "message": "Utwórz identyfikator Session"
}, },
"recoveryPhrase": { "recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": { "enterDisplayName": {
"message": "Wprowadź wyświetlaną nazwe" "message": "Wprowadź wyświetlaną nazwe"
}, },
"enterSessionIDHere": {
"message": "Wpisz swój identyfikator Session"
},
"continueYourSession": { "continueYourSession": {
"message": "Kontynuuj swoją sesję" "message": "Kontynuuj swoją sesję"
}, },

@ -1308,7 +1308,7 @@
"allUsersAreRandomly...": { "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." "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" "message": "Criar ID Session"
}, },
"recoveryPhrase": { "recoveryPhrase": {
@ -1320,9 +1320,6 @@
"enterDisplayName": { "enterDisplayName": {
"message": "Digite um nome de exibição" "message": "Digite um nome de exibição"
}, },
"enterSessionIDHere": {
"message": "Digite seu ID Session"
},
"continueYourSession": { "continueYourSession": {
"message": "Continuar com seu Session" "message": "Continuar com seu Session"
}, },

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

@ -1272,7 +1272,7 @@
"allUsersAreRandomly...": { "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." "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" "message": "Tạo Session ID"
}, },
"recoveryPhrase": { "recoveryPhrase": {
@ -1284,9 +1284,6 @@
"enterDisplayName": { "enterDisplayName": {
"message": "Nhập một tên hiển thị" "message": "Nhập một tên hiển thị"
}, },
"enterSessionIDHere": {
"message": "Nhập Session ID của bạn"
},
"continueYourSession": { "continueYourSession": {
"message": "Tiếp tục Session của bạn" "message": "Tiếp tục Session của bạn"
}, },

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

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

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

@ -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>
);
};

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

@ -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>
);
}
};

@ -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>
);
};

@ -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>
);
};

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

Loading…
Cancel
Save