feat: Add handleSlotSelect prop for custom timeslot selection/reservation handling (#21133)
* feat: Add `handleSlotSelect` prop for custom timeslot selection/reservation handling * Update custom-slot-select-flow.mdx * Update custom-slot-select-flow.mdx * refactor: rename handleSlotSelect to handleSlotReservation for clearer intent * docs: add API reference link for slot reservation api
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
## Using `handleSlotReservation` for Custom Slot Selection Flows
|
||||
|
||||
If you want to trigger a custom action immediately when a user selects a timeslot (before the booking form appears), you can use the `handleSlotReservation` prop. This prop allows you to intercept the slot selection event, enabling you to run custom logic—such as calling the reserve slot api's https://cal.com/docs/api-reference/v2/slots/reserve-a-slot.
|
||||
|
||||
**Example usage:**
|
||||
|
||||
```tsx
|
||||
<Booker
|
||||
handleSlotReservation={(timeslot) => {
|
||||
// Your custom logic here
|
||||
console.log("User selected timeslot:", timeslot);
|
||||
// For example, call the reserve slot api's etc.
|
||||
}}
|
||||
// ...other props
|
||||
/>
|
||||
```
|
||||
|
||||
- When a user selects a slot, the `handleSlotReservation` function will be called with the selected timeslot as its argument.
|
||||
- If you provide this prop, the default slot reservation flow will be interrupted until your custom logic is complete.
|
||||
- This is useful for introducing custom slot reservation flows.
|
||||
@@ -25,6 +25,7 @@ export const BookerEmbed = (
|
||||
hostsLimit?: BookerPlatformWrapperAtomPropsForTeam["hostsLimit"];
|
||||
metadata?: BookerPlatformWrapperAtomPropsForTeam["metadata"];
|
||||
handleCreateBooking?: BookerPlatformWrapperAtomPropsForTeam["handleCreateBooking"];
|
||||
handleSlotReservation?: BookerPlatformWrapperAtomPropsForTeam["handleSlotReservation"];
|
||||
preventEventTypeRedirect?: BookerPlatformWrapperAtomPropsForTeam["preventEventTypeRedirect"];
|
||||
}
|
||||
| (BookerPlatformWrapperAtomPropsForIndividual & {
|
||||
|
||||
@@ -60,6 +60,7 @@ export const BookerPlatformWrapper = (
|
||||
allowUpdatingUrlParams = false,
|
||||
confirmButtonDisabled,
|
||||
isBookingDryRun,
|
||||
handleSlotReservation,
|
||||
} = props;
|
||||
const layout = BookerLayouts[view];
|
||||
|
||||
@@ -400,6 +401,7 @@ export const BookerPlatformWrapper = (
|
||||
onDeleteSlotSuccess: props.onDeleteSlotSuccess,
|
||||
onDeleteSlotError: props.onDeleteSlotError,
|
||||
isBookingDryRun: routingParams?.isBookingDryRun,
|
||||
handleSlotReservation,
|
||||
});
|
||||
|
||||
const { data: connectedCalendars, isPending: fetchingConnectedCalendars } = useConnectedCalendars({
|
||||
|
||||
@@ -66,6 +66,7 @@ export type BookerPlatformWrapperAtomProps = Omit<
|
||||
onDeleteSlotSuccess?: (data: ApiSuccessResponseWithoutData) => void;
|
||||
onDeleteSlotError?: (data: ApiErrorResponse) => void;
|
||||
onBookerStateChange?: (state: BookerStoreValues) => void;
|
||||
handleSlotReservation?: (timeslot: string) => void;
|
||||
locationUrl?: string;
|
||||
view?: VIEW_TYPE;
|
||||
metadata?: Record<string, string>;
|
||||
|
||||
@@ -20,6 +20,7 @@ type UseSlotsCallbacks = {
|
||||
onReserveSlotError?: (err: ApiErrorResponse) => void;
|
||||
onDeleteSlotSuccess?: (data: ApiSuccessResponseWithoutData) => void;
|
||||
onDeleteSlotError?: (err: ApiErrorResponse) => void;
|
||||
handleSlotReservation?: (timeslot: string) => void;
|
||||
};
|
||||
|
||||
export type UseSlotsReturnType = ReturnType<typeof useSlots>;
|
||||
@@ -32,6 +33,7 @@ export const useSlots = (
|
||||
onDeleteSlotSuccess,
|
||||
onDeleteSlotError,
|
||||
isBookingDryRun,
|
||||
handleSlotReservation,
|
||||
}: UseSlotsCallbacks & { isBookingDryRun?: boolean } = {}
|
||||
) => {
|
||||
const selectedDuration = useBookerStore((state) => state.selectedDuration);
|
||||
@@ -63,6 +65,11 @@ export const useSlots = (
|
||||
|
||||
const handleReserveSlot = () => {
|
||||
if (event?.data?.id && selectedTimeslot && (selectedDuration || event?.data?.length)) {
|
||||
if (handleSlotReservation) {
|
||||
handleSlotReservation(selectedTimeslot);
|
||||
return;
|
||||
}
|
||||
|
||||
reserveSlotMutation.mutate({
|
||||
slotUtcStartDate: dayjs(selectedTimeslot).utc().format(),
|
||||
eventTypeId: event.data.id,
|
||||
|
||||
@@ -57,6 +57,7 @@ export const Router = React.memo(
|
||||
| "hostsLimit"
|
||||
| "metadata"
|
||||
| "handleCreateBooking"
|
||||
| "handleSlotReservation"
|
||||
| "preventEventTypeRedirect"
|
||||
>;
|
||||
renderLoader?: (isLoading?: boolean) => ReactElement | ReactElement[];
|
||||
|
||||
@@ -131,8 +131,10 @@ export default function Bookings(props: { calUsername: string; calEmail: string
|
||||
? { isTeamEvent: true, teamId: teams?.[0]?.id || 0 }
|
||||
: { username: props.calUsername })}
|
||||
hostsLimit={3}
|
||||
selectedDate={new Date("2025-03-25")}
|
||||
allowUpdatingUrlParams={true}
|
||||
handleSlotReservation={(timeslot) => {
|
||||
console.log("Selected timeslot:", timeslot);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user