Files
Eunjae LeeGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>sean-brydon
52d5261b51 feat(booking): implement cross-page/week navigation in booking details sheet with view persistence (#25545)
* 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: [email protected] <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>
2025-12-15 16:04:00 +00:00

50 lines
1.7 KiB
TypeScript

import { ErrorWithCode } from "@calcom/lib/errors";
import type { PrismaClient } from "@calcom/prisma";
import { BookingRepository } from "../repositories/BookingRepository";
import { BookingAccessService } from "./BookingAccessService";
export class BookingDetailsService {
private bookingRepo: BookingRepository;
private bookingAccessService: BookingAccessService;
constructor(prismaClient: PrismaClient) {
this.bookingRepo = new BookingRepository(prismaClient);
this.bookingAccessService = new BookingAccessService(prismaClient);
}
async getBookingDetails({ userId, bookingUid }: { userId: number; bookingUid: string }) {
const hasAccess = await this.bookingAccessService.checkBookingAccessWithPBAC({
userId,
bookingUid,
});
if (!hasAccess) {
throw ErrorWithCode.Factory.Forbidden("You do not have permission to view this booking");
}
const booking = await this.bookingRepo.findByUidForDetails({ bookingUid });
if (!booking) {
throw ErrorWithCode.Factory.BookingNotFound("Booking not found");
}
const [rescheduledToBooking, previousBooking] = await Promise.all([
// For old rescheduled bookings, find the new booking
booking.rescheduled
? this.bookingRepo.findRescheduledToBooking({ bookingUid: booking.uid })
: Promise.resolve(null),
// For new bookings that replaced an old one, fetch the previous booking's schedule
booking.fromReschedule
? this.bookingRepo.findPreviousBooking({ fromReschedule: booking.fromReschedule })
: Promise.resolve(null),
]);
return {
rescheduledToBooking,
previousBooking,
tracking: booking.tracking,
};
}
}