refactor: Composant *InscriptionForm*

This commit is contained in:
N3WT DE COMPET
2024-11-24 11:55:26 +01:00
parent edc97242f2
commit 56e27628f8
3 changed files with 179 additions and 203 deletions

View File

@ -134,7 +134,7 @@ class FicheInscriptionView(APIView):
di.save() di.save()
ficheInscriptions_List=bdd.getAllObjects(FicheInscription) ficheInscriptions_List=bdd.getAllObjects(FicheInscription)
return JsonResponse({'totalInscrits':len(ficheInscriptions_List)}, safe=False) return JsonResponse(ficheEleve_serializer.data, safe=False)
return JsonResponse(ficheEleve_serializer.errors, safe=False) return JsonResponse(ficheEleve_serializer.errors, safe=False)

View File

@ -24,7 +24,8 @@ import { BK_GESTIONINSCRIPTION_FICHESINSCRIPTION_URL,
BK_GESTIONINSCRIPTION_ARCHIVE_URL, BK_GESTIONINSCRIPTION_ARCHIVE_URL,
BK_GESTIONINSCRIPTION_CLASSES_URL, BK_GESTIONINSCRIPTION_CLASSES_URL,
BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL, BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL,
BK_GESTIONINSCRIPTION_ELEVES_URL } from '@/utils/Url'; BK_GESTIONINSCRIPTION_ELEVES_URL,
BK_PROFILE_URL } from '@/utils/Url';
import DjangoCSRFToken from '@/components/DjangoCSRFToken' import DjangoCSRFToken from '@/components/DjangoCSRFToken'
import useCsrfToken from '@/hooks/useCsrfToken'; import useCsrfToken from '@/hooks/useCsrfToken';
@ -64,6 +65,10 @@ export default function Page({ params: { locale } }) {
setIsOpen(true); setIsOpen(true);
} }
const closeModal = () => {
setIsOpen(false);
}
const openModalAssociationEleve = (eleveSelected) => { const openModalAssociationEleve = (eleveSelected) => {
setIsOpenAffectationClasse(true); setIsOpenAffectationClasse(true);
setEleve(eleveSelected); setEleve(eleveSelected);
@ -273,6 +278,109 @@ export default function Page({ params: { locale } }) {
fetchData(newPage, itemsPerPage); // Appeler fetchData directement ici fetchData(newPage, itemsPerPage); // Appeler fetchData directement ici
}; };
const createDI = (updatedData) => {
if (updatedData.selectedResponsables.length !== 0) {
const selectedResponsablesIds = updatedData.selectedResponsables.map(responsableId => responsableId)
const data = {
eleve: {
nom: updatedData.eleveNom,
prenom: updatedData.elevePrenom,
},
idResponsables: selectedResponsablesIds
};
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);
setFichesInscriptionsDataEnCours(prevState => [...prevState, data]);
setTotalPending(totalPending+1);
})
.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: updatedData.responsableEmail,
password: 'Provisoire01!',
username: updatedData.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: updatedData.eleveNom,
prenom: updatedData.elevePrenom,
responsables: [
{
mail: updatedData.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);
setFichesInscriptionsDataEnCours(prevState => [...prevState, data]);
setTotalPending(totalPending+1);
})
.catch((error) => {
console.error('Error:', error);
});
}
})
.catch(error => {
console.error('Error fetching data:', error);
error = error.errorMessage;
console.log(error);
});
}
closeModal();
}
const validateAndAssociate = (updatedData) => { const validateAndAssociate = (updatedData) => {
fetch(`${BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL}/${eleve.id}`, { fetch(`${BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL}/${eleve.id}`, {
method: 'PUT', method: 'PUT',
@ -516,7 +624,9 @@ const columnsSubscribed = [
setIsOpen={setIsOpen} setIsOpen={setIsOpen}
title={"Création d'un nouveau dossier d'inscription"} title={"Création d'un nouveau dossier d'inscription"}
ContentComponent={() => ( ContentComponent={() => (
<InscriptionForm eleves={eleves} onSubmit={handleModalSubmit} /> <InscriptionForm eleves={eleves}
onSubmit={createDI}
/>
)} )}
/> />
)} )}

View File

@ -1,46 +1,25 @@
import { useState, useEffect } from 'react'; import { useState } 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 InscriptionForm = ( { eleves, onSubmit }) => {
const [step, setStep] = useState(1); const [formData, setFormData] = useState({
const [eleveNom, setEleveNom] = useState(''); eleveNom: '',
const [elevePrenom, setElevePrenom] = useState(''); elevePrenom: '',
const [responsableEmail, setResponsableEmail] = useState(''); responsableEmail: '',
const [responsableType, setResponsableType] = useState('new'); selectedResponsables: [],
const [selectedEleve, setSelectedEleve] = useState(null); responsableType: 'new'
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 [step, setStep] = useState(1);
const [selectedEleve, setSelectedEleve] = useState('');
const [existingResponsables, setExistingResponsables] = useState([]);
const handleChange = (e) => {
const { name, value, type } = e.target;
setFormData((prevState) => ({
...prevState,
[name]: value,
}));
};
const nextStep = () => { const nextStep = () => {
if (step < 3) { if (step < 3) {
@ -56,165 +35,52 @@ const InscriptionForm = () => {
const handleEleveSelection = (eleve) => { const handleEleveSelection = (eleve) => {
setSelectedEleve(eleve); setSelectedEleve(eleve);
setFormData((prevData) => ({
...prevData,
selectedResponsables: []
}));
setExistingResponsables(eleve.responsables); setExistingResponsables(eleve.responsables);
}; };
const handleResponsableSelection = (id) => { const handleResponsableSelection = (responsableId) => {
setSelectedResponsables((prevSelectedResponsables) => { setFormData((prevData) => {
const newSelectedResponsables = new Set(prevSelectedResponsables); const selectedResponsables = prevData.selectedResponsables.includes(responsableId)
if (newSelectedResponsables.has(id)) { ? prevData.selectedResponsables.filter(id => id !== responsableId)
newSelectedResponsables.delete(id); : [...prevData.selectedResponsables, responsableId];
} else { return { ...prevData, selectedResponsables };
newSelectedResponsables.add(id);
}
return Array.from(newSelectedResponsables);
}); });
}; };
const resetResponsableEmail = () => { const submit = () => {
setResponsableEmail(''); onSubmit(formData);
};
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);
});
} }
} console.log(eleves)
return ( return (
<div className="p-6 w-full max-w-4xl bg-white rounded-xl shadow-md space-y-4"> <div className="space-y-4 mt-8">
{step === 1 && ( {step === 1 && (
<div> <div>
<h2 className="text-2xl font-bold mb-4">Nouvel élève</h2> <h2 className="text-2xl font-bold mb-4">Nouvel élève</h2>
<input <input
type="text" type="text"
placeholder="Nom de l'élève" placeholder="Nom de l'élève"
value={eleveNom} name="eleveNom"
onChange={(e) => setEleveNom(e.target.value)} value={formData.eleveNom}
onChange={handleChange}
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" 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 <input
type="text" type="text"
placeholder="Prénom de l'élève" placeholder="Prénom de l'élève"
value={elevePrenom} name="elevePrenom"
onChange={(e) => setElevePrenom(e.target.value)} value={formData.elevePrenom}
onChange={handleChange}
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" 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> </div>
)} )}
{step === 2 && ( {step === 2 && (
<div className="mt-6"> <div className="mt-6">
<h2 className="text-2xl font-bold mb-4">Responsable(s)</h2> <h2 className="text-2xl font-bold mb-4">Responsable(s)</h2>
@ -224,8 +90,8 @@ const InscriptionForm = () => {
type="radio" type="radio"
name="responsableType" name="responsableType"
value="new" value="new"
checked={responsableType === 'new'} checked={formData.responsableType === 'new'}
onChange={() => setResponsableType('new')} onChange={handleChange}
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" 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> <span className="text-gray-900">Nouveau Responsable</span>
@ -235,29 +101,27 @@ const InscriptionForm = () => {
type="radio" type="radio"
name="responsableType" name="responsableType"
value="existing" value="existing"
checked={responsableType === 'existing'} checked={formData.responsableType === 'existing'}
onChange={() => { onChange={handleChange}
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" 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> <span className="text-gray-900">Responsable Existant</span>
</label> </label>
</div> </div>
{responsableType === 'new' && ( {formData.responsableType === 'new' && (
<div className="mt-4"> <div className="mt-4">
<input <input
type="email" type="email"
placeholder="Email du responsable" placeholder="Email du responsable"
value={responsableEmail} name="responsableEmail"
onChange={(e) => setResponsableEmail(e.target.value)} value={formData.responsableEmail}
onChange={handleChange}
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" 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> </div>
)} )}
{responsableType === 'existing' && ( {formData.responsableType === 'existing' && (
<div className="mt-4"> <div className="mt-4">
<div className="mt-4" style={{ maxHeight: '300px', overflowY: 'auto' }}> <div className="mt-4" style={{ maxHeight: '300px', overflowY: 'auto' }}>
<table className="min-w-full bg-white border"> <table className="min-w-full bg-white border">
@ -268,7 +132,7 @@ const InscriptionForm = () => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{allEleves.map((eleve, index) => ( {eleves.map((eleve, index) => (
<tr <tr
key={eleve.id} key={eleve.id}
className={`cursor-pointer ${selectedEleve && selectedEleve.id === eleve.id ? 'bg-emerald-600 text-white' : index % 2 === 0 ? 'bg-emerald-100' : ''}`} className={`cursor-pointer ${selectedEleve && selectedEleve.id === eleve.id ? 'bg-emerald-600 text-white' : index % 2 === 0 ? 'bg-emerald-100' : ''}`}
@ -289,7 +153,7 @@ const InscriptionForm = () => {
<label className="flex items-center space-x-3 mt-2"> <label className="flex items-center space-x-3 mt-2">
<input <input
type="checkbox" type="checkbox"
checked={selectedResponsables.includes(responsable.id)} checked={formData.selectedResponsables.includes(responsable.id)}
className="form-checkbox h-5 w-5 text-emerald-600" className="form-checkbox h-5 w-5 text-emerald-600"
onChange={() => handleResponsableSelection(responsable.id)} onChange={() => handleResponsableSelection(responsable.id)}
/> />
@ -305,24 +169,25 @@ const InscriptionForm = () => {
)} )}
</div> </div>
)} )}
{step === 3 && ( {step === 3 && (
<div> <div>
<h2 className="text-2xl font-bold mb-4">Récapitulatif</h2> <h2 className="text-2xl font-bold mb-4">Récapitulatif</h2>
<div className="mb-4"> <div className="mb-4">
<h3 className="text-xl font-semibold">Élève</h3> <h3 className="text-xl font-semibold">Élève</h3>
<p>Nom : {eleveNom}</p> <p>Nom : {formData.eleveNom}</p>
<p>Prénom : {elevePrenom}</p> <p>Prénom : {formData.elevePrenom}</p>
</div> </div>
<div className="mb-4"> <div className="mb-4">
<h3 className="text-xl font-semibold">Responsable(s)</h3> <h3 className="text-xl font-semibold">Responsable(s)</h3>
{responsableType === 'new' && ( {formData.responsableType === 'new' && (
<p>Email du nouveau responsable : {responsableEmail}</p> <p>Email du nouveau responsable : {formData.responsableEmail}</p>
)} )}
{responsableType === 'existing' && selectedEleve && ( {formData.responsableType === 'existing' && selectedEleve && (
<div> <div>
<h4 className="font-bold">Responsables associés à {selectedEleve.nom} {selectedEleve.prenom} :</h4> <h4 className="font-bold">Responsables associés à {selectedEleve.nom} {selectedEleve.prenom} :</h4>
<ul className="list-disc ml-6"> <ul className="list-disc ml-6">
{existingResponsables.filter(responsable => selectedResponsables.includes(responsable.id)).map((responsable) => ( {existingResponsables.filter(responsable => formData.selectedResponsables.includes(responsable.id)).map((responsable) => (
<li key={responsable.id}> <li key={responsable.id}>
{responsable.nom && responsable.prenom ? `${responsable.nom} ${responsable.prenom}` : responsable.mail} {responsable.nom && responsable.prenom ? `${responsable.nom} ${responsable.prenom}` : responsable.mail}
</li> </li>
@ -333,6 +198,7 @@ const InscriptionForm = () => {
</div> </div>
</div> </div>
)} )}
<div className="flex justify-end mt-4 space-x-4"> <div className="flex justify-end mt-4 space-x-4">
{step > 1 && ( {step > 1 && (
<button <button
@ -346,26 +212,26 @@ const InscriptionForm = () => {
<button <button
onClick={nextStep} onClick={nextStep}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${ className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(step === 1 && (!eleveNom || !elevePrenom)) || (step === 1 && (!formData.eleveNom || !formData.elevePrenom)) ||
(step === 2 && (responsableType === 'new' && !responsableEmail || responsableType === 'existing' && (!selectedEleve || selectedResponsables.length === 0))) (step === 2 && formData.responsableType === "new" && !formData.responsableEmail) ||
(step === 2 && formData.responsableType === "existing" && formData.selectedResponsables.length === 0)
? "bg-gray-300 text-gray-700 cursor-not-allowed" ? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600" : "bg-emerald-500 text-white hover:bg-emerald-600"
}`} }`}
disabled={(step === 1 && (!eleveNom || !elevePrenom)) || disabled={(step === 1 && (!formData.eleveNom || !formData.elevePrenom)) ||
(step === 2 && (responsableType === 'new' && !responsableEmail || responsableType === 'existing' && (!selectedEleve || selectedResponsables.length === 0)))} // Désactive le bouton "Suivant" selon les conditions spécifiées (step === 2 && formData.responsableType === "new" && !formData.responsableEmail) ||
(step === 2 && formData.responsableType === "existing" && formData.selectedResponsables.length === 0)
}
> >
Suivant Suivant
</button> </button>
) : ( ) : (
<>
<DjangoCSRFToken csrfToken={csrfToken} />
<button <button
onClick={submit} onClick={submit}
className="px-4 py-2 bg-emerald-500 text-white rounded-md shadow-sm hover:bg-emerald-600 focus:outline-none" className="px-4 py-2 bg-emerald-500 text-white rounded-md shadow-sm hover:bg-emerald-600 focus:outline-none"
> >
Soumettre Créer
</button> </button>
</>
)} )}
</div> </div>
</div> </div>