add registration errors show to user
This commit is contained in:
parent
b5aba194c9
commit
214679dece
|
@ -2532,5 +2532,11 @@
|
|||
},
|
||||
"devicesSettingsDescription": {
|
||||
"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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -28,6 +28,7 @@ interface Props {
|
|||
buttonType: SessionButtonType;
|
||||
buttonColor: SessionButtonColor;
|
||||
onClick: any;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export class SessionButton extends React.PureComponent<Props> {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue