mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
chore: Initial Commit
feat: Gestion des inscriptions [#1] feat(frontend): Création des vues pour le paramétrage de l'école [#2] feat: Gestion du login [#6] fix: Correction lors de la migration des modèle [#8] feat: Révision du menu principal [#9] feat: Ajout d'un footer [#10] feat: Création des dockers compose pour les environnements de développement et de production [#12] doc(ci): Mise en place de Husky et d'un suivi de version automatique [#14]
This commit is contained in:
375
Front-End/src/components/Inscription/InscriptionForm.js
Normal file
375
Front-End/src/components/Inscription/InscriptionForm.js
Normal file
@ -0,0 +1,375 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import {BK_GESTIONINSCRIPTION_ELEVES_URL,
|
||||
BK_PROFILE_URL,
|
||||
BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL } from '@/utils/Url';
|
||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken'
|
||||
import useCsrfToken from '@/hooks/useCsrfToken';
|
||||
import { useSearchParams, redirect, useRouter } from 'next/navigation'
|
||||
|
||||
const InscriptionForm = () => {
|
||||
const [step, setStep] = useState(1);
|
||||
const [eleveNom, setEleveNom] = useState('');
|
||||
const [elevePrenom, setElevePrenom] = useState('');
|
||||
const [responsableEmail, setResponsableEmail] = useState('');
|
||||
const [responsableType, setResponsableType] = useState('new');
|
||||
const [selectedEleve, setSelectedEleve] = useState(null);
|
||||
const [existingResponsables, setExistingResponsables] = useState([]);
|
||||
const [allEleves, setAllEleves] = useState([]);
|
||||
const [selectedResponsables, setSelectedResponsables] = useState([]);
|
||||
|
||||
const csrfToken = useCsrfToken();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const request = new Request(
|
||||
`${BK_GESTIONINSCRIPTION_ELEVES_URL}`,
|
||||
{
|
||||
method:'GET',
|
||||
headers: {
|
||||
'Content-Type':'application/json'
|
||||
},
|
||||
}
|
||||
);
|
||||
fetch(request).then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
setAllEleves(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching data:', error);
|
||||
error = error.message;
|
||||
console.log(error);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const nextStep = () => {
|
||||
if (step < 3) {
|
||||
setStep(step + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const prevStep = () => {
|
||||
if (step > 1) {
|
||||
setStep(step - 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEleveSelection = (eleve) => {
|
||||
setSelectedEleve(eleve);
|
||||
setExistingResponsables(eleve.responsables);
|
||||
};
|
||||
|
||||
const handleResponsableSelection = (id) => {
|
||||
setSelectedResponsables((prevSelectedResponsables) => {
|
||||
const newSelectedResponsables = new Set(prevSelectedResponsables);
|
||||
if (newSelectedResponsables.has(id)) {
|
||||
newSelectedResponsables.delete(id);
|
||||
} else {
|
||||
newSelectedResponsables.add(id);
|
||||
}
|
||||
return Array.from(newSelectedResponsables);
|
||||
});
|
||||
};
|
||||
|
||||
const resetResponsableEmail = () => {
|
||||
setResponsableEmail('');
|
||||
};
|
||||
|
||||
const submit = function(){
|
||||
if (selectedResponsables.length !== 0) {
|
||||
const selectedResponsablesIds = selectedResponsables.map(responsableId => responsableId)
|
||||
|
||||
const data = {
|
||||
eleve: {
|
||||
nom: eleveNom,
|
||||
prenom: elevePrenom,
|
||||
},
|
||||
idResponsables: selectedResponsablesIds
|
||||
};
|
||||
|
||||
console.log(data);
|
||||
|
||||
const url = `${BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL}`;
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrfToken
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
|
||||
// Ajouter vérifications sur le retour de la commande (saisies incorrecte, ...)
|
||||
window.location.reload()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Création d'un profil associé à l'adresse mail du responsable saisie
|
||||
// Le profil est inactif
|
||||
const request = new Request(
|
||||
`${BK_PROFILE_URL}`,
|
||||
{
|
||||
method:'POST',
|
||||
headers: {
|
||||
'Content-Type':'application/json',
|
||||
'X-CSRFToken': csrfToken
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify( {
|
||||
email: responsableEmail,
|
||||
password: 'Provisoire01!',
|
||||
username: responsableEmail,
|
||||
is_active: 0, // On rend le profil inactif : impossible de s'y connecter dans la fenêtre du login tant qu'il ne s'est pas inscrit
|
||||
droit:1
|
||||
}),
|
||||
}
|
||||
);
|
||||
fetch(request).then(response => response.json())
|
||||
.then(response => {
|
||||
console.log('Success:', response);
|
||||
if (response.id) {
|
||||
let idProfil = response.id;
|
||||
|
||||
const data = {
|
||||
eleve: {
|
||||
nom: eleveNom,
|
||||
prenom: elevePrenom,
|
||||
responsables: [
|
||||
{
|
||||
mail: responsableEmail,
|
||||
//telephone: telephoneResponsable,
|
||||
profilAssocie: idProfil // Association entre le reponsable de l'élève et le profil créé par défaut précédemment
|
||||
}
|
||||
],
|
||||
freres: []
|
||||
}
|
||||
};
|
||||
const url = `${BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL}`;
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrfToken
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
credentials: 'include'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
|
||||
// Ajouter vérifications sur le retour de la commande (saisies incorrecte, ...)
|
||||
window.location.reload()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching data:', error);
|
||||
error = error.errorMessage;
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-6 w-full max-w-4xl bg-white rounded-xl shadow-md space-y-4">
|
||||
{step === 1 && (
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold mb-4">Nouvel élève</h2>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Nom de l'élève"
|
||||
value={eleveNom}
|
||||
onChange={(e) => setEleveNom(e.target.value)}
|
||||
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-emerald-500 focus:border-emerald-500 italic"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Prénom de l'élève"
|
||||
value={elevePrenom}
|
||||
onChange={(e) => setElevePrenom(e.target.value)}
|
||||
className="mt-4 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-emerald-500 focus:border-emerald-500 italic"
|
||||
/>
|
||||
<div className="flex justify-between mt-4">
|
||||
{step > 1 && (
|
||||
<button
|
||||
onClick={prevStep}
|
||||
className="px-4 py-2 bg-gray-300 text-gray-700 rounded-md shadow-sm hover:bg-gray-400 focus:outline-none"
|
||||
>
|
||||
Précédent
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{step === 2 && (
|
||||
<div className="mt-6">
|
||||
<h2 className="text-2xl font-bold mb-4">Responsable(s)</h2>
|
||||
<div className="flex flex-col space-y-4">
|
||||
<label className="flex items-center space-x-3">
|
||||
<input
|
||||
type="radio"
|
||||
name="responsableType"
|
||||
value="new"
|
||||
checked={responsableType === 'new'}
|
||||
onChange={() => setResponsableType('new')}
|
||||
className="form-radio h-3 w-3 text-emerald-600 focus:ring-emerald-500 hover:ring-emerald-400 checked:bg-emerald-600 checked:h-3 checked:w-3"
|
||||
/>
|
||||
<span className="text-gray-900">Nouveau Responsable</span>
|
||||
</label>
|
||||
<label className="flex items-center space-x-3">
|
||||
<input
|
||||
type="radio"
|
||||
name="responsableType"
|
||||
value="existing"
|
||||
checked={responsableType === 'existing'}
|
||||
onChange={() => {
|
||||
setResponsableType('existing');
|
||||
resetResponsableEmail();
|
||||
}}
|
||||
className="form-radio h-3 w-3 text-emerald-600 focus:ring-emerald-500 hover:ring-emerald-400 checked:bg-emerald-600 checked:h-3 checked:w-3"
|
||||
/>
|
||||
<span className="text-gray-900">Responsable Existant</span>
|
||||
</label>
|
||||
</div>
|
||||
{responsableType === 'new' && (
|
||||
<div className="mt-4">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email du responsable"
|
||||
value={responsableEmail}
|
||||
onChange={(e) => setResponsableEmail(e.target.value)}
|
||||
className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-emerald-500 focus:border-emerald-500 italic"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{responsableType === 'existing' && (
|
||||
<div className="mt-4">
|
||||
<div className="mt-4" style={{ maxHeight: '300px', overflowY: 'auto' }}>
|
||||
<table className="min-w-full bg-white border">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="px-4 py-2 border">Nom</th>
|
||||
<th className="px-4 py-2 border">Prénom</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{allEleves.map((eleve, index) => (
|
||||
<tr
|
||||
key={eleve.id}
|
||||
className={`cursor-pointer ${selectedEleve && selectedEleve.id === eleve.id ? 'bg-emerald-600 text-white' : index % 2 === 0 ? 'bg-emerald-100' : ''}`}
|
||||
onClick={() => handleEleveSelection(eleve)}
|
||||
>
|
||||
<td className="px-4 py-2 border">{eleve.nom}</td>
|
||||
<td className="px-4 py-2 border">{eleve.prenom}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{selectedEleve && (
|
||||
<div className="mt-4">
|
||||
<h3 className="font-bold">Responsables associés à {selectedEleve.nom} {selectedEleve.prenom} :</h3>
|
||||
{existingResponsables.map((responsable) => (
|
||||
<div key={responsable.id}>
|
||||
<label className="flex items-center space-x-3 mt-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedResponsables.includes(responsable.id)}
|
||||
className="form-checkbox h-5 w-5 text-emerald-600"
|
||||
onChange={() => handleResponsableSelection(responsable.id)}
|
||||
/>
|
||||
<span className="text-gray-900">
|
||||
{responsable.nom && responsable.prenom ? `${responsable.nom} ${responsable.prenom}` : `adresse mail : ${responsable.mail}`}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{step === 3 && (
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold mb-4">Récapitulatif</h2>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-xl font-semibold">Élève</h3>
|
||||
<p>Nom : {eleveNom}</p>
|
||||
<p>Prénom : {elevePrenom}</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<h3 className="text-xl font-semibold">Responsable(s)</h3>
|
||||
{responsableType === 'new' && (
|
||||
<p>Email du nouveau responsable : {responsableEmail}</p>
|
||||
)}
|
||||
{responsableType === 'existing' && selectedEleve && (
|
||||
<div>
|
||||
<h4 className="font-bold">Responsables associés à {selectedEleve.nom} {selectedEleve.prenom} :</h4>
|
||||
<ul className="list-disc ml-6">
|
||||
{existingResponsables.filter(responsable => selectedResponsables.includes(responsable.id)).map((responsable) => (
|
||||
<li key={responsable.id}>
|
||||
{responsable.nom && responsable.prenom ? `${responsable.nom} ${responsable.prenom}` : responsable.mail}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-end mt-4 space-x-4">
|
||||
{step > 1 && (
|
||||
<button
|
||||
onClick={prevStep}
|
||||
className="px-4 py-2 bg-gray-300 text-gray-700 rounded-md shadow-sm hover:bg-gray-400 focus:outline-none"
|
||||
>
|
||||
Précédent
|
||||
</button>
|
||||
)}
|
||||
{step < 3 ? (
|
||||
<button
|
||||
onClick={nextStep}
|
||||
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
|
||||
(step === 1 && (!eleveNom || !elevePrenom)) ||
|
||||
(step === 2 && (responsableType === 'new' && !responsableEmail || responsableType === 'existing' && (!selectedEleve || selectedResponsables.length === 0)))
|
||||
? "bg-gray-300 text-gray-700 cursor-not-allowed"
|
||||
: "bg-emerald-500 text-white hover:bg-emerald-600"
|
||||
}`}
|
||||
disabled={(step === 1 && (!eleveNom || !elevePrenom)) ||
|
||||
(step === 2 && (responsableType === 'new' && !responsableEmail || responsableType === 'existing' && (!selectedEleve || selectedResponsables.length === 0)))} // Désactive le bouton "Suivant" selon les conditions spécifiées
|
||||
>
|
||||
Suivant
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<DjangoCSRFToken csrfToken={csrfToken} />
|
||||
<button
|
||||
onClick={submit}
|
||||
className="px-4 py-2 bg-emerald-500 text-white rounded-md shadow-sm hover:bg-emerald-600 focus:outline-none"
|
||||
>
|
||||
Soumettre
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default InscriptionForm;
|
||||
181
Front-End/src/components/Inscription/InscriptionFormShared.js
Normal file
181
Front-End/src/components/Inscription/InscriptionFormShared.js
Normal file
@ -0,0 +1,181 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import InputText from '@/components/InputText';
|
||||
import SelectChoice from '@/components/SelectChoice';
|
||||
import ResponsableInputFields from '@/components/Inscription/ResponsableInputFields';
|
||||
import Loader from '@/components/Loader';
|
||||
import Button from '@/components/Button';
|
||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken';
|
||||
|
||||
|
||||
const niveaux = [
|
||||
{ value:'1', label: 'TPS - Très Petite Section'},
|
||||
{ value:'2', label: 'PS - Petite Section'},
|
||||
{ value:'3', label: 'MS - Moyenne Section'},
|
||||
{ value:'4', label: 'GS - Grande Section'},
|
||||
];
|
||||
|
||||
export default function InscriptionFormShared({
|
||||
initialData,
|
||||
csrfToken,
|
||||
onSubmit,
|
||||
cancelUrl,
|
||||
isLoading = false
|
||||
}) {
|
||||
|
||||
const [formData, setFormData] = useState(() => ({
|
||||
id: initialData?.id || '',
|
||||
nom: initialData?.nom || '',
|
||||
prenom: initialData?.prenom || '',
|
||||
adresse: initialData?.adresse || '',
|
||||
dateNaissance: initialData?.dateNaissance || '',
|
||||
lieuNaissance: initialData?.lieuNaissance || '',
|
||||
codePostalNaissance: initialData?.codePostalNaissance || '',
|
||||
nationalite: initialData?.nationalite || '',
|
||||
medecinTraitant: initialData?.medecinTraitant || '',
|
||||
niveau: initialData?.niveau || ''
|
||||
}));
|
||||
|
||||
const [responsables, setReponsables] = useState(() =>
|
||||
initialData?.responsables || []
|
||||
);
|
||||
|
||||
// Mettre à jour les données quand initialData change
|
||||
useEffect(() => {
|
||||
if (initialData) {
|
||||
setFormData({
|
||||
id: initialData.id || '',
|
||||
nom: initialData.nom || '',
|
||||
prenom: initialData.prenom || '',
|
||||
adresse: initialData.adresse || '',
|
||||
dateNaissance: initialData.dateNaissance || '',
|
||||
lieuNaissance: initialData.lieuNaissance || '',
|
||||
codePostalNaissance: initialData.codePostalNaissance || '',
|
||||
nationalite: initialData.nationalite || '',
|
||||
medecinTraitant: initialData.medecinTraitant || '',
|
||||
niveau: initialData.niveau || ''
|
||||
});
|
||||
setReponsables(initialData.responsables || []);
|
||||
}
|
||||
}, [initialData]);
|
||||
|
||||
const updateFormField = (field, value) => {
|
||||
setFormData(prev => ({...prev, [field]: value}));
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
onSubmit({
|
||||
eleve: {
|
||||
...formData,
|
||||
responsables
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (isLoading) return <Loader />;
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto p-6">
|
||||
<form onSubmit={handleSubmit} className="space-y-8">
|
||||
<DjangoCSRFToken csrfToken={csrfToken}/>
|
||||
{/* Section Élève */}
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<h2 className="text-xl font-bold mb-4 text-gray-800">Informations de l'élève</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<InputText
|
||||
name="nom"
|
||||
label="Nom"
|
||||
value={formData.nom}
|
||||
onChange={(e) => updateFormField('nom', e.target.value)}
|
||||
required
|
||||
/>
|
||||
<InputText
|
||||
name="prenom"
|
||||
label="Prénom"
|
||||
value={formData.prenom}
|
||||
onChange={(e) => updateFormField('prenom', e.target.value)}
|
||||
required
|
||||
/>
|
||||
<InputText
|
||||
name="nationalite"
|
||||
label="Nationalité"
|
||||
value={formData.nationalite}
|
||||
onChange={(e) => updateFormField('nationalite', e.target.value)}
|
||||
/>
|
||||
<InputText
|
||||
name="dateNaissance"
|
||||
type="date"
|
||||
label="Date de Naissance"
|
||||
value={formData.dateNaissance}
|
||||
onChange={(e) => updateFormField('dateNaissance', e.target.value)}
|
||||
required
|
||||
/>
|
||||
<InputText
|
||||
name="lieuNaissance"
|
||||
label="Lieu de Naissance"
|
||||
value={formData.lieuNaissance}
|
||||
onChange={(e) => updateFormField('lieuNaissance', e.target.value)}
|
||||
/>
|
||||
<InputText
|
||||
name="codePostalNaissance"
|
||||
label="Code Postal de Naissance"
|
||||
value={formData.codePostalNaissance}
|
||||
onChange={(e) => updateFormField('codePostalNaissance', e.target.value)}
|
||||
/>
|
||||
<div className="md:col-span-2">
|
||||
<InputText
|
||||
name="adresse"
|
||||
label="Adresse"
|
||||
value={formData.adresse}
|
||||
onChange={(e) => updateFormField('adresse', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<InputText
|
||||
name="medecinTraitant"
|
||||
label="Médecin Traitant"
|
||||
value={formData.medecinTraitant}
|
||||
onChange={(e) => updateFormField('medecinTraitant', e.target.value)}
|
||||
/>
|
||||
<SelectChoice
|
||||
name="niveau"
|
||||
label="Niveau"
|
||||
selected={formData.niveau}
|
||||
callback={(e) => updateFormField('niveau', e.target.value)}
|
||||
choices={niveaux}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Section Responsables */}
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<h2 className="text-xl font-bold mb-4 text-gray-800">Responsables</h2>
|
||||
<ResponsableInputFields
|
||||
responsables={responsables}
|
||||
onResponsablesChange={(id, field, value) => {
|
||||
const updatedResponsables = responsables.map(resp =>
|
||||
resp.id === id ? { ...resp, [field]: value } : resp
|
||||
);
|
||||
setReponsables(updatedResponsables);
|
||||
}}
|
||||
addResponsible={(e) => {
|
||||
e.preventDefault();
|
||||
setReponsables([...responsables, { id: Date.now() }]);
|
||||
}}
|
||||
deleteResponsable={(index) => {
|
||||
const newArray = [...responsables];
|
||||
newArray.splice(index, 1);
|
||||
setReponsables(newArray);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Boutons de contrôle */}
|
||||
<div className="flex justify-end space-x-4">
|
||||
<Button href={cancelUrl} text="Annuler" />
|
||||
<Button type="submit" text="Valider" primary />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
103
Front-End/src/components/Inscription/ResponsableInputFields.js
Normal file
103
Front-End/src/components/Inscription/ResponsableInputFields.js
Normal file
@ -0,0 +1,103 @@
|
||||
import InputText from '@/components/InputText';
|
||||
import InputPhone from '@/components/InputPhone';
|
||||
import Button from '@/components/Button';
|
||||
import React from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import 'react-phone-number-input/style.css'
|
||||
|
||||
export default function ResponsableInputFields({responsables, onResponsablesChange, addResponsible, deleteResponsable}) {
|
||||
const t = useTranslations('ResponsableInputFields');
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
{responsables.map((item, index) => (
|
||||
<div className="p-6 bg-gray-50 rounded-lg shadow-sm" key={index}>
|
||||
<div className='flex justify-between items-center mb-4'>
|
||||
<h3 className='text-xl font-bold'>{t('responsable')} {index+1}</h3>
|
||||
{responsables.length > 1 && (
|
||||
<Button
|
||||
text={t('delete')}
|
||||
onClick={() => deleteResponsable(index)}
|
||||
className="w-32"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="idResponsable" value={item.id} />
|
||||
|
||||
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-4 mb-4'>
|
||||
<InputText
|
||||
name="nomResponsable"
|
||||
type="text"
|
||||
label={t('lastname')}
|
||||
value={item.nom}
|
||||
onChange={(event) => {onResponsablesChange(item.id, "nom", event.target.value)}}
|
||||
/>
|
||||
<InputText
|
||||
name="prenomResponsable"
|
||||
type="text"
|
||||
label={t('firstname')}
|
||||
value={item.prenom}
|
||||
onChange={(event) => {onResponsablesChange(item.id, "prenom", event.target.value)}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-4 mb-4'>
|
||||
<InputText
|
||||
name="mailResponsable"
|
||||
type="email"
|
||||
label={t('email')}
|
||||
value={item.mail}
|
||||
onChange={(event) => {onResponsablesChange(item.id, "mail", event.target.value)}}
|
||||
/>
|
||||
<InputPhone
|
||||
name="telephoneResponsable"
|
||||
label={t('phone')}
|
||||
value={item.telephone}
|
||||
onChange={(event) => {onResponsablesChange(item.id, "telephone", event)}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-4 mb-4'>
|
||||
<InputText
|
||||
name="dateNaissanceResponsable"
|
||||
type="date"
|
||||
label={t('birthdate')}
|
||||
value={item.dateNaissance}
|
||||
onChange={(event) => {onResponsablesChange(item.id, "dateNaissance", event.target.value)}}
|
||||
/>
|
||||
<InputText
|
||||
name="professionResponsable"
|
||||
type="text"
|
||||
label={t('profession')}
|
||||
value={item.profession}
|
||||
onChange={(event) => {onResponsablesChange(item.id, "profession", event.target.value)}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='grid grid-cols-1 gap-4'>
|
||||
<InputText
|
||||
name="adresseResponsable"
|
||||
type="text"
|
||||
label={t('address')}
|
||||
value={item.adresse}
|
||||
onChange={(event) => {onResponsablesChange(item.id, "adresse", event.target.value)}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
text={t('add_responsible')}
|
||||
onClick={(e) => addResponsible(e)}
|
||||
primary
|
||||
icon={<i className="icon profile-add" />}
|
||||
type="button"
|
||||
className="w-64"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user