@wix/headless-bookings 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/cjs/dist/api/fetch-availability/index.d.ts +5 -5
  2. package/cjs/dist/api/fetch-availability/index.js +9 -6
  3. package/cjs/dist/react/booking/Book.d.ts +49 -0
  4. package/cjs/dist/react/booking/Book.js +46 -0
  5. package/cjs/dist/react/booking/Booking.d.ts +18 -0
  6. package/cjs/dist/react/booking/Booking.js +19 -0
  7. package/cjs/dist/react/core/booking/Book.d.ts +41 -0
  8. package/cjs/dist/react/core/booking/Book.js +59 -0
  9. package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
  10. package/cjs/dist/react/core/time-slot-list/TimeSlot.js +3 -10
  11. package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +3 -3
  12. package/cjs/dist/react/time-slot-list/TimeSlot.js +3 -3
  13. package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +5 -3
  14. package/cjs/dist/services/booking/book-action/bookAction.d.ts +21 -0
  15. package/cjs/dist/services/booking/book-action/bookAction.js +59 -0
  16. package/cjs/dist/services/booking/book-action/buildBookingRequest.d.ts +22 -0
  17. package/cjs/dist/services/booking/book-action/buildBookingRequest.js +81 -0
  18. package/cjs/dist/services/booking/book-action/buildCheckoutRequest.d.ts +26 -0
  19. package/cjs/dist/services/booking/book-action/buildCheckoutRequest.js +62 -0
  20. package/cjs/dist/services/booking/book-action/canBook.d.ts +23 -0
  21. package/cjs/dist/services/booking/book-action/canBook.js +19 -0
  22. package/cjs/dist/services/booking/book-action/index.d.ts +8 -0
  23. package/cjs/dist/services/booking/book-action/index.js +7 -0
  24. package/cjs/dist/services/booking/book-action/types.d.ts +50 -0
  25. package/cjs/dist/services/booking/book-action/types.js +4 -0
  26. package/cjs/dist/services/booking/booking.d.ts +2 -0
  27. package/cjs/dist/services/booking/booking.js +16 -0
  28. package/cjs/dist/services/index.d.ts +1 -0
  29. package/cjs/dist/services/index.js +1 -0
  30. package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +10 -2
  31. package/cjs/dist/services/time-slot-list/time-slot-list.js +9 -29
  32. package/dist/api/fetch-availability/index.d.ts +5 -5
  33. package/dist/api/fetch-availability/index.js +9 -6
  34. package/dist/react/booking/Book.d.ts +49 -0
  35. package/dist/react/booking/Book.js +46 -0
  36. package/dist/react/booking/Booking.d.ts +18 -0
  37. package/dist/react/booking/Booking.js +19 -0
  38. package/dist/react/core/booking/Book.d.ts +41 -0
  39. package/dist/react/core/booking/Book.js +59 -0
  40. package/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
  41. package/dist/react/core/time-slot-list/TimeSlot.js +3 -10
  42. package/dist/react/time-slot-list/TimeSlot.d.ts +3 -3
  43. package/dist/react/time-slot-list/TimeSlot.js +3 -3
  44. package/dist/react/time-slot-list/TimeSlotList.d.ts +5 -3
  45. package/dist/services/booking/book-action/bookAction.d.ts +21 -0
  46. package/dist/services/booking/book-action/bookAction.js +59 -0
  47. package/dist/services/booking/book-action/buildBookingRequest.d.ts +22 -0
  48. package/dist/services/booking/book-action/buildBookingRequest.js +81 -0
  49. package/dist/services/booking/book-action/buildCheckoutRequest.d.ts +26 -0
  50. package/dist/services/booking/book-action/buildCheckoutRequest.js +62 -0
  51. package/dist/services/booking/book-action/canBook.d.ts +23 -0
  52. package/dist/services/booking/book-action/canBook.js +19 -0
  53. package/dist/services/booking/book-action/index.d.ts +8 -0
  54. package/dist/services/booking/book-action/index.js +7 -0
  55. package/dist/services/booking/book-action/types.d.ts +50 -0
  56. package/dist/services/booking/book-action/types.js +4 -0
  57. package/dist/services/booking/booking.d.ts +2 -0
  58. package/dist/services/booking/booking.js +16 -0
  59. package/dist/services/index.d.ts +1 -0
  60. package/dist/services/index.js +1 -0
  61. package/dist/services/time-slot-list/time-slot-list.def.d.ts +10 -2
  62. package/dist/services/time-slot-list/time-slot-list.js +9 -29
  63. package/package.json +4 -3
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Builds the createCheckout request
3
+ */
4
+ import { ChannelType } from '@wix/auto_sdk_ecom_checkout';
5
+ const BOOKINGS_APP_DEF_ID = '13d21c63-b5ec-5912-8397-c3a5ddb27a97';
6
+ /**
7
+ * Builds a checkout request from the booking ID and contact details
8
+ *
9
+ * Contact details come from the booking response and are used to populate:
10
+ * - billingInfo.contactDetails (firstName, lastName, phone)
11
+ * - billingInfo.address (from fullAddress if available)
12
+ * - shippingInfo.shippingDestination.contactDetails
13
+ * - buyerInfo (email, contactId)
14
+ *
15
+ * @param params - The checkout parameters
16
+ * @returns CreateCheckoutRequest ready to be sent to the API
17
+ */
18
+ export function buildCheckoutRequest(params) {
19
+ const { bookingId, contactDetails, businessLocationId } = params;
20
+ // Build checkoutInfo incrementally for readability
21
+ const checkoutInfo = {};
22
+ // businessLocationId for multi-location support
23
+ if (businessLocationId) {
24
+ checkoutInfo.businessLocationId = businessLocationId;
25
+ }
26
+ // Billing info and shipping info from contact details
27
+ if (contactDetails) {
28
+ checkoutInfo.billingInfo = {
29
+ contactDetails,
30
+ ...(contactDetails.fullAddress?.country
31
+ ? { address: { ...contactDetails.fullAddress } }
32
+ : {}),
33
+ };
34
+ checkoutInfo.shippingInfo = {
35
+ shippingDestination: {
36
+ contactDetails,
37
+ },
38
+ };
39
+ }
40
+ // Buyer info with email and contactId
41
+ if (contactDetails?.email) {
42
+ checkoutInfo.buyerInfo = {
43
+ email: contactDetails.email,
44
+ ...(contactDetails.contactId
45
+ ? { contactId: contactDetails.contactId }
46
+ : {}),
47
+ };
48
+ }
49
+ return {
50
+ channelType: ChannelType.WEB,
51
+ lineItems: [
52
+ {
53
+ quantity: 1,
54
+ catalogReference: {
55
+ catalogItemId: bookingId,
56
+ appId: BOOKINGS_APP_DEF_ID,
57
+ },
58
+ },
59
+ ],
60
+ checkoutInfo,
61
+ };
62
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Validation logic for the Book action
3
+ */
4
+ import type { ServiceSelection } from '../booking.js';
5
+ import type { FormValues } from '@wix/form-public';
6
+ /**
7
+ * Parameters for canBook validation
8
+ */
9
+ export interface CanBookParams {
10
+ serviceSelections: ServiceSelection[];
11
+ formSubmission: FormValues | null;
12
+ }
13
+ /**
14
+ * Validates if booking can be executed
15
+ * Checks that all required data is present:
16
+ * - At least one service selection
17
+ * - Each service selection has a time slot selected
18
+ * - Form submission filled
19
+ *
20
+ * @param params - The booking data to validate
21
+ * @returns true if booking can proceed, false otherwise
22
+ */
23
+ export declare function canBook(params: CanBookParams): boolean;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Validation logic for the Book action
3
+ */
4
+ /**
5
+ * Validates if booking can be executed
6
+ * Checks that all required data is present:
7
+ * - At least one service selection
8
+ * - Each service selection has a time slot selected
9
+ * - Form submission filled
10
+ *
11
+ * @param params - The booking data to validate
12
+ * @returns true if booking can proceed, false otherwise
13
+ */
14
+ export function canBook(params) {
15
+ const { serviceSelections, formSubmission } = params;
16
+ return (serviceSelections.length > 0 &&
17
+ serviceSelections.every((item) => item.timeSlot !== undefined) &&
18
+ formSubmission !== null);
19
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Book Action - Exports
3
+ */
4
+ export { executeBookAction } from './bookAction.js';
5
+ export { canBook, type CanBookParams } from './canBook.js';
6
+ export { buildBookingRequest } from './buildBookingRequest.js';
7
+ export { buildCheckoutRequest, type BuildCheckoutParams, } from './buildCheckoutRequest.js';
8
+ export type { BookProps, BookResult, BookingError, BookActionParams, BookChildProps, } from './types.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Book Action - Exports
3
+ */
4
+ export { executeBookAction } from './bookAction.js';
5
+ export { canBook } from './canBook.js';
6
+ export { buildBookingRequest } from './buildBookingRequest.js';
7
+ export { buildCheckoutRequest, } from './buildCheckoutRequest.js';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Types for the Book action
3
+ */
4
+ import type { ServiceSelection, Location } from '../booking.js';
5
+ import type { FormValues } from '@wix/form-public';
6
+ /**
7
+ * Result returned from the book action
8
+ */
9
+ export type BookResult = {
10
+ checkoutId: string;
11
+ };
12
+ /**
13
+ * Error object for booking errors
14
+ */
15
+ export interface BookingError {
16
+ message: string;
17
+ errorObject: unknown;
18
+ }
19
+ /**
20
+ * Parameters for executing the book action
21
+ */
22
+ export interface BookActionParams {
23
+ serviceSelections: ServiceSelection[];
24
+ location: Location | null;
25
+ formSubmission: FormValues | null;
26
+ timezone?: string;
27
+ }
28
+ /**
29
+ * Props passed to children of Book component
30
+ */
31
+ export interface BookChildProps {
32
+ isLoading: boolean;
33
+ error: BookingError | null;
34
+ canBook: boolean;
35
+ onClick: () => void;
36
+ disabled: boolean;
37
+ }
38
+ /**
39
+ * Props for the Book headless component
40
+ */
41
+ export interface BookProps {
42
+ asChild?: boolean;
43
+ children?: React.ReactNode | ((props: BookChildProps) => React.ReactNode);
44
+ className?: string;
45
+ label?: string;
46
+ loadingState?: string;
47
+ disabled?: boolean;
48
+ onCheckoutRequired?: (result: BookResult) => void;
49
+ onError?: (error: BookingError) => void;
50
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Types for the Book action
3
+ */
4
+ export {};
@@ -7,6 +7,7 @@ import { type Signal } from '@wix/services-definitions/core-services/signals';
7
7
  import type { Service } from '@wix/auto_sdk_bookings_services';
8
8
  import type { Resource, EventInfo } from '@wix/auto_sdk_bookings_availability-time-slots';
9
9
  import type { FormValues } from '@wix/form-public';
10
+ import type { BookResult } from './book-action/types.js';
10
11
  export declare const ANY_STAFF_MEMBER_ID = "__any_staff_member__";
11
12
  /**
12
13
  * Minimal time slot data for service selections
@@ -62,6 +63,7 @@ export interface BookingServiceActions {
62
63
  setFormSubmission(values: FormValues | null): void;
63
64
  clearFormSubmission(): void;
64
65
  clearAll(): void;
66
+ book(): Promise<BookResult>;
65
67
  }
66
68
  /**
67
69
  * Booking Service interface
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { defineService, implementService } from '@wix/services-definitions';
7
7
  import { SignalsServiceDefinition, } from '@wix/services-definitions/core-services/signals';
8
+ import { executeBookAction } from './book-action/bookAction.js';
8
9
  // ============================================================================
9
10
  // Constants
10
11
  // ============================================================================
@@ -174,6 +175,21 @@ export const BookingService = implementService.withConfig()(BookingServiceDefini
174
175
  locationSignal.set(null);
175
176
  formSubmissionSignal.set(null);
176
177
  },
178
+ // Book action - collects data from signals and delegates to executeBookAction
179
+ // Loading/error state management is handled in Book.tsx component
180
+ async book() {
181
+ const serviceSelections = serviceSelectionsSignal.get();
182
+ const formSubmission = formSubmissionSignal.get();
183
+ const location = locationSignal.get();
184
+ const timezone = timezoneSignal.get();
185
+ // Validation happens inside executeBookAction
186
+ return executeBookAction({
187
+ serviceSelections,
188
+ formSubmission,
189
+ location,
190
+ timezone,
191
+ });
192
+ },
177
193
  };
178
194
  return {
179
195
  serviceSelections: serviceSelectionsSignal,
@@ -6,4 +6,5 @@ export { ServiceService, ServiceServiceDefinition, type ServiceServiceAPI, type
6
6
  export { BookingService, BookingServiceDefinition, type BookingServiceConfig, type Location, type BookingServiceActions, type ServiceSelection, type ServiceSelectionTimeSlot, } from './booking/booking.js';
7
7
  export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeSlotListConfig, type TimeSlotListServiceAPI, type TimeSlotListServiceActions, type TimeSlotListServiceConfig, type SlotSelection, type TimeSlot, type LoadTimeSlotListConfigOptions, type LoadTimeSlotListConfigResult, } from './time-slot-list/index.js';
8
8
  export { ServiceListService, ServiceListServiceDefinition, type ServiceListServiceAPI, type ServiceListServiceConfig, type ServiceListFilters, type ServiceListActions, type QueryOptions, loadServiceListServiceInitialData, type SuccessServiceListServiceConfigResult, type ErrorServiceListServiceConfigResult, } from './service-list/service-list.js';
9
+ export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, type CanBookParams, type BookResult, type BookingError, type BookActionParams, type BookChildProps, type BookProps, type BuildCheckoutParams, } from './booking/book-action/index.js';
9
10
  export { BookingFormService, BookingFormServiceDefinition, type BookingFormServiceAPI, type BookingFormServiceConfig, type BookingFormServiceInternalAPI, type ValidationResult, } from './booking-form/booking-form.js';
@@ -6,4 +6,5 @@ export { ServiceService, ServiceServiceDefinition, loadServiceServiceInitialData
6
6
  export { BookingService, BookingServiceDefinition, } from './booking/booking.js';
7
7
  export { TimeSlotListService, TimeSlotListServiceDefinition, ViewMode, loadTimeSlotListConfig, } from './time-slot-list/index.js';
8
8
  export { ServiceListService, ServiceListServiceDefinition, loadServiceListServiceInitialData, } from './service-list/service-list.js';
9
+ export { executeBookAction, canBook, buildBookingRequest, buildCheckoutRequest, } from './booking/book-action/index.js';
9
10
  export { BookingFormService, BookingFormServiceDefinition, } from './booking-form/booking-form.js';
@@ -3,8 +3,16 @@
3
3
  * Defines interfaces and service contract for time slot management
4
4
  */
5
5
  import type { Signal } from '@wix/services-definitions/core-services/signals';
6
- import type { TimeSlot as ApiTimeSlot, Location } from '@wix/auto_sdk_bookings_availability-time-slots';
6
+ import type { TimeSlot as ApiTimeSlot, LocationTypeWithLiterals } from '@wix/auto_sdk_bookings_availability-time-slots';
7
7
  import type { Service } from '@wix/auto_sdk_bookings_services';
8
+ /**
9
+ * Location filter input for availability calls.
10
+ * Require a stable `id` + `locationType` pair (no optional fields).
11
+ */
12
+ export interface Location {
13
+ id: string;
14
+ locationType: LocationTypeWithLiterals;
15
+ }
8
16
  export declare enum ViewMode {
9
17
  CLASSIC = "classic",
10
18
  AGENDA = "agenda"
@@ -48,7 +56,7 @@ export interface SlotSelection {
48
56
  */
49
57
  export interface TimeSlotsFilters {
50
58
  /** Filter by specific locations */
51
- locations?: Location[];
59
+ location?: Location;
52
60
  /** Filter by specific staff member IDs */
53
61
  staffMemberIds?: string[];
54
62
  /** Filter by bookable status. If undefined, returns both bookable and non-bookable */
@@ -65,31 +65,13 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
65
65
  * Helper: Get services from config or BookingService
66
66
  */
67
67
  const getServices = () => {
68
- if (config.services?.length)
69
- return config.services;
70
- return bookingService.serviceSelections.get().map((s) => s.service);
71
- };
72
- /**
73
- * Helper: Get filters from config or BookingService
74
- */
75
- const getFilters = () => {
76
- // Get BookingService selections (these take priority)
77
- const location = bookingService.location.get();
78
- const serviceSelections = bookingService.serviceSelections.get();
79
- const selectedStaffMemberIds = serviceSelections
80
- .map((serviceSelection) => serviceSelection.resources.map((r) => r._id))
81
- .flat();
82
- const selectedLocation = location ? { _id: location.id } : null;
83
- // Merge config filters with BookingService selections (selections win)
84
- return {
85
- ...config.filters,
86
- locations: selectedLocation
87
- ? [selectedLocation]
88
- : config.filters?.locations,
89
- staffMemberIds: selectedStaffMemberIds.length
90
- ? selectedStaffMemberIds
91
- : config.filters?.staffMemberIds,
92
- };
68
+ const selectedServices = bookingService.serviceSelections
69
+ .get()
70
+ .map((s) => s.service);
71
+ if (selectedServices.length) {
72
+ return selectedServices;
73
+ }
74
+ return config.services ?? [];
93
75
  };
94
76
  /**
95
77
  * Fetch time slots from API
@@ -97,7 +79,6 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
97
79
  */
98
80
  const fetchTimeSlots = async () => {
99
81
  const selectedServices = getServices();
100
- const filters = getFilters();
101
82
  isLoadingSignal.set(true);
102
83
  errorSignal.set(null);
103
84
  cursorSignal.set(undefined);
@@ -110,7 +91,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
110
91
  timeZone: bookingService.timezone.get(),
111
92
  viewMode: viewModeSignal.get(),
112
93
  cursor: cursorSignal.get(),
113
- ...filters,
94
+ ...config.filters,
114
95
  });
115
96
  timeSlotsSignal.set(response.timeSlots);
116
97
  const nextCursor = response.cursorPagingMetadata?.cursors?.next ?? undefined;
@@ -303,7 +284,6 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
303
284
  if (!cursor || isLoadingSignal.get())
304
285
  return;
305
286
  const selectedServices = getServices();
306
- const filters = getFilters();
307
287
  isLoadingSignal.set(true);
308
288
  try {
309
289
  const response = await fetchAvailability({
@@ -313,7 +293,7 @@ export const TimeSlotListService = implementService.withConfig()(TimeSlotListSer
313
293
  timeZone: bookingService.timezone.get(),
314
294
  cursor,
315
295
  viewMode: viewModeSignal.get(),
316
- ...filters,
296
+ ...config.filters,
317
297
  });
318
298
  // API returns grouped slots, merge with existing
319
299
  const existing = timeSlotsSignal.get();
@@ -2,15 +2,15 @@
2
2
  * Time Slot List API
3
3
  * Fetches available time slots for booking services from Wix Bookings
4
4
  */
5
- import { type Location, type CursorPaging, type CursorPagingMetadata } from '@wix/auto_sdk_bookings_availability-time-slots';
5
+ import { type CursorPaging, type CursorPagingMetadata } from '@wix/auto_sdk_bookings_availability-time-slots';
6
6
  import { type Service } from '@wix/auto_sdk_bookings_services';
7
- import { ViewMode, type TimeSlot } from '../../services/time-slot-list/time-slot-list.def.js';
7
+ import { ViewMode, type TimeSlot, type Location } from '../../services/time-slot-list/time-slot-list.def.js';
8
8
  export interface FetchAvailabilityOptions {
9
9
  services: Service[];
10
10
  fromLocalDate?: string | null;
11
11
  toLocalDate?: string | null;
12
12
  timeZone?: string | null;
13
- locations?: Location[];
13
+ location?: Location;
14
14
  /** Filter by specific staff member IDs (passed as resourceIds to API) */
15
15
  staffMemberIds?: string[];
16
16
  cursorPaging?: CursorPaging;
@@ -52,12 +52,12 @@ export interface FetchAvailabilityResponse {
52
52
  * // response.timeSlots are grouped by time
53
53
  * ```
54
54
  */
55
- export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }: {
55
+ export declare function fetchAvailability({ services: selectedServices, viewMode, fromLocalDate, toLocalDate, timeZone, location, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }: {
56
56
  services: Service[];
57
57
  fromLocalDate: Date;
58
58
  toLocalDate: Date;
59
59
  timeZone?: string;
60
- locations?: Location[];
60
+ location?: Location;
61
61
  staffMemberIds?: string[];
62
62
  cursor?: string;
63
63
  viewMode?: ViewMode;
@@ -115,7 +115,7 @@ function detectFlow(bookingServices, viewMode) {
115
115
  * // response.timeSlots are grouped by time
116
116
  * ```
117
117
  */
118
- export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, locations, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }) {
118
+ export async function fetchAvailability({ services: selectedServices, viewMode = ViewMode.CLASSIC, fromLocalDate, toLocalDate, timeZone, location, staffMemberIds, cursor, slotsPerPage, bookable, bookingPolicyViolations, timeSlotsPerDay, }) {
119
119
  const flow = detectFlow(selectedServices, viewMode);
120
120
  const serviceIds = selectedServices.map((s) => s._id);
121
121
  // Convert Date objects to local ISO strings
@@ -138,6 +138,12 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
138
138
  },
139
139
  ]
140
140
  : undefined;
141
+ const includeResourceTypeIds = isAnyStaffMemberSelected || isFetchAvailabileDays
142
+ ? undefined
143
+ : [STAFF_RESOURCE_TYPE_ID];
144
+ const locations = location
145
+ ? [{ _id: location.id, locationType: location.locationType }]
146
+ : undefined;
141
147
  const response = await listAvailabilityTimeSlots({
142
148
  serviceId: serviceIds[0],
143
149
  fromLocalDate: fromLocalDateStr,
@@ -148,9 +154,7 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
148
154
  resourceTypes,
149
155
  bookable,
150
156
  bookingPolicyViolations,
151
- includeResourceTypeIds: isAnyStaffMemberSelected || isFetchAvailabileDays
152
- ? undefined
153
- : [STAFF_RESOURCE_TYPE_ID],
157
+ includeResourceTypeIds,
154
158
  timeSlotsPerDay,
155
159
  });
156
160
  return {
@@ -164,7 +168,7 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
164
168
  }
165
169
  if (flow === FlowType.CLASS) {
166
170
  // Build eventFilter for location and staff filtering
167
- const locationIds = locations?.map((l) => l._id);
171
+ const locationIds = location ? [location.id] : undefined;
168
172
  const eventFilter = {};
169
173
  if (locationIds?.length) {
170
174
  eventFilter['location.id'] = locationIds;
@@ -185,7 +189,6 @@ export async function fetchAvailability({ services: selectedServices, viewMode =
185
189
  });
186
190
  return {
187
191
  timeSlots: groupTimeSlotsByTime(response.timeSlots || []),
188
- // Note: listEventTimeSlots uses pagingMetadata instead of cursorPagingMetadata
189
192
  cursorPagingMetadata: response.pagingMetadata,
190
193
  };
191
194
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Book - High-level headless component for the book action button
3
+ * Wraps core Book with AsChildSlot pattern for customization
4
+ */
5
+ import React from 'react';
6
+ import type { BookChildProps, BookResult, BookingError } from '../../services/booking/book-action/types.js';
7
+ /**
8
+ * Props for the high-level Book component
9
+ */
10
+ export interface BookProps {
11
+ asChild?: boolean;
12
+ children?: React.ReactNode | ((props: BookChildProps) => React.ReactNode);
13
+ className?: string;
14
+ label?: string;
15
+ loadingState?: string;
16
+ disabled?: boolean;
17
+ onCheckoutRequired?: (result: BookResult) => void;
18
+ onError?: (error: BookingError) => void;
19
+ }
20
+ /**
21
+ * Book action button component with AsChildSlot pattern
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * // Simple usage
26
+ * <Booking.Actions.Book />
27
+ *
28
+ * // With callbacks
29
+ * <Booking.Actions.Book
30
+ * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
31
+ * onError={(error) => console.error(error.message)}
32
+ * />
33
+ *
34
+ * // With render function
35
+ * <Booking.Actions.Book onCheckoutRequired={handleCheckout}>
36
+ * {({ isLoading, error, canBook, onClick, disabled }) => (
37
+ * <button onClick={onClick} disabled={disabled}>
38
+ * {isLoading ? <Spinner /> : 'Book Now'}
39
+ * </button>
40
+ * )}
41
+ * </Booking.Actions.Book>
42
+ *
43
+ * // With asChild
44
+ * <Booking.Actions.Book asChild onCheckoutRequired={handleCheckout}>
45
+ * <CustomBookButton />
46
+ * </Booking.Actions.Book>
47
+ * ```
48
+ */
49
+ export declare const Book: React.ForwardRefExoticComponent<BookProps & React.RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Book - High-level headless component for the book action button
4
+ * Wraps core Book with AsChildSlot pattern for customization
5
+ */
6
+ import React from 'react';
7
+ import { AsChildSlot } from '@wix/headless-utils/react';
8
+ import * as CoreBook from '../core/booking/Book.js';
9
+ var TestIds;
10
+ (function (TestIds) {
11
+ TestIds["bookingActionBook"] = "booking-action-book";
12
+ })(TestIds || (TestIds = {}));
13
+ /**
14
+ * Book action button component with AsChildSlot pattern
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * // Simple usage
19
+ * <Booking.Actions.Book />
20
+ *
21
+ * // With callbacks
22
+ * <Booking.Actions.Book
23
+ * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
24
+ * onError={(error) => console.error(error.message)}
25
+ * />
26
+ *
27
+ * // With render function
28
+ * <Booking.Actions.Book onCheckoutRequired={handleCheckout}>
29
+ * {({ isLoading, error, canBook, onClick, disabled }) => (
30
+ * <button onClick={onClick} disabled={disabled}>
31
+ * {isLoading ? <Spinner /> : 'Book Now'}
32
+ * </button>
33
+ * )}
34
+ * </Booking.Actions.Book>
35
+ *
36
+ * // With asChild
37
+ * <Booking.Actions.Book asChild onCheckoutRequired={handleCheckout}>
38
+ * <CustomBookButton />
39
+ * </Booking.Actions.Book>
40
+ * ```
41
+ */
42
+ export const Book = React.forwardRef((props, ref) => {
43
+ const { asChild, children, className, label = 'Book Now', loadingState = 'Booking...', disabled, onCheckoutRequired, onError, } = props;
44
+ return (_jsx(CoreBook.Book, { onCheckoutRequired: onCheckoutRequired, onError: onError, disabled: disabled, children: (childProps) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.bookingActionBook, "data-in-progress": childProps.isLoading, customElement: children, customElementProps: childProps, children: _jsx("button", { onClick: childProps.onClick, disabled: childProps.disabled, children: childProps.isLoading ? loadingState : label }) })) }));
45
+ });
46
+ Book.displayName = 'Booking.Actions.Book';
@@ -34,3 +34,21 @@ export declare const Root: {
34
34
  (props: BookingRootProps): React.ReactNode;
35
35
  displayName: string;
36
36
  };
37
+ /**
38
+ * Actions namespace containing action components for booking
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * // Simple usage
43
+ * <Booking.Actions.Book />
44
+ *
45
+ * // With callbacks
46
+ * <Booking.Actions.Book
47
+ * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
48
+ * onError={(error) => toast.error(error)}
49
+ * />
50
+ * ```
51
+ */
52
+ export declare const Actions: {
53
+ Book: React.ForwardRefExoticComponent<import("./Book.js").BookProps & React.RefAttributes<HTMLButtonElement>>;
54
+ };
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import * as CoreBooking from '../core/booking/Booking.js';
3
+ import { Book } from './Book.js';
3
4
  /**
4
5
  * Root component that provides booking context to the entire app.
5
6
  *
@@ -23,3 +24,21 @@ export const Root = (props) => {
23
24
  return (_jsx(CoreBooking.Root, { bookingServiceConfig: bookingServiceConfig, children: children }));
24
25
  };
25
26
  Root.displayName = 'Booking.Root';
27
+ /**
28
+ * Actions namespace containing action components for booking
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * // Simple usage
33
+ * <Booking.Actions.Book />
34
+ *
35
+ * // With callbacks
36
+ * <Booking.Actions.Book
37
+ * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
38
+ * onError={(error) => toast.error(error)}
39
+ * />
40
+ * ```
41
+ */
42
+ export const Actions = {
43
+ Book,
44
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Core Book - Provides book action data via render props
3
+ * NO AsChildSlot, NO asChild - that belongs in high-level component
4
+ */
5
+ import React from 'react';
6
+ import type { BookResult, BookingError } from '../../../services/booking/book-action/types.js';
7
+ /**
8
+ * Data exposed by Book component via render props
9
+ */
10
+ export interface BookData {
11
+ isLoading: boolean;
12
+ error: BookingError | null;
13
+ canBook: boolean;
14
+ onClick: () => Promise<void>;
15
+ disabled: boolean;
16
+ }
17
+ /**
18
+ * Props for core Book component
19
+ */
20
+ export interface BookProps {
21
+ children: (data: BookData) => React.ReactNode;
22
+ onCheckoutRequired?: (result: BookResult) => void;
23
+ onError?: (error: BookingError) => void;
24
+ disabled?: boolean;
25
+ }
26
+ /**
27
+ * Core Book component - provides book action data via render props.
28
+ * Used internally by higher-level Booking.Actions.Book component.
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * <Book onCheckoutRequired={handleCheckout}>
33
+ * {({ isLoading, error, canBook, onClick, disabled }) => (
34
+ * <button onClick={onClick} disabled={disabled}>
35
+ * {isLoading ? 'Booking...' : 'Book Now'}
36
+ * </button>
37
+ * )}
38
+ * </Book>
39
+ * ```
40
+ */
41
+ export declare function Book(props: BookProps): React.ReactNode;