mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
fix: Ajout du mode Visu
This commit is contained in:
@ -102,7 +102,8 @@ class ChildrenListView(APIView):
|
|||||||
RegistrationForm.RegistrationFormStatus.RF_SENT,
|
RegistrationForm.RegistrationFormStatus.RF_SENT,
|
||||||
RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW,
|
RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW,
|
||||||
RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT,
|
RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT,
|
||||||
RegistrationForm.RegistrationFormStatus.RF_SEPA_TO_SEND
|
RegistrationForm.RegistrationFormStatus.RF_SEPA_TO_SEND,
|
||||||
|
RegistrationForm.RegistrationFormStatus.RF_VALIDATED
|
||||||
]
|
]
|
||||||
).distinct()
|
).distinct()
|
||||||
students_serializer = RegistrationFormByParentSerializer(students, many=True)
|
students_serializer = RegistrationFormByParentSerializer(students, many=True)
|
||||||
|
|||||||
@ -143,69 +143,64 @@ export default function Layout({ children }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ProtectedRoute requiredRight={[RIGHTS.ADMIN, RIGHTS.TEACHER]}>
|
<ProtectedRoute requiredRight={[RIGHTS.ADMIN, RIGHTS.TEACHER]}>
|
||||||
|
{/* Topbar */}
|
||||||
{/* Topbar */}
|
<header className="absolute top-0 left-0 right-0 h-16 bg-white border-b border-gray-200 px-4 md:px-8 flex items-center justify-between z-10 box-border">
|
||||||
<header className="absolute top-0 left-0 right-0 h-16 bg-white border-b border-gray-200 px-4 md:px-8 flex items-center justify-between z-10 box-border">
|
<div className="flex items-center">
|
||||||
<div className="flex items-center">
|
<button
|
||||||
<button
|
className="mr-4 md:hidden text-gray-600 hover:text-gray-900"
|
||||||
className="mr-4 md:hidden text-gray-600 hover:text-gray-900"
|
|
||||||
onClick={toggleSidebar}
|
|
||||||
aria-label="Toggle menu"
|
|
||||||
>
|
|
||||||
{isSidebarOpen ? <X size={24} /> : <Menu size={24} />}
|
|
||||||
</button>
|
|
||||||
<div className="text-lg md:text-xl font-semibold">{headerTitle}</div>
|
|
||||||
</div>
|
|
||||||
<DropdownMenu
|
|
||||||
buttonContent={
|
|
||||||
<Image
|
|
||||||
src={getGravatarUrl(user?.email)}
|
|
||||||
alt="Profile"
|
|
||||||
className="w-8 h-8 rounded-full cursor-pointer"
|
|
||||||
width={32}
|
|
||||||
height={32}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
items={dropdownItems}
|
|
||||||
buttonClassName=""
|
|
||||||
menuClassName="absolute right-0 mt-2 w-64 bg-white border border-gray-200 rounded shadow-lg"
|
|
||||||
/>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* Sidebar */}
|
|
||||||
<div
|
|
||||||
className={`absolute top-16 bottom-16 left-0 z-30 w-64 bg-white border-r border-gray-200 box-border ${
|
|
||||||
isSidebarOpen ? 'block' : 'hidden md:block'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<Sidebar
|
|
||||||
establishments={establishments}
|
|
||||||
currentPage={currentPage}
|
|
||||||
items={Object.values(sidebarItems)}
|
|
||||||
onCloseMobile={toggleSidebar}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Overlay for mobile */}
|
|
||||||
{isSidebarOpen && (
|
|
||||||
<div
|
|
||||||
className="fixed inset-0 bg-black bg-opacity-50 z-20 md:hidden"
|
|
||||||
onClick={toggleSidebar}
|
onClick={toggleSidebar}
|
||||||
/>
|
aria-label="Toggle menu"
|
||||||
)}
|
>
|
||||||
|
{isSidebarOpen ? <X size={24} /> : <Menu size={24} />}
|
||||||
{/* Main container */}
|
</button>
|
||||||
<div className="absolute overflow-auto bg-gray-50 top-16 bottom-16 left-64 right-0 ">
|
<div className="text-lg md:text-xl font-semibold">{headerTitle}</div>
|
||||||
{children}
|
|
||||||
</div>
|
</div>
|
||||||
|
<DropdownMenu
|
||||||
|
buttonContent={
|
||||||
|
<Image
|
||||||
|
src={getGravatarUrl(user?.email)}
|
||||||
|
alt="Profile"
|
||||||
|
className="w-8 h-8 rounded-full cursor-pointer"
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
items={dropdownItems}
|
||||||
|
buttonClassName=""
|
||||||
|
menuClassName="absolute right-0 mt-2 w-64 bg-white border border-gray-200 rounded shadow-lg"
|
||||||
|
/>
|
||||||
|
</header>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Sidebar */}
|
||||||
|
<div
|
||||||
|
className={`absolute top-16 bottom-16 left-0 z-30 w-64 bg-white border-r border-gray-200 box-border ${
|
||||||
|
isSidebarOpen ? 'block' : 'hidden md:block'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Sidebar
|
||||||
|
establishments={establishments}
|
||||||
|
currentPage={currentPage}
|
||||||
|
items={Object.values(sidebarItems)}
|
||||||
|
onCloseMobile={toggleSidebar}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Footer
|
{/* Overlay for mobile */}
|
||||||
softwareName={softwareName}
|
{isSidebarOpen && (
|
||||||
softwareVersion={softwareVersion}
|
<div
|
||||||
/>
|
className="fixed inset-0 bg-black bg-opacity-50 z-20 md:hidden"
|
||||||
|
onClick={toggleSidebar}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Main container */}
|
||||||
|
<div className="absolute overflow-auto bg-gray-50 top-16 bottom-16 left-64 right-0 ">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
|
||||||
|
<Footer softwareName={softwareName} softwareVersion={softwareVersion} />
|
||||||
|
|
||||||
<Popup
|
<Popup
|
||||||
visible={isPopupVisible}
|
visible={isPopupVisible}
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { PlanningModes, PlanningProvider, RecurrenceType } from '@/context/PlanningContext';
|
import {
|
||||||
|
PlanningModes,
|
||||||
|
PlanningProvider,
|
||||||
|
RecurrenceType,
|
||||||
|
} from '@/context/PlanningContext';
|
||||||
import Calendar from '@/components/Calendar/Calendar';
|
import Calendar from '@/components/Calendar/Calendar';
|
||||||
import EventModal from '@/components/Calendar/EventModal';
|
import EventModal from '@/components/Calendar/EventModal';
|
||||||
import ScheduleNavigation from '@/components/Calendar/ScheduleNavigation';
|
import ScheduleNavigation from '@/components/Calendar/ScheduleNavigation';
|
||||||
@ -47,7 +51,10 @@ export default function Page() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlanningProvider establishmentId={selectedEstablishmentId} modeSet={PlanningModes.PLANNING}>
|
<PlanningProvider
|
||||||
|
establishmentId={selectedEstablishmentId}
|
||||||
|
modeSet={PlanningModes.PLANNING}
|
||||||
|
>
|
||||||
{/* <div className="flex h-full overflow-hidden"> */}
|
{/* <div className="flex h-full overflow-hidden"> */}
|
||||||
<div className="flex h-full overflow-hidden">
|
<div className="flex h-full overflow-hidden">
|
||||||
<ScheduleNavigation />
|
<ScheduleNavigation />
|
||||||
|
|||||||
@ -60,7 +60,6 @@ export default function Page() {
|
|||||||
// Fetch data for classes
|
// Fetch data for classes
|
||||||
handleClasses();
|
handleClasses();
|
||||||
|
|
||||||
|
|
||||||
// Fetch data for registration discounts
|
// Fetch data for registration discounts
|
||||||
handleRegistrationDiscounts();
|
handleRegistrationDiscounts();
|
||||||
|
|
||||||
@ -126,7 +125,6 @@ export default function Page() {
|
|||||||
.catch((error) => logger.error('Error fetching classes:', error));
|
.catch((error) => logger.error('Error fetching classes:', error));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleRegistrationDiscounts = () => {
|
const handleRegistrationDiscounts = () => {
|
||||||
fetchRegistrationDiscounts(selectedEstablishmentId)
|
fetchRegistrationDiscounts(selectedEstablishmentId)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
@ -336,12 +334,14 @@ export default function Page() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PlanningProvider establishmentId={selectedEstablishmentId} modeSet={PlanningModes.CLASS_SCHEDULE}>
|
<PlanningProvider
|
||||||
<DjangoCSRFToken csrfToken={csrfToken} />
|
establishmentId={selectedEstablishmentId}
|
||||||
<SidebarTabs tabs={tabs} />
|
modeSet={PlanningModes.CLASS_SCHEDULE}
|
||||||
|
>
|
||||||
|
<DjangoCSRFToken csrfToken={csrfToken} />
|
||||||
|
<SidebarTabs tabs={tabs} />
|
||||||
</PlanningProvider>
|
</PlanningProvider>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import InscriptionFormShared from '@/components/Inscription/InscriptionFormShare
|
|||||||
import { FE_ADMIN_SUBSCRIPTIONS_URL } from '@/utils/Url';
|
import { FE_ADMIN_SUBSCRIPTIONS_URL } from '@/utils/Url';
|
||||||
import { useCsrfToken } from '@/context/CsrfContext';
|
import { useCsrfToken } from '@/context/CsrfContext';
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
import { editRegisterFormWithBinaryFile } from '@/app/actions/subscriptionAction';
|
import { editRegisterForm } from '@/app/actions/subscriptionAction';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import Loader from '@/components/Loader';
|
import Loader from '@/components/Loader';
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,8 @@ import logger from '@/utils/logger';
|
|||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const idProfil = searchParams.get('id');
|
|
||||||
const studentId = searchParams.get('studentId');
|
const studentId = searchParams.get('studentId');
|
||||||
|
const enable = searchParams.get('enabled') === 'true';
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const csrfToken = useCsrfToken();
|
const csrfToken = useCsrfToken();
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
@ -37,6 +37,7 @@ export default function Page() {
|
|||||||
selectedEstablishmentId={selectedEstablishmentId}
|
selectedEstablishmentId={selectedEstablishmentId}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
cancelUrl={FE_PARENTS_HOME_URL}
|
cancelUrl={FE_PARENTS_HOME_URL}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import { useCsrfToken } from '@/context/CsrfContext';
|
|||||||
|
|
||||||
export default function ParentHomePage() {
|
export default function ParentHomePage() {
|
||||||
const [children, setChildren] = useState([]);
|
const [children, setChildren] = useState([]);
|
||||||
const [userId, setUserId] = useState(null);
|
|
||||||
const { user, selectedEstablishmentId } = useEstablishment();
|
const { user, selectedEstablishmentId } = useEstablishment();
|
||||||
const [uploadingStudentId, setUploadingStudentId] = useState(null); // ID de l'étudiant pour l'upload
|
const [uploadingStudentId, setUploadingStudentId] = useState(null); // ID de l'étudiant pour l'upload
|
||||||
const [uploadedFile, setUploadedFile] = useState(null); // Fichier uploadé
|
const [uploadedFile, setUploadedFile] = useState(null); // Fichier uploadé
|
||||||
@ -29,7 +28,6 @@ export default function ParentHomePage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user !== null) {
|
if (user !== null) {
|
||||||
const userIdFromSession = user.user_id;
|
const userIdFromSession = user.user_id;
|
||||||
setUserId(userIdFromSession);
|
|
||||||
fetchChildren(userIdFromSession, selectedEstablishmentId).then((data) => {
|
fetchChildren(userIdFromSession, selectedEstablishmentId).then((data) => {
|
||||||
setChildren(data);
|
setChildren(data);
|
||||||
});
|
});
|
||||||
@ -40,14 +38,14 @@ export default function ParentHomePage() {
|
|||||||
function handleView(eleveId) {
|
function handleView(eleveId) {
|
||||||
logger.debug(`View dossier for student id: ${eleveId}`);
|
logger.debug(`View dossier for student id: ${eleveId}`);
|
||||||
router.push(
|
router.push(
|
||||||
`${FE_PARENTS_EDIT_INSCRIPTION_URL}?id=${userId}&studentId=${eleveId}&view=true`
|
`${FE_PARENTS_EDIT_INSCRIPTION_URL}?studentId=${eleveId}&enabled=false`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEdit(eleveId) {
|
function handleEdit(eleveId) {
|
||||||
logger.debug(`Edit dossier for student id: ${eleveId}`);
|
logger.debug(`Edit dossier for student id: ${eleveId}`);
|
||||||
router.push(
|
router.push(
|
||||||
`${FE_PARENTS_EDIT_INSCRIPTION_URL}?id=${userId}&studentId=${eleveId}`
|
`${FE_PARENTS_EDIT_INSCRIPTION_URL}?studentId=${eleveId}&enabled=true`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +174,19 @@ export default function ParentHomePage() {
|
|||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{row.status === 5 && (
|
||||||
|
<button
|
||||||
|
className="text-purple-500 hover:text-purple-700"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleView(row.student.id);
|
||||||
|
}}
|
||||||
|
aria-label="Visualiser le dossier"
|
||||||
|
>
|
||||||
|
<Eye className="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -53,8 +53,11 @@ const removeDatas = (url, csrfToken) => {
|
|||||||
}).then(requestResponseHandler);
|
}).then(requestResponseHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchPlannings = (establishment_id=null,planningMode=null) => {
|
export const fetchPlannings = (
|
||||||
let url = `${BE_PLANNING_PLANNINGS_URL}`;
|
establishment_id = null,
|
||||||
|
planningMode = null
|
||||||
|
) => {
|
||||||
|
let url = `${BE_PLANNING_PLANNINGS_URL}`;
|
||||||
if (establishment_id) {
|
if (establishment_id) {
|
||||||
url += `?establishment_id=${establishment_id}`;
|
url += `?establishment_id=${establishment_id}`;
|
||||||
}
|
}
|
||||||
@ -80,7 +83,7 @@ export const deletePlanning = (id, csrfToken) => {
|
|||||||
return removeDatas(`${BE_PLANNING_PLANNINGS_URL}/${id}`, csrfToken);
|
return removeDatas(`${BE_PLANNING_PLANNINGS_URL}/${id}`, csrfToken);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchEvents = (establishment_id=null, planningMode=null) => {
|
export const fetchEvents = (establishment_id = null, planningMode = null) => {
|
||||||
let url = `${BE_PLANNING_EVENTS_URL}`;
|
let url = `${BE_PLANNING_EVENTS_URL}`;
|
||||||
if (establishment_id) {
|
if (establishment_id) {
|
||||||
url += `?establishment_id=${establishment_id}`;
|
url += `?establishment_id=${establishment_id}`;
|
||||||
@ -90,7 +93,6 @@ export const fetchEvents = (establishment_id=null, planningMode=null) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return getData(url);
|
return getData(url);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getEvent = (id) => {
|
export const getEvent = (id) => {
|
||||||
@ -109,8 +111,8 @@ export const deleteEvent = (id, csrfToken) => {
|
|||||||
return removeDatas(`${BE_PLANNING_EVENTS_URL}/${id}`, csrfToken);
|
return removeDatas(`${BE_PLANNING_EVENTS_URL}/${id}`, csrfToken);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchUpcomingEvents = (establishment_id=null) => {
|
export const fetchUpcomingEvents = (establishment_id = null) => {
|
||||||
let url = `${BE_PLANNING_EVENTS_URL}/upcoming`;
|
let url = `${BE_PLANNING_EVENTS_URL}/upcoming`;
|
||||||
if (establishment_id) {
|
if (establishment_id) {
|
||||||
url += `?establishment_id=${establishment_id}`;
|
url += `?establishment_id=${establishment_id}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export default async function RootLayout({ children, params }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang={locale}>
|
<html lang={locale}>
|
||||||
<body className='p-0 m-0'>
|
<body className="p-0 m-0">
|
||||||
<Providers messages={messages} locale={locale} session={params.session}>
|
<Providers messages={messages} locale={locale} session={params.session}>
|
||||||
{children}
|
{children}
|
||||||
</Providers>
|
</Providers>
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { usePlanning,PlanningModes } from '@/context/PlanningContext';
|
import { usePlanning, PlanningModes } from '@/context/PlanningContext';
|
||||||
import { Plus, Edit2, Eye, EyeOff, Check, X } from 'lucide-react';
|
import { Plus, Edit2, Eye, EyeOff, Check, X } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function ScheduleNavigation({ classes, modeSet = 'event' }) {
|
||||||
export default function ScheduleNavigation({classes, modeSet='event'}) {
|
|
||||||
const {
|
const {
|
||||||
schedules,
|
schedules,
|
||||||
selectedSchedule,
|
selectedSchedule,
|
||||||
@ -46,7 +45,7 @@ export default function ScheduleNavigation({classes, modeSet='event'}) {
|
|||||||
|
|
||||||
const handleAddNew = () => {
|
const handleAddNew = () => {
|
||||||
if (newSchedule.name) {
|
if (newSchedule.name) {
|
||||||
let payload = {
|
let payload = {
|
||||||
name: newSchedule.name,
|
name: newSchedule.name,
|
||||||
color: newSchedule.color,
|
color: newSchedule.color,
|
||||||
};
|
};
|
||||||
@ -65,7 +64,11 @@ export default function ScheduleNavigation({classes, modeSet='event'}) {
|
|||||||
return (
|
return (
|
||||||
<nav className="w-64 border-r p-4">
|
<nav className="w-64 border-r p-4">
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<h2 className="font-semibold">{(planningMode === PlanningModes.CLASS_SCHEDULE)?"Emplois du temps":"Plannings"}</h2>
|
<h2 className="font-semibold">
|
||||||
|
{planningMode === PlanningModes.CLASS_SCHEDULE
|
||||||
|
? 'Emplois du temps'
|
||||||
|
: 'Plannings'}
|
||||||
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsAddingNew(true)}
|
onClick={() => setIsAddingNew(true)}
|
||||||
className="p-1 hover:bg-gray-100 rounded"
|
className="p-1 hover:bg-gray-100 rounded"
|
||||||
@ -83,7 +86,11 @@ export default function ScheduleNavigation({classes, modeSet='event'}) {
|
|||||||
setNewSchedule((prev) => ({ ...prev, name: e.target.value }))
|
setNewSchedule((prev) => ({ ...prev, name: e.target.value }))
|
||||||
}
|
}
|
||||||
className="w-full p-1 mb-2 border rounded"
|
className="w-full p-1 mb-2 border rounded"
|
||||||
placeholder={(planningMode===PlanningModes.CLASS_SCHEDULE)?"Nom de l'emplois du temps":"Nom du planning"}
|
placeholder={
|
||||||
|
planningMode === PlanningModes.CLASS_SCHEDULE
|
||||||
|
? "Nom de l'emplois du temps"
|
||||||
|
: 'Nom du planning'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<div className="flex gap-2 items-center mb-2">
|
<div className="flex gap-2 items-center mb-2">
|
||||||
<label className="text-sm">Couleur:</label>
|
<label className="text-sm">Couleur:</label>
|
||||||
@ -96,7 +103,7 @@ export default function ScheduleNavigation({classes, modeSet='event'}) {
|
|||||||
className="w-8 h-8"
|
className="w-8 h-8"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{planningMode === PlanningModes.CLASS_SCHEDULE&& (
|
{planningMode === PlanningModes.CLASS_SCHEDULE && (
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<label className="text-sm">Classe (optionnel):</label>
|
<label className="text-sm">Classe (optionnel):</label>
|
||||||
<select
|
<select
|
||||||
@ -110,13 +117,14 @@ export default function ScheduleNavigation({classes, modeSet='event'}) {
|
|||||||
className="w-full p-1 border rounded"
|
className="w-full p-1 border rounded"
|
||||||
>
|
>
|
||||||
<option value="">Aucune</option>
|
<option value="">Aucune</option>
|
||||||
{classes.map((classe) => { console.log({classe});
|
{classes.map((classe) => {
|
||||||
|
console.log({ classe });
|
||||||
return (
|
return (
|
||||||
<option key={classe.id} value={classe.id}>
|
<option key={classe.id} value={classe.id}>
|
||||||
{classe.atmosphere_name}
|
{classe.atmosphere_name}
|
||||||
</option>
|
</option>
|
||||||
)}
|
);
|
||||||
)}
|
})}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -138,111 +146,109 @@ export default function ScheduleNavigation({classes, modeSet='event'}) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{schedules
|
{schedules.map((schedule) => (
|
||||||
.map((schedule) => (
|
<li
|
||||||
<li
|
key={schedule.id}
|
||||||
key={schedule.id}
|
className={`p-2 rounded ${
|
||||||
className={`p-2 rounded ${
|
selectedSchedule === schedule.id
|
||||||
selectedSchedule === schedule.id
|
? 'bg-gray-100'
|
||||||
? 'bg-gray-100'
|
: 'hover:bg-gray-50'
|
||||||
: 'hover:bg-gray-50'
|
}`}
|
||||||
}`}
|
>
|
||||||
>
|
{editingId === schedule.id ? (
|
||||||
{editingId === schedule.id ? (
|
<div className="space-y-2">
|
||||||
<div className="space-y-2">
|
<input
|
||||||
|
type="text"
|
||||||
|
value={editedName}
|
||||||
|
onChange={(e) => setEditedName(e.target.value)}
|
||||||
|
className="w-full p-1 border rounded"
|
||||||
|
/>
|
||||||
|
<div className="flex gap-2 items-center">
|
||||||
|
<label className="text-sm">Couleur:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="color"
|
||||||
value={editedName}
|
value={editedColor}
|
||||||
onChange={(e) => setEditedName(e.target.value)}
|
onChange={(e) => setEditedColor(e.target.value)}
|
||||||
className="w-full p-1 border rounded"
|
className="w-8 h-8"
|
||||||
/>
|
/>
|
||||||
<div className="flex gap-2 items-center">
|
|
||||||
<label className="text-sm">Couleur:</label>
|
|
||||||
<input
|
|
||||||
type="color"
|
|
||||||
value={editedColor}
|
|
||||||
onChange={(e) => setEditedColor(e.target.value)}
|
|
||||||
className="w-8 h-8"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{planningMode === PlanningModes.CLASS_SCHEDULE && (
|
|
||||||
<div className="mb-2">
|
|
||||||
<label className="text-sm">Classe:</label>
|
|
||||||
<select
|
|
||||||
value={editedSchoolClass}
|
|
||||||
onChange={(e) => setEditedSchoolClass(e.target.value)}
|
|
||||||
|
|
||||||
className="w-full p-1 border rounded"
|
|
||||||
>
|
|
||||||
<option value="">Aucune</option>
|
|
||||||
{classes.map((classe) => (
|
|
||||||
<option key={classe.id} value={classe.id}>
|
|
||||||
{classe.atmosphere_name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="flex justify-end gap-2">
|
|
||||||
<button
|
|
||||||
onClick={() => setEditingId(null)}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded"
|
|
||||||
>
|
|
||||||
<X className="w-4 h-4" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={handleSave}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded"
|
|
||||||
>
|
|
||||||
<Check className="w-4 h-4" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
{planningMode === PlanningModes.CLASS_SCHEDULE && (
|
||||||
<div className="flex items-center justify-between">
|
<div className="mb-2">
|
||||||
<div
|
<label className="text-sm">Classe:</label>
|
||||||
className="flex items-center gap-2 flex-1 cursor-pointer"
|
<select
|
||||||
onClick={() => setSelectedSchedule(schedule.id)}
|
value={editedSchoolClass}
|
||||||
|
onChange={(e) => setEditedSchoolClass(e.target.value)}
|
||||||
|
className="w-full p-1 border rounded"
|
||||||
|
>
|
||||||
|
<option value="">Aucune</option>
|
||||||
|
{classes.map((classe) => (
|
||||||
|
<option key={classe.id} value={classe.id}>
|
||||||
|
{classe.atmosphere_name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="flex justify-end gap-2">
|
||||||
|
<button
|
||||||
|
onClick={() => setEditingId(null)}
|
||||||
|
className="p-1 hover:bg-gray-100 rounded"
|
||||||
>
|
>
|
||||||
<div
|
<X className="w-4 h-4" />
|
||||||
className="w-3 h-3 rounded-full"
|
</button>
|
||||||
style={{ backgroundColor: schedule.color }}
|
<button
|
||||||
/>
|
onClick={handleSave}
|
||||||
<span
|
className="p-1 hover:bg-gray-100 rounded"
|
||||||
className={
|
>
|
||||||
hiddenSchedules.includes(schedule.id)
|
<Check className="w-4 h-4" />
|
||||||
? 'text-gray-400'
|
</button>
|
||||||
: ''
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{schedule.name}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-1">
|
|
||||||
<button
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation(); // Empêcher la propagation du clic
|
|
||||||
toggleScheduleVisibility(schedule.id);
|
|
||||||
}}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded"
|
|
||||||
>
|
|
||||||
{hiddenSchedules.includes(schedule.id) ? (
|
|
||||||
<EyeOff className="w-4 h-4" />
|
|
||||||
) : (
|
|
||||||
<Eye className="w-4 h-4" />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => handleEdit(schedule)}
|
|
||||||
className="p-1 hover:bg-gray-100 rounded"
|
|
||||||
>
|
|
||||||
<Edit2 className="w-4 h-4" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</li>
|
) : (
|
||||||
))}
|
<div className="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
className="flex items-center gap-2 flex-1 cursor-pointer"
|
||||||
|
onClick={() => setSelectedSchedule(schedule.id)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="w-3 h-3 rounded-full"
|
||||||
|
style={{ backgroundColor: schedule.color }}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={
|
||||||
|
hiddenSchedules.includes(schedule.id)
|
||||||
|
? 'text-gray-400'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{schedule.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation(); // Empêcher la propagation du clic
|
||||||
|
toggleScheduleVisibility(schedule.id);
|
||||||
|
}}
|
||||||
|
className="p-1 hover:bg-gray-100 rounded"
|
||||||
|
>
|
||||||
|
{hiddenSchedules.includes(schedule.id) ? (
|
||||||
|
<EyeOff className="w-4 h-4" />
|
||||||
|
) : (
|
||||||
|
<Eye className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleEdit(schedule)}
|
||||||
|
className="p-1 hover:bg-gray-100 rounded"
|
||||||
|
>
|
||||||
|
<Edit2 className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -44,7 +44,7 @@ const WeekView = ({ onDateClick, onEventClick, events }) => {
|
|||||||
const hours = currentTime.getHours();
|
const hours = currentTime.getHours();
|
||||||
const minutes = currentTime.getMinutes();
|
const minutes = currentTime.getMinutes();
|
||||||
const rowHeight = 5; // Hauteur des lignes en rem (h-20 = 5rem)
|
const rowHeight = 5; // Hauteur des lignes en rem (h-20 = 5rem)
|
||||||
return `${((hours + minutes / 60) * rowHeight)}rem`;
|
return `${(hours + minutes / 60) * rowHeight}rem`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Utiliser les événements déjà filtrés passés en props
|
// Utiliser les événements déjà filtrés passés en props
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
import { CloudUpload } from 'lucide-react';
|
import { CloudUpload } from 'lucide-react';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import { BASE_URL } from '@/utils/Url';
|
|
||||||
|
|
||||||
export default function FileUpload({
|
export default function FileUpload({
|
||||||
selectionMessage,
|
selectionMessage,
|
||||||
@ -10,57 +9,78 @@ export default function FileUpload({
|
|||||||
existingFile,
|
existingFile,
|
||||||
required,
|
required,
|
||||||
errorMsg,
|
errorMsg,
|
||||||
|
enable = true, // Nouvelle prop pour activer/désactiver le champ
|
||||||
}) {
|
}) {
|
||||||
const [localFileName, setLocalFileName] = useState(uploadedFileName || '');
|
const [localFileName, setLocalFileName] = useState(uploadedFileName || '');
|
||||||
const fileInputRef = useRef(null); // Utilisation de useRef pour cibler l'input
|
const fileInputRef = useRef(null);
|
||||||
|
|
||||||
const handleFileChange = (e) => {
|
const handleFileChange = (e) => {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
setLocalFileName(file.name);
|
setLocalFileName(file.name);
|
||||||
logger.debug('Fichier sélectionné:', file.name);
|
logger.debug('Fichier sélectionné:', file.name);
|
||||||
onFileSelect(file); // Appelle la fonction passée en prop
|
onFileSelect(file);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFileDrop = (e) => {
|
const handleFileDrop = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (!enable) return; // Empêcher le dépôt si désactivé
|
||||||
const file = e.dataTransfer.files[0];
|
const file = e.dataTransfer.files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
setLocalFileName(file.name);
|
setLocalFileName(file.name);
|
||||||
logger.debug('Fichier déposé:', file.name);
|
logger.debug('Fichier déposé:', file.name);
|
||||||
onFileSelect(file); // Appelle la fonction passée en prop
|
onFileSelect(file);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border p-4 rounded-md shadow-md">
|
<div
|
||||||
|
className={`border p-4 rounded-md shadow-md ${
|
||||||
|
!enable ? 'bg-gray-100 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<h3 className="text-lg font-semibold mb-4">
|
<h3 className="text-lg font-semibold mb-4">
|
||||||
{`${selectionMessage}`}
|
{`${selectionMessage}`}
|
||||||
{required && <span className="text-red-500 ml-1">*</span>}
|
{required && <span className="text-red-500 ml-1">*</span>}
|
||||||
</h3>
|
</h3>
|
||||||
<div
|
<div
|
||||||
className="border-2 border-dashed border-gray-500 p-6 rounded-lg flex flex-col items-center justify-center cursor-pointer hover:border-emerald-500"
|
className={`border-2 border-dashed p-6 rounded-lg flex flex-col items-center justify-center ${
|
||||||
onClick={() => fileInputRef.current.click()} // Utilisation de la référence pour ouvrir l'explorateur
|
!enable
|
||||||
onDragOver={(e) => e.preventDefault()}
|
? 'border-gray-300 bg-gray-100 cursor-not-allowed'
|
||||||
|
: 'border-gray-500 hover:border-emerald-500'
|
||||||
|
}`}
|
||||||
|
onClick={() => enable && fileInputRef.current.click()} // Désactiver le clic si `enable` est false
|
||||||
|
onDragOver={(e) => enable && e.preventDefault()}
|
||||||
onDrop={handleFileDrop}
|
onDrop={handleFileDrop}
|
||||||
>
|
>
|
||||||
<CloudUpload className="w-12 h-12 text-emerald-500 mb-4" />{' '}
|
<CloudUpload
|
||||||
{/* Icône de cloud */}
|
className={`w-12 h-12 mb-4 ${
|
||||||
|
!enable ? 'text-gray-400' : 'text-emerald-500'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
accept=".pdf, .png, .jpg, .jpeg, .gif, .bmp"
|
accept=".pdf, .png, .jpg, .jpeg, .gif, .bmp"
|
||||||
onChange={handleFileChange}
|
onChange={handleFileChange}
|
||||||
className="hidden"
|
className="hidden"
|
||||||
ref={fileInputRef} // Attachement de la référence
|
ref={fileInputRef}
|
||||||
|
disabled={!enable} // Désactiver l'input si `enable` est false
|
||||||
/>
|
/>
|
||||||
<label htmlFor="fileInput" className="text-center text-gray-500">
|
<label
|
||||||
<p className="text-lg font-semibold text-gray-800">
|
htmlFor="fileInput"
|
||||||
Déposez votre fichier ici
|
className={`text-center ${
|
||||||
</p>
|
!enable ? 'text-gray-400' : 'text-gray-500'
|
||||||
<p className="text-sm text-gray-500 mt-2">
|
}`}
|
||||||
ou cliquez pour sélectionner un fichier
|
>
|
||||||
|
<p className="text-lg font-semibold">
|
||||||
|
{enable ? 'Déposez votre fichier ici' : 'Téléversement désactivé'}
|
||||||
</p>
|
</p>
|
||||||
|
{enable && (
|
||||||
|
<p className="text-sm text-gray-500 mt-2">
|
||||||
|
ou cliquez pour sélectionner un fichier
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -70,18 +90,10 @@ export default function FileUpload({
|
|||||||
<CloudUpload className="w-6 h-6 text-emerald-500" />
|
<CloudUpload className="w-6 h-6 text-emerald-500" />
|
||||||
<p className="text-sm font-medium text-gray-800">
|
<p className="text-sm font-medium text-gray-800">
|
||||||
<span className="font-semibold">
|
<span className="font-semibold">
|
||||||
{typeof existingFile === 'string' ? (
|
{typeof existingFile === 'string'
|
||||||
<a
|
? existingFile.split('/').pop() // Si c'est une chaîne, utilisez split
|
||||||
href={`${BASE_URL}${existingFile}`}
|
: existingFile?.name || 'Nom de fichier inconnu'}{' '}
|
||||||
target="_blank"
|
// Sinon, utilisez une propriété ou un fallback
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-blue-500 hover:text-blue-700 underline"
|
|
||||||
>
|
|
||||||
{existingFile.split('/').pop()}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
existingFile?.name || 'Fichier inconnu'
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -10,10 +10,10 @@ export default function InputPhone({
|
|||||||
errorMsg,
|
errorMsg,
|
||||||
className,
|
className,
|
||||||
required,
|
required,
|
||||||
|
enable = true, // Par défaut, le champ est activé
|
||||||
}) {
|
}) {
|
||||||
const handlePhoneChange = (phone) => {
|
const handlePhoneChange = (phone) => {
|
||||||
// Appeler onChange avec un objet personnalisé
|
if (enable && onChange) {
|
||||||
if (onChange) {
|
|
||||||
if (phone && phone.target) {
|
if (phone && phone.target) {
|
||||||
const { name, value } = phone.target;
|
const { name, value } = phone.target;
|
||||||
onChange({ target: { name: name, value: value } });
|
onChange({ target: { name: name, value: value } });
|
||||||
@ -37,11 +37,20 @@ export default function InputPhone({
|
|||||||
inputProps={{
|
inputProps={{
|
||||||
name: name,
|
name: name,
|
||||||
required: required,
|
required: required,
|
||||||
|
disabled: !enable, // Désactiver l'input si enable est false
|
||||||
}}
|
}}
|
||||||
className="!w-full mt-1 !h-[38px]"
|
className={`!w-full mt-1 !h-[38px] ${
|
||||||
containerClassName="!w-full !h-[36px] !flex !items-center !rounded-md"
|
!enable ? 'bg-gray-100 cursor-not-allowed' : ''
|
||||||
inputClassName={`flex-1 px-3 py-2 block w-full sm:text-sm border-none focus:ring-0 outline-none !rounded-r-md !outline-none items-center !border !border-gray-200 rounded-md ${errorMsg ? 'border-red-500' : ''} hover:border-gray-400 focus-within:border-gray-500`}
|
}`}
|
||||||
buttonClassName="!h-[38px] !flex !items-center !justify-center !rounded-l-md !border border-gray-200 !border-r-0"
|
containerClassName={`!w-full !h-[36px] !flex !items-center !rounded-md ${
|
||||||
|
!enable ? 'bg-gray-100 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
|
inputClassName={`flex-1 px-3 py-2 block w-full sm:text-sm border-none focus:ring-0 outline-none !rounded-r-md items-center !border !border-gray-200 rounded-md ${
|
||||||
|
errorMsg ? 'border-red-500' : ''
|
||||||
|
} ${!enable ? 'bg-gray-100 cursor-not-allowed' : 'hover:border-gray-400 focus-within:border-gray-500'}`}
|
||||||
|
buttonClassName={`!h-[38px] !flex !items-center !justify-center !rounded-l-md !border border-gray-200 !border-r-0 ${
|
||||||
|
!enable ? 'cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export default function InputText({
|
|||||||
placeholder,
|
placeholder,
|
||||||
className,
|
className,
|
||||||
required,
|
required,
|
||||||
|
enable = true, // Nouvelle prop pour activer/désactiver le champ
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -25,7 +26,9 @@ export default function InputText({
|
|||||||
errorMsg || errorLocalMsg
|
errorMsg || errorLocalMsg
|
||||||
? 'border-red-500 hover:border-red-700'
|
? 'border-red-500 hover:border-red-700'
|
||||||
: 'border-gray-200 hover:border-gray-400'
|
: 'border-gray-200 hover:border-gray-400'
|
||||||
} ${!errorMsg && !errorLocalMsg ? 'focus-within:border-gray-500' : ''}`}
|
} ${!errorMsg && !errorLocalMsg ? 'focus-within:border-gray-500' : ''} ${
|
||||||
|
!enable ? 'bg-gray-100 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
@ -33,9 +36,12 @@ export default function InputText({
|
|||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={enable ? onChange : undefined} // Désactiver onChange si enable est false
|
||||||
className="flex-1 px-3 py-2 block w-full sm:text-sm border-none focus:ring-0 outline-none rounded-md"
|
className={`flex-1 px-3 py-2 block w-full sm:text-sm border-none focus:ring-0 outline-none rounded-md ${
|
||||||
|
!enable ? 'bg-gray-100 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
required={required}
|
required={required}
|
||||||
|
readOnly={!enable ? 'readOnly' : ''} // Activer le mode readonly si enable est false
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export default function FilesToUpload({
|
|||||||
uploadedFiles,
|
uploadedFiles,
|
||||||
onFileUpload,
|
onFileUpload,
|
||||||
onFileDelete,
|
onFileDelete,
|
||||||
|
enable = true,
|
||||||
}) {
|
}) {
|
||||||
const [selectedFile, setSelectedFile] = useState(null); // État pour le fichier sélectionné
|
const [selectedFile, setSelectedFile] = useState(null); // État pour le fichier sélectionné
|
||||||
const [actionType, setActionType] = useState(null);
|
const [actionType, setActionType] = useState(null);
|
||||||
@ -124,41 +125,43 @@ export default function FilesToUpload({
|
|||||||
>
|
>
|
||||||
<Eye className="w-5 h-5" />
|
<Eye className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
{enable && (
|
||||||
className="flex items-center justify-center w-8 h-8 rounded-full text-red-500 hover:text-red-700"
|
<button
|
||||||
onClick={() => {
|
className="flex items-center justify-center w-8 h-8 rounded-full text-red-500 hover:text-red-700"
|
||||||
setRemovePopupVisible(true);
|
onClick={() => {
|
||||||
setRemovePopupMessage(
|
setRemovePopupVisible(true);
|
||||||
`Êtes-vous sûr(e) de vouloir supprimer le fichier "${row.master_name}" ?`
|
setRemovePopupMessage(
|
||||||
);
|
`Êtes-vous sûr(e) de vouloir supprimer le fichier "${row.master_name}" ?`
|
||||||
setRemovePopupOnConfirm(() => () => {
|
);
|
||||||
onFileDelete(row.id)
|
setRemovePopupOnConfirm(() => () => {
|
||||||
.then(() => {
|
onFileDelete(row.id)
|
||||||
setPopupMessage(
|
.then(() => {
|
||||||
`Le fichier "${row.master_name}" a été supprimé avec succès.`
|
setPopupMessage(
|
||||||
);
|
`Le fichier "${row.master_name}" a été supprimé avec succès.`
|
||||||
setPopupVisible(true);
|
);
|
||||||
setRemovePopupVisible(false);
|
setPopupVisible(true);
|
||||||
})
|
setRemovePopupVisible(false);
|
||||||
.catch((error) => {
|
})
|
||||||
logger.error(
|
.catch((error) => {
|
||||||
'Erreur lors de la suppression du fichier :',
|
logger.error(
|
||||||
error
|
'Erreur lors de la suppression du fichier :',
|
||||||
);
|
error
|
||||||
setPopupMessage(
|
);
|
||||||
`Erreur lors de la suppression du fichier "${row.master_name}".`
|
setPopupMessage(
|
||||||
);
|
`Erreur lors de la suppression du fichier "${row.master_name}".`
|
||||||
setPopupVisible(true);
|
);
|
||||||
setRemovePopupVisible(false);
|
setPopupVisible(true);
|
||||||
});
|
setRemovePopupVisible(false);
|
||||||
setActionType(null);
|
});
|
||||||
setSelectedFile(null);
|
setActionType(null);
|
||||||
});
|
setSelectedFile(null);
|
||||||
}}
|
});
|
||||||
type="button"
|
}}
|
||||||
>
|
type="button"
|
||||||
<Trash2 className="w-5 h-5" />
|
>
|
||||||
</button>
|
<Trash2 className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!uploadedFile && (
|
{!uploadedFile && (
|
||||||
@ -218,7 +221,7 @@ export default function FilesToUpload({
|
|||||||
border: 'none',
|
border: 'none',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : actionType === 'upload' ? (
|
) : actionType === 'upload' && enable ? (
|
||||||
<FileUpload
|
<FileUpload
|
||||||
selectionMessage={`Téléversez le fichier ${selectedFile.master_name}`}
|
selectionMessage={`Téléversez le fichier ${selectedFile.master_name}`}
|
||||||
onFileSelect={(file) => handleUpload(file, selectedFile)}
|
onFileSelect={(file) => handleUpload(file, selectedFile)}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import {
|
|||||||
fetchRegistrationPaymentPlans,
|
fetchRegistrationPaymentPlans,
|
||||||
fetchTuitionPaymentPlans,
|
fetchTuitionPaymentPlans,
|
||||||
} from '@/app/actions/schoolAction';
|
} from '@/app/actions/schoolAction';
|
||||||
import { BASE_URL } from '@/utils/Url';
|
import { BASE_URL, FE_PARENTS_HOME_URL } from '@/utils/Url';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
import FilesToUpload from '@/components/Inscription/FilesToUpload';
|
import FilesToUpload from '@/components/Inscription/FilesToUpload';
|
||||||
import { DocusealForm } from '@docuseal/react';
|
import { DocusealForm } from '@docuseal/react';
|
||||||
@ -27,6 +27,7 @@ import SiblingInputFields from '@/components/Inscription/SiblingInputFields';
|
|||||||
import PaymentMethodSelector from '@/components/Inscription/PaymentMethodSelector';
|
import PaymentMethodSelector from '@/components/Inscription/PaymentMethodSelector';
|
||||||
import ProgressStep from '@/components/ProgressStep';
|
import ProgressStep from '@/components/ProgressStep';
|
||||||
import { CheckCircle, Hourglass } from 'lucide-react';
|
import { CheckCircle, Hourglass } from 'lucide-react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composant de formulaire d'inscription partagé
|
* Composant de formulaire d'inscription partagé
|
||||||
@ -42,6 +43,7 @@ export default function InscriptionFormShared({
|
|||||||
selectedEstablishmentId,
|
selectedEstablishmentId,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
errors = {}, // Nouvelle prop pour les erreurs
|
errors = {}, // Nouvelle prop pour les erreurs
|
||||||
|
enable = true,
|
||||||
}) {
|
}) {
|
||||||
// États pour gérer les données du formulaire
|
// États pour gérer les données du formulaire
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@ -85,6 +87,20 @@ export default function InscriptionFormShared({
|
|||||||
// État pour suivre l'index du fichier en cours
|
// État pour suivre l'index du fichier en cours
|
||||||
const [currentTemplateIndex, setCurrentTemplateIndex] = useState(0);
|
const [currentTemplateIndex, setCurrentTemplateIndex] = useState(0);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
// Mettre à jour les états en fonction de la valeur de `enable`
|
||||||
|
useEffect(() => {
|
||||||
|
if (!enable) {
|
||||||
|
setIsPage1Valid(true);
|
||||||
|
setIsPage2Valid(true);
|
||||||
|
setIsPage3Valid(true);
|
||||||
|
setIsPage4Valid(true);
|
||||||
|
setIsPage5Valid(true);
|
||||||
|
setIsPage6Valid(true);
|
||||||
|
}
|
||||||
|
}, [enable]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Trouver le premier template non signé
|
// Trouver le premier template non signé
|
||||||
const firstUnsignedIndex = schoolFileTemplates.findIndex(
|
const firstUnsignedIndex = schoolFileTemplates.findIndex(
|
||||||
@ -465,10 +481,7 @@ export default function InscriptionFormShared({
|
|||||||
setStep={setCurrentPage}
|
setStep={setCurrentPage}
|
||||||
isStepValid={isStepValid}
|
isStepValid={isStepValid}
|
||||||
/>
|
/>
|
||||||
<div
|
<div className="flex-1 h-full mt-12 ">
|
||||||
className="flex-1 overflow-y-auto mt-12 "
|
|
||||||
style={{ maxHeight: 'calc(100vh - 400px)' }}
|
|
||||||
>
|
|
||||||
{/* Page 1 : Informations sur l'élève */}
|
{/* Page 1 : Informations sur l'élève */}
|
||||||
{currentPage === 1 && (
|
{currentPage === 1 && (
|
||||||
<StudentInfoForm
|
<StudentInfoForm
|
||||||
@ -482,6 +495,7 @@ export default function InscriptionFormShared({
|
|||||||
setIsPageValid={setIsPage1Valid}
|
setIsPageValid={setIsPage1Valid}
|
||||||
hasInteracted={hasInteracted}
|
hasInteracted={hasInteracted}
|
||||||
setHasInteracted={setHasInteracted}
|
setHasInteracted={setHasInteracted}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -492,6 +506,7 @@ export default function InscriptionFormShared({
|
|||||||
setGuardians={setGuardians}
|
setGuardians={setGuardians}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
setIsPageValid={setIsPage2Valid}
|
setIsPageValid={setIsPage2Valid}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -503,6 +518,7 @@ export default function InscriptionFormShared({
|
|||||||
setFormData={setFormData}
|
setFormData={setFormData}
|
||||||
errors={errors.siblings || []}
|
errors={errors.siblings || []}
|
||||||
setIsPageValid={setIsPage3Valid}
|
setIsPageValid={setIsPage3Valid}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -518,6 +534,7 @@ export default function InscriptionFormShared({
|
|||||||
tuitionPaymentPlans={tuitionPaymentPlans}
|
tuitionPaymentPlans={tuitionPaymentPlans}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
setIsPageValid={setIsPage4Valid}
|
setIsPageValid={setIsPage4Valid}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -605,66 +622,67 @@ export default function InscriptionFormShared({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Dernière page : Section Fichiers parents */}
|
{/* Dernière page : Section Fichiers parents */}
|
||||||
{currentPage === 5 && (
|
{currentPage === 6 && (
|
||||||
<FilesToUpload
|
<FilesToUpload
|
||||||
parentFileTemplates={parentFileTemplates}
|
parentFileTemplates={parentFileTemplates}
|
||||||
uploadedFiles={uploadedFiles}
|
uploadedFiles={uploadedFiles}
|
||||||
onFileUpload={handleFileUpload}
|
onFileUpload={handleFileUpload}
|
||||||
onFileDelete={handleDeleteFile}
|
onFileDelete={handleDeleteFile}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Boutons de contrôle */}
|
{/* Boutons de contrôle */}
|
||||||
<div className="flex justify-center space-x-4 mt-12">
|
<div className="flex justify-center space-x-4 mt-12">
|
||||||
{currentPage > 1 && (
|
{enable ? (
|
||||||
|
<>
|
||||||
|
{currentPage > 1 && (
|
||||||
|
<Button
|
||||||
|
text="Précédent"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handlePreviousPage();
|
||||||
|
}}
|
||||||
|
primary
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{currentPage < steps.length && (
|
||||||
|
<Button
|
||||||
|
text="Suivant"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleNextPage();
|
||||||
|
}}
|
||||||
|
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
|
||||||
|
(currentPage === 1 && !isPage1Valid) ||
|
||||||
|
(currentPage === 2 && !isPage2Valid) ||
|
||||||
|
(currentPage === 3 && !isPage3Valid) ||
|
||||||
|
(currentPage === 4 && !isPage4Valid) ||
|
||||||
|
(currentPage === 5 && !isPage5Valid) ||
|
||||||
|
(currentPage === 6 && !isPage6Valid)
|
||||||
|
? 'bg-gray-300 text-gray-700 cursor-not-allowed'
|
||||||
|
: 'bg-emerald-500 text-white hover:bg-emerald-600'
|
||||||
|
}`}
|
||||||
|
disabled={
|
||||||
|
(currentPage === 1 && !isPage1Valid) ||
|
||||||
|
(currentPage === 2 && !isPage2Valid) ||
|
||||||
|
(currentPage === 3 && !isPage3Valid) ||
|
||||||
|
(currentPage === 4 && !isPage4Valid) ||
|
||||||
|
(currentPage === 5 && !isPage5Valid) ||
|
||||||
|
(currentPage === 6 && !isPage6Valid)
|
||||||
|
}
|
||||||
|
primary
|
||||||
|
name="Next"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
<Button
|
<Button
|
||||||
text="Précédent"
|
onClick={() => router.push(FE_PARENTS_HOME_URL)}
|
||||||
onClick={(e) => {
|
text="Quitter"
|
||||||
e.preventDefault();
|
|
||||||
handlePreviousPage();
|
|
||||||
}}
|
|
||||||
primary
|
primary
|
||||||
/>
|
className="bg-emerald-500 text-white hover:bg-emerald-600"
|
||||||
)}
|
|
||||||
{currentPage < steps.length && (
|
|
||||||
<Button
|
|
||||||
text="Suivant"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
handleNextPage();
|
|
||||||
}}
|
|
||||||
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
|
|
||||||
(currentPage === 1 && !isPage1Valid) ||
|
|
||||||
(currentPage === 2 && !isPage2Valid) ||
|
|
||||||
(currentPage === 3 && !isPage3Valid) ||
|
|
||||||
(currentPage === 4 && !isPage4Valid) ||
|
|
||||||
(currentPage === 5 && !isPage5Valid)
|
|
||||||
? 'bg-gray-300 text-gray-700 cursor-not-allowed'
|
|
||||||
: 'bg-emerald-500 text-white hover:bg-emerald-600'
|
|
||||||
}`}
|
|
||||||
disabled={
|
|
||||||
(currentPage === 1 && !isPage1Valid) ||
|
|
||||||
(currentPage === 2 && !isPage2Valid) ||
|
|
||||||
(currentPage === 3 && !isPage3Valid) ||
|
|
||||||
(currentPage === 4 && !isPage4Valid) ||
|
|
||||||
(currentPage === 5 && !isPage5Valid)
|
|
||||||
}
|
|
||||||
primary
|
|
||||||
name="Next"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{currentPage === steps.length && (
|
|
||||||
<Button
|
|
||||||
onClick={handleSubmit}
|
|
||||||
text="Valider"
|
|
||||||
primary
|
|
||||||
className={`px-4 py-2 rounded-md shadow-sm focus:outline-none ${
|
|
||||||
currentPage === 6 && !isPage6Valid
|
|
||||||
? 'bg-gray-300 text-gray-700 cursor-not-allowed'
|
|
||||||
: 'bg-emerald-500 text-white hover:bg-emerald-600'
|
|
||||||
}`}
|
|
||||||
disabled={currentPage === 6 && !isPage6Valid}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export default function PaymentMethodSelector({
|
|||||||
tuitionPaymentPlans,
|
tuitionPaymentPlans,
|
||||||
errors,
|
errors,
|
||||||
setIsPageValid,
|
setIsPageValid,
|
||||||
|
enable = true,
|
||||||
}) {
|
}) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isValid = !Object.keys(formData).some(
|
const isValid = !Object.keys(formData).some(
|
||||||
@ -94,6 +95,7 @@ export default function PaymentMethodSelector({
|
|||||||
errorMsg={getError('registration_payment')}
|
errorMsg={getError('registration_payment')}
|
||||||
errorLocalMsg={getLocalError('registration_payment')}
|
errorLocalMsg={getLocalError('registration_payment')}
|
||||||
required
|
required
|
||||||
|
disabled={!enable}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RadioList
|
<RadioList
|
||||||
@ -122,6 +124,7 @@ export default function PaymentMethodSelector({
|
|||||||
}}
|
}}
|
||||||
fieldName="registration_payment_plan"
|
fieldName="registration_payment_plan"
|
||||||
className="mt-4"
|
className="mt-4"
|
||||||
|
disabled={!enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -155,6 +158,7 @@ export default function PaymentMethodSelector({
|
|||||||
errorMsg={getError('tuition_payment')}
|
errorMsg={getError('tuition_payment')}
|
||||||
errorLocalMsg={getLocalError('tuition_payment')}
|
errorLocalMsg={getLocalError('tuition_payment')}
|
||||||
required
|
required
|
||||||
|
disabled={!enable}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RadioList
|
<RadioList
|
||||||
@ -179,6 +183,7 @@ export default function PaymentMethodSelector({
|
|||||||
getError('tuition_payment_plan') ||
|
getError('tuition_payment_plan') ||
|
||||||
getLocalError('tuition_payment_plan')
|
getLocalError('tuition_payment_plan')
|
||||||
}
|
}
|
||||||
|
disabled={!enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export default function ResponsableInputFields({
|
|||||||
setGuardians,
|
setGuardians,
|
||||||
errors,
|
errors,
|
||||||
setIsPageValid,
|
setIsPageValid,
|
||||||
|
enable = true,
|
||||||
}) {
|
}) {
|
||||||
const t = useTranslations('ResponsableInputFields');
|
const t = useTranslations('ResponsableInputFields');
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
@ -145,6 +146,7 @@ export default function ResponsableInputFields({
|
|||||||
errorMsg={getError('last_name')}
|
errorMsg={getError('last_name')}
|
||||||
errorLocalMsg={getLocalError(index, 'last_name')}
|
errorLocalMsg={getLocalError(index, 'last_name')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="prenomResponsable"
|
name="prenomResponsable"
|
||||||
@ -157,6 +159,7 @@ export default function ResponsableInputFields({
|
|||||||
errorMsg={getError('first_name')}
|
errorMsg={getError('first_name')}
|
||||||
errorLocalMsg={getLocalError(index, 'first_name')}
|
errorLocalMsg={getLocalError(index, 'first_name')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -176,6 +179,7 @@ export default function ResponsableInputFields({
|
|||||||
errorMsg={getError('associated_profile_email')}
|
errorMsg={getError('associated_profile_email')}
|
||||||
errorLocalMsg={getLocalError(index, 'associated_profile_email')}
|
errorLocalMsg={getLocalError(index, 'associated_profile_email')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputPhone
|
<InputPhone
|
||||||
name="telephoneResponsable"
|
name="telephoneResponsable"
|
||||||
@ -187,6 +191,7 @@ export default function ResponsableInputFields({
|
|||||||
errorMsg={getError('phone')}
|
errorMsg={getError('phone')}
|
||||||
errorLocalMsg={getLocalError(index, 'phone')}
|
errorLocalMsg={getLocalError(index, 'phone')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -202,6 +207,7 @@ export default function ResponsableInputFields({
|
|||||||
errorMsg={getError('birth_date')}
|
errorMsg={getError('birth_date')}
|
||||||
errorLocalMsg={getLocalError(index, 'birth_date')}
|
errorLocalMsg={getLocalError(index, 'birth_date')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="professionResponsable"
|
name="professionResponsable"
|
||||||
@ -214,6 +220,7 @@ export default function ResponsableInputFields({
|
|||||||
errorMsg={getError('profession')}
|
errorMsg={getError('profession')}
|
||||||
errorLocalMsg={getLocalError(index, 'profession')}
|
errorLocalMsg={getLocalError(index, 'profession')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -229,29 +236,32 @@ export default function ResponsableInputFields({
|
|||||||
errorMsg={getError('address')}
|
errorMsg={getError('address')}
|
||||||
errorLocalMsg={getLocalError(index, 'address')}
|
errorLocalMsg={getLocalError(index, 'address')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<div className="flex justify-center">
|
{enable && (
|
||||||
<Plus
|
<div className="flex justify-center">
|
||||||
className={`w-8 h-8 ${
|
<Plus
|
||||||
guardians.length >= MAX_GUARDIANS
|
className={`w-8 h-8 ${
|
||||||
? 'text-gray-400 cursor-not-allowed'
|
guardians.length >= MAX_GUARDIANS
|
||||||
: 'text-green-500 cursor-pointer hover:text-green-700'
|
? 'text-gray-400 cursor-not-allowed'
|
||||||
} transition-colors border-2 ${
|
: 'text-green-500 cursor-pointer hover:text-green-700'
|
||||||
guardians.length >= MAX_GUARDIANS
|
} transition-colors border-2 ${
|
||||||
? 'border-gray-400'
|
guardians.length >= MAX_GUARDIANS
|
||||||
: 'border-green-500 hover:border-green-700'
|
? 'border-gray-400'
|
||||||
} rounded-full p-1`}
|
: 'border-green-500 hover:border-green-700'
|
||||||
onClick={(e) => {
|
} rounded-full p-1`}
|
||||||
if (guardians.length < MAX_GUARDIANS) {
|
onClick={(e) => {
|
||||||
addGuardian(e);
|
if (guardians.length < MAX_GUARDIANS) {
|
||||||
}
|
addGuardian(e);
|
||||||
}}
|
}
|
||||||
/>
|
}}
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ export default function SiblingInputFields({
|
|||||||
setFormData,
|
setFormData,
|
||||||
errors,
|
errors,
|
||||||
setIsPageValid,
|
setIsPageValid,
|
||||||
|
enable = true,
|
||||||
}) {
|
}) {
|
||||||
const getError = (index, field) => {
|
const getError = (index, field) => {
|
||||||
return errors[index]?.[field]?.[0];
|
return errors[index]?.[field]?.[0];
|
||||||
@ -121,6 +122,7 @@ export default function SiblingInputFields({
|
|||||||
errorMsg={getError('last_name')}
|
errorMsg={getError('last_name')}
|
||||||
errorLocalMsg={getLocalError(index, 'last_name')}
|
errorLocalMsg={getLocalError(index, 'last_name')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="first_name"
|
name="first_name"
|
||||||
@ -133,6 +135,7 @@ export default function SiblingInputFields({
|
|||||||
errorMsg={getError('first_name')}
|
errorMsg={getError('first_name')}
|
||||||
errorLocalMsg={getLocalError(index, 'first_name')}
|
errorLocalMsg={getLocalError(index, 'first_name')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -148,17 +151,20 @@ export default function SiblingInputFields({
|
|||||||
errorMsg={getError('birth_date')}
|
errorMsg={getError('birth_date')}
|
||||||
errorLocalMsg={getLocalError(index, 'birth_date')}
|
errorLocalMsg={getLocalError(index, 'birth_date')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<div className="flex justify-center">
|
{enable && (
|
||||||
<Plus
|
<div className="flex justify-center">
|
||||||
className="w-8 h-8 text-green-500 cursor-pointer hover:text-green-700 transition-colors border-2 border-green-500 hover:border-green-700 rounded-full p-1"
|
<Plus
|
||||||
onClick={addSibling}
|
className="w-8 h-8 text-green-500 cursor-pointer hover:text-green-700 transition-colors border-2 border-green-500 hover:border-green-700 rounded-full p-1"
|
||||||
/>
|
onClick={addSibling}
|
||||||
</div>
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export default function StudentInfoForm({
|
|||||||
setIsPageValid,
|
setIsPageValid,
|
||||||
hasInteracted,
|
hasInteracted,
|
||||||
setHasInteracted,
|
setHasInteracted,
|
||||||
|
enable = true,
|
||||||
}) {
|
}) {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
@ -181,6 +182,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('last_name')}
|
errorMsg={getError('last_name')}
|
||||||
errorLocalMsg={getLocalError('last_name')}
|
errorLocalMsg={getLocalError('last_name')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="first_name"
|
name="first_name"
|
||||||
@ -190,6 +192,7 @@ export default function StudentInfoForm({
|
|||||||
errorMsg={getError('first_name')}
|
errorMsg={getError('first_name')}
|
||||||
errorLocalMsg={getLocalError('first_name')}
|
errorLocalMsg={getLocalError('first_name')}
|
||||||
required
|
required
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<SelectChoice
|
<SelectChoice
|
||||||
name="gender"
|
name="gender"
|
||||||
@ -201,6 +204,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('gender')}
|
errorMsg={getError('gender')}
|
||||||
errorLocalMsg={getLocalError('gender')}
|
errorLocalMsg={getLocalError('gender')}
|
||||||
|
disabled={!enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
@ -213,6 +217,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('birth_date')}
|
errorMsg={getError('birth_date')}
|
||||||
errorLocalMsg={getLocalError('birth_date')}
|
errorLocalMsg={getLocalError('birth_date')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="birth_place"
|
name="birth_place"
|
||||||
@ -222,6 +227,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('birth_place')}
|
errorMsg={getError('birth_place')}
|
||||||
errorLocalMsg={getLocalError('birth_place')}
|
errorLocalMsg={getLocalError('birth_place')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="birth_postal_code"
|
name="birth_postal_code"
|
||||||
@ -231,6 +237,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('birth_postal_code')}
|
errorMsg={getError('birth_postal_code')}
|
||||||
errorLocalMsg={getLocalError('birth_postal_code')}
|
errorLocalMsg={getLocalError('birth_postal_code')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
@ -242,6 +249,7 @@ export default function StudentInfoForm({
|
|||||||
onChange={(e) => onChange('nationality', e.target.value)}
|
onChange={(e) => onChange('nationality', e.target.value)}
|
||||||
errorMsg={getError('nationality')}
|
errorMsg={getError('nationality')}
|
||||||
errorLocalMsg={getLocalError('nationality')}
|
errorLocalMsg={getLocalError('nationality')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
name="address"
|
name="address"
|
||||||
@ -251,6 +259,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('address')}
|
errorMsg={getError('address')}
|
||||||
errorLocalMsg={getLocalError('address')}
|
errorLocalMsg={getLocalError('address')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
@ -262,6 +271,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('attending_physician')}
|
errorMsg={getError('attending_physician')}
|
||||||
errorLocalMsg={getLocalError('attending_physician')}
|
errorLocalMsg={getLocalError('attending_physician')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
<SelectChoice
|
<SelectChoice
|
||||||
name="level"
|
name="level"
|
||||||
@ -273,6 +283,7 @@ export default function StudentInfoForm({
|
|||||||
required
|
required
|
||||||
errorMsg={getError('level')}
|
errorMsg={getError('level')}
|
||||||
errorLocalMsg={getLocalError('level')}
|
errorLocalMsg={getLocalError('level')}
|
||||||
|
disabled={!enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-1 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-1 gap-8">
|
||||||
@ -281,6 +292,7 @@ export default function StudentInfoForm({
|
|||||||
onFileSelect={(file) => handlePhotoUpload(file)}
|
onFileSelect={(file) => handlePhotoUpload(file)}
|
||||||
existingFile={formData.photo}
|
existingFile={formData.photo}
|
||||||
errorMsg={getError('photo')}
|
errorMsg={getError('photo')}
|
||||||
|
enable={enable}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,6 +9,7 @@ const RadioList = ({
|
|||||||
className,
|
className,
|
||||||
sectionLabel,
|
sectionLabel,
|
||||||
required,
|
required,
|
||||||
|
disabled = false,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={`mb-4 ${className}`}>
|
<div className={`mb-4 ${className}`}>
|
||||||
@ -20,7 +21,12 @@ const RadioList = ({
|
|||||||
)}
|
)}
|
||||||
<div className="grid grid-cols-1 gap-4">
|
<div className="grid grid-cols-1 gap-4">
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<div key={item.id} className="flex items-center">
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className={`flex items-center ${
|
||||||
|
disabled ? 'opacity-50 cursor-not-allowed' : ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
key={`${item.id}-${Math.random()}`}
|
key={`${item.id}-${Math.random()}`}
|
||||||
type="radio"
|
type="radio"
|
||||||
@ -31,10 +37,13 @@ const RadioList = ({
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="form-radio h-4 w-4 text-emerald-600 focus:ring-emerald-500 hover:ring-emerald-400 checked:bg-emerald-600 cursor-pointer"
|
className="form-radio h-4 w-4 text-emerald-600 focus:ring-emerald-500 hover:ring-emerald-400 checked:bg-emerald-600 cursor-pointer"
|
||||||
style={{ outline: 'none', boxShadow: 'none' }}
|
style={{ outline: 'none', boxShadow: 'none' }}
|
||||||
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor={`${fieldName}-${item.id}`}
|
htmlFor={`${fieldName}-${item.id}`}
|
||||||
className="ml-2 block text-sm text-gray-900 flex items-center cursor-pointer"
|
className={`ml-2 block text-sm text-gray-900 flex items-center ${
|
||||||
|
disabled ? 'cursor-not-allowed' : 'cursor-pointer'
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@ -20,14 +20,14 @@ const SidebarTabs = ({ tabs }) => {
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{tabs.map((tab) => (
|
{tabs.map((tab) => (
|
||||||
<div
|
<div
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
className={`${activeTab === tab.id ? 'block h-[calc(100%-3.5rem)]' : 'hidden'}`}
|
className={`${activeTab === tab.id ? 'block h-[calc(100%-3.5rem)]' : 'hidden'}`}
|
||||||
>
|
>
|
||||||
{tab.content}
|
{tab.content}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const StatusLabel = ({ status, onChange, showDropdown = true, parent }) => {
|
|||||||
? [
|
? [
|
||||||
{ value: 2, label: 'Nouveau' },
|
{ value: 2, label: 'Nouveau' },
|
||||||
{ value: 3, label: 'En validation' },
|
{ value: 3, label: 'En validation' },
|
||||||
|
{ value: 5, label: 'Validé' },
|
||||||
{ value: 7, label: 'SEPA reçu' },
|
{ value: 7, label: 'SEPA reçu' },
|
||||||
{ value: 8, label: 'En validation' },
|
{ value: 8, label: 'En validation' },
|
||||||
]
|
]
|
||||||
@ -32,6 +33,7 @@ const StatusLabel = ({ status, onChange, showDropdown = true, parent }) => {
|
|||||||
return (
|
return (
|
||||||
(status === 2 && 'bg-orange-50 text-orange-600') ||
|
(status === 2 && 'bg-orange-50 text-orange-600') ||
|
||||||
((status === 3 || status === 8) && 'bg-purple-50 text-purple-600') ||
|
((status === 3 || status === 8) && 'bg-purple-50 text-purple-600') ||
|
||||||
|
(status === 5 && 'bg-green-50 text-green-600') ||
|
||||||
(status === 7 && 'bg-yellow-50 text-yellow-600')
|
(status === 7 && 'bg-yellow-50 text-yellow-600')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { useEstablishment } from '@/context/EstablishmentContext';
|
|||||||
import { FE_ADMIN_STRUCTURE_SCHOOLCLASS_MANAGEMENT_URL } from '@/utils/Url';
|
import { FE_ADMIN_STRUCTURE_SCHOOLCLASS_MANAGEMENT_URL } from '@/utils/Url';
|
||||||
import { usePlanning } from '@/context/PlanningContext';
|
import { usePlanning } from '@/context/PlanningContext';
|
||||||
import { useClasses } from '@/context/ClassesContext';
|
import { useClasses } from '@/context/ClassesContext';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
const ItemTypes = {
|
const ItemTypes = {
|
||||||
TEACHER: 'teacher',
|
TEACHER: 'teacher',
|
||||||
@ -119,7 +119,6 @@ const ClassesSection = ({
|
|||||||
handleCreate,
|
handleCreate,
|
||||||
handleEdit,
|
handleEdit,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
|
|
||||||
}) => {
|
}) => {
|
||||||
const [formData, setFormData] = useState({});
|
const [formData, setFormData] = useState({});
|
||||||
const [editingClass, setEditingClass] = useState(null);
|
const [editingClass, setEditingClass] = useState(null);
|
||||||
@ -134,8 +133,8 @@ const ClassesSection = ({
|
|||||||
const [selectedClass, setSelectedClass] = useState(null);
|
const [selectedClass, setSelectedClass] = useState(null);
|
||||||
const { selectedEstablishmentId } = useEstablishment();
|
const { selectedEstablishmentId } = useEstablishment();
|
||||||
const { addSchedule, reloadPlanning, reloadEvents } = usePlanning();
|
const { addSchedule, reloadPlanning, reloadEvents } = usePlanning();
|
||||||
const{ getNiveauxLabels, allNiveaux } = useClasses();
|
const { getNiveauxLabels, allNiveaux } = useClasses();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
// Fonction pour générer les années scolaires
|
// Fonction pour générer les années scolaires
|
||||||
const getSchoolYearChoices = () => {
|
const getSchoolYearChoices = () => {
|
||||||
@ -222,10 +221,9 @@ const ClassesSection = ({
|
|||||||
name: planningName,
|
name: planningName,
|
||||||
color: '#FF5733', // Couleur par défaut
|
color: '#FF5733', // Couleur par défaut
|
||||||
school_class: createdClass.id,
|
school_class: createdClass.id,
|
||||||
}
|
};
|
||||||
addSchedule(newPlanning)
|
addSchedule(newPlanning);
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error('Error:', error.message);
|
logger.error('Error:', error.message);
|
||||||
|
|||||||
@ -9,12 +9,12 @@ export default function ScheduleEventModal({
|
|||||||
setEventData,
|
setEventData,
|
||||||
specialities,
|
specialities,
|
||||||
teachers,
|
teachers,
|
||||||
classes
|
classes,
|
||||||
}) {
|
}) {
|
||||||
const { addEvent, handleUpdateEvent, handleDeleteEvent, schedules } = usePlanning();
|
const { addEvent, handleUpdateEvent, handleDeleteEvent, schedules } =
|
||||||
|
usePlanning();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
||||||
if (!eventData?.planning && schedules.length > 0) {
|
if (!eventData?.planning && schedules.length > 0) {
|
||||||
const defaultSchedule = schedules[0];
|
const defaultSchedule = schedules[0];
|
||||||
if (eventData?.planning !== defaultSchedule.id) {
|
if (eventData?.planning !== defaultSchedule.id) {
|
||||||
@ -26,9 +26,10 @@ export default function ScheduleEventModal({
|
|||||||
}
|
}
|
||||||
}, [schedules, eventData?.planning]);
|
}, [schedules, eventData?.planning]);
|
||||||
|
|
||||||
|
|
||||||
const handleSpecialityChange = (specialityId) => {
|
const handleSpecialityChange = (specialityId) => {
|
||||||
const selectedSpeciality = specialities.find((s) => s.id === parseInt(specialityId, 10));
|
const selectedSpeciality = specialities.find(
|
||||||
|
(s) => s.id === parseInt(specialityId, 10)
|
||||||
|
);
|
||||||
if (selectedSpeciality) {
|
if (selectedSpeciality) {
|
||||||
setEventData((prev) => ({
|
setEventData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
@ -40,7 +41,9 @@ export default function ScheduleEventModal({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleTeacherChange = (teacherId) => {
|
const handleTeacherChange = (teacherId) => {
|
||||||
const selectedTeacher = teachers.find((t) => t.id === parseInt(teacherId, 10));
|
const selectedTeacher = teachers.find(
|
||||||
|
(t) => t.id === parseInt(teacherId, 10)
|
||||||
|
);
|
||||||
if (selectedTeacher) {
|
if (selectedTeacher) {
|
||||||
setEventData((prev) => ({
|
setEventData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
@ -51,7 +54,9 @@ export default function ScheduleEventModal({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePlanningChange = (planningId) => {
|
const handlePlanningChange = (planningId) => {
|
||||||
const selectedSchedule = schedules.find((s) => s.id === parseInt(planningId, 10));
|
const selectedSchedule = schedules.find(
|
||||||
|
(s) => s.id === parseInt(planningId, 10)
|
||||||
|
);
|
||||||
if (selectedSchedule) {
|
if (selectedSchedule) {
|
||||||
setEventData((prev) => ({
|
setEventData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
|||||||
@ -8,9 +8,11 @@ import Calendar from '@/components/Calendar/Calendar';
|
|||||||
import ScheduleEventModal from '@/components/Structure/Planning/ScheduleEventModal';
|
import ScheduleEventModal from '@/components/Structure/Planning/ScheduleEventModal';
|
||||||
import ScheduleNavigation from '@/components/Calendar/ScheduleNavigation';
|
import ScheduleNavigation from '@/components/Calendar/ScheduleNavigation';
|
||||||
|
|
||||||
|
export default function ScheduleManagement({
|
||||||
|
classes,
|
||||||
export default function ScheduleManagement({classes,specialities,teachers}) {
|
specialities,
|
||||||
|
teachers,
|
||||||
|
}) {
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [eventData, setEventData] = useState({
|
const [eventData, setEventData] = useState({
|
||||||
title: '',
|
title: '',
|
||||||
@ -50,25 +52,24 @@ export default function ScheduleManagement({classes,specialities,teachers}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full overflow-hidden">
|
<div className="flex h-full overflow-hidden">
|
||||||
<ScheduleNavigation classes={classes} />
|
<ScheduleNavigation classes={classes} />
|
||||||
<Calendar
|
<Calendar
|
||||||
onDateClick={initializeNewEvent}
|
onDateClick={initializeNewEvent}
|
||||||
onEventClick={(event) => {
|
onEventClick={(event) => {
|
||||||
setEventData(event);
|
setEventData(event);
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ScheduleEventModal
|
<ScheduleEventModal
|
||||||
isOpen={isModalOpen}
|
isOpen={isModalOpen}
|
||||||
onClose={() => setIsModalOpen(false)}
|
onClose={() => setIsModalOpen(false)}
|
||||||
eventData={eventData}
|
eventData={eventData}
|
||||||
setEventData={setEventData}
|
setEventData={setEventData}
|
||||||
specialities={specialities}
|
specialities={specialities}
|
||||||
teachers={teachers}
|
teachers={teachers}
|
||||||
classes={classes}
|
classes={classes}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -116,7 +116,6 @@ export const ClassesProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const groupSpecialitiesBySubject = (teachers) => {
|
const groupSpecialitiesBySubject = (teachers) => {
|
||||||
const groupedSpecialities = {};
|
const groupedSpecialities = {};
|
||||||
|
|
||||||
@ -142,7 +141,6 @@ export const ClassesProvider = ({ children }) => {
|
|||||||
return Object.values(groupedSpecialities);
|
return Object.values(groupedSpecialities);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ClassesContext.Provider
|
<ClassesContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
|||||||
@ -33,11 +33,13 @@ export const RecurrenceType = Object.freeze({
|
|||||||
|
|
||||||
export const PlanningModes = Object.freeze({
|
export const PlanningModes = Object.freeze({
|
||||||
CLASS_SCHEDULE: 'classSchedule',
|
CLASS_SCHEDULE: 'classSchedule',
|
||||||
PLANNING: 'planning'
|
PLANNING: 'planning',
|
||||||
});
|
});
|
||||||
|
|
||||||
export function PlanningProvider({ children, modeSet=PlanningModes.PLANNING}) {
|
export function PlanningProvider({
|
||||||
|
children,
|
||||||
|
modeSet = PlanningModes.PLANNING,
|
||||||
|
}) {
|
||||||
const [events, setEvents] = useState([]);
|
const [events, setEvents] = useState([]);
|
||||||
const [schedules, setSchedules] = useState([]);
|
const [schedules, setSchedules] = useState([]);
|
||||||
const [selectedSchedule, setSelectedSchedule] = useState(0);
|
const [selectedSchedule, setSelectedSchedule] = useState(0);
|
||||||
@ -53,21 +55,20 @@ export function PlanningProvider({ children, modeSet=PlanningModes.PLANNING}) {
|
|||||||
reloadEvents();
|
reloadEvents();
|
||||||
}, [planningMode, selectedEstablishmentId]);
|
}, [planningMode, selectedEstablishmentId]);
|
||||||
|
|
||||||
|
const reloadEvents = () => {
|
||||||
|
fetchEvents(selectedEstablishmentId, planningMode).then((data) => {
|
||||||
|
setEvents(data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const reloadEvents = () =>{
|
const reloadPlanning = () => {
|
||||||
fetchEvents(selectedEstablishmentId, planningMode).then((data) => {
|
fetchPlannings(selectedEstablishmentId, planningMode).then((data) => {
|
||||||
setEvents(data);
|
setSchedules(data);
|
||||||
});
|
if (data.length > 0) {
|
||||||
}
|
setSelectedSchedule(data[0].id);
|
||||||
|
}
|
||||||
const reloadPlanning = () =>{
|
});
|
||||||
fetchPlannings(selectedEstablishmentId, planningMode).then((data) => {
|
};
|
||||||
setSchedules(data);
|
|
||||||
if (data.length > 0) {
|
|
||||||
setSelectedSchedule(data[0].id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const addEvent = (newEvent) => {
|
const addEvent = (newEvent) => {
|
||||||
createEvent(newEvent).then(() => {
|
createEvent(newEvent).then(() => {
|
||||||
reloadEvents();
|
reloadEvents();
|
||||||
@ -82,7 +83,7 @@ const reloadPlanning = () =>{
|
|||||||
|
|
||||||
const handleDeleteEvent = (id) => {
|
const handleDeleteEvent = (id) => {
|
||||||
deleteEvent(id, csrfToken).then((data) => {
|
deleteEvent(id, csrfToken).then((data) => {
|
||||||
reloadEvents();
|
reloadEvents();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user