feat: Ajout de l'option d'envoi automatique [#1]

This commit is contained in:
N3WT DE COMPET
2024-11-24 14:58:54 +01:00
parent afc1632797
commit a77dd8ec64
4 changed files with 197 additions and 128 deletions

View File

@ -133,7 +133,6 @@ class FicheInscriptionView(APIView):
di.eleve.responsables.add(responsable) di.eleve.responsables.add(responsable)
di.save() di.save()
ficheInscriptions_List=bdd.getAllObjects(FicheInscription)
return JsonResponse(ficheEleve_serializer.data, 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

@ -183,7 +183,7 @@ export default function Page({ params: { locale } }) {
useEffect(() => { useEffect(() => {
fetchClasses(); fetchClasses();
fetchStudents(); fetchStudents();
}, []); }, [fichesInscriptionsDataEnCours]);
useEffect(() => { useEffect(() => {
const fetchDataAndSetState = () => { const fetchDataAndSetState = () => {
@ -303,8 +303,16 @@ export default function Page({ params: { locale } }) {
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
console.log('Success:', data); console.log('Success:', data);
setFichesInscriptionsDataEnCours(prevState => [...prevState, data]); setFichesInscriptionsDataEnCours(prevState => {
if (prevState && prevState.length > 0) {
return [...prevState, data];
}
return prevState;
});
setTotalPending(totalPending+1); setTotalPending(totalPending+1);
if (updatedData.autoMail) {
sendConfirmFicheInscription(data.eleve.id, updatedData.eleveNom, updatedData.elevePrenom);
}
}) })
.catch((error) => { .catch((error) => {
console.error('Error:', error); console.error('Error:', error);
@ -344,7 +352,7 @@ export default function Page({ params: { locale } }) {
responsables: [ responsables: [
{ {
mail: updatedData.responsableEmail, mail: updatedData.responsableEmail,
//telephone: telephoneResponsable, telephone: updatedData.responsableTel,
profilAssocie: idProfil // Association entre le reponsable de l'élève et le profil créé par défaut précédemment profilAssocie: idProfil // Association entre le reponsable de l'élève et le profil créé par défaut précédemment
} }
], ],
@ -364,8 +372,16 @@ export default function Page({ params: { locale } }) {
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
console.log('Success:', data); console.log('Success:', data);
setFichesInscriptionsDataEnCours(prevState => [...prevState, data]); setFichesInscriptionsDataEnCours(prevState => {
if (prevState && prevState.length > 0) {
return [...prevState, data];
}
return prevState;
});
setTotalPending(totalPending+1); setTotalPending(totalPending+1);
if (updatedData.autoMail) {
sendConfirmFicheInscription(data.eleve.id, updatedData.eleveNom, updatedData.elevePrenom);
}
}) })
.catch((error) => { .catch((error) => {
console.error('Error:', error); console.error('Error:', error);
@ -623,6 +639,7 @@ const columnsSubscribed = [
isOpen={isOpen} isOpen={isOpen}
setIsOpen={setIsOpen} setIsOpen={setIsOpen}
title={"Création d'un nouveau dossier d'inscription"} title={"Création d'un nouveau dossier d'inscription"}
size='sm:w-1/4'
ContentComponent={() => ( ContentComponent={() => (
<InscriptionForm eleves={eleves} <InscriptionForm eleves={eleves}
onSubmit={createDI} onSubmit={createDI}

View File

@ -1,10 +1,13 @@
import { useState } from 'react'; import { useState } from 'react';
import { User, Mail, Phone, UserCheck } from 'lucide-react';
import InputTextIcon from '@/components/InputTextIcon';
const InscriptionForm = ( { eleves, onSubmit }) => { const InscriptionForm = ( { eleves, onSubmit }) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
eleveNom: '', eleveNom: '',
elevePrenom: '', elevePrenom: '',
responsableEmail: '', responsableEmail: '',
responsableTel: '',
selectedResponsables: [], selectedResponsables: [],
responsableType: 'new' responsableType: 'new'
}); });
@ -12,6 +15,13 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
const [step, setStep] = useState(1); const [step, setStep] = useState(1);
const [selectedEleve, setSelectedEleve] = useState(''); const [selectedEleve, setSelectedEleve] = useState('');
const [existingResponsables, setExistingResponsables] = useState([]); const [existingResponsables, setExistingResponsables] = useState([]);
const [autoMail, setAutoMail] = useState(false);
const maxStep = 4
const handleToggleChange = () => {
setAutoMail(!autoMail);
setFormData({ ...formData, autoMail: !autoMail });
};
const handleChange = (e) => { const handleChange = (e) => {
const { name, value, type } = e.target; const { name, value, type } = e.target;
@ -22,7 +32,7 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
}; };
const nextStep = () => { const nextStep = () => {
if (step < 3) { if (step < maxStep) {
setStep(step + 1); setStep(step + 1);
} }
}; };
@ -52,31 +62,31 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
}; };
const submit = () => { const submit = () => {
onSubmit(formData); onSubmit({ ...formData, autoMail });
} }
console.log(eleves)
return ( return (
<div className="space-y-4 mt-8"> <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 <InputTextIcon
type="text"
placeholder="Nom de l'élève"
name="eleveNom" name="eleveNom"
type="text"
IconItem={User}
placeholder="Nom de l'élève"
value={formData.eleveNom} value={formData.eleveNom}
onChange={handleChange} 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="w-full"
/> />
<input <InputTextIcon
type="text"
placeholder="Prénom de l'élève"
name="elevePrenom" name="elevePrenom"
type="text"
IconItem={User}
placeholder="Prénom de l'élève"
value={formData.elevePrenom} value={formData.elevePrenom}
onChange={handleChange} 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="w-full"
/> />
</div> </div>
)} )}
@ -109,16 +119,15 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
</label> </label>
</div> </div>
{formData.responsableType === 'new' && ( {formData.responsableType === 'new' && (
<div className="mt-4"> <InputTextIcon
<input
type="email"
placeholder="Email du responsable"
name="responsableEmail" name="responsableEmail"
type="email"
IconItem={Mail}
placeholder="Email du responsable"
value={formData.responsableEmail} value={formData.responsableEmail}
onChange={handleChange} 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="w-full mt-4"
/> />
</div>
)} )}
{formData.responsableType === 'existing' && ( {formData.responsableType === 'existing' && (
@ -171,21 +180,47 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
)} )}
{step === 3 && ( {step === 3 && (
<div className="mt-6">
<h2 className="text-2xl font-bold mb-4">Téléphone (optionnel)</h2>
<InputTextIcon
name="responsableTel"
type="tel"
IconItem={Phone}
placeholder="Numéro de téléphone"
value={formData.responsableTel}
onChange={handleChange}
className="w-full mt-4"
/>
</div>
)}
{step === maxStep && (
<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="flex items-center justify-between space-x-4">
<h3 className="text-xl font-semibold">Élève</h3> <div className="bg-gray-100 p-3 rounded-lg shadow-md flex items-center w-1/2 mb-4">
<User className="w-10 h-10 text-gray-300 mr-4" />
<div>
<p className="italic text-gray-600">Élève</p>
<p>Nom : {formData.eleveNom}</p> <p>Nom : {formData.eleveNom}</p>
<p>Prénom : {formData.elevePrenom}</p> <p>Prénom : {formData.elevePrenom}</p>
</div> </div>
<div className="mb-4"> </div>
<h3 className="text-xl font-semibold">Responsable(s)</h3> </div>
<div className="flex items-center justify-between space-x-4">
<div className="bg-gray-100 p-3 rounded-lg shadow-md flex items-center w-1/2">
<UserCheck className="w-10 h-10 text-gray-300 mr-4" />
{formData.responsableType === 'new' && ( {formData.responsableType === 'new' && (
<p>Email du nouveau responsable : {formData.responsableEmail}</p> <div>
<p className="italic text-gray-600">Responsable</p>
<p>Email : {formData.responsableEmail}</p>
<p>Téléphone : {formData.responsableTel}</p>
</div>
)} )}
{formData.responsableType === 'existing' && selectedEleve && ( {formData.responsableType === 'existing' && selectedEleve && (
<div> <div>
<h4 className="font-bold">Responsables associés à {selectedEleve.nom} {selectedEleve.prenom} :</h4> <p className="italic text-gray-600">Responsable(s)</p>
<p>Associé(s) à : {selectedEleve.nom} {selectedEleve.prenom}</p>
<ul className="list-disc ml-6"> <ul className="list-disc ml-6">
{existingResponsables.filter(responsable => formData.selectedResponsables.includes(responsable.id)).map((responsable) => ( {existingResponsables.filter(responsable => formData.selectedResponsables.includes(responsable.id)).map((responsable) => (
<li key={responsable.id}> <li key={responsable.id}>
@ -197,6 +232,24 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
)} )}
</div> </div>
</div> </div>
<div className="flex items-center mt-4">
<label className="mr-2 text-gray-600">Envoi automatique</label>
<div className="relative inline-block w-10 mr-2 align-middle select-none transition duration-200 ease-in">
<input
type="checkbox"
name="toggle"
id="toggle"
checked={autoMail}
onChange={handleToggleChange}
className="toggle-checkbox absolute block w-6 h-6 rounded-full bg-white border-4 appearance-none cursor-pointer border-emerald-500 checked:right-0 checked:border-emerald-500 checked:bg-emerald-500 focus:border-emerald-500 focus:bg-emerald-500 hover:border-emerald-500 hover:bg-emerald-500"
/>
<label
htmlFor="toggle"
className={`toggle-label block overflow-hidden h-6 rounded-full cursor-pointer transition-colors duration-200 ${autoMail ? 'bg-emerald-300' : 'bg-gray-300'}`}
></label>
</div>
</div>
</div>
)} )}
<div className="flex justify-end mt-4 space-x-4"> <div className="flex justify-end mt-4 space-x-4">
@ -208,7 +261,7 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
Précédent Précédent
</button> </button>
)} )}
{step < 3 ? ( {step < maxStep ? (
<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 ${

View File

@ -1,12 +1,12 @@
import * as Dialog from '@radix-ui/react-dialog'; import * as Dialog from '@radix-ui/react-dialog';
const Modal = ({ isOpen, setIsOpen, title, ContentComponent }) => { const Modal = ({ isOpen, setIsOpen, title, ContentComponent, size }) => {
return ( return (
<Dialog.Root open={isOpen} onOpenChange={setIsOpen}> <Dialog.Root open={isOpen} onOpenChange={setIsOpen}>
<Dialog.Portal> <Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" /> <Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
<Dialog.Content className="fixed inset-0 flex items-center justify-center"> <Dialog.Content className="fixed inset-0 flex items-center justify-center">
<div className="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full sm:p-6"> <div className={`inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:p-6 ${size ? size : 'sm:w-full' }`}>
<Dialog.Title className="text-lg font-medium text-gray-900"> <Dialog.Title className="text-lg font-medium text-gray-900">
{title} {title}
</Dialog.Title> </Dialog.Title>