@wix/headless-bookings 0.0.47 → 0.0.49

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 (35) hide show
  1. package/cjs/dist/api/create-order/index.d.ts +20 -0
  2. package/cjs/dist/api/create-order/index.js +21 -0
  3. package/cjs/dist/api/index.d.ts +1 -0
  4. package/cjs/dist/api/index.js +1 -0
  5. package/cjs/dist/react/booking/Book.d.ts +18 -5
  6. package/cjs/dist/react/booking/Book.js +13 -5
  7. package/cjs/dist/react/core/booking/Book.d.ts +11 -3
  8. package/cjs/dist/react/core/booking/Book.js +12 -3
  9. package/cjs/dist/services/booking/book-action/bookAction.d.ts +8 -5
  10. package/cjs/dist/services/booking/book-action/bookAction.js +28 -8
  11. package/cjs/dist/services/booking/book-action/buildBookingRequest.js +21 -1
  12. package/cjs/dist/services/booking/book-action/index.d.ts +2 -1
  13. package/cjs/dist/services/booking/book-action/index.js +2 -0
  14. package/cjs/dist/services/booking/book-action/isCheckoutRequired.d.ts +20 -0
  15. package/cjs/dist/services/booking/book-action/isCheckoutRequired.js +32 -0
  16. package/cjs/dist/services/booking/book-action/types.d.ts +17 -1
  17. package/cjs/dist/services/booking/book-action/types.js +8 -1
  18. package/dist/api/create-order/index.d.ts +20 -0
  19. package/dist/api/create-order/index.js +21 -0
  20. package/dist/api/index.d.ts +1 -0
  21. package/dist/api/index.js +1 -0
  22. package/dist/react/booking/Book.d.ts +18 -5
  23. package/dist/react/booking/Book.js +13 -5
  24. package/dist/react/core/booking/Book.d.ts +11 -3
  25. package/dist/react/core/booking/Book.js +12 -3
  26. package/dist/services/booking/book-action/bookAction.d.ts +8 -5
  27. package/dist/services/booking/book-action/bookAction.js +28 -8
  28. package/dist/services/booking/book-action/buildBookingRequest.js +21 -1
  29. package/dist/services/booking/book-action/index.d.ts +2 -1
  30. package/dist/services/booking/book-action/index.js +2 -0
  31. package/dist/services/booking/book-action/isCheckoutRequired.d.ts +20 -0
  32. package/dist/services/booking/book-action/isCheckoutRequired.js +32 -0
  33. package/dist/services/booking/book-action/types.d.ts +17 -1
  34. package/dist/services/booking/book-action/types.js +8 -1
  35. package/package.json +2 -2
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Create Order API
3
+ * Wrapper for the Wix eCommerce createOrder SDK function
4
+ */
5
+ import { type CreateOrderOptions, type CreateOrderResponse } from '@wix/auto_sdk_ecom_checkout';
6
+ /**
7
+ * Creates an order from a checkout session
8
+ *
9
+ * @param checkoutId - The checkout session ID
10
+ * @param options - Optional additional order creation options
11
+ * @returns Promise resolving to the created order response
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const response = await createOrder(checkoutId);
16
+ * const orderId = response.orderId;
17
+ * ```
18
+ */
19
+ export declare function createOrder(checkoutId: string, options?: CreateOrderOptions): Promise<CreateOrderResponse>;
20
+ export type { CreateOrderOptions, CreateOrderResponse };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Create Order API
3
+ * Wrapper for the Wix eCommerce createOrder SDK function
4
+ */
5
+ import { createOrder as createOrderSdk, } from '@wix/auto_sdk_ecom_checkout';
6
+ /**
7
+ * Creates an order from a checkout session
8
+ *
9
+ * @param checkoutId - The checkout session ID
10
+ * @param options - Optional additional order creation options
11
+ * @returns Promise resolving to the created order response
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const response = await createOrder(checkoutId);
16
+ * const orderId = response.orderId;
17
+ * ```
18
+ */
19
+ export async function createOrder(checkoutId, options) {
20
+ return createOrderSdk(checkoutId, options);
21
+ }
@@ -8,6 +8,7 @@ export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, t
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, type CreateBookingOptions, type Booking, type CreateBookingRequest, type CreateBookingResponse, type ParticipantNotification, type ContactDetails, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, type CreateCheckoutRequest, type CreateCheckoutResponse, } from './create-checkout/index.js';
11
+ export { createOrder, type CreateOrderOptions, type CreateOrderResponse, } from './create-order/index.js';
11
12
  export { queryLocations, type QueryLocationsResult, type LocationData, } from './query-locations/index.js';
12
13
  export { queryCategories, type QueryCategoriesResult, type Category, } from './query-categories/index.js';
13
14
  /**
@@ -8,6 +8,7 @@ export { getServiceById, getServiceBySlug, queryServices, } from './query-servic
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, } from './create-checkout/index.js';
11
+ export { createOrder, } from './create-order/index.js';
11
12
  export { queryLocations, } from './query-locations/index.js';
12
13
  export { queryCategories, } from './query-categories/index.js';
13
14
  /**
@@ -3,7 +3,7 @@
3
3
  * Wraps core Book with AsChildSlot pattern for customization
4
4
  */
5
5
  import React from 'react';
6
- import type { BookChildProps, BookResult, BookingError } from '../../services/booking/book-action/types.js';
6
+ import type { BookChildProps, BookingError } from '../../services/booking/book-action/types.js';
7
7
  /**
8
8
  * Props for the high-level Book component
9
9
  */
@@ -14,7 +14,12 @@ export interface BookProps {
14
14
  label?: string;
15
15
  loadingState?: string;
16
16
  disabled?: boolean;
17
- onCheckoutRequired?: (result: BookResult) => void;
17
+ onCheckout?: (result: {
18
+ checkoutId: string;
19
+ }) => void;
20
+ onComplete?: (result: {
21
+ orderId: string;
22
+ }) => void;
18
23
  onError?: (error: BookingError) => void;
19
24
  }
20
25
  /**
@@ -27,12 +32,16 @@ export interface BookProps {
27
32
  *
28
33
  * // With callbacks
29
34
  * <Booking.Actions.Book
30
- * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
35
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
36
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
31
37
  * onError={(error) => console.error(error.message)}
32
38
  * />
33
39
  *
34
40
  * // With render function
35
- * <Booking.Actions.Book onCheckoutRequired={handleCheckout}>
41
+ * <Booking.Actions.Book
42
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
43
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
44
+ * >
36
45
  * {({ isLoading, error, canBook, onClick, disabled }) => (
37
46
  * <button onClick={onClick} disabled={disabled}>
38
47
  * {isLoading ? <Spinner /> : 'Book Now'}
@@ -41,7 +50,11 @@ export interface BookProps {
41
50
  * </Booking.Actions.Book>
42
51
  *
43
52
  * // With asChild
44
- * <Booking.Actions.Book asChild onCheckoutRequired={handleCheckout}>
53
+ * <Booking.Actions.Book
54
+ * asChild
55
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
56
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
57
+ * >
45
58
  * <CustomBookButton />
46
59
  * </Booking.Actions.Book>
47
60
  * ```
@@ -20,12 +20,16 @@ var TestIds;
20
20
  *
21
21
  * // With callbacks
22
22
  * <Booking.Actions.Book
23
- * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
23
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
24
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
24
25
  * onError={(error) => console.error(error.message)}
25
26
  * />
26
27
  *
27
28
  * // With render function
28
- * <Booking.Actions.Book onCheckoutRequired={handleCheckout}>
29
+ * <Booking.Actions.Book
30
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
31
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
32
+ * >
29
33
  * {({ isLoading, error, canBook, onClick, disabled }) => (
30
34
  * <button onClick={onClick} disabled={disabled}>
31
35
  * {isLoading ? <Spinner /> : 'Book Now'}
@@ -34,13 +38,17 @@ var TestIds;
34
38
  * </Booking.Actions.Book>
35
39
  *
36
40
  * // With asChild
37
- * <Booking.Actions.Book asChild onCheckoutRequired={handleCheckout}>
41
+ * <Booking.Actions.Book
42
+ * asChild
43
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
44
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
45
+ * >
38
46
  * <CustomBookButton />
39
47
  * </Booking.Actions.Book>
40
48
  * ```
41
49
  */
42
50
  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 }) })) }));
51
+ const { asChild, children, className, label = 'Book Now', loadingState = 'Booking...', disabled, onCheckout, onComplete, onError, } = props;
52
+ return (_jsx(CoreBook.Book, { onCheckout: onCheckout, onComplete: onComplete, 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
53
  });
46
54
  Book.displayName = 'Booking.Actions.Book';
@@ -3,7 +3,7 @@
3
3
  * NO AsChildSlot, NO asChild - that belongs in high-level component
4
4
  */
5
5
  import React from 'react';
6
- import type { BookResult, BookingError } from '../../../services/booking/book-action/types.js';
6
+ import { type BookingError } from '../../../services/booking/book-action/types.js';
7
7
  /**
8
8
  * Data exposed by Book component via render props
9
9
  */
@@ -19,7 +19,12 @@ export interface BookData {
19
19
  */
20
20
  export interface BookProps {
21
21
  children: (data: BookData) => React.ReactNode;
22
- onCheckoutRequired?: (result: BookResult) => void;
22
+ onCheckout?: (result: {
23
+ checkoutId: string;
24
+ }) => void;
25
+ onComplete?: (result: {
26
+ orderId: string;
27
+ }) => void;
23
28
  onError?: (error: BookingError) => void;
24
29
  disabled?: boolean;
25
30
  }
@@ -29,7 +34,10 @@ export interface BookProps {
29
34
  *
30
35
  * @example
31
36
  * ```tsx
32
- * <Book onCheckoutRequired={handleCheckout}>
37
+ * <Book
38
+ * onCheckout={({ checkoutId }) => navigate(`/checkout?id=${checkoutId}`)}
39
+ * onComplete={({ orderId }) => navigate(`/thank-you?orderId=${orderId}`)}
40
+ * >
33
41
  * {({ isLoading, error, canBook, onClick, disabled }) => (
34
42
  * <button onClick={onClick} disabled={disabled}>
35
43
  * {isLoading ? 'Booking...' : 'Book Now'}
@@ -6,13 +6,17 @@ import { useState } from 'react';
6
6
  import { useService } from '@wix/services-manager-react';
7
7
  import { BookingServiceDefinition } from '../../../services/booking/booking.js';
8
8
  import { canBook } from '../../../services/booking/book-action/canBook.js';
9
+ import { BookResultType, } from '../../../services/booking/book-action/types.js';
9
10
  /**
10
11
  * Core Book component - provides book action data via render props.
11
12
  * Used internally by higher-level Booking.Actions.Book component.
12
13
  *
13
14
  * @example
14
15
  * ```tsx
15
- * <Book onCheckoutRequired={handleCheckout}>
16
+ * <Book
17
+ * onCheckout={({ checkoutId }) => navigate(`/checkout?id=${checkoutId}`)}
18
+ * onComplete={({ orderId }) => navigate(`/thank-you?orderId=${orderId}`)}
19
+ * >
16
20
  * {({ isLoading, error, canBook, onClick, disabled }) => (
17
21
  * <button onClick={onClick} disabled={disabled}>
18
22
  * {isLoading ? 'Booking...' : 'Book Now'}
@@ -22,7 +26,7 @@ import { canBook } from '../../../services/booking/book-action/canBook.js';
22
26
  * ```
23
27
  */
24
28
  export function Book(props) {
25
- const { children, onCheckoutRequired, onError, disabled } = props;
29
+ const { children, onCheckout, onComplete, onError, disabled } = props;
26
30
  const [isLoading, setIsLoading] = useState(false);
27
31
  const [error, setError] = useState(null);
28
32
  const bookingService = useService(BookingServiceDefinition);
@@ -34,7 +38,12 @@ export function Book(props) {
34
38
  setError(null);
35
39
  try {
36
40
  const result = await bookingService.actions.book();
37
- onCheckoutRequired?.(result);
41
+ if (result.type === BookResultType.CheckoutRequired) {
42
+ onCheckout?.({ checkoutId: result.checkoutId });
43
+ }
44
+ else {
45
+ onComplete?.({ orderId: result.orderId });
46
+ }
38
47
  }
39
48
  catch (e) {
40
49
  const bookingError = {
@@ -4,18 +4,21 @@
4
4
  * 1. Validates booking data with canBook()
5
5
  * 2. Creates a booking via createBooking() from API layer
6
6
  * 3. Creates a checkout via createCheckout() from API layer
7
- * 4. Returns the checkoutId for navigation
7
+ * 4. Determines if checkout is required or can be skipped
8
+ * 5. Returns appropriate result for navigation
8
9
  */
9
- import type { BookActionParams, BookResult } from './types.js';
10
+ import { type BookActionParams, type BookResult } from './types.js';
10
11
  /**
11
12
  * Executes the complete booking flow:
12
13
  * 1. Validates that all required data is present
13
14
  * 2. Creates a booking with the selected service, time slot, and form data
14
15
  * 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
+ * 4. Determines if checkout page is required or can be skipped
17
+ * 5. If checkout can be skipped (free/offline), creates order directly
18
+ * 6. Returns appropriate result for navigation
16
19
  *
17
20
  * @param params - The booking action parameters
18
- * @returns BookResult with the checkoutId
19
- * @throws Error if validation fails, or booking/checkout creation fails
21
+ * @returns BookResult with either checkoutId or orderId
22
+ * @throws Error if validation fails, or booking/checkout/order creation fails
20
23
  */
21
24
  export declare function executeBookAction(params: BookActionParams): Promise<BookResult>;
@@ -4,23 +4,29 @@
4
4
  * 1. Validates booking data with canBook()
5
5
  * 2. Creates a booking via createBooking() from API layer
6
6
  * 3. Creates a checkout via createCheckout() from API layer
7
- * 4. Returns the checkoutId for navigation
7
+ * 4. Determines if checkout is required or can be skipped
8
+ * 5. Returns appropriate result for navigation
8
9
  */
9
10
  import { createBooking } from '../../../api/create-booking/index.js';
10
11
  import { createCheckout } from '../../../api/create-checkout/index.js';
12
+ import { createOrder } from '../../../api/create-order/index.js';
11
13
  import { buildBookingRequest } from './buildBookingRequest.js';
12
14
  import { buildCheckoutRequest } from './buildCheckoutRequest.js';
13
15
  import { canBook } from './canBook.js';
16
+ import { isCheckoutRequired } from './isCheckoutRequired.js';
17
+ import { BookResultType, } from './types.js';
14
18
  /**
15
19
  * Executes the complete booking flow:
16
20
  * 1. Validates that all required data is present
17
21
  * 2. Creates a booking with the selected service, time slot, and form data
18
22
  * 3. Creates a checkout session for payment (includes contact details from booking)
19
- * 4. Returns the checkout ID for navigation to the checkout page
23
+ * 4. Determines if checkout page is required or can be skipped
24
+ * 5. If checkout can be skipped (free/offline), creates order directly
25
+ * 6. Returns appropriate result for navigation
20
26
  *
21
27
  * @param params - The booking action parameters
22
- * @returns BookResult with the checkoutId
23
- * @throws Error if validation fails, or booking/checkout creation fails
28
+ * @returns BookResult with either checkoutId or orderId
29
+ * @throws Error if validation fails, or booking/checkout/order creation fails
24
30
  */
25
31
  export async function executeBookAction(params) {
26
32
  // Step 0: Validate
@@ -45,16 +51,30 @@ export async function executeBookAction(params) {
45
51
  // Step 2: Create checkout
46
52
  // businessLocationId: prefer timeSlot.location, fallback to global location
47
53
  const firstSelection = params.serviceSelections[0];
48
- const businessLocationId = firstSelection?.timeSlot?.location?._id ?? undefined;
54
+ if (!firstSelection) {
55
+ throw new Error('No service selection found');
56
+ }
57
+ const businessLocationId = firstSelection.timeSlot?.location?._id ?? undefined;
49
58
  const checkoutRequest = buildCheckoutRequest({
50
59
  bookingId,
51
60
  contactDetails,
52
61
  businessLocationId,
53
62
  });
54
63
  const checkoutResponse = await createCheckout(checkoutRequest);
55
- const checkoutId = checkoutResponse.checkout?._id;
56
- if (!checkoutId) {
64
+ const checkout = checkoutResponse.checkout;
65
+ if (!checkout?._id) {
57
66
  throw new Error('Failed to create checkout');
58
67
  }
59
- return { checkoutId };
68
+ // Step 3: Determine if checkout is required or can be skipped
69
+ const service = firstSelection.service;
70
+ if (isCheckoutRequired(checkout, service)) {
71
+ return { type: BookResultType.CheckoutRequired, checkoutId: checkout._id };
72
+ }
73
+ // Step 4: Skip checkout - create order directly
74
+ const orderResponse = await createOrder(checkout._id);
75
+ const orderId = orderResponse.orderId;
76
+ if (!orderId) {
77
+ throw new Error('Failed to create order');
78
+ }
79
+ return { type: BookResultType.CheckoutSkipped, orderId };
60
80
  }
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Builds the createBooking request from BookActionParams
3
3
  */
4
+ import { LocationType as TimeSlotLocationType } from '@wix/auto_sdk_bookings_availability-time-slots';
5
+ import { LocationType as BookingLocationType } from '@wix/auto_sdk_bookings_bookings';
4
6
  /**
5
7
  * Derives the selected payment option from service payment settings.
6
8
  * Maps service.payment.options to booking API's selectedPaymentOption.
@@ -69,7 +71,11 @@ export function buildBookingRequest(params) {
69
71
  ? { _id: resource._id, name: resource.name }
70
72
  : undefined,
71
73
  location: slotLocation
72
- ? { _id: slotLocation._id, name: slotLocation.name }
74
+ ? {
75
+ _id: slotLocation._id,
76
+ name: slotLocation.name,
77
+ locationType: mapTimeSlotLocationTypeToBookingLocationType(slotLocation.locationType),
78
+ }
73
79
  : undefined,
74
80
  },
75
81
  },
@@ -81,3 +87,17 @@ export function buildBookingRequest(params) {
81
87
  formSubmission: formSubmission ?? undefined,
82
88
  };
83
89
  }
90
+ function mapTimeSlotLocationTypeToBookingLocationType(slotLocationType) {
91
+ switch (slotLocationType) {
92
+ case TimeSlotLocationType.BUSINESS:
93
+ return BookingLocationType.OWNER_BUSINESS;
94
+ case TimeSlotLocationType.CUSTOMER:
95
+ return BookingLocationType.CUSTOM;
96
+ case TimeSlotLocationType.CUSTOM:
97
+ return BookingLocationType.OWNER_CUSTOM;
98
+ case TimeSlotLocationType.UNKNOWN_LOCATION_TYPE:
99
+ return BookingLocationType.UNDEFINED;
100
+ default:
101
+ return BookingLocationType.OWNER_BUSINESS;
102
+ }
103
+ }
@@ -5,4 +5,5 @@ export { executeBookAction } from './bookAction.js';
5
5
  export { canBook, type CanBookParams } from './canBook.js';
6
6
  export { buildBookingRequest } from './buildBookingRequest.js';
7
7
  export { buildCheckoutRequest, type BuildCheckoutParams, } from './buildCheckoutRequest.js';
8
- export type { BookProps, BookResult, BookingError, BookActionParams, BookChildProps, } from './types.js';
8
+ export { isCheckoutRequired } from './isCheckoutRequired.js';
9
+ export { BookResultType, type BookProps, type BookResult, type BookingError, type BookActionParams, type BookChildProps, } from './types.js';
@@ -5,3 +5,5 @@ export { executeBookAction } from './bookAction.js';
5
5
  export { canBook } from './canBook.js';
6
6
  export { buildBookingRequest } from './buildBookingRequest.js';
7
7
  export { buildCheckoutRequest, } from './buildCheckoutRequest.js';
8
+ export { isCheckoutRequired } from './isCheckoutRequired.js';
9
+ export { BookResultType, } from './types.js';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Determines if checkout page is required based on payment amounts
3
+ */
4
+ import type { Checkout } from '@wix/auto_sdk_ecom_checkout';
5
+ import type { Service } from '@wix/auto_sdk_bookings_services';
6
+ /**
7
+ * Determines if checkout page is required based on payment amounts.
8
+ *
9
+ * Skip checkout when:
10
+ * - Free booking: payNow = 0 AND payLater = 0
11
+ * - Offline payment: payNow = 0
12
+ *
13
+ * Force checkout when:
14
+ * - Service has cancellation fee
15
+ *
16
+ * @param checkout - The checkout response from createCheckout
17
+ * @param service - The service being booked
18
+ * @returns true if checkout page is required, false if can skip to order
19
+ */
20
+ export declare function isCheckoutRequired(checkout: Checkout, service: Service): boolean;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Determines if checkout page is required based on payment amounts
3
+ */
4
+ /**
5
+ * Determines if checkout page is required based on payment amounts.
6
+ *
7
+ * Skip checkout when:
8
+ * - Free booking: payNow = 0 AND payLater = 0
9
+ * - Offline payment: payNow = 0
10
+ *
11
+ * Force checkout when:
12
+ * - Service has cancellation fee
13
+ *
14
+ * @param checkout - The checkout response from createCheckout
15
+ * @param service - The service being booked
16
+ * @returns true if checkout page is required, false if can skip to order
17
+ */
18
+ export function isCheckoutRequired(checkout, service) {
19
+ // Force checkout for cancellation fee
20
+ const hasCancellationFee = service.bookingPolicy?.cancellationPolicy?.enabled;
21
+ if (hasCancellationFee) {
22
+ return true;
23
+ }
24
+ const payNowAmount = Number(checkout.payNow?.total?.amount ?? 0);
25
+ const payLaterAmount = Number(checkout.payLater?.total?.amount ?? 0);
26
+ // Free or price plan: both amounts are 0
27
+ const isFreeOrPricePlan = payNowAmount === 0 && payLaterAmount === 0;
28
+ // Offline payment: payNow is 0
29
+ const isOfflinePayment = payNowAmount === 0;
30
+ // Skip checkout if free/price plan OR offline payment
31
+ return !(isFreeOrPricePlan || isOfflinePayment);
32
+ }
@@ -4,11 +4,22 @@
4
4
  import type { ServiceSelection } from '../booking.js';
5
5
  import type { FormValues } from '@wix/form-public';
6
6
  import type { Location as TimeSlotLocationType } from '@wix/auto_sdk_bookings_availability-time-slots';
7
+ /**
8
+ * Enum for book result types
9
+ */
10
+ export declare enum BookResultType {
11
+ CheckoutRequired = "checkout_required",
12
+ CheckoutSkipped = "checkout_skipped"
13
+ }
7
14
  /**
8
15
  * Result returned from the book action
9
16
  */
10
17
  export type BookResult = {
18
+ type: BookResultType.CheckoutRequired;
11
19
  checkoutId: string;
20
+ } | {
21
+ type: BookResultType.CheckoutSkipped;
22
+ orderId: string;
12
23
  };
13
24
  /**
14
25
  * Error object for booking errors
@@ -46,6 +57,11 @@ export interface BookProps {
46
57
  label?: string;
47
58
  loadingState?: string;
48
59
  disabled?: boolean;
49
- onCheckoutRequired?: (result: BookResult) => void;
60
+ onCheckout?: (result: {
61
+ checkoutId: string;
62
+ }) => void;
63
+ onComplete?: (result: {
64
+ orderId: string;
65
+ }) => void;
50
66
  onError?: (error: BookingError) => void;
51
67
  }
@@ -1,4 +1,11 @@
1
1
  /**
2
2
  * Types for the Book action
3
3
  */
4
- export {};
4
+ /**
5
+ * Enum for book result types
6
+ */
7
+ export var BookResultType;
8
+ (function (BookResultType) {
9
+ BookResultType["CheckoutRequired"] = "checkout_required";
10
+ BookResultType["CheckoutSkipped"] = "checkout_skipped";
11
+ })(BookResultType || (BookResultType = {}));
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Create Order API
3
+ * Wrapper for the Wix eCommerce createOrder SDK function
4
+ */
5
+ import { type CreateOrderOptions, type CreateOrderResponse } from '@wix/auto_sdk_ecom_checkout';
6
+ /**
7
+ * Creates an order from a checkout session
8
+ *
9
+ * @param checkoutId - The checkout session ID
10
+ * @param options - Optional additional order creation options
11
+ * @returns Promise resolving to the created order response
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const response = await createOrder(checkoutId);
16
+ * const orderId = response.orderId;
17
+ * ```
18
+ */
19
+ export declare function createOrder(checkoutId: string, options?: CreateOrderOptions): Promise<CreateOrderResponse>;
20
+ export type { CreateOrderOptions, CreateOrderResponse };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Create Order API
3
+ * Wrapper for the Wix eCommerce createOrder SDK function
4
+ */
5
+ import { createOrder as createOrderSdk, } from '@wix/auto_sdk_ecom_checkout';
6
+ /**
7
+ * Creates an order from a checkout session
8
+ *
9
+ * @param checkoutId - The checkout session ID
10
+ * @param options - Optional additional order creation options
11
+ * @returns Promise resolving to the created order response
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const response = await createOrder(checkoutId);
16
+ * const orderId = response.orderId;
17
+ * ```
18
+ */
19
+ export async function createOrder(checkoutId, options) {
20
+ return createOrderSdk(checkoutId, options);
21
+ }
@@ -8,6 +8,7 @@ export { getServiceById, getServiceBySlug, queryServices, type PagingMetadata, t
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, type CreateBookingOptions, type Booking, type CreateBookingRequest, type CreateBookingResponse, type ParticipantNotification, type ContactDetails, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, type CreateCheckoutRequest, type CreateCheckoutResponse, } from './create-checkout/index.js';
11
+ export { createOrder, type CreateOrderOptions, type CreateOrderResponse, } from './create-order/index.js';
11
12
  export { queryLocations, type QueryLocationsResult, type LocationData, } from './query-locations/index.js';
12
13
  export { queryCategories, type QueryCategoriesResult, type Category, } from './query-categories/index.js';
13
14
  /**
package/dist/api/index.js CHANGED
@@ -8,6 +8,7 @@ export { getServiceById, getServiceBySlug, queryServices, } from './query-servic
8
8
  export { fetchAvailability } from './fetch-availability/index.js';
9
9
  export { createBooking, } from './create-booking/index.js';
10
10
  export { createCheckout, ChannelType, } from './create-checkout/index.js';
11
+ export { createOrder, } from './create-order/index.js';
11
12
  export { queryLocations, } from './query-locations/index.js';
12
13
  export { queryCategories, } from './query-categories/index.js';
13
14
  /**
@@ -3,7 +3,7 @@
3
3
  * Wraps core Book with AsChildSlot pattern for customization
4
4
  */
5
5
  import React from 'react';
6
- import type { BookChildProps, BookResult, BookingError } from '../../services/booking/book-action/types.js';
6
+ import type { BookChildProps, BookingError } from '../../services/booking/book-action/types.js';
7
7
  /**
8
8
  * Props for the high-level Book component
9
9
  */
@@ -14,7 +14,12 @@ export interface BookProps {
14
14
  label?: string;
15
15
  loadingState?: string;
16
16
  disabled?: boolean;
17
- onCheckoutRequired?: (result: BookResult) => void;
17
+ onCheckout?: (result: {
18
+ checkoutId: string;
19
+ }) => void;
20
+ onComplete?: (result: {
21
+ orderId: string;
22
+ }) => void;
18
23
  onError?: (error: BookingError) => void;
19
24
  }
20
25
  /**
@@ -27,12 +32,16 @@ export interface BookProps {
27
32
  *
28
33
  * // With callbacks
29
34
  * <Booking.Actions.Book
30
- * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
35
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
36
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
31
37
  * onError={(error) => console.error(error.message)}
32
38
  * />
33
39
  *
34
40
  * // With render function
35
- * <Booking.Actions.Book onCheckoutRequired={handleCheckout}>
41
+ * <Booking.Actions.Book
42
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
43
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
44
+ * >
36
45
  * {({ isLoading, error, canBook, onClick, disabled }) => (
37
46
  * <button onClick={onClick} disabled={disabled}>
38
47
  * {isLoading ? <Spinner /> : 'Book Now'}
@@ -41,7 +50,11 @@ export interface BookProps {
41
50
  * </Booking.Actions.Book>
42
51
  *
43
52
  * // With asChild
44
- * <Booking.Actions.Book asChild onCheckoutRequired={handleCheckout}>
53
+ * <Booking.Actions.Book
54
+ * asChild
55
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
56
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
57
+ * >
45
58
  * <CustomBookButton />
46
59
  * </Booking.Actions.Book>
47
60
  * ```
@@ -20,12 +20,16 @@ var TestIds;
20
20
  *
21
21
  * // With callbacks
22
22
  * <Booking.Actions.Book
23
- * onCheckoutRequired={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
23
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
24
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
24
25
  * onError={(error) => console.error(error.message)}
25
26
  * />
26
27
  *
27
28
  * // With render function
28
- * <Booking.Actions.Book onCheckoutRequired={handleCheckout}>
29
+ * <Booking.Actions.Book
30
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
31
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
32
+ * >
29
33
  * {({ isLoading, error, canBook, onClick, disabled }) => (
30
34
  * <button onClick={onClick} disabled={disabled}>
31
35
  * {isLoading ? <Spinner /> : 'Book Now'}
@@ -34,13 +38,17 @@ var TestIds;
34
38
  * </Booking.Actions.Book>
35
39
  *
36
40
  * // With asChild
37
- * <Booking.Actions.Book asChild onCheckoutRequired={handleCheckout}>
41
+ * <Booking.Actions.Book
42
+ * asChild
43
+ * onCheckout={({ checkoutId }) => router.push(`/checkout?id=${checkoutId}`)}
44
+ * onComplete={({ orderId }) => router.push(`/thank-you?orderId=${orderId}`)}
45
+ * >
38
46
  * <CustomBookButton />
39
47
  * </Booking.Actions.Book>
40
48
  * ```
41
49
  */
42
50
  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 }) })) }));
51
+ const { asChild, children, className, label = 'Book Now', loadingState = 'Booking...', disabled, onCheckout, onComplete, onError, } = props;
52
+ return (_jsx(CoreBook.Book, { onCheckout: onCheckout, onComplete: onComplete, 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
53
  });
46
54
  Book.displayName = 'Booking.Actions.Book';
@@ -3,7 +3,7 @@
3
3
  * NO AsChildSlot, NO asChild - that belongs in high-level component
4
4
  */
5
5
  import React from 'react';
6
- import type { BookResult, BookingError } from '../../../services/booking/book-action/types.js';
6
+ import { type BookingError } from '../../../services/booking/book-action/types.js';
7
7
  /**
8
8
  * Data exposed by Book component via render props
9
9
  */
@@ -19,7 +19,12 @@ export interface BookData {
19
19
  */
20
20
  export interface BookProps {
21
21
  children: (data: BookData) => React.ReactNode;
22
- onCheckoutRequired?: (result: BookResult) => void;
22
+ onCheckout?: (result: {
23
+ checkoutId: string;
24
+ }) => void;
25
+ onComplete?: (result: {
26
+ orderId: string;
27
+ }) => void;
23
28
  onError?: (error: BookingError) => void;
24
29
  disabled?: boolean;
25
30
  }
@@ -29,7 +34,10 @@ export interface BookProps {
29
34
  *
30
35
  * @example
31
36
  * ```tsx
32
- * <Book onCheckoutRequired={handleCheckout}>
37
+ * <Book
38
+ * onCheckout={({ checkoutId }) => navigate(`/checkout?id=${checkoutId}`)}
39
+ * onComplete={({ orderId }) => navigate(`/thank-you?orderId=${orderId}`)}
40
+ * >
33
41
  * {({ isLoading, error, canBook, onClick, disabled }) => (
34
42
  * <button onClick={onClick} disabled={disabled}>
35
43
  * {isLoading ? 'Booking...' : 'Book Now'}
@@ -6,13 +6,17 @@ import { useState } from 'react';
6
6
  import { useService } from '@wix/services-manager-react';
7
7
  import { BookingServiceDefinition } from '../../../services/booking/booking.js';
8
8
  import { canBook } from '../../../services/booking/book-action/canBook.js';
9
+ import { BookResultType, } from '../../../services/booking/book-action/types.js';
9
10
  /**
10
11
  * Core Book component - provides book action data via render props.
11
12
  * Used internally by higher-level Booking.Actions.Book component.
12
13
  *
13
14
  * @example
14
15
  * ```tsx
15
- * <Book onCheckoutRequired={handleCheckout}>
16
+ * <Book
17
+ * onCheckout={({ checkoutId }) => navigate(`/checkout?id=${checkoutId}`)}
18
+ * onComplete={({ orderId }) => navigate(`/thank-you?orderId=${orderId}`)}
19
+ * >
16
20
  * {({ isLoading, error, canBook, onClick, disabled }) => (
17
21
  * <button onClick={onClick} disabled={disabled}>
18
22
  * {isLoading ? 'Booking...' : 'Book Now'}
@@ -22,7 +26,7 @@ import { canBook } from '../../../services/booking/book-action/canBook.js';
22
26
  * ```
23
27
  */
24
28
  export function Book(props) {
25
- const { children, onCheckoutRequired, onError, disabled } = props;
29
+ const { children, onCheckout, onComplete, onError, disabled } = props;
26
30
  const [isLoading, setIsLoading] = useState(false);
27
31
  const [error, setError] = useState(null);
28
32
  const bookingService = useService(BookingServiceDefinition);
@@ -34,7 +38,12 @@ export function Book(props) {
34
38
  setError(null);
35
39
  try {
36
40
  const result = await bookingService.actions.book();
37
- onCheckoutRequired?.(result);
41
+ if (result.type === BookResultType.CheckoutRequired) {
42
+ onCheckout?.({ checkoutId: result.checkoutId });
43
+ }
44
+ else {
45
+ onComplete?.({ orderId: result.orderId });
46
+ }
38
47
  }
39
48
  catch (e) {
40
49
  const bookingError = {
@@ -4,18 +4,21 @@
4
4
  * 1. Validates booking data with canBook()
5
5
  * 2. Creates a booking via createBooking() from API layer
6
6
  * 3. Creates a checkout via createCheckout() from API layer
7
- * 4. Returns the checkoutId for navigation
7
+ * 4. Determines if checkout is required or can be skipped
8
+ * 5. Returns appropriate result for navigation
8
9
  */
9
- import type { BookActionParams, BookResult } from './types.js';
10
+ import { type BookActionParams, type BookResult } from './types.js';
10
11
  /**
11
12
  * Executes the complete booking flow:
12
13
  * 1. Validates that all required data is present
13
14
  * 2. Creates a booking with the selected service, time slot, and form data
14
15
  * 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
+ * 4. Determines if checkout page is required or can be skipped
17
+ * 5. If checkout can be skipped (free/offline), creates order directly
18
+ * 6. Returns appropriate result for navigation
16
19
  *
17
20
  * @param params - The booking action parameters
18
- * @returns BookResult with the checkoutId
19
- * @throws Error if validation fails, or booking/checkout creation fails
21
+ * @returns BookResult with either checkoutId or orderId
22
+ * @throws Error if validation fails, or booking/checkout/order creation fails
20
23
  */
21
24
  export declare function executeBookAction(params: BookActionParams): Promise<BookResult>;
@@ -4,23 +4,29 @@
4
4
  * 1. Validates booking data with canBook()
5
5
  * 2. Creates a booking via createBooking() from API layer
6
6
  * 3. Creates a checkout via createCheckout() from API layer
7
- * 4. Returns the checkoutId for navigation
7
+ * 4. Determines if checkout is required or can be skipped
8
+ * 5. Returns appropriate result for navigation
8
9
  */
9
10
  import { createBooking } from '../../../api/create-booking/index.js';
10
11
  import { createCheckout } from '../../../api/create-checkout/index.js';
12
+ import { createOrder } from '../../../api/create-order/index.js';
11
13
  import { buildBookingRequest } from './buildBookingRequest.js';
12
14
  import { buildCheckoutRequest } from './buildCheckoutRequest.js';
13
15
  import { canBook } from './canBook.js';
16
+ import { isCheckoutRequired } from './isCheckoutRequired.js';
17
+ import { BookResultType, } from './types.js';
14
18
  /**
15
19
  * Executes the complete booking flow:
16
20
  * 1. Validates that all required data is present
17
21
  * 2. Creates a booking with the selected service, time slot, and form data
18
22
  * 3. Creates a checkout session for payment (includes contact details from booking)
19
- * 4. Returns the checkout ID for navigation to the checkout page
23
+ * 4. Determines if checkout page is required or can be skipped
24
+ * 5. If checkout can be skipped (free/offline), creates order directly
25
+ * 6. Returns appropriate result for navigation
20
26
  *
21
27
  * @param params - The booking action parameters
22
- * @returns BookResult with the checkoutId
23
- * @throws Error if validation fails, or booking/checkout creation fails
28
+ * @returns BookResult with either checkoutId or orderId
29
+ * @throws Error if validation fails, or booking/checkout/order creation fails
24
30
  */
25
31
  export async function executeBookAction(params) {
26
32
  // Step 0: Validate
@@ -45,16 +51,30 @@ export async function executeBookAction(params) {
45
51
  // Step 2: Create checkout
46
52
  // businessLocationId: prefer timeSlot.location, fallback to global location
47
53
  const firstSelection = params.serviceSelections[0];
48
- const businessLocationId = firstSelection?.timeSlot?.location?._id ?? undefined;
54
+ if (!firstSelection) {
55
+ throw new Error('No service selection found');
56
+ }
57
+ const businessLocationId = firstSelection.timeSlot?.location?._id ?? undefined;
49
58
  const checkoutRequest = buildCheckoutRequest({
50
59
  bookingId,
51
60
  contactDetails,
52
61
  businessLocationId,
53
62
  });
54
63
  const checkoutResponse = await createCheckout(checkoutRequest);
55
- const checkoutId = checkoutResponse.checkout?._id;
56
- if (!checkoutId) {
64
+ const checkout = checkoutResponse.checkout;
65
+ if (!checkout?._id) {
57
66
  throw new Error('Failed to create checkout');
58
67
  }
59
- return { checkoutId };
68
+ // Step 3: Determine if checkout is required or can be skipped
69
+ const service = firstSelection.service;
70
+ if (isCheckoutRequired(checkout, service)) {
71
+ return { type: BookResultType.CheckoutRequired, checkoutId: checkout._id };
72
+ }
73
+ // Step 4: Skip checkout - create order directly
74
+ const orderResponse = await createOrder(checkout._id);
75
+ const orderId = orderResponse.orderId;
76
+ if (!orderId) {
77
+ throw new Error('Failed to create order');
78
+ }
79
+ return { type: BookResultType.CheckoutSkipped, orderId };
60
80
  }
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Builds the createBooking request from BookActionParams
3
3
  */
4
+ import { LocationType as TimeSlotLocationType } from '@wix/auto_sdk_bookings_availability-time-slots';
5
+ import { LocationType as BookingLocationType } from '@wix/auto_sdk_bookings_bookings';
4
6
  /**
5
7
  * Derives the selected payment option from service payment settings.
6
8
  * Maps service.payment.options to booking API's selectedPaymentOption.
@@ -69,7 +71,11 @@ export function buildBookingRequest(params) {
69
71
  ? { _id: resource._id, name: resource.name }
70
72
  : undefined,
71
73
  location: slotLocation
72
- ? { _id: slotLocation._id, name: slotLocation.name }
74
+ ? {
75
+ _id: slotLocation._id,
76
+ name: slotLocation.name,
77
+ locationType: mapTimeSlotLocationTypeToBookingLocationType(slotLocation.locationType),
78
+ }
73
79
  : undefined,
74
80
  },
75
81
  },
@@ -81,3 +87,17 @@ export function buildBookingRequest(params) {
81
87
  formSubmission: formSubmission ?? undefined,
82
88
  };
83
89
  }
90
+ function mapTimeSlotLocationTypeToBookingLocationType(slotLocationType) {
91
+ switch (slotLocationType) {
92
+ case TimeSlotLocationType.BUSINESS:
93
+ return BookingLocationType.OWNER_BUSINESS;
94
+ case TimeSlotLocationType.CUSTOMER:
95
+ return BookingLocationType.CUSTOM;
96
+ case TimeSlotLocationType.CUSTOM:
97
+ return BookingLocationType.OWNER_CUSTOM;
98
+ case TimeSlotLocationType.UNKNOWN_LOCATION_TYPE:
99
+ return BookingLocationType.UNDEFINED;
100
+ default:
101
+ return BookingLocationType.OWNER_BUSINESS;
102
+ }
103
+ }
@@ -5,4 +5,5 @@ export { executeBookAction } from './bookAction.js';
5
5
  export { canBook, type CanBookParams } from './canBook.js';
6
6
  export { buildBookingRequest } from './buildBookingRequest.js';
7
7
  export { buildCheckoutRequest, type BuildCheckoutParams, } from './buildCheckoutRequest.js';
8
- export type { BookProps, BookResult, BookingError, BookActionParams, BookChildProps, } from './types.js';
8
+ export { isCheckoutRequired } from './isCheckoutRequired.js';
9
+ export { BookResultType, type BookProps, type BookResult, type BookingError, type BookActionParams, type BookChildProps, } from './types.js';
@@ -5,3 +5,5 @@ export { executeBookAction } from './bookAction.js';
5
5
  export { canBook } from './canBook.js';
6
6
  export { buildBookingRequest } from './buildBookingRequest.js';
7
7
  export { buildCheckoutRequest, } from './buildCheckoutRequest.js';
8
+ export { isCheckoutRequired } from './isCheckoutRequired.js';
9
+ export { BookResultType, } from './types.js';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Determines if checkout page is required based on payment amounts
3
+ */
4
+ import type { Checkout } from '@wix/auto_sdk_ecom_checkout';
5
+ import type { Service } from '@wix/auto_sdk_bookings_services';
6
+ /**
7
+ * Determines if checkout page is required based on payment amounts.
8
+ *
9
+ * Skip checkout when:
10
+ * - Free booking: payNow = 0 AND payLater = 0
11
+ * - Offline payment: payNow = 0
12
+ *
13
+ * Force checkout when:
14
+ * - Service has cancellation fee
15
+ *
16
+ * @param checkout - The checkout response from createCheckout
17
+ * @param service - The service being booked
18
+ * @returns true if checkout page is required, false if can skip to order
19
+ */
20
+ export declare function isCheckoutRequired(checkout: Checkout, service: Service): boolean;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Determines if checkout page is required based on payment amounts
3
+ */
4
+ /**
5
+ * Determines if checkout page is required based on payment amounts.
6
+ *
7
+ * Skip checkout when:
8
+ * - Free booking: payNow = 0 AND payLater = 0
9
+ * - Offline payment: payNow = 0
10
+ *
11
+ * Force checkout when:
12
+ * - Service has cancellation fee
13
+ *
14
+ * @param checkout - The checkout response from createCheckout
15
+ * @param service - The service being booked
16
+ * @returns true if checkout page is required, false if can skip to order
17
+ */
18
+ export function isCheckoutRequired(checkout, service) {
19
+ // Force checkout for cancellation fee
20
+ const hasCancellationFee = service.bookingPolicy?.cancellationPolicy?.enabled;
21
+ if (hasCancellationFee) {
22
+ return true;
23
+ }
24
+ const payNowAmount = Number(checkout.payNow?.total?.amount ?? 0);
25
+ const payLaterAmount = Number(checkout.payLater?.total?.amount ?? 0);
26
+ // Free or price plan: both amounts are 0
27
+ const isFreeOrPricePlan = payNowAmount === 0 && payLaterAmount === 0;
28
+ // Offline payment: payNow is 0
29
+ const isOfflinePayment = payNowAmount === 0;
30
+ // Skip checkout if free/price plan OR offline payment
31
+ return !(isFreeOrPricePlan || isOfflinePayment);
32
+ }
@@ -4,11 +4,22 @@
4
4
  import type { ServiceSelection } from '../booking.js';
5
5
  import type { FormValues } from '@wix/form-public';
6
6
  import type { Location as TimeSlotLocationType } from '@wix/auto_sdk_bookings_availability-time-slots';
7
+ /**
8
+ * Enum for book result types
9
+ */
10
+ export declare enum BookResultType {
11
+ CheckoutRequired = "checkout_required",
12
+ CheckoutSkipped = "checkout_skipped"
13
+ }
7
14
  /**
8
15
  * Result returned from the book action
9
16
  */
10
17
  export type BookResult = {
18
+ type: BookResultType.CheckoutRequired;
11
19
  checkoutId: string;
20
+ } | {
21
+ type: BookResultType.CheckoutSkipped;
22
+ orderId: string;
12
23
  };
13
24
  /**
14
25
  * Error object for booking errors
@@ -46,6 +57,11 @@ export interface BookProps {
46
57
  label?: string;
47
58
  loadingState?: string;
48
59
  disabled?: boolean;
49
- onCheckoutRequired?: (result: BookResult) => void;
60
+ onCheckout?: (result: {
61
+ checkoutId: string;
62
+ }) => void;
63
+ onComplete?: (result: {
64
+ orderId: string;
65
+ }) => void;
50
66
  onError?: (error: BookingError) => void;
51
67
  }
@@ -1,4 +1,11 @@
1
1
  /**
2
2
  * Types for the Book action
3
3
  */
4
- export {};
4
+ /**
5
+ * Enum for book result types
6
+ */
7
+ export var BookResultType;
8
+ (function (BookResultType) {
9
+ BookResultType["CheckoutRequired"] = "checkout_required";
10
+ BookResultType["CheckoutSkipped"] = "checkout_skipped";
11
+ })(BookResultType || (BookResultType = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-bookings",
3
- "version": "0.0.47",
3
+ "version": "0.0.49",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -72,5 +72,5 @@
72
72
  "groupId": "com.wixpress.headless-components"
73
73
  }
74
74
  },
75
- "falconPackageHash": "b4efe3be968a8e8d6806b0e818d5e30742584c3d834296262bc1572f"
75
+ "falconPackageHash": "ce9857f84a2dc23726f81fe1b20c314c9c652cbe712b90742c92d448"
76
76
  }