@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.
- package/cjs/dist/api/create-booking/index.d.ts +42 -0
- package/cjs/dist/api/create-booking/index.js +35 -0
- package/cjs/dist/api/create-checkout/index.d.ts +40 -0
- package/cjs/dist/api/create-checkout/index.js +37 -0
- package/cjs/dist/api/fetch-availability/index.d.ts +5 -5
- package/cjs/dist/api/fetch-availability/index.js +9 -6
- package/cjs/dist/api/index.d.ts +2 -0
- package/cjs/dist/api/index.js +2 -0
- package/cjs/dist/react/booking/Book.d.ts +49 -0
- package/cjs/dist/react/booking/Book.js +46 -0
- package/cjs/dist/react/booking/Booking.d.ts +18 -0
- package/cjs/dist/react/booking/Booking.js +19 -0
- package/cjs/dist/react/core/booking/Book.d.ts +41 -0
- package/cjs/dist/react/core/booking/Book.js +59 -0
- package/cjs/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
- package/cjs/dist/react/core/time-slot-list/TimeSlot.js +3 -10
- package/cjs/dist/react/time-slot-list/TimeSlot.d.ts +3 -3
- package/cjs/dist/react/time-slot-list/TimeSlot.js +3 -3
- package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +5 -3
- package/cjs/dist/services/booking/book-action/bookAction.d.ts +21 -0
- package/cjs/dist/services/booking/book-action/bookAction.js +59 -0
- package/cjs/dist/services/booking/book-action/buildBookingRequest.d.ts +22 -0
- package/cjs/dist/services/booking/book-action/buildBookingRequest.js +81 -0
- package/cjs/dist/services/booking/book-action/buildCheckoutRequest.d.ts +26 -0
- package/cjs/dist/services/booking/book-action/buildCheckoutRequest.js +62 -0
- package/cjs/dist/services/booking/book-action/canBook.d.ts +23 -0
- package/cjs/dist/services/booking/book-action/canBook.js +19 -0
- package/cjs/dist/services/booking/book-action/index.d.ts +8 -0
- package/cjs/dist/services/booking/book-action/index.js +7 -0
- package/cjs/dist/services/booking/book-action/types.d.ts +50 -0
- package/cjs/dist/services/booking/book-action/types.js +4 -0
- package/cjs/dist/services/booking/booking.d.ts +2 -0
- package/cjs/dist/services/booking/booking.js +16 -0
- package/cjs/dist/services/index.d.ts +1 -0
- package/cjs/dist/services/index.js +1 -0
- package/cjs/dist/services/time-slot-list/time-slot-list.def.d.ts +10 -2
- package/cjs/dist/services/time-slot-list/time-slot-list.js +9 -29
- package/dist/api/create-booking/index.d.ts +42 -0
- package/dist/api/create-booking/index.js +35 -0
- package/dist/api/create-checkout/index.d.ts +40 -0
- package/dist/api/create-checkout/index.js +37 -0
- package/dist/api/fetch-availability/index.d.ts +5 -5
- package/dist/api/fetch-availability/index.js +9 -6
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/react/booking/Book.d.ts +49 -0
- package/dist/react/booking/Book.js +46 -0
- package/dist/react/booking/Booking.d.ts +18 -0
- package/dist/react/booking/Booking.js +19 -0
- package/dist/react/core/booking/Book.d.ts +41 -0
- package/dist/react/core/booking/Book.js +59 -0
- package/dist/react/core/time-slot-list/TimeSlot.d.ts +4 -4
- package/dist/react/core/time-slot-list/TimeSlot.js +3 -10
- package/dist/react/time-slot-list/TimeSlot.d.ts +3 -3
- package/dist/react/time-slot-list/TimeSlot.js +3 -3
- package/dist/react/time-slot-list/TimeSlotList.d.ts +5 -3
- package/dist/services/booking/book-action/bookAction.d.ts +21 -0
- package/dist/services/booking/book-action/bookAction.js +59 -0
- package/dist/services/booking/book-action/buildBookingRequest.d.ts +22 -0
- package/dist/services/booking/book-action/buildBookingRequest.js +81 -0
- package/dist/services/booking/book-action/buildCheckoutRequest.d.ts +26 -0
- package/dist/services/booking/book-action/buildCheckoutRequest.js +62 -0
- package/dist/services/booking/book-action/canBook.d.ts +23 -0
- package/dist/services/booking/book-action/canBook.js +19 -0
- package/dist/services/booking/book-action/index.d.ts +8 -0
- package/dist/services/booking/book-action/index.js +7 -0
- package/dist/services/booking/book-action/types.d.ts +50 -0
- package/dist/services/booking/book-action/types.js +4 -0
- package/dist/services/booking/booking.d.ts +2 -0
- package/dist/services/booking/booking.js +16 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/time-slot-list/time-slot-list.def.d.ts +10 -2
- package/dist/services/time-slot-list/time-slot-list.js +9 -29
- package/package.json +4 -3
|
@@ -0,0 +1,59 @@
|
|
|
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 { createBooking } from '../../../api/create-booking/index.js';
|
|
10
|
+
import { createCheckout } from '../../../api/create-checkout/index.js';
|
|
11
|
+
import { buildBookingRequest } from './buildBookingRequest.js';
|
|
12
|
+
import { buildCheckoutRequest } from './buildCheckoutRequest.js';
|
|
13
|
+
import { canBook } from './canBook.js';
|
|
14
|
+
/**
|
|
15
|
+
* Executes the complete booking flow:
|
|
16
|
+
* 1. Validates that all required data is present
|
|
17
|
+
* 2. Creates a booking with the selected service, time slot, and form data
|
|
18
|
+
* 3. Creates a checkout session for payment (includes contact details from booking)
|
|
19
|
+
* 4. Returns the checkout ID for navigation to the checkout page
|
|
20
|
+
*
|
|
21
|
+
* @param params - The booking action parameters
|
|
22
|
+
* @returns BookResult with the checkoutId
|
|
23
|
+
* @throws Error if validation fails, or booking/checkout creation fails
|
|
24
|
+
*/
|
|
25
|
+
export async function executeBookAction(params) {
|
|
26
|
+
// Step 0: Validate
|
|
27
|
+
if (!canBook({
|
|
28
|
+
serviceSelections: params.serviceSelections,
|
|
29
|
+
formSubmission: params.formSubmission,
|
|
30
|
+
})) {
|
|
31
|
+
throw new Error('Cannot book: missing required data');
|
|
32
|
+
}
|
|
33
|
+
// Step 1: Create booking
|
|
34
|
+
const createBookingRequest = buildBookingRequest(params);
|
|
35
|
+
const bookingResponse = await createBooking(createBookingRequest.booking, {
|
|
36
|
+
participantNotification: createBookingRequest.participantNotification,
|
|
37
|
+
sendSmsReminder: createBookingRequest.sendSmsReminder ?? undefined,
|
|
38
|
+
formSubmission: createBookingRequest.formSubmission ?? undefined,
|
|
39
|
+
});
|
|
40
|
+
const bookingId = bookingResponse.booking?._id;
|
|
41
|
+
const contactDetails = bookingResponse.booking?.contactDetails;
|
|
42
|
+
if (!bookingId) {
|
|
43
|
+
throw new Error('Failed to create booking');
|
|
44
|
+
}
|
|
45
|
+
// Step 2: Create checkout
|
|
46
|
+
// businessLocationId comes from location.id for multi-location support
|
|
47
|
+
const businessLocationId = params.location?.id ?? undefined;
|
|
48
|
+
const checkoutRequest = buildCheckoutRequest({
|
|
49
|
+
bookingId,
|
|
50
|
+
contactDetails,
|
|
51
|
+
businessLocationId,
|
|
52
|
+
});
|
|
53
|
+
const checkoutResponse = await createCheckout(checkoutRequest);
|
|
54
|
+
const checkoutId = checkoutResponse.checkout?._id;
|
|
55
|
+
if (!checkoutId) {
|
|
56
|
+
throw new Error('Failed to create checkout');
|
|
57
|
+
}
|
|
58
|
+
return { checkoutId };
|
|
59
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the createBooking request from BookActionParams
|
|
3
|
+
*/
|
|
4
|
+
import type { CreateBookingRequest } from '../../../api/create-booking/index.js';
|
|
5
|
+
import type { BookActionParams } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Builds a CreateBookingRequest from the booking action parameters
|
|
8
|
+
*
|
|
9
|
+
* Maps ServiceSelection data to the Booking API's slot format:
|
|
10
|
+
* - serviceId: from serviceSelection.service._id
|
|
11
|
+
* - scheduleId: from serviceSelection.timeSlot.scheduleId
|
|
12
|
+
* - startDate: from serviceSelection.timeSlot.startDate
|
|
13
|
+
* - endDate: from serviceSelection.timeSlot.endDate
|
|
14
|
+
* - timezone: from serviceSelection.timezone
|
|
15
|
+
* - eventId: from serviceSelection.timeSlot.eventInfo.eventId (for classes)
|
|
16
|
+
* - location: from location param
|
|
17
|
+
* - resource: from serviceSelection.resources[0]
|
|
18
|
+
*
|
|
19
|
+
* @param params - The booking action parameters
|
|
20
|
+
* @returns CreateBookingRequest ready to be sent to the API
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildBookingRequest(params: BookActionParams): CreateBookingRequest;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the createBooking request from BookActionParams
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Derives the selected payment option from service payment settings.
|
|
6
|
+
* Maps service.payment.options to booking API's selectedPaymentOption.
|
|
7
|
+
*
|
|
8
|
+
* @param service - The service containing payment options
|
|
9
|
+
* @returns 'ONLINE' or 'OFFLINE' based on available payment methods
|
|
10
|
+
*/
|
|
11
|
+
function deriveSelectedPaymentOption(service) {
|
|
12
|
+
const options = service.payment?.options;
|
|
13
|
+
// Only online payment available
|
|
14
|
+
if (options?.online && !options?.inPerson) {
|
|
15
|
+
return 'ONLINE';
|
|
16
|
+
}
|
|
17
|
+
// Only offline payment available
|
|
18
|
+
if (!options?.online && options?.inPerson) {
|
|
19
|
+
return 'OFFLINE';
|
|
20
|
+
}
|
|
21
|
+
// Both available or neither specified - default to ONLINE
|
|
22
|
+
return 'ONLINE';
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Builds a CreateBookingRequest from the booking action parameters
|
|
26
|
+
*
|
|
27
|
+
* Maps ServiceSelection data to the Booking API's slot format:
|
|
28
|
+
* - serviceId: from serviceSelection.service._id
|
|
29
|
+
* - scheduleId: from serviceSelection.timeSlot.scheduleId
|
|
30
|
+
* - startDate: from serviceSelection.timeSlot.startDate
|
|
31
|
+
* - endDate: from serviceSelection.timeSlot.endDate
|
|
32
|
+
* - timezone: from serviceSelection.timezone
|
|
33
|
+
* - eventId: from serviceSelection.timeSlot.eventInfo.eventId (for classes)
|
|
34
|
+
* - location: from location param
|
|
35
|
+
* - resource: from serviceSelection.resources[0]
|
|
36
|
+
*
|
|
37
|
+
* @param params - The booking action parameters
|
|
38
|
+
* @returns CreateBookingRequest ready to be sent to the API
|
|
39
|
+
*/
|
|
40
|
+
export function buildBookingRequest(params) {
|
|
41
|
+
const { serviceSelections, location, formSubmission } = params;
|
|
42
|
+
const item = serviceSelections[0]; // Single booking focus
|
|
43
|
+
if (!item) {
|
|
44
|
+
throw new Error('No service selection provided');
|
|
45
|
+
}
|
|
46
|
+
if (!item.timeSlot) {
|
|
47
|
+
throw new Error('No time slot selected for service selection');
|
|
48
|
+
}
|
|
49
|
+
// Get resource from service selection
|
|
50
|
+
const resource = item.resources?.[0];
|
|
51
|
+
return {
|
|
52
|
+
booking: {
|
|
53
|
+
// Payment option derived from service payment settings
|
|
54
|
+
selectedPaymentOption: deriveSelectedPaymentOption(item.service),
|
|
55
|
+
// Participants
|
|
56
|
+
totalParticipants: item.totalParticipants || 1,
|
|
57
|
+
// Booked entity slot
|
|
58
|
+
bookedEntity: {
|
|
59
|
+
slot: {
|
|
60
|
+
serviceId: item.service._id ?? undefined,
|
|
61
|
+
scheduleId: item.timeSlot.scheduleId ?? undefined,
|
|
62
|
+
startDate: item.timeSlot.startDate,
|
|
63
|
+
endDate: item.timeSlot.endDate,
|
|
64
|
+
timezone: params.timezone,
|
|
65
|
+
eventId: item.timeSlot.eventInfo?.eventId ?? undefined,
|
|
66
|
+
resource: resource
|
|
67
|
+
? { _id: resource._id, name: resource.name }
|
|
68
|
+
: undefined,
|
|
69
|
+
location: location
|
|
70
|
+
? { _id: location.id, name: location.name }
|
|
71
|
+
: undefined,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
participantNotification: {
|
|
76
|
+
notifyParticipants: true,
|
|
77
|
+
},
|
|
78
|
+
sendSmsReminder: true,
|
|
79
|
+
formSubmission: formSubmission ?? undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the createCheckout request
|
|
3
|
+
*/
|
|
4
|
+
import { type CreateCheckoutRequest } from '../../../api/create-checkout/index.js';
|
|
5
|
+
import type { ContactDetails } from '../../../api/create-booking/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parameters for building checkout request
|
|
8
|
+
*/
|
|
9
|
+
export interface BuildCheckoutParams {
|
|
10
|
+
bookingId: string;
|
|
11
|
+
contactDetails?: ContactDetails;
|
|
12
|
+
businessLocationId?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Builds a checkout request from the booking ID and contact details
|
|
16
|
+
*
|
|
17
|
+
* Contact details come from the booking response and are used to populate:
|
|
18
|
+
* - billingInfo.contactDetails (firstName, lastName, phone)
|
|
19
|
+
* - billingInfo.address (from fullAddress if available)
|
|
20
|
+
* - shippingInfo.shippingDestination.contactDetails
|
|
21
|
+
* - buyerInfo (email, contactId)
|
|
22
|
+
*
|
|
23
|
+
* @param params - The checkout parameters
|
|
24
|
+
* @returns CreateCheckoutRequest ready to be sent to the API
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildCheckoutRequest(params: BuildCheckoutParams): CreateCheckoutRequest;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the createCheckout request
|
|
3
|
+
*/
|
|
4
|
+
import { ChannelType, } from '../../../api/create-checkout/index.js';
|
|
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,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
|
+
}
|
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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();
|
|
@@ -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';
|