'use client'; import React, { useState, useEffect } from 'react'; import Table from '@/components/Table'; import Tab from '@/components/Tab'; import { useTranslations } from 'next-intl'; import StatusLabel from '@/components/StatusLabel'; import Popup from '@/components/Popup'; import Loader from '@/components/Loader'; import { useRouter } from 'next/navigation'; import { Search, Send, Edit, Archive, FileText, CheckCircle, Plus, Upload, Eye, } from 'lucide-react'; import Modal from '@/components/Modal'; import { useEstablishment } from '@/context/EstablishmentContext'; import { fetchRegisterForms, sendRegisterForm, archiveRegisterForm, editRegisterForm, } from '@/app/actions/subscriptionAction'; import { fetchClasses } from '@/app/actions/schoolAction'; import { FE_ADMIN_SUBSCRIPTIONS_EDIT_URL, FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL, FE_ADMIN_SUBSCRIPTIONS_CREATE_URL, BASE_URL, } from '@/utils/Url'; import DjangoCSRFToken from '@/components/DjangoCSRFToken'; import { useCsrfToken } from '@/context/CsrfContext'; import logger from '@/utils/logger'; import { PhoneLabel } from '@/components/PhoneLabel'; import FileUpload from '@/components/FileUpload'; import FilesModal from '@/components/Inscription/FilesModal'; import { getCurrentSchoolYear, getNextSchoolYear } from '@/utils/Date'; import { RegistrationFormStatus, CURRENT_YEAR_FILTER, NEXT_YEAR_FILTER, HISTORICAL_FILTER, } from '@/utils/constants'; import AlertMessage from '@/components/AlertMessage'; import { useNotification } from '@/context/NotificationContext'; export default function Page({ params: { locale } }) { const t = useTranslations('subscriptions'); const [registrationForms, setRegistrationForms] = useState([]); const [ registrationFormsDataCurrentYear, setRegistrationFormsDataCurrentYear, ] = useState([]); const [registrationFormsDataNextYear, setRegistrationFormsDataNextYear] = useState([]); const [registrationFormsDataHistorical, setRegistrationFormsDataHistorical] = useState([]); const currentSchoolYear = getCurrentSchoolYear(); const nextSchoolYear = getNextSchoolYear(); const [totalCurrentSchoolYearPages, setTotalCurrentSchoolYearPages] = useState(1); const [totalNextSchoolYearPages, setTotalNextSchoolYearPages] = useState(1); const [totalHistoricalPages, setTotalHistoricalPages] = useState(1); const [currentSchoolYearPage, setCurrentSchoolYearPage] = useState(1); const [currentSchoolNextYearPage, setCurrentSchoolNextYearPage] = useState(1); const [currentSchoolHistoricalYearPage, setCurrentSchoolHistoricalYearPage] = useState(1); const [searchTerm, setSearchTerm] = useState(''); const [isLoading, setIsLoading] = useState(false); const [activeTab, setActiveTab] = useState(CURRENT_YEAR_FILTER); const [totalCurrentYear, setTotalCurrentYear] = useState(0); const [totalNextYear, setTotalNextYear] = useState(0); const [totalHistorical, setTotalHistorical] = useState(0); const [itemsPerPage, setItemsPerPage] = useState(10); // Définir le nombre d'éléments par page const [student, setStudent] = useState(''); const [classes, setClasses] = useState([]); const [reloadFetch, setReloadFetch] = useState(false); const [isOpenAddGuardian, setIsOpenAddGuardian] = useState(false); const [isFilesModalOpen, setIsFilesModalOpen] = useState(false); const [selectedRegisterForm, setSelectedRegisterForm] = useState([]); const [confirmPopupVisible, setConfirmPopupVisible] = useState(false); const [confirmPopupMessage, setConfirmPopupMessage] = useState(''); const [confirmPopupOnConfirm, setConfirmPopupOnConfirm] = useState(() => {}); const [isSepaUploadModalOpen, setIsSepaUploadModalOpen] = useState(false); const [selectedRowForUpload, setSelectedRowForUpload] = useState(null); const csrfToken = useCsrfToken(); const router = useRouter(); const { selectedEstablishmentId } = useEstablishment(); const { showNotification } = useNotification(); const openSepaUploadModal = (row) => { setSelectedRowForUpload(row); setIsSepaUploadModalOpen(true); }; const closeSepaUploadModal = () => { setSelectedRowForUpload(null); setIsSepaUploadModalOpen(false); }; const openFilesModal = (row) => { setSelectedRegisterForm(row || []); setIsFilesModalOpen(true); }; const requestErrorHandler = (err) => { logger.error('Error fetching data:', err); }; /** * Handles the pending data for the registration form. * * @param {Object} data - The data object containing registration forms and count. * @param {Array} data.registerForms - The array of registration forms. * @param {number} data.count - The total count of registration forms. */ const registerFormCurrrentYearDataHandler = (data) => { if (data) { const { registerForms, count, page_size } = data; setRegistrationFormsDataCurrentYear(registerForms); const calculatedTotalPages = count === 0 ? count : Math.ceil(count / page_size); setTotalCurrentYear(count); setTotalCurrentSchoolYearPages(calculatedTotalPages); } }; /** * Handles the data received from the subscription registration form. * * @param {Object} data - The data object received from the subscription registration form. * @param {Array} data.registerForms - An array of registration forms. * @param {number} data.count - The total count of subscribed forms. */ const registerFormNextYearDataHandler = (data) => { if (data) { const { registerForms, count, page_size } = data; setRegistrationFormsDataNextYear(registerForms); const calculatedTotalPages = count === 0 ? count : Math.ceil(count / page_size); setTotalNextYear(count); setTotalNextSchoolYearPages(calculatedTotalPages); } }; /** * Handles the archived data for the register form. * * @param {Object} data - The data object containing archived register forms and count. * @param {Array} data.registerForms - The array of archived register forms. * @param {number} data.count - The total count of archived register forms. */ const registerFormHistoricalDataHandler = (data) => { if (data) { const { registerForms, count, page_size } = data; setRegistrationFormsDataHistorical(registerForms); const calculatedTotalPages = count === 0 ? count : Math.ceil(count / page_size); setTotalHistorical(count); setTotalHistoricalPages(calculatedTotalPages); } }; useEffect(() => { if (selectedEstablishmentId) { const fetchDataAndSetState = () => { setIsLoading(true); Promise.all([ fetchRegisterForms( selectedEstablishmentId, CURRENT_YEAR_FILTER, currentSchoolYearPage, itemsPerPage, searchTerm ) .then(registerFormCurrrentYearDataHandler) .catch(requestErrorHandler), fetchClasses(selectedEstablishmentId) .then((classesData) => { setClasses(classesData); }) .catch(requestErrorHandler), fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR_FILTER) .then(registerFormNextYearDataHandler) .catch(requestErrorHandler), fetchRegisterForms(selectedEstablishmentId, HISTORICAL_FILTER) .then(registerFormHistoricalDataHandler) .catch(requestErrorHandler), ]) .then(() => { setIsLoading(false); setReloadFetch(false); }) .catch((err) => { logger.error(err); setIsLoading(false); setReloadFetch(false); }); }; fetchDataAndSetState(); } }, [selectedEstablishmentId, reloadFetch]); useEffect(() => { if (selectedEstablishmentId) { const fetchDataAndSetState = () => { fetchRegisterForms( selectedEstablishmentId, CURRENT_YEAR_FILTER, currentSchoolYearPage, itemsPerPage, searchTerm ) .then(registerFormCurrrentYearDataHandler) .catch(requestErrorHandler); fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR_FILTER) .then(registerFormNextYearDataHandler) .catch(requestErrorHandler); fetchRegisterForms(selectedEstablishmentId, HISTORICAL_FILTER) .then(registerFormHistoricalDataHandler) .catch(requestErrorHandler); setReloadFetch(false); }; const timeoutId = setTimeout(() => { fetchDataAndSetState(); }, 500); // Debounce la recherche return () => clearTimeout(timeoutId); } }, [searchTerm, selectedEstablishmentId, currentSchoolYearPage, itemsPerPage]); /** * UseEffect to update page count of tab */ useEffect(() => { if (activeTab === CURRENT_YEAR_FILTER) { setTotalCurrentSchoolYearPages( Math.ceil(totalCurrentYear / itemsPerPage) ); } else if (activeTab === NEXT_YEAR_FILTER) { setTotalNextSchoolYearPages(Math.ceil(totalNextYear / itemsPerPage)); } else if (activeTab === HISTORICAL_FILTER) { setTotalHistoricalPages(Math.ceil(totalHistorical / itemsPerPage)); } }, [currentSchoolYearPage]); const handleSepaFileUpload = (file, row) => { if (!file || !row) { logger.error("Aucun fichier ou ligne sélectionnée pour l'upload."); return; } // Préparer les données JSON const jsonData = { status: 7, }; const formData = new FormData(); // Ajouter les données JSON sous forme de chaîne formData.append('data', JSON.stringify(jsonData)); formData.append('sepa_file', file); // Appeler l'API pour uploader le fichier SEPA editRegisterForm(row.student.id, formData, csrfToken) .then((response) => { logger.debug('Mandat SEPA uploadé avec succès :', response); showNotification( 'Le mandat SEPA a été uploadé avec succès.', 'success', 'Succès' ); setReloadFetch(true); closeSepaUploadModal(); }) .catch((error) => { logger.error("Erreur lors de l'upload du mandat SEPA :", error); showNotification( "Erreur lors de l'upload du mandat SEPA.", 'error', 'Erreur' ); }); }; /** * Archives a registration form after user confirmation. * * @param {number} id - The ID of the registration form to be archived. * @param {string} nom - The last name of the person whose registration form is being archived. * @param {string} prenom - The first name of the person whose registration form is being archived. */ const archiveFicheInscription = (id, nom, prenom) => { setConfirmPopupMessage( `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 ?` ); setConfirmPopupOnConfirm(() => () => { archiveRegisterForm(id) .then((data) => { logger.debug('Success:', data); showNotification( "Le dossier d'inscription a été correctement archivé", 'success', 'Succès' ); setRegistrationForms( registrationForms.filter((fiche) => fiche.id !== id) ); setReloadFetch(true); }) .catch((error) => { showNotification( "Erreur lors de l'archivage du dossier d'inscription", 'error', 'Erreur' ); }); setConfirmPopupVisible(false); }); setConfirmPopupVisible(true); }; const sendConfirmRegisterForm = (id, nom, prenom) => { setConfirmPopupMessage( `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 ?` ); setConfirmPopupOnConfirm(() => () => { sendRegisterForm(id) .then((data) => { logger.debug('Success:', data); showNotification( "Le dossier d'inscription a été envoyé avec succès", 'success', 'Succès' ); setReloadFetch(true); }) .catch((error) => { logger.error('Error archiving data:', error); showNotification( "Erreur lors de l'envoi du dossier d'inscription", 'error', 'Erreur' ); }); setConfirmPopupVisible(false); }); setConfirmPopupVisible(true); }; const updateStatusAction = (id, newStatus) => { logger.debug( `Mise à jour du statut du dossier d'inscription avec l'ID : ${id} vers le statut : ${newStatus}` ); }; const handleSearchChange = (event) => { setSearchTerm(event.target.value); }; const handlePageChange = (newPage) => { if (activeTab === CURRENT_YEAR_FILTER) { setCurrentSchoolYearPage(newPage); } else if (activeTab === NEXT_YEAR_FILTER) { setCurrentSchoolNextYearPage(newPage); } else if (activeTab === HISTORICAL_FILTER) { setCurrentSchoolHistoricalYearPage(newPage); } }; const getActionsByStatus = (row) => { const actions = { // Etat "A envoyer" : // - Editer le formulaire de création // - Envoyer le formulaire aux parents // - Archiver le dossier [RegistrationFormStatus.STATUS_TO_SEND]: [ { icon: ( ), onClick: () => router.push( `${FE_ADMIN_SUBSCRIPTIONS_CREATE_URL}?id=${row.student.id}&school_year=${activeTab}` ), }, { icon: ( ), onClick: () => sendConfirmRegisterForm( row.student.id, row.student.last_name, row.student.first_name ), }, ], // Etat "En attente" : // - Editer le formulaire de création // - Renvoyer le formulaire aux parents // - Archiver le dossier [RegistrationFormStatus.STATUS_PENDING]: [ { icon: ( ), onClick: () => router.push( `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&enabled=true` ), }, { icon: ( ), onClick: () => sendConfirmRegisterForm( row.student.id, row.student.last_name, row.student.first_name ), }, ], // Etat "Signé" : // - Editer le formulaire d'inscription // - Visualiser les documents signés par les parents // - Valider le dossier d'inscription // - Archiver le dossier [RegistrationFormStatus.STATUS_TO_VALIDATE]: [ { icon: ( ), onClick: () => router.push( `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&enabled=true` ), }, { icon: ( ), onClick: () => openFilesModal(row), }, { icon: ( ), onClick: () => { const url = `${FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL}?studentId=${row.student.id}&firstName=${row.student.first_name}&lastName=${row.student.last_name}&level=${row.student.level}&sepa_file=${row.sepa_file}&student_file=${row.registration_file}`; router.push(`${url}`); }, }, ], // Etat "A relancer" - NON TESTE [RegistrationFormStatus.STATUS_TO_FOLLOW_UP]: [ // To do... ], // Etat "Validé" : // - Editer le formulaire d'inscription // - Visualiser les documents signés par les parents // - A ajouter : Action pour éditer le suivi de l'élève // - Archiver le dossier [RegistrationFormStatus.STATUS_VALIDATED]: [ { icon: ( ), onClick: () => router.push( `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&enabled=true` ), }, { icon: ( ), onClick: () => openFilesModal(row), }, ], // Etat "Archivé" // - Editer le formulaire d'inscription en lecture seule [RegistrationFormStatus.STATUS_ARCHIVED]: [ { icon: ( ), onClick: () => router.push( `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&enabled=false` ), }, ], // Etat "En attente de signature de SEPA" : // - Editer le formulaire d'inscription // - Visualiser les documents signés par les parents // - Archiver le dossier [RegistrationFormStatus.STATUS_SEPA_PENDING]: [ { icon: ( ), onClick: () => router.push( `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&enabled=true` ), }, { icon: ( ), onClick: () => openFilesModal(row), }, ], // Etat "SEPA à envoyer" : // - Editer le formulaire d'inscription // - Visualiser les documents signés par les parents // - Envoyer le mandat SEPA aux parents // - Archiver le dossier [RegistrationFormStatus.STATUS_SEPA_TO_SEND]: [ { icon: ( ), onClick: () => router.push( `${FE_ADMIN_SUBSCRIPTIONS_EDIT_URL}?studentId=${row.student.id}&enabled=true` ), }, { icon: ( ), onClick: () => openFilesModal(row), }, { icon: ( ), onClick: () => openSepaUploadModal(row), }, ], default: [ { icon: ( ), onClick: () => archiveFicheInscription( row.student.id, row.student.last_name, row.student.first_name ), }, ], }; // Combine actions for the specific status and default actions return [ ...(actions[row.status] || []), ...(row.status !== 6 ? actions.default : []), ]; }; const columns = [ { name: t('photo'), transform: (row) => (
{row.student.photo ? ( {`${row.student.first_name} ) : (
{row.student.first_name[0]} {row.student.last_name[0]}
)}
), }, { name: t('studentName'), transform: (row) => row.student.last_name }, { name: t('studentFistName'), transform: (row) => row.student.first_name }, { name: t('mainContactMail'), transform: (row) => row.student.guardians && row.student.guardians.length > 0 && row.student.guardians[0].associated_profile_email, }, { name: t('phone'), transform: (row) => row.student.guardians[0]?.phone ? ( ) : null, // N'affiche rien si le numéro de téléphone est absent }, { name: t('lastUpdateDate'), transform: (row) => row.formatted_last_update, }, { name: t('registrationFileStatus'), transform: (row) => (
updateStatusAction(row.student.id, newStatus) } showDropdown={false} />
), }, { name: 'Actions', transform: (row) => (
{getActionsByStatus(row).map((action, index) => ( ))}
), }, ]; let emptyMessage; if (activeTab === CURRENT_YEAR_FILTER && searchTerm === '') { emptyMessage = ( ); } else if (activeTab === NEXT_YEAR_FILTER && searchTerm === '') { emptyMessage = ( ); } else if (activeTab === HISTORICAL_FILTER && searchTerm === '') { emptyMessage = ( ); } if (isLoading) { return ; } return (
{/* Tab pour l'année scolaire en cours */} {currentSchoolYear} ({totalCurrentYear}) } active={activeTab === CURRENT_YEAR_FILTER} onClick={() => setActiveTab(CURRENT_YEAR_FILTER)} /> {/* Tab pour l'année scolaire prochaine */} {nextSchoolYear} ({totalNextYear}) } active={activeTab === NEXT_YEAR_FILTER} onClick={() => setActiveTab(NEXT_YEAR_FILTER)} /> {/* Tab pour l'historique */} {t('historical')} ({totalHistorical}) } active={activeTab === HISTORICAL_FILTER} onClick={() => setActiveTab(HISTORICAL_FILTER)} />
{activeTab === CURRENT_YEAR_FILTER || activeTab === NEXT_YEAR_FILTER || activeTab === HISTORICAL_FILTER ? (
) : null} setConfirmPopupVisible(false)} /> {isSepaUploadModalOpen && ( handleSepaFileUpload(file, selectedRowForUpload) } /> )} {isFilesModalOpen && ( )} ); }