Upgraded ConfirmEmail
This commit is contained in:
parent
8308515c9b
commit
04c1875d5d
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"Activate": "Activate",
|
||||||
"Admin": "Admin",
|
"Admin": "Admin",
|
||||||
|
"AnErrorOccurred": "An error occurred",
|
||||||
"AuditLog": "Audit Logs",
|
"AuditLog": "Audit Logs",
|
||||||
"AuditLogs": "Audit Logs",
|
"AuditLogs": "Audit Logs",
|
||||||
"BlockedIPAddresses": "Blocked IP addresses",
|
"BlockedIPAddresses": "Blocked IP addresses",
|
||||||
@ -8,6 +10,7 @@
|
|||||||
"ClientDomainManager": "Client Domain Manager",
|
"ClientDomainManager": "Client Domain Manager",
|
||||||
"ClientDomains": "Client Domains",
|
"ClientDomains": "Client Domains",
|
||||||
"Comment": "Comment",
|
"Comment": "Comment",
|
||||||
|
"ConfirmPassword": "Confirm Password",
|
||||||
"CustomFieldManager": "Custom Field Manager",
|
"CustomFieldManager": "Custom Field Manager",
|
||||||
"CustomFields": "Custom Fields",
|
"CustomFields": "Custom Fields",
|
||||||
"DisplayName": "Display Name",
|
"DisplayName": "Display Name",
|
||||||
@ -35,6 +38,10 @@
|
|||||||
"NumberOfAttempts": "Number Of Attempts",
|
"NumberOfAttempts": "Number Of Attempts",
|
||||||
"NewValue": "New Value",
|
"NewValue": "New Value",
|
||||||
"OldValue": "Old Value",
|
"OldValue": "Old Value",
|
||||||
|
"Password": "Password",
|
||||||
|
"PasswordIsRequired": "Password is required",
|
||||||
|
"PasswordMinLength": "Password must be at least {{minPasswordLength}} characters",
|
||||||
|
"PasswordsMustMatch": "You need to confirm by typing exactly the same as the new password",
|
||||||
"PressAgainToUnblock": "Press again to unblock",
|
"PressAgainToUnblock": "Press again to unblock",
|
||||||
"Sequence": "Sequence",
|
"Sequence": "Sequence",
|
||||||
"SequenceManager": "Sequence Manager",
|
"SequenceManager": "Sequence Manager",
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
import Form, { FormState, FormData, businessValidationResult } from "../../../components/common/Form";
|
import React, { useState } from "react";
|
||||||
import Joi from "joi";
|
|
||||||
import authentication from "../services/authenticationService";
|
import authentication from "../services/authenticationService";
|
||||||
import { IEmailUserAction } from "../models/IEmailUserAction";
|
import { IEmailUserAction } from "../models/IEmailUserAction";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
|
import Input from "../../../components/common/Input";
|
||||||
|
import Button, { ButtonType } from "../../../components/common/Button";
|
||||||
|
import ErrorBlock from "../../../components/common/ErrorBlock";
|
||||||
|
import { FormData } from "../../../components/common/Form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Namespaces } from "../../../i18n/i18n";
|
||||||
|
|
||||||
export interface EmailUserActionConfirmEmailData extends FormData {
|
export interface EmailUserActionConfirmEmailData extends FormData {
|
||||||
password: string;
|
password: string;
|
||||||
@ -10,81 +15,74 @@ export interface EmailUserActionConfirmEmailData extends FormData {
|
|||||||
emailConfirmed: boolean;
|
emailConfirmed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmailUserActionConfirmEmailState extends FormState {
|
interface Props {
|
||||||
data: EmailUserActionConfirmEmailData;
|
emailUserAction: IEmailUserAction;
|
||||||
hasTwelveCharacters: boolean,
|
|
||||||
hasSpecialCharacter: boolean,
|
|
||||||
hasUppercaseLetter: boolean,
|
|
||||||
hasLowercaseLetter: boolean,
|
|
||||||
hasNumber: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmailUserActionConfirmEmail extends Form<any, any, EmailUserActionConfirmEmailState> {
|
const EmailUserActionConfirmEmail: React.FC<Props> = ({ emailUserAction }) => {
|
||||||
state = {
|
const { t } = useTranslation<typeof Namespaces.Common>();
|
||||||
loaded: true,
|
const [password, setPassword] = useState("");
|
||||||
passwordMaxLenght: 255,
|
const [confirmPassword, setConfirmPassword] = useState("");
|
||||||
data: { password: "", confirmPassword: "", emailConfirmed: false },
|
const [emailConfirmed, setEmailConfirmed] = useState(false);
|
||||||
errors: {},
|
const [generalError, setGeneralError] = useState("");
|
||||||
hasTwelveCharacters: false,
|
const [errors, setErrors] = useState<{ [key: string]: string }>({});
|
||||||
hasSpecialCharacter: false,
|
const [hasTwelveCharacters, setHasTwelveCharacters] = useState(false);
|
||||||
hasUppercaseLetter: false,
|
const [hasSpecialCharacter, setHasSpecialCharacter] = useState(false);
|
||||||
hasLowercaseLetter: false,
|
const [hasUppercaseLetter, setHasUppercaseLetter] = useState(false);
|
||||||
hasNumber: false
|
const [hasLowercaseLetter, setHasLowercaseLetter] = useState(false);
|
||||||
|
const [hasNumber, setHasNumber] = useState(false);
|
||||||
|
|
||||||
|
const LABEL_PASSWORD = t("Password");
|
||||||
|
const LABEL_CONFIRM_PASSWORD = t("Confirmassword");
|
||||||
|
const LABEL_CONFIRM_EMAIL = t("Activate");
|
||||||
|
const PASSWORD_MAX_LENGTH = 255;
|
||||||
|
|
||||||
|
const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const newPassword = e.currentTarget.value;
|
||||||
|
setPassword(newPassword);
|
||||||
|
setConfirmPassword("");
|
||||||
|
setHasNumber(/\d+/g.test(newPassword));
|
||||||
|
setHasLowercaseLetter(/[a-z]/g.test(newPassword));
|
||||||
|
setHasUppercaseLetter(/[A-Z]/g.test(newPassword));
|
||||||
|
setHasSpecialCharacter(
|
||||||
|
/[ ~`! @#$%^&*()_+\-=[\]{};:\\|,.'"<>/?]/.test(newPassword),
|
||||||
|
);
|
||||||
|
setHasTwelveCharacters(newPassword.length >= 12);
|
||||||
};
|
};
|
||||||
|
|
||||||
labelPassword = "Password";
|
const handleConfirmPasswordChange = (
|
||||||
labelConfirmPassword = "Confirm Password";
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
labelConfirmEmail = "Activate";
|
) => {
|
||||||
|
setConfirmPassword(e.currentTarget.value);
|
||||||
schema = {
|
|
||||||
password: Joi.string().required().min(12).label(this.labelPassword),
|
|
||||||
confirmPassword: Joi.string()
|
|
||||||
.when("password", {
|
|
||||||
is: "",
|
|
||||||
then: Joi.optional(),
|
|
||||||
otherwise: Joi.valid(Joi.ref("password")).error(() => {
|
|
||||||
const e = new Error("Passwords must match");
|
|
||||||
e.name = "confirmPassword";
|
|
||||||
return e;
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.label(this.labelConfirmPassword),
|
|
||||||
|
|
||||||
emailConfirmed: Joi.boolean(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BusinessValidation(): businessValidationResult | null {
|
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
const { password, confirmPassword } = this.state.data;
|
e.preventDefault();
|
||||||
|
const newErrors: { [key: string]: string } = {};
|
||||||
|
|
||||||
if (password !== confirmPassword) {
|
const minPasswordLength = 12;
|
||||||
return {
|
|
||||||
details: [
|
// Validation
|
||||||
{
|
if (!password) {
|
||||||
path: "confirmPassword",
|
newErrors.password = t("PasswordIsRequired");
|
||||||
message: "You need to confirm by typing exactly the same as the new password",
|
} else if (password.length < minPasswordLength) {
|
||||||
},
|
newErrors.password = t("PasswordMinLength", {
|
||||||
],
|
minPasswordLength: minPasswordLength,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePasswordChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
if (password && password !== confirmPassword) {
|
||||||
const stateData = this.state;
|
newErrors.confirmPassword = t("PasswordsMustMatch");
|
||||||
stateData.data.password = e.currentTarget.value;
|
}
|
||||||
stateData.data.confirmPassword = "";
|
|
||||||
stateData.hasNumber = /\d+/g.test(stateData.data.password);
|
|
||||||
stateData.hasLowercaseLetter = /[a-z]/g.test(stateData.data.password);
|
|
||||||
stateData.hasUppercaseLetter = /[A-Z]/g.test(stateData.data.password);;
|
|
||||||
stateData.hasSpecialCharacter = /[ ~`! @#$%^&*()_+\-=[\]{};:\\|,.'"<>/?]/.test(stateData.data.password);
|
|
||||||
stateData.hasTwelveCharacters = stateData.data.password.length >= 12;
|
|
||||||
this.setState(stateData)
|
|
||||||
};
|
|
||||||
|
|
||||||
doSubmit = async (buttonName : string) => {
|
if (Object.keys(newErrors).length > 0) {
|
||||||
const { emailUserAction } = this.props;
|
setErrors(newErrors);
|
||||||
const { password } = this.state.data;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors({});
|
||||||
|
|
||||||
|
try {
|
||||||
const action: IEmailUserAction = {
|
const action: IEmailUserAction = {
|
||||||
email: emailUserAction.email,
|
email: emailUserAction.email,
|
||||||
token: emailUserAction.token,
|
token: emailUserAction.token,
|
||||||
@ -92,50 +90,85 @@ class EmailUserActionConfirmEmail extends Form<any, any, EmailUserActionConfirmE
|
|||||||
emailActionType: emailUserAction.emailActionType,
|
emailActionType: emailUserAction.emailActionType,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
|
||||||
const callResult = await authentication.completeEmailAction(action);
|
const callResult = await authentication.completeEmailAction(action);
|
||||||
if (callResult === 1) {
|
if (callResult === 1) {
|
||||||
let data = { ...this.state.data };
|
setEmailConfirmed(true);
|
||||||
data.emailConfirmed = true;
|
setTimeout(() => {
|
||||||
this.setState({ data });
|
window.location.replace("/login");
|
||||||
setTimeout(function () {
|
|
||||||
window.location.replace('/login');
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
} catch (ex: any) {
|
||||||
catch(ex: any) {
|
setGeneralError(ex?.message || t("AnErrorOccurred"));
|
||||||
this.handleGeneralError(ex);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
const isFormValid =
|
||||||
const { emailConfirmed, password, confirmPassword } = this.state.data;
|
password !== "" &&
|
||||||
const { hasNumber, hasLowercaseLetter, hasSpecialCharacter, hasUppercaseLetter, hasTwelveCharacters, passwordMaxLenght } = this.state;
|
password === confirmPassword &&
|
||||||
const isFormValid = password !== "" && password === confirmPassword && hasNumber && hasLowercaseLetter && hasSpecialCharacter && hasUppercaseLetter && hasTwelveCharacters;
|
hasNumber &&
|
||||||
|
hasLowercaseLetter &&
|
||||||
|
hasSpecialCharacter &&
|
||||||
|
hasUppercaseLetter &&
|
||||||
|
hasTwelveCharacters;
|
||||||
|
|
||||||
if (emailConfirmed) {
|
if (emailConfirmed) {
|
||||||
return <div className="alert alert-info">Success, your e-mail is confirmed. You can now log in.</div>;
|
return (
|
||||||
|
<div className="alert alert-info">
|
||||||
|
Success, your e-mail is confirmed. You can now log in.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>To activate your account, please enter a password</div>
|
<div>To activate your account, please enter a password</div>
|
||||||
|
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
{this.renderError("_general")}
|
{generalError && <ErrorBlock error={generalError} />}
|
||||||
{this.renderInputWithChangeEvent("password", "", InputType.password, undefined, this.handlePasswordChange, undefined, this.labelPassword, passwordMaxLenght)}
|
<Input
|
||||||
<div className={hasTwelveCharacters ? "checked" : "unchecked"}>Password requires a minimum of 12 characters containing a combination of:</div>
|
name="password"
|
||||||
|
label={LABEL_PASSWORD}
|
||||||
|
type={InputType.password}
|
||||||
|
value={password}
|
||||||
|
onChange={handlePasswordChange}
|
||||||
|
maxLength={PASSWORD_MAX_LENGTH}
|
||||||
|
error={errors.password}
|
||||||
|
/>
|
||||||
|
<div className={hasTwelveCharacters ? "checked" : "unchecked"}>
|
||||||
|
Password requires a minimum of 12 characters containing a combination
|
||||||
|
of:
|
||||||
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li className={hasSpecialCharacter ? "checked" : ""}>At least 1 symbol</li>
|
<li className={hasSpecialCharacter ? "checked" : ""}>
|
||||||
|
At least 1 symbol
|
||||||
|
</li>
|
||||||
<li className={hasNumber ? "checked" : ""}>At least 1 number</li>
|
<li className={hasNumber ? "checked" : ""}>At least 1 number</li>
|
||||||
<li className={hasLowercaseLetter ? "checked" : ""}>At least 1 lowercase letter</li>
|
<li className={hasLowercaseLetter ? "checked" : ""}>
|
||||||
<li className={hasUppercaseLetter ? "checked" : ""}>At least 1 uppercase letter</li>
|
At least 1 lowercase letter
|
||||||
|
</li>
|
||||||
|
<li className={hasUppercaseLetter ? "checked" : ""}>
|
||||||
|
At least 1 uppercase letter
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{this.renderInput("confirmPassword", "", InputType.password, undefined, undefined, this.labelConfirmPassword, passwordMaxLenght)}
|
<Input
|
||||||
{this.renderButton(this.labelConfirmEmail, "confirmEmail", undefined, undefined, isFormValid)}
|
name="confirmPassword"
|
||||||
|
label={LABEL_CONFIRM_PASSWORD}
|
||||||
|
type={InputType.password}
|
||||||
|
value={confirmPassword}
|
||||||
|
onChange={handleConfirmPasswordChange}
|
||||||
|
maxLength={PASSWORD_MAX_LENGTH}
|
||||||
|
error={errors.confirmPassword}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
buttonType={ButtonType.primary}
|
||||||
|
disabled={!isFormValid}
|
||||||
|
onClick={() => {}}
|
||||||
|
>
|
||||||
|
{LABEL_CONFIRM_EMAIL}
|
||||||
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default EmailUserActionConfirmEmail;
|
export default EmailUserActionConfirmEmail;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user