Les filtreCollaborateur case rh/president et directeur de campus
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
// Récupération des congés de l'équipe pour affichage dans le calendrier
|
|
||||||
header("Access-Control-Allow-Origin: *");
|
header("Access-Control-Allow-Origin: *");
|
||||||
header("Access-Control-Allow-Methods: GET, OPTIONS");
|
header("Access-Control-Allow-Methods: GET, OPTIONS");
|
||||||
header("Access-Control-Allow-Headers: Content-Type");
|
header("Access-Control-Allow-Headers: Content-Type");
|
||||||
@@ -11,7 +10,6 @@ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
|||||||
|
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
// Log des erreurs pour debug
|
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
@@ -22,93 +20,214 @@ $username = "wpuser";
|
|||||||
$password = "-2b/)ru5/Bi8P[7_";
|
$password = "-2b/)ru5/Bi8P[7_";
|
||||||
|
|
||||||
$conn = new mysqli($host, $username, $password, $dbname);
|
$conn = new mysqli($host, $username, $password, $dbname);
|
||||||
|
|
||||||
if ($conn->connect_error) {
|
if ($conn->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"]);
|
echo json_encode(["success" => false, "message" => "Erreur de connexion à la base de données"]);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On récupère le rôle directement depuis la requête GET pour la logique PHP
|
||||||
$userId = $_GET['user_id'] ?? null;
|
$userId = $_GET['user_id'] ?? null;
|
||||||
|
$role = strtolower($_GET['role'] ?? 'collaborateur');
|
||||||
|
|
||||||
if ($userId === null) {
|
if ($userId === null) {
|
||||||
echo json_encode(["success" => false, "message" => "ID utilisateur manquant"]);
|
echo json_encode(["success" => false, "message" => "ID utilisateur manquant"]);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
error_log("getTeamLeaves - User ID: $userId");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Récupérer le service de l'utilisateur
|
// 🔹 Infos utilisateur
|
||||||
$queryUserService = "SELECT ServiceId FROM Users WHERE ID = ?";
|
$queryUser = "
|
||||||
$stmtUser = $conn->prepare($queryUserService);
|
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->bind_param("i", $userId);
|
||||||
$stmtUser->execute();
|
$stmtUser->execute();
|
||||||
$resultUser = $stmtUser->get_result();
|
$resultUser = $stmtUser->get_result();
|
||||||
|
|
||||||
if ($userRow = $resultUser->fetch_assoc()) {
|
if (!$userRow = $resultUser->fetch_assoc()) {
|
||||||
$serviceId = $userRow['ServiceId'];
|
echo json_encode(["success" => false, "message" => "Collaborateur non trouvé"]);
|
||||||
error_log("getTeamLeaves - Service ID: $serviceId");
|
exit();
|
||||||
|
|
||||||
// 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é"
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmtUser->close();
|
$serviceId = $userRow['ServiceId'];
|
||||||
|
$campusId = $userRow['CampusId'];
|
||||||
} catch (Exception $e) {
|
$societeId = $userRow['SocieteId'];
|
||||||
error_log("Erreur getTeamLeaves: " . $e->getMessage());
|
|
||||||
|
// -------------------------
|
||||||
|
// 🔹 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([
|
echo json_encode([
|
||||||
"success" => false,
|
"success" => true,
|
||||||
"message" => "Erreur lors de la récupération des congés: " . $e->getMessage()
|
"role" => $role,
|
||||||
|
"leaves" => $leaves,
|
||||||
|
"filters" => $filters
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$stmtLeaves->close();
|
||||||
|
$stmtUser->close();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(["success" => false, "message" => "Erreur: " . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$conn->close();
|
$conn->close();
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import NewLeaveRequestModal from '../components/NewLeaveRequestModal';
|
|||||||
|
|
||||||
const Calendar = () => {
|
const Calendar = () => {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
// Juste après const { user } = useAuth();
|
||||||
|
const role = user?.role?.toLowerCase();
|
||||||
|
|
||||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
const [currentDate, setCurrentDate] = useState(new Date());
|
const [currentDate, setCurrentDate] = useState(new Date());
|
||||||
const [selectedDate, setSelectedDate] = useState(null);
|
const [selectedDate, setSelectedDate] = useState(null);
|
||||||
@@ -22,6 +25,13 @@ const Calendar = () => {
|
|||||||
availableABS: 0
|
availableABS: 0
|
||||||
});
|
});
|
||||||
const [teamLeaves, setTeamLeaves] = useState([]);
|
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 = [
|
const monthNames = [
|
||||||
'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
|
'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
|
||||||
@@ -30,6 +40,15 @@ const Calendar = () => {
|
|||||||
|
|
||||||
const dayNames = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven'];
|
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
|
// Récupération des jours fériés depuis l'API gouvernementale française
|
||||||
const fetchFrenchHolidays = async (year) => {
|
const fetchFrenchHolidays = async (year) => {
|
||||||
try {
|
try {
|
||||||
@@ -66,6 +85,7 @@ const Calendar = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Charger les jours fériés au montage du composant et lors du changement d'année
|
// Charger les jours fériés au montage du composant et lors du changement d'année
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadHolidays = async () => {
|
const loadHolidays = async () => {
|
||||||
@@ -88,10 +108,13 @@ const Calendar = () => {
|
|||||||
const loadTeamLeaves = async () => {
|
const loadTeamLeaves = async () => {
|
||||||
if (user?.id) {
|
if (user?.id) {
|
||||||
try {
|
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();
|
const data = await response.json();
|
||||||
|
console.log("📡 Réponse API :", data);
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
setTeamLeaves(data.leaves || []);
|
setTeamLeaves(data.leaves || []);
|
||||||
|
setFilters(data.filters || {});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erreur récupération congés équipe:', error);
|
console.error('Erreur récupération congés équipe:', error);
|
||||||
@@ -143,6 +166,25 @@ const Calendar = () => {
|
|||||||
|
|
||||||
return days;
|
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) => {
|
const navigateMonth = (direction) => {
|
||||||
setCurrentDate(prev => {
|
setCurrentDate(prev => {
|
||||||
@@ -289,13 +331,18 @@ const Calendar = () => {
|
|||||||
if (!date) return false;
|
if (!date) return false;
|
||||||
|
|
||||||
// Vérifier les congés de l'équipe
|
// Vérifier les congés de l'équipe
|
||||||
return teamLeaves.some(leave => {
|
return filteredLeaves.some(leave => {
|
||||||
const startDate = new Date(leave.start_date);
|
const startDate = parseLocalDate(leave.start_date);
|
||||||
const endDate = new Date(leave.end_date);
|
const endDate = parseLocalDate(leave.end_date);
|
||||||
return date >= startDate && date <= endDate;
|
return date >= startDate && date <= endDate;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const days = getDaysInMonth(currentDate);
|
const days = getDaysInMonth(currentDate);
|
||||||
|
|
||||||
// Export CSV
|
// Export CSV
|
||||||
@@ -305,8 +352,8 @@ const Calendar = () => {
|
|||||||
...teamLeaves.map(leave => {
|
...teamLeaves.map(leave => {
|
||||||
// Conversion date YYYY-MM-DD -> MM/DD/YYYY
|
// Conversion date YYYY-MM-DD -> MM/DD/YYYY
|
||||||
const formatDate = dateStr => {
|
const formatDate = dateStr => {
|
||||||
const [year, month, day] = dateStr.split('-');
|
const d = parseLocalDate(dateStr);
|
||||||
return `${month}/${day}/${year}`;
|
return `${(d.getMonth() + 1).toString().padStart(2, '0')}/${d.getDate().toString().padStart(2, '0')}/${d.getFullYear()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -420,6 +467,105 @@ END:VEVENT`;
|
|||||||
<span className="hidden sm:inline">Nouvelle demande</span>
|
<span className="hidden sm:inline">Nouvelle demande</span>
|
||||||
<span className="sm:hidden">Nouveau</span>
|
<span className="sm:hidden">Nouveau</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{/* Filtres dynamiques en fonction du rôle */}
|
||||||
|
{["collaborateur", "validateur"].includes(role) && (
|
||||||
|
<div className="flex items-center bg-white border border-gray-200 rounded-lg shadow-sm px-3 py-2">
|
||||||
|
<label className="mr-2 text-sm font-medium text-gray-700">Collaborateur :</label>
|
||||||
|
<select
|
||||||
|
value={employeeFilter}
|
||||||
|
onChange={(e) => setEmployeeFilter(e.target.value)}
|
||||||
|
className="bg-transparent focus:outline-none text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<option value="">Sélectionner un collaborateur</option>
|
||||||
|
<option value="all">Tous</option>
|
||||||
|
{filters.employees?.map((name, i) => (
|
||||||
|
<option key={i} value={name}>{name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{role === "directeur de campus" && (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center bg-white border border-gray-200 rounded-lg shadow-sm px-3 py-2">
|
||||||
|
<label className="mr-2 text-sm font-medium text-gray-700">Société :</label>
|
||||||
|
<select
|
||||||
|
value={selectedSociete}
|
||||||
|
onChange={(e) => setSelectedSociete(e.target.value)}
|
||||||
|
className="bg-transparent focus:outline-none text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<option value="">Sélectionner une société</option>
|
||||||
|
<option value="all">Toutes</option>
|
||||||
|
{filters.societes?.map((soc, i) => (
|
||||||
|
<option key={i} value={soc}>{soc}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center bg-white border border-gray-200 rounded-lg shadow-sm px-3 py-2">
|
||||||
|
<label className="mr-2 text-sm font-medium text-gray-700">Service :</label>
|
||||||
|
<select
|
||||||
|
value={selectedService}
|
||||||
|
onChange={(e) => setSelectedService(e.target.value)}
|
||||||
|
className="bg-transparent focus:outline-none text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<option value="">Sélectionner un service</option>
|
||||||
|
<option value="all">Tous</option>
|
||||||
|
{filters.services?.map((srv, i) => (
|
||||||
|
<option key={i} value={srv}>{srv}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{["president", "rh"].includes(role) && (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center bg-white border border-gray-200 rounded-lg shadow-sm px-3 py-2">
|
||||||
|
<label className="mr-2 text-sm font-medium text-gray-700">Campus :</label>
|
||||||
|
<select
|
||||||
|
value={selectedCampus}
|
||||||
|
onChange={(e) => setSelectedCampus(e.target.value)}
|
||||||
|
className="bg-transparent focus:outline-none text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<option value="">Sélectionner un campus</option>
|
||||||
|
<option value="all">Tous</option>
|
||||||
|
{filters.campus?.map((camp, i) => (
|
||||||
|
<option key={i} value={camp}>{camp}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center bg-white border border-gray-200 rounded-lg shadow-sm px-3 py-2">
|
||||||
|
<label className="mr-2 text-sm font-medium text-gray-700">Société :</label>
|
||||||
|
<select
|
||||||
|
value={selectedSociete}
|
||||||
|
onChange={(e) => setSelectedSociete(e.target.value)}
|
||||||
|
className="bg-transparent focus:outline-none text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<option value="">Sélectionner une société</option>
|
||||||
|
<option value="all">Toutes</option>
|
||||||
|
{filters.societes?.map((soc, i) => (
|
||||||
|
<option key={i} value={soc}>{soc}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center bg-white border border-gray-200 rounded-lg shadow-sm px-3 py-2">
|
||||||
|
<label className="mr-2 text-sm font-medium text-gray-700">Service :</label>
|
||||||
|
<select
|
||||||
|
value={selectedService}
|
||||||
|
onChange={(e) => setSelectedService(e.target.value)}
|
||||||
|
className="bg-transparent focus:outline-none text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<option value="">Sélectionner un service</option>
|
||||||
|
<option value="all">Tous</option>
|
||||||
|
{filters.services?.map((srv, i) => (
|
||||||
|
<option key={i} value={srv}>{srv}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -524,27 +670,29 @@ END:VEVENT`;
|
|||||||
{/* Leave info: names of employees with leave */}
|
{/* Leave info: names of employees with leave */}
|
||||||
{hasLeave(date) && (
|
{hasLeave(date) && (
|
||||||
<div className="mt-1 flex flex-col items-center space-y-0.5 text-[10px] lg:text-xs text-green-700 text-center leading-tight">
|
<div className="mt-1 flex flex-col items-center space-y-0.5 text-[10px] lg:text-xs text-green-700 text-center leading-tight">
|
||||||
{teamLeaves
|
{filteredLeaves
|
||||||
.filter(leave => {
|
.filter(leave => {
|
||||||
const start = new Date(leave.start_date);
|
const start = parseLocalDate(leave.start_date);
|
||||||
const end = new Date(leave.end_date);
|
const end = parseLocalDate(leave.end_date);
|
||||||
return date >= start && date <= end;
|
return date >= start && date <= end;
|
||||||
})
|
})
|
||||||
.map((leave, i) => (
|
.map((leave, i) => (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
title={`${leave.employee_name} - ${leave.type}`}
|
title={`${leave.employee_name} - ${leave.type}${["president", "rh", "directeur de campus"].includes(role)
|
||||||
className="flex items-center gap-1"
|
? ` - ${leave.campus_nom} / ${leave.societe_nom} / ${leave.service_nom}`
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
className="flex flex-col items-center gap-1"
|
||||||
>
|
>
|
||||||
{/* Optional colored dot for leave type */}
|
|
||||||
<span
|
|
||||||
className="inline-block w-2 h-2 rounded-full"
|
|
||||||
style={{ backgroundColor: leave.color || '#3B82F6' }}
|
|
||||||
></span>
|
|
||||||
<span className="text-[10px] lg:text-xs text-green-800 leading-tight break-words text-center">
|
<span className="text-[10px] lg:text-xs text-green-800 leading-tight break-words text-center">
|
||||||
{leave.employee_name}
|
{leave.employee_name}
|
||||||
|
{["president", "rh", "directeur de campus"].includes(role) && (
|
||||||
|
<span className="text-[9px] text-gray-600 block">
|
||||||
|
{leave.campus_nom} / {leave.societe_nom} / {leave.service_nom}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user