form validation with formik
This commit was merged in pull request #41.
This commit is contained in:
@@ -1,61 +1,87 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import InputDetails from "./IntroDetails";
|
||||
import OTPSection from "./OtpSection";
|
||||
import SpouseDetails from "./SpouseDetails";
|
||||
import { Button } from "..";
|
||||
import React from "react";
|
||||
|
||||
// interface Option {
|
||||
// value: string;
|
||||
// label: string;
|
||||
// }
|
||||
import { Button, InputCompOne } from "..";
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
const initialValues = {
|
||||
title: "",
|
||||
marital_status: "",
|
||||
agent_id: "",
|
||||
bvn: "",
|
||||
first_name: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
surname: "",
|
||||
dob: "",
|
||||
second_name: "",
|
||||
spouse_bvn: "",
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
title: Yup.string()
|
||||
.required("Required"),
|
||||
marital_status: Yup.string()
|
||||
.required("Required"),
|
||||
agent_id: Yup.string()
|
||||
.required("Required"),
|
||||
bvn: Yup.string()
|
||||
.required("BVN is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, "must be 11 digits")
|
||||
.max(11, "must be 11 digits"),
|
||||
first_name: Yup.string()
|
||||
.required("Required"),
|
||||
phone: Yup.string()
|
||||
.required("Required"),
|
||||
email: Yup.string()
|
||||
.required("Required")
|
||||
.email("Wrong email format"),
|
||||
surname: Yup.string()
|
||||
.required("Required"),
|
||||
dob: Yup.string()
|
||||
.required("Required"),
|
||||
});
|
||||
|
||||
interface BasicInfoProps {
|
||||
inputValues: {
|
||||
title: string;
|
||||
marital: string;
|
||||
agentId: string;
|
||||
bvn: string;
|
||||
firstName: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
surname: string;
|
||||
dob: string;
|
||||
secondName: string;
|
||||
spouseBVN: string;
|
||||
};
|
||||
setInputValues: React.Dispatch<React.SetStateAction<any>>;
|
||||
handleNextStep: any;
|
||||
}
|
||||
|
||||
const BasicInfo: React.FC<BasicInfoProps> = ({
|
||||
inputValues,
|
||||
setInputValues,
|
||||
handleNextStep,
|
||||
}) => {
|
||||
const [hideOTPComponent, setHideOTPComponent] = useState<boolean>(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
// const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target as HTMLInputElement;
|
||||
setInputValues((prev: typeof inputValues) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
// const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
// const { name, value } = e.target as HTMLInputElement;
|
||||
|
||||
const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target as HTMLInputElement;
|
||||
// if (name === "bvn") {
|
||||
// const isNumeric = /^[0-9]+$/.test(value);
|
||||
|
||||
if (name === "bvn") {
|
||||
const isNumeric = /^[0-9]+$/.test(value);
|
||||
// if (isNumeric) {
|
||||
// if (value.length === 10) {
|
||||
// setHideOTPComponent(false);
|
||||
// } else {
|
||||
// setHideOTPComponent(true);
|
||||
// }
|
||||
// } else {
|
||||
// console.log("Invalid BVN");
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
if (isNumeric) {
|
||||
if (value.length === 10) {
|
||||
setHideOTPComponent(false);
|
||||
} else {
|
||||
setHideOTPComponent(true);
|
||||
}
|
||||
} else {
|
||||
console.log("Invalid BVN");
|
||||
}
|
||||
}
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -64,38 +90,222 @@ const BasicInfo: React.FC<BasicInfoProps> = ({
|
||||
<h1 className="font-semibold text-[2.375rem] text-[#5C2684] my-[.5rem]">
|
||||
Let’s Get You Started
|
||||
</h1>
|
||||
<form>
|
||||
<InputDetails
|
||||
inputValues={inputValues}
|
||||
handleChange={handleChange}
|
||||
handleInput={handleInput}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
{!hideOTPComponent && (
|
||||
<>
|
||||
<OTPSection
|
||||
inputValues={inputValues}
|
||||
handleChange={handleChange}
|
||||
handleInput={handleInput}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
<SpouseDetails
|
||||
inputValues={inputValues}
|
||||
handleChange={handleChange}
|
||||
handleInput={handleInput}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
<Button
|
||||
className="mt-8 btn-R bg-[#5A2C82]"
|
||||
text="Enter"
|
||||
type="button"
|
||||
onClick={handleNextStep}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props)=>(
|
||||
<Form>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
BASIC INFORMATION
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-2">
|
||||
<div className="flex flex-col gap-4 max-w-[15.6875rem]">
|
||||
<InputCompOne
|
||||
parentInputClass="max-w-[224px] w-full"
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="title"
|
||||
label="Title"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
select={true}
|
||||
selectClass="w-full h-[36px] rounded-[6px]"
|
||||
selectOptions={titleOptions}
|
||||
selectValue={props.values.title}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.title && props.touched.title) ? props.errors.title : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentInputClass="max-w-[224px] w-full"
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="marital_status"
|
||||
label="Marital Status"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
select={true}
|
||||
selectClass="w-full h-[36px] rounded-[6px]"
|
||||
selectOptions={maritalStatusOptions}
|
||||
selectValue={props.values.marital_status}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.marital_status && props.touched.marital_status) ? props.errors.marital_status : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentInputClass="max-w-[224px] w-full"
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="agent_id"
|
||||
label="Direct Sales Agent ID"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
select={true}
|
||||
selectClass="w-full h-[36px] rounded-[6px]"
|
||||
selectOptions={{loading: false, data:[{ value: "", label: "Select" }, { value: "dd", label: "AB001" }]}}
|
||||
selectValue={props.values.agent_id}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.agent_id && props.touched.agent_id) ? props.errors.agent_id : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
label="BVN"
|
||||
name="bvn"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( To get your BVN, dial *565*0# )"
|
||||
labelSpanClass="text-[11px] text-[#7a7373]"
|
||||
placeholder="Enter your BVN"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px] gap-[2px]"
|
||||
input={true}
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] rounded-[6px]"
|
||||
value={props.values.bvn}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.bvn && props.touched.bvn) ? props.errors.bvn : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="First Name"
|
||||
name="first_name"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.first_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.first_name && props.touched.first_name) ? props.errors.first_name : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Phone Number"
|
||||
name="phone"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.phone}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.phone && props.touched.phone) ? props.errors.phone : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Email Address"
|
||||
name="email"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.email && props.touched.email) ? props.errors.email : ''}
|
||||
/>
|
||||
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Surname"
|
||||
name="surname"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem] px-3"
|
||||
value={props.values.surname}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.surname && props.touched.surname) ? props.errors.surname : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Date of Birth"
|
||||
name="dob"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputType='date'
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem] px-3"
|
||||
value={props.values.dob}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.dob && props.touched.dob) ? props.errors.dob : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Second Name"
|
||||
name="second_name"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem] px-3"
|
||||
value={props.values.second_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.second_name && props.touched.second_name) ? props.errors.second_name : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5 mt-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
SPOUSE DETAILS ( If not applicable, please move to the next stage )
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-2">
|
||||
<div className="flex flex-col gap-4 max-w-[15.6875rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="BVN"
|
||||
name="spouse_bvn"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( To get your BVN, dial *565*0# )"
|
||||
labelSpanClass="text-[11px] text-[#7a7373]"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.spouse_bvn}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.spouse_bvn && props.touched.spouse_bvn) ? props.errors.spouse_bvn : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<>
|
||||
<Button
|
||||
className="mt-8 btn-R bg-[#5A2C82]"
|
||||
text="Enter"
|
||||
type="submit"
|
||||
/>
|
||||
</>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BasicInfo;
|
||||
|
||||
|
||||
|
||||
interface SelectOption {
|
||||
loading: boolean;
|
||||
data: {value: string;
|
||||
label: string}[]
|
||||
}
|
||||
|
||||
const maritalStatusOptions: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Select" },
|
||||
{ value: "single", label: "Single" },
|
||||
{ value: "married", label: "Married" },
|
||||
{ value: "divorced", label: "Divorced" },
|
||||
{ value: "widowed", label: "Widowed" },
|
||||
]
|
||||
}
|
||||
|
||||
const titleOptions: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Select" },
|
||||
{ value: "ms", label: "Ms" },
|
||||
{ value: "mr", label: "Mr" },
|
||||
{ value: "miss", label: "Miss" },
|
||||
{ value: "mrs", label: "Mrs" },
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user