Unverified Commit eaabc567 authored by Zhou (Link)  Fang's avatar Zhou (Link) Fang Committed by GitHub
Browse files

Added more validation to match back-end ones (#292)

* Added more validation

* improved country validation

* corrected the max length value to 255

* Added more validation

* improved country validation

* corrected the max length value to 255

* Improved return logic based on feedback
parent 5eb16861
......@@ -31,6 +31,7 @@ export const REVIEW = 'Review';
export const HAS_TOKEN_EXPIRED = 'HAS_TOKEN_EXPIRED';
export const LOGIN_EXPIRED_MSG = 'Your session has expired, please sign in again.';
export const MAX_LENGTH_HELPER_TEXT = 'The value exceeds max length 255 characters'
export const PATH_NAME_ARRAY = [
'/company-info',
......
......@@ -3,7 +3,12 @@ import { formField } from '../../UIComponents/FormComponents/formFieldModel';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { TextField } from '@material-ui/core';
import DropdownMenu from '../../UIComponents/Inputs/DropdownMenu';
import { OPTIONS_FOR_ORG_TYPE, OPTIONS_FOR_REVENUE, OPTIONS_FOR_EMPLOYEE_COUNT, HELPERTEXT_FOR_REVENUE } from '../../../Constants/Constants';
import {
OPTIONS_FOR_ORG_TYPE,
OPTIONS_FOR_REVENUE,
OPTIONS_FOR_EMPLOYEE_COUNT,
HELPERTEXT_FOR_REVENUE,
} from '../../../Constants/Constants';
/**
* Render Oraganization selector (used React-Select)
......@@ -43,6 +48,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
requiredMark={true}
value={formik.values.organization.legalName}
onChange={formik.handleChange}
error={formik.touched.organization?.legalName && Boolean(formik.errors.organization?.legalName)}
helperText={formik.errors.organization?.legalName}
/>
</div>
</div>
......@@ -54,6 +61,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
inputValue={formik.values.organization.type}
optionsArray={OPTIONS_FOR_ORG_TYPE}
handleChange={formik.handleChange}
error={formik.touched.organization?.type && Boolean(formik.errors.organization?.type)}
helperText={formik.errors.organization?.type}
/>
</div>
<div className="col-md-8">
......@@ -89,8 +98,10 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
inputName={organizationRevenue.revenue.name}
inputValue={formik.values.organization.revenue}
optionsArray={OPTIONS_FOR_REVENUE}
helperText={HELPERTEXT_FOR_REVENUE}
explanationHelperText={HELPERTEXT_FOR_REVENUE}
handleChange={(ev) => handleFieldChange(ev.target.value, 'organization.revenue')}
error={formik.touched.organization?.revenue && Boolean(formik.errors.organization?.revenue)}
helperText={formik.errors.organization?.revenue}
/>
</div>
<div className="col-md-8">
......@@ -100,6 +111,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
inputValue={formik.values.organization.employeeCount}
optionsArray={OPTIONS_FOR_EMPLOYEE_COUNT}
handleChange={(ev) => handleFieldChange(ev.target.value, 'organization.employeeCount')}
error={formik.touched.organization?.employeeCount && Boolean(formik.errors.organization?.employeeCount)}
helperText={formik.errors.organization?.employeeCount}
/>
</div>
</div>
......@@ -117,6 +130,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
value={formik.values.organization.address.street}
onChange={formik.handleChange}
ariaLabel={`${organizationName.name}-address`}
error={formik.touched.organization?.address?.street && Boolean(formik.errors.organization?.address?.street)}
helperText={formik.errors.organization?.address?.street}
/>
</div>
<div className="col-md-8">
......@@ -128,6 +143,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
value={formik.values.organization.address.city}
onChange={formik.handleChange}
ariaLabel={`${organizationName.name}-address`}
error={formik.touched.organization?.address?.city && Boolean(formik.errors.organization?.address?.city)}
helperText={formik.errors.organization?.address?.city}
/>
</div>
</div>
......@@ -167,8 +184,9 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
size="small"
required={true}
className={classes.textField}
error={Boolean(formik.errors.organization?.address?.country)}
helperText={formik.errors.organization?.address?.country}
error={formik.touched.organization?.address?.city && Boolean(formik.errors.organization?.address?.country)}
helperText={formik.touched.organization?.address?.city && formik.errors.organization?.address?.country}
oncha
/>
);
}}
......@@ -184,6 +202,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
value={formik.values.organization.address.provinceOrState}
onChange={formik.handleChange}
ariaLabel={`${organizationName.name}-address`}
error={Boolean(formik.errors.organization?.address?.provinceOrState)}
helperText={formik.errors.organization?.address?.provinceOrState}
/>
</div>
......@@ -196,6 +216,8 @@ const CompanyInformationCompany = ({ formik, useStyles }) => {
value={formik.values.organization.address.postalCode}
onChange={formik.handleChange}
ariaLabel={`${organizationName.name}-address`}
error={Boolean(formik.errors.organization?.address?.postalCode)}
helperText={formik.errors.organization?.address?.postalCode}
/>
</div>
</div>
......
......@@ -107,12 +107,7 @@ const Contacts = ({ formik, formikWG }) => {
isWGRepSameAsCompany && formikWG.setFieldValue('workingGroups', newWG);
};
const generateContacts = (
representativeFields,
prefix,
type,
disableInput
) => (
const generateContacts = (representativeFields, prefix, type, disableInput) => (
<>
{representativeFields.map((el, index) => (
<div key={prefix + index} className="col-md-12">
......@@ -124,12 +119,13 @@ const Contacts = ({ formik, formikWG }) => {
requiredMark={true}
disableInput={disableInput}
onChange={
type === 'member'
? (ev) => handleMemberInputChange(ev.target.value, el.name)
: formik.handleChange
type === 'member' ? (ev) => handleMemberInputChange(ev.target.value, el.name) : formik.handleChange
}
value={formik.values.representative?.[type]?.[el.name]}
error={Boolean(formik.errors.representative?.[type]?.[el.name])}
error={
formik.touched.representative?.[type]?.[el.name] &&
Boolean(formik.errors.representative?.[type]?.[el.name])
}
helperText={formik.errors.representative?.[type]?.[el.name]}
/>
</div>
......
......@@ -23,17 +23,11 @@ export default function CompanyInformationVAT({ formik }) {
return (
<>
<h2
className="fw-600 h4 section-header"
id={`${purchasingProcess.name}-ctn`}
>
<h2 className="fw-600 h4 section-header" id={`${purchasingProcess.name}-ctn`}>
Purchasing Process
<span className="orange-star margin-left-5">*</span>
</h2>
<p>
Does your organization require a Purchase Order to facilitate payment of
your membership dues?
</p>
<p>Does your organization require a Purchase Order to facilitate payment of your membership dues?</p>
<div className="row">
<div className="col-md-12 margin-bottom-40">
<DropdownMenu
......@@ -42,6 +36,11 @@ export default function CompanyInformationVAT({ formik }) {
inputValue={formik.values.purchasingAndVAT.purchasingProcess}
optionsArray={OPTIONS_FOR_PURCHASING_PROCESS}
handleChange={formik.handleChange}
error={
formik.touched.purchasingAndVAT?.purchasingProcess &&
Boolean(formik.errors.purchasingAndVAT?.purchasingProcess)
}
helperText={formik.errors.purchasingAndVAT?.purchasingProcess}
/>
</div>
</div>
......@@ -72,6 +71,11 @@ export default function CompanyInformationVAT({ formik }) {
value={formik.values.purchasingAndVAT.vatNumber}
onChange={formik.handleChange}
ariaLabel={`vatRegistration`}
error={
formik.touched.purchasingAndVAT?.vatNumber &&
Boolean(formik.errors.purchasingAndVAT?.vatNumber)
}
helperText={formik.errors.purchasingAndVAT?.vatNumber}
/>
</div>
......@@ -84,6 +88,11 @@ export default function CompanyInformationVAT({ formik }) {
value={formik.values.purchasingAndVAT.countryOfRegistration}
onChange={formik.handleChange}
ariaLabel={`vatRegistration`}
error={
formik.touched.purchasingAndVAT?.countryOfRegistration &&
Boolean(formik.errors.purchasingAndVAT?.countryOfRegistration)
}
helperText={formik.errors.purchasingAndVAT?.countryOfRegistration}
/>
</div>
</div>
......
......@@ -41,6 +41,8 @@ const MembershipLevel = ({ formik }) => {
inputValue={formik.values.membershipLevel}
optionsArray={MEMBERSHIP_LEVELS}
handleChange={formik.handleChange}
error={formik.touched.membershipLevel && Boolean(formik.errors.membershipLevel)}
helperText={formik.errors.membershipLevel}
/>
</div>
</div>
......
......@@ -143,30 +143,17 @@ const WorkingGroup = ({ formik, fullWorkingGroupList, formikOrgValue }) => {
const wgLabelPropery = `${workingGroupsLabel}.${index}.workingGroup-label`;
// if array.find returns a wg obejct, then it means it's already selected
const selectedWGValue =
formik.values.workingGroups.find((item) => {
if (
item.workingGroup?.label === inputValue &&
item['workingGroup-label'] === inputValue
) {
return true;
} else {
return false;
}
});
const selectedWGValue = formik.values.workingGroups.find(
(item) =>
item.workingGroup?.label === inputValue && item['workingGroup-label'] === inputValue
);
// if the wg user types is already selected somewhere else,
// then make the validation fail and show error message
if (selectedWGValue) {
formik.setFieldValue(
wgLabelPropery,
`${inputValue} already selected`
);
formik.setFieldValue(wgLabelPropery, `${inputValue} already selected`);
} else {
formik.setFieldValue(
wgLabelPropery,
inputValue || null
);
formik.setFieldValue(wgLabelPropery, inputValue || null);
}
}}
label={WORKING_GROUPS}
......@@ -176,9 +163,11 @@ const WorkingGroup = ({ formik, fullWorkingGroupList, formikOrgValue }) => {
required={true}
className={classes.textField}
error={Boolean(
formik.touched.workingGroups?.[index]?.['workingGroup'] &&
formik.errors.workingGroups?.[index]?.['workingGroup']
)}
helperText={
formik.touched.workingGroups?.[index]?.['workingGroup'] &&
formik.errors.workingGroups?.[index]?.['workingGroup']
}
/>
......
......@@ -51,6 +51,11 @@ const ParticipationLevel = ({ name, workingGroupUserJoined, fullWorkingGroupList
inputValue={formik.values.workingGroups[theIndex]['participationLevel']}
optionsArray={participationLevelOptions}
handleChange={formik.handleChange}
error={
formik.touched.workingGroups?.[theIndex]?.['participationLevel'] &&
Boolean(formik.errors.workingGroups?.[theIndex]?.['participationLevel'])
}
helperText={formik.errors.workingGroups?.[theIndex]?.['participationLevel']}
/>
)}
</div>
......
import * as yup from 'yup';
import { MAX_LENGTH_HELPER_TEXT } from '../../../Constants/Constants';
import { requiredErrorMsg } from './formFieldModel';
/**
......@@ -35,6 +36,15 @@ const countryList = require('country-list')
.getNames()
.map((item) => item);
const REQUIRED_MAX_YUP = yup.string().required(requiredErrorMsg).max(255, MAX_LENGTH_HELPER_TEXT);
const MAX_YUP = yup.string().max(255, MAX_LENGTH_HELPER_TEXT);
const CONTACT_YUP = yup.object().shape({
email: yup.string().required(requiredErrorMsg).email('Please enter a valid email'),
firstName: REQUIRED_MAX_YUP,
lastName: REQUIRED_MAX_YUP,
jobtitle: REQUIRED_MAX_YUP,
});
export const validationSchema = [
// First step - company Info
yup.object().shape({
......@@ -43,9 +53,17 @@ export const validationSchema = [
address: yup.object().shape({
country: yup
.mixed()
.required('Please enter/select a valid country name')
.oneOf(countryList, 'Please enter/select a valid country name'),
street: REQUIRED_MAX_YUP,
provinceOrState: MAX_YUP,
postalCode: MAX_YUP,
city: REQUIRED_MAX_YUP,
}),
legalName: REQUIRED_MAX_YUP,
revenue: REQUIRED_MAX_YUP,
employeeCount: REQUIRED_MAX_YUP,
type: REQUIRED_MAX_YUP,
twitterHandle: yup
.string()
.min(2, 'Twitter handle is too short')
......@@ -53,21 +71,20 @@ export const validationSchema = [
.matches(/^@([A-Za-z0-9_])*$/, 'Please enter a valid Twitter handle'),
}),
representative: yup.object().shape({
member: yup.object().shape({
email: yup.string().email('Please enter a valid email'),
}),
marketing: yup.object().shape({
email: yup.string().email('Please enter a valid email'),
}),
accounting: yup.object().shape({
email: yup.string().email('Please enter a valid email'),
member: CONTACT_YUP,
marketing: CONTACT_YUP,
accounting: CONTACT_YUP,
}),
purchasingAndVAT: yup.object().shape({
purchasingProcess: REQUIRED_MAX_YUP,
vatNumber: MAX_YUP,
countryOfRegistration: MAX_YUP,
}),
}),
// Second step - membership level
yup.object().shape({
'membershipLevel-label': yup.mixed(),
membershipLevel: REQUIRED_MAX_YUP,
}),
// Third step - working groups
......@@ -77,34 +94,21 @@ export const validationSchema = [
workingGroup: yup
.object()
.nullable()
.test(
'workingGroup',
'Please enter/select a valid working group',
function (selectedWG) {
.required('Please enter/select a valid working group')
.test('workingGroup', 'Please enter/select a valid working group', function (selectedWG) {
const allWorkingGroups = this.options.parent?.allWorkingGroups;
const typedWG = this.options.parent?.['workingGroup-label'];
const isValid =
allWorkingGroups?.includes(typedWG) && selectedWG?.label
? true
: false;
const isValid = allWorkingGroups?.includes(typedWG) && selectedWG?.label ? true : false;
return typedWG ? isValid : true;
}
),
workingGroupRepresentative: yup.object().shape({
email: yup.string().email('Please enter a valid email'),
}),
participationLevel: REQUIRED_MAX_YUP,
workingGroupRepresentative: CONTACT_YUP,
})
),
}),
// Forth, signing Authority
yup.object().shape({
signingAuthorityRepresentative: yup.object().shape({
firstName: yup.string().required(`${requiredErrorMsg}`),
lastName: yup.string().required(`${requiredErrorMsg}`),
jobtitle: yup.string().required(`${requiredErrorMsg}`),
email: yup.string().email('Please enter a valid email'),
}),
signingAuthorityRepresentative: CONTACT_YUP,
}),
];
......@@ -18,7 +18,7 @@ const REVENUE = 'Revenue';
const EMPLOYEE_COUNT = 'Employee Count';
const ORG_TYPE = 'Organization Type';
export const requiredErrorMsg = 'is required';
export const requiredErrorMsg = 'Required field';
// Initial values passed to Formik, this defines
// the form fields, names, and nesting relations of the whole form
......
......@@ -14,11 +14,11 @@ const useStyles = makeStyles(() => ({
},
}));
export default function DropdownMenu({ inputLabel, inputName, inputValue, optionsArray, handleChange, helperText }) {
export default function DropdownMenu({ inputLabel, inputName, inputValue, optionsArray, handleChange, explanationHelperText, error, helperText }) {
const classes = useStyles();
return (
<FormControl margin="dense" variant="outlined" required={true} className={classes.formControl}>
<FormControl margin="dense" variant="outlined" required={true} className={classes.formControl} error={error}>
<InputLabel>{inputLabel}</InputLabel>
<Select
name={inputName}
......@@ -33,7 +33,8 @@ export default function DropdownMenu({ inputLabel, inputName, inputValue, option
</MenuItem>
))}
</Select>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
{error && <FormHelperText>{helperText}</FormHelperText>}
{explanationHelperText && <FormHelperText>{explanationHelperText}</FormHelperText>}
</FormControl>
);
}
......@@ -51,7 +51,7 @@ export default function Input(props) {
value={value}
onChange={onChange}
error={error}
helperText={helperText}
helperText={error && helperText}
size="small"
variant="outlined"
className={classes.root}
......@@ -62,6 +62,7 @@ export default function Input(props) {
className: classes.input,
inputProps: {
'aria-labelledby': ariaLabel,
maxLength: 255,
},
}}
/>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment