session-desktop/ts/components/session/registration/SignInTab.tsx

228 lines
7.5 KiB
TypeScript
Raw Normal View History

2021-02-26 05:29:30 +01:00
import React, { useState } from 'react';
import { Flex } from '../../basic/Flex';
import { SpacerLG } from '../../basic/Text';
2021-04-22 10:03:58 +02:00
import { SessionButton, SessionButtonColor, SessionButtonType } from '../SessionButton';
import { SessionSpinner } from '../SessionSpinner';
2021-04-22 10:03:58 +02:00
import { signInWithLinking, signInWithRecovery, validatePassword } from './RegistrationTabs';
2021-02-26 05:29:30 +01:00
import { RegistrationUserDetails } from './RegistrationUserDetails';
import { TermsAndConditions } from './TermsAndConditions';
export enum SignInMode {
Default,
UsingRecoveryPhrase,
LinkDevice,
}
// tslint:disable: use-simple-attributes
// tslint:disable: react-unused-props-and-state
2021-02-26 05:29:30 +01:00
const LinkDeviceButton = (props: { onLinkDeviceButtonClicked: () => any }) => {
return (
<SessionButton
onClick={props.onLinkDeviceButtonClicked}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
text={window.i18n('linkDevice')}
/>
);
};
2021-04-22 10:03:58 +02:00
const RestoreUsingRecoveryPhraseButton = (props: { onRecoveryButtonClicked: () => any }) => {
2021-02-26 05:29:30 +01:00
return (
<SessionButton
onClick={props.onRecoveryButtonClicked}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
text={window.i18n('restoreUsingRecoveryPhrase')}
/>
);
};
const ContinueYourSessionButton = (props: {
handleContinueYourSessionClick: () => any;
2021-03-01 02:05:39 +01:00
disabled: boolean;
2021-02-26 05:29:30 +01:00
}) => {
return (
<SessionButton
onClick={props.handleContinueYourSessionClick}
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('continueYourSession')}
2021-03-01 02:05:39 +01:00
disabled={props.disabled}
2021-02-26 05:29:30 +01:00
/>
);
};
2021-03-01 02:05:39 +01:00
const SignInContinueButton = (props: {
2021-02-26 05:29:30 +01:00
signInMode: SignInMode;
2021-03-01 02:05:39 +01:00
disabled: boolean;
2021-02-26 05:29:30 +01:00
handleContinueYourSessionClick: () => any;
}) => {
if (props.signInMode === SignInMode.Default) {
2021-03-01 02:05:39 +01:00
return <></>;
2021-02-26 05:29:30 +01:00
}
return (
<ContinueYourSessionButton
handleContinueYourSessionClick={props.handleContinueYourSessionClick}
2021-03-01 02:05:39 +01:00
disabled={props.disabled}
2021-02-26 05:29:30 +01:00
/>
);
};
2021-03-01 02:05:39 +01:00
const SignInButtons = (props: {
signInMode: SignInMode;
onRecoveryButtonClicked: () => any;
onLinkDeviceButtonClicked: () => any;
}) => {
if (props.signInMode !== SignInMode.Default) {
return <></>;
}
return (
<div>
2021-04-22 10:03:58 +02:00
<RestoreUsingRecoveryPhraseButton onRecoveryButtonClicked={props.onRecoveryButtonClicked} />
<SpacerLG />
2021-03-01 02:05:39 +01:00
<div className="or">{window.i18n('or')}</div>
<SpacerLG />
2021-04-22 10:03:58 +02:00
<LinkDeviceButton onLinkDeviceButtonClicked={props.onLinkDeviceButtonClicked} />
2021-03-01 02:05:39 +01:00
</div>
);
};
export const SignInTab = () => {
2021-02-26 05:29:30 +01:00
const [signInMode, setSignInMode] = useState(SignInMode.Default);
const [recoveryPhrase, setRecoveryPhrase] = useState('');
2021-04-22 10:03:58 +02:00
const [recoveryPhraseError, setRecoveryPhraseError] = useState(undefined as string | undefined);
2021-02-26 05:29:30 +01:00
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 [loading, setIsLoading] = useState(false);
2021-02-26 05:29:30 +01:00
2021-03-01 02:05:39 +01:00
const isRecovery = signInMode === SignInMode.UsingRecoveryPhrase;
const isLinking = signInMode === SignInMode.LinkDevice;
2021-02-26 05:29:30 +01:00
const showTermsAndConditions = signInMode !== SignInMode.Default;
2021-03-01 02:05:39 +01:00
// show display name input only if we are trying to recover from seed.
// We don't need a display name when we link a device, as the display name
// from the configuration message will be used.
const showDisplayNameField = isRecovery;
// Display name is required only on isRecoveryMode
2021-04-22 10:03:58 +02:00
const displayNameOK = (isRecovery && !displayNameError && !!displayName) || isLinking;
2021-03-01 02:05:39 +01:00
// Password is valid if empty, or if no error and fields are matching
2021-04-22 10:03:58 +02:00
const passwordsOK = !password || (!passwordErrorString && passwordFieldsMatch);
2021-03-01 02:05:39 +01:00
// Seed is mandatory no matter which mode
const seedOK = recoveryPhrase && !recoveryPhraseError;
2021-04-22 10:03:58 +02:00
const activateContinueButton = seedOK && displayNameOK && passwordsOK && !loading;
2021-03-01 02:05:39 +01:00
2021-03-02 06:49:41 +01:00
const continueYourSession = async () => {
if (isRecovery) {
await signInWithRecovery({
displayName,
userRecoveryPhrase: recoveryPhrase,
password,
verifyPassword: passwordVerify,
});
} else if (isLinking) {
setIsLoading(true);
await signInWithLinking({
userRecoveryPhrase: recoveryPhrase,
password,
verifyPassword: passwordVerify,
});
setIsLoading(false);
}
};
2021-02-26 05:29:30 +01:00
return (
<div className="session-registration__content">
{signInMode !== SignInMode.Default && (
<RegistrationUserDetails
2021-03-01 02:05:39 +01:00
showDisplayNameField={showDisplayNameField}
2021-02-26 05:29:30 +01:00
showSeedField={true}
displayName={displayName}
2021-03-02 06:49:41 +01:00
handlePressEnter={continueYourSession}
2021-02-26 05:29:30 +01:00
onDisplayNameChanged={(name: string) => {
const sanitizedName = name.replace(window.displayNameRegex, '');
const trimName = sanitizedName.trim();
setDisplayName(sanitizedName);
2021-04-22 10:03:58 +02:00
setDisplayNameError(!trimName ? window.i18n('displayNameEmpty') : undefined);
2021-02-26 05:29:30 +01:00
}}
onPasswordChanged={(val: string) => {
setPassword(val);
2021-03-02 06:49:41 +01:00
// if user just removed the password, empty the verify too
if (!val) {
setPasswordVerify('');
setPasswordErrorString('');
setPasswordFieldsMatch(true);
return;
}
2021-02-26 05:29:30 +01:00
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);
2021-04-22 10:03:58 +02:00
setRecoveryPhraseError(!seed ? window.i18n('recoveryPhraseEmpty') : undefined);
2021-02-26 05:29:30 +01:00
}}
password={password}
passwordErrorString={passwordErrorString}
passwordFieldsMatch={passwordFieldsMatch}
recoveryPhrase={recoveryPhrase}
stealAutoFocus={true}
/>
)}
<SignInButtons
signInMode={signInMode}
onRecoveryButtonClicked={() => {
setSignInMode(SignInMode.UsingRecoveryPhrase);
setRecoveryPhrase('');
setDisplayName('');
setIsLoading(false);
2021-02-26 05:29:30 +01:00
}}
onLinkDeviceButtonClicked={() => {
setSignInMode(SignInMode.LinkDevice);
setRecoveryPhrase('');
setDisplayName('');
setIsLoading(false);
2021-02-26 05:29:30 +01:00
}}
2021-03-01 02:05:39 +01:00
/>
<SignInContinueButton
signInMode={signInMode}
2021-03-02 06:49:41 +01:00
handleContinueYourSessionClick={continueYourSession}
2021-03-01 02:05:39 +01:00
disabled={!activateContinueButton}
2021-02-26 05:29:30 +01:00
/>
{loading && (
<Flex
container={true}
justifyContent="center"
alignItems="center"
style={{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
pointerEvents: 'all',
backgroundColor: '#00000088',
}}
>
<SessionSpinner loading={true} />
</Flex>
)}
2021-02-26 05:29:30 +01:00
{showTermsAndConditions && <TermsAndConditions />}
</div>
);
};