@wix/headless-bookings 0.0.25 → 0.0.27

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 (75) hide show
  1. package/cjs/dist/api/create-booking/index.d.ts +42 -0
  2. package/cjs/dist/api/create-booking/index.js +35 -0
  3. package/cjs/dist/api/create-checkout/index.d.ts +40 -0
  4. package/cjs/dist/api/create-checkout/index.js +37 -0
  5. package/cjs/dist/api/fetch-availability/index.d.ts +5 -5
  6. package/cjs/dist/api/fetch-availability/index.js +9 -6
  7. package/cjs/dist/api/index.d.ts +2 -0
  8. package/cjs/dist/api/index.js +2 -0
  9. package/cjs/dist/react/booking/Book.d.ts +49 -0
  10. package/cjs/dist/react/booking/Book.js +46 -0
  11. package/cjs/dist/react/booking/Booking.d.ts +18 -0
  12. package/cjs/dist/react/booking/Booking.js +19 -0
  13. package/cjs/dist/react/core/booking/Book.d.ts +41 -0
  14. package/cjs/dist/react/core/booking/Book.js +59 -0
  15. package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
  16. package/cjs/dist/react/core/time-slot-list/TimeSlot.js +3 -10
  17. package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +3 -3
  18. package/cjs/dist/react/time-slot-list/TimeSlot.js +3 -3
  19. package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +5 -3
  20. package/cjs/dist/services/booking/book-action/bookAction.d.ts +21 -0
  21. package/cjs/dist/services/booking/book-action/bookAction.js +59 -0
  22. package/cjs/dist/services/booking/book-action/buildBookingRequest.d.ts +22 -0
  23. package/cjs/dist/services/booking/book-action/buildBookingRequest.js +81 -0
  24. package/cjs/dist/services/booking/book-action/buildCheckoutRequest.d.ts +26 -0
  25. package/cjs/dist/services/booking/book-action/buildCheckoutRequest.js +62 -0
  26. package/cjs/dist/services/booking/book-action/canBook.d.ts +23 -0
  27. package/cjs/dist/services/booking/book-action/canBook.js +19 -0
  28. package/cjs/dist/services/booking/book-action/index.d.ts +8 -0
  29. package/cjs/dist/services/booking/book-action/index.js +7 -0
  30. package/cjs/dist/services/booking/book-action/types.d.ts +50 -0
  31. package/cjs/dist/services/booking/book-action/types.js +4 -0
  32. package/cjs/dist/services/booking/booking.d.ts +2 -0
  33. package/cjs/dist/services/booking/booking.js +16 -0
  34. package/cjs/dist/services/index.d.ts +1 -0
  35. package/cjs/dist/services/index.js +1 -0
  36. package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +10 -2
  37. package/cjs/dist/services/time-slot-list/time-slot-list.js +9 -29
  38. package/dist/api/create-booking/index.d.ts +42 -0
  39. package/dist/api/create-booking/index.js +35 -0
  40. package/dist/api/create-checkout/index.d.ts +40 -0
  41. package/dist/api/create-checkout/index.js +37 -0
  42. package/dist/api/fetch-availability/index.d.ts +5 -5
  43. package/dist/api/fetch-availability/index.js +9 -6
  44. package/dist/api/index.d.ts +2 -0
  45. package/dist/api/index.js +2 -0
  46. package/dist/react/booking/Book.d.ts +49 -0
  47. package/dist/react/booking/Book.js +46 -0
  48. package/dist/react/booking/Booking.d.ts +18 -0
  49. package/dist/react/booking/Booking.js +19 -0
  50. package/dist/react/core/booking/Book.d.ts +41 -0
  51. package/dist/react/core/booking/Book.js +59 -0
  52. package/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
  53. package/dist/react/core/time-slot-list/TimeSlot.js +3 -10
  54. package/dist/react/time-slot-list/TimeSlot.d.ts +3 -3
  55. package/dist/react/time-slot-list/TimeSlot.js +3 -3
  56. package/dist/react/time-slot-list/TimeSlotList.d.ts +5 -3
  57. package/dist/services/booking/book-action/bookAction.d.ts +21 -0
  58. package/dist/services/booking/book-action/bookAction.js +59 -0
  59. package/dist/services/booking/book-action/buildBookingRequest.d.ts +22 -0
  60. package/dist/services/booking/book-action/buildBookingRequest.js +81 -0
  61. package/dist/services/booking/book-action/buildCheckoutRequest.d.ts +26 -0
  62. package/dist/services/booking/book-action/buildCheckoutRequest.js +62 -0
  63. package/dist/services/booking/book-action/canBook.d.ts +23 -0
  64. package/dist/services/booking/book-action/canBook.js +19 -0
  65. package/dist/services/booking/book-action/index.d.ts +8 -0
  66. package/dist/services/booking/book-action/index.js +7 -0
  67. package/dist/services/booking/book-action/types.d.ts +50 -0
  68. package/dist/services/booking/book-action/types.js +4 -0
  69. package/dist/services/booking/booking.d.ts +2 -0
  70. package/dist/services/booking/booking.js +16 -0
  71. package/dist/services/index.d.ts +1 -0
  72. package/dist/services/index.js +1 -0
  73. package/dist/services/time-slot-list/time-slot-list.def.d.ts +10 -2
  74. package/dist/services/time-slot-list/time-slot-list.js +9 -29
  75. package/package.json +4 -3
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Create Booking API
3
+ * Wrapper for the Wix Bookings createBooking SDK function
4
+ */
5
+ import { type Booking, type CreateBookingResponse, type ParticipantNotification } from '@wix/auto_sdk_bookings_bookings';
6
+ import type { FormValues } from '@wix/form-public';
7
+ /**
8
+ * Options for creating a booking
9
+ */
10
+ export interface CreateBookingOptions {
11
+ /** Notification settings for participants */
12
+ participantNotification?: ParticipantNotification;
13
+ /** Whether to send SMS reminder */
14
+ sendSmsReminder?: boolean;
15
+ /** Form submission data */
16
+ formSubmission?: FormValues;
17
+ }
18
+ /**
19
+ * Creates a booking with the specified booking data and options
20
+ *
21
+ * @param booking - The booking data
22
+ * @param options - Optional settings for notifications and form submission
23
+ * @returns Promise resolving to the created booking response
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const response = await createBooking(
28
+ * {
29
+ * selectedPaymentOption: 'ONLINE',
30
+ * totalParticipants: 1,
31
+ * bookedEntity: { slot: { ... } }
32
+ * },
33
+ * {
34
+ * participantNotification: { notifyParticipants: true },
35
+ * sendSmsReminder: true,
36
+ * formSubmission: formValues
37
+ * }
38
+ * );
39
+ * ```
40
+ */
41
+ export declare function createBooking(booking: Booking, options?: CreateBookingOptions): Promise<CreateBookingResponse>;
42
+ export type { Booking, CreateBookingRequest, CreateBookingResponse, ParticipantNotification, ContactDetails, } from '@wix/auto_sdk_bookings_bookings';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Create Booking API
3
+ * Wrapper for the Wix Bookings createBooking SDK function
4
+ */
5
+ import { createBooking as createBookingSdk, } from '@wix/auto_sdk_bookings_bookings';
6
+ /**
7
+ * Creates a booking with the specified booking data and options
8
+ *
9
+ * @param booking - The booking data
10
+ * @param options - Optional settings for notifications and form submission
11
+ * @returns Promise resolving to the created booking response
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const response = await createBooking(
16
+ * {
17
+ * selectedPaymentOption: 'ONLINE',
18
+ * totalParticipants: 1,
19
+ * bookedEntity: { slot: { ... } }
20
+ * },
21
+ * {
22
+ * participantNotification: { notifyParticipants: true },
23
+ * sendSmsReminder: true,
24
+ * formSubmission: formValues
25
+ * }
26
+ * );
27
+ * ```
28
+ */
29
+ export async function createBooking(booking, options) {
30
+ return createBookingSdk(booking, {
31
+ participantNotification: options?.participantNotification,
32
+ sendSmsReminder: options?.sendSmsReminder,
33
+ formSubmission: options?.formSubmission,
34
+ });
35
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Create Checkout API
3
+ * Wrapper for the Wix eCommerce createCheckout SDK function
4
+ */
5
+ import { type CreateCheckoutRequest, type Checkout } from '@wix/auto_sdk_ecom_checkout';
6
+ /**
7
+ * Response from createCheckout API
8
+ */
9
+ export interface CreateCheckoutResponse {
10
+ /** The created checkout */
11
+ checkout?: Checkout;
12
+ }
13
+ /**
14
+ * Creates a checkout session with the specified request data
15
+ *
16
+ * @param request - The checkout request data including line items and checkout info
17
+ * @returns Promise resolving to the created checkout response
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const response = await createCheckout({
22
+ * channelType: ChannelType.WEB,
23
+ * lineItems: [
24
+ * {
25
+ * quantity: 1,
26
+ * catalogReference: {
27
+ * catalogItemId: bookingId,
28
+ * appId: BOOKINGS_APP_DEF_ID,
29
+ * },
30
+ * },
31
+ * ],
32
+ * checkoutInfo: {
33
+ * businessLocationId,
34
+ * billingInfo: { ... },
35
+ * },
36
+ * });
37
+ * ```
38
+ */
39
+ export declare function createCheckout(request: CreateCheckoutRequest): Promise<CreateCheckoutResponse>;
40
+ export { ChannelType, type CreateCheckoutRequest, } from '@wix/auto_sdk_ecom_checkout';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Create Checkout API
3
+ * Wrapper for the Wix eCommerce createCheckout SDK function
4
+ */
5
+ import { createCheckout as createCheckoutSdk, } from '@wix/auto_sdk_ecom_checkout';
6
+ /**
7
+ * Creates a checkout session with the specified request data
8
+ *
9
+ * @param request - The checkout request data including line items and checkout info
10
+ * @returns Promise resolving to the created checkout response
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const response = await createCheckout({
15
+ * channelType: ChannelType.WEB,
16
+ * lineItems: [
17
+ * {
18
+ * quantity: 1,
19
+ * catalogReference: {
20
+ * catalogItemId: bookingId,
21
+ * appId: BOOKINGS_APP_DEF_ID,
22
+ * },
23
+ * },
24
+ * ],
25
+ * checkoutInfo: {
26
+ * businessLocationId,
27
+ * billingInfo: { ... },
28
+ * },
29
+ * });
30
+ * ```
31
+ */
32
+ export async function createCheckout(request) {
33
+ const checkout = await createCheckoutSdk(request);
34
+ return { checkout };
35
+ }
36
+ // Re-export types and constants that consumers may need
37
+ export { ChannelType, } from '@wix/auto_sdk_ecom_checkout';
@@ -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
  }
@@ -6,6 +6,8 @@
6
6
  */
7
7
  export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, type ServiceListFilters, type QueryServicesRequest, } from './query-services/index.js';
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
+ export { createBooking, type CreateBookingOptions, type Booking, type CreateBookingRequest, type CreateBookingResponse, type ParticipantNotification, type ContactDetails, } from './create-booking/index.js';
10
+ export { createCheckout, ChannelType, type CreateCheckoutRequest, type CreateCheckoutResponse, } from './create-checkout/index.js';
9
11
  /**
10
12
  * PagingMetadata includes:
11
13
  * - limit: Number of items per page
@@ -6,6 +6,8 @@
6
6
  */
7
7
  export { getServiceById, getServiceBySlug, queryServices, } from './query-services/index.js';
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
+ export { createBooking, } from './create-booking/index.js';
10
+ export { createCheckout, ChannelType, } from './create-checkout/index.js';
9
11
  /**
10
12
  * PagingMetadata includes:
11
13
  * - limit: Number of items per page
@@ -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;
@@ -0,0 +1,59 @@
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 { useState } from 'react';
6
+ import { useService } from '@wix/services-manager-react';
7
+ import { BookingServiceDefinition } from '../../../services/booking/booking.js';
8
+ import { canBook } from '../../../services/booking/book-action/canBook.js';
9
+ /**
10
+ * Core Book component - provides book action data via render props.
11
+ * Used internally by higher-level Booking.Actions.Book component.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <Book onCheckoutRequired={handleCheckout}>
16
+ * {({ isLoading, error, canBook, onClick, disabled }) => (
17
+ * <button onClick={onClick} disabled={disabled}>
18
+ * {isLoading ? 'Booking...' : 'Book Now'}
19
+ * </button>
20
+ * )}
21
+ * </Book>
22
+ * ```
23
+ */
24
+ export function Book(props) {
25
+ const { children, onCheckoutRequired, onError, disabled } = props;
26
+ const [isLoading, setIsLoading] = useState(false);
27
+ const [error, setError] = useState(null);
28
+ const bookingService = useService(BookingServiceDefinition);
29
+ const serviceSelections = bookingService.serviceSelections.get();
30
+ const formSubmission = bookingService.formSubmission.get();
31
+ const canBookValue = canBook({ serviceSelections, formSubmission });
32
+ const handleClick = async () => {
33
+ setIsLoading(true);
34
+ setError(null);
35
+ try {
36
+ const result = await bookingService.actions.book();
37
+ onCheckoutRequired?.(result);
38
+ }
39
+ catch (e) {
40
+ const bookingError = {
41
+ message: e instanceof Error ? e.message : 'Booking failed',
42
+ errorObject: e,
43
+ };
44
+ setError(bookingError);
45
+ onError?.(bookingError);
46
+ }
47
+ finally {
48
+ setIsLoading(false);
49
+ }
50
+ };
51
+ const isDisabled = isLoading || disabled || !canBookValue;
52
+ return children({
53
+ isLoading,
54
+ error,
55
+ canBook: canBookValue,
56
+ onClick: handleClick,
57
+ disabled: isDisabled,
58
+ });
59
+ }
@@ -89,11 +89,11 @@ export declare function StaffMemberProvider(props: StaffMemberProviderProps): Re
89
89
  export interface InfoProps {
90
90
  children: (data: {
91
91
  /** Parsed localStartDate as Date (constructed from the raw localStartDate string) */
92
- startDate: Date | undefined;
92
+ startDate: Date;
93
93
  /** Parsed localEndDate as Date (constructed from the raw localEndDate string) */
94
- endDate: Date | undefined;
95
- /** Calculated duration in minutes (null if dates unavailable) */
96
- durationInMinutes: number | null;
94
+ endDate: Date;
95
+ /** Calculated duration in minutes */
96
+ durationInMinutes: number;
97
97
  /** Whether the timeSlot is bookable */
98
98
  bookable: boolean;
99
99
  /** Whether this timeSlot is currently selected */
@@ -116,18 +116,11 @@ export function StaffMemberProvider(props) {
116
116
  */
117
117
  export function Info(props) {
118
118
  const { timeSlot, isSelected } = useTimeSlotContext();
119
- const startDate = timeSlot.localStartDate
120
- ? new Date(timeSlot.localStartDate)
121
- : undefined;
122
- const endDate = timeSlot.localEndDate
123
- ? new Date(timeSlot.localEndDate)
124
- : undefined;
119
+ const startDate = new Date(timeSlot.localStartDate);
120
+ const endDate = new Date(timeSlot.localEndDate);
125
121
  const bookable = timeSlot.bookable ?? false;
126
122
  // Calculate duration from start and end dates
127
- let durationInMinutes = null;
128
- if (startDate && endDate) {
129
- durationInMinutes = Math.round((endDate.getTime() - startDate.getTime()) / (1000 * 60));
130
- }
123
+ const durationInMinutes = Math.round((endDate.getTime() - startDate.getTime()) / (1000 * 60));
131
124
  return props.children({
132
125
  startDate,
133
126
  endDate,
@@ -16,7 +16,7 @@ export type { LocationData, StaffMemberData, } from '../core/time-slot-list/Time
16
16
  export interface StartDateProps {
17
17
  asChild?: boolean;
18
18
  children?: AsChildChildren<{
19
- startDate: Date | undefined;
19
+ startDate: Date;
20
20
  }>;
21
21
  className?: string;
22
22
  }
@@ -45,7 +45,7 @@ export declare const StartDate: React.ForwardRefExoticComponent<StartDateProps &
45
45
  export interface EndDateProps {
46
46
  asChild?: boolean;
47
47
  children?: AsChildChildren<{
48
- endDate: Date | undefined;
48
+ endDate: Date;
49
49
  }>;
50
50
  className?: string;
51
51
  }
@@ -74,7 +74,7 @@ export declare const EndDate: React.ForwardRefExoticComponent<EndDateProps & Rea
74
74
  export interface DurationProps {
75
75
  asChild?: boolean;
76
76
  children?: AsChildChildren<{
77
- durationInMinutes: number | null;
77
+ durationInMinutes: number;
78
78
  }>;
79
79
  className?: string;
80
80
  }
@@ -53,7 +53,7 @@ var TestIds;
53
53
  */
54
54
  export const StartDate = React.forwardRef((props, ref) => {
55
55
  const { asChild, children, className } = props;
56
- return (_jsx(CoreTimeSlot.Info, { children: ({ startDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotStartDate, customElement: children, customElementProps: { startDate }, children: _jsx("span", { children: startDate?.toString() }) })) }));
56
+ return (_jsx(CoreTimeSlot.Info, { children: ({ startDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotStartDate, customElement: children, customElementProps: { startDate }, children: _jsx("span", { children: startDate.toString() }) })) }));
57
57
  });
58
58
  StartDate.displayName = 'TimeSlot.StartDate';
59
59
  /**
@@ -76,7 +76,7 @@ StartDate.displayName = 'TimeSlot.StartDate';
76
76
  */
77
77
  export const EndDate = React.forwardRef((props, ref) => {
78
78
  const { asChild, children, className } = props;
79
- return (_jsx(CoreTimeSlot.Info, { children: ({ endDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotEndDate, customElement: children, customElementProps: { endDate }, children: _jsx("span", { children: endDate?.toString() }) })) }));
79
+ return (_jsx(CoreTimeSlot.Info, { children: ({ endDate }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotEndDate, customElement: children, customElementProps: { endDate }, children: _jsx("span", { children: endDate.toString() }) })) }));
80
80
  });
81
81
  EndDate.displayName = 'TimeSlot.EndDate';
82
82
  /**
@@ -99,7 +99,7 @@ EndDate.displayName = 'TimeSlot.EndDate';
99
99
  */
100
100
  export const Duration = React.forwardRef((props, ref) => {
101
101
  const { asChild, children, className } = props;
102
- return (_jsx(CoreTimeSlot.Info, { children: ({ durationInMinutes }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotDuration, customElement: children, customElementProps: { durationInMinutes }, children: durationInMinutes && _jsx("span", { children: durationInMinutes }) })) }));
102
+ return (_jsx(CoreTimeSlot.Info, { children: ({ durationInMinutes }) => (_jsx(AsChildSlot, { ref: ref, asChild: asChild, className: className, "data-testid": TestIds.timeSlotDuration, customElement: children, customElementProps: { durationInMinutes }, children: _jsx("span", { children: durationInMinutes }) })) }));
103
103
  });
104
104
  Duration.displayName = 'TimeSlot.Duration';
105
105
  /**
@@ -85,6 +85,8 @@ export interface TimeSlotsProps {
85
85
  emptyState?: React.ReactNode;
86
86
  /** Content to display while time slots are loading */
87
87
  loadingState?: React.ReactNode;
88
+ /** Content to display when an error occurs while loading time slots */
89
+ errorState?: React.ReactNode;
88
90
  className?: string;
89
91
  }
90
92
  /**
@@ -114,11 +116,11 @@ export interface TimeSlotRepeaterChildProps {
114
116
  /** Whether the slot can be booked */
115
117
  bookable: boolean;
116
118
  /** Start date/time as Date (constructed from the raw localStartDate string) */
117
- startDate: Date | undefined;
119
+ startDate: Date;
118
120
  /** End date/time as Date (constructed from the raw localEndDate string) */
119
- endDate: Date | undefined;
121
+ endDate: Date;
120
122
  /** Duration in minutes */
121
- durationInMinutes: number | null;
123
+ durationInMinutes: number;
122
124
  /** The raw time slot data */
123
125
  timeSlot: TimeSlotType;
124
126
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Book Action - Orchestrates the booking flow
3
+ *
4
+ * 1. Validates booking data with canBook()
5
+ * 2. Creates a booking via createBooking() from API layer
6
+ * 3. Creates a checkout via createCheckout() from API layer
7
+ * 4. Returns the checkoutId for navigation
8
+ */
9
+ import type { BookActionParams, BookResult } from './types.js';
10
+ /**
11
+ * Executes the complete booking flow:
12
+ * 1. Validates that all required data is present
13
+ * 2. Creates a booking with the selected service, time slot, and form data
14
+ * 3. Creates a checkout session for payment (includes contact details from booking)
15
+ * 4. Returns the checkout ID for navigation to the checkout page
16
+ *
17
+ * @param params - The booking action parameters
18
+ * @returns BookResult with the checkoutId
19
+ * @throws Error if validation fails, or booking/checkout creation fails
20
+ */
21
+ export declare function executeBookAction(params: BookActionParams): Promise<BookResult>;