feat: Ajouter filtre multi-mois pour les contrats CDDU
- Ajouter un bouton de filtre rapide 'Multi-mois' dans la page staff/contrats - Le filtre affiche uniquement les contrats CDDU dont la date de début et la date de fin sont sur des mois calendaires différents - Ajout d'un compteur en temps réel pour afficher le nombre de contrats multi-mois - Le filtre est persisté dans le localStorage comme les autres filtres - Utilise une icône Calendar de Lucide React et une couleur violette (purple)
This commit is contained in:
parent
b89d26d26e
commit
18edf3b9b0
2 changed files with 113 additions and 6 deletions
|
|
@ -226,11 +226,13 @@ export type ContractsGridHandle = {
|
|||
quickFilterPaieATraiterToutes: () => void;
|
||||
quickFilterNonSignesDateProche: () => void;
|
||||
quickFilterContratsEnCours: () => void;
|
||||
quickFilterMultiMois: () => void;
|
||||
getCountDpaeAFaire: () => number | null;
|
||||
getCountContratsAFaireMois: () => number | null;
|
||||
getCountPaieATraiterMoisDernier: () => number | null;
|
||||
getCountPaieATraiterToutes: () => number | null;
|
||||
getCountNonSignesDateProche: () => number | null;
|
||||
getCountMultiMois: () => number | null;
|
||||
};
|
||||
|
||||
function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract[]; activeOrgId?: string | null }, ref: React.ForwardedRef<ContractsGridHandle>) {
|
||||
|
|
@ -278,6 +280,7 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
const [etatPaieFilter, setEtatPaieFilter] = useState<string | null>(savedFilters?.etatPaieFilter || null);
|
||||
const [dpaeFilter, setDpaeFilter] = useState<string | null>(savedFilters?.dpaeFilter || null);
|
||||
const [signatureFilter, setSignatureFilter] = useState<string | null>(savedFilters?.signatureFilter || null);
|
||||
const [multiMoisFilter, setMultiMoisFilter] = useState<boolean>(savedFilters?.multiMoisFilter || false);
|
||||
const [startFrom, setStartFrom] = useState<string | null>(savedFilters?.startFrom || null);
|
||||
const [startTo, setStartTo] = useState<string | null>(savedFilters?.startTo || null);
|
||||
const [endFrom, setEndFrom] = useState<string | null>(savedFilters?.endFrom || null);
|
||||
|
|
@ -314,6 +317,7 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
const [countPaieATraiterMoisDernier, setCountPaieATraiterMoisDernier] = useState<number | null>(null);
|
||||
const [countPaieATraiterToutes, setCountPaieATraiterToutes] = useState<number | null>(null);
|
||||
const [countContratsNonSignesDateProche, setCountContratsNonSignesDateProche] = useState<number | null>(null);
|
||||
const [countMultiMois, setCountMultiMois] = useState<number | null>(null);
|
||||
|
||||
// PDF generation state
|
||||
const [isGeneratingPdfs, setIsGeneratingPdfs] = useState(false);
|
||||
|
|
@ -494,6 +498,26 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
setSortOrder('asc');
|
||||
};
|
||||
|
||||
const applyQuickFilterMultiMois = () => {
|
||||
// Contrats multi-mois : CDDU dont la date de début et la date de fin ne sont pas sur le même mois calendaire
|
||||
// Reset tous les filtres pour voir uniquement ce filtre rapide
|
||||
setQ(""); // Reset recherche
|
||||
setStructureFilter(null); // Reset organisation
|
||||
setTypeFilter('CDDU'); // Uniquement les CDDU
|
||||
setProductionFilter(null); // Reset production
|
||||
setSignatureFilter(null); // Tous les contrats
|
||||
setEtatPaieFilter(null); // Reset état paie
|
||||
setEtatContratFilters(new Set()); // Reset état contrat
|
||||
setDpaeFilter(null); // Reset DPAE
|
||||
setMultiMoisFilter(true); // Activer le filtre multi-mois
|
||||
setStartFrom(null);
|
||||
setStartTo(null);
|
||||
setEndFrom(null);
|
||||
setEndTo(null);
|
||||
setSortField('start_date');
|
||||
setSortOrder('desc');
|
||||
};
|
||||
|
||||
// Expose imperative handlers to parent wrappers
|
||||
useImperativeHandle(ref, () => ({
|
||||
quickFilterDpaeAFaire: applyQuickFilterDpaeAFaire,
|
||||
|
|
@ -502,12 +526,14 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
quickFilterPaieATraiterToutes: applyQuickFilterPaieATraiterToutes,
|
||||
quickFilterNonSignesDateProche: applyQuickFilterNonSignesDateProche,
|
||||
quickFilterContratsEnCours: applyQuickFilterContratsEnCours,
|
||||
quickFilterMultiMois: applyQuickFilterMultiMois,
|
||||
getCountDpaeAFaire: () => countDpaeAFaire,
|
||||
getCountContratsAFaireMois: () => countContratsAFaireMois,
|
||||
getCountPaieATraiterMoisDernier: () => countPaieATraiterMoisDernier,
|
||||
getCountPaieATraiterToutes: () => countPaieATraiterToutes,
|
||||
getCountNonSignesDateProche: () => countContratsNonSignesDateProche,
|
||||
}), [applyQuickFilterDpaeAFaire, applyQuickFilterContratsAFaireMois, applyQuickFilterPaieATraiterMoisDernier, applyQuickFilterPaieATraiterToutes, applyQuickFilterNonSignesDateProche, applyQuickFilterContratsEnCours, countDpaeAFaire, countContratsAFaireMois, countPaieATraiterMoisDernier, countPaieATraiterToutes, countContratsNonSignesDateProche]);
|
||||
getCountMultiMois: () => countMultiMois,
|
||||
}), [applyQuickFilterDpaeAFaire, applyQuickFilterContratsAFaireMois, applyQuickFilterPaieATraiterMoisDernier, applyQuickFilterPaieATraiterToutes, applyQuickFilterNonSignesDateProche, applyQuickFilterContratsEnCours, applyQuickFilterMultiMois, countDpaeAFaire, countContratsAFaireMois, countPaieATraiterMoisDernier, countPaieATraiterToutes, countContratsNonSignesDateProche, countMultiMois]);
|
||||
|
||||
// Save filters to localStorage whenever they change
|
||||
useEffect(() => {
|
||||
|
|
@ -520,6 +546,7 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
etatPaieFilter,
|
||||
dpaeFilter,
|
||||
signatureFilter,
|
||||
multiMoisFilter,
|
||||
startFrom,
|
||||
startTo,
|
||||
endFrom,
|
||||
|
|
@ -529,7 +556,7 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
showFilters
|
||||
};
|
||||
saveFiltersToStorage(filters);
|
||||
}, [q, structureFilter, typeFilter, productionFilter, etatContratFilters, etatPaieFilter, dpaeFilter, signatureFilter, startFrom, startTo, endFrom, endTo, sortField, sortOrder, showFilters]);
|
||||
}, [q, structureFilter, typeFilter, productionFilter, etatContratFilters, etatPaieFilter, dpaeFilter, signatureFilter, multiMoisFilter, startFrom, startTo, endFrom, endTo, sortField, sortOrder, showFilters]);
|
||||
|
||||
// Réinitialiser le filtre de production quand la structure change
|
||||
useEffect(() => {
|
||||
|
|
@ -733,16 +760,37 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
|
||||
// Apply local sorting when using initial data
|
||||
const sortedRows = useMemo(() => {
|
||||
const noFilters = !q && !structureFilter && !typeFilter && !productionFilter && etatContratFilters.size === 0 && !etatPaieFilter && !dpaeFilter && !signatureFilter && !startFrom && !startTo && !endFrom && !endTo;
|
||||
const noFilters = !q && !structureFilter && !typeFilter && !productionFilter && etatContratFilters.size === 0 && !etatPaieFilter && !dpaeFilter && !signatureFilter && !startFrom && !startTo && !endFrom && !endTo && !multiMoisFilter;
|
||||
|
||||
let filteredRows = rows;
|
||||
|
||||
// Appliquer le filtre multi-mois côté client si activé
|
||||
if (multiMoisFilter) {
|
||||
filteredRows = rows.filter(contract => {
|
||||
if (!contract.start_date || !contract.end_date) return false;
|
||||
|
||||
const startDate = new Date(contract.start_date);
|
||||
const endDate = new Date(contract.end_date);
|
||||
|
||||
// Vérifier si les mois ou les années sont différents
|
||||
return startDate.getMonth() !== endDate.getMonth() ||
|
||||
startDate.getFullYear() !== endDate.getFullYear();
|
||||
});
|
||||
}
|
||||
|
||||
if (noFilters) {
|
||||
// Utiliser le tri local pour les données initiales
|
||||
return sortContractsLocally(rows, sortField, sortOrder);
|
||||
return sortContractsLocally(filteredRows, sortField, sortOrder);
|
||||
}
|
||||
|
||||
// Pour les données filtrées, utiliser les données telles qu'elles viennent du serveur
|
||||
return rows;
|
||||
}, [rows, sortField, sortOrder, q, structureFilter, typeFilter, productionFilter, etatContratFilters, etatPaieFilter, dpaeFilter, signatureFilter, startFrom, startTo, endFrom, endTo]);
|
||||
// mais appliquer le tri local car nous avons potentiellement filtré côté client
|
||||
if (multiMoisFilter) {
|
||||
return sortContractsLocally(filteredRows, sortField, sortOrder);
|
||||
}
|
||||
|
||||
return filteredRows;
|
||||
}, [rows, sortField, sortOrder, q, structureFilter, typeFilter, productionFilter, etatContratFilters, etatPaieFilter, dpaeFilter, signatureFilter, startFrom, startTo, endFrom, endTo, multiMoisFilter]);
|
||||
|
||||
// Selection functions (updated to use sortedRows for selection)
|
||||
const toggleSelectAll = () => {
|
||||
|
|
@ -1558,6 +1606,26 @@ function ContractsGridImpl({ initialData, activeOrgId }: { initialData: Contract
|
|||
calculateCounts();
|
||||
}, []);
|
||||
|
||||
// Calculate multi-mois count from client-side data (separate useEffect)
|
||||
useEffect(() => {
|
||||
const cdduContracts = rows.filter(contract =>
|
||||
contract.type_de_contrat === 'CDDU' || contract.type_de_contrat === 'CDDU_MONO' || contract.type_de_contrat === 'CDDU_MULTI'
|
||||
);
|
||||
|
||||
const multiMoisCount = cdduContracts.filter(contract => {
|
||||
if (!contract.start_date || !contract.end_date) return false;
|
||||
|
||||
const startDate = new Date(contract.start_date);
|
||||
const endDate = new Date(contract.end_date);
|
||||
|
||||
// Vérifier si les mois ou les années sont différents
|
||||
return startDate.getMonth() !== endDate.getMonth() ||
|
||||
startDate.getFullYear() !== endDate.getFullYear();
|
||||
}).length;
|
||||
|
||||
setCountMultiMois(multiMoisCount);
|
||||
}, [rows]);
|
||||
|
||||
// Fonction pour relancer un salarié spécifique
|
||||
const handleReminderClick = async (contract: any) => {
|
||||
setSelectedContractForReminder(contract);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export default function StaffContractsPageClient({ initialData, activeOrgId }: {
|
|||
paieATraiterMoisDernier: null as number | null,
|
||||
paieATraiterToutes: null as number | null,
|
||||
nonSignesDateProche: null as number | null,
|
||||
multiMois: null as number | null,
|
||||
});
|
||||
|
||||
// Check localStorage to detect which filter is active
|
||||
|
|
@ -125,6 +126,15 @@ export default function StaffContractsPageClient({ initialData, activeOrgId }: {
|
|||
setActiveFilter('contrats-en-cours');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for Multi-mois filter
|
||||
if (filters.multiMoisFilter === true &&
|
||||
filters.typeFilter === 'CDDU' &&
|
||||
filters.sortField === 'start_date' &&
|
||||
filters.sortOrder === 'desc') {
|
||||
setActiveFilter('multi-mois');
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
|
|
@ -140,6 +150,7 @@ export default function StaffContractsPageClient({ initialData, activeOrgId }: {
|
|||
paieATraiterMoisDernier: gridRef.current?.getCountPaieATraiterMoisDernier() ?? null,
|
||||
paieATraiterToutes: gridRef.current?.getCountPaieATraiterToutes() ?? null,
|
||||
nonSignesDateProche: gridRef.current?.getCountNonSignesDateProche() ?? null,
|
||||
multiMois: gridRef.current?.getCountMultiMois() ?? null,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -178,6 +189,11 @@ export default function StaffContractsPageClient({ initialData, activeOrgId }: {
|
|||
setActiveFilter('contrats-en-cours');
|
||||
};
|
||||
|
||||
const handleMultiMois = () => {
|
||||
gridRef.current?.quickFilterMultiMois();
|
||||
setActiveFilter('multi-mois');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{/* Card de raccourcis pleine largeur */}
|
||||
|
|
@ -268,6 +284,29 @@ export default function StaffContractsPageClient({ initialData, activeOrgId }: {
|
|||
<Calendar size={16} />
|
||||
En cours
|
||||
</button>
|
||||
|
||||
{/* Bouton Multi-mois */}
|
||||
<button
|
||||
onClick={handleMultiMois}
|
||||
className={`inline-flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg font-medium transition-all relative ${
|
||||
activeFilter === 'multi-mois'
|
||||
? 'bg-gradient-to-r from-purple-500 to-purple-600 text-white shadow-md'
|
||||
: 'bg-white text-purple-700 border border-purple-300 hover:border-purple-500 hover:shadow-sm'
|
||||
}`}
|
||||
title="Afficher uniquement les contrats CDDU multi-mois (date de début et date de fin sur des mois calendaires différents)"
|
||||
>
|
||||
<Calendar size={16} />
|
||||
Multi-mois
|
||||
{counts.multiMois !== null && (
|
||||
<span className={`ml-1 inline-flex items-center justify-center w-5 h-5 rounded-full text-xs font-bold ${
|
||||
activeFilter === 'multi-mois'
|
||||
? 'bg-purple-300 text-purple-900'
|
||||
: 'bg-purple-200 text-purple-800'
|
||||
}`}>
|
||||
{counts.multiMois}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue