'use client'; import { useEffect, useState } from 'react'; import { Button, Input, LoaderSpinner, Select } from '@theme/components'; import { twMerge } from 'tailwind-merge'; import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import * as yup from 'yup'; import DynamicForm from './dynamic-form'; import { AllFieldClassesType, FieldPropertiesType, FormField, FormPropertiesType, Schema } from '@akinon/next/types'; import { useLocalization } from '@akinon/next/hooks'; export function GenerateFormFields({ schema, allFieldClasses, fieldProperties, formProperties, submitButtonText }: { schema: Schema; allFieldClasses?: AllFieldClassesType; fieldProperties: FieldPropertiesType[]; formProperties: FormPropertiesType; submitButtonText: string; }) { const { t } = useLocalization(); const [fields, setFields] = useState([]); const [loading, setIsLoading] = useState(true); const [isSubmitting, setIsSubmitting] = useState(false); const [submitStatus, setSubmitStatus] = useState< 'idle' | 'success' | 'error' >('idle'); const [submitMessage, setSubmitMessage] = useState(''); const generateValidationSchema = () => { const schemaObject = {}; Object.keys(schema).forEach((key) => { const item = schema[key]; if (item.validators) { const { validators } = item; let fieldSchema; if (item.input_type === 'integer') { fieldSchema = yup .number() .transform((value) => (Number.isNaN(value) ? null : value)) .nullable(); } else { fieldSchema = yup.string(); } if (validators.required) { fieldSchema = fieldSchema.required(); } if (validators.min_length !== undefined) { fieldSchema = fieldSchema.min(validators.min_length); } if (validators.max_length !== undefined) { fieldSchema = fieldSchema.max(validators.max_length); } if (validators.min_value !== undefined) { fieldSchema = fieldSchema.min(validators.min_value); } if (validators.max_value !== undefined) { fieldSchema = fieldSchema.max(validators.max_value); } schemaObject[item.key] = fieldSchema; } }); return yup.object().shape(schemaObject); }; const { handleSubmit, register, reset, formState: { errors } } = useForm({ resolver: yupResolver(generateValidationSchema()) }); useEffect(() => { const sortedFields = Object.keys(schema) .map((key) => { const item = schema[key]; fieldProperties.find((fieldProperty) => { if (fieldProperty.key === item.key) { item.class = fieldProperty.className; item.attributes = fieldProperty.attributes; item.labelClass = fieldProperty.labelClassName; item.wrapperClass = fieldProperty.wrapperClassName; } }); return item; }) .sort((a, b) => a.order - b.order); setFields(sortedFields); setIsLoading(false); }, [schema, fieldProperties]); const onSubmit = async (data) => { setIsSubmitting(true); setSubmitStatus('idle'); setSubmitMessage(''); try { const formData = new FormData(); Object.keys(data).forEach((key) => { formData.append(key, data[key]); }); const response = await fetch(formProperties.actionUrl, { method: 'POST', body: formData }); if (response.ok) { setSubmitStatus('success'); setSubmitMessage(t('common.forms.success')); reset(); } else { setSubmitStatus('error'); setSubmitMessage(t('common.forms.error')); } } catch (error) { console.error(t('common.forms.submit_error'), error); setSubmitStatus('error'); setSubmitMessage(t('common.forms.error')); } finally { setIsSubmitting(false); } }; const generateField = (field: FormField) => { const inputType = field.input_type; if (!inputType) { return null; } switch (inputType) { case 'text': case 'email': return (
); case 'integer': return (
); case 'text_area': return (