From 01fd5fa010c0c3f7af1e4b87c79c0d2343f9e9fd Mon Sep 17 00:00:00 2001 From: Cuong Vu Date: Thu, 16 Jul 2020 15:01:05 +0700 Subject: [PATCH 1/2] fix: #2067 wip remove hoc --- .../forms/contact-information-form.tsx | 139 +++++++++--------- 1 file changed, 66 insertions(+), 73 deletions(-) diff --git a/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx b/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx index d7b68f39b8..b6238b23bf 100644 --- a/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx +++ b/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx @@ -1,5 +1,4 @@ import React from 'react' -import { compose } from 'redux' import { FormSection, FormHeading, @@ -7,57 +6,78 @@ import { Input, Button, Form, - withFormik, - FormikProps, FormikBag, LevelRight, Grid, GridItem, + Formik, } from '@reapit/elements' import { DeveloperModel } from '@reapit/foundations-ts-definitions' import { validate } from '@/utils/form/settings-contact-information' -export type ContactInformationFormProps = FormikProps - +export type ContactInformationFormProps = { + developerInformation: DeveloperModel | null + updateDeveloperInformation: (values: ContactInformationValues) => void +} export const ContactInformationForm: React.FC = ({ - isSubmitting, - isValidating, - isValid, + developerInformation, + updateDeveloperInformation, }) => { return ( - -
- Contact Information - Please use the fields below to edit your contact information - - - - - - - - - - - - - - - - - - - -
-
+ + {({ isSubmitting, isValidating, isValid }) => { + return ( + +
+ Contact Information + Please use the fields below to edit your contact information + + + + + + + + + + + + + + + + + + + +
+
+ ) + }} +
) } @@ -68,38 +88,11 @@ export type ContactInformationValues = { telephone: string } -export const mapPropsContactInformation = ({ developerInformation }: EnhanceContactInformationProps) => { - return { - jobTitle: developerInformation?.jobTitle || '', - telephone: developerInformation?.telephone || '', - companyName: developerInformation?.company || '', - name: developerInformation?.name || '', - } -} - -export type EnhanceContactInformationProps = { - developerInformation: DeveloperModel | null - updateDeveloperInformation: (values: ContactInformationValues) => void -} - -export const handleSubmitContactInformation = async ( - values: ContactInformationValues, - { setSubmitting, props }: FormikBag, -) => { +export const handleSubmitContactInformation = ( + updateDeveloperInformation: (values: ContactInformationValues) => void, +) => (values: ContactInformationValues, { setSubmitting }: FormikBag) => { setSubmitting(true) - props.updateDeveloperInformation(values) + updateDeveloperInformation(values) } -export const withContactInformationForm = withFormik({ - displayName: 'WithContactInformationForm', - mapPropsToValues: mapPropsContactInformation, - handleSubmit: handleSubmitContactInformation, - validate, -}) - -const EnhanceContactInformation = compose>(withContactInformationForm)( - ContactInformationForm, -) -EnhanceContactInformation.displayName = 'EnhanceContactInformation' - -export default EnhanceContactInformation +export default ContactInformationForm From 9458df4b697bda14d0394ddf8aa3e1a785597e8d Mon Sep 17 00:00:00 2001 From: Cuong Vu Date: Thu, 16 Jul 2020 17:06:22 +0700 Subject: [PATCH 2/2] fix: #2067 developer profile validation --- .../contact-information-form.test.tsx.snap | 512 +++++++++++++----- .../contact-information-form.test.tsx | 116 ++-- .../forms/contact-information-form.tsx | 93 +++- .../settings/forms/form-schema/form-fields.ts | 26 + .../forms/form-schema/validation-schema.ts | 34 ++ .../company-information.test.tsx.snap | 1 + .../company-information-section.tsx | 2 +- .../__tests__/settings-contact-information.ts | 34 -- .../form/settings-contact-information.ts | 19 - 9 files changed, 573 insertions(+), 264 deletions(-) create mode 100644 packages/developer-portal/src/components/pages/settings/forms/form-schema/form-fields.ts create mode 100644 packages/developer-portal/src/components/pages/settings/forms/form-schema/validation-schema.ts delete mode 100644 packages/developer-portal/src/utils/form/__tests__/settings-contact-information.ts delete mode 100644 packages/developer-portal/src/utils/form/settings-contact-information.ts diff --git a/packages/developer-portal/src/components/pages/settings/forms/__tests__/__snapshots__/contact-information-form.test.tsx.snap b/packages/developer-portal/src/components/pages/settings/forms/__tests__/__snapshots__/contact-information-form.test.tsx.snap index 112fd1ce60..3b3363367d 100644 --- a/packages/developer-portal/src/components/pages/settings/forms/__tests__/__snapshots__/contact-information-form.test.tsx.snap +++ b/packages/developer-portal/src/components/pages/settings/forms/__tests__/__snapshots__/contact-information-form.test.tsx.snap @@ -1,129 +1,395 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ContactInformationForm should match snapshot 1`] = ` - -
- - Contact Information - - - Please use the fields below to edit your contact information - - - - - - - - - - - - - - - - - - - - Save Changes - - - - + + + `; -exports[`ContactInformationForm should match snapshot 2`] = ` - -
- - Contact Information - - - Please use the fields below to edit your contact information - - - - - - - - - - - - - - - - - - - - Save Changes - - - - +exports[`ContactInformationForm should match snapshot with developerInfomation = null 1`] = ` + + + `; diff --git a/packages/developer-portal/src/components/pages/settings/forms/__tests__/contact-information-form.test.tsx b/packages/developer-portal/src/components/pages/settings/forms/__tests__/contact-information-form.test.tsx index 0bac943f89..86821e77bc 100644 --- a/packages/developer-portal/src/components/pages/settings/forms/__tests__/contact-information-form.test.tsx +++ b/packages/developer-portal/src/components/pages/settings/forms/__tests__/contact-information-form.test.tsx @@ -1,84 +1,72 @@ import React from 'react' import { shallow } from 'enzyme' import { + defaultInitialValues, + generateInitialValues, ContactInformationForm, - ContactInformationFormProps, - mapPropsContactInformation, - EnhanceContactInformationProps, ContactInformationValues, handleSubmitContactInformation, } from '../contact-information-form' -import { mockFormikAction } from '@/utils/mock-formik' -import { developerStub } from '@/sagas/__stubs__/developer' +import appState from '@/reducers/__stubs__/app-state' +import { DeveloperModel } from '@reapit/foundations-ts-definitions' + +const developerInfo: DeveloperModel | null = appState.settings.developerInfomation + +const valuesMock: ContactInformationValues = { + name: 'name', + jobTitle: 'jobTitle', + telephone: '12341234', + companyName: 'companyName', +} describe('ContactInformationForm', () => { it('should match snapshot', () => { - const mockProps = { - isSubmitting: false, - isValidating: false, - isValid: true, - } as ContactInformationFormProps - const wrapper = shallow() + const wrapper = shallow( + , + ) expect(wrapper).toMatchSnapshot() }) - it('should match snapshot', () => { - const mockProps = { - isSubmitting: true, - isValidating: true, - isValid: false, - } as ContactInformationFormProps - const wrapper = shallow() + + it('should match snapshot with developerInfomation = null', () => { + const wrapper = shallow( + , + ) expect(wrapper).toMatchSnapshot() }) - describe('mapPropsContactInformation', () => { - it('should run correctly', () => { - const mockProps: EnhanceContactInformationProps = { - developerInformation: developerStub, - updateDeveloperInformation: jest.fn(), - } - const result = mapPropsContactInformation(mockProps) - const output = { - jobTitle: mockProps.developerInformation?.jobTitle || '', - telephone: mockProps.developerInformation?.telephone || '', - companyName: mockProps.developerInformation?.company || '', - name: mockProps.developerInformation?.name || '', - } - expect(result).toEqual(output) - }) +}) - it('should return to fall back', () => { - const mockProps: EnhanceContactInformationProps = { - developerInformation: developerStub, - updateDeveloperInformation: jest.fn(), - } - const result = mapPropsContactInformation(mockProps) - const output = { - jobTitle: mockProps.developerInformation?.jobTitle || '', - telephone: mockProps.developerInformation?.telephone || '', - companyName: mockProps.developerInformation?.company || '', - name: mockProps.developerInformation?.name || '', - } - expect(result).toEqual(output) +describe('handleSubmitContactInformation', () => { + it('should run correctly', () => { + const updateDeveloperInformation = jest.fn() + const setSubmitting = jest.fn() + const fn = handleSubmitContactInformation(updateDeveloperInformation) + fn(valuesMock, { setSubmitting } as any) + expect(setSubmitting).toHaveBeenCalledWith(true) + expect(updateDeveloperInformation).toHaveBeenCalledWith(valuesMock) + }) +}) + +describe('generateInitialValues', () => { + it('should return correctly', () => { + const result = generateInitialValues({ + developerInfo, + defaultInitialValues, }) + const { name, company: companyName, telephone, jobTitle } = developerInfo as DeveloperModel + const expectedResult = { + name, + companyName, + telephone, + jobTitle, + } + expect(result).toEqual(expectedResult) }) - describe('handleSubmitContactInformation', () => { - it('should call setSubmitting', () => { - const mockValues: ContactInformationValues = { - companyName: 'Reapit Ltd', - name: 'Reapit Ltd', - jobTitle: 'Head of Cloud', - telephone: '01234 567890', - } - const mockForm = { - ...mockFormikAction, - } - const mockProps: EnhanceContactInformationProps = { - developerInformation: developerStub, - updateDeveloperInformation: jest.fn(), - } - handleSubmitContactInformation(mockValues, { ...mockForm, props: mockProps }) - expect(mockForm.setSubmitting).toBeCalledWith(true) - expect(mockProps.updateDeveloperInformation).toBeCalled() + + it('should return correctly with developerInfo null', () => { + const result = generateInitialValues({ + developerInfo: null, + defaultInitialValues, }) + expect(result).toEqual(defaultInitialValues) }) }) diff --git a/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx b/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx index b6238b23bf..0dc44e0b3f 100644 --- a/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx +++ b/packages/developer-portal/src/components/pages/settings/forms/contact-information-form.tsx @@ -6,32 +6,68 @@ import { Input, Button, Form, - FormikBag, LevelRight, Grid, GridItem, Formik, + FormikHelpers, } from '@reapit/elements' import { DeveloperModel } from '@reapit/foundations-ts-definitions' -import { validate } from '@/utils/form/settings-contact-information' +import { validationSchema } from './form-schema/validation-schema' +import { formFieldsContactInfomation } from './form-schema/form-fields' + +const { nameField, jobTitleField, telephoneField, companyNameField } = formFieldsContactInfomation + +export type ContactInformationValues = { + companyName: string + name: string + jobTitle: string + telephone: string +} export type ContactInformationFormProps = { developerInformation: DeveloperModel | null updateDeveloperInformation: (values: ContactInformationValues) => void } + +export const defaultInitialValues: ContactInformationValues = { + name: '', + companyName: '', + telephone: '', + jobTitle: '', +} + +export const generateInitialValues = ({ + defaultInitialValues, + developerInfo, +}: { + defaultInitialValues: ContactInformationValues + developerInfo: DeveloperModel | null +}): ContactInformationValues => { + if (!developerInfo) { + return defaultInitialValues + } + + const { name = '', company: companyName = '', telephone = '', jobTitle = '' } = developerInfo + + return { + name, + companyName, + telephone, + jobTitle, + } +} + export const ContactInformationForm: React.FC = ({ developerInformation, updateDeveloperInformation, }) => { + const initialValues = generateInitialValues({ defaultInitialValues, developerInfo: developerInformation }) + return ( {({ isSubmitting, isValidating, isValid }) => { @@ -45,21 +81,39 @@ export const ContactInformationForm: React.FC = ({ - + - + - + @@ -81,16 +135,9 @@ export const ContactInformationForm: React.FC = ({ ) } -export type ContactInformationValues = { - companyName: string - name: string - jobTitle: string - telephone: string -} - export const handleSubmitContactInformation = ( updateDeveloperInformation: (values: ContactInformationValues) => void, -) => (values: ContactInformationValues, { setSubmitting }: FormikBag) => { +) => (values: ContactInformationValues, { setSubmitting }: FormikHelpers) => { setSubmitting(true) updateDeveloperInformation(values) } diff --git a/packages/developer-portal/src/components/pages/settings/forms/form-schema/form-fields.ts b/packages/developer-portal/src/components/pages/settings/forms/form-schema/form-fields.ts new file mode 100644 index 0000000000..a3a4ef21a1 --- /dev/null +++ b/packages/developer-portal/src/components/pages/settings/forms/form-schema/form-fields.ts @@ -0,0 +1,26 @@ +import { FormFieldInfo } from '@reapit/elements' + +type FieldContactInformation = 'companyNameField' | 'nameField' | 'jobTitleField' | 'telephoneField' + +export const formFieldsContactInfomation: Record = { + companyNameField: { + name: 'companyName', + label: 'Company Name', + errorMessage: 'Company name is not valid', + }, + nameField: { + name: 'name', + label: 'Full Name', + errorMessage: 'Full name is not valid', + }, + jobTitleField: { + name: 'jobTitle', + label: 'Job Title', + errorMessage: 'Job title is not valid', + }, + telephoneField: { + name: 'telephone', + label: 'Telephone', + errorMessage: 'Telephone is not valid', + }, +} diff --git a/packages/developer-portal/src/components/pages/settings/forms/form-schema/validation-schema.ts b/packages/developer-portal/src/components/pages/settings/forms/form-schema/validation-schema.ts new file mode 100644 index 0000000000..b2039b9ac5 --- /dev/null +++ b/packages/developer-portal/src/components/pages/settings/forms/form-schema/validation-schema.ts @@ -0,0 +1,34 @@ +import * as Yup from 'yup' +import { telephoneRegex, personNameRegex, letterNumberSpaceRegex } from '@reapit/utils' +import errorMessages from '@/constants/error-messages' +import { formFieldsContactInfomation } from './form-fields' + +const { nameField, jobTitleField, telephoneField, companyNameField } = formFieldsContactInfomation + +const { FIELD_REQUIRED, MAXIMUM_CHARACTER_LENGTH } = errorMessages + +export const validationSchema = Yup.object().shape({ + [companyNameField.name]: Yup.string() + .trim() + .required(FIELD_REQUIRED) + .matches(letterNumberSpaceRegex, companyNameField.errorMessage) + .max(256, MAXIMUM_CHARACTER_LENGTH(256)), + + [nameField.name]: Yup.string() + .trim() + .required(FIELD_REQUIRED) + .matches(personNameRegex, nameField.errorMessage) + .max(256, MAXIMUM_CHARACTER_LENGTH(256)), + + [telephoneField.name]: Yup.string() + .trim() + .required(FIELD_REQUIRED) + .matches(telephoneRegex, telephoneField.errorMessage) + .max(20, MAXIMUM_CHARACTER_LENGTH(20)), + + [jobTitleField.name]: Yup.string() + .trim() + .required(FIELD_REQUIRED) + .matches(letterNumberSpaceRegex, jobTitleField.errorMessage) + .max(256, MAXIMUM_CHARACTER_LENGTH(256)), +}) diff --git a/packages/developer-portal/src/components/pages/settings/settings-organisation-tab/organisation-form/__tests__/__snapshots__/company-information.test.tsx.snap b/packages/developer-portal/src/components/pages/settings/settings-organisation-tab/organisation-form/__tests__/__snapshots__/company-information.test.tsx.snap index 77655ce483..ede95408b7 100644 --- a/packages/developer-portal/src/components/pages/settings/settings-organisation-tab/organisation-form/__tests__/__snapshots__/company-information.test.tsx.snap +++ b/packages/developer-portal/src/components/pages/settings/settings-organisation-tab/organisation-form/__tests__/__snapshots__/company-information.test.tsx.snap @@ -31,6 +31,7 @@ exports[`CompanyInformationSection should match a snapshot when no error 1`] = ` = ({ f - + diff --git a/packages/developer-portal/src/utils/form/__tests__/settings-contact-information.ts b/packages/developer-portal/src/utils/form/__tests__/settings-contact-information.ts deleted file mode 100644 index 8fb7e5d1bd..0000000000 --- a/packages/developer-portal/src/utils/form/__tests__/settings-contact-information.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { validate } from '../settings-contact-information' -import { ContactInformationValues } from '@/components/pages/settings/forms/contact-information-form' -import errorMessages from '@/constants/error-messages' - -describe('ContactInformationValues validation', () => { - it('validate invalid fullname', () => { - const input: ContactInformationValues = { - companyName: 'Reapit', - name: '123&&&&', - jobTitle: 'Developer', - telephone: '0845 123 4512', - } - - const validateRequiredKeys = ['name'] - - const output = {} - for (let key of validateRequiredKeys) { - output[key] = errorMessages.FIELD_INVALID_NAME - } - expect(validate(input)).toEqual(output) - }) - - it('validate invalid telephone', () => { - const input: ContactInformationValues = { - companyName: 'Reapit', - name: 'Levy', - jobTitle: 'Developer', - telephone: '0845 xxx yyy', - } - expect(validate(input)).toEqual({ - telephone: errorMessages.FIELD_PHONE_NUMER, - }) - }) -}) diff --git a/packages/developer-portal/src/utils/form/settings-contact-information.ts b/packages/developer-portal/src/utils/form/settings-contact-information.ts deleted file mode 100644 index 9fda227f0a..0000000000 --- a/packages/developer-portal/src/utils/form/settings-contact-information.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ContactInformationValues } from '@/components/pages/settings/forms/contact-information-form' -import ErrorMessages from '@/constants/error-messages' -import { isValidPersonName, isValidTelephone } from '@/utils/validate' - -export type SettingsContactInformationErrorKeys = Partial - -export const validate = (values: ContactInformationValues) => { - let errors: SettingsContactInformationErrorKeys = {} - - if (values.telephone && !isValidTelephone(values.telephone)) { - errors.telephone = ErrorMessages.FIELD_PHONE_NUMER - } - - if (values.name && !isValidPersonName(values.name)) { - errors.name = ErrorMessages.FIELD_INVALID_NAME - } - - return errors -}