diff --git a/project/src/components/NewLeaveRequestModal.jsx b/project/src/components/NewLeaveRequestModal.jsx
index 22bfaf3..ceeb631 100644
--- a/project/src/components/NewLeaveRequestModal.jsx
+++ b/project/src/components/NewLeaveRequestModal.jsx
@@ -24,6 +24,8 @@ const NewLeaveRequestModal = ({
const [error, setError] = useState('');
const [calculatedDays, setCalculatedDays] = useState(0);
const [isPreselected, setIsPreselected] = useState(false);
+ const [isOtherChecked, setIsOtherChecked] = useState(false);
+ const [otherLeaveType, setOtherLeaveType] = useState('');
// Vérifier si des valeurs sont pré-sélectionnées
useEffect(() => {
@@ -130,8 +132,36 @@ const NewLeaveRequestModal = ({
return { ...prev, types: newTypes };
});
setError('');
+
+ // Désélectionner le type "Autre" si un autre type est sélectionné
+
+ if (type !== 'Autres') {
+ setIsOtherChecked(false);
+ setOtherLeaveType('');
+ }
};
+ const handleOtherCheckboxChange = (e) => {
+ const isChecked = e.target.checked;
+ setIsOtherChecked(isChecked);
+
+ // Si la case est cochée, désélectionner les autres types
+ if (isChecked) {
+ setFormData(prev => ({ ...prev, types: ['Autres'] }));
+ } else {
+ // Si elle est décochée, vider le type et les documents
+ setOtherLeaveType('');
+ setFormData(prev => ({ ...prev, types: [] }));
+ }
+ setError('');
+ };
+
+ const handleOtherTypeChange = (e) => {
+ setOtherLeaveType(e.target.value);
+ setFormData(prev => ({ ...prev, types: [e.target.value] }));
+ };
+
+
const handleDistributionChange = (type, days) => {
setTypeDistribution(prev => ({
...prev,
@@ -183,6 +213,12 @@ const NewLeaveRequestModal = ({
setError('Impossible de faire une demande pour une date passée');
return false;
}
+ // Vérification de la sélection d'un type "autre"
+
+ if (isOtherChecked && !otherLeaveType) {
+ setError('Veuillez sélectionner un type de congé dans la liste "Autre"');
+ return false;
+ }
// Vérification de la distribution des jours
if (formData.types.length > 1) {
@@ -197,6 +233,12 @@ const NewLeaveRequestModal = ({
for (const type of formData.types) {
const requiredDays = formData.types.length > 1 ? (typeDistribution[type] || 0) : calculatedDays;
+ // Les types "autres" n'ont pas de solde à vérifier
+ const nonSoldeTypes = ['Récup', 'Congés sans solde', 'Congés pour évènement familial', 'Congé maternité', 'Congé paternité', 'Congé parental', 'Congé parental à temps partiel', 'Autres'];
+ if (nonSoldeTypes.includes(type)) {
+ continue;
+ }
+
if (type === 'CP' && requiredDays > availableLeaveCounters.availableCP) {
setError(`Solde CP insuffisant. Vous avez ${availableLeaveCounters.availableCP} jours disponibles`);
return false;
@@ -223,6 +265,8 @@ const NewLeaveRequestModal = ({
// Créer une demande pour chaque type de congé
const requests = formData.types.map(type => {
const days = formData.types.length > 1 ? (typeDistribution[type] || 0) : calculatedDays;
+ // Utiliser le type sélectionné dans la liste déroulante si "Autre" est coché
+ const finalType = type === 'Autres' ? otherLeaveType : type;
return {
EmployeeId: userId,
TypeConge: type,
@@ -325,6 +369,7 @@ const NewLeaveRequestModal = ({
)}
{/* Type de congé */}
+
))}
+ {/* Nouvelle case à cocher pour "Autre" */}
+
+
+
+ {/* Liste déroulante "Autre" conditionnelle */}
+ {isOtherChecked && (
+
+
+
+
+ )}
+
{/* Distribution des jours si plusieurs types sélectionnés */}
{formData.types.length > 1 && calculatedDays > 0 && (
diff --git a/project/src/pages/Calendar.jsx b/project/src/pages/Calendar.jsx
index 1a1a4f7..882fe9c 100644
--- a/project/src/pages/Calendar.jsx
+++ b/project/src/pages/Calendar.jsx
@@ -57,9 +57,9 @@ const Calendar = () => {
// Fallback avec quelques jours fériés fixes si l'API échoue
return [
{ date: new Date(year, 0, 1), name: 'Jour de l\'An' },
- { date: new Date(year, 4, 1), name: 'Fête du Travail' },
+ { date: new Date(year, 5, 1), name: 'Fête du Travail' },
{ date: new Date(year, 6, 14), name: 'Fête Nationale' },
- { date: new Date(year, 11, 25), name: 'Noël' }
+ { date: new Date(year, 12, 25), name: 'Noël' }
];
} finally {
setIsLoadingHolidays(false);
@@ -298,6 +298,89 @@ const Calendar = () => {
const days = getDaysInMonth(currentDate);
+ // Export CSV
+ const exportTeamLeavesToGoogleCSV = (teamLeaves) => {
+ const csvRows = [
+ ['Subject', 'Start Date', 'Start Time', 'End Date', 'End Time', 'All Day Event', 'Description', 'Location', 'Private'],
+ ...teamLeaves.map(leave => {
+ // Conversion date YYYY-MM-DD -> MM/DD/YYYY
+ const formatDate = dateStr => {
+ const [year, month, day] = dateStr.split('-');
+ return `${month}/${day}/${year}`;
+ };
+
+ return [
+ `Congé - ${leave.employee_name}`, // Subject
+ formatDate(leave.start_date), // Start Date
+ '', // Start Time (vide car congé toute la journée)
+ formatDate(leave.end_date), // End Date
+ '', // End Time
+ 'TRUE', // All Day Event
+ `Type de congé: ${leave.type}`, // Description
+ '', // Location vide
+ 'TRUE' // Privé
+ ];
+ })
+ ];
+
+ const csvContent = csvRows.map(row => row.join(',')).join('\n');
+
+ // Ajouter BOM UTF-8 pour Excel/Google Sheets
+ const BOM = '\uFEFF';
+ const blob = new Blob([BOM + csvContent], { type: 'text/csv;charset=utf-8;' });
+
+ const url = URL.createObjectURL(blob);
+
+ const link = document.createElement('a');
+ link.setAttribute('href', url);
+ link.setAttribute('download', 'conges_equipe_googleagenda.csv');
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ };
+
+
+
+ // Export ICS
+ const exportTeamLeavesToICS = (teamLeaves) => {
+ const ICS_HEADER =
+ `BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//TonEntreprise//CongesEquipe//FR
+CALSCALE:GREGORIAN`;
+
+ const ICS_FOOTER = 'END:VCALENDAR';
+
+ const events = teamLeaves.map(leave => {
+ // Format date YYYYMMDD
+ const startDate = leave.start_date.replace(/-/g, '');
+ const endDate = leave.end_date.replace(/-/g, '');
+
+ return `BEGIN:VEVENT
+SUMMARY:Congé - ${leave.employee_name}
+DTSTART;VALUE=DATE:${startDate}
+DTEND;VALUE=DATE:${endDate}
+DESCRIPTION:Type de congé: ${leave.type}
+STATUS:CONFIRMED
+END:VEVENT`;
+ }).join('\n');
+
+ const icsContent = `${ICS_HEADER}\n${events}\n${ICS_FOOTER}`;
+
+ // Blob pour téléchargement
+ const blob = new Blob([icsContent], { type: 'text/calendar;charset=utf-8;' });
+ const url = URL.createObjectURL(blob);
+
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = 'conges_equipe.ics';
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ };
+
+
+
return (
setSidebarOpen(!sidebarOpen)} />
@@ -410,8 +493,8 @@ const Calendar = () => {
{
hasLeave(date) ? 'bg-green-100 text-green-800' :
'hover:bg-gray-50'
}
- ${isSelectingRange && selectedDate && !selectedEndDate && date && date > selectedDate && !isPastDate(date) && !isHoliday(date) ? 'bg-blue-50' : ''}
- `}
+ ${isSelectingRange && selectedDate && !selectedEndDate && date && date > selectedDate && !isPastDate(date) && !isHoliday(date) ? 'bg-blue-50' : ''}
+ `}
onClick={() => handleDateClick(date)}
onContextMenu={(e) => handleContextMenu(e, date)}
title={isHoliday(date) ? getHolidayName(date) : ''}
>
{date && (
-
+
+ {/* Date number */}
{date.getDate()}
+
+
{isHoliday(date) && getHolidayName(date) && (
-
- {getHolidayName(date).length > 8 ? getHolidayName(date).substring(0, 8) + '...' : getHolidayName(date)}
-
+
+ {getHolidayName(date)}
+
)}
+
+
+ {/* Leave info: names of employees with leave */}
{hasLeave(date) && (
-
+
+ {teamLeaves
+ .filter(leave => {
+ const start = new Date(leave.start_date);
+ const end = new Date(leave.end_date);
+ return date >= start && date <= end;
+ })
+ .map((leave, i) => (
+
+ {/* Optional colored dot for leave type */}
+
+
+ {leave.employee_name}
+
+
+
+ ))}
+
)}
)}
))}
-
+
{/* Legend */}
@@ -518,6 +631,19 @@ const Calendar = () => {
)}
+ {/* button csv */}
+
+
+
+
+
+
+ {/* Ton rendu de calendrier ici */}
+
{/* Modal nouvelle demande */}
{showNewRequestModal && (
diff --git a/project/src/pages/Requests.jsx b/project/src/pages/Requests.jsx
index 1520bb2..edcdee7 100644
--- a/project/src/pages/Requests.jsx
+++ b/project/src/pages/Requests.jsx
@@ -52,7 +52,12 @@ const Requests = () => {
// Filtre par type
if (typeFilter !== 'all') {
- filtered = filtered.filter(request => request.type === typeFilter);
+ if (typeFilter === 'Autres') {
+ const otherTypes = ['Récup', 'Congés sans solde', 'Congés pour évènement familial', 'Congé maternité', 'Congé paternité', 'Congé parental', 'Congé parental à temps partiel'];
+ filtered = filtered.filter(request => otherTypes.includes(request.type));
+ } else {
+ filtered = filtered.filter(request => request.type === typeFilter);
+ }
}
setFilteredRequests(filtered);
@@ -84,7 +89,7 @@ const Requests = () => {
};
const fetchAllRequests = async () => {
- console.log('🔍 Requests - Début fetchAllRequests pour user:', user?.id);
+ console.log('Requests - Début fetchAllRequests pour user:', user?.id);
try {
const url = `http://localhost/GTA/project/public/getRequests.php?user_id=${user.id}`;
@@ -381,6 +386,7 @@ const Requests = () => {
+ {/* Nouvelle option */}