refactor: Refactorisation du login et de admin/subscription

This commit is contained in:
Luc SORIGNET
2025-01-12 16:34:32 +01:00
parent 427b6c7588
commit 41aa9d55d3
14 changed files with 254 additions and 250 deletions

View File

@ -236,7 +236,7 @@ class ChildrenListView(APIView):
# Récupération des élèves d'un parent # Récupération des élèves d'un parent
# idProfile : identifiant du profil connecté rattaché aux fiches d'élèves # idProfile : identifiant du profil connecté rattaché aux fiches d'élèves
def get(self, request, _idProfile): def get(self, request, _idProfile):
students = bdd.getObjects(_objectName=RegistrationForm, _columnName='student__guardians__profilAssocie__id', _value=_idProfile) students = bdd.getObjects(_objectName=RegistrationForm, _columnName='student__guardians__associated_profile__id', _value=_idProfile)
students_serializer = RegistrationFormByParentSerializer(students, many=True) students_serializer = RegistrationFormByParentSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False) return JsonResponse(students_serializer.data, safe=False)

View File

@ -2,11 +2,10 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
import InscriptionFormShared from '@/components/Inscription/InscriptionFormShared'; import InscriptionFormShared from '@/components/Inscription/InscriptionFormShared';
import { FE_ADMIN_SUBSCRIPTIONS_URL, import { FE_ADMIN_SUBSCRIPTIONS_URL } from '@/utils/Url';
BE_SUBSCRIPTION_STUDENT_URL,
BE_SUBSCRIPTION_REGISTERFORM_URL } from '@/utils/Url';
import useCsrfToken from '@/hooks/useCsrfToken'; import useCsrfToken from '@/hooks/useCsrfToken';
import { mockStudent } from '@/data/mockStudent'; import { mockStudent } from '@/data/mockStudent';
import { editRegisterForm, fetchRegisterForm } from '@/app/lib/subscriptionAction';
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true'; const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
@ -24,22 +23,21 @@ export default function Page() {
setInitialData(mockStudent); setInitialData(mockStudent);
setIsLoading(false); setIsLoading(false);
} else { } else {
fetch(`${BE_SUBSCRIPTION_STUDENT_URL}/${studentId}`) // Utilisation de studentId au lieu de codeDI fetchRegisterForm(studentId)
.then(response => response.json())
.then(data => { .then(data => {
console.log('Fetched data:', data); // Pour le débogage console.log('Fetched data:', data); // Pour le débogage
const formattedData = { const formattedData = {
id: data.id, id: data.id,
nom: data.nom, last_name: data.last_name,
prenom: data.prenom, first_name: data.first_name,
adresse: data.adresse, address: data.address,
dateNaissance: data.dateNaissance, birth_date: data.birth_date,
lieuNaissance: data.lieuNaissance, birth_place: data.birth_place,
codePostalNaissance: data.codePostalNaissance, birth_postal_code: data.birth_postal_code,
nationalite: data.nationalite, nationality: data.nationality,
medecinTraitant: data.medecinTraitant, attending_physician: data.attending_physician,
niveau: data.niveau, level: data.level,
responsables: data.responsables || [] guardians: data.guardians || []
}; };
setInitialData(formattedData); setInitialData(formattedData);
setIsLoading(false); setIsLoading(false);
@ -58,18 +56,8 @@ export default function Page() {
} }
try { try {
const response = await fetch(`${BE_SUBSCRIPTION_REGISTERFORM_URL}/${studentId}`, { // Utilisation de studentId const result = await editRegisterForm(studentId, data, csrfToken);
method: 'PUT', // Utilisation de studentId
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
credentials: 'include',
body: JSON.stringify(data),
});
const result = await response.json();
console.log('Success:', result); console.log('Success:', result);
// Redirection après succès // Redirection après succès
window.location.href = FE_ADMIN_SUBSCRIPTIONS_URL; window.location.href = FE_ADMIN_SUBSCRIPTIONS_URL;

View File

@ -21,7 +21,7 @@ import {
PENDING, PENDING,
SUBSCRIBED, SUBSCRIBED,
ARCHIVED, ARCHIVED,
fetchRegisterForm, fetchRegisterForms,
createRegisterForm, createRegisterForm,
sendRegisterForm, sendRegisterForm,
archiveRegisterForm, archiveRegisterForm,
@ -159,13 +159,13 @@ const registerFormArchivedDataHandler = (data) => {
useEffect(() => { useEffect(() => {
const fetchDataAndSetState = () => { const fetchDataAndSetState = () => {
if (!useFakeData) { if (!useFakeData) {
fetchRegisterForm(PENDING, currentPage, itemsPerPage, searchTerm) fetchRegisterForms(PENDING, currentPage, itemsPerPage, searchTerm)
.then(registerFormPendingDataHandler) .then(registerFormPendingDataHandler)
.catch(requestErrorHandler) .catch(requestErrorHandler)
fetchRegisterForm(SUBSCRIBED) fetchRegisterForms(SUBSCRIBED)
.then(registerFormSubscribedDataHandler) .then(registerFormSubscribedDataHandler)
.catch(requestErrorHandler) .catch(requestErrorHandler)
fetchRegisterForm(ARCHIVED) fetchRegisterForms(ARCHIVED)
.then(registerFormArchivedDataHandler) .then(registerFormArchivedDataHandler)
.catch(requestErrorHandler) .catch(requestErrorHandler)
} else { } else {
@ -184,7 +184,7 @@ const registerFormArchivedDataHandler = (data) => {
// Modifier le useEffect pour la recherche // Modifier le useEffect pour la recherche
useEffect(() => { useEffect(() => {
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
fetchRegisterForm(PENDING, currentPage, itemsPerPage, searchTerm) fetchRegisterForms(PENDING, currentPage, itemsPerPage, searchTerm)
.then(registerFormPendingDataHandler) .then(registerFormPendingDataHandler)
.catch(requestErrorHandler) .catch(requestErrorHandler)
}, 500); // Debounce la recherche }, 500); // Debounce la recherche

View File

@ -5,7 +5,7 @@ import DropdownMenu from '@/components/DropdownMenu';
import { useRouter } from 'next/navigation'; // Ajout de l'importation import { useRouter } from 'next/navigation'; // Ajout de l'importation
import { Bell, User, MessageSquare, LogOut, Settings, Home } from 'lucide-react'; // Ajout de l'importation de l'icône Home import { Bell, User, MessageSquare, LogOut, Settings, Home } from 'lucide-react'; // Ajout de l'importation de l'icône Home
import Logo from '@/components/Logo'; // Ajout de l'importation du composant Logo import Logo from '@/components/Logo'; // Ajout de l'importation du composant Logo
import { FE_PARENTS_HOME_URL,FE_PARENTS_MESSAGERIE_URL,FE_PARENTS_SETTINGS_URL, BE_GESTIONINSCRIPTION_MESSAGES_URL } from '@/utils/Url'; // Ajout de l'importation de l'URL de la page d'accueil parent import { FE_PARENTS_HOME_URL,FE_PARENTS_MESSAGERIE_URL,FE_PARENTS_SETTINGS_URL, BE_GESTIONMESSAGERIE_MESSAGES_URL } from '@/utils/Url'; // Ajout de l'importation de l'URL de la page d'accueil parent
import useLocalStorage from '@/hooks/useLocalStorage'; import useLocalStorage from '@/hooks/useLocalStorage';
export default function Layout({ export default function Layout({
@ -19,7 +19,7 @@ export default function Layout({
useEffect(() => { useEffect(() => {
setUserId(userId); setUserId(userId);
fetch(`${BE_GESTIONINSCRIPTION_MESSAGES_URL}/${userId}`, { fetch(`${BE_GESTIONMESSAGERIE_MESSAGES_URL}/${userId}`, {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },

View File

@ -5,7 +5,8 @@ import Table from '@/components/Table';
import { Edit } from 'lucide-react'; import { Edit } from 'lucide-react';
import StatusLabel from '@/components/StatusLabel'; import StatusLabel from '@/components/StatusLabel';
import useLocalStorage from '@/hooks/useLocalStorage'; import useLocalStorage from '@/hooks/useLocalStorage';
import { BE_SUBSCRIPTION_CHILDRENS_URL , FE_PARENTS_EDIT_INSCRIPTION_URL } from '@/utils/Url'; import { FE_PARENTS_EDIT_INSCRIPTION_URL } from '@/utils/Url';
import { fetchChildren } from '@/app/lib/subscriptionAction';
export default function ParentHomePage() { export default function ParentHomePage() {
const [actions, setActions] = useState([]); const [actions, setActions] = useState([]);
@ -17,34 +18,22 @@ export default function ParentHomePage() {
useEffect(() => { useEffect(() => {
if (!userId) return; if (!userId) return;
const fetchActions = async () => { fetchChildren(userId).then(data => {
const response = await fetch('/api/actions'); setChildren(data);
const data = await response.json(); });
setActions(data);
};
const fetchEleves = async () => {
const response = await fetch(`${BE_SUBSCRIPTION_CHILDRENS_URL}/${userId}`);
const data = await response.json();
console.log(data);
setChildren(data);
};
fetchEleves();
}, [userId]); }, [userId]);
function handleEdit(eleveId) { function handleEdit(eleveId) {
// Logique pour éditer le dossier de l'élève // Logique pour éditer le dossier de l'élève
console.log(`Edit dossier for eleve id: ${eleveId}`); console.log(`Edit dossier for student id: ${eleveId}`);
router.push(`${FE_PARENTS_EDIT_INSCRIPTION_URL}?id=${userId}&studentId=${eleveId}`); router.push(`${FE_PARENTS_EDIT_INSCRIPTION_URL}?id=${userId}&studentId=${eleveId}`);
} }
const actionColumns = [ const actionColumns = [
{ name: 'Action', transform: (row) => row.action }, { name: 'Action', transform: (row) => row.action },
]; ];
const getShadowColor = (etat) => { const getShadowColor = (status) => {
switch (etat) { switch (status) {
case 1: case 1:
return 'shadow-blue-500'; // Couleur d'ombre plus visible return 'shadow-blue-500'; // Couleur d'ombre plus visible
case 2: case 2:
@ -73,12 +62,12 @@ export default function ParentHomePage() {
<h2 className="text-xl font-semibold mb-4">Enfants</h2> <h2 className="text-xl font-semibold mb-4">Enfants</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{children.map((child) => ( {children.map((child) => (
<div key={child.eleve.id} className={`border p-4 rounded shadow ${getShadowColor(child.etat)}`}> <div key={child.student.id} className={`border p-4 rounded shadow ${getShadowColor(child.status)}`}>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<h3 className="text-lg font-semibold">{child.eleve.nom} {child.eleve.prenom}</h3> <h3 className="text-lg font-semibold">{child.student.last_name} {child.student.first_name}</h3>
<Edit className="cursor-pointer" onClick={() => handleEdit(child.eleve.id)} /> <Edit className="cursor-pointer" onClick={() => handleEdit(child.student.id)} />
</div> </div>
<StatusLabel etat={child.etat } showDropdown={false}/> <StatusLabel etat={child.status } showDropdown={false}/>
</div> </div>
))} ))}
</div> </div>

View File

@ -8,9 +8,15 @@ import InputTextIcon from '@/components/InputTextIcon';
import Loader from '@/components/Loader'; // Importez le composant Loader import Loader from '@/components/Loader'; // Importez le composant Loader
import Button from '@/components/Button'; // Importez le composant Button import Button from '@/components/Button'; // Importez le composant Button
import { User, KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires import { User, KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires
import { BE_AUTH_LOGIN_URL, FE_ADMIN_SUBSCRIPTIONS_EDIT_URL, FE_ADMIN_SUBSCRIPTIONS_URL, FE_PARENTS_HOME_URL, FE_USERS_NEW_PASSWORD_URL, FE_USERS_SUBSCRIBE_URL } from '@/utils/Url'; import {
FE_ADMIN_SUBSCRIPTIONS_EDIT_URL,
FE_ADMIN_SUBSCRIPTIONS_URL,
FE_PARENTS_HOME_URL,
FE_USERS_NEW_PASSWORD_URL } from '@/utils/Url';
import useLocalStorage from '@/hooks/useLocalStorage'; import useLocalStorage from '@/hooks/useLocalStorage';
import useCsrfToken from '@/hooks/useCsrfToken'; import useCsrfToken from '@/hooks/useCsrfToken';
import { login } from '@/app/lib/authAction';
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true'; const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
export default function Page() { export default function Page() {
@ -55,22 +61,11 @@ export default function Page() {
} }
} }
} else { } else {
const request = new Request( const data = {
`${BE_AUTH_LOGIN_URL}`, email: formData.get('login'),
{ password: formData.get('password'),
method:'POST', }
headers: { login(data,csrfToken)
'Content-Type':'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify( {
email: formData.get('login'),
password: formData.get('password'),
}),
credentials: 'include',
}
);
fetch(request).then(response => response.json())
.then(data => { .then(data => {
console.log('Success:', data); console.log('Success:', data);
setUserFieldError("") setUserFieldError("")

View File

@ -1,16 +1,17 @@
'use client' 'use client'
import React, { useState, useEffect } from 'react'; import React, { useState } from 'react';
import DjangoCSRFToken from '@/components/DjangoCSRFToken' import DjangoCSRFToken from '@/components/DjangoCSRFToken'
import Logo from '@/components/Logo'; import Logo from '@/components/Logo';
import { useSearchParams, useRouter } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
import InputTextIcon from '@/components/InputTextIcon'; import InputTextIcon from '@/components/InputTextIcon';
import Loader from '@/components/Loader'; // Importez le composant Loader import Loader from '@/components/Loader'; // Importez le composant Loader
import Button from '@/components/Button'; // Importez le composant Button import Button from '@/components/Button'; // Importez le composant Button
import Popup from '@/components/Popup'; // Importez le composant Popup import Popup from '@/components/Popup'; // Importez le composant Popup
import { User } from 'lucide-react'; // Importez directement les icônes nécessaires import { User } from 'lucide-react'; // Importez directement les icônes nécessaires
import { BE_AUTH_NEW_PASSWORD_URL,FE_USERS_LOGIN_URL } from '@/utils/Url'; import { FE_USERS_LOGIN_URL } from '@/utils/Url';
import useCsrfToken from '@/hooks/useCsrfToken'; import useCsrfToken from '@/hooks/useCsrfToken';
import { sendNewPassword } from '@/app/lib/authAction';
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true'; const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
@ -34,21 +35,8 @@ export default function Page() {
setPopupVisible(true); setPopupVisible(true);
}, 1000); // Simule un délai de traitement }, 1000); // Simule un délai de traitement
} else { } else {
const request = new Request( const data = {email: formData.get('email')}
`${BE_AUTH_NEW_PASSWORD_URL}`, sendNewPassword(data, csrfToken)
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
credentials: 'include',
body: JSON.stringify({
email: formData.get('email')
}),
}
);
fetch(request).then(response => response.json())
.then(data => { .then(data => {
console.log('Success:', data); console.log('Success:', data);
setUserFieldError(""); setUserFieldError("");

View File

@ -9,9 +9,10 @@ import InputTextIcon from '@/components/InputTextIcon';
import Loader from '@/components/Loader'; // Importez le composant Loader import Loader from '@/components/Loader'; // Importez le composant Loader
import Button from '@/components/Button'; // Importez le composant Button import Button from '@/components/Button'; // Importez le composant Button
import Popup from '@/components/Popup'; import Popup from '@/components/Popup';
import { BE_AUTH_RESET_PASSWORD_URL, FE_USERS_LOGIN_URL } from '@/utils/Url'; import { FE_USERS_LOGIN_URL } from '@/utils/Url';
import { KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires import { KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires
import useCsrfToken from '@/hooks/useCsrfToken'; import useCsrfToken from '@/hooks/useCsrfToken';
import { getResetPassword, resetPassword } from '@/app/lib/authAction';
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true'; const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
@ -34,12 +35,7 @@ export default function Page() {
setIsLoading(false); setIsLoading(false);
}, 1000); }, 1000);
} else { } else {
const url= `${BE_AUTH_RESET_PASSWORD_URL}/${uuid}`; getResetPassword(uuid)
fetch(url, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
.then(data => { .then(data => {
console.log('Success:', data); console.log('Success:', data);
setIsLoading(true); setIsLoading(true);
@ -65,22 +61,11 @@ export default function Page() {
setPopupVisible(true); setPopupVisible(true);
}, 1000); }, 1000);
} else { } else {
const request = new Request( const data = {
`${BE_AUTH_RESET_PASSWORD_URL}/${uuid}`, password1: formData.get('password1'),
{ password2: formData.get('password2'),
method:'POST', }
headers: { resetPassword(uuid,data,csrfToken)
'Content-Type':'application/json',
'X-CSRFToken': csrfToken
},
credentials: 'include',
body: JSON.stringify( {
password1: formData.get('password1'),
password2: formData.get('password2'),
}),
}
);
fetch(request).then(response => response.json())
.then(data => { .then(data => {
console.log('Success:', data); console.log('Success:', data);
setPassword1FieldError("") setPassword1FieldError("")

View File

@ -10,8 +10,9 @@ import Loader from '@/components/Loader'; // Importez le composant Loader
import Button from '@/components/Button'; // Importez le composant Button import Button from '@/components/Button'; // Importez le composant Button
import Popup from '@/components/Popup'; // Importez le composant Popup import Popup from '@/components/Popup'; // Importez le composant Popup
import { User, KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires import { User, KeySquare } from 'lucide-react'; // Importez directement les icônes nécessaires
import { BE_AUTH_REGISTER_URL, FE_USERS_LOGIN_URL } from '@/utils/Url'; import { FE_USERS_LOGIN_URL } from '@/utils/Url';
import useCsrfToken from '@/hooks/useCsrfToken'; import useCsrfToken from '@/hooks/useCsrfToken';
import { subscribe } from '@/app/lib/authAction';
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true'; const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
export default function Page() { export default function Page() {
@ -21,7 +22,7 @@ export default function Page() {
const [userFieldError,setUserFieldError] = useState("") const [userFieldError,setUserFieldError] = useState("")
const [password1FieldError,setPassword1FieldError] = useState("") const [password1FieldError,setPassword1FieldError] = useState("")
const [password2FieldError,setPassword2FieldError] = useState("") const [password2FieldError,setPassword2FieldError] = useState("")
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(false);
const [popupVisible, setPopupVisible] = useState(false); const [popupVisible, setPopupVisible] = useState(false);
const [popupMessage, setPopupMessage] = useState(""); const [popupMessage, setPopupMessage] = useState("");
@ -30,6 +31,7 @@ export default function Page() {
useEffect(() => { useEffect(() => {
if (useFakeData) { if (useFakeData) {
setIsLoading(true);
// Simuler une réponse réussie // Simuler une réponse réussie
const data = { const data = {
errorFields: {}, errorFields: {},
@ -40,33 +42,6 @@ export default function Page() {
setPassword2FieldError("") setPassword2FieldError("")
setErrorMessage("") setErrorMessage("")
setIsLoading(false); setIsLoading(false);
} else {
const url= `${BE_AUTH_REGISTER_URL}`;
fetch(url, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
.then(data => {
console.log('Success:', data);
setUserFieldError("")
setPassword1FieldError("")
setPassword2FieldError("")
setErrorMessage("")
setIsLoading(true);
if(data.errorFields){
setUserFieldError(data.errorFields.email)
setPassword1FieldError(data.errorFields.password1)
setPassword2FieldError(data.errorFields.password2)
}
if(data.errorMessage){
setErrorMessage(data.errorMessage)
}
setIsLoading(false);
})
.catch(error => {
console.error('Error fetching data:', error);
});
} }
}, []); }, []);
@ -74,7 +49,7 @@ export default function Page() {
return data.errorMessage === "" return data.errorMessage === ""
} }
function suscribe(formData) { function subscribeFormSubmit(formData) {
if (useFakeData) { if (useFakeData) {
// Simuler une réponse réussie // Simuler une réponse réussie
const data = { const data = {
@ -99,24 +74,12 @@ export default function Page() {
} }
} }
} else { } else {
const request = new Request( const data ={
`${BE_AUTH_REGISTER_URL}`, email: formData.get('login'),
{ password1: formData.get('password1'),
method:'POST', password2: formData.get('password2'),
headers: { }
'Content-Type':'application/json', subscribe(data,csrfToken).then(data => {
'X-CSRFToken': csrfToken
},
credentials: 'include',
body: JSON.stringify( {
email: formData.get('login'),
password1: formData.get('password1'),
password2: formData.get('password2'),
}),
}
);
fetch(request).then(response => response.json())
.then(data => {
console.log('Success:', data); console.log('Success:', data);
setUserFieldError("") setUserFieldError("")
setPassword1FieldError("") setPassword1FieldError("")
@ -153,7 +116,7 @@ export default function Page() {
<Logo className="h-150 w-150" /> <Logo className="h-150 w-150" />
</div> </div>
<h1 className="text-2xl font-bold text-center mb-4">Nouveau profil</h1> <h1 className="text-2xl font-bold text-center mb-4">Nouveau profil</h1>
<form className="max-w-md mx-auto" onSubmit={(e) => { e.preventDefault(); suscribe(new FormData(e.target)); }}> <form className="max-w-md mx-auto" onSubmit={(e) => { e.preventDefault(); subscribeFormSubmit(new FormData(e.target)); }}>
<DjangoCSRFToken csrfToken={csrfToken} /> <DjangoCSRFToken csrfToken={csrfToken} />
<InputTextIcon name="login" type="text" IconItem={User} label="Identifiant" placeholder="Identifiant" errorMsg={userFieldError} className="w-full" /> <InputTextIcon name="login" type="text" IconItem={User} label="Identifiant" placeholder="Identifiant" errorMsg={userFieldError} className="w-full" />
<InputTextIcon name="password1" type="password" IconItem={KeySquare} label="Mot de passe" placeholder="Mot de passe" errorMsg={password1FieldError} className="w-full" /> <InputTextIcon name="password1" type="password" IconItem={KeySquare} label="Mot de passe" placeholder="Mot de passe" errorMsg={password1FieldError} className="w-full" />

View File

@ -1,7 +1,10 @@
import { import {
BE_AUTH_LOGIN_URL, BE_AUTH_LOGIN_URL,
BE_AUTH_REGISTER_URL,
BE_AUTH_PROFILE_URL, BE_AUTH_PROFILE_URL,
BE_AUTH_RESET_PASSWORD_URL,
BE_AUTH_NEW_PASSWORD_URL,
FE_USERS_LOGIN_URL , FE_USERS_LOGIN_URL ,
} from '@/utils/Url'; } from '@/utils/Url';
@ -9,6 +12,21 @@ import {mockUser} from "@/data/mockUsersData";
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true'; const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
export const login = (data, csrfToken) => {
const request = new Request(
`${BE_AUTH_LOGIN_URL}`,
{
method:'POST',
headers: {
'Content-Type':'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(data),
credentials: 'include',
}
);
return fetch(request).then(response => response.json())
}
/** /**
* Disconnects the user after confirming the action. * Disconnects the user after confirming the action.
@ -49,7 +67,6 @@ const request = new Request(
return fetch(request).then(response => response.json()) return fetch(request).then(response => response.json())
} }
export const updateProfile = (id, data, csrfToken) => { export const updateProfile = (id, data, csrfToken) => {
const request = new Request( const request = new Request(
`${BE_AUTH_PROFILE_URL}/${id}`, `${BE_AUTH_PROFILE_URL}/${id}`,
@ -65,3 +82,61 @@ export const updateProfile = (id, data, csrfToken) => {
); );
return fetch(request).then(response => response.json()) return fetch(request).then(response => response.json())
} }
export const sendNewPassword = (data, csrfToken) => {
const request = new Request(
`${BE_AUTH_NEW_PASSWORD_URL}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
credentials: 'include',
body: JSON.stringify(data),
}
);
return fetch(request).then(response => response.json())
}
export const subscribe = (data,csrfToken) =>{
const request = new Request(
`${BE_AUTH_REGISTER_URL}`,
{
method:'POST',
headers: {
'Content-Type':'application/json',
'X-CSRFToken': csrfToken
},
credentials: 'include',
body: JSON.stringify( data),
}
);
return fetch(request).then(response => response.json())
}
export const resetPassword = (uuid, data, csrfToken) => {
const request = new Request(
`${BE_AUTH_RESET_PASSWORD_URL}/${uuid}`,
{
method:'POST',
headers: {
'Content-Type':'application/json',
'X-CSRFToken': csrfToken
},
credentials: 'include',
body: JSON.stringify(data),
}
);
return fetch(request).then(response => response.json())
}
export const getResetPassword = (uuid) => {
const url= `${BE_AUTH_RESET_PASSWORD_URL}/${uuid}`;
return fetch(url, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
}

View File

@ -1,7 +1,9 @@
import { import {
BE_SUBSCRIPTION_STUDENTS_URL, BE_SUBSCRIPTION_STUDENTS_URL,
BE_SUBSCRIPTION_STUDENT_URL,
BE_SUBSCRIPTION_ARCHIVE_URL, BE_SUBSCRIPTION_ARCHIVE_URL,
BE_SUBSCRIPTION_SEND_URL, BE_SUBSCRIPTION_SEND_URL,
BE_SUBSCRIPTION_CHILDRENS_URL,
BE_SUBSCRIPTION_REGISTERFORM_URL, BE_SUBSCRIPTION_REGISTERFORM_URL,
BE_SUBSCRIPTION_REGISTERFORMS_URL, BE_SUBSCRIPTION_REGISTERFORMS_URL,
BE_SUBSCRIPTION_REGISTERFORMFILE_TEMPLATE_URL BE_SUBSCRIPTION_REGISTERFORMFILE_TEMPLATE_URL
@ -12,7 +14,7 @@ export const SUBSCRIBED = 'subscribed';
export const ARCHIVED = 'archived'; export const ARCHIVED = 'archived';
export const fetchRegisterForm = (type=PENDING, page='', pageSize='', search = '') => { export const fetchRegisterForms = (type=PENDING, page='', pageSize='', search = '') => {
let url = `${BE_SUBSCRIPTION_REGISTERFORMS_URL}/${type}`; let url = `${BE_SUBSCRIPTION_REGISTERFORMS_URL}/${type}`;
if (page !== '' && pageSize !== '') { if (page !== '' && pageSize !== '') {
url = `${BE_SUBSCRIPTION_REGISTERFORMS_URL}/${type}?page=${page}&search=${search}`; url = `${BE_SUBSCRIPTION_REGISTERFORMS_URL}/${type}?page=${page}&search=${search}`;
@ -24,6 +26,11 @@ export const fetchRegisterForm = (type=PENDING, page='', pageSize='', search =
}).then(response => response.json()) }).then(response => response.json())
}; };
export const fetchRegisterForm = (id) =>{
return fetch(`${BE_SUBSCRIPTION_STUDENT_URL}/${id}`) // Utilisation de studentId au lieu de codeDI
.then(response => response.json())
}
export const editRegisterForm=(id, data, csrfToken)=>{ export const editRegisterForm=(id, data, csrfToken)=>{
return fetch(`${BE_SUBSCRIPTION_REGISTERFORM_URL}/${id}`, { return fetch(`${BE_SUBSCRIPTION_REGISTERFORM_URL}/${id}`, {
@ -121,3 +128,16 @@ export const fetchStudents = () => {
return fetch(request).then(response => response.json()) return fetch(request).then(response => response.json())
}; };
export const fetchChildren = (id) =>{
const request = new Request(
`${BE_SUBSCRIPTION_CHILDRENS_URL}/${id}`,
{
method:'GET',
headers: {
'Content-Type':'application/json'
},
}
);
return fetch(request).then(response => response.json())
}

View File

@ -25,19 +25,19 @@ export default function InscriptionFormShared({
const [formData, setFormData] = useState(() => ({ const [formData, setFormData] = useState(() => ({
id: initialData?.id || '', id: initialData?.id || '',
nom: initialData?.nom || '', last_name: initialData?.last_name || '',
prenom: initialData?.prenom || '', first_name: initialData?.first_name || '',
adresse: initialData?.adresse || '', address: initialData?.address || '',
dateNaissance: initialData?.dateNaissance || '', birth_date: initialData?.birth_date || '',
lieuNaissance: initialData?.lieuNaissance || '', birth_place: initialData?.birth_place || '',
codePostalNaissance: initialData?.codePostalNaissance || '', birth_postal_code: initialData?.birth_postal_code || '',
nationalite: initialData?.nationalite || '', nationality: initialData?.nationality || '',
medecinTraitant: initialData?.medecinTraitant || '', attending_physician: initialData?.attending_physician || '',
niveau: initialData?.niveau || '' level: initialData?.level || ''
})); }));
const [responsables, setReponsables] = useState(() => const [guardians, setGuardians] = useState(() =>
initialData?.responsables || [] initialData?.guardians || []
); );
const [uploadedFiles, setUploadedFiles] = useState([]); const [uploadedFiles, setUploadedFiles] = useState([]);
@ -47,17 +47,17 @@ export default function InscriptionFormShared({
if (initialData) { if (initialData) {
setFormData({ setFormData({
id: initialData.id || '', id: initialData.id || '',
nom: initialData.nom || '', last_name: initialData.last_name || '',
prenom: initialData.prenom || '', first_name: initialData.first_name || '',
adresse: initialData.adresse || '', address: initialData.address || '',
dateNaissance: initialData.dateNaissance || '', birth_date: initialData.birth_date || '',
lieuNaissance: initialData.lieuNaissance || '', birth_place: initialData.birth_place || '',
codePostalNaissance: initialData.codePostalNaissance || '', birth_postal_code: initialData.birth_postal_code || '',
nationalite: initialData.nationalite || '', nationality: initialData.nationality || '',
medecinTraitant: initialData.medecinTraitant || '', attending_physician: initialData.attending_physician || '',
niveau: initialData.niveau || '' level: initialData.level || ''
}); });
setReponsables(initialData.responsables || []); setGuardians(initialData.guardians || []);
} }
}, [initialData]); }, [initialData]);
@ -71,16 +71,17 @@ export default function InscriptionFormShared({
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
onSubmit({ const data ={
eleve: { student: {
...formData, ...formData,
responsables guardians
} }
}); }
onSubmit(data);
}; };
const columns = [ const columns = [
{ name: 'Nom du fichier', transform: (row) => row.nom }, { name: 'Nom du fichier', transform: (row) => row.last_name },
{ name: 'Actions', transform: (row) => ( { name: 'Actions', transform: (row) => (
<a href={URL.createObjectURL(row.fichier)} target='_blank' className="text-blue-500 hover:text-blue-700"> <a href={URL.createObjectURL(row.fichier)} target='_blank' className="text-blue-500 hover:text-blue-700">
Télécharger Télécharger
@ -99,64 +100,64 @@ export default function InscriptionFormShared({
<h2 className="text-xl font-bold mb-4 text-gray-800">Informations de l'élève</h2> <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"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<InputText <InputText
name="nom" name="last_name"
label="Nom" label="Nom"
value={formData.nom} value={formData.last_name}
onChange={(e) => updateFormField('nom', e.target.value)} onChange={(e) => updateFormField('last_name', e.target.value)}
required required
/> />
<InputText <InputText
name="prenom" name="first_name"
label="Prénom" label="Prénom"
value={formData.prenom} value={formData.first_name}
onChange={(e) => updateFormField('prenom', e.target.value)} onChange={(e) => updateFormField('first_name', e.target.value)}
required required
/> />
<InputText <InputText
name="nationalite" name="nationality"
label="Nationalité" label="Nationalité"
value={formData.nationalite} value={formData.nationality}
onChange={(e) => updateFormField('nationalite', e.target.value)} onChange={(e) => updateFormField('nationality', e.target.value)}
/> />
<InputText <InputText
name="dateNaissance" name="birth_date"
type="date" type="date"
label="Date de Naissance" label="Date de Naissance"
value={formData.dateNaissance} value={formData.birth_date}
onChange={(e) => updateFormField('dateNaissance', e.target.value)} onChange={(e) => updateFormField('birth_date', e.target.value)}
required required
/> />
<InputText <InputText
name="lieuNaissance" name="birth_place"
label="Lieu de Naissance" label="Lieu de Naissance"
value={formData.lieuNaissance} value={formData.birth_place}
onChange={(e) => updateFormField('lieuNaissance', e.target.value)} onChange={(e) => updateFormField('birth_place', e.target.value)}
/> />
<InputText <InputText
name="codePostalNaissance" name="birth_postal_code"
label="Code Postal de Naissance" label="Code Postal de Naissance"
value={formData.codePostalNaissance} value={formData.birth_postal_code}
onChange={(e) => updateFormField('codePostalNaissance', e.target.value)} onChange={(e) => updateFormField('birth_postal_code', e.target.value)}
/> />
<div className="md:col-span-2"> <div className="md:col-span-2">
<InputText <InputText
name="adresse" name="address"
label="Adresse" label="Adresse"
value={formData.adresse} value={formData.address}
onChange={(e) => updateFormField('adresse', e.target.value)} onChange={(e) => updateFormField('address', e.target.value)}
/> />
</div> </div>
<InputText <InputText
name="medecinTraitant" name="attending_physician"
label="Médecin Traitant" label="Médecin Traitant"
value={formData.medecinTraitant} value={formData.attending_physician}
onChange={(e) => updateFormField('medecinTraitant', e.target.value)} onChange={(e) => updateFormField('attending_physician', e.target.value)}
/> />
<SelectChoice <SelectChoice
name="niveau" name="level"
label="Niveau" label="Niveau"
selected={formData.niveau} selected={formData.level}
callback={(e) => updateFormField('niveau', e.target.value)} callback={(e) => updateFormField('level', e.target.value)}
choices={niveaux} choices={niveaux}
required required
/> />
@ -167,21 +168,21 @@ export default function InscriptionFormShared({
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200"> <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> <h2 className="text-xl font-bold mb-4 text-gray-800">Responsables</h2>
<ResponsableInputFields <ResponsableInputFields
responsables={responsables} guardians={guardians}
onResponsablesChange={(id, field, value) => { onGuardiansChange={(id, field, value) => {
const updatedResponsables = responsables.map(resp => const updatedGuardians = guardians.map(resp =>
resp.id === id ? { ...resp, [field]: value } : resp resp.id === id ? { ...resp, [field]: value } : resp
); );
setReponsables(updatedResponsables); setGuardians(updatedGuardians);
}} }}
addResponsible={(e) => { addGuardian={(e) => {
e.preventDefault(); e.preventDefault();
setReponsables([...responsables, { id: Date.now() }]); setGuardians([...guardians, { id: Date.now() }]);
}} }}
deleteResponsable={(index) => { deleteGuardian={(index) => {
const newArray = [...responsables]; const newArray = [...guardians];
newArray.splice(index, 1); newArray.splice(index, 1);
setReponsables(newArray); setGuardians(newArray);
}} }}
/> />
</div> </div>

View File

@ -5,19 +5,19 @@ import React from 'react';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import 'react-phone-number-input/style.css' import 'react-phone-number-input/style.css'
export default function ResponsableInputFields({responsables, onResponsablesChange, addResponsible, deleteResponsable}) { export default function ResponsableInputFields({guardians, onGuardiansChange, addGuardian, deleteGuardian}) {
const t = useTranslations('ResponsableInputFields'); const t = useTranslations('ResponsableInputFields');
return ( return (
<div className="space-y-8"> <div className="space-y-8">
{responsables.map((item, index) => ( {guardians.map((item, index) => (
<div className="p-6 bg-gray-50 rounded-lg shadow-sm" key={index}> <div className="p-6 bg-gray-50 rounded-lg shadow-sm" key={index}>
<div className='flex justify-between items-center mb-4'> <div className='flex justify-between items-center mb-4'>
<h3 className='text-xl font-bold'>{t('responsable')} {index+1}</h3> <h3 className='text-xl font-bold'>{t('responsable')} {index+1}</h3>
{responsables.length > 1 && ( {guardians.length > 1 && (
<Button <Button
text={t('delete')} text={t('delete')}
onClick={() => deleteResponsable(index)} onClick={() => deleteGuardian(index)}
className="w-32" className="w-32"
/> />
)} )}
@ -31,15 +31,15 @@ export default function ResponsableInputFields({responsables, onResponsablesChan
name="nomResponsable" name="nomResponsable"
type="text" type="text"
label={t('lastname')} label={t('lastname')}
value={item.nom} value={item.last_name}
onChange={(event) => {onResponsablesChange(item.id, "nom", event.target.value)}} onChange={(event) => {onGuardiansChange(item.id, "last_name", event.target.value)}}
/> />
<InputText <InputText
name="prenomResponsable" name="prenomResponsable"
type="text" type="text"
label={t('firstname')} label={t('firstname')}
value={item.prenom} value={item.first_name}
onChange={(event) => {onResponsablesChange(item.id, "prenom", event.target.value)}} onChange={(event) => {onGuardiansChange(item.id, "first_name", event.target.value)}}
/> />
</div> </div>
@ -48,14 +48,14 @@ export default function ResponsableInputFields({responsables, onResponsablesChan
name="mailResponsable" name="mailResponsable"
type="email" type="email"
label={t('email')} label={t('email')}
value={item.mail} value={item.email}
onChange={(event) => {onResponsablesChange(item.id, "mail", event.target.value)}} onChange={(event) => {onGuardiansChange(item.id, "email", event.target.value)}}
/> />
<InputPhone <InputPhone
name="telephoneResponsable" name="telephoneResponsable"
label={t('phone')} label={t('phone')}
value={item.telephone} value={item.phone}
onChange={(event) => {onResponsablesChange(item.id, "telephone", event)}} onChange={(event) => {onGuardiansChange(item.id, "phone", event)}}
/> />
</div> </div>
@ -64,15 +64,15 @@ export default function ResponsableInputFields({responsables, onResponsablesChan
name="dateNaissanceResponsable" name="dateNaissanceResponsable"
type="date" type="date"
label={t('birthdate')} label={t('birthdate')}
value={item.dateNaissance} value={item.birth_date}
onChange={(event) => {onResponsablesChange(item.id, "dateNaissance", event.target.value)}} onChange={(event) => {onGuardiansChange(item.id, "birth_date", event.target.value)}}
/> />
<InputText <InputText
name="professionResponsable" name="professionResponsable"
type="text" type="text"
label={t('profession')} label={t('profession')}
value={item.profession} value={item.profession}
onChange={(event) => {onResponsablesChange(item.id, "profession", event.target.value)}} onChange={(event) => {onGuardiansChange(item.id, "profession", event.target.value)}}
/> />
</div> </div>
@ -81,8 +81,8 @@ export default function ResponsableInputFields({responsables, onResponsablesChan
name="adresseResponsable" name="adresseResponsable"
type="text" type="text"
label={t('address')} label={t('address')}
value={item.adresse} value={item.address}
onChange={(event) => {onResponsablesChange(item.id, "adresse", event.target.value)}} onChange={(event) => {onGuardiansChange(item.id, "address", event.target.value)}}
/> />
</div> </div>
</div> </div>
@ -91,7 +91,7 @@ export default function ResponsableInputFields({responsables, onResponsablesChan
<div className="flex justify-center"> <div className="flex justify-center">
<Button <Button
text={t('add_responsible')} text={t('add_responsible')}
onClick={(e) => addResponsible(e)} onClick={(e) => addGuardian(e)}
primary primary
icon={<i className="icon profile-add" />} icon={<i className="icon profile-add" />}
type="button" type="button"

View File

@ -17,7 +17,7 @@ export const BE_AUTH_CSRF_URL = `${BASE_URL}/Auth/csrf`
// GESTION INSCRIPTION // GESTION INSCRIPTION
export const BE_SUBSCRIPTION_STUDENT_URL = `${BASE_URL}/Subscriptions/student` export const BE_SUBSCRIPTION_STUDENT_URL = `${BASE_URL}/Subscriptions/student`
export const BE_SUBSCRIPTION_STUDENTS_URL = `${BASE_URL}/Subscriptions/students` // Récupère la liste des élèves inscrits ou en cours d'inscriptions export const BE_SUBSCRIPTION_STUDENTS_URL = `${BASE_URL}/Subscriptions/students` // Récupère la liste des élèves inscrits ou en cours d'inscriptions
export const BE_SUBSCRIPTION_CHILDRENS_URL = `${BASE_URL}/Subscriptions/childrens` // Récupère la liste des élèves d'un profil export const BE_SUBSCRIPTION_CHILDRENS_URL = `${BASE_URL}/Subscriptions/children` // Récupère la liste des élèves d'un profil
export const BE_SUBSCRIPTION_SEND_URL = `${BASE_URL}/Subscriptions/send` export const BE_SUBSCRIPTION_SEND_URL = `${BASE_URL}/Subscriptions/send`
export const BE_SUBSCRIPTION_ARCHIVE_URL = `${BASE_URL}/Subscriptions/archive` export const BE_SUBSCRIPTION_ARCHIVE_URL = `${BASE_URL}/Subscriptions/archive`
export const BE_SUBSCRIPTION_REGISTERFORM_URL = `${BASE_URL}/Subscriptions/registerForm` export const BE_SUBSCRIPTION_REGISTERFORM_URL = `${BASE_URL}/Subscriptions/registerForm`
@ -36,7 +36,7 @@ export const BE_SCHOOL_PLANNING_URL = `${BASE_URL}/School/planning`
export const BE_SCHOOL_PLANNINGS_URL = `${BASE_URL}/School/plannings` export const BE_SCHOOL_PLANNINGS_URL = `${BASE_URL}/School/plannings`
// GESTION MESSAGERIE // GESTION MESSAGERIE
export const BE_GESTIONINSCRIPTION_MESSAGES_URL = `${BASE_URL}/GestionMessagerie/messagerie` export const BE_GESTIONMESSAGERIE_MESSAGES_URL = `${BASE_URL}/GestionMessagerie/messagerie`
// URL FRONT-END // URL FRONT-END
export const FE_HOME_URL = `/` export const FE_HOME_URL = `/`