feat: creation d'un FormRenderer.js pour creer un formulaire dynamique [NEWTS-17]

This commit is contained in:
Luc SORIGNET
2025-08-31 12:26:04 +02:00
parent 482e8c1357
commit 9481a0132d
47 changed files with 324 additions and 130 deletions

View File

@ -0,0 +1,194 @@
import logger from '@/utils/logger';
import { useForm, Controller } from 'react-hook-form';
import SelectChoice from './SelectChoice';
import InputTextIcon from './InputTextIcon';
import * as LucideIcons from 'lucide-react';
import Button from './Button';
import DjangoCSRFToken from '../DjangoCSRFToken';
import WisiwigTextArea from './WisiwigTextArea';
/*
* Récupère une icône Lucide par son nom.
*/
export function getIcon(name) {
if (Object.keys(LucideIcons).includes(name)) {
const Icon = LucideIcons[name];
return Icon ?? null;
} else {
return null;
}
}
const formConfigTest = {
id: 0,
title: 'Mon formulaire dynamique',
submitLabel: 'Envoyer',
fields: [
{ id: 'name', label: 'Nom', type: 'text', required: true },
{ id: 'email', label: 'Email', type: 'email' },
{
id: 'email2',
label: 'Email',
type: 'text',
icon: 'Mail',
},
{
id: 'role',
label: 'Rôle',
type: 'select',
options: ['Admin', 'Utilisateur', 'Invité'],
required: true,
},
{
type: 'paragraph',
text: "Bonjour, Bienvenue dans ce formulaire d'inscription haha",
},
{
id: 'birthdate',
label: 'Date de naissance',
type: 'date',
icon: 'Calendar',
},
{
id: 'textarea',
label: 'toto',
type: 'textarea',
},
],
};
export default function FormRenderer({
formConfig = formConfigTest,
csrfToken,
}) {
const {
handleSubmit,
control,
formState: { errors },
reset,
} = useForm();
const onSubmit = (data) => {
logger.debug('=== DÉBUT onSubmit ===');
logger.debug('Réponses :', data);
const formattedData = {
//TODO: idDossierInscriptions: 123,
formId: formConfig.id,
responses: { ...data },
};
//TODO: ENVOYER LES DONNÉES AU BACKEND
alert('Données reçues : ' + JSON.stringify(formattedData, null, 2));
reset(); // Réinitialiser le formulaire après soumission
logger.debug('=== FIN onSubmit ===');
};
const onError = (errors) => {
logger.error('=== ERREURS DE VALIDATION ===');
logger.error('Erreurs :', errors);
alert('Erreurs de validation : ' + JSON.stringify(errors, null, 2));
};
return (
<form
onSubmit={handleSubmit(onSubmit, onError)}
className="max-w-md mx-auto"
>
{csrfToken ? <DjangoCSRFToken csrfToken={csrfToken} /> : null}
<h2 className="text-2xl font-bold text-center mb-4">
{formConfig.title}
</h2>
{formConfig.fields.map((field) => (
<div key={field.id} className="flex flex-col mt-4">
{field.type === 'paragraph' && <p>{field.text}</p>}
{(field.type === 'text' ||
field.type === 'email' ||
field.type === 'date') && (
<Controller
name={field.id}
control={control}
rules={{ required: field.required }}
render={({ field: { onChange, value, name } }) => (
<InputTextIcon
label={field.label}
required={field.required}
IconItem={field.icon ? getIcon(field.icon) : null}
type={field.type}
name={name}
value={value || ''}
onChange={onChange}
errorMsg={
errors[field.id]
? field.required
? `${field.label} est requis`
: 'Champ invalide'
: ''
}
/>
)}
/>
)}
{field.type === 'select' && (
<Controller
name={field.id}
control={control}
rules={{ required: field.required }}
render={({ field: { onChange, value, name } }) => (
<SelectChoice
label={field.label}
required={field.required}
name={name}
selected={value || ''}
callback={onChange}
choices={field.options.map((e) => ({ label: e, value: e }))}
placeHolder={`Sélectionner ${field.label.toLowerCase()}`}
errorMsg={
errors[field.id]
? field.required
? `${field.label} est requis`
: 'Champ invalide'
: ''
}
/>
)}
/>
)}
{field.type === 'textarea' && (
<Controller
name={field.id}
control={control}
rules={{ required: field.required }}
render={({ field: { onChange, value } }) => (
<WisiwigTextArea
label={field.label}
placeholder={field.placeholder}
value={value || ''}
onChange={onChange}
required={field.required}
errorMsg={
errors[field.id]
? field.required
? `${field.label} est requis`
: 'Champ invalide'
: ''
}
/>
)}
/>
)}
</div>
))}
<div className="form-group-submit mt-4">
<Button
type="submit"
primary
text={formConfig.submitLabel ? formConfig.submitLabel : 'Envoyer'}
className="mb-1 px-4 py-2 rounded-md shadow bg-emerald-500 text-white hover:bg-emerald-600 w-full"
/>
</div>
</form>
);
}