test
This commit is contained in:
parent
49bbf77c04
commit
addd13efae
@ -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 (
|
||||
<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
|
||||
? ' 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="min-w-0">
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
@ -1264,77 +1288,76 @@ const WeeklySummaryPage = ({ userId }) => {
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<CardContent className="min-h-0 flex-1">
|
||||
{/* Sélection utilisateur */}
|
||||
{isAdmin && (
|
||||
<div className="flex flex-col gap-3 pb-4 md:flex-row md:items-center">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<label
|
||||
htmlFor="weekly-selected-user"
|
||||
className="shrink-0 text-sm font-medium"
|
||||
>
|
||||
Voir le récap de :
|
||||
</label>
|
||||
<div className="flex flex-col gap-3 pb-4 md:flex-row md:items-center">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<label
|
||||
htmlFor="weekly-selected-user"
|
||||
className="shrink-0 text-sm font-medium"
|
||||
>
|
||||
Voir le récap de :
|
||||
</label>
|
||||
|
||||
<select
|
||||
id="weekly-selected-user"
|
||||
value={selectedUserId}
|
||||
disabled={showAllUsers}
|
||||
onChange={(event) => {
|
||||
setSelectedUserId(
|
||||
event.target.value,
|
||||
);
|
||||
<select
|
||||
id="weekly-selected-user"
|
||||
value={selectedUserId}
|
||||
disabled={showAllUsers}
|
||||
onChange={(event) => {
|
||||
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 ? (
|
||||
<option value="">
|
||||
Aucun utilisateur
|
||||
disponible
|
||||
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 ? (
|
||||
<option value="">
|
||||
Aucun utilisateur
|
||||
disponible
|
||||
</option>
|
||||
) : (
|
||||
users.map(
|
||||
(user) => (
|
||||
<option
|
||||
key={getUserId(
|
||||
user,
|
||||
)}
|
||||
value={getUserId(
|
||||
user,
|
||||
)}
|
||||
>
|
||||
{getUserLabel(
|
||||
user,
|
||||
)}
|
||||
</option>
|
||||
) : (
|
||||
users.map(
|
||||
(user) => (
|
||||
<option
|
||||
key={getUserId(
|
||||
user,
|
||||
)}
|
||||
value={getUserId(
|
||||
user,
|
||||
)}
|
||||
>
|
||||
{getUserLabel(
|
||||
user,
|
||||
)}
|
||||
</option>
|
||||
),
|
||||
)
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
),
|
||||
)
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label className="flex h-10 shrink-0 cursor-pointer items-center gap-2 rounded-md border px-3 text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showAllUsers}
|
||||
onChange={(event) => {
|
||||
setShowAllUsers(
|
||||
event.target.checked,
|
||||
);
|
||||
<label className="flex h-10 shrink-0 cursor-pointer items-center gap-2 rounded-md border px-3 text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showAllUsers}
|
||||
onChange={(event) => {
|
||||
setShowAllUsers(
|
||||
event.target.checked,
|
||||
);
|
||||
|
||||
setError('');
|
||||
}}
|
||||
className="size-4 accent-primary"
|
||||
/>
|
||||
setError('');
|
||||
}}
|
||||
className="size-4 accent-primary"
|
||||
/>
|
||||
|
||||
<span>
|
||||
Voir tout le monde
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<span>
|
||||
Voir tout le monde
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Légende */}
|
||||
@ -1381,9 +1404,20 @@ const WeeklySummaryPage = ({ userId }) => {
|
||||
|
||||
<div
|
||||
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={{
|
||||
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`,
|
||||
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 ? (
|
||||
<div
|
||||
@ -1515,11 +1546,9 @@ const WeeklySummaryPage = ({ userId }) => {
|
||||
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 }) => {
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
/*
|
||||
* 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 ? (
|
||||
<div
|
||||
@ -1851,9 +1868,6 @@ const WeeklySummaryPage = ({ userId }) => {
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
/*
|
||||
* Utilisateur sélectionné
|
||||
*/
|
||||
getSelectedUserAttendances(
|
||||
dayAttendances,
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user