refactor: Renommage du menu "Eleves" en "Inscriptions"

This commit is contained in:
N3WT DE COMPET
2024-11-24 12:06:01 +01:00
parent 56e27628f8
commit 692e8454bf
10 changed files with 18 additions and 18 deletions

View File

@ -0,0 +1,651 @@
'use client'
import React, { useState, useEffect } from 'react';
import Table from '@/components/Table';
import {mockFicheInscription} from '@/data/mockFicheInscription';
import Tab from '@/components/Tab';
import { useTranslations } from 'next-intl';
import StatusLabel from '@/components/StatusLabel';
import { Search } from 'lucide-react';
import Popup from '@/components/Popup';
import Loader from '@/components/Loader';
import AlertWithModal from '@/components/AlertWithModal';
import Button from '@/components/Button';
import DropdownMenu from "@/components/DropdownMenu";
import { swapFormatDate } from '@/utils/Date';
import { formatPhoneNumber } from '@/utils/Telephone';
import { MoreVertical, Send, Edit, Trash2, FileText, ChevronUp, UserPlus, CheckCircle } from 'lucide-react';
import Modal from '@/components/Modal';
import InscriptionForm from '@/components/Inscription/InscriptionForm'
import AffectationClasseForm from '@/components/AffectationClasseForm'
import { BK_GESTIONINSCRIPTION_FICHESINSCRIPTION_URL,
BK_GESTIONINSCRIPTION_SEND_URL,
FR_ADMIN_SUBSCRIPTIONS_EDIT_URL,
BK_GESTIONINSCRIPTION_ARCHIVE_URL,
BK_GESTIONINSCRIPTION_CLASSES_URL,
BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL,
BK_GESTIONINSCRIPTION_ELEVES_URL,
BK_PROFILE_URL } from '@/utils/Url';
import DjangoCSRFToken from '@/components/DjangoCSRFToken'
import useCsrfToken from '@/hooks/useCsrfToken';
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
export default function Page({ params: { locale } }) {
const t = useTranslations('subscriptions');
const [ficheInscriptions, setFicheInscriptions] = useState([]);
const [fichesInscriptionsDataEnCours, setFichesInscriptionsDataEnCours] = useState([]);
const [fichesInscriptionsDataInscrits, setFichesInscriptionsDataInscrits] = useState([]);
const [fichesInscriptionsDataArchivees, setFichesInscriptionsDataArchivees] = useState([]);
// const [filter, setFilter] = useState('*');
const [searchTerm, setSearchTerm] = useState('');
const [alertPage, setAlertPage] = useState(false);
const [mailSent, setMailSent] = useState(false);
const [ficheArchivee, setFicheArchivee] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [popup, setPopup] = useState({ visible: false, message: '', onConfirm: null });
const [activeTab, setActiveTab] = useState('pending');
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalPending, setTotalPending] = useState(0);
const [totalSubscribed, setTotalSubscribed] = useState(0);
const [totalArchives, setTotalArchives] = useState(0);
const [itemsPerPage, setItemsPerPage] = useState(5); // Définir le nombre d'éléments par page
const [isOpen, setIsOpen] = useState(false);
const [isOpenAffectationClasse, setIsOpenAffectationClasse] = useState(false);
const [eleve, setEleve] = useState('');
const [classes, setClasses] = useState([]);
const [eleves, setEleves] = useState([]);
const csrfToken = useCsrfToken();
const openModal = () => {
setIsOpen(true);
}
const closeModal = () => {
setIsOpen(false);
}
const openModalAssociationEleve = (eleveSelected) => {
setIsOpenAffectationClasse(true);
setEleve(eleveSelected);
}
// Modifier la fonction fetchData pour inclure le terme de recherche
const fetchData = (page, pageSize, search = '') => {
const url = `${BK_GESTIONINSCRIPTION_FICHESINSCRIPTION_URL}/pending?page=${page}&page_size=${pageSize}&search=${search}`;
fetch(url, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
.then(data => {
setIsLoading(false);
if (data) {
const { fichesInscriptions, count } = data;
if (ficheInscriptions) {
setFichesInscriptionsDataEnCours(fichesInscriptions);
}
const calculatedTotalPages = Math.ceil(count / pageSize);
setTotalPending(count);
setTotalPages(calculatedTotalPages);
}
console.log('Success PENDING:', data);
})
.catch(error => {
console.error('Error fetching data:', error);
setIsLoading(false);
});
};
const fetchDataSubscribed = () => {
fetch(`${BK_GESTIONINSCRIPTION_FICHESINSCRIPTION_URL}/subscribed`, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
.then(data => {
setIsLoading(false);
if (data) {
const { fichesInscriptions, count } = data;
setTotalSubscribed(count);
if (fichesInscriptions) {
setFichesInscriptionsDataInscrits(fichesInscriptions);
}
}
console.log('Success SUBSCRIBED:', data);
})
.catch(error => {
console.error('Error fetching data:', error);
setIsLoading(false);
});
};
const fetchDataArchived = () => {
fetch(`${BK_GESTIONINSCRIPTION_FICHESINSCRIPTION_URL}/archived`, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
.then(data => {
setIsLoading(false);
if (data) {
const { fichesInscriptions, count } = data;
setTotalArchives(count);
if (fichesInscriptions) {
setFichesInscriptionsDataArchivees(fichesInscriptions);
}
}
console.log('Success ARCHIVED:', data);
})
.catch(error => {
console.error('Error fetching data:', error);
setIsLoading(false);
});
};
const fetchClasses = () => {
fetch(`${BK_GESTIONINSCRIPTION_CLASSES_URL}`)
.then(response => response.json())
.then(data => {
setClasses(data);
console.log("Success CLASSES : ", data)
})
.catch(error => {
console.error('Error fetching classes:', error);
});
};
const fetchStudents = () => {
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 STUDENTS:', data);
setEleves(data);
})
.catch(error => {
console.error('Error fetching data:', error);
error = error.message;
console.log(error);
});
};
useEffect(() => {
fetchClasses();
fetchStudents();
}, []);
useEffect(() => {
const fetchDataAndSetState = () => {
if (!useFakeData) {
fetchData(currentPage, itemsPerPage, searchTerm);
fetchDataSubscribed();
fetchDataArchived();
} else {
setTimeout(() => {
setFichesInscriptionsDataEnCours(mockFicheInscription);
setIsLoading(false);
}, 1000);
}
setFicheArchivee(false);
setMailSent(false);
};
fetchDataAndSetState();
}, [mailSent, ficheArchivee, currentPage, itemsPerPage]);
// Modifier le useEffect pour la recherche
useEffect(() => {
const timeoutId = setTimeout(() => {
fetchData(currentPage, itemsPerPage, searchTerm);
}, 500); // Debounce la recherche
return () => clearTimeout(timeoutId);
}, [searchTerm, currentPage, itemsPerPage]);
const archiveFicheInscription = (id, nom, prenom) => {
setPopup({
visible: true,
message: `Attentions ! \nVous êtes sur le point d'archiver le dossier d'inscription de ${nom} ${prenom}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`,
onConfirm: () => {
const url = `${BK_GESTIONINSCRIPTION_ARCHIVE_URL}/${id}`;
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
.then(data => {
console.log('Success:', data);
setFicheInscriptions(ficheInscriptions.filter(fiche => fiche.id !== id));
setFicheArchivee(true);
alert("Le dossier d'inscription a été correctement archivé");
})
.catch(error => {
console.error('Error archiving data:', error);
alert("Erreur lors de l'archivage du dossier d'inscription.\nContactez l'administrateur.");
});
}
});
};
const sendConfirmFicheInscription = (id, nom, prenom) => {
setPopup({
visible: true,
message: `Avertissement ! \nVous êtes sur le point d'envoyer un dossier d'inscription à ${nom} ${prenom}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`,
onConfirm: () => {
const url = `${BK_GESTIONINSCRIPTION_SEND_URL}/${id}`;
fetch(url, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json())
.then(data => {
console.log('Success:', data);
setMailSent(true);
})
.catch(error => {
console.error('Error fetching data:', error);
});
}
});
};
const updateStatusAction = (id, newStatus) => {
console.log('Edit fiche inscription with id:', id);
};
const handleLetterClick = (letter) => {
setFilter(letter);
};
const handleSearchChange = (event) => {
setSearchTerm(event.target.value);
};
const handlePageChange = (newPage) => {
setCurrentPage(newPage);
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) => {
fetch(`${BK_GESTIONINSCRIPTION_FICHEINSCRIPTION_URL}/${eleve.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify(updatedData),
credentials: 'include'
})
.then(response => response.json())
.then(data => {
console.log('Succès :', data);
})
.catch(error => {
console.error('Erreur :', error);
});
}
const columns = [
{ name: t('studentName'), transform: (row) => row.eleve.nom },
{ name: t('studentFistName'), transform: (row) => row.eleve.prenom },
{ name: t('mainContactMail'), transform: (row) => row.eleve.responsables[0].mail },
{ name: t('phone'), transform: (row) => formatPhoneNumber(row.eleve.responsables[0].telephone) },
{ name: t('lastUpdateDate'), transform: (row) => row.dateMAJ_formattee},
{ name: t('registrationFileStatus'), transform: (row) => (
<div className="flex justify-center items-center h-full">
<StatusLabel etat={row.etat} onChange={(newStatus) => updateStatusAction(row.eleve.id, newStatus)} showDropdown={false} />
</div>
)
},
{ name: t('files'), transform: (row) => (
<ul>
{row.fichiers?.map((fichier, fileIndex) => (
<li key={fileIndex} className="flex items-center gap-2">
<FileText size={16} />
<a href={fichier.url}>{fichier.nom}</a>
</li>
))}
</ul>
) },
{ name: 'Actions', transform: (row) => (
<DropdownMenu
buttonContent={<MoreVertical size={20} className="text-gray-400 hover:text-gray-600" />}
items={[
...(row.etat === 1 ? [{
label: (
<>
<Send size={16} className="mr-2" /> Envoyer
</>
),
onClick: () => sendConfirmFicheInscription(row.eleve.id, row.eleve.nom, row.eleve.prenom),
}] : []),
...(row.etat === 1 ? [{
label: (
<>
<Edit size={16} className="mr-2" /> Modifier
</>
),
onClick: () => window.location.href = `${FR_ADMIN_SUBSCRIPTIONS_EDIT_URL}?idEleve=${row.eleve.id}&id=1`,
}] : []),
...(row.etat === 2 ? [{
label: (
<>
<Edit size={16} className="mr-2" /> Modifier
</>
),
onClick: () => window.location.href = `${FR_ADMIN_SUBSCRIPTIONS_EDIT_URL}?idEleve=${row.eleve.id}&id=1`,
}] : []),
...(row.etat === 3 ? [{
label: (
<>
<CheckCircle size={16} className="mr-2" /> Valider
</>
),
onClick: () => openModalAssociationEleve(row.eleve),
}] : []),
...(row.etat === 5 ? [{
label: (
<>
<CheckCircle size={16} className="mr-2" /> Rattacher
</>
),
onClick: () => openModalAssociationEleve(row.eleve),
}] : []),
...(row.etat !== 6 ? [{
label: (
<>
<Trash2 size={16} className="mr-2 text-red-700" /> Archiver
</>
),
onClick: () => archiveFicheInscription(row.eleve.id, row.eleve.nom, row.eleve.prenom),
}] : []),
]}
buttonClassName="text-gray-400 hover:text-gray-600"
menuClassName="absolute right-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-10 flex flex-col items-center"
/>
) },
];
const columnsSubscribed = [
{ name: t('studentName'), transform: (row) => row.eleve.nom },
{ name: t('studentFistName'), transform: (row) => row.eleve.prenom },
{ name: t('lastUpdateDate'), transform: (row) => row.dateMAJ_formattee},
{ name: t('class'), transform: (row) => row.eleve.classeAssocieeName},
{ name: t('registrationFileStatus'), transform: (row) => (
<div className="flex justify-center items-center h-full">
<StatusLabel etat={row.etat} onChange={(newStatus) => updateStatusAction(row.eleve.id, newStatus)} showDropdown={false} />
</div>
)
},
{ name: t('files'), transform: (row) => (
<ul>
{row.fichiers?.map((fichier, fileIndex) => (
<li key={fileIndex} className="flex items-center gap-2">
<FileText size={16} />
<a href={fichier.url}>{fichier.nom}</a>
</li>
))}
</ul>
) },
{ name: 'Actions', transform: (row) => (
<DropdownMenu
buttonContent={<MoreVertical size={20} className="text-gray-400 hover:text-gray-600" />}
items={[
{ label: (
<>
<CheckCircle size={16} className="mr-2" /> Rattacher
</>
),
onClick: () => openModalAssociationEleve(row.eleve)
},
{ label: (
<>
<Trash2 size={16} className="mr-2 text-red-700" /> Archiver
</>
),
onClick: () => archiveFicheInscription(row.eleve.id, row.eleve.nom, row.eleve.prenom),
}
]}
buttonClassName="text-gray-400 hover:text-gray-600"
menuClassName="absolute right-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-10 flex flex-col items-center"
/>
) },
];
if (isLoading) {
return <Loader />;
} else {
if (ficheInscriptions.length === 0 && fichesInscriptionsDataArchivees.length === 0 && alertPage) {
return (
<div className='p-8'>
<AlertWithModal
title={t("information")}
message={t("no_records") + " " + t("create_first_record")}
buttonText={t("add_button")}
/>
</div>
);
} else {
return (
<div className='p-8'>
<div className="border-b border-gray-200 mb-6">
<div className="flex gap-8">
<Tab
text={<>
{t('pending')}
<span className="ml-2 text-sm text-gray-400">({totalPending})</span>
</>}
active={activeTab === 'pending'}
onClick={() => setActiveTab('pending')}
/>
<Tab
text={<>
{t('subscribed')}
<span className="ml-2 text-sm text-gray-400">({totalSubscribed})</span>
</>}
active={activeTab === 'subscribed'}
onClick={() => setActiveTab('subscribed')}
/>
<Tab
text={<>
{t('archived')}
<span className="ml-2 text-sm text-gray-400">({totalArchives})</span>
</>}
active={activeTab === 'archived'}
onClick={() => setActiveTab('archived')}
/>
<Button text={t("addStudent")} primary onClick={openModal} icon={<UserPlus size={20} />} />
</div>
</div>
<div className="flex justify-between items-center mb-6">
<div className="relative flex-grow mr-4">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400" size={20} />
<input
type="text"
placeholder={t('searchStudent')}
className="w-full pl-10 pr-4 py-2 border border-gray-200 rounded-md"
value={searchTerm}
onChange={handleSearchChange}
/>
</div>
</div>
<DjangoCSRFToken csrfToken={csrfToken} />
<Table
key={`${currentPage}-${searchTerm}`}
data={
activeTab === 'pending'
? fichesInscriptionsDataEnCours
: activeTab === 'subscribed'
? fichesInscriptionsDataInscrits
: fichesInscriptionsDataArchivees
}
columns={
activeTab === 'subscribed'
? columnsSubscribed
: columns
}
itemsPerPage={itemsPerPage}
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
/>
<Popup
visible={popup.visible}
message={popup.message}
onConfirm={() => {
popup.onConfirm();
setPopup({ ...popup, visible: false });
}}
onCancel={() => setPopup({ ...popup, visible: false })}
/>
{isOpen && (
<Modal
isOpen={isOpen}
setIsOpen={setIsOpen}
title={"Création d'un nouveau dossier d'inscription"}
ContentComponent={() => (
<InscriptionForm eleves={eleves}
onSubmit={createDI}
/>
)}
/>
)}
{isOpenAffectationClasse && (
<Modal
isOpen={isOpenAffectationClasse}
setIsOpen={setIsOpenAffectationClasse}
title="Affectation à une classe"
ContentComponent={() => (
<AffectationClasseForm
eleve={eleve}
onSubmit={validateAndAssociate}
classes={classes}
/>
)}
/>
)}
</div>
);
}
}
}