Add react-select component and integrate into FormHTML
Added `react-select` library dependency to `package.json` and lock file. Created a new `FormHTML` component in `formHTML.tsx` to handle form field rendering, including support for `select` fields using `react-select` for multi-select functionality.
This commit is contained in:
@@ -30,7 +30,7 @@ export const apply: FormData = {
|
||||
{
|
||||
label: "Do you meet the minimum pc requirements?",
|
||||
name: "pc_requirements",
|
||||
type: "text",
|
||||
type: "dropdown",
|
||||
min_length: 2,
|
||||
max_length: 3,
|
||||
required: true,
|
||||
@@ -50,7 +50,7 @@ export const apply: FormData = {
|
||||
{
|
||||
label: "What is your preferred pronoun?",
|
||||
name: "pronoun",
|
||||
type: "text",
|
||||
type: "dropdown",
|
||||
min_length: 0,
|
||||
max_length: 16,
|
||||
required: true,
|
||||
@@ -75,10 +75,12 @@ export const apply: FormData = {
|
||||
{
|
||||
label: "Which days are you normally able to come on?",
|
||||
name: "available_days",
|
||||
type: "textarea",
|
||||
type: "select",
|
||||
min_length: 6,
|
||||
max_length: 128,
|
||||
required: true,
|
||||
drop_down: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
|
||||
multiple: true
|
||||
},
|
||||
{
|
||||
label: "What time of the day are you normally online?",
|
||||
@@ -177,10 +179,11 @@ export const apply: FormData = {
|
||||
.max(168, 'There are only 168 hours in a week')
|
||||
.required('Please enter the average time you will be available each week'),
|
||||
|
||||
available_days: Yup.string()
|
||||
.min(6, 'Please provide at least 6 characters')
|
||||
.max(128, 'Please provide at most 128 characters')
|
||||
.required('Please enter your available days are required'),
|
||||
available_days: Yup.lazy(value =>
|
||||
Array.isArray(value)
|
||||
? Yup.array().of(Yup.string()).min(1).max(7).required('Please select the days you will be available on')
|
||||
: Yup.string().required('Please select the days you will be available on')
|
||||
),
|
||||
|
||||
available_time: Yup.string()
|
||||
.min(3, 'Please provide at least 3 characters')
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import React, {useState} from "react";
|
||||
import './GenericForm.css';
|
||||
import {Field} from "formik";
|
||||
import {FormHandlerProps} from "./formInterfaces";
|
||||
import ReactSelect from 'react-select';
|
||||
|
||||
const FormHTML: React.FC<FormHandlerProps> = ({
|
||||
steps,
|
||||
currentStep,
|
||||
handleChange,
|
||||
setFieldTouched,
|
||||
setFieldValue,
|
||||
values,
|
||||
prevLength,
|
||||
setPrevLength
|
||||
}) => {
|
||||
const currentField = steps[currentStep];
|
||||
let fieldOptions = currentField.drop_down && Array.isArray(currentField.drop_down)
|
||||
? currentField.drop_down.map((value: string) => ({ value, label: value }))
|
||||
: [];
|
||||
const fieldValues = values[currentStep] ? values[currentStep].split(', ').map(value => ({ value, label: value })) : []
|
||||
|
||||
const [selectedOptions, setSelectedOptions] = useState(fieldValues);
|
||||
|
||||
if (currentField.type === 'select') {
|
||||
return (
|
||||
<ReactSelect
|
||||
name={currentField.name}
|
||||
isMulti={true}
|
||||
options={fieldOptions}
|
||||
value={selectedOptions}
|
||||
onChange={(selected) => {
|
||||
let value: string = '';
|
||||
if (selected === null) {
|
||||
value = '';
|
||||
setSelectedOptions([]);
|
||||
} else if (Array.isArray(selected)) {
|
||||
value = selected.map(s => s.value).join(', ');
|
||||
setSelectedOptions(selected);
|
||||
}
|
||||
|
||||
setFieldValue(currentField.name, value);
|
||||
|
||||
if (prevLength !== value.length) {
|
||||
setFieldTouched(currentField.name);
|
||||
setPrevLength(value.length);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (currentField.type === 'dropdown') {
|
||||
return (
|
||||
<Field as="select"
|
||||
name={steps[currentStep].name}
|
||||
{...(steps[currentStep].multiple && { multiple: true })}
|
||||
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
handleChange(e);
|
||||
if (prevLength !== values[steps[currentStep].name].length) {
|
||||
setFieldTouched(steps[currentStep].name);
|
||||
setPrevLength(values[steps[currentStep].name].length);
|
||||
}
|
||||
}}>
|
||||
{steps[currentStep].drop_down?.map((option, i) => (
|
||||
<option key={i} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<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);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default FormHTML;
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Yup from "yup";
|
||||
import React from "react";
|
||||
|
||||
type InputNames = "username" | "email" | "question" | "discord" | "pc_requirements" | "age" | "pronoun" | "join_date" |
|
||||
"avg_time" | "available_days" | "available_time" | "staff_experience" | "plugin_experience" | "why_staff" |
|
||||
@@ -7,12 +8,13 @@ type InputNames = "username" | "email" | "question" | "discord" | "pc_requiremen
|
||||
export interface Step {
|
||||
label: string;
|
||||
name: InputNames;
|
||||
type: "text" | "email" | "textarea" | "date";
|
||||
type: "text" | "email" | "textarea" | "date" | "dropdown" | "select";
|
||||
min_length: number;
|
||||
max_length: number;
|
||||
required: boolean;
|
||||
additional_info?: string;
|
||||
drop_down?: string[]
|
||||
multiple?: boolean
|
||||
}
|
||||
|
||||
export interface UserInput {
|
||||
@@ -30,4 +32,15 @@ export type FormData = {
|
||||
export interface FormProperties {
|
||||
path: string
|
||||
formData: FormData;
|
||||
}
|
||||
}
|
||||
|
||||
export type FormHandlerProps = {
|
||||
steps: Step[];
|
||||
currentStep: number;
|
||||
handleChange: (event: React.ChangeEvent<any>) => void;
|
||||
setFieldTouched: (name: string) => void;
|
||||
setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void;
|
||||
values: UserInput;
|
||||
prevLength: number;
|
||||
setPrevLength: (len: number) => void;
|
||||
};
|
||||
@@ -4,6 +4,8 @@ import {useNavigate} from 'react-router-dom'
|
||||
import {ErrorMessage, Field, Form, FormikProvider, FormikValues, useFormik} from "formik";
|
||||
import {Step, UserInput, FormData} from './formInterfaces';
|
||||
import * as Yup from "yup";
|
||||
import formHTML from "./formHTML";
|
||||
import FormHTML from "./formHTML";
|
||||
|
||||
const GenericForm = (formData: FormData) => {
|
||||
const steps: Step[] = formData.steps;
|
||||
@@ -16,6 +18,7 @@ const GenericForm = (formData: FormData) => {
|
||||
const [currentStep, setCurrentStep] = useState<number>(0);
|
||||
|
||||
const handleSubmit = async (formikValues: FormikValues) => {
|
||||
console.log(JSON.stringify(formikValues))
|
||||
try {
|
||||
const response = await fetch(backend, {
|
||||
method: 'POST',
|
||||
@@ -71,6 +74,7 @@ const GenericForm = (formData: FormData) => {
|
||||
handleChange,
|
||||
values,
|
||||
setFieldTouched,
|
||||
setFieldValue,
|
||||
} = formik;
|
||||
|
||||
const [prevLength, setPrevLength] = useState(0);
|
||||
@@ -99,41 +103,10 @@ const GenericForm = (formData: FormData) => {
|
||||
</label>
|
||||
</label>
|
||||
<label>
|
||||
{
|
||||
steps[currentStep].drop_down ? (
|
||||
<Field as="select"
|
||||
name={steps[currentStep].name}
|
||||
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
handleChange(e);
|
||||
if (prevLength !== values[steps[currentStep].name].length) {
|
||||
setFieldTouched(steps[currentStep].name);
|
||||
setPrevLength(values[steps[currentStep].name].length);
|
||||
}
|
||||
}}>
|
||||
{steps[currentStep].drop_down?.map((option, i) => (
|
||||
<option key={i} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
) : (
|
||||
<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);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<FormHTML steps={steps} currentStep={currentStep} handleChange={handleChange}
|
||||
setFieldTouched={setFieldTouched} setFieldValue={setFieldValue} values={values}
|
||||
prevLength={prevLength} setPrevLength={setPrevLength}>
|
||||
</FormHTML>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user