This commit is contained in:
Louis Mazin 2026-09-20 00:38:55 +02:00
parent 17270122df
commit db61ec30e1

View File

@ -27,6 +27,10 @@ const DEFAULT_END_HOUR = 18;
const SCHEDULE_HEADER_HEIGHT = 58; const SCHEDULE_HEADER_HEIGHT = 58;
const MIN_SCHEDULE_HEIGHT = 180; const MIN_SCHEDULE_HEIGHT = 180;
const MOBILE_TIME_COLUMN_WIDTH = 64;
const MOBILE_USER_COLUMN_WIDTH = 40;
const MOBILE_DEFAULT_CONTENT_WIDTH = 236;
const USER_COLORS = [ const USER_COLORS = [
'#c56a3d', '#c56a3d',
'#3d7c8c', '#3d7c8c',
@ -440,13 +444,6 @@ const WeeklySummaryPage = ({ userId }) => {
const tableTop = const tableTop =
scheduleTable.getBoundingClientRect().top; scheduleTable.getBoundingClientRect().top;
/*
* Ici on calcule UNIQUEMENT la hauteur
* disponible pour les heures.
*
* Le header de 58px est ajouté séparément
* dans la hauteur totale du planning.
*/
const remainingHeight = const remainingHeight =
window.innerHeight - window.innerHeight -
tableTop - tableTop -
@ -475,7 +472,13 @@ const WeeklySummaryPage = ({ userId }) => {
updateScheduleHeight, updateScheduleHeight,
); );
}; };
}, [loading, error, showAllUsers, isMobile]); }, [
loading,
error,
showAllUsers,
isMobile,
users.length,
]);
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
@ -898,7 +901,7 @@ const WeeklySummaryPage = ({ userId }) => {
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
* États du planning * États
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
@ -941,13 +944,6 @@ const WeeklySummaryPage = ({ userId }) => {
const hourCount = const hourCount =
endHour - startHour; endHour - startHour;
/*
* Hauteur EXACTE de la zone horaire.
*
* Le header fait exactement 58px.
* La grille des heures utilise exactement
* availableScheduleHeight.
*/
const scheduleHeight = Math.max( const scheduleHeight = Math.max(
MIN_SCHEDULE_HEIGHT, MIN_SCHEDULE_HEIGHT,
availableScheduleHeight, availableScheduleHeight,
@ -981,14 +977,25 @@ const WeeklySummaryPage = ({ userId }) => {
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
* Mobile * Mobile : largeur des colonnes utilisateurs
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
const displayDay = const mobileUserCount =
weekDays[ Math.max(users.length, 1);
selectedDayIndex
]; const mobileUsersWidth =
isAdmin && showAllUsers
? Math.max(
mobileUserCount *
MOBILE_USER_COLUMN_WIDTH,
MOBILE_DEFAULT_CONTENT_WIDTH,
)
: MOBILE_DEFAULT_CONTENT_WIDTH;
const mobilePlanningWidth =
MOBILE_TIME_COLUMN_WIDTH +
mobileUsersWidth;
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
@ -1111,7 +1118,9 @@ const WeeklySummaryPage = ({ userId }) => {
variant="secondary" variant="secondary"
className="text-sm" className="text-sm"
> >
{displayDay.toLocaleDateString( {weekDays[
selectedDayIndex
].toLocaleDateString(
'fr-FR', 'fr-FR',
{ {
weekday: 'long', weekday: 'long',
@ -1267,19 +1276,25 @@ const WeeklySummaryPage = ({ userId }) => {
{isMobile ? ( {isMobile ? (
<div <div
className="grid min-w-[300px] grid-cols-1" className="grid"
style={{ style={{
width: `${mobilePlanningWidth}px`,
minWidth: `${mobilePlanningWidth}px`,
height: `${totalPlanningHeight}px`, height: `${totalPlanningHeight}px`,
gridTemplateRows: `${SCHEDULE_HEADER_HEIGHT}px ${scheduleHeight}px`,
}} }}
> >
{/* Header */} {/* Header */}
<div <div
className="sticky top-0 z-10 flex items-center justify-center border-b bg-background p-2 text-center font-medium" className="flex items-center justify-center border-b bg-background p-2 text-center font-medium"
style={{ style={{
gridColumn: '1 / -1',
height: `${SCHEDULE_HEADER_HEIGHT}px`, height: `${SCHEDULE_HEADER_HEIGHT}px`,
}} }}
> >
{displayDay.toLocaleDateString( {weekDays[
selectedDayIndex
].toLocaleDateString(
'fr-FR', 'fr-FR',
{ {
weekday: 'long', weekday: 'long',
@ -1289,9 +1304,12 @@ const WeeklySummaryPage = ({ userId }) => {
)} )}
</div> </div>
{/* Corps */}
<div <div
className="grid grid-cols-[64px_1fr]" className="grid"
style={{ style={{
gridColumn: '1 / -1',
gridTemplateColumns: `${MOBILE_TIME_COLUMN_WIDTH}px ${mobileUsersWidth}px`,
height: `${scheduleHeight}px`, height: `${scheduleHeight}px`,
}} }}
> >
@ -1319,34 +1337,53 @@ const WeeklySummaryPage = ({ userId }) => {
)} )}
</div> </div>
{/* Planning */} {/* Zone utilisateurs */}
<div <div
className="relative" className="relative"
style={{ style={{
height: `${scheduleHeight}px`, height: `${scheduleHeight}px`,
width: `${mobileUsersWidth}px`,
}} }}
> >
{/* Grille horaire */}
{hours.map( {hours.map(
(hour) => ( (hour) => (
<div <div
key={hour} key={hour}
className="border-b border-gray-200" className="absolute left-0 right-0 border-b border-gray-200"
style={{ style={{
top: `${
(hour -
startHour) *
hourHeight
}px`,
height: `${hourHeight}px`, height: `${hourHeight}px`,
}} }}
/> />
), ),
)} )}
{/* ==================================================
ADMIN + TOUS LES UTILISATEURS
1 utilisateur = 1 colonne
================================================== */}
{isAdmin && {isAdmin &&
showAllUsers ? ( showAllUsers ? (
<div className="absolute inset-0 flex"> <div
className="absolute inset-0 grid"
style={{
gridTemplateColumns: `repeat(${mobileUserCount}, minmax(${MOBILE_USER_COLUMN_WIDTH}px, 1fr))`,
}}
>
{users.map( {users.map(
(user) => { (user) => {
const bounds = const bounds =
getUserDayBounds( getUserDayBounds(
getAttendancesForDay( getAttendancesForDay(
displayDay, weekDays[
selectedDayIndex
],
), ),
user, user,
); );
@ -1356,57 +1393,57 @@ const WeeklySummaryPage = ({ userId }) => {
user, user,
); );
if (!bounds) {
return (
<div
key={getUserId(
user,
)}
className="relative min-w-0 flex-1"
/>
);
}
const style =
getAttendanceStyle(
bounds.start,
bounds.end,
startHour,
endHour,
hourHeight,
);
return ( return (
<div <div
key={getUserId( key={getUserId(
user, user,
)} )}
className="relative min-w-0 flex-1" className="relative border-r border-border/30 last:border-r-0"
title={`${getUserLabel( title={
user, bounds
)} : ${formatSegmentTime( ? `${getUserLabel(
bounds.start, user,
)} - ${formatSegmentTime( )} : ${formatSegmentTime(
bounds.end, bounds.start,
)}`} )} - ${formatSegmentTime(
bounds.end,
)}`
: getUserLabel(
user,
)
}
> >
<div {bounds && (
className="absolute left-1/2 w-2 -translate-x-1/2 rounded-full" <div
style={{ className="absolute left-1/2 w-2 -translate-x-1/2 rounded-full"
...style, style={{
backgroundColor: ...getAttendanceStyle(
color, bounds.start,
}} bounds.end,
/> startHour,
endHour,
hourHeight,
),
backgroundColor:
color,
}}
/>
)}
</div> </div>
); );
}, },
)} )}
</div> </div>
) : ( ) : (
/*
* Utilisateur sélectionné /
* utilisateur normal.
*/
getSelectedUserAttendances( getSelectedUserAttendances(
getAttendancesForDay( getAttendancesForDay(
displayDay, weekDays[
selectedDayIndex
],
), ),
) )
.map( .map(
@ -1452,10 +1489,14 @@ const WeeklySummaryPage = ({ userId }) => {
return ( return (
<div <div
key={`${formatDateKey( key={`${formatDateKey(
displayDay, weekDays[
selectedDayIndex
],
)}-${start}-${end}`} )}-${start}-${end}`}
className="absolute left-0 right-0 rounded-sm border border-blue-600/30 bg-blue-500/80" className="absolute left-0 right-0 overflow-hidden rounded-sm border border-blue-600/30 bg-blue-500/80"
style={style} style={
style
}
> >
<div className="p-1 text-xs text-white"> <div className="p-1 text-xs text-white">
{formatSegmentTime( {formatSegmentTime(
@ -1484,10 +1525,8 @@ const WeeklySummaryPage = ({ userId }) => {
style={{ style={{
gridTemplateColumns: gridTemplateColumns:
'64px repeat(7, minmax(120px, 1fr))', '64px repeat(7, minmax(120px, 1fr))',
gridTemplateRows: gridTemplateRows:
`${SCHEDULE_HEADER_HEIGHT}px ${scheduleHeight}px`, `${SCHEDULE_HEADER_HEIGHT}px ${scheduleHeight}px`,
height: `${totalPlanningHeight}px`, height: `${totalPlanningHeight}px`,
}} }}
> >
@ -1597,13 +1636,12 @@ const WeeklySummaryPage = ({ userId }) => {
{/* ================================================== {/* ==================================================
ADMIN : TOUS LES UTILISATEURS ADMIN : TOUS LES UTILISATEURS
1 colonne = 1 utilisateur 1 utilisateur = 1 colonne
1 barre = 1 utilisateur
================================================== */} ================================================== */}
{isAdmin && {isAdmin &&
showAllUsers ? ( showAllUsers ? (
<div className="absolute inset-0 flex"> <div className="absolute inset-0 grid grid-cols-[repeat(auto-fit,minmax(0,1fr))]">
{users.map( {users.map(
(user) => { (user) => {
const bounds = const bounds =
@ -1622,7 +1660,7 @@ const WeeklySummaryPage = ({ userId }) => {
key={getUserId( key={getUserId(
user, user,
)} )}
className="relative min-w-0 flex-1 border-r border-border/30 last:border-r-0" className="relative min-w-0 border-r border-border/30 last:border-r-0"
title={ title={
bounds bounds
? `${getUserLabel( ? `${getUserLabel(
@ -1659,10 +1697,9 @@ const WeeklySummaryPage = ({ userId }) => {
)} )}
</div> </div>
) : ( ) : (
/* ================================================== /*
UTILISATEUR SÉLECTIONNÉ * Utilisateur sélectionné
================================================== */ */
getSelectedUserAttendances( getSelectedUserAttendances(
dayAttendances, dayAttendances,
) )