fix: nested scrolls on /bookings (#19284)

This commit is contained in:
Eunjae Lee
2025-02-17 10:25:42 +01:00
committed by GitHub
parent e441f3308f
commit 14bba343a4
2 changed files with 46 additions and 2 deletions
@@ -7,7 +7,9 @@ import {
getSortedRowModel,
createColumnHelper,
} from "@tanstack/react-table";
import { useMemo, useState, useEffect } from "react";
// eslint-disable-next-line no-restricted-imports
import { debounce } from "lodash";
import { useMemo, useState, useRef, useEffect, useCallback } from "react";
import type { z } from "zod";
import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/components";
@@ -105,6 +107,8 @@ function BookingsContent({ status }: BookingsProps) {
const { t } = useLocale();
const user = useMeQuery().data;
const [isFiltersVisible, setIsFiltersVisible] = useState<boolean>(false);
const tableContainerRef = useRef<HTMLDivElement>(null);
useProperHeightForMobile(tableContainerRef);
useEffect(() => {
if (user?.isTeamAdminOrOwner && !filterQuery.userIds?.length) {
@@ -276,6 +280,7 @@ function BookingsContent({ status }: BookingsProps) {
<WipeMyCalActionButton bookingStatus={status} bookingsEmpty={isEmpty} />
)}
<DataTableWrapper
tableContainerRef={tableContainerRef}
table={table}
testId={`${status}-bookings`}
bodyTestId="bookings"
@@ -305,3 +310,39 @@ function BookingsContent({ status }: BookingsProps) {
</div>
);
}
// Dynamically adjusts DataTable height on mobile to prevent nested scrolling
// and ensure the table fits within the viewport without overflowing (hacky)
function useProperHeightForMobile(ref: React.RefObject<HTMLDivElement>) {
const lastOffsetY = useRef<number>();
const lastWindowHeight = useRef<number>();
const BOTTOM_NAV_HEIGHT = 64;
const BUFFER = 32;
const updateHeight = useCallback(
debounce(() => {
if (!ref.current || window.innerWidth >= 640) return;
const rect = ref.current.getBoundingClientRect();
if (rect.top !== lastOffsetY.current || window.innerHeight !== lastWindowHeight.current) {
lastOffsetY.current = rect.top;
lastWindowHeight.current = window.innerHeight;
const height = window.innerHeight - lastOffsetY.current - BOTTOM_NAV_HEIGHT - BUFFER;
ref.current.style.height = `${height}px`;
}
}, 200),
[ref.current]
);
useEffect(() => {
const handleResize = () => {
updateHeight();
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, [updateHeight]);
updateHeight();
}
@@ -28,6 +28,7 @@ export type DataTableWrapperProps<TData, TValue> = {
className?: string;
containerClassName?: string;
children?: React.ReactNode;
tableContainerRef?: React.RefObject<HTMLDivElement>;
};
export function DataTableWrapper<TData, TValue>({
@@ -46,8 +47,10 @@ export function DataTableWrapper<TData, TValue>({
className,
containerClassName,
children,
tableContainerRef: externalRef,
}: DataTableWrapperProps<TData, TValue>) {
const tableContainerRef = useRef<HTMLDivElement>(null);
const internalRef = useRef<HTMLDivElement>(null);
const tableContainerRef = externalRef || internalRef;
const fetchMoreOnBottomReached = useFetchMoreOnBottomReached({
tableContainerRef,
hasNextPage,