diff --git a/frontend/src/pages/WeeklySummaryPage.jsx b/frontend/src/pages/WeeklySummaryPage.jsx index 3d718b2..b1ae5eb 100644 --- a/frontend/src/pages/WeeklySummaryPage.jsx +++ b/frontend/src/pages/WeeklySummaryPage.jsx @@ -84,13 +84,6 @@ const WeeklySummaryPage = ({ userId }) => { 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] = useState(0); @@ -426,60 +419,95 @@ const WeeklySummaryPage = ({ userId }) => { const scheduleTable = scheduleTableRef.current; - const main = - document.querySelector('main'); - - const footer = - document.querySelector('footer'); - if (!scheduleTable) { return; } /* - * Largeur réelle visible du planning. - * - * On utilise clientWidth et non window.innerWidth - * afin de tenir compte du CardContent, des paddings, - * des bordures, etc. + * Largeur réellement disponible. */ setMobileContainerWidth( scheduleTable.clientWidth, ); - if ( - !main || - !footer - ) { + /* + * Sur mobile, on ne force pas la hauteur du planning + * à rentrer dans l'écran. + * + * Le planning doit pouvoir être scrollé verticalement. + */ + if (window.innerWidth < 768) { return; } - const mainStyles = - window.getComputedStyle(main); + const cardContent = + scheduleTable.closest( + '[data-slot="card-content"]', + ); - const bottomPadding = - parseFloat( - mainStyles.paddingBottom, - ) || 0; + const footer = + document.querySelector('footer'); - const footerHeight = - footer.getBoundingClientRect().height; + if (!cardContent) { + return; + } + /* + * Position réelle du planning. + */ const tableTop = scheduleTable.getBoundingClientRect().top; - const remainingHeight = - window.innerHeight - - tableTop - - footerHeight - - bottomPadding - - SCHEDULE_HEADER_HEIGHT; + /* + * Limite basse réelle disponible. + * + * Cela tient compte : + * - du CardContent + * - 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( MIN_SCHEDULE_HEIGHT, - remainingHeight, - ), + nextTotalHeight - + SCHEDULE_HEADER_HEIGHT, + ); + + setAvailableScheduleHeight( + nextScheduleHeight, ); }; @@ -873,9 +901,6 @@ const WeeklySummaryPage = ({ userId }) => { /* * ------------------------------------------------------------ * Utilisateurs actifs sur une période - * - * Desktop -> toute la semaine - * Mobile -> journée sélectionnée * ------------------------------------------------------------ */ @@ -1010,10 +1035,23 @@ const WeeklySummaryPage = ({ userId }) => { const hourCount = endHour - startHour; - const scheduleHeight = Math.max( - MIN_SCHEDULE_HEIGHT, - availableScheduleHeight, - ); + /* + * 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, + availableScheduleHeight, + ); const totalPlanningHeight = SCHEDULE_HEADER_HEIGHT + @@ -1044,9 +1082,6 @@ const WeeklySummaryPage = ({ userId }) => { /* * ------------------------------------------------------------ * Utilisateurs réellement affichés - * - * Desktop : actifs sur la semaine - * Mobile : actifs sur le jour * ------------------------------------------------------------ */ @@ -1071,17 +1106,6 @@ const WeeklySummaryPage = ({ userId }) => { /* * ------------------------------------------------------------ * 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 ( - +
@@ -1264,77 +1288,76 @@ const WeeklySummaryPage = ({ userId }) => {
- + {/* Sélection utilisateur */} {isAdmin && ( -
-
- +
+
+ - { + setSelectedUserId( + event.target.value, + ); - setError(''); - }} - 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 === - 0 ? ( - + ) : ( + users.map( + (user) => ( + - ) : ( - users.map( - (user) => ( - - ), - ) - )} - -
+ ), + ) + )} + +
-
+ + Voir tout le monde + + +
)} {/* Légende */} @@ -1381,9 +1404,20 @@ const WeeklySummaryPage = ({ userId }) => {
{/* ==================================================== @@ -1397,6 +1431,7 @@ const WeeklySummaryPage = ({ userId }) => { width: `${mobilePlanningWidth}px`, minWidth: `${mobilePlanningWidth}px`, height: `${totalPlanningHeight}px`, + minHeight: `${totalPlanningHeight}px`, gridTemplateRows: `${SCHEDULE_HEADER_HEIGHT}px ${scheduleHeight}px`, }} > @@ -1479,11 +1514,7 @@ const WeeklySummaryPage = ({ userId }) => { ), )} - {/* ================================================== - ADMIN + TOUS LES UTILISATEURS - 1 utilisateur actif = 1 colonne - ================================================== */} - + {/* Tous les utilisateurs */} {isAdmin && showAllUsers ? (
{ user, )} className="relative border-r border-border/30 last:border-r-0" - title={ - getUserLabel( - user, - ) - } + title={getUserLabel( + user, + )} > {schedules.map( ({ @@ -1563,10 +1592,6 @@ const WeeklySummaryPage = ({ userId }) => { )}
) : ( - /* - * Utilisateur sélectionné / - * utilisateur normal. - */ getSelectedUserAttendances( getAttendancesForDay( weekDays[ @@ -1767,15 +1792,7 @@ const WeeklySummaryPage = ({ userId }) => { ), )} - {/* ================================================== - ADMIN : TOUS LES UTILISATEURS - - 1 utilisateur ayant pointé dans la semaine - = 1 colonne - - Chaque pointage est affiché séparément. - ================================================== */} - + {/* Tous les utilisateurs */} {isAdmin && showAllUsers ? (
{ )}
) : ( - /* - * Utilisateur sélectionné - */ getSelectedUserAttendances( dayAttendances, )