refactor: Création de composants et uniformisation des modales (#2)

This commit is contained in:
N3WT DE COMPET
2024-11-24 18:42:42 +01:00
parent 5946cbdee6
commit d51778ba54
18 changed files with 362 additions and 299 deletions

View File

@ -335,7 +335,7 @@ export default function Page({ params: { locale } }) {
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
droit:2 // Profil PARENT
}),
}
);

View File

@ -80,13 +80,12 @@ export default function Page() {
localStorage.setItem('userId', data.profil); // Stocker l'identifiant de l'utilisateur
if (data.droit == 0) {
// Vue ECOLE
} else if (data.droit == 1) {
// Vue PARENT
router.push(`${FR_PARENTS_HOME_URL}`);
} else if (data.droit == 2) {
// Vue ADMIN
router.push(`${FR_ADMIN_SUBSCRIPTIONS_URL}`);
} else if (data.droit == 2) {
// Vue PARENT
router.push(`${FR_PARENTS_HOME_URL}`);
} else {
// Cas anormal
}

View File

@ -1,12 +1,12 @@
import React from 'react';
import { useRouter } from 'next/navigation';
const Button = ({ text, onClick, href, className, primary, icon }) => {
const Button = ({ text, onClick, href, className, primary, icon, disabled}) => {
const router = useRouter();
const baseClass = 'px-4 py-2 rounded-md text-white h-8 flex items-center justify-center';
const primaryClass = 'bg-emerald-500 hover:bg-emerald-600';
const secondaryClass = 'bg-gray-300 hover:bg-gray-400 text-black';
const buttonClass = `${baseClass} ${primary ? primaryClass : secondaryClass} ${className}`;
const buttonClass = `${baseClass} ${primary && !disabled ? primaryClass : secondaryClass} ${className}`;
const handleClick = (e) => {
if (href) {
@ -17,7 +17,7 @@ const Button = ({ text, onClick, href, className, primary, icon }) => {
};
return (
<button className={buttonClass} onClick={handleClick}>
<button className={buttonClass} onClick={handleClick} disabled={disabled}>
{icon && <span className="mr-2">{icon}</span>}
{text}
</button>

View File

@ -1,13 +1,24 @@
import React, { useState } from 'react';
import Slider from '@/components/Slider'
import InputTextIcon from '@/components/InputTextIcon';
import Button from '@/components/Button';
import SelectChoice from '@/components/SelectChoice';
import RadioList from '@/components/RadioList';
import { Users, Maximize2, Globe, Calendar, GraduationCap } from 'lucide-react';
const ClassForm = ({ classe, onSubmit, isNew, specialities, teachers }) => {
const langues = [
{ value:'Français', label: 'Français'},
{ value:'Anglais', label: 'Anglais'},
{ value:'Espagnol', label: 'Espagnol'},
];
const [formData, setFormData] = useState({
nom_ambiance: classe.nom_ambiance || '',
tranche_age: classe.tranche_age || [3, 6],
nombre_eleves: classe.nombre_eleves || '',
langue_enseignement: classe.langue_enseignement || 'Français',
annee_scolaire: classe.annee_scolaire || '2024-2025',
annee_scolaire: classe.annee_scolaire || '',
specialites_ids: classe.specialites_ids || [],
enseignant_principal_id: classe.enseignant_principal_id || null,
});
@ -49,19 +60,21 @@ const ClassForm = ({ classe, onSubmit, isNew, specialities, teachers }) => {
});
};
const getTeacherLabel = (teacher) => {
return `${teacher.nom} ${teacher.prenom} (${teacher.specialite.nom})`;
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<form onSubmit={handleSubmit} className="space-y-4 mt-8">
<div>
<label className="block text-sm font-medium text-gray-700">
Nom d'ambiance
</label>
<input
type="text"
placeholder="Nom de l'ambiance"
<InputTextIcon
name="nom_ambiance"
type="text"
IconItem={Users}
placeholder="Nom d'ambiance"
value={formData.nom_ambiance}
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"
/>
</div>
<div>
@ -69,51 +82,43 @@ const ClassForm = ({ classe, onSubmit, isNew, specialities, teachers }) => {
Tranche d'âge
</label>
<Slider
min={3}
max={12}
min={2}
max={18}
value={formData.tranche_age}
onChange={handleSliderChange}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Nombre d'élèves
</label>
<input
type="number"
<InputTextIcon
name="nombre_eleves"
type="number"
IconItem={Maximize2}
placeholder="Capacité max"
value={formData.nombre_eleves}
onChange={handleNumberChange}
min="1"
max="40"
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 sm:text-sm"
onChange={handleChange}
className="w-full"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Langue d'enseignement
</label>
<select
name="langue_enseignement"
value={formData.langue_enseignement}
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 sm:text-sm"
>
<option value="Français">Français</option>
<option value="Anglais">Anglais</option>
<option value="Espagnol">Espagnol</option>
</select>
<SelectChoice
name="langue_enseignement"
label="Langue d'enseignement"
selected={formData.langue_enseignement}
callback={handleChange}
choices={langues}
IconItem={Globe}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Année scolaire
</label>
<input
type="text"
<InputTextIcon
name="annee_scolaire"
type="text"
IconItem={Calendar}
placeholder="Année scolaire (20xx-20xx)"
value={formData.annee_scolaire}
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 sm:text-sm"
className="w-full"
/>
</div>
<div>
@ -144,41 +149,30 @@ const ClassForm = ({ classe, onSubmit, isNew, specialities, teachers }) => {
))}
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Enseignant principal
</label>
<div className="mt-2 grid grid-cols-1 gap-4">
{teachers.map(teacher => (
<div key={teacher.id} className="flex items-center">
<input
type="radio"
id={`teacher-${teacher.id}`}
name="enseignant_principal_id"
value={teacher.id}
checked={formData.enseignant_principal_id === teacher.id}
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"
/>
<label htmlFor={`teacher-${teacher.id}`} className="ml-2 block text-sm text-gray-900 flex items-center">
{teacher.nom} {teacher.prenom}
</label>
</div>
))}
</div>
<div className="flex space-x-4">
<RadioList
items={teachers}
formData={formData}
handleChange={handleChange}
fieldName="enseignant_principal_id"
label="Enseignant principal"
itemLabelFunc={getTeacherLabel}
icon={GraduationCap}
className="w-full mt-4"
/>
</div>
<div className="flex justify-end mt-4 space-x-4">
<button
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(!formData.nom_ambiance || !formData.nombre_eleves)
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
disabled={(!formData.nom_ambiance || !formData.nombre_eleves)}
>
Soumettre
</button>
<Button text="Créer"
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(!formData.nom_ambiance || !formData.nombre_eleves || !formData.annee_scolaire || !formData.enseignant_principal_id)
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
primary
disabled={(!formData.nom_ambiance || !formData.nombre_eleves || !formData.annee_scolaire || !formData.enseignant_principal_id)}
type="submit"
name="Create" />
</div>
</form>
);

View File

@ -107,9 +107,11 @@ const ClassesSection = ({ classes, specialities, teachers, handleCreate, handleE
<Modal
isOpen={isOpen}
setIsOpen={setIsOpen}
title={editingClass ? "Modification de la classe" : "Création d'une nouvelle classe"} ContentComponent={() => (
<ClassForm classe={editingClass || {}} onSubmit={handleModalSubmit} isNew={!editingClass} specialities={specialities} teachers={teachers} />
)}
title={editingClass ? "Modification de la classe" : "Création d'une nouvelle classe"}
size='sm:w-1/4'
ContentComponent={() => (
<ClassForm classe={editingClass || {}} onSubmit={handleModalSubmit} isNew={!editingClass} specialities={specialities} teachers={teachers} />
)}
/>
)}
{isOpenDetails && (

View File

@ -0,0 +1,28 @@
import React from 'react';
import { Palette } from 'lucide-react';
const InputColorIcon = ({ name, label, value, onChange, errorMsg, className }) => {
return (
<>
<div className={`mb-4 ${className}`}>
<label htmlFor={name} className="block text-sm font-medium text-gray-700">{label}</label>
<div className={`flex items-center border-2 border-gray-200 rounded-md ${errorMsg ? 'border-red-500' : ''} hover:border-gray-400 focus-within:border-gray-500 h-8 w-1/3`}>
<span className="inline-flex items-center px-3 rounded-l-md bg-gray-50 text-gray-500 text-sm h-full">
<Palette className="w-5 h-5" />
</span>
<input
type="color"
id={name}
name={name}
value={value}
onChange={onChange}
className="flex-1 block rounded-r-md sm:text-sm border-none focus:ring-0 outline-none h-full p-0 w-8"
/>
</div>
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
</div>
</>
);
};
export default InputColorIcon;

View File

@ -1,6 +1,8 @@
import { useState } from 'react';
import { User, Mail, Phone, UserCheck } from 'lucide-react';
import InputTextIcon from '@/components/InputTextIcon';
import ToggleSwitch from '@/components/ToggleSwitch';
import Button from '@/components/Button';
const InscriptionForm = ( { eleves, onSubmit }) => {
const [formData, setFormData] = useState({
@ -9,18 +11,17 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
responsableEmail: '',
responsableTel: '',
selectedResponsables: [],
responsableType: 'new'
responsableType: 'new',
autoMail: false
});
const [step, setStep] = useState(1);
const [selectedEleve, setSelectedEleve] = useState('');
const [existingResponsables, setExistingResponsables] = useState([]);
const [autoMail, setAutoMail] = useState(false);
const maxStep = 4
const handleToggleChange = () => {
setAutoMail(!autoMail);
setFormData({ ...formData, autoMail: !autoMail });
const handleToggleChange = () => {
setFormData({ ...formData, autoMail: !formData.autoMail });
};
const handleChange = (e) => {
@ -62,7 +63,7 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
};
const submit = () => {
onSubmit({ ...formData, autoMail });
onSubmit(formData);
}
return (
@ -167,7 +168,7 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
onChange={() => handleResponsableSelection(responsable.id)}
/>
<span className="text-gray-900">
{responsable.nom && responsable.prenom ? `${responsable.nom} ${responsable.prenom}` : `adresse mail : ${responsable.mail}`}
{responsable.nom && responsable.prenom ? `${responsable.nom} ${responsable.prenom}` : `${responsable.mail}`}
</span>
</label>
</div>
@ -232,59 +233,46 @@ const InscriptionForm = ( { eleves, onSubmit }) => {
)}
</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 className='mt-4'>
<ToggleSwitch
label="Envoi automatique"
checked={formData.autoMail}
onChange={handleToggleChange}
/>
</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>
<Button text="Précédent"
onClick={prevStep}
className="px-4 py-2 bg-gray-300 text-gray-700 rounded-md shadow-sm hover:bg-gray-400 focus:outline-none"
secondary
name="Previous" />
)}
{step < maxStep ? (
<button
onClick={nextStep}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(step === 1 && (!formData.eleveNom || !formData.elevePrenom)) ||
(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-emerald-500 text-white hover:bg-emerald-600"
}`}
disabled={(step === 1 && (!formData.eleveNom || !formData.elevePrenom)) ||
(step === 2 && formData.responsableType === "new" && !formData.responsableEmail) ||
(step === 2 && formData.responsableType === "existing" && formData.selectedResponsables.length === 0)
}
>
Suivant
</button>
<Button text="Suivant"
onClick={nextStep}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(step === 1 && (!formData.eleveNom || !formData.elevePrenom)) ||
(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-emerald-500 text-white hover:bg-emerald-600"
}`}
disabled={(step === 1 && (!formData.eleveNom || !formData.elevePrenom)) ||
(step === 2 && formData.responsableType === "new" && !formData.responsableEmail) ||
(step === 2 && formData.responsableType === "existing" && formData.selectedResponsables.length === 0)
}
primary
name="Next" />
) : (
<button
onClick={submit}
className="px-4 py-2 bg-emerald-500 text-white rounded-md shadow-sm hover:bg-emerald-600 focus:outline-none"
>
Créer
</button>
<Button text="Créer"
onClick={submit}
className="px-4 py-2 bg-emerald-500 text-white rounded-md shadow-sm hover:bg-emerald-600 focus:outline-none"
primary
name="Create" />
)}
</div>
</div>

View File

@ -1,4 +1,5 @@
import * as Dialog from '@radix-ui/react-dialog';
import Button from '@/components/Button';
const Modal = ({ isOpen, setIsOpen, title, ContentComponent, size }) => {
return (
@ -13,14 +14,14 @@ const Modal = ({ isOpen, setIsOpen, title, ContentComponent, size }) => {
<div className="mt-2">
<ContentComponent />
</div>
<div className="mt-4 flex justify-end">
<div className="mt-4 flex justify-end space-x-4">
<Dialog.Close asChild>
<button
className="px-4 py-2 rounded-md shadow-sm focus:outline-none bg-gray-300 text-gray-700 hover:bg-gray-400"
<Button text="Fermer"
onClick={() => setIsOpen(false)}
>
Fermer
</button>
className="px-4 py-2 rounded-md shadow-sm focus:outline-none bg-gray-300 text-gray-700 hover:bg-gray-400"
secondary
type="submit"
name="Create" />
</Dialog.Close>
</div>
</div>

View File

@ -0,0 +1,39 @@
import React from 'react';
const RadioList = ({ items, formData, handleChange, fieldName, label, icon: Icon, className, itemLabelFunc}) => {
return (
<div className={`mb-4 ${className}`}>
<label className="block text-sm font-medium text-gray-700 flex items-center">
{Icon && <Icon className="w-5 h-5 mr-2" />}
{label}
</label>
<div className="mt-2 grid grid-cols-1 gap-4">
{items.map(item => (
<div key={item.id} className="flex items-center">
<input
type="radio"
id={`${fieldName}-${item.id}`}
name={fieldName}
value={item.id}
checked={formData[fieldName] === item.id}
onChange={handleChange}
className="form-radio h-4 w-4 text-emerald-600 focus:ring-emerald-500 hover:ring-emerald-400 checked:bg-emerald-600"
/>
<label htmlFor={`${fieldName}-${item.id}`} className="ml-2 block text-sm text-gray-900 flex items-center">
{itemLabelFunc(item)}
{item.codeCouleur && (
<div
className="w-4 h-4 rounded-full ml-2"
style={{ backgroundColor: item.codeCouleur }}
title={item.codeCouleur}
></div>
)}
</label>
</div>
))}
</div>
</div>
);
};
export default RadioList;

View File

@ -1,18 +1,23 @@
export default function SelectChoice({type, name, label, choices, callback, selected, error }) {
export default function SelectChoice({type, name, label, choices, callback, selected, error, IconItem }) {
return (
<>
<div className="mb-4">
<label htmlFor={name} className="block text-sm font-medium text-gray-700">{label}</label>
<select
className={`mt-1 block w-full px-3 py-2 text-base border ${error ? 'border-red-500' : 'border-gray-300'} focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md`}
type={type}
id={name}
name={name}
value={selected}
onChange={callback}
>
{choices.map(({ value, label }, index) => <option key={value} value={value}>{label}</option>)}
</select>
<div className={`flex items-center border-2 border-gray-200 rounded-md hover:border-gray-400 focus-within:border-gray-500 h-8`}>
<span className="inline-flex items-center px-3 rounded-l-md bg-gray-50 text-gray-500 text-sm h-full">
{IconItem && <IconItem />}
</span>
<select
className="mt-1 block w-full px-2 py-0 text-base rounded-r-md sm:text-sm border-none focus:ring-0 outline-none"
type={type}
id={name}
name={name}
value={selected}
onChange={callback}
>
{choices.map(({ value, label }, index) => <option key={value} value={value}>{label}</option>)}
</select>
</div>
{error && <p className="mt-2 text-sm text-red-600">{error}</p>}
</div>
</>

View File

@ -23,28 +23,30 @@ const Slider = ({ min, max, value, onChange }) => {
return (
<div className="space-y-4">
<div className="flex items-center space-x-2 w-1/2">
<span className="text-emerald-600">{value[0]}</span>
<input
type="range"
min={min}
max={max}
value={value[0]}
onChange={handleMinChange}
className="w-full h-2 bg-emerald-200 rounded-lg appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-opacity-50"
/>
</div>
<div className="flex items-center space-x-2 w-1/2">
<span className="text-emerald-600">{value[1]}</span>
<input
type="range"
min={value[0] + 1}
max={max}
value={value[1]}
onChange={handleMaxChange}
className="w-full h-2 bg-emerald-200 rounded-lg appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-opacity-50"
/>
</div>
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-2 w-1/2">
<span className="text-emerald-600">{value[0]}</span>
<input
type="range"
min={min}
max={max}
value={value[0]}
onChange={handleMinChange}
className="w-full h-2 bg-emerald-200 rounded-lg appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-opacity-50"
/>
</div>
<div className="flex items-center space-x-2 w-1/2 justify-end">
<span className="text-emerald-600">{value[1]}</span>
<input
type="range"
min={value[0] + 1}
max={max}
value={value[1]}
onChange={handleMaxChange}
className="w-full h-2 bg-emerald-200 rounded-lg appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-opacity-50"
/>
</div>
</div>
</div>
);
};

View File

@ -75,9 +75,11 @@ const SpecialitiesSection = ({ specialities, handleCreate, handleEdit, handleDel
<Modal
isOpen={isOpen}
setIsOpen={setIsOpen}
title={editingSpeciality ? "Modification de la spécialité" : "Création d'une nouvelle spécialité"} ContentComponent={() => (
<SpecialityForm speciality={editingSpeciality || {}} onSubmit={handleModalSubmit} isNew={!editingSpeciality} />
)}
title={editingSpeciality ? "Modification de la spécialité" : "Création d'une nouvelle spécialité"}
size='sm:w-1/6'
ContentComponent={() => (
<SpecialityForm speciality={editingSpeciality || {}} onSubmit={handleModalSubmit} isNew={!editingSpeciality} />
)}
/>
)}
</div>

View File

@ -1,4 +1,8 @@
import { useState } from 'react';
import { BookOpen, Palette } from 'lucide-react';
import InputTextIcon from '@/components/InputTextIcon';
import InputColorIcon from '@/components/InputColorIcon';
import Button from '@/components/Button';
const SpecialityForm = ({ speciality = {}, onSubmit, isNew }) => {
const [nom, setNom] = useState(speciality.nom || '');
@ -13,35 +17,39 @@ const SpecialityForm = ({ speciality = {}, onSubmit, isNew }) => {
};
return (
<div className="p-4">
<div className="space-y-4 mt-8">
<div>
<input
type="text"
placeholder="Nom de la spécialité"
value={nom}
onChange={(e) => setNom(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"
<InputTextIcon
type="text"
IconItem={BookOpen}
placeholder="Nom de la spécialité"
value={nom}
onChange={(e) => setNom(e.target.value)}
className="w-full mt-4"
/>
</div>
<div className="mt-4">
<label className="block text-sm font-medium text-gray-700">
Code couleur de la spécialité
</label>
<input
type="color"
value={codeCouleur}
onChange={(e) => setCodeCouleur(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 h-10 w-10 p-0 cursor-pointer"
style={{ appearance: 'none', borderRadius: '0' }}
<InputColorIcon
type="color"
IconItem={Palette}
placeholder="Nom de la spécialité"
value={codeCouleur}
onChange={(e) => setCodeCouleur(e.target.value)}
className="w-full mt-4"
/>
</div>
<div className="flex justify-end mt-4 space-x-4">
<button
onClick={handleSubmit}
className="px-4 py-2 bg-emerald-500 text-white rounded-md shadow-sm hover:bg-emerald-600 focus:outline-none"
>
Soumettre
</button>
<Button text="Créer"
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
!nom
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
primary
disabled={!nom}
type="submit"
name="Create" />
</div>
</div>
);

View File

@ -1,10 +1,11 @@
import React, { useState } from 'react';
import { GraduationCap, Mail, BookOpen } from 'lucide-react';
import InputTextIcon from '@/components/InputTextIcon';
import Button from '@/components/Button';
import RadioList from '@/components/RadioList';
import ToggleSwitch from '@/components/ToggleSwitch'
const TeacherForm = ({ teacher, onSubmit, isNew, specialities }) => {
const profils = [
{ value: 0, label: "École" },
{ value: 2, label: "Administrateur" },
];
const [formData, setFormData] = useState({
nom: teacher.nom || '',
@ -13,13 +14,17 @@ const TeacherForm = ({ teacher, onSubmit, isNew, specialities }) => {
specialite_id: teacher.specialite_id || '',
classes: teacher.classes || [],
profilAssocie_id: teacher.profilAssocie_id || [],
DroitValue: teacher.DroitValue || 0
droit: teacher.DroitValue || 0
});
const handleToggleChange = () => {
console.log('new value : ', 1-formData.droit)
setFormData({ ...formData, droit: 1-formData.droit });
};
const handleChange = (e) => {
const { name, value, type } = e.target;
const newValue = type === 'radio' ? parseInt(value, 10) : value;
console.log(`Name: ${name}, Value: ${newValue}`);
setFormData((prevState) => ({
...prevState,
[name]: newValue,
@ -31,112 +36,70 @@ const TeacherForm = ({ teacher, onSubmit, isNew, specialities }) => {
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<form onSubmit={handleSubmit} className="space-y-4 mt-8">
<div>
<label className="block text-sm font-medium text-gray-700">
Nom
</label>
<input
type="text"
placeholder="Nom de l'enseignant"
<InputTextIcon
name="nom"
type="text"
IconItem={GraduationCap}
placeholder="Nom de l'enseignant"
value={formData.nom}
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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Prénom
</label>
<input
type="text"
placeholder="Prénom de l'enseignant"
<InputTextIcon
name="prenom"
type="text"
IconItem={GraduationCap}
placeholder="Prénom de l'enseignant"
value={formData.prenom}
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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Adresse email
</label>
<input
type="text"
placeholder="email de l'enseignant"
name="mail"
value={formData.mail}
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"
<InputTextIcon
name="mail"
type="email"
IconItem={Mail}
placeholder="Email de l'enseignant"
value={formData.mail}
onChange={handleChange}
className="w-full mt-4"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Spécialités
</label>
<div className="mt-2 grid grid-cols-1 gap-4">
{specialities.map(speciality => (
<div key={speciality.id} className="flex items-center">
<input
type="radio"
id={`speciality-${speciality.id}`}
name="specialite_id"
value={speciality.id}
checked={formData.specialite_id === speciality.id}
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"
/>
<label htmlFor={`speciality-${speciality.id}`} className="ml-2 block text-sm text-gray-900 flex items-center">
{speciality.nom}
<div
className="w-4 h-4 rounded-full ml-2"
style={{ backgroundColor: speciality.codeCouleur }}
title={speciality.codeCouleur}
></div>
</label>
</div>
))}
</div>
<div className="flex space-x-4">
<RadioList
items={specialities}
formData={formData}
handleChange={handleChange}
fieldName="specialite_id"
label="Spécialités"
icon={BookOpen}
className="w-full mt-4"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">
Types de profil
</label>
<div className="mt-2 grid grid-cols-1 gap-4">
{profils.map((profil) => (
<div key={profil.value} className="flex items-center">
<input
type="radio"
id={`profil-${profil.value}`}
name="DroitValue"
value={profil.value}
checked={formData.DroitValue === profil.value}
onChange={handleChange}
className="form-radio h-4 w-4 text-emerald-600 focus:ring-emerald-500"
/>
<label
htmlFor={`profil-${profil.value}`}
className="ml-2 block text-sm text-gray-900"
>
{profil.label}
</label>
</div>
))}
</div>
<div className='mt-4'>
<ToggleSwitch
label="Administrateur"
checked={formData.droit}
onChange={handleToggleChange}
/>
</div>
<div className="flex justify-end mt-4 space-x-4">
<button
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(!formData.nom || !formData.prenom || !formData.mail || !formData.specialite_id)
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
disabled={(!formData.nom || !formData.prenom || !formData.mail || !formData.specialite_id)}
>
Soumettre
</button>
<Button text="Créer"
onClick={handleSubmit}
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
(!formData.nom || !formData.prenom || !formData.mail || !formData.specialite_id)
? "bg-gray-300 text-gray-700 cursor-not-allowed"
: "bg-emerald-500 text-white hover:bg-emerald-600"
}`}
primary
disabled={(!formData.nom || !formData.prenom || !formData.mail || !formData.specialite_id)}
type="submit"
name="Create" />
</div>
</form>
);

View File

@ -39,7 +39,7 @@ const TeachersSection = ({ teachers, handleCreate, handleEdit, handleDelete, spe
body: JSON.stringify( {
email: updatedData.mail,
username: updatedData.mail,
droit:updatedData.DroitValue
droit:updatedData.droit
}),
}
);
@ -71,7 +71,7 @@ const TeachersSection = ({ teachers, handleCreate, handleEdit, handleDelete, spe
password: 'Provisoire01!',
username: updatedData.mail,
is_active: 1, // On rend le profil actif : on considère qu'au moment de la configuration de l'école un abonnement a été souscrit
droit:updatedData.DroitValue
droit:updatedData.droit
}),
}
);
@ -159,9 +159,11 @@ const TeachersSection = ({ teachers, handleCreate, handleEdit, handleDelete, spe
<Modal
isOpen={isOpen}
setIsOpen={setIsOpen}
title={editingTeacher ? "Modification de l'enseignant" : "Création d'un nouvel enseignant"} ContentComponent={() => (
<TeacherForm teacher={editingTeacher || {}} onSubmit={handleModalSubmit} isNew={!editingTeacher} specialities={specialities} />
)}
title={editingTeacher ? "Modification de l'enseignant" : "Création d'un nouvel enseignant"}
size='sm:w-1/4'
ContentComponent={() => (
<TeacherForm teacher={editingTeacher || {}} onSubmit={handleModalSubmit} isNew={!editingTeacher} specialities={specialities} />
)}
/>
)}
</div>

View File

@ -0,0 +1,25 @@
import React from 'react';
const ToggleSwitch = ({ label, checked, onChange }) => {
return (
<div className="flex items-center mt-4">
<label className="mr-2 text-gray-600">{label}</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={checked}
onChange={onChange}
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 ${checked ? 'bg-emerald-300' : 'bg-gray-300'}`}
></label>
</div>
</div>
);
};
export default ToggleSwitch;