Refactor forms to use a generic form component
Replaced the contact form with a generic form component to support multiple form configurations. Moved validation schema and form data to a new structure, allowing dynamic form rendering. Updated the App component to utilize this generic approach for handling different forms.
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import React, {useState} from "react";
|
||||
import './GenericForm.css';
|
||||
import {useNavigate} from 'react-router-dom'
|
||||
import {ErrorMessage, Field, Form, Formik, FormikValues} from "formik";
|
||||
import {Step, UserInput, FormData} from './formInterfaces';
|
||||
import * as Yup from "yup";
|
||||
|
||||
const GenericForm = (formData: FormData) => {
|
||||
const steps: Step[] = formData.steps;
|
||||
const backend: string = formData.backend;
|
||||
const userInput: UserInput = formData.userInput;
|
||||
const spec: Yup.Schema<any> = formData.spec;
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [currentStep, setCurrentStep] = useState<number>(0);
|
||||
|
||||
const handleSubmit = async (e: FormikValues) => {
|
||||
try {
|
||||
const response = await fetch(backend, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(e)
|
||||
})
|
||||
if (!response.ok) {
|
||||
let json: string = JSON.stringify(steps);
|
||||
const blob = new Blob([json], {type: "application/json"});
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = 'form_data.json';
|
||||
link.click();
|
||||
URL.revokeObjectURL(url);
|
||||
//TODO clean up
|
||||
alert("Your form submission was denied by the server, or the server was unable to process it, if you didn't mess with the data please contact the administrator at [email protected]");
|
||||
} else {
|
||||
navigate('/verify-email', {
|
||||
state: {
|
||||
email: e['email']
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
alert("Your form submission was denied by the server, if you didn't mess with the data please contact the administrator at [email protected]")
|
||||
}
|
||||
};
|
||||
|
||||
const next = () => {
|
||||
setCurrentStep(current => current + 1)
|
||||
}
|
||||
|
||||
const prev = () => {
|
||||
setCurrentStep(current => Math.max(current - 1, 0))
|
||||
}
|
||||
|
||||
const [prevLength, setPrevLength] = useState(0);
|
||||
return (
|
||||
<div className="container">
|
||||
<div>
|
||||
<h1>Contact Form</h1>
|
||||
</div>
|
||||
<div>
|
||||
<Formik
|
||||
initialValues={userInput}
|
||||
validationSchema={spec}
|
||||
onSubmit={(values: FormikValues) => {
|
||||
handleSubmit(values);
|
||||
}}
|
||||
>
|
||||
{({
|
||||
touched,
|
||||
errors,
|
||||
isValid,
|
||||
handleChange,
|
||||
values,
|
||||
setFieldTouched
|
||||
}) => (
|
||||
|
||||
<Form>
|
||||
<div>
|
||||
<label>
|
||||
{steps[currentStep].label}
|
||||
<Field
|
||||
type={steps[currentStep].type}
|
||||
name={steps[currentStep].name}
|
||||
required={steps[currentStep].required}
|
||||
min={steps[currentStep].min_length}
|
||||
max={steps[currentStep].max_length}
|
||||
as={(steps[currentStep].type === "textarea") ? "textarea" : "input"}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
handleChange(e);
|
||||
if (prevLength !== values[steps[currentStep].name].length) {
|
||||
setFieldTouched(steps[currentStep].name);
|
||||
setPrevLength(values[steps[currentStep].name].length);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<ErrorMessage name={steps[currentStep].name} component="div"/>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" onClick={prev} disabled={currentStep === 0}>
|
||||
Previous
|
||||
</button>
|
||||
<button type="button" onClick={next}
|
||||
hidden={currentStep === (steps.length - 1)}
|
||||
disabled={(!touched[steps[currentStep].name] || !!errors[steps[currentStep].name]) || currentStep === (steps.length - 1)}>
|
||||
Next
|
||||
</button>
|
||||
<input type="submit" value="Submit"
|
||||
hidden={currentStep !== (steps.length - 1)}
|
||||
disabled={!isValid || currentStep !== (steps.length - 1)}
|
||||
/>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GenericForm;
|
||||
Reference in New Issue
Block a user