You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
11 KiB
TypeScript

// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import React from 'react';
import Form, { FormComponentProps } from '@ant-design/compatible/lib/form/Form';
import { UserAddOutlined, MailOutlined, LockOutlined } from '@ant-design/icons';
import Button from 'antd/lib/button';
import Input from 'antd/lib/input';
import Checkbox from 'antd/lib/checkbox';
import patterns from 'utils/validation-patterns';
import { UserAgreement } from 'reducers/interfaces';
import { Row, Col } from 'antd/lib/grid';
export interface UserConfirmation {
name: string;
value: boolean;
}
export interface RegisterData {
username: string;
firstName: string;
lastName: string;
email: string;
password1: string;
password2: string;
confirmations: UserConfirmation[];
}
type RegisterFormProps = {
fetching: boolean;
userAgreements: UserAgreement[];
onSubmit(registerData: RegisterData): void;
} & FormComponentProps;
class RegisterFormComponent extends React.PureComponent<RegisterFormProps> {
private validateConfirmation = (rule: any, value: any, callback: any): void => {
const { form } = this.props;
if (value && value !== form.getFieldValue('password1')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
};
private validatePassword = (_: any, value: any, callback: any): void => {
const { form } = this.props;
if (!patterns.validatePasswordLength.pattern.test(value)) {
callback(patterns.validatePasswordLength.message);
}
if (!patterns.passwordContainsNumericCharacters.pattern.test(value)) {
callback(patterns.passwordContainsNumericCharacters.message);
}
if (!patterns.passwordContainsUpperCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsUpperCaseCharacter.message);
}
if (!patterns.passwordContainsLowerCaseCharacter.pattern.test(value)) {
callback(patterns.passwordContainsLowerCaseCharacter.message);
}
if (value) {
form.validateFields(['password2'], { force: true });
}
callback();
};
private validateUsername = (_: any, value: any, callback: any): void => {
if (!patterns.validateUsernameLength.pattern.test(value)) {
callback(patterns.validateUsernameLength.message);
}
if (!patterns.validateUsernameCharacters.pattern.test(value)) {
callback(patterns.validateUsernameCharacters.message);
}
callback();
};
private validateAgrement = (agreement: any, value: any, callback: any): void => {
const { userAgreements } = this.props;
let isValid = true;
for (const userAgreement of userAgreements) {
if (agreement.field === userAgreement.name && userAgreement.required && !value) {
isValid = false;
callback(`You must accept the ${userAgreement.displayText} to continue!`);
break;
}
}
if (isValid) {
callback();
}
};
private handleSubmit = (e: React.FormEvent): void => {
e.preventDefault();
const { form, onSubmit, userAgreements } = this.props;
form.validateFields((error, values): void => {
if (!error) {
const validatedFields = {
...values,
confirmations: [],
};
for (const userAgreement of userAgreements) {
validatedFields.confirmations.push({
name: userAgreement.name,
value: validatedFields[userAgreement.name],
});
delete validatedFields[userAgreement.name];
}
onSubmit(validatedFields);
}
});
};
private renderFirstNameField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('firstName', {
rules: [
{
required: true,
message: 'Please specify a first name',
pattern: patterns.validateName.pattern,
},
],
})(
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='First name'
/>,
)}
</Form.Item>
);
}
private renderLastNameField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('lastName', {
rules: [
{
required: true,
message: 'Please specify a last name',
pattern: patterns.validateName.pattern,
},
],
})(
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Last name'
/>,
)}
</Form.Item>
);
}
private renderUsernameField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('username', {
rules: [
{
required: true,
message: 'Please specify a username',
},
{
validator: this.validateUsername,
},
],
})(
<Input
prefix={<UserAddOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Username'
/>,
)}
</Form.Item>
);
}
private renderEmailField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('email', {
rules: [
{
type: 'email',
message: 'The input is not valid E-mail!',
},
{
required: true,
message: 'Please specify an email address',
},
],
})(
<Input
autoComplete='email'
prefix={<MailOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Email address'
/>,
)}
</Form.Item>
);
}
private renderPasswordField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('password1', {
rules: [
{
required: true,
message: 'Please input your password!',
},
{
validator: this.validatePassword,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Password'
/>,
)}
</Form.Item>
);
}
private renderPasswordConfirmationField(): JSX.Element {
const { form } = this.props;
return (
<Form.Item hasFeedback>
{form.getFieldDecorator('password2', {
rules: [
{
required: true,
message: 'Please confirm your password!',
},
{
validator: this.validateConfirmation,
},
],
})(
<Input.Password
autoComplete='new-password'
prefix={<LockOutlined style={{ color: 'rgba(0, 0, 0, 0.25)' }} />}
placeholder='Confirm password'
/>,
)}
</Form.Item>
);
}
private renderUserAgreements(): JSX.Element[] {
const { form, userAgreements } = this.props;
const getUserAgreementsElements = (): JSX.Element[] => {
const agreementsList: JSX.Element[] = [];
for (const userAgreement of userAgreements) {
agreementsList.push(
<Form.Item key={userAgreement.name}>
{form.getFieldDecorator(userAgreement.name, {
initialValue: false,
valuePropName: 'checked',
rules: [
{
required: true,
message: 'You must accept to continue!',
},
{
validator: this.validateAgrement,
},
],
})(
<Checkbox>
I read and accept the
<a rel='noopener noreferrer' target='_blank' href={userAgreement.url}>
{` ${userAgreement.displayText}`}
</a>
</Checkbox>,
)}
</Form.Item>,
);
}
return agreementsList;
};
return getUserAgreementsElements();
}
public render(): JSX.Element {
const { fetching } = this.props;
return (
<Form onSubmit={this.handleSubmit} className='login-form'>
<Row gutter={8}>
<Col span={12}>{this.renderFirstNameField()}</Col>
<Col span={12}>{this.renderLastNameField()}</Col>
</Row>
{this.renderUsernameField()}
{this.renderEmailField()}
{this.renderPasswordField()}
{this.renderPasswordConfirmationField()}
{this.renderUserAgreements()}
<Form.Item>
<Button
type='primary'
htmlType='submit'
className='register-form-button'
loading={fetching}
disabled={fetching}
>
Submit
</Button>
</Form.Item>
</Form>
);
}
}
export default Form.create<RegisterFormProps>()(RegisterFormComponent);