From 34a369dccd356cd4a0ba48a8603d4bce408f271f Mon Sep 17 00:00:00 2001 From: Ouijdane IMER Date: Fri, 29 Aug 2025 15:12:21 +0200 Subject: [PATCH] Les filtreCollaborateur case rh/president et directeur de campus --- project/public/php/getTeamLeaves.php | 259 +++++++++++++++++++-------- project/src/pages/Calendar.jsx | 182 +++++++++++++++++-- 2 files changed, 354 insertions(+), 87 deletions(-) diff --git a/project/public/php/getTeamLeaves.php b/project/public/php/getTeamLeaves.php index bdda57e..15e076c 100644 --- a/project/public/php/getTeamLeaves.php +++ b/project/public/php/getTeamLeaves.php @@ -1,5 +1,4 @@ connect_error) { - error_log("Erreur connexion DB getTeamLeaves: " . $conn->connect_error); echo json_encode(["success" => false, "message" => "Erreur de connexion à la base de données"]); exit(); } +// On récupère le rôle directement depuis la requête GET pour la logique PHP $userId = $_GET['user_id'] ?? null; +$role = strtolower($_GET['role'] ?? 'collaborateur'); if ($userId === null) { echo json_encode(["success" => false, "message" => "ID utilisateur manquant"]); exit(); } -error_log("getTeamLeaves - User ID: $userId"); - try { - // Récupérer le service de l'utilisateur - $queryUserService = "SELECT ServiceId FROM Users WHERE ID = ?"; - $stmtUser = $conn->prepare($queryUserService); + // 🔹 Infos utilisateur + $queryUser = " + SELECT ca.ServiceId, sa.CampusId, sa.SocieteId, + s.Nom as service_nom, c.Nom as campus_nom, so.Nom as societe_nom + FROM CollaborateurAD ca + JOIN ServiceAffectation sa ON sa.ServiceId = ca.ServiceId + JOIN Services s ON ca.ServiceId = s.Id + JOIN Campus c ON sa.CampusId = c.Id + JOIN Societe so ON sa.SocieteId = so.Id + WHERE ca.id = ? + LIMIT 1 + "; + $stmtUser = $conn->prepare($queryUser); $stmtUser->bind_param("i", $userId); $stmtUser->execute(); $resultUser = $stmtUser->get_result(); - - if ($userRow = $resultUser->fetch_assoc()) { - $serviceId = $userRow['ServiceId']; - error_log("getTeamLeaves - Service ID: $serviceId"); - - // Récupérer les congés validés de l'équipe (même service) - $queryLeaves = " - SELECT - dc.DateDebut as start_date, - dc.DateFin as end_date, - CONCAT(u.Prenom, ' ', u.Nom) as employee_name, - tc.Nom as type, - tc.CouleurHex as color - FROM DemandeConge dc - JOIN Users u ON dc.EmployeeId = u.ID - JOIN TypeConge tc ON dc.TypeCongeId = tc.Id - WHERE u.ServiceId = ? - AND dc.Statut = 'Validée' - AND dc.DateFin >= CURDATE() - INTERVAL 30 DAY - ORDER BY dc.DateDebut ASC - "; - - $stmtLeaves = $conn->prepare($queryLeaves); - $stmtLeaves->bind_param("i", $serviceId); - $stmtLeaves->execute(); - $resultLeaves = $stmtLeaves->get_result(); - - $leaves = []; - while ($row = $resultLeaves->fetch_assoc()) { - $leaves[] = [ - 'start_date' => $row['start_date'], - 'end_date' => $row['end_date'], - 'employee_name' => $row['employee_name'], - 'type' => $row['type'], - 'color' => $row['color'] ?? '#3B82F6' - ]; - } - - error_log("getTeamLeaves - Congés trouvés: " . count($leaves)); - - echo json_encode([ - "success" => true, - "message" => "Congés de l'équipe récupérés avec succès", - "leaves" => $leaves, - "service_id" => $serviceId - ]); - - $stmtLeaves->close(); - } else { - error_log("getTeamLeaves - Utilisateur non trouvé: $userId"); - echo json_encode([ - "success" => false, - "message" => "Utilisateur non trouvé" - ]); + + if (!$userRow = $resultUser->fetch_assoc()) { + echo json_encode(["success" => false, "message" => "Collaborateur non trouvé"]); + exit(); } - - $stmtUser->close(); - -} catch (Exception $e) { - error_log("Erreur getTeamLeaves: " . $e->getMessage()); + + $serviceId = $userRow['ServiceId']; + $campusId = $userRow['CampusId']; + $societeId = $userRow['SocieteId']; + + // ------------------------- + // 🔹 Construire la requête selon le rôle + // ------------------------- + switch ($role) { + case 'president': + case 'rh': + $queryLeaves = " + SELECT + DATE_FORMAT(dc.DateDebut, '%Y-%m-%d') as start_date, + DATE_FORMAT(dc.DateFin, '%Y-%m-%d') as end_date, + CONCAT(ca.prenom, ' ', ca.nom) as employee_name, + tc.Nom as type, + tc.CouleurHex as color, + s.Nom as service_nom, + c.Nom as campus_nom, + so.Nom as societe_nom + FROM DemandeConge dc + JOIN CollaborateurAD ca ON dc.CollaborateurADId = ca.id + JOIN TypeConge tc ON dc.TypeCongeId = tc.Id + JOIN ServiceAffectation sa ON sa.ServiceId = ca.ServiceId + JOIN Services s ON sa.ServiceId = s.Id + JOIN Campus c ON sa.CampusId = c.Id + JOIN Societe so ON sa.SocieteId = so.Id -- CORRIGÉ ICI + WHERE dc.Statut = 'Validée' + ORDER BY c.Nom, so.Nom, s.Nom, dc.DateDebut ASC + "; + $stmtLeaves = $conn->prepare($queryLeaves); + break; + + case 'directeur de campus': + $queryLeaves = " + SELECT + DATE_FORMAT(dc.DateDebut, '%Y-%m-%d') as start_date, + DATE_FORMAT(dc.DateFin, '%Y-%m-%d') as end_date, + CONCAT(ca.prenom, ' ', ca.nom) as employee_name, + tc.Nom as type, + tc.CouleurHex as color, + s.Nom as service_nom, + so.Nom as societe_nom, + c.Nom as campus_nom + FROM DemandeConge dc + JOIN CollaborateurAD ca ON dc.CollaborateurADId = ca.id + JOIN TypeConge tc ON dc.TypeCongeId = tc.Id + JOIN ServiceAffectation sa ON sa.ServiceId = ca.ServiceId + JOIN Services s ON sa.ServiceId = s.Id + JOIN Societe so ON sa.SocieteId = so.Id -- CORRIGÉ ICI + JOIN Campus c ON sa.CampusId = c.Id + WHERE sa.CampusId = ? + AND dc.Statut = 'Validée' + ORDER BY so.Nom, s.Nom, dc.DateDebut ASC + "; + $stmtLeaves = $conn->prepare($queryLeaves); + $stmtLeaves->bind_param("i", $campusId); + break; + + case 'validateur': + case 'collaborateur': + default: + $queryLeaves = " + SELECT + DATE_FORMAT(dc.DateDebut, '%Y-%m-%d') as start_date, + DATE_FORMAT(dc.DateFin, '%Y-%m-%d') as end_date, + CONCAT(ca.prenom, ' ', ca.nom) as employee_name, + tc.Nom as type, + tc.CouleurHex as color, + s.Nom as service_nom, + c.Nom as campus_nom, + so.Nom as societe_nom + FROM DemandeConge dc + JOIN CollaborateurAD ca ON dc.CollaborateurADId = ca.id + JOIN TypeConge tc ON dc.TypeCongeId = tc.Id + JOIN ServiceAffectation sa ON sa.ServiceId = ca.ServiceId + JOIN Services s ON sa.ServiceId = s.Id + JOIN Campus c ON sa.CampusId = c.Id + JOIN Societe so ON sa.SocieteId = so.Id -- CORRIGÉ ICI + WHERE ca.ServiceId = ? + AND sa.CampusId = ? + AND dc.Statut = 'Validée' + AND dc.DateFin >= CURDATE() - INTERVAL 30 DAY + ORDER BY dc.DateDebut ASC + "; + $stmtLeaves = $conn->prepare($queryLeaves); + $stmtLeaves->bind_param("ii", $serviceId, $campusId); + } + + $stmtLeaves->execute(); + $resultLeaves = $stmtLeaves->get_result(); + + $leaves = []; + while ($row = $resultLeaves->fetch_assoc()) { + $leaves[] = [ + 'start_date' => $row['start_date'], + 'end_date' => $row['end_date'], + 'employee_name' => $row['employee_name'], + 'type' => $row['type'], + 'color' => $row['color'] ?? '#3B82F6', + 'service_nom' => $row['service_nom'], + 'campus_nom' => $row['campus_nom'] ?? null, + 'societe_nom' => $row['societe_nom'] ?? null + ]; + } + + // ------------------------- + // 🔹 Construire les filtres dynamiques + // ------------------------- + $filters = []; + + if (in_array($role, ['collaborateur', 'validateur'])) { + $queryEmployees = " + SELECT CONCAT(ca.prenom, ' ', ca.nom) as employee_name + FROM CollaborateurAD ca + JOIN ServiceAffectation sa ON sa.ServiceId = ca.ServiceId + WHERE ca.ServiceId = ? + AND sa.CampusId = ? + ORDER BY ca.prenom, ca.nom + "; + $stmtEmployees = $conn->prepare($queryEmployees); + $stmtEmployees->bind_param("ii", $serviceId, $campusId); + $stmtEmployees->execute(); + $resultEmployees = $stmtEmployees->get_result(); + + $employees = []; + while ($row = $resultEmployees->fetch_assoc()) { + $employees[] = $row['employee_name']; + } + $filters['employees'] = $employees; + $stmtEmployees->close(); + + } elseif ($role === 'directeur de campus') { + + $filters['societes'] = []; + $filters['services'] = []; + $result = $conn->query("SELECT DISTINCT Nom as societe_nom FROM Societe ORDER BY societe_nom"); + while($row = $result->fetch_assoc()) $filters['societes'][] = $row['societe_nom']; + + $result = $conn->query("SELECT DISTINCT Nom as service_nom FROM Services ORDER BY service_nom"); + while($row = $result->fetch_assoc()) $filters['services'][] = $row['service_nom']; + + + } elseif (in_array($role, ['president', 'rh'])) { + // 🔹 Récupérer tous les campus, sociétés, services de manière unique + $filters['campus'] = []; + $filters['societes'] = []; + $filters['services'] = []; + + $result = $conn->query("SELECT DISTINCT Nom as campus_nom FROM Campus ORDER BY campus_nom"); + while($row = $result->fetch_assoc()) $filters['campus'][] = $row['campus_nom']; + + $result = $conn->query("SELECT DISTINCT Nom as societe_nom FROM Societe ORDER BY societe_nom"); + while($row = $result->fetch_assoc()) $filters['societes'][] = $row['societe_nom']; + + $result = $conn->query("SELECT DISTINCT Nom as service_nom FROM Services ORDER BY service_nom"); + while($row = $result->fetch_assoc()) $filters['services'][] = $row['service_nom']; +} + echo json_encode([ - "success" => false, - "message" => "Erreur lors de la récupération des congés: " . $e->getMessage() + "success" => true, + "role" => $role, + "leaves" => $leaves, + "filters" => $filters ]); + + $stmtLeaves->close(); + $stmtUser->close(); + +} catch (Exception $e) { + echo json_encode(["success" => false, "message" => "Erreur: " . $e->getMessage()]); } $conn->close(); diff --git a/project/src/pages/Calendar.jsx b/project/src/pages/Calendar.jsx index 9aedab4..48ee9a8 100644 --- a/project/src/pages/Calendar.jsx +++ b/project/src/pages/Calendar.jsx @@ -6,6 +6,9 @@ import NewLeaveRequestModal from '../components/NewLeaveRequestModal'; const Calendar = () => { const { user } = useAuth(); + // Juste après const { user } = useAuth(); + const role = user?.role?.toLowerCase(); + const [sidebarOpen, setSidebarOpen] = useState(false); const [currentDate, setCurrentDate] = useState(new Date()); const [selectedDate, setSelectedDate] = useState(null); @@ -22,6 +25,13 @@ const Calendar = () => { availableABS: 0 }); const [teamLeaves, setTeamLeaves] = useState([]); + const [filters, setFilters] = useState({}); + + // Valeurs sélectionnées dans les filtres + const [employeeFilter, setEmployeeFilter] = useState(""); + const [selectedCampus, setSelectedCampus] = useState(""); + const [selectedSociete, setSelectedSociete] = useState(""); + const [selectedService, setSelectedService] = useState(""); const monthNames = [ 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', @@ -30,6 +40,15 @@ const Calendar = () => { const dayNames = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven']; + + // Convertir YYYY-MM-DD en Date locale (évite le décalage UTC) + const parseLocalDate = (dateStr) => { + if (!dateStr) return null; + const [year, month, day] = dateStr.split('-').map(Number); + return new Date(year, month - 1, day); // mois = 0-11 + }; + + // Récupération des jours fériés depuis l'API gouvernementale française const fetchFrenchHolidays = async (year) => { try { @@ -66,6 +85,7 @@ const Calendar = () => { } }; + // Charger les jours fériés au montage du composant et lors du changement d'année useEffect(() => { const loadHolidays = async () => { @@ -88,10 +108,13 @@ const Calendar = () => { const loadTeamLeaves = async () => { if (user?.id) { try { - const response = await fetch(`http://localhost/GTA/project/public/php/getTeamLeaves.php?user_id=${user.id}`); + + const response = await fetch(`http://localhost/GTA/project/public/php/getTeamLeaves.php?user_id=${user.id}&role=${user.role}`); const data = await response.json(); + console.log("📡 Réponse API :", data); if (data.success) { setTeamLeaves(data.leaves || []); + setFilters(data.filters || {}); } } catch (error) { console.error('Erreur récupération congés équipe:', error); @@ -143,6 +166,25 @@ const Calendar = () => { return days; }; + + + const filteredLeaves = teamLeaves.filter(leave => { + if (["collaborateur", "validateur"].includes(role)) { + if (employeeFilter !== "all" && leave.employee_name !== employeeFilter) return false; + } + if (role === "directeur de campus") { + if (selectedSociete !== "all" && leave.societe_nom !== selectedSociete) return false; + if (selectedService !== "all" && leave.service_nom !== selectedService) return false; + } + if (["president", "rh"].includes(role)) { + if (selectedCampus !== "all" && leave.campus_nom !== selectedCampus) return false; + if (selectedSociete !== "all" && leave.societe_nom !== selectedSociete) return false; + if (selectedService !== "all" && leave.service_nom !== selectedService) return false; + } + return true; + }); + + const navigateMonth = (direction) => { setCurrentDate(prev => { @@ -289,13 +331,18 @@ const Calendar = () => { if (!date) return false; // Vérifier les congés de l'équipe - return teamLeaves.some(leave => { - const startDate = new Date(leave.start_date); - const endDate = new Date(leave.end_date); + return filteredLeaves.some(leave => { + const startDate = parseLocalDate(leave.start_date); + const endDate = parseLocalDate(leave.end_date); return date >= startDate && date <= endDate; }); }; + + + + + const days = getDaysInMonth(currentDate); // Export CSV @@ -305,8 +352,8 @@ const Calendar = () => { ...teamLeaves.map(leave => { // Conversion date YYYY-MM-DD -> MM/DD/YYYY const formatDate = dateStr => { - const [year, month, day] = dateStr.split('-'); - return `${month}/${day}/${year}`; + const d = parseLocalDate(dateStr); + return `${(d.getMonth() + 1).toString().padStart(2, '0')}/${d.getDate().toString().padStart(2, '0')}/${d.getFullYear()}`; }; return [ @@ -420,6 +467,105 @@ END:VEVENT`; Nouvelle demande Nouveau + + {/* Filtres dynamiques en fonction du rôle */} + {["collaborateur", "validateur"].includes(role) && ( +
+ + +
+ )} + + {role === "directeur de campus" && ( + <> +
+ + +
+
+ + +
+ + )} + + {["president", "rh"].includes(role) && ( + <> +
+ + +
+
+ + +
+
+ + +
+ + )} + @@ -524,27 +670,29 @@ END:VEVENT`; {/* Leave info: names of employees with leave */} {hasLeave(date) && (
- {teamLeaves + {filteredLeaves .filter(leave => { - const start = new Date(leave.start_date); - const end = new Date(leave.end_date); + const start = parseLocalDate(leave.start_date); + const end = parseLocalDate(leave.end_date); return date >= start && date <= end; }) .map((leave, i) => (
- {/* Optional colored dot for leave type */} - {leave.employee_name} + {["president", "rh", "directeur de campus"].includes(role) && ( + + {leave.campus_nom} / {leave.societe_nom} / {leave.service_nom} + + )} -
))}