52d5261b51
* display UTM parameters * persist view (list | calendar) in localStorage * move to next page on clicking "next" of last item in the page improve navigation ^ Conflicts: ^ apps/web/modules/bookings/components/BookingCalendarContainer.tsx * fix navigation on calendar view * Delete apps/web/modules/bookings/NAVIGATION_IMPLEMENTATION.md * avoid page size being 0 * check feature flag on user level * use map to improve useBookingListData * address feedback * feat(bookings): add smart navigation for calendar view - Add sort option to tRPC bookings.get schema and handler - Create NAVIGATION_PROBE_WINDOW_MONTHS constant (3 months) - Create useNearestFutureBooking hook to find nearest future booking - Create useNearestPastBooking hook to find nearest past booking - Update useCalendarNavigationCapabilities to use probe results - Update BookingCalendarContainer to wire up probe hooks This enables the booking details sheet to: - Disable next/prev buttons when no bookings exist in that direction - Jump directly to the week containing the nearest booking Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix type error * feat: add booking selection state when using slideover (#25637) * implement booking selection when using slideover * remove pixel shift * fix * auto scroll to selected event on calendar * make DateValues header sticky when scrolling --------- Co-authored-by: Eunjae Lee <hey@eunjae.dev> * prefetch previous / next weeks on calendar view * clean up classes * handle "fetched & but no data" situation more correctly in useCalendarAutoSelector --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
127 lines
4.5 KiB
TypeScript
127 lines
4.5 KiB
TypeScript
import { useCallback, useMemo, useEffect } from "react";
|
|
|
|
import type { Dayjs } from "@calcom/dayjs";
|
|
import dayjs from "@calcom/dayjs";
|
|
import { trpc } from "@calcom/trpc/react";
|
|
|
|
import { getWeekStart } from "../lib/weekUtils";
|
|
import type { NavigationCapabilities } from "../store/bookingDetailsSheetStore";
|
|
import type { BookingListingStatus } from "../types";
|
|
import { useNearestFutureBooking } from "./useNearestFutureBooking";
|
|
import { useNearestPastBooking } from "./useNearestPastBooking";
|
|
|
|
interface UseCalendarNavigationCapabilitiesProps {
|
|
currentWeekStart: Dayjs;
|
|
setCurrentWeekStart: (date: Dayjs) => void;
|
|
userWeekStart: number;
|
|
/** Filters to use for probe queries and prefetching */
|
|
filters: {
|
|
statuses: BookingListingStatus[];
|
|
userIds?: number[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Calendar view navigation capabilities adapter.
|
|
* Provides week-based navigation logic for the booking details sheet.
|
|
*
|
|
* This hook:
|
|
* - Uses probe queries to find nearest bookings in each direction
|
|
* - Jumps directly to the week containing the nearest booking (not just adjacent week)
|
|
* - Disables navigation buttons when no bookings exist in that direction
|
|
* - Prefetches booking data for the target weeks to improve navigation performance
|
|
*/
|
|
export function useCalendarNavigationCapabilities({
|
|
currentWeekStart,
|
|
setCurrentWeekStart,
|
|
userWeekStart,
|
|
filters,
|
|
}: UseCalendarNavigationCapabilitiesProps): NavigationCapabilities {
|
|
const trpcUtils = trpc.useUtils();
|
|
|
|
// Probe queries for navigation - find nearest bookings in each direction
|
|
const { nearestBooking: nearestFutureBooking } = useNearestFutureBooking({
|
|
currentWeekStart,
|
|
filters,
|
|
});
|
|
|
|
const { nearestBooking: nearestPastBooking } = useNearestPastBooking({
|
|
currentWeekStart,
|
|
filters,
|
|
});
|
|
|
|
const hasFutureBooking = !!nearestFutureBooking;
|
|
const hasPastBooking = !!nearestPastBooking;
|
|
const nextBookingDate = nearestFutureBooking?.startTime?.toString() ?? null;
|
|
const prevBookingDate = nearestPastBooking?.startTime?.toString() ?? null;
|
|
|
|
// Calculate target week starts for prefetching
|
|
const nextWeekStart = useMemo(() => {
|
|
if (!nextBookingDate) return null;
|
|
return getWeekStart(dayjs(nextBookingDate), userWeekStart);
|
|
}, [nextBookingDate, userWeekStart]);
|
|
|
|
const prevWeekStart = useMemo(() => {
|
|
if (!prevBookingDate) return null;
|
|
return getWeekStart(dayjs(prevBookingDate), userWeekStart);
|
|
}, [prevBookingDate, userWeekStart]);
|
|
|
|
// Prefetch bookings for the next week with bookings
|
|
// Uses prefetchInfinite to match the useInfiniteQuery used in BookingCalendarContainer
|
|
useEffect(() => {
|
|
if (!nextWeekStart) return;
|
|
|
|
trpcUtils.viewer.bookings.get.prefetchInfinite({
|
|
limit: 100,
|
|
filters: {
|
|
statuses: filters.statuses,
|
|
userIds: filters.userIds,
|
|
afterStartDate: nextWeekStart.startOf("day").toISOString(),
|
|
beforeEndDate: nextWeekStart.add(6, "day").endOf("day").toISOString(),
|
|
},
|
|
});
|
|
}, [nextWeekStart, filters.statuses, filters.userIds, trpcUtils]);
|
|
|
|
// Prefetch bookings for the previous week with bookings
|
|
// Uses prefetchInfinite to match the useInfiniteQuery used in BookingCalendarContainer
|
|
useEffect(() => {
|
|
if (!prevWeekStart) return;
|
|
|
|
trpcUtils.viewer.bookings.get.prefetchInfinite({
|
|
limit: 100,
|
|
filters: {
|
|
statuses: filters.statuses,
|
|
userIds: filters.userIds,
|
|
afterStartDate: prevWeekStart.startOf("day").toISOString(),
|
|
beforeEndDate: prevWeekStart.add(6, "day").endOf("day").toISOString(),
|
|
},
|
|
});
|
|
}, [prevWeekStart, filters.statuses, filters.userIds, trpcUtils]);
|
|
|
|
const canNavigateToNextPeriod = useCallback(() => hasFutureBooking, [hasFutureBooking]);
|
|
|
|
const canNavigateToPreviousPeriod = useCallback(() => hasPastBooking, [hasPastBooking]);
|
|
|
|
const requestNextPeriod = useCallback(() => {
|
|
if (!nextBookingDate) return;
|
|
const targetWeekStart = getWeekStart(dayjs(nextBookingDate), userWeekStart);
|
|
setCurrentWeekStart(targetWeekStart);
|
|
}, [nextBookingDate, setCurrentWeekStart, userWeekStart]);
|
|
|
|
const requestPreviousPeriod = useCallback(() => {
|
|
if (!prevBookingDate) return;
|
|
const targetWeekStart = getWeekStart(dayjs(prevBookingDate), userWeekStart);
|
|
setCurrentWeekStart(targetWeekStart);
|
|
}, [prevBookingDate, setCurrentWeekStart, userWeekStart]);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
canNavigateToNextPeriod,
|
|
canNavigateToPreviousPeriod,
|
|
requestNextPeriod,
|
|
requestPreviousPeriod,
|
|
}),
|
|
[canNavigateToNextPeriod, canNavigateToPreviousPeriod, requestNextPeriod, requestPreviousPeriod]
|
|
);
|
|
}
|