mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
feat: Ajout d'un nouvel état dans l'automatique lorsqu'un mandat SEPA
doit être envoyé aux parent
This commit is contained in:
@ -7,6 +7,7 @@ import { useCsrfToken } from '@/context/CsrfContext';
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
import { editRegisterForm } from '@/app/actions/subscriptionAction';
|
||||
import logger from '@/utils/logger';
|
||||
import Loader from '@/components/Loader';
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter();
|
||||
@ -16,14 +17,18 @@ export default function Page() {
|
||||
const [formErrors, setFormErrors] = useState({});
|
||||
const csrfToken = useCsrfToken();
|
||||
const { selectedEstablishmentId } = useEstablishment();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleSubmit = (data) => {
|
||||
setIsLoading(true);
|
||||
editRegisterForm(studentId, data, csrfToken)
|
||||
.then((result) => {
|
||||
setIsLoading(false);
|
||||
logger.debug('Success:', result);
|
||||
router.push(FE_ADMIN_SUBSCRIPTIONS_URL);
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsLoading(false);
|
||||
logger.error('Error:', error.message);
|
||||
if (error.details) {
|
||||
logger.error('Form errors:', error.details);
|
||||
@ -32,6 +37,10 @@ export default function Page() {
|
||||
});
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<InscriptionFormShared
|
||||
studentId={studentId}
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
FileText,
|
||||
CheckCircle,
|
||||
Plus,
|
||||
XCircle,
|
||||
Upload,
|
||||
} from 'lucide-react';
|
||||
import Modal from '@/components/Modal';
|
||||
import InscriptionForm from '@/components/Inscription/InscriptionForm';
|
||||
@ -35,6 +35,7 @@ import {
|
||||
archiveRegisterForm,
|
||||
fetchStudents,
|
||||
editRegisterForm,
|
||||
sendSEPARegisterForm,
|
||||
} from '@/app/actions/subscriptionAction';
|
||||
|
||||
import {
|
||||
@ -66,6 +67,7 @@ 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';
|
||||
|
||||
export default function Page({ params: { locale } }) {
|
||||
const t = useTranslations('subscriptions');
|
||||
@ -80,11 +82,6 @@ export default function Page({ params: { locale } }) {
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [alertPage, setAlertPage] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [popup, setPopup] = useState({
|
||||
visible: false,
|
||||
message: '',
|
||||
onConfirm: null,
|
||||
});
|
||||
const [activeTab, setActiveTab] = useState('pending');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
@ -113,10 +110,29 @@ export default function Page({ params: { locale } }) {
|
||||
const [isFilesModalOpen, setIsFilesModalOpen] = useState(false);
|
||||
const [selectedRowFiles, setSelectedRowFiles] = useState([]);
|
||||
|
||||
const [popupVisible, setPopupVisible] = useState(false);
|
||||
const [popupMessage, setPopupMessage] = 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 openSepaUploadModal = (row) => {
|
||||
setSelectedRowForUpload(row);
|
||||
setIsSepaUploadModalOpen(true);
|
||||
};
|
||||
|
||||
const closeSepaUploadModal = () => {
|
||||
setSelectedRowForUpload(null);
|
||||
setIsSepaUploadModalOpen(false);
|
||||
};
|
||||
|
||||
const openModal = () => {
|
||||
setIsOpen(true);
|
||||
};
|
||||
@ -221,28 +237,6 @@ export default function Page({ params: { locale } }) {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEstablishmentId) {
|
||||
const fetchInitialData = () => {
|
||||
Promise.all([
|
||||
fetchClasses(selectedEstablishmentId),
|
||||
fetchStudents(selectedEstablishmentId),
|
||||
])
|
||||
.then(([classesData, studentsData]) => {
|
||||
setClasses(classesData);
|
||||
setEleves(studentsData);
|
||||
logger.debug('Success - Classes:', classesData);
|
||||
logger.debug('Success - Students:', studentsData);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error fetching initial data:', error);
|
||||
});
|
||||
};
|
||||
|
||||
fetchInitialData();
|
||||
}
|
||||
}, [selectedEstablishmentId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedEstablishmentId) {
|
||||
const fetchDataAndSetState = () => {
|
||||
@ -257,6 +251,19 @@ export default function Page({ params: { locale } }) {
|
||||
)
|
||||
.then(registerFormPendingDataHandler)
|
||||
.catch(requestErrorHandler),
|
||||
|
||||
fetchClasses(selectedEstablishmentId)
|
||||
.then((classesData) => {
|
||||
setClasses(classesData);
|
||||
})
|
||||
.catch(requestErrorHandler),
|
||||
|
||||
fetchStudents(selectedEstablishmentId)
|
||||
.then((studentsData) => {
|
||||
setEleves(studentsData);
|
||||
})
|
||||
.catch(requestErrorHandler),
|
||||
|
||||
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
|
||||
.then(registerFormSubscribedDataHandler)
|
||||
.catch(requestErrorHandler),
|
||||
@ -378,6 +385,33 @@ export default function Page({ params: { locale } }) {
|
||||
setTotalPages(Math.ceil(totalArchives / itemsPerPage));
|
||||
}
|
||||
}, [currentPage]);
|
||||
|
||||
const handleSepaFileUpload = (file, row) => {
|
||||
if (!file || !row) {
|
||||
logger.error("Aucun fichier ou ligne sélectionnée pour l'upload.");
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('status', 7);
|
||||
formData.append('sepa_file', file);
|
||||
|
||||
// Appeler l'API pour uploader le fichier SEPA
|
||||
sendSEPARegisterForm(row.student.id, formData, csrfToken)
|
||||
.then((response) => {
|
||||
logger.debug('Mandat SEPA uploadé avec succès :', response);
|
||||
setPopupMessage('Le mandat SEPA a été uploadé avec succès.');
|
||||
setPopupVisible(true);
|
||||
setReloadFetch(true);
|
||||
closeSepaUploadModal();
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error("Erreur lors de l'upload du mandat SEPA :", error);
|
||||
setPopupMessage("Erreur lors de l'upload du mandat SEPA.");
|
||||
setPopupVisible(true);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Archives a registration form after user confirmation.
|
||||
*
|
||||
@ -386,44 +420,56 @@ export default function Page({ params: { locale } }) {
|
||||
* @param {string} prenom - The first name of the person whose registration form is being archived.
|
||||
*/
|
||||
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: () => {
|
||||
archiveRegisterForm(id)
|
||||
.then((data) => {
|
||||
logger.debug('Success:', data);
|
||||
setRegistrationForms(
|
||||
registrationForms.filter((fiche) => fiche.id !== id)
|
||||
);
|
||||
setReloadFetch(true);
|
||||
alert("Le dossier d'inscription a été correctement archivé");
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error archiving data:', error);
|
||||
alert(
|
||||
"Erreur lors de l'archivage du dossier d'inscription.\nContactez l'administrateur."
|
||||
);
|
||||
});
|
||||
},
|
||||
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);
|
||||
setPopupMessage(
|
||||
`Le dossier d'inscription a été correctement archivé`
|
||||
);
|
||||
setPopupVisible(true);
|
||||
setRegistrationForms(
|
||||
registrationForms.filter((fiche) => fiche.id !== id)
|
||||
);
|
||||
setReloadFetch(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error archiving data:', error);
|
||||
setPopupMessage(
|
||||
`Erreur lors de l'archivage du dossier d'inscription.\nContactez l'administrateur.`
|
||||
);
|
||||
setPopupVisible(true);
|
||||
});
|
||||
setConfirmPopupVisible(false);
|
||||
});
|
||||
setConfirmPopupVisible(true);
|
||||
};
|
||||
|
||||
const sendConfirmRegisterForm = (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: () => {
|
||||
sendRegisterForm(id)
|
||||
.then((data) => {
|
||||
logger.debug('Success:', data);
|
||||
setReloadFetch(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error fetching data:', error);
|
||||
});
|
||||
},
|
||||
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);
|
||||
setPopupMessage(`Le dossier d'inscription a été envoyé avec succès`);
|
||||
setPopupVisible(true);
|
||||
setReloadFetch(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error archiving data:', error);
|
||||
setPopupMessage(
|
||||
`Erreur lors de l'envoi du dossier d'inscription.\nContactez l'administrateur.`
|
||||
);
|
||||
setPopupVisible(true);
|
||||
});
|
||||
setConfirmPopupVisible(false);
|
||||
});
|
||||
setConfirmPopupVisible(true);
|
||||
};
|
||||
|
||||
const affectationClassFormSubmitHandler = (formdata) => {
|
||||
@ -437,25 +483,6 @@ export default function Page({ params: { locale } }) {
|
||||
});
|
||||
};
|
||||
|
||||
const refuseRegistrationForm = (id, lastname, firstname, guardianEmail) => {
|
||||
const data = { status: 2, establishment: selectedEstablishmentId };
|
||||
|
||||
setPopup({
|
||||
visible: true,
|
||||
message: `Avertissement ! \nVous êtes sur le point de refuser le dossier d'inscription de ${lastname} ${firstname}\nUne notification va être envoyée à l'adresse ${guardianEmail}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`,
|
||||
onConfirm: () => {
|
||||
editRegisterForm(id, data, csrfToken)
|
||||
.then((data) => {
|
||||
logger.debug('Success:', data);
|
||||
setReloadFetch(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Error refusing RF:', error);
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const updateStatusAction = (id, newStatus) => {
|
||||
logger.debug(
|
||||
`Mise à jour du statut du dossier d'inscription avec l'ID : ${id} vers le statut : ${newStatus}`
|
||||
@ -551,6 +578,7 @@ export default function Page({ params: { locale } }) {
|
||||
establishment: selectedEstablishmentId,
|
||||
};
|
||||
|
||||
setIsLoading(true);
|
||||
createRegisterForm(data, csrfToken)
|
||||
.then((data) => {
|
||||
// Cloner les schoolFileTemplates pour chaque templateMaster du fileGroup
|
||||
@ -582,6 +610,7 @@ export default function Page({ params: { locale } }) {
|
||||
logger.debug('Template enregistré avec succès:', response);
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsLoading(false);
|
||||
logger.error(
|
||||
"Erreur lors de l'enregistrement du template:",
|
||||
error
|
||||
@ -589,6 +618,7 @@ export default function Page({ params: { locale } }) {
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsLoading(false);
|
||||
logger.error('Error during cloning or sending:', error);
|
||||
});
|
||||
});
|
||||
@ -608,6 +638,7 @@ export default function Page({ params: { locale } }) {
|
||||
logger.debug('Parent template enregistré avec succès:', response);
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsLoading(false);
|
||||
logger.error(
|
||||
"Erreur lors de l'enregistrement du parent template:",
|
||||
error
|
||||
@ -634,12 +665,15 @@ export default function Page({ params: { locale } }) {
|
||||
closeModal(); // Appeler closeModal ici après que tout soit terminé
|
||||
// Forcer le rechargement complet des données
|
||||
setReloadFetch(true);
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsLoading(false);
|
||||
logger.error('Error during cloning or sending:', error);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsLoading(false);
|
||||
logger.error('Error:', error);
|
||||
});
|
||||
};
|
||||
@ -810,6 +844,24 @@ export default function Page({ params: { locale } }) {
|
||||
onClick: () => openFilesModal(row),
|
||||
},
|
||||
],
|
||||
8: [
|
||||
{
|
||||
icon: (
|
||||
<span title="Voir les fichiers">
|
||||
<FileText className="w-5 h-5 text-cyan-500 hover:text-cyan-700" />
|
||||
</span>
|
||||
),
|
||||
onClick: () => openFilesModal(row),
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
<span title="Uploader un mandat SEPA">
|
||||
<Upload className="w-5 h-5 text-emerald-500 hover:text-emerald-700" />
|
||||
</span>
|
||||
),
|
||||
onClick: () => openSepaUploadModal(row),
|
||||
},
|
||||
],
|
||||
default: [
|
||||
{
|
||||
icon: (
|
||||
@ -879,37 +931,6 @@ export default function Page({ params: { locale } }) {
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: t('files'),
|
||||
transform: (row) => (
|
||||
<ul>
|
||||
{row.registration_file && (
|
||||
<li className="flex justify-center items-center gap-2">
|
||||
<FileText size={16} />
|
||||
<a
|
||||
href={`${BASE_URL}${row.registration_file}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{row.registration_file?.split('/').pop()}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{row.sepa_file && (
|
||||
<li className="flex justify-center items-center gap-2">
|
||||
<FileText size={16} />
|
||||
<a
|
||||
href={`${BASE_URL}${row.sepa_file}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{row.sepa_file?.split('/').pop()}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Actions',
|
||||
transform: (row) => (
|
||||
@ -1116,13 +1137,16 @@ export default function Page({ params: { locale } }) {
|
||||
) : null}
|
||||
</div>
|
||||
<Popup
|
||||
visible={popup.visible}
|
||||
message={popup.message}
|
||||
onConfirm={() => {
|
||||
popup.onConfirm();
|
||||
setPopup({ ...popup, visible: false });
|
||||
}}
|
||||
onCancel={() => setPopup({ ...popup, visible: false })}
|
||||
visible={popupVisible}
|
||||
message={popupMessage}
|
||||
onConfirm={() => setPopupVisible(false)}
|
||||
uniqueConfirmButton={true}
|
||||
/>
|
||||
<Popup
|
||||
visible={confirmPopupVisible}
|
||||
message={confirmPopupMessage}
|
||||
onConfirm={confirmPopupOnConfirm}
|
||||
onCancel={() => setConfirmPopupVisible(false)}
|
||||
/>
|
||||
|
||||
{isOpen && (
|
||||
@ -1176,6 +1200,21 @@ export default function Page({ params: { locale } }) {
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isSepaUploadModalOpen && (
|
||||
<Modal
|
||||
isOpen={isSepaUploadModalOpen}
|
||||
setIsOpen={setIsSepaUploadModalOpen}
|
||||
title="Uploader un mandat SEPA"
|
||||
ContentComponent={() => (
|
||||
<FileUpload
|
||||
selectionMessage="Sélectionnez un mandat SEPA à uploader"
|
||||
onFileSelect={(file) =>
|
||||
handleSepaFileUpload(file, selectedRowForUpload)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isFilesModalOpen && (
|
||||
<Modal
|
||||
isOpen={isFilesModalOpen}
|
||||
|
||||
@ -24,15 +24,16 @@ export default function ParentHomePage() {
|
||||
const [uploadState, setUploadState] = useState('off'); // État "on" ou "off" pour l'affichage du composant
|
||||
const router = useRouter();
|
||||
const csrfToken = useCsrfToken();
|
||||
const [reloadFetch, setReloadFetch] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const userIdFromSession = user.user_id;
|
||||
setUserId(userIdFromSession);
|
||||
console.log(selectedEstablishmentId);
|
||||
fetchChildren(userIdFromSession, selectedEstablishmentId).then((data) => {
|
||||
setChildren(data);
|
||||
});
|
||||
}, [selectedEstablishmentId]);
|
||||
setReloadFetch(false);
|
||||
}, [selectedEstablishmentId, reloadFetch]);
|
||||
|
||||
function handleView(eleveId) {
|
||||
logger.debug(`View dossier for student id: ${eleveId}`);
|
||||
@ -70,7 +71,8 @@ export default function ParentHomePage() {
|
||||
sendSEPARegisterForm(uploadingStudentId, formData, csrfToken)
|
||||
.then((response) => {
|
||||
logger.debug('RF mis à jour avec succès:', response);
|
||||
// Logique supplémentaire après la mise à jour (par exemple, redirection ou notification)
|
||||
setReloadFetch(true);
|
||||
setUploadState('off');
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error('Erreur lors de la mise à jour du RF:', error);
|
||||
@ -118,7 +120,7 @@ export default function ParentHomePage() {
|
||||
</button>
|
||||
)}
|
||||
|
||||
{row.status === 3 && (
|
||||
{(row.status === 3 || row.status === 8) && (
|
||||
<button
|
||||
className="text-purple-500 hover:text-purple-700"
|
||||
onClick={(e) => {
|
||||
|
||||
Reference in New Issue
Block a user