Вот как я создаю свои формы.
У меня есть Компонент FormGroup:
Код: Выделить всё
"use client";
import { useEffect, useState } from "react";
type FormGroupProps = {
label?: string;
inputType?: "input" | "textarea" | "select" | "file";
inputProps?:
| React.InputHTMLAttributes
| React.TextareaHTMLAttributes;
selectOptions?: Array;
error?: string;
};
export default function FormGroup({
label,
inputType = "input",
inputProps,
selectOptions = [],
error,
}: FormGroupProps) {
const [hasError, setHasError] = useState(false);
useEffect(() => {
setHasError(error !== undefined);
}, [error]);
return (
className={`form-group flex flex-col h-full gap-2.5 ${
inputProps?.className || ""
}`}
>
{label && (
{label}
)}
{inputType === "input" && (
)}
{error && {error}}
{inputType === "textarea" && (
)}
{inputType === "file" && (
)}
{inputType === "select" && (
{selectOptions?.map((option) => (
{option.label}
))}
)}
);
}
Код: Выделить всё
"use client";
import React, { useState } from "react";
import FormGroup from "./FormGroup";
import FormTitle from "./FormTitle";
interface GenericFormProps {
title: string;
fields: Array;
onSubmit: (data: T) => void;
errors: { [key in keyof T]?: string };
handleChange?: (event: React.ChangeEvent) => void;
}
interface FormData {
nombre: string;
apellido: string;
dni: string;
celular: string;
mail: string;
comentarios: string;
cv?: {
name: string;
type: string;
base64: string;
};
}
function GenericForm({
title,
fields,
onSubmit,
errors,
handleChange,
}: GenericFormProps) {
const initialFormData = {} as T;
const [formData, setFormData] = useState(initialFormData);
const combinedHandleChange = (event: React.ChangeEvent) => {
if (handleChange) {
handleChange(event);
}
const { name, value, files } = event.target as HTMLInputElement & {
files: FileList | null;
};
setFormData((prevData) => ({
...prevData,
[name]: files ? files[0] : value,
}));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
onSubmit(formData);
if (!Object.values(errors).some((error) => error !== undefined)) {
setFormData(initialFormData);
}
};
return (
{fields.map((field, index) => (
))}
Enviar
);
}
export default GenericForm;
Код: Выделить всё
"use client";
import GenericForm from "./GenericForm";
import TrabajaConNosotrosSchema from "@/schemes/trabaja-con-nosotros.scheme";
import handleSubmit from "@/utils/submitForm";
import { useState } from "react";
const TrabajaConNosotros = () => {
const fields = [
{ label: "Nombre", inputType: "input", name: "nombre" },
{ label: "Apellido", inputType: "input", name: "apellido" },
{ label: "DNI (sin puntos)", inputType: "input", name: "dni" },
{ label: "Celular", inputType: "input", name: "celular" },
{ label: "Mail", inputType: "input", name: "mail" },
{ label: "Comentarios", inputType: "textarea", name: "comentarios" },
{ label: "Adjuntar CV", inputType: "file", name: "cv" },
];
const [errors, setErrors] = useState({});
const [selectedFile, setSelectedFile] = useState(null);
const handleChange = (event: React.ChangeEvent) => {
const file = event.target.files?.[0];
if (file) {
setSelectedFile(file);
}
};
const readFileAsync = (file: File): Promise =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result as string);
reader.onerror = reject;
reader.readAsDataURL(file);
});
const onSubmit = async (data: FormData) => {
if (selectedFile) {
try {
const base64 = await readFileAsync(selectedFile);
const formDataWithCV = {
...data,
cv: {
name: selectedFile.name,
type: selectedFile.type,
base64: base64.split(',')[1],
},
};
await handleSubmit(formDataWithCV, TrabajaConNosotrosSchema, 'trabajar_con_nosotros');
setErrors({});
} catch (err) {
console.error(err);
}
} else {
try {
await handleSubmit(data, TrabajaConNosotrosSchema, 'trabajar_con_nosotros');
setErrors({});
} catch (err) {
if (err.inner) {
const formErrors = err.inner.reduce((acc, currentError) => {
acc[currentError.path] = currentError.message;
return acc;
}, {});
setErrors(formErrors);
} else {
setErrors({ general: "Ha ocurrido un error desconocido" });
}
}
}
};
return (
);
};
export default TrabajaConNosotros;
Код: Выделить всё
Uncaught DOMException: An attempt was made to use an object that is not, or is no longer, usableПодробнее здесь: https://stackoverflow.com/questions/793 ... ange-event