Selaa lähdekoodia

Add validation to personalInformation form

Tatiana Inama 6 vuotta sitten
vanhempi
commit
ce0293bd81
2 muutettua tiedostoa jossa 86 lisäystä ja 19 poistoa
  1. 4 4
      src/App.tsx
  2. 82 15
      src/PersonalInformation.tsx

+ 4 - 4
src/App.tsx

@@ -2,7 +2,7 @@ import React, { useState } from 'react';
 import './App.css';
 import 'bootstrap/dist/css/bootstrap.css';
 
-import PersonalInformation, { PersonalInformationValues } from './PersonalInformation';
+import PersonalInformation, { FormData } from './PersonalInformation';
 
 type SectionComponentProps = {
   changePage: () => void
@@ -42,7 +42,7 @@ const TermsAndConditions: React.FunctionComponent<SectionComponentProps> = ({ ch
 
 
 type AnswersData = {
-  personalInformation: PersonalInformationValues,
+  personalInformation: FormData,
 };
 
 const App = () => {
@@ -70,7 +70,8 @@ const App = () => {
     PersonalInformation({
       changePage: () => {setCurrentPage(currentPage + 1)},
       closeApp: () => {alert('thank you for your interest, but permission from your parent/guardian is required before you are able to participate.')},
-      saveData: (data: PersonalInformationValues) => {
+      saveData: (data: FormData) => {
+        console.log("data", data)
         saveAnswers({
           ...answers,
           personalInformation: data
@@ -78,7 +79,6 @@ const App = () => {
       }
     }),
   ];
-  console.log("currentPage", currentPage);
   return (
     <div className="App bg-light">
       <div className="container">

+ 82 - 15
src/PersonalInformation.tsx

@@ -11,7 +11,7 @@ import {
   FormText,
 } from 'reactstrap';
 
-export type PersonalInformationValues = {
+export type FormData = {
   age: string,
   ageAuthorized: boolean,
   gender: string,
@@ -23,14 +23,53 @@ export type PersonalInformationValues = {
   nonNative: string
 };
 
+type FormDataKey = keyof FormData;
+
 type PersonalInformationProps = {
   changePage: () => void,
   closeApp: () => void,
-  saveData: (data: PersonalInformationValues) => void
+  saveData: (data: FormData) => void
+};
+
+type Validations = {
+  [field in FormDataKey]: boolean;
 };
 
+const notEmpty = (value: string) => value !== '';
+
+const notEmptyIfValid = (value: string, conditional: string) => {
+  if (conditional === 'other') {
+    return notEmpty(value)
+  }
+  return true;
+};
+
+const validateData = (values: FormData): Validations => ({
+  age: notEmpty(values.age),
+  ageAuthorized: true,
+  gender: notEmpty(values.gender),
+  genderCustom: notEmptyIfValid(values.genderCustom, values.gender),
+  ethnicity: notEmpty(values.ethnicity),
+  ethnicityCustom: notEmptyIfValid(values.ethnicityCustom, values.ethnicity),
+  birthPlace: notEmpty(values.birthPlace),
+  currentPlace: notEmpty(values.currentPlace),
+  nonNative: true
+});
+
+const _initialValidation = {
+  age: false,
+  ageAuthorized: false,
+  gender: false,
+  genderCustom: false,
+  ethnicity: false,
+  ethnicityCustom: false,
+  birthPlace: false,
+  currentPlace: false,
+  nonNative: false
+}
+
 export const PersonalInformation: React.FunctionComponent<PersonalInformationProps> = ({ changePage, closeApp, saveData }) => {
-  const [ values, setValue ] = useState<PersonalInformationValues>({
+  const [ values, setValue ] = useState<FormData>({
     age: '',
     ageAuthorized: false,
     gender: '',
@@ -42,7 +81,26 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
     nonNative: '',
   });
 
+  const [ submitted, submit ] = useState(false);
   const [ openModal, toggleModal ] = useState(false);
+  const [ validationResult, validate ] = useState<Validations>({..._initialValidation});
+
+  const revalidate = () => {
+    if (submitted) {
+      validate(validateData(values))
+    }
+  };
+
+  const setInputValidation = (field: FormDataKey): undefined | { valid: true } | { invalid: true } => {
+    if (!submitted) {
+      return undefined;
+    }
+    if (validationResult[field]) {
+      return { valid: true }
+    } else {
+      return { invalid: true }
+    }
+  }
 
   const setAgeAuthorization = (authorized: boolean) => {
     setValue({
@@ -51,11 +109,14 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
     })
   };
 
-  const handleSelect = (value: keyof PersonalInformationValues ) => (e: React.ChangeEvent<HTMLSelectElement|HTMLInputElement>) => {
+  const handleSelect = (value: keyof FormData ) => (e: React.ChangeEvent<HTMLSelectElement|HTMLInputElement>) => {
     setValue({
       ...values,
       [value]: e.target.value
     });
+    if (submitted) {
+      revalidate();
+    }
   };
 
   return (
@@ -90,9 +151,12 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
             if (e.target.value === '1') {
               toggleModal(true);
             } else {
-              handleSelect('age')(e)
+              handleSelect('age')(e);
             }
-          }} required>
+          }}
+          required
+          { ...setInputValidation('age') }
+          >
             <option value="" disabled>Please chooose</option>
             <option value="1">11 - 17</option>
             <option value="2">18 - 25</option>
@@ -105,7 +169,7 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
 
         <FormGroup>
           <Label for="gender">Gender</Label>
-          <Input type="select" id="gender" value={values.gender} onChange={handleSelect('gender')} required>
+          <Input type="select" id="gender" value={values.gender} onChange={handleSelect('gender')} required { ...setInputValidation('gender') }>
             <option value="" disabled>Please choose</option>
             <option value="male">Male</option>
             <option value="female">Female</option>
@@ -113,7 +177,7 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
           </Input>
           {
             values.gender === 'other' && (
-              <Input type="text" id="gender-custom" className="mt-2" value={values.genderCustom} onChange={handleSelect('genderCustom')} required/>
+              <Input type="text" id="gender-custom" className="mt-2" value={values.genderCustom} onChange={handleSelect('genderCustom')} { ...setInputValidation('genderCustom') } required/>
             )
           }
         </FormGroup>
@@ -125,7 +189,7 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
               The following options are taken from the 2011 UK Census. You can also define yours selecting the 'None of the above' option.
             </FormText>
           </Label>
-          <Input type="select" id="ethnicity" value={values.ethnicity} onChange={handleSelect('ethnicity')} required>
+          <Input type="select" id="ethnicity" value={values.ethnicity} onChange={handleSelect('ethnicity')} { ...setInputValidation('ethnicity') } required>
             <option value="" disabled>Please choose</option>
             <optgroup label="White">
               <option value="English/Welsh/Scottish/Northern Irish/British">English/Welsh/Scottish/Northern Irish/British</option>
@@ -154,24 +218,24 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
           </Input>
           {
             values.ethnicity === 'other' && (
-              <Input type="text" id="ethnicity-custom" className="mt-2" required value={values.ethnicityCustom} onChange={handleSelect('ethnicityCustom')} />
+              <Input type="text" id="ethnicity-custom" className="mt-2" required value={values.ethnicityCustom} onChange={handleSelect('ethnicityCustom')} { ...setInputValidation('ethnicityCustom') }/>
             )
           }
         </FormGroup>
 
         <FormGroup>
           <Label for="place-birth">Place of birth (Town/City and Country)</Label>
-          <Input id="place-birth" type="text" required value={values.birthPlace} onChange={handleSelect('birthPlace')} />
+          <Input id="place-birth" type="text" required value={values.birthPlace} onChange={handleSelect('birthPlace')} { ...setInputValidation('birthPlace') }/>
         </FormGroup>
 
         <FormGroup>
           <Label for="post-code">Current place of residence (postcode)</Label>
-          <Input id="post-code" type="text" value={values.currentPlace} onChange={handleSelect('currentPlace')} required/>
+          <Input id="post-code" type="text" value={values.currentPlace} onChange={handleSelect('currentPlace')} { ...setInputValidation('currentPlace') }/>
         </FormGroup>
 
         <FormGroup>
           <Label for="non-native">If you were <b>not</b> born in Merseyside:</Label>
-          <Input type="select" id="non-native" value={values.nonNative} onChange={handleSelect('nonNative')}>
+          <Input type="select" id="non-native" value={values.nonNative} onChange={handleSelect('nonNative')} { ...setInputValidation('nonNative') }>
             <option value='' disabled>Please choose</option>
             <option value="1">Less than two years</option>
             <option value="2">3-5 years</option>
@@ -182,8 +246,11 @@ export const PersonalInformation: React.FunctionComponent<PersonalInformationPro
 
         <Button
           onClick={() => {
-            console.log(values);
-            saveData(values);
+            if (!submitted) {
+              submit(true);
+            }
+            validate(validateData(values));
+            saveData(values)
           }}
         >Next</Button>
       </Form>