feat: Formulaire de création RF sur une seule pag

This commit is contained in:
N3WT DE COMPET
2025-05-05 20:57:51 +02:00
parent 2a6b3bdf63
commit 76f9a7dd14
19 changed files with 1299 additions and 422 deletions

File diff suppressed because it is too large Load Diff

View File

@ -25,40 +25,24 @@ import InscriptionForm from '@/components/Inscription/InscriptionForm';
import { useEstablishment } from '@/context/EstablishmentContext';
import {
PENDING,
SUBSCRIBED,
ARCHIVED,
CURRENT_YEAR,
NEXT_YEAR,
HISTORICAL,
fetchRegisterForms,
createRegisterForm,
sendRegisterForm,
archiveRegisterForm,
fetchStudents,
editRegisterForm,
editRegisterFormWithBinaryFile,
} from '@/app/actions/subscriptionAction';
import {
fetchRegistrationSchoolFileMasters,
fetchRegistrationParentFileMasters,
createRegistrationSchoolFileTemplate,
createRegistrationParentFileTemplate,
fetchRegistrationFileGroups,
cloneTemplate,
} from '@/app/actions/registerFileGroupAction';
import {
fetchClasses,
fetchRegistrationDiscounts,
fetchTuitionDiscounts,
fetchRegistrationFees,
fetchTuitionFees,
} from '@/app/actions/schoolAction';
import { fetchClasses, updateDatas } from '@/app/actions/schoolAction';
import { fetchProfiles } from '@/app/actions/authAction';
import {
FE_ADMIN_SUBSCRIPTIONS_EDIT_URL,
FE_ADMIN_SUBSCRIPTIONS_VALIDATE_URL,
FE_ADMIN_SUBSCRIPTIONS_CREATE_URL,
BASE_URL,
} from '@/utils/Url';
@ -68,41 +52,41 @@ import logger from '@/utils/logger';
import { PhoneLabel } from '@/components/PhoneLabel';
import FileUpload from '@/components/FileUpload';
import FilesModal from '@/components/Inscription/FilesModal';
import {
getCurrentSchoolYear,
getNextSchoolYear,
getHistoricalYears,
} from '@/utils/Date';
export default function Page({ params: { locale } }) {
const t = useTranslations('subscriptions');
const [registrationForms, setRegistrationForms] = useState([]);
const [registrationFormsDataPending, setRegistrationFormsDataPending] =
const [
registrationFormsDataCurrentYear,
setRegistrationFormsDataCurrentYear,
] = useState([]);
const [registrationFormsDataNextYear, setRegistrationFormsDataNextYear] =
useState([]);
const [registrationFormsDataSubscribed, setRegistrationFormsDataSubscribed] =
const [registrationFormsDataHistorical, setRegistrationFormsDataHistorical] =
useState([]);
const [registrationFormsDataArchived, setRegistrationFormsDataArchived] =
useState([]);
// const [filter, setFilter] = useState('*');
const currentSchoolYear = getCurrentSchoolYear(); // Exemple : "2024-2025"
const nextSchoolYear = getNextSchoolYear(); // Exemple : "2025-2026"
const historicalYears = getHistoricalYears();
const [searchTerm, setSearchTerm] = useState('');
const [alertPage, setAlertPage] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [activeTab, setActiveTab] = useState('pending');
const [activeTab, setActiveTab] = useState('currentYear');
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 [totalCurrentYear, setTotalCurrentYear] = useState(0);
const [totalSubscribed, setTotalNextYear] = useState(0);
const [totalHistorical, setTotalHistorical] = useState(0);
const [itemsPerPage, setItemsPerPage] = useState(10); // Définir le nombre d'éléments par page
const [schoolFileMasters, setSchoolFileMasters] = useState([]);
const [parentFileMasters, setParentFileMasters] = useState([]);
const [isOpen, setIsOpen] = useState(false);
const [student, setStudent] = useState('');
const [classes, setClasses] = useState([]);
const [students, setEleves] = useState([]);
const [reloadFetch, setReloadFetch] = useState(false);
const [registrationDiscounts, setRegistrationDiscounts] = useState([]);
const [tuitionDiscounts, setTuitionDiscounts] = useState([]);
const [registrationFees, setRegistrationFees] = useState([]);
const [tuitionFees, setTuitionFees] = useState([]);
const [groups, setGroups] = useState([]);
const [profiles, setProfiles] = useState([]);
const [isOpenAddGuardian, setIsOpenAddGuardian] = useState(false);
@ -132,14 +116,6 @@ export default function Page({ params: { locale } }) {
setIsSepaUploadModalOpen(false);
};
const openModal = () => {
setIsOpen(true);
};
const closeModal = () => {
setIsOpen(false);
};
const openFilesModal = (row) => {
setSelectedRegisterForm(row || []);
setIsFilesModalOpen(true);
@ -160,11 +136,11 @@ export default function Page({ params: { locale } }) {
if (data) {
const { registerForms, count, page_size } = data;
if (registerForms) {
setRegistrationFormsDataPending(registerForms);
setRegistrationFormsDataCurrentYear(registerForms);
}
const calculatedTotalPages =
count === 0 ? 1 : Math.ceil(count / page_size);
setTotalPending(count);
setTotalCurrentYear(count);
setTotalPages(calculatedTotalPages);
}
};
@ -179,9 +155,9 @@ export default function Page({ params: { locale } }) {
const registerFormSubscribedDataHandler = (data) => {
if (data) {
const { registerForms, count, page_size } = data;
setTotalSubscribed(count);
setTotalNextYear(count);
if (registerForms) {
setRegistrationFormsDataSubscribed(registerForms);
setRegistrationFormsDataNextYear(registerForms);
}
}
};
@ -197,9 +173,9 @@ export default function Page({ params: { locale } }) {
if (data) {
const { registerForms, count, page_size } = data;
setTotalArchives(count);
setTotalHistorical(count);
if (registerForms) {
setRegistrationFormsDataArchived(registerForms);
setRegistrationFormsDataHistorical(registerForms);
}
}
};
@ -211,7 +187,7 @@ export default function Page({ params: { locale } }) {
Promise.all([
fetchRegisterForms(
selectedEstablishmentId,
PENDING,
CURRENT_YEAR,
currentPage,
itemsPerPage,
searchTerm
@ -225,59 +201,12 @@ export default function Page({ params: { locale } }) {
})
.catch(requestErrorHandler),
fetchStudents(selectedEstablishmentId)
.then((studentsData) => {
setEleves(studentsData);
})
.catch(requestErrorHandler),
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR)
.then(registerFormSubscribedDataHandler)
.catch(requestErrorHandler),
fetchRegisterForms(selectedEstablishmentId, ARCHIVED)
fetchRegisterForms(selectedEstablishmentId, HISTORICAL)
.then(registerFormArchivedDataHandler)
.catch(requestErrorHandler),
fetchRegistrationSchoolFileMasters()
.then((data) => {
setSchoolFileMasters(data);
})
.catch((err) => {
logger.debug(err.message);
}),
fetchRegistrationParentFileMasters()
.then((data) => {
setParentFileMasters(data);
})
.catch((err) => {
logger.debug(err.message);
}),
fetchRegistrationDiscounts(selectedEstablishmentId)
.then((data) => {
setRegistrationDiscounts(data);
})
.catch(requestErrorHandler),
fetchTuitionDiscounts(selectedEstablishmentId)
.then((data) => {
setTuitionDiscounts(data);
})
.catch(requestErrorHandler),
fetchRegistrationFees(selectedEstablishmentId)
.then((data) => {
setRegistrationFees(data);
})
.catch(requestErrorHandler),
fetchTuitionFees(selectedEstablishmentId)
.then((data) => {
setTuitionFees(data);
})
.catch(requestErrorHandler),
fetchRegistrationFileGroups(selectedEstablishmentId)
.then((data) => {
setGroups(data);
})
.catch((error) => {
logger.error('Error fetching file groups:', error);
}),
fetchProfiles()
.then((data) => {
setProfiles(data);
@ -307,27 +236,19 @@ export default function Page({ params: { locale } }) {
setIsLoading(true);
fetchRegisterForms(
selectedEstablishmentId,
PENDING,
CURRENT_YEAR,
currentPage,
itemsPerPage,
searchTerm
)
.then(registerFormPendingDataHandler)
.catch(requestErrorHandler);
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
fetchRegisterForms(selectedEstablishmentId, NEXT_YEAR)
.then(registerFormSubscribedDataHandler)
.catch(requestErrorHandler);
fetchRegisterForms(selectedEstablishmentId, ARCHIVED)
fetchRegisterForms(selectedEstablishmentId, HISTORICAL)
.then(registerFormArchivedDataHandler)
.catch(requestErrorHandler);
fetchRegistrationSchoolFileMasters()
.then((data) => {
setSchoolFileMasters(data);
})
.catch((err) => {
err = err.message;
logger.debug(err);
});
setIsLoading(false);
setReloadFetch(false);
@ -344,12 +265,12 @@ export default function Page({ params: { locale } }) {
* UseEffect to update page count of tab
*/
useEffect(() => {
if (activeTab === 'pending') {
setTotalPages(Math.ceil(totalPending / itemsPerPage));
} else if (activeTab === 'subscribed') {
if (activeTab === 'currentYear') {
setTotalPages(Math.ceil(totalCurrentYear / itemsPerPage));
} else if (activeTab === 'nextYear') {
setTotalPages(Math.ceil(totalSubscribed / itemsPerPage));
} else if (activeTab === 'archived') {
setTotalPages(Math.ceil(totalArchives / itemsPerPage));
} else if (activeTab === 'historical') {
setTotalPages(Math.ceil(totalHistorical / itemsPerPage));
}
}, [currentPage]);
@ -460,187 +381,6 @@ export default function Page({ params: { locale } }) {
setCurrentPage(newPage);
};
const createRF = (updatedData) => {
logger.debug('createRF updatedData:', updatedData);
const selectedRegistrationFeesIds =
updatedData.selectedRegistrationFees.map((feeId) => feeId);
const selectedRegistrationDiscountsIds =
updatedData.selectedRegistrationDiscounts.map((discountId) => discountId);
const selectedTuitionFeesIds = updatedData.selectedTuitionFees.map(
(feeId) => feeId
);
const selectedTuitionDiscountsIds =
updatedData.selectedTuitionDiscounts.map((discountId) => discountId);
const selectedFileGroup = updatedData.selectedFileGroup;
const allFeesIds = [
...selectedRegistrationFeesIds,
...selectedTuitionFeesIds,
];
const allDiscountsds = [
...selectedRegistrationDiscountsIds,
...selectedTuitionDiscountsIds,
];
const data = {
student: {
last_name: updatedData.studentLastName,
first_name: updatedData.studentFirstName,
guardians:
updatedData.selectedGuardians.length !== 0
? updatedData.selectedGuardians.map((guardianId) => ({
id: guardianId,
}))
: (() => {
if (updatedData.isExistingParentProfile) {
return [
{
profile_role_data: {
establishment: selectedEstablishmentId,
role_type: 2,
is_active: false,
profile: updatedData.existingProfileId, // Associer au profil existant
},
last_name: updatedData.guardianLastName,
first_name: updatedData.guardianFirstName,
birth_date: updatedData.guardianBirthDate,
address: updatedData.guardianAddress,
phone: updatedData.guardianPhone,
profession: updatedData.guardianProfession,
},
];
}
// Si aucun profil existant n'est trouvé, créer un nouveau profil
return [
{
profile_role_data: {
establishment: selectedEstablishmentId,
role_type: 2,
is_active: false,
profile_data: {
email: updatedData.guardianEmail,
password: 'Provisoire01!',
username: updatedData.guardianEmail,
},
},
last_name: updatedData.guardianLastName,
first_name: updatedData.guardianFirstName,
birth_date: updatedData.guardianBirthDate,
address: updatedData.guardianAddress,
phone: updatedData.guardianPhone,
profession: updatedData.guardianProfession,
},
];
})(),
sibling: [],
},
fees: allFeesIds,
discounts: allDiscountsds,
fileGroup: selectedFileGroup,
establishment: selectedEstablishmentId,
};
setIsLoading(true);
createRegisterForm(data, csrfToken)
.then((data) => {
// Cloner les schoolFileTemplates pour chaque templateMaster du fileGroup
const masters = schoolFileMasters.filter((file) =>
file.groups.includes(selectedFileGroup)
);
const parent_masters = parentFileMasters.filter((file) =>
file.groups.includes(selectedFileGroup)
);
const clonePromises = masters.map((templateMaster) => {
return cloneTemplate(
templateMaster.id,
updatedData.guardianEmail,
templateMaster.is_required
)
.then((clonedDocument) => {
// Sauvegarde des schoolFileTemplates clonés dans la base de données
const cloneData = {
name: `${templateMaster.name}_${updatedData.studentFirstName}_${updatedData.studentLastName}`,
slug: clonedDocument.slug,
id: clonedDocument.id,
master: templateMaster.id,
registration_form: data.student.id,
};
return createRegistrationSchoolFileTemplate(cloneData, csrfToken)
.then((response) => {
logger.debug('Template enregistré avec succès:', response);
})
.catch((error) => {
setIsLoading(false);
logger.error(
"Erreur lors de l'enregistrement du template:",
error
);
});
})
.catch((error) => {
setIsLoading(false);
logger.error('Error during cloning or sending:', error);
});
});
// Créer les parentFileTemplates pour chaque parentMaster
const parentClonePromises = parent_masters.map((parentMaster) => {
const parentTemplateData = {
master: parentMaster.id,
registration_form: data.student.id,
};
return createRegistrationParentFileTemplate(
parentTemplateData,
csrfToken
)
.then((response) => {
logger.debug('Parent template enregistré avec succès:', response);
})
.catch((error) => {
setIsLoading(false);
logger.error(
"Erreur lors de l'enregistrement du parent template:",
error
);
});
});
// Attendre que tous les clones (school et parent) soient créés
Promise.all([...clonePromises, ...parentClonePromises])
.then(() => {
// Mise à jour immédiate des données
setRegistrationFormsDataPending((prevState) => [
...(prevState || []),
data,
]);
setTotalPending((prev) => prev + 1);
if (updatedData.autoMail) {
sendConfirmRegisterForm(
data.student.id,
updatedData.studentLastName,
updatedData.studentFirstName
);
}
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);
});
};
const updateRF = (updatedData) => {
logger.debug('updateRF updatedData:', updatedData);
@ -700,11 +440,11 @@ export default function Page({ params: { locale } }) {
editRegisterForm(student.id, data, csrfToken)
.then((data) => {
// Mise à jour immédiate des données
setRegistrationFormsDataPending((prevState) => [
setRegistrationFormsDataCurrentYear((prevState) => [
...(prevState || []),
data,
]);
setTotalPending((prev) => prev + 1);
setTotalCurrentYear((prev) => prev + 1);
if (updatedData.autoMail) {
sendConfirmRegisterForm(
data.student.id,
@ -980,7 +720,7 @@ export default function Page({ params: { locale } }) {
} else {
if (
registrationForms.length === 0 &&
registrationFormsDataArchived.length === 0 &&
registrationFormsDataHistorical.length === 0 &&
alertPage
) {
return (
@ -997,49 +737,54 @@ export default function Page({ params: { locale } }) {
<div className="p-8">
<div className="border-b border-gray-200 mb-6">
<div className="flex items-center gap-8">
{/* Tab pour l'année scolaire en cours */}
<Tab
text={
<>
{t('pending')}
{currentSchoolYear}
<span className="ml-2 text-sm text-gray-400">
({totalPending})
({totalCurrentYear})
</span>
</>
}
active={activeTab === 'pending'}
onClick={() => setActiveTab('pending')}
active={activeTab === 'currentYear'}
onClick={() => setActiveTab('currentYear')}
/>
{/* Tab pour l'année scolaire prochaine */}
<Tab
text={
<>
{t('subscribed')}
{nextSchoolYear}
<span className="ml-2 text-sm text-gray-400">
({totalSubscribed})
</span>
</>
}
active={activeTab === 'subscribed'}
onClick={() => setActiveTab('subscribed')}
active={activeTab === 'nextYear'}
onClick={() => setActiveTab('nextYear')}
/>
{/* Tab pour l'historique */}
<Tab
text={
<>
{t('archived')}
{t('historical')}
<span className="ml-2 text-sm text-gray-400">
({totalArchives})
({totalHistorical})
</span>
</>
}
active={activeTab === 'archived'}
onClick={() => setActiveTab('archived')}
active={activeTab === 'historical'}
onClick={() => setActiveTab('historical')}
/>
</div>
</div>
<div className="border-b border-gray-200 mb-6 w-full">
{/*SI STATE == pending || subscribe || archived */}
{activeTab === 'pending' ||
activeTab === 'subscribed' ||
activeTab === 'archived' ? (
{activeTab === 'currentYear' ||
activeTab === 'nextYear' ||
activeTab === 'historical' ? (
<React.Fragment>
<div className="flex justify-between items-center mb-4 w-full">
<div className="relative flex-grow">
@ -1056,7 +801,10 @@ export default function Page({ params: { locale } }) {
/>
</div>
<button
onClick={openModal}
onClick={() => {
const url = `${FE_ADMIN_SUBSCRIPTIONS_CREATE_URL}`;
router.push(url);
}}
className="flex items-center bg-emerald-600 text-white p-2 rounded-full shadow hover:bg-emerald-900 transition duration-200 ml-4"
>
<Plus className="w-5 h-5" />
@ -1068,18 +816,13 @@ export default function Page({ params: { locale } }) {
<Table
key={`${currentPage}-${searchTerm}`}
data={
activeTab === 'pending'
? [
...registrationFormsDataPending,
...registrationFormsDataSubscribed,
]
: activeTab === 'subscribed'
? registrationFormsDataSubscribed
: registrationFormsDataArchived
}
columns={
activeTab === 'subscribed' ? columnsSubscribed : columns
activeTab === 'currentYear'
? registrationFormsDataCurrentYear
: activeTab === 'nextYear'
? registrationFormsDataNextYear
: registrationFormsDataHistorical
}
columns={columns}
itemsPerPage={itemsPerPage}
currentPage={currentPage}
totalPages={totalPages}
@ -1102,27 +845,6 @@ export default function Page({ params: { locale } }) {
onCancel={() => setConfirmPopupVisible(false)}
/>
{isOpen && (
<Modal
isOpen={isOpen}
setIsOpen={setIsOpen}
title={"Nouveau dossier d'inscription"}
ContentComponent={() => (
<InscriptionForm
students={students}
registrationDiscounts={registrationDiscounts}
tuitionDiscounts={tuitionDiscounts}
registrationFees={registrationFees.filter(
(fee) => fee.is_active
)}
tuitionFees={tuitionFees.filter((fee) => fee.is_active)}
groups={groups}
profiles={profiles}
onSubmit={createRF}
/>
)}
/>
)}
{isSepaUploadModalOpen && (
<Modal
isOpen={isSepaUploadModalOpen}

View File

@ -6,9 +6,9 @@ import {
BE_SUBSCRIPTION_ABSENCES_URL,
} from '@/utils/Url';
export const PENDING = 'pending';
export const SUBSCRIBED = 'subscribed';
export const ARCHIVED = 'archived';
export const CURRENT_YEAR = 'current_year';
export const NEXT_YEAR = 'next_year';
export const HISTORICAL = 'historical';
const requestResponseHandler = async (response) => {
const body = await response.json();
@ -23,7 +23,7 @@ const requestResponseHandler = async (response) => {
export const fetchRegisterForms = (
establishment,
filter = PENDING,
filter = CURRENT_YEAR,
page = '',
pageSize = '',
search = ''