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