This commit is contained in:
Louis Mazin 2026-09-20 02:17:25 +02:00
parent 49bbf77c04
commit addd13efae

View File

@ -84,13 +84,6 @@ const WeeklySummaryPage = ({ userId }) => {
const [isMobile, setIsMobile] = useState(false); const [isMobile, setIsMobile] = useState(false);
/*
* Largeur réelle disponible du planning mobile.
*
* Important :
* on ne se base pas directement sur window.innerWidth,
* car le CardContent possède ses propres marges/paddings.
*/
const [mobileContainerWidth, setMobileContainerWidth] = const [mobileContainerWidth, setMobileContainerWidth] =
useState(0); useState(0);
@ -426,60 +419,95 @@ const WeeklySummaryPage = ({ userId }) => {
const scheduleTable = const scheduleTable =
scheduleTableRef.current; scheduleTableRef.current;
const main =
document.querySelector('main');
const footer =
document.querySelector('footer');
if (!scheduleTable) { if (!scheduleTable) {
return; return;
} }
/* /*
* Largeur réelle visible du planning. * Largeur réellement disponible.
*
* On utilise clientWidth et non window.innerWidth
* afin de tenir compte du CardContent, des paddings,
* des bordures, etc.
*/ */
setMobileContainerWidth( setMobileContainerWidth(
scheduleTable.clientWidth, scheduleTable.clientWidth,
); );
if ( /*
!main || * Sur mobile, on ne force pas la hauteur du planning
!footer * à rentrer dans l'écran.
) { *
* Le planning doit pouvoir être scrollé verticalement.
*/
if (window.innerWidth < 768) {
return; return;
} }
const mainStyles = const cardContent =
window.getComputedStyle(main); scheduleTable.closest(
'[data-slot="card-content"]',
);
const bottomPadding = const footer =
parseFloat( document.querySelector('footer');
mainStyles.paddingBottom,
) || 0;
const footerHeight = if (!cardContent) {
footer.getBoundingClientRect().height; return;
}
/*
* Position réelle du planning.
*/
const tableTop = const tableTop =
scheduleTable.getBoundingClientRect().top; scheduleTable.getBoundingClientRect().top;
const remainingHeight = /*
window.innerHeight - * Limite basse réelle disponible.
tableTop - *
footerHeight - * Cela tient compte :
bottomPadding - * - du CardContent
SCHEDULE_HEADER_HEIGHT; * - de son padding
* - du footer
* - de la hauteur de la fenêtre
*/
const contentRect =
cardContent.getBoundingClientRect();
setAvailableScheduleHeight( const footerTop = footer
? footer.getBoundingClientRect().top
: window.innerHeight;
const availableBottom =
Math.min(
contentRect.bottom,
footerTop,
window.innerHeight,
);
/*
* Petite marge de sécurité pour éviter
* les scrollbars de quelques pixels.
*/
const SAFETY_MARGIN = 4;
const totalAvailableHeight =
availableBottom -
tableTop -
SAFETY_MARGIN;
const nextTotalHeight =
Math.max(
SCHEDULE_HEADER_HEIGHT +
MIN_SCHEDULE_HEIGHT,
totalAvailableHeight,
);
const nextScheduleHeight =
Math.max( Math.max(
MIN_SCHEDULE_HEIGHT, MIN_SCHEDULE_HEIGHT,
remainingHeight, nextTotalHeight -
), SCHEDULE_HEADER_HEIGHT,
);
setAvailableScheduleHeight(
nextScheduleHeight,
); );
}; };
@ -873,9 +901,6 @@ const WeeklySummaryPage = ({ userId }) => {
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
* Utilisateurs actifs sur une période * Utilisateurs actifs sur une période
*
* Desktop -> toute la semaine
* Mobile -> journée sélectionnée
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
@ -1010,7 +1035,20 @@ const WeeklySummaryPage = ({ userId }) => {
const hourCount = const hourCount =
endHour - startHour; endHour - startHour;
const scheduleHeight = Math.max( /*
* Desktop :
* hauteur calculée pour tenir exactement dans le Card.
*
* Mobile :
* on conserve une hauteur confortable et le conteneur
* devient scrollable verticalement.
*/
const scheduleHeight = isMobile
? Math.max(
MIN_SCHEDULE_HEIGHT,
availableScheduleHeight,
)
: Math.max(
MIN_SCHEDULE_HEIGHT, MIN_SCHEDULE_HEIGHT,
availableScheduleHeight, availableScheduleHeight,
); );
@ -1044,9 +1082,6 @@ const WeeklySummaryPage = ({ userId }) => {
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
* Utilisateurs réellement affichés * Utilisateurs réellement affichés
*
* Desktop : actifs sur la semaine
* Mobile : actifs sur le jour
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
@ -1071,17 +1106,6 @@ const WeeklySummaryPage = ({ userId }) => {
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
* Largeur mobile * Largeur mobile
*
* La zone utilisateurs prend maintenant toute la largeur
* réellement disponible dans le conteneur.
*
* On garde cependant une largeur minimale correspondant :
* - à la largeur minimale des colonnes utilisateurs
* - à l'ancien minimum de contenu
*
* Si plusieurs utilisateurs dépassent cette largeur,
* le planning peut naturellement devenir plus large et
* déclencher le scroll horizontal.
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
@ -1137,13 +1161,13 @@ const WeeklySummaryPage = ({ userId }) => {
return ( return (
<Card <Card
className={`flex h-full min-h-0 w-full weekly-schedule page-layout${ className={`flex h-full min-h-0 w-full overflow-hidden weekly-schedule page-layout${
isAdmin isAdmin
? ' multi-user-schedule' ? ' multi-user-schedule'
: '' : ''
}`} }`}
> >
<CardHeader className="border-b"> <CardHeader className="shrink-0 border-b">
<div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between"> <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<div className="min-w-0"> <div className="min-w-0">
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2">
@ -1264,7 +1288,7 @@ const WeeklySummaryPage = ({ userId }) => {
</div> </div>
</CardHeader> </CardHeader>
<CardContent> <CardContent className="min-h-0 flex-1">
{/* Sélection utilisateur */} {/* Sélection utilisateur */}
{isAdmin && ( {isAdmin && (
<div className="flex flex-col gap-3 pb-4 md:flex-row md:items-center"> <div className="flex flex-col gap-3 pb-4 md:flex-row md:items-center">
@ -1289,8 +1313,7 @@ const WeeklySummaryPage = ({ userId }) => {
}} }}
className="h-10 min-w-0 flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" className="h-10 min-w-0 flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
> >
{users.length === {users.length === 0 ? (
0 ? (
<option value=""> <option value="">
Aucun utilisateur Aucun utilisateur
disponible disponible
@ -1381,9 +1404,20 @@ const WeeklySummaryPage = ({ userId }) => {
<div <div
ref={scheduleTableRef} ref={scheduleTableRef}
className="relative overflow-x-auto overflow-y-auto rounded-lg border" className={`relative rounded-lg border ${
isMobile
? 'overflow-auto'
: 'overflow-x-auto overflow-y-hidden'
}`}
style={{ style={{
height: `${totalPlanningHeight}px`, height: `${totalPlanningHeight}px`,
maxHeight: isMobile
? 'none'
: `${totalPlanningHeight}px`,
WebkitOverflowScrolling:
'touch',
touchAction:
'pan-x pan-y',
}} }}
> >
{/* ==================================================== {/* ====================================================
@ -1397,6 +1431,7 @@ const WeeklySummaryPage = ({ userId }) => {
width: `${mobilePlanningWidth}px`, width: `${mobilePlanningWidth}px`,
minWidth: `${mobilePlanningWidth}px`, minWidth: `${mobilePlanningWidth}px`,
height: `${totalPlanningHeight}px`, height: `${totalPlanningHeight}px`,
minHeight: `${totalPlanningHeight}px`,
gridTemplateRows: `${SCHEDULE_HEADER_HEIGHT}px ${scheduleHeight}px`, gridTemplateRows: `${SCHEDULE_HEADER_HEIGHT}px ${scheduleHeight}px`,
}} }}
> >
@ -1479,11 +1514,7 @@ const WeeklySummaryPage = ({ userId }) => {
), ),
)} )}
{/* ================================================== {/* Tous les utilisateurs */}
ADMIN + TOUS LES UTILISATEURS
1 utilisateur actif = 1 colonne
================================================== */}
{isAdmin && {isAdmin &&
showAllUsers ? ( showAllUsers ? (
<div <div
@ -1515,11 +1546,9 @@ const WeeklySummaryPage = ({ userId }) => {
user, user,
)} )}
className="relative border-r border-border/30 last:border-r-0" className="relative border-r border-border/30 last:border-r-0"
title={ title={getUserLabel(
getUserLabel(
user, user,
) )}
}
> >
{schedules.map( {schedules.map(
({ ({
@ -1563,10 +1592,6 @@ const WeeklySummaryPage = ({ userId }) => {
)} )}
</div> </div>
) : ( ) : (
/*
* Utilisateur sélectionné /
* utilisateur normal.
*/
getSelectedUserAttendances( getSelectedUserAttendances(
getAttendancesForDay( getAttendancesForDay(
weekDays[ weekDays[
@ -1767,15 +1792,7 @@ const WeeklySummaryPage = ({ userId }) => {
), ),
)} )}
{/* ================================================== {/* Tous les utilisateurs */}
ADMIN : TOUS LES UTILISATEURS
1 utilisateur ayant pointé dans la semaine
= 1 colonne
Chaque pointage est affiché séparément.
================================================== */}
{isAdmin && {isAdmin &&
showAllUsers ? ( showAllUsers ? (
<div <div
@ -1851,9 +1868,6 @@ const WeeklySummaryPage = ({ userId }) => {
)} )}
</div> </div>
) : ( ) : (
/*
* Utilisateur sélectionné
*/
getSelectedUserAttendances( getSelectedUserAttendances(
dayAttendances, dayAttendances,
) )