mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-06-04 21:36:12 +00:00
feat: Ajout des composants manquant dans le FormTemplateBuilder [N3WTS-17]
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import InputTextIcon from './InputTextIcon';
|
||||
import SelectChoice from './SelectChoice';
|
||||
@ -16,23 +16,69 @@ export default function AddFieldModal({
|
||||
}) {
|
||||
const isEditing = editingIndex >= 0;
|
||||
|
||||
const [currentField, setCurrentField] = useState(
|
||||
editingField || {
|
||||
id: '',
|
||||
label: '',
|
||||
type: 'text',
|
||||
required: false,
|
||||
icon: '',
|
||||
options: [],
|
||||
text: '',
|
||||
placeholder: '',
|
||||
}
|
||||
);
|
||||
const [currentField, setCurrentField] = useState({
|
||||
id: '',
|
||||
label: '',
|
||||
type: 'text',
|
||||
required: false,
|
||||
icon: '',
|
||||
options: [],
|
||||
text: '',
|
||||
placeholder: '',
|
||||
acceptTypes: '',
|
||||
maxSize: 5, // 5MB par défaut
|
||||
checked: false,
|
||||
validation: {
|
||||
pattern: '',
|
||||
minLength: '',
|
||||
maxLength: '',
|
||||
},
|
||||
});
|
||||
|
||||
const [showIconPicker, setShowIconPicker] = useState(false);
|
||||
const [newOption, setNewOption] = useState('');
|
||||
|
||||
const { control, handleSubmit, reset } = useForm();
|
||||
const { control, handleSubmit, reset, setValue } = useForm();
|
||||
|
||||
// Mettre à jour l'état et les valeurs du formulaire lorsque editingField change
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
const defaultValues = editingField || {
|
||||
id: '',
|
||||
label: '',
|
||||
type: 'text',
|
||||
required: false,
|
||||
icon: '',
|
||||
options: [],
|
||||
text: '',
|
||||
placeholder: '',
|
||||
acceptTypes: '',
|
||||
maxSize: 5,
|
||||
checked: false,
|
||||
validation: {
|
||||
pattern: '',
|
||||
minLength: '',
|
||||
maxLength: '',
|
||||
},
|
||||
};
|
||||
|
||||
setCurrentField(defaultValues);
|
||||
|
||||
// Réinitialiser le formulaire avec les valeurs de l'élément à éditer
|
||||
reset({
|
||||
type: defaultValues.type,
|
||||
label: defaultValues.label,
|
||||
placeholder: defaultValues.placeholder,
|
||||
required: defaultValues.required,
|
||||
icon: defaultValues.icon,
|
||||
text: defaultValues.text,
|
||||
acceptTypes: defaultValues.acceptTypes,
|
||||
maxSize: defaultValues.maxSize,
|
||||
checked: defaultValues.checked,
|
||||
validation: defaultValues.validation,
|
||||
});
|
||||
}
|
||||
}, [isOpen, editingField, reset]);
|
||||
|
||||
// Ajouter une option au select
|
||||
const addOption = () => {
|
||||
@ -326,6 +372,195 @@ export default function AddFieldModal({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentField.type === 'radio' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Options des boutons radio
|
||||
</label>
|
||||
<div className="flex gap-2 mb-2">
|
||||
<input
|
||||
type="text"
|
||||
value={newOption}
|
||||
onChange={(e) => setNewOption(e.target.value)}
|
||||
placeholder="Nouvelle option"
|
||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
onKeyPress={(e) =>
|
||||
e.key === 'Enter' && (e.preventDefault(), addOption())
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
text="Ajouter"
|
||||
onClick={addOption}
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{currentField.options.map((option, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center justify-between bg-gray-50 p-2 rounded"
|
||||
>
|
||||
<span>{option}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeOption(index)}
|
||||
className="text-red-500 hover:text-red-700"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentField.type === 'phone' && (
|
||||
<Controller
|
||||
name="validation.pattern"
|
||||
control={control}
|
||||
defaultValue={currentField.validation?.pattern || ''}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<InputTextIcon
|
||||
label="Format de téléphone (optionnel, exemple: ^\\+?[0-9]{10,15}$)"
|
||||
name="phonePattern"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
setCurrentField({
|
||||
...currentField,
|
||||
validation: {
|
||||
...currentField.validation,
|
||||
pattern: e.target.value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{currentField.type === 'file' && (
|
||||
<>
|
||||
<Controller
|
||||
name="acceptTypes"
|
||||
control={control}
|
||||
defaultValue={currentField.acceptTypes || ''}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<InputTextIcon
|
||||
label="Types de fichiers acceptés (ex: .pdf,.jpg,.png)"
|
||||
name="acceptTypes"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
setCurrentField({
|
||||
...currentField,
|
||||
acceptTypes: e.target.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="maxSize"
|
||||
control={control}
|
||||
defaultValue={currentField.maxSize || 5}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<InputTextIcon
|
||||
label="Taille maximale (MB)"
|
||||
name="maxSize"
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
setCurrentField({
|
||||
...currentField,
|
||||
maxSize: parseInt(e.target.value) || 5,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentField.type === 'checkbox' && (
|
||||
<>
|
||||
<div className="flex items-center mt-2">
|
||||
<Controller
|
||||
name="checked"
|
||||
control={control}
|
||||
defaultValue={currentField.checked || false}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<input
|
||||
type="checkbox"
|
||||
id="defaultChecked"
|
||||
checked={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.checked);
|
||||
setCurrentField({
|
||||
...currentField,
|
||||
checked: e.target.checked,
|
||||
});
|
||||
}}
|
||||
className="mr-2"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<label htmlFor="defaultChecked">Coché par défaut</label>
|
||||
</div>
|
||||
<div className="flex items-center mt-2">
|
||||
<Controller
|
||||
name="horizontal"
|
||||
control={control}
|
||||
defaultValue={currentField.horizontal || false}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<input
|
||||
type="checkbox"
|
||||
id="horizontal"
|
||||
checked={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.checked);
|
||||
setCurrentField({
|
||||
...currentField,
|
||||
horizontal: e.target.checked,
|
||||
});
|
||||
}}
|
||||
className="mr-2"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<label htmlFor="horizontal">Label au-dessus (horizontal)</label>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentField.type === 'toggle' && (
|
||||
<div className="flex items-center mt-2">
|
||||
<Controller
|
||||
name="checked"
|
||||
control={control}
|
||||
defaultValue={currentField.checked || false}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<input
|
||||
type="checkbox"
|
||||
id="defaultToggled"
|
||||
checked={value}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.checked);
|
||||
setCurrentField({
|
||||
...currentField,
|
||||
checked: e.target.checked,
|
||||
});
|
||||
}}
|
||||
className="mr-2"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<label htmlFor="defaultToggled">Activé par défaut</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2 mt-6">
|
||||
<Button
|
||||
type="submit"
|
||||
|
||||
Reference in New Issue
Block a user