add registration errors show to user

This commit is contained in:
Audric Ackermann 2020-01-06 11:30:22 +11:00
parent b5aba194c9
commit 214679dece
6 changed files with 159 additions and 107 deletions

View File

@ -2532,5 +2532,11 @@
},
"devicesSettingsDescription": {
"message": "Managed linked devices"
},
"mnemonicEmpty": {
"message": "Seed is mandatory"
},
"displayNameEmpty": {
"message": "Display Name Is Mandatory"
}
}

View File

@ -222,8 +222,6 @@ $session_message-container-border-radius: 5px;
border: 2px solid $textAndBorderColor;
}
width: auto;
border: none;
display: flex;
@ -246,8 +244,7 @@ $session_message-container-border-radius: 5px;
border: 2px solid $session-color-green;
background-color: $session-color-green;
&.disabled,
&:disabled {
&.disabled {
background-color: rgba($session-color-green, 0.6);
}
}
@ -294,7 +291,6 @@ $session_message-container-border-radius: 5px;
&.square-outline {
&.green {
@include transparent-background($session-color-green);
}
&.white {
@include transparent-background($session-color-white);
@ -338,7 +334,6 @@ $session_message-container-border-radius: 5px;
&.square-outline {
border-radius: 0px;
}
&:hover {
filter: brightness(80%);
@ -520,64 +515,6 @@ label {
cursor: pointer;
}
.input-with-label-container {
height: 46.5px;
width: 280px;
color: $session-color-white;
padding: 2px 0 2px 0;
transition: opacity $session-transition-duration;
opacity: 1;
position: relative;
label {
line-height: 14px;
opacity: 0;
color: #737373;
font-size: 10px;
line-height: 11px;
position: absolute;
top: 0px;
}
&.filled {
opacity: 1;
}
input {
border: none;
outline: 0;
height: 14px;
width: 280px;
background: transparent;
color: $session-color-white;
font-size: 12px;
line-height: 14px;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
hr {
border: 1px solid $session-color-white;
width: 100%;
position: absolute;
bottom: 0px;
}
button {
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 0px;
}
}
.user-details-dialog {
.message {
word-break: break-all;
}
}
#session-toast-container {
position: fixed;
right: $session-margin-lg;

View File

@ -62,7 +62,6 @@
&__content {
width: 100%;
overflow-y: auto;
padding-top: 20px;
}
@ -112,10 +111,11 @@
&__welcome-session {
@include registration-label-mixin;
font-size: 12px;
font-size: 14px;
font-weight: 700;
line-height: 12px;
line-height: 14px;
padding-top: 2em;
text-align: center;
}
&__unique-session-id {
@ -157,6 +157,10 @@
opacity: 1;
}
&.error {
color: red;
}
input {
border: none;
outline: 0;

View File

@ -40,6 +40,8 @@ interface State {
mnemonicSeed: string;
hexGeneratedPubKey: string;
primaryDevicePubKey: string;
mnemonicError: string | undefined;
displayNameError: string | undefined;
}
const Tab = ({
@ -111,6 +113,8 @@ export class RegistrationTabs extends React.Component<{}, State> {
mnemonicSeed: '',
hexGeneratedPubKey: '',
primaryDevicePubKey: '',
mnemonicError: undefined,
displayNameError: undefined,
};
this.accountManager = window.getAccountManager();
@ -196,25 +200,39 @@ export class RegistrationTabs extends React.Component<{}, State> {
mnemonicSeed: '',
hexGeneratedPubKey: '',
primaryDevicePubKey: '',
mnemonicError: undefined,
displayNameError: undefined,
});
};
private onSeedChanged(val: string) {
this.setState({ mnemonicSeed: val });
this.setState({
mnemonicSeed: val,
mnemonicError: !val ? window.i18n('mnemonicEmpty') : undefined,
});
}
private onDisplayNameChanged(val: string) {
const sanitizedName = this.sanitiseNameInput(val);
this.setState({ displayName: sanitizedName });
this.setState({
displayName: sanitizedName,
displayNameError: !sanitizedName
? window.i18n('displayNameEmpty')
: undefined,
});
}
private onPasswordChanged(val: string) {
this.setState({ password: val });
this.onValidatePassword(); // FIXME add bubbles or something to help the user know what he did wrong
this.setState({ password: val }, () => {
this.validatePassword();
});
}
private onPasswordVerifyChanged(val: string) {
this.setState({ validatePassword: val });
this.setState({ validatePassword: val }, () => {
this.validatePassword();
});
}
private renderSections() {
@ -250,6 +268,21 @@ export class RegistrationTabs extends React.Component<{}, State> {
);
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">
@ -264,6 +297,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('completeSignUp')}
enabled={enableCompleteSignUp}
/>
</div>
);
@ -399,6 +433,11 @@ export class RegistrationTabs extends React.Component<{}, State> {
}
private renderNamePasswordAndVerifyPasswordFields() {
const passwordDoesNotMatchString =
!this.state.passwordFieldsMatch && this.state.password
? window.i18n('passwordsDoNotMatch')
: undefined;
return (
<div className="inputfields">
<SessionInput
@ -416,6 +455,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
<SessionInput
label={window.i18n('optionalPassword')}
error={this.state.passwordErrorString}
type="password"
placeholder={window.i18n('enterOptionalPassword')}
onValueChanged={(val: string) => {
@ -428,6 +468,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
<SessionInput
label={window.i18n('verifyPassword')}
error={passwordDoesNotMatchString}
type="password"
placeholder={window.i18n('optionalPassword')}
onValueChanged={(val: string) => {
@ -488,7 +529,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
<h4>{or}</h4>
{this.renderRestoreUsingSeedButton(
SessionButtonType.BrandOutline,
SessionButtonColor.Green
SessionButtonColor.White
)}
</div>
);
@ -525,6 +566,32 @@ export class RegistrationTabs extends React.Component<{}, State> {
}
private renderContinueYourSessionButton() {
const {
signUpMode,
signInMode,
passwordErrorString,
passwordFieldsMatch,
displayNameError,
mnemonicError,
primaryDevicePubKey,
displayName,
mnemonicSeed,
password,
} = this.state;
let enableContinue = true;
const displayNameOK = !displayNameError && !!displayName; //display name required
const mnemonicOK = !mnemonicError && !!mnemonicSeed; //Mnemonic required
const passwordsOK =
!password || (!passwordErrorString && passwordFieldsMatch); // password is valid if empty, or if no error and fields are matching
if (signInMode === SignInMode.UsingSeed) {
enableContinue = displayNameOK && mnemonicOK && passwordsOK;
} else if (signInMode === SignInMode.LinkingDevice) {
enableContinue = !!primaryDevicePubKey;
} else if (signUpMode === SignUpMode.EnterDetails) {
enableContinue = displayNameOK && passwordsOK;
}
return (
<SessionButton
onClick={() => {
@ -533,6 +600,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
buttonType={SessionButtonType.Brand}
buttonColor={SessionButtonColor.Green}
text={window.i18n('continueYourSession')}
enabled={enableContinue}
/>
);
}
@ -603,37 +671,37 @@ export class RegistrationTabs extends React.Component<{}, State> {
// If user hasn't set a value then skip
if (!input && !confirmationInput) {
return null;
this.setState({
passwordErrorString: '',
passwordFieldsMatch: true,
});
return;
}
const error = window.passwordUtil.validatePassword(input, window.i18n);
if (error) {
return error;
this.setState({
passwordErrorString: error,
passwordFieldsMatch: true,
});
return;
}
if (input !== confirmationInput) {
return "Password don't match";
}
return null;
}
private onValidatePassword() {
const passwordValidation = this.validatePassword();
if (passwordValidation) {
this.setState({ passwordErrorString: passwordValidation });
} else {
// Show green box around inputs that match
const input = this.trim(this.state.password);
const confirmationInput = this.trim(this.state.validatePassword);
const passwordFieldsMatch =
input !== undefined && input === confirmationInput;
this.setState({
passwordErrorString: '',
passwordFieldsMatch,
passwordFieldsMatch: false,
});
return;
}
this.setState({
passwordErrorString: '',
passwordFieldsMatch: true,
});
}
private sanitiseNameInput(val: string) {
@ -654,10 +722,21 @@ export class RegistrationTabs extends React.Component<{}, State> {
}
private async register(language: string) {
const { password, mnemonicSeed, displayName } = this.state;
const {
password,
mnemonicSeed,
displayName,
passwordErrorString,
passwordFieldsMatch,
} = this.state;
// Make sure the password is valid
if (this.validatePassword()) {
//this.showToast(window.i18n('invalidPassword'));
if (passwordErrorString || passwordFieldsMatch) {
window.pushToast({
title: window.i18n('invalidPassword'),
type: 'success',
id: 'invalidPassword',
});
return;
}
if (!mnemonicSeed) {

View File

@ -28,6 +28,7 @@ interface Props {
buttonType: SessionButtonType;
buttonColor: SessionButtonColor;
onClick: any;
enabled?: boolean;
}
export class SessionButton extends React.PureComponent<Props> {

View File

@ -5,6 +5,7 @@ import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
interface Props {
label: string;
error?: string;
type: string;
value?: string;
placeholder: string;
@ -32,23 +33,14 @@ export class SessionInput extends React.PureComponent<Props, State> {
}
public render() {
const { placeholder, type, label, value, enableShowHide } = this.props;
const { inputValue, forceShow } = this.state;
const { placeholder, type, value, enableShowHide, error } = this.props;
const { forceShow } = this.state;
const correctType = forceShow ? 'text' : type;
return (
<div className="session-input-with-label-container">
<label
htmlFor="session-input-floating-label"
className={classNames(
inputValue !== ''
? 'session-input-with-label-container filled'
: 'session-input-with-label-container'
)}
>
{label}
</label>
{error ? this.renderError() : this.renderLabel()}
<input
id="session-input-floating-label"
type={correctType}
@ -75,6 +67,39 @@ export class SessionInput extends React.PureComponent<Props, State> {
);
}
private renderLabel() {
const { inputValue } = this.state;
const { label } = this.props;
return (
<label
htmlFor="session-input-floating-label"
className={classNames(
inputValue !== ''
? 'session-input-with-label-container filled'
: 'session-input-with-label-container'
)}
>
{label}
</label>
);
}
private renderError() {
const { error } = this.props;
return (
<label
htmlFor="session-input-floating-label"
className={classNames(
'session-input-with-label-container filled error'
)}
>
{error}
</label>
);
}
private renderShowHideButton() {
return (
<SessionIconButton