fix: Pré-sélection des dates lors de la réouverture des modales de sélection + amélioration UI du bouton Appliquer

This commit is contained in:
odentas 2025-11-20 17:58:54 +01:00
parent 3435581761
commit 91adeb8fc8
3 changed files with 66 additions and 12 deletions

View file

@ -41,16 +41,21 @@ export default function DatePickerCalendar({
const [isDragging, setIsDragging] = useState(false);
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
const modalRef = useRef<HTMLDivElement>(null);
const prevIsOpenRef = useRef(isOpen);
// Initialiser avec les dates initiales
useEffect(() => {
if (isOpen) {
// Vérifier si la modale vient de s'ouvrir (transition de false à true)
const justOpened = isOpen && !prevIsOpenRef.current;
prevIsOpenRef.current = isOpen;
if (justOpened) {
if (initialDates.length > 0) {
// Convertir format input "12/10" en ISO
// On utilise le minDate ou maxDate comme contexte d'année
const yearContext = minDate || maxDate || new Date().toISOString().slice(0, 10);
const isos = initialDates
.map(d => parseFrenchedDate(d, yearContext))
.map(d => parseFrenchedDate(d.trim(), yearContext))
.filter(iso => iso.length === 10);
setSelectedIsos(isos);
@ -59,10 +64,14 @@ export default function DatePickerCalendar({
const firstDate = new Date(isos[0] + "T00:00:00Z");
setCurrentMonth(firstDate);
}
} else if (minDate) {
// Si pas de dates initiales, utiliser la date de début du contrat
const startDate = new Date(minDate + "T00:00:00Z");
setCurrentMonth(startDate);
} else {
// Réinitialiser les sélections si pas de dates initiales
setSelectedIsos([]);
if (minDate) {
// Si pas de dates initiales, utiliser la date de début du contrat
const startDate = new Date(minDate + "T00:00:00Z");
setCurrentMonth(startDate);
}
}
}
}, [isOpen, initialDates, minDate, maxDate]);

View file

@ -432,13 +432,13 @@ export default function DatesQuantityModal({
className="w-24"
/>
<span className="text-sm text-emerald-700">{getUnitLabel(dateType, false)}</span>
<Button
<button
type="button"
onClick={handleApplyToAll}
className="ml-auto bg-emerald-600 hover:bg-emerald-700 text-white text-sm px-3 py-1.5"
className="ml-auto bg-emerald-600 hover:bg-emerald-700 text-white text-sm px-3 py-1.5 rounded-md font-medium transition-colors"
>
Appliquer
</Button>
</button>
</div>
</div>
)}

View file

@ -169,6 +169,51 @@ function parseFormattedDatesWithQuantities(
return result;
}
/**
* Extrait uniquement les dates (format DD/MM) d'une chaîne formatée PDFMonkey
* Utile pour initialDates des modales de calendrier
*
* @param dateStr - Chaîne formatée (ex: "1 représentation par jour du 24/11 au 26/11 ; 2 représentations le 28/11.")
* @param yearContext - Contexte de l'année (ex: "2025-11-01")
* @returns Array de dates au format "DD/MM"
*/
function extractDatesFromFormatted(dateStr: string, yearContext: string): string[] {
if (!dateStr || !dateStr.trim()) return [];
const dates: string[] = [];
const groups = dateStr.split(" ; ");
groups.forEach((group) => {
// Vérifier si c'est une plage (contient "du ... au ...")
const rangeMatch = group.match(/du\s+(\d{2}\/\d{2})\s+au\s+(\d{2}\/\d{2})/);
if (rangeMatch) {
// C'est une plage : générer toutes les dates intermédiaires
const startFr = rangeMatch[1];
const endFr = rangeMatch[2];
// Convertir en ISO
const startIso = parseFrenchedDate(startFr, yearContext);
const endIso = parseFrenchedDate(endFr, yearContext);
// Générer toutes les dates de la plage
const allDatesIso = generateDateRange(startIso, endIso);
// Convertir en format DD/MM
allDatesIso.forEach((iso) => {
dates.push(formatDateFr(iso));
});
} else {
// Date isolée (ex: "le 28/11")
const dateMatch = group.match(/(\d{2}\/\d{2})/);
if (dateMatch) {
dates.push(dateMatch[1]);
}
}
});
return dates;
}
// Petit hook local de debounce (réutilisable)
function useDebouncedValue<T>(value: T, delay = 300) {
const [debounced, setDebounced] = useState<T>(value);
@ -2319,14 +2364,14 @@ useEffect(() => {
isOpen={datesRepOpen}
onClose={() => setDatesRepOpen(false)}
onApply={handleDatesRepApply}
initialDates={datesRep ? datesRep.split(", ") : []}
initialDates={datesRep ? extractDatesFromFormatted(datesRep, dateDebut || new Date().toISOString().slice(0, 10)) : []}
title="Sélectionner les dates de représentations"
/>
<DatePickerCalendar
isOpen={datesServOpen}
onClose={() => setDatesServOpen(false)}
onApply={handleDatesServApply}
initialDates={datesServ ? datesServ.split(", ") : []}
initialDates={datesServ ? extractDatesFromFormatted(datesServ, dateDebut || new Date().toISOString().slice(0, 10)) : []}
title="Sélectionner les dates de répétitions"
/>
</>
@ -2404,7 +2449,7 @@ useEffect(() => {
isOpen={joursTravailOpen}
onClose={() => setJoursTravailOpen(false)}
onApply={handleJoursTravailApply}
initialDates={joursTravailRaw}
initialDates={joursTravailRaw.length > 0 ? joursTravailRaw : (joursTravail ? extractDatesFromFormatted(joursTravail, dateDebut || new Date().toISOString().slice(0, 10)) : [])}
title="Sélectionner les jours de travail"
/>
</>