add registration errors show to user

pull/715/head
Audric Ackermann 6 years ago
parent b5aba194c9
commit 214679dece

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

@ -222,8 +222,6 @@ $session_message-container-border-radius: 5px;
border: 2px solid $textAndBorderColor; border: 2px solid $textAndBorderColor;
} }
width: auto; width: auto;
border: none; border: none;
display: flex; display: flex;
@ -246,8 +244,7 @@ $session_message-container-border-radius: 5px;
border: 2px solid $session-color-green; border: 2px solid $session-color-green;
background-color: $session-color-green; background-color: $session-color-green;
&.disabled, &.disabled {
&:disabled {
background-color: rgba($session-color-green, 0.6); background-color: rgba($session-color-green, 0.6);
} }
} }
@ -294,7 +291,6 @@ $session_message-container-border-radius: 5px;
&.square-outline { &.square-outline {
&.green { &.green {
@include transparent-background($session-color-green); @include transparent-background($session-color-green);
} }
&.white { &.white {
@include transparent-background($session-color-white); @include transparent-background($session-color-white);
@ -339,7 +335,6 @@ $session_message-container-border-radius: 5px;
border-radius: 0px; border-radius: 0px;
} }
&:hover { &:hover {
filter: brightness(80%); filter: brightness(80%);
} }
@ -520,64 +515,6 @@ label {
cursor: pointer; 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 { #session-toast-container {
position: fixed; position: fixed;
right: $session-margin-lg; right: $session-margin-lg;

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

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

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

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

Loading…
Cancel
Save