Les filtreCollaborateur case rh/president et directeur de campus
This commit is contained in:
@@ -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`;
|
||||
<span className="hidden sm:inline">Nouvelle demande</span>
|
||||
<span className="sm:hidden">Nouveau</span>
|
||||
</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>
|
||||
|
||||
@@ -524,27 +670,29 @@ END:VEVENT`;
|
||||
{/* Leave info: names of employees with leave */}
|
||||
{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">
|
||||
{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) => (
|
||||
<div
|
||||
key={i}
|
||||
title={`${leave.employee_name} - ${leave.type}`}
|
||||
className="flex items-center gap-1"
|
||||
title={`${leave.employee_name} - ${leave.type}${["president", "rh", "directeur de campus"].includes(role)
|
||||
? ` - ${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">
|
||||
{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>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user