@wix/headless-bookings 0.0.61 → 0.0.62
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/react/booking/Book.d.ts +2 -0
- package/cjs/dist/react/booking/Book.js +11 -1
- package/cjs/dist/react/core/time-slot-list/TimeSlotList.d.ts +47 -3
- package/cjs/dist/react/core/time-slot-list/TimeSlotList.js +55 -5
- package/cjs/dist/react/time-slot-list/TimeSlotList.d.ts +30 -7
- package/cjs/dist/react/time-slot-list/TimeSlotList.js +31 -8
- package/cjs/dist/utils/index.d.ts +5 -0
- package/cjs/dist/utils/index.js +5 -0
- package/cjs/dist/utils/navigation.d.ts +7 -0
- package/cjs/dist/utils/navigation.js +75 -0
- package/dist/react/booking/Book.d.ts +2 -0
- package/dist/react/booking/Book.js +11 -1
- package/dist/react/core/time-slot-list/TimeSlotList.d.ts +47 -3
- package/dist/react/core/time-slot-list/TimeSlotList.js +55 -5
- package/dist/react/time-slot-list/TimeSlotList.d.ts +30 -7
- package/dist/react/time-slot-list/TimeSlotList.js +31 -8
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/navigation.d.ts +7 -0
- package/dist/utils/navigation.js +75 -0
- package/package.json +2 -2
|
@@ -16,9 +16,11 @@ export interface BookProps {
|
|
|
16
16
|
disabled?: boolean;
|
|
17
17
|
onCheckout?: (result: {
|
|
18
18
|
checkoutId: string;
|
|
19
|
+
navigateToCheckout: (checkoutId: string) => void;
|
|
19
20
|
}) => void;
|
|
20
21
|
onComplete?: (result: {
|
|
21
22
|
orderId: string;
|
|
23
|
+
navigateToThankYou: (orderId: string) => void;
|
|
22
24
|
}) => void;
|
|
23
25
|
onError?: (error: BookingError) => void;
|
|
24
26
|
}
|
|
@@ -6,6 +6,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
8
8
|
import * as CoreBook from '../core/booking/Book.js';
|
|
9
|
+
import { navigateToCheckout } from '../../utils/navigation.js';
|
|
9
10
|
var TestIds;
|
|
10
11
|
(function (TestIds) {
|
|
11
12
|
TestIds["bookingActionBook"] = "booking-action-book";
|
|
@@ -49,6 +50,15 @@ var TestIds;
|
|
|
49
50
|
*/
|
|
50
51
|
export const Book = React.forwardRef((props, ref) => {
|
|
51
52
|
const { asChild, children, className, label = 'Book Now', loadingState = 'Booking...', disabled, onCheckout, onComplete, onError, } = props;
|
|
52
|
-
return (_jsx(CoreBook.Book, { onCheckout:
|
|
53
|
+
return (_jsx(CoreBook.Book, { onCheckout: (result) => {
|
|
54
|
+
onCheckout?.({ ...result, navigateToCheckout });
|
|
55
|
+
}, onComplete: (result) => {
|
|
56
|
+
onComplete?.({
|
|
57
|
+
...result,
|
|
58
|
+
navigateToThankYou: (orderId) => {
|
|
59
|
+
console.log('navigateToThankYou', orderId);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}, 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 }) })) }));
|
|
53
63
|
});
|
|
54
64
|
Book.displayName = 'Booking.Actions.Book';
|
|
@@ -5,12 +5,49 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { type TimeSlotListServiceConfig } from '../../../services/time-slot-list/index.js';
|
|
7
7
|
import type { TimeSlot } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
8
|
+
import { type ServiceSelectionTimeSlot } from '../../../services/booking/booking.js';
|
|
9
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
10
|
+
/**
|
|
11
|
+
* Render props data provided to TimeSlotList.Root children
|
|
12
|
+
*/
|
|
13
|
+
export interface TimeSlotListRootRenderProps {
|
|
14
|
+
/** Function to navigate to the booking form with the selected time slot */
|
|
15
|
+
navigateToBookingForm: ({ timeSlot, service, }: {
|
|
16
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
17
|
+
service?: Service;
|
|
18
|
+
}) => Promise<void>;
|
|
19
|
+
}
|
|
8
20
|
/**
|
|
9
21
|
* Props for Root component
|
|
10
22
|
*/
|
|
11
23
|
export interface RootProps {
|
|
12
|
-
children: React.ReactNode;
|
|
24
|
+
children: (data: TimeSlotListRootRenderProps) => React.ReactNode;
|
|
13
25
|
config: TimeSlotListServiceConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Function to navigate to the booking form with the selected time slot.
|
|
28
|
+
* The timeSlot and service parameters are optional - if not provided,
|
|
29
|
+
* BookingService will be used to get them from the current service selections.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* <Root
|
|
34
|
+
* config={config}
|
|
35
|
+
* navigateToBookingForm={async ({ timeSlot, service }) => {
|
|
36
|
+
* // Custom navigation logic
|
|
37
|
+
* await navigateToBookingForm({ timeSlot, service });
|
|
38
|
+
* }}
|
|
39
|
+
* >
|
|
40
|
+
* {({ navigateToBookingForm }) => (
|
|
41
|
+
* // Use navigateToBookingForm in children
|
|
42
|
+
* // Can call with: navigateToBookingForm() or navigateToBookingForm({ timeSlot, service })
|
|
43
|
+
* )}
|
|
44
|
+
* </Root>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
navigateToBookingForm: ({ timeSlot, service, }: {
|
|
48
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
49
|
+
service?: Service;
|
|
50
|
+
}) => Promise<void>;
|
|
14
51
|
}
|
|
15
52
|
/**
|
|
16
53
|
* Root component that provides TimeSlotListService context to its children.
|
|
@@ -18,8 +55,15 @@ export interface RootProps {
|
|
|
18
55
|
* @component
|
|
19
56
|
* @example
|
|
20
57
|
* ```tsx
|
|
21
|
-
* <Root
|
|
22
|
-
* {
|
|
58
|
+
* <Root
|
|
59
|
+
* config={{ services, timeSlots, timezone }}
|
|
60
|
+
* navigateToBookingForm={async (selection) => {
|
|
61
|
+
* await navigateToBookingForm(selection);
|
|
62
|
+
* }}
|
|
63
|
+
* >
|
|
64
|
+
* {({ navigateToBookingForm }) => (
|
|
65
|
+
* // Your components that can use navigateToBookingForm
|
|
66
|
+
* )}
|
|
23
67
|
* </Root>
|
|
24
68
|
* ```
|
|
25
69
|
*/
|
|
@@ -1,21 +1,71 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useService, WixServices } from '@wix/services-manager-react';
|
|
3
3
|
import { createServicesMap } from '@wix/services-manager';
|
|
4
4
|
import { TimeSlotListServiceDefinition, TimeSlotListService, } from '../../../services/time-slot-list/index.js';
|
|
5
|
-
import { BookingServiceDefinition } from '../../../services/booking/booking.js';
|
|
5
|
+
import { BookingServiceDefinition, } from '../../../services/booking/booking.js';
|
|
6
6
|
/**
|
|
7
7
|
* Root component that provides TimeSlotListService context to its children.
|
|
8
8
|
*
|
|
9
9
|
* @component
|
|
10
10
|
* @example
|
|
11
11
|
* ```tsx
|
|
12
|
-
* <Root
|
|
13
|
-
* {
|
|
12
|
+
* <Root
|
|
13
|
+
* config={{ services, timeSlots, timezone }}
|
|
14
|
+
* navigateToBookingForm={async (selection) => {
|
|
15
|
+
* await navigateToBookingForm(selection);
|
|
16
|
+
* }}
|
|
17
|
+
* >
|
|
18
|
+
* {({ navigateToBookingForm }) => (
|
|
19
|
+
* // Your components that can use navigateToBookingForm
|
|
20
|
+
* )}
|
|
14
21
|
* </Root>
|
|
15
22
|
* ```
|
|
16
23
|
*/
|
|
17
24
|
export function Root(props) {
|
|
18
|
-
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(TimeSlotListServiceDefinition, TimeSlotListService, props.config), children: props.children }));
|
|
25
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(TimeSlotListServiceDefinition, TimeSlotListService, props.config), children: _jsx(RootContent, { navigateToBookingForm: props.navigateToBookingForm, children: props.children }) }));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Internal component that wraps navigateToBookingForm to handle optional parameters
|
|
29
|
+
*/
|
|
30
|
+
function RootContent({ navigateToBookingForm: providedNavigateToBookingForm, children, }) {
|
|
31
|
+
// Get BookingService to use when timeSlot/service are not provided
|
|
32
|
+
let bookingService = null;
|
|
33
|
+
try {
|
|
34
|
+
bookingService = useService(BookingServiceDefinition);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// BookingService not available - that's ok, user must provide timeSlot/service
|
|
38
|
+
bookingService = null;
|
|
39
|
+
}
|
|
40
|
+
// Wrap the provided navigateToBookingForm to handle optional parameters
|
|
41
|
+
const navigateToBookingForm = async ({ timeSlot, service, }) => {
|
|
42
|
+
// If timeSlot or service are not provided, try to get them from BookingService
|
|
43
|
+
let resolvedTimeSlot = timeSlot;
|
|
44
|
+
let resolvedService = service;
|
|
45
|
+
if ((!resolvedTimeSlot || !resolvedService) && bookingService) {
|
|
46
|
+
const serviceSelections = bookingService.serviceSelections.get();
|
|
47
|
+
if (serviceSelections.length > 0) {
|
|
48
|
+
const firstSelection = serviceSelections[0];
|
|
49
|
+
if (firstSelection) {
|
|
50
|
+
resolvedService = resolvedService || firstSelection.service;
|
|
51
|
+
resolvedTimeSlot = resolvedTimeSlot || firstSelection.timeSlot;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Validate that we have both timeSlot and service
|
|
56
|
+
if (!resolvedTimeSlot) {
|
|
57
|
+
throw new Error('timeSlot is required. Either provide it as a parameter or ensure BookingService has a service selection with a timeSlot.');
|
|
58
|
+
}
|
|
59
|
+
if (!resolvedService) {
|
|
60
|
+
throw new Error('service is required. Either provide it as a parameter or ensure BookingService has a service selection.');
|
|
61
|
+
}
|
|
62
|
+
// Call the provided function with resolved values
|
|
63
|
+
return providedNavigateToBookingForm({
|
|
64
|
+
timeSlot: resolvedTimeSlot,
|
|
65
|
+
service: resolvedService,
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
return _jsx(_Fragment, { children: children({ navigateToBookingForm }) });
|
|
19
69
|
}
|
|
20
70
|
// ============================================================================
|
|
21
71
|
// Timezone Component
|
|
@@ -6,7 +6,9 @@ import React from 'react';
|
|
|
6
6
|
import { ListVariant } from '@wix/headless-components/react';
|
|
7
7
|
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
8
8
|
import type { TimeSlot as TimeSlotType } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
9
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
9
10
|
import type { TimeSlotListServiceConfig } from '../../services/time-slot-list/time-slot-list.def.js';
|
|
11
|
+
import { ServiceSelectionTimeSlot } from '../../services/booking/booking.js';
|
|
10
12
|
export type { StartDateProps as TimeSlotStartDateProps, EndDateProps as TimeSlotEndDateProps, DurationProps as TimeSlotDurationProps, SelectProps as TimeSlotSelectProps, LocationNameProps as TimeSlotLocationNameProps, StaffMembersProps as TimeSlotStaffMembersProps, StaffMemberRepeaterProps as TimeSlotStaffMemberRepeaterProps, StaffMemberNameProps as TimeSlotStaffMemberNameProps, SelectStaffMemberProps as TimeSlotSelectStaffMemberProps, ClearStaffSelectionProps as TimeSlotClearStaffSelectionProps, } from './TimeSlot.js';
|
|
11
13
|
/**
|
|
12
14
|
* Render props for TimeSlotList.Timezone component
|
|
@@ -49,8 +51,23 @@ export declare const Timezone: React.ForwardRefExoticComponent<TimezoneProps & R
|
|
|
49
51
|
* Props for TimeSlotList.Root component
|
|
50
52
|
*/
|
|
51
53
|
export interface RootProps {
|
|
52
|
-
children: React.ReactNode
|
|
54
|
+
children: React.ReactNode | ((data: {
|
|
55
|
+
navigateToBookingForm: ({ timeSlot, service, }: {
|
|
56
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
57
|
+
service?: Service;
|
|
58
|
+
}) => Promise<void>;
|
|
59
|
+
}) => React.ReactNode);
|
|
53
60
|
config: TimeSlotListServiceConfig;
|
|
61
|
+
/**
|
|
62
|
+
* Function to navigate to the booking form.
|
|
63
|
+
* The timeSlot and service parameters are optional - if not provided,
|
|
64
|
+
* BookingService will be used to get them from the current service selections.
|
|
65
|
+
* If not provided, will use the default navigation utility.
|
|
66
|
+
*/
|
|
67
|
+
navigateToBookingForm?: ({ timeSlot, service, }: {
|
|
68
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
69
|
+
service?: Service;
|
|
70
|
+
}) => Promise<void>;
|
|
54
71
|
className?: string;
|
|
55
72
|
variant?: ListVariant;
|
|
56
73
|
}
|
|
@@ -62,15 +79,21 @@ export interface RootProps {
|
|
|
62
79
|
* @example
|
|
63
80
|
* ```tsx
|
|
64
81
|
* import { TimeSlotList } from '@wix/bookings/components';
|
|
82
|
+
* import { navigateToBookingForm } from '@wix/headless-bookings/utils';
|
|
65
83
|
*
|
|
66
84
|
* function TimeSlotsPage({ config }) {
|
|
67
85
|
* return (
|
|
68
|
-
* <TimeSlotList.Root
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
86
|
+
* <TimeSlotList.Root
|
|
87
|
+
* config={config}
|
|
88
|
+
* navigateToBookingForm={navigateToBookingForm}
|
|
89
|
+
* >
|
|
90
|
+
* {({ navigateToBookingForm }) => (
|
|
91
|
+
* <TimeSlotList.TimeSlots>
|
|
92
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
93
|
+
* {children}
|
|
94
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
95
|
+
* </TimeSlotList.TimeSlots>
|
|
96
|
+
* )}
|
|
74
97
|
* </TimeSlotList.Root>
|
|
75
98
|
* );
|
|
76
99
|
* }
|
|
@@ -9,6 +9,7 @@ import { AsChildSlot } from '@wix/headless-utils/react';
|
|
|
9
9
|
import * as CoreTimeSlotList from '../core/time-slot-list/TimeSlotList.js';
|
|
10
10
|
import * as CoreTimeSlot from '../core/time-slot-list/TimeSlot.js';
|
|
11
11
|
import { StartDate as TimeSlotStartDate, EndDate as TimeSlotEndDate, Duration, Actions as TimeSlotActions, Location, StaffMembers, StaffMemberRepeater, StaffMember, Root as TimeSlotRoot, } from './TimeSlot.js';
|
|
12
|
+
import { navigateToBookingForm as defaultNavigateToBookingForm } from '../../utils/navigation.js';
|
|
12
13
|
// ============================================================================
|
|
13
14
|
// Utilities
|
|
14
15
|
// ============================================================================
|
|
@@ -28,6 +29,7 @@ var TestIds;
|
|
|
28
29
|
TestIds["timeSlotListTimeSlot"] = "time-slot-list-time-slot";
|
|
29
30
|
TestIds["timeSlotListTimezone"] = "time-slot-list-timezone";
|
|
30
31
|
TestIds["timeSlotListLoadMore"] = "time-slot-list-load-more";
|
|
32
|
+
TestIds["timeSlotListContinue"] = "time-slot-list-continue";
|
|
31
33
|
TestIds["timeSlotListDateRangeInput"] = "time-slot-list-date-range-input";
|
|
32
34
|
})(TestIds || (TestIds = {}));
|
|
33
35
|
/**
|
|
@@ -62,23 +64,44 @@ Timezone.displayName = 'TimeSlotList.Timezone';
|
|
|
62
64
|
* @example
|
|
63
65
|
* ```tsx
|
|
64
66
|
* import { TimeSlotList } from '@wix/bookings/components';
|
|
67
|
+
* import { navigateToBookingForm } from '@wix/headless-bookings/utils';
|
|
65
68
|
*
|
|
66
69
|
* function TimeSlotsPage({ config }) {
|
|
67
70
|
* return (
|
|
68
|
-
* <TimeSlotList.Root
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
71
|
+
* <TimeSlotList.Root
|
|
72
|
+
* config={config}
|
|
73
|
+
* navigateToBookingForm={navigateToBookingForm}
|
|
74
|
+
* >
|
|
75
|
+
* {({ navigateToBookingForm }) => (
|
|
76
|
+
* <TimeSlotList.TimeSlots>
|
|
77
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
78
|
+
* {children}
|
|
79
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
80
|
+
* </TimeSlotList.TimeSlots>
|
|
81
|
+
* )}
|
|
74
82
|
* </TimeSlotList.Root>
|
|
75
83
|
* );
|
|
76
84
|
* }
|
|
77
85
|
* ```
|
|
78
86
|
*/
|
|
79
87
|
export const Root = React.forwardRef((props, ref) => {
|
|
80
|
-
const { children, config, className, variant } = props;
|
|
81
|
-
|
|
88
|
+
const { children, config, className, variant, navigateToBookingForm: providedNavigateToBookingForm, } = props;
|
|
89
|
+
// Wrap defaultNavigateToBookingForm to match optional parameter signature
|
|
90
|
+
// The core component will handle getting timeSlot/service from BookingService if not provided
|
|
91
|
+
const navigateToBookingForm = providedNavigateToBookingForm ||
|
|
92
|
+
(async ({ timeSlot, service, }) => {
|
|
93
|
+
// This will be handled by the core component's wrapper
|
|
94
|
+
// which will resolve timeSlot/service from BookingService if needed
|
|
95
|
+
if (!timeSlot || !service) {
|
|
96
|
+
throw new Error('timeSlot and service are required when using default navigation. Either provide them or ensure BookingService has service selections.');
|
|
97
|
+
}
|
|
98
|
+
return defaultNavigateToBookingForm({ timeSlot, service });
|
|
99
|
+
});
|
|
100
|
+
return (_jsx(CoreTimeSlotList.Root, { config: config, navigateToBookingForm: navigateToBookingForm, children: (coreData) => (_jsx(RootContent, { className: className, ref: ref, variant: variant, children: typeof children === 'function'
|
|
101
|
+
? children({
|
|
102
|
+
navigateToBookingForm: coreData.navigateToBookingForm,
|
|
103
|
+
})
|
|
104
|
+
: children })) }));
|
|
82
105
|
});
|
|
83
106
|
Root.displayName = 'TimeSlotList.Root';
|
|
84
107
|
/**
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ServiceSelectionTimeSlot } from '../services/booking/booking.js';
|
|
2
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
3
|
+
export declare function navigateToCheckout(checkoutId: string): Promise<void>;
|
|
4
|
+
export declare function navigateToBookingForm({ timeSlot, service, }: {
|
|
5
|
+
timeSlot: ServiceSelectionTimeSlot;
|
|
6
|
+
service: Service;
|
|
7
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { redirects } from '@wix/redirects';
|
|
2
|
+
import { LocationType as TimeSlotLocationType } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
3
|
+
import { LocationType as BookingsLocationType } from '@wix/auto_sdk_redirects_redirects';
|
|
4
|
+
export async function navigateToCheckout(checkoutId) {
|
|
5
|
+
const { redirectSession } = await redirects.createRedirectSession({
|
|
6
|
+
ecomCheckout: { checkoutId },
|
|
7
|
+
callbacks: {
|
|
8
|
+
postFlowUrl: window.location.href,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
if (redirectSession?.fullUrl) {
|
|
12
|
+
window.location.href = redirectSession.fullUrl;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
throw new Error('Failed to create redirect session');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function mapTimeSlotLocationToBookingLocation(timeSlotLocationType) {
|
|
19
|
+
switch (timeSlotLocationType) {
|
|
20
|
+
case TimeSlotLocationType.BUSINESS:
|
|
21
|
+
return BookingsLocationType.OWNER_BUSINESS;
|
|
22
|
+
case TimeSlotLocationType.CUSTOMER:
|
|
23
|
+
return BookingsLocationType.CUSTOM;
|
|
24
|
+
case TimeSlotLocationType.CUSTOM:
|
|
25
|
+
return BookingsLocationType.OWNER_CUSTOM;
|
|
26
|
+
default:
|
|
27
|
+
return BookingsLocationType.UNDEFINED;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function navigateToBookingForm({ timeSlot, service, }) {
|
|
31
|
+
if (!timeSlot) {
|
|
32
|
+
throw new Error('No time slot provided');
|
|
33
|
+
}
|
|
34
|
+
if (!service) {
|
|
35
|
+
throw new Error('No service provided');
|
|
36
|
+
}
|
|
37
|
+
// Get the first resource (staff member) if available
|
|
38
|
+
const selectedResource = timeSlot.resources?.[0];
|
|
39
|
+
const { redirectSession } = await redirects.createRedirectSession({
|
|
40
|
+
bookingsCheckout: {
|
|
41
|
+
slotAvailability: {
|
|
42
|
+
bookable: true,
|
|
43
|
+
slot: {
|
|
44
|
+
...timeSlot,
|
|
45
|
+
serviceId: service._id ?? undefined,
|
|
46
|
+
scheduleId: timeSlot.scheduleId,
|
|
47
|
+
startDate: timeSlot.startDate,
|
|
48
|
+
endDate: timeSlot.endDate,
|
|
49
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
50
|
+
resource: selectedResource
|
|
51
|
+
? {
|
|
52
|
+
_id: selectedResource._id,
|
|
53
|
+
name: selectedResource.name,
|
|
54
|
+
}
|
|
55
|
+
: undefined,
|
|
56
|
+
location: {
|
|
57
|
+
_id: timeSlot.location?._id,
|
|
58
|
+
name: timeSlot.location?.name,
|
|
59
|
+
formattedAddress: timeSlot.location?.formattedAddress,
|
|
60
|
+
locationType: mapTimeSlotLocationToBookingLocation(timeSlot.location?.locationType),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
callbacks: {
|
|
66
|
+
postFlowUrl: window.location.href,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
if (redirectSession?.fullUrl) {
|
|
70
|
+
window.location.href = redirectSession.fullUrl;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new Error('Failed to create redirect session');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -16,9 +16,11 @@ export interface BookProps {
|
|
|
16
16
|
disabled?: boolean;
|
|
17
17
|
onCheckout?: (result: {
|
|
18
18
|
checkoutId: string;
|
|
19
|
+
navigateToCheckout: (checkoutId: string) => void;
|
|
19
20
|
}) => void;
|
|
20
21
|
onComplete?: (result: {
|
|
21
22
|
orderId: string;
|
|
23
|
+
navigateToThankYou: (orderId: string) => void;
|
|
22
24
|
}) => void;
|
|
23
25
|
onError?: (error: BookingError) => void;
|
|
24
26
|
}
|
|
@@ -6,6 +6,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import { AsChildSlot } from '@wix/headless-utils/react';
|
|
8
8
|
import * as CoreBook from '../core/booking/Book.js';
|
|
9
|
+
import { navigateToCheckout } from '../../utils/navigation.js';
|
|
9
10
|
var TestIds;
|
|
10
11
|
(function (TestIds) {
|
|
11
12
|
TestIds["bookingActionBook"] = "booking-action-book";
|
|
@@ -49,6 +50,15 @@ var TestIds;
|
|
|
49
50
|
*/
|
|
50
51
|
export const Book = React.forwardRef((props, ref) => {
|
|
51
52
|
const { asChild, children, className, label = 'Book Now', loadingState = 'Booking...', disabled, onCheckout, onComplete, onError, } = props;
|
|
52
|
-
return (_jsx(CoreBook.Book, { onCheckout:
|
|
53
|
+
return (_jsx(CoreBook.Book, { onCheckout: (result) => {
|
|
54
|
+
onCheckout?.({ ...result, navigateToCheckout });
|
|
55
|
+
}, onComplete: (result) => {
|
|
56
|
+
onComplete?.({
|
|
57
|
+
...result,
|
|
58
|
+
navigateToThankYou: (orderId) => {
|
|
59
|
+
console.log('navigateToThankYou', orderId);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}, 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 }) })) }));
|
|
53
63
|
});
|
|
54
64
|
Book.displayName = 'Booking.Actions.Book';
|
|
@@ -5,12 +5,49 @@
|
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { type TimeSlotListServiceConfig } from '../../../services/time-slot-list/index.js';
|
|
7
7
|
import type { TimeSlot } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
8
|
+
import { type ServiceSelectionTimeSlot } from '../../../services/booking/booking.js';
|
|
9
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
10
|
+
/**
|
|
11
|
+
* Render props data provided to TimeSlotList.Root children
|
|
12
|
+
*/
|
|
13
|
+
export interface TimeSlotListRootRenderProps {
|
|
14
|
+
/** Function to navigate to the booking form with the selected time slot */
|
|
15
|
+
navigateToBookingForm: ({ timeSlot, service, }: {
|
|
16
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
17
|
+
service?: Service;
|
|
18
|
+
}) => Promise<void>;
|
|
19
|
+
}
|
|
8
20
|
/**
|
|
9
21
|
* Props for Root component
|
|
10
22
|
*/
|
|
11
23
|
export interface RootProps {
|
|
12
|
-
children: React.ReactNode;
|
|
24
|
+
children: (data: TimeSlotListRootRenderProps) => React.ReactNode;
|
|
13
25
|
config: TimeSlotListServiceConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Function to navigate to the booking form with the selected time slot.
|
|
28
|
+
* The timeSlot and service parameters are optional - if not provided,
|
|
29
|
+
* BookingService will be used to get them from the current service selections.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* <Root
|
|
34
|
+
* config={config}
|
|
35
|
+
* navigateToBookingForm={async ({ timeSlot, service }) => {
|
|
36
|
+
* // Custom navigation logic
|
|
37
|
+
* await navigateToBookingForm({ timeSlot, service });
|
|
38
|
+
* }}
|
|
39
|
+
* >
|
|
40
|
+
* {({ navigateToBookingForm }) => (
|
|
41
|
+
* // Use navigateToBookingForm in children
|
|
42
|
+
* // Can call with: navigateToBookingForm() or navigateToBookingForm({ timeSlot, service })
|
|
43
|
+
* )}
|
|
44
|
+
* </Root>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
navigateToBookingForm: ({ timeSlot, service, }: {
|
|
48
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
49
|
+
service?: Service;
|
|
50
|
+
}) => Promise<void>;
|
|
14
51
|
}
|
|
15
52
|
/**
|
|
16
53
|
* Root component that provides TimeSlotListService context to its children.
|
|
@@ -18,8 +55,15 @@ export interface RootProps {
|
|
|
18
55
|
* @component
|
|
19
56
|
* @example
|
|
20
57
|
* ```tsx
|
|
21
|
-
* <Root
|
|
22
|
-
* {
|
|
58
|
+
* <Root
|
|
59
|
+
* config={{ services, timeSlots, timezone }}
|
|
60
|
+
* navigateToBookingForm={async (selection) => {
|
|
61
|
+
* await navigateToBookingForm(selection);
|
|
62
|
+
* }}
|
|
63
|
+
* >
|
|
64
|
+
* {({ navigateToBookingForm }) => (
|
|
65
|
+
* // Your components that can use navigateToBookingForm
|
|
66
|
+
* )}
|
|
23
67
|
* </Root>
|
|
24
68
|
* ```
|
|
25
69
|
*/
|
|
@@ -1,21 +1,71 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useService, WixServices } from '@wix/services-manager-react';
|
|
3
3
|
import { createServicesMap } from '@wix/services-manager';
|
|
4
4
|
import { TimeSlotListServiceDefinition, TimeSlotListService, } from '../../../services/time-slot-list/index.js';
|
|
5
|
-
import { BookingServiceDefinition } from '../../../services/booking/booking.js';
|
|
5
|
+
import { BookingServiceDefinition, } from '../../../services/booking/booking.js';
|
|
6
6
|
/**
|
|
7
7
|
* Root component that provides TimeSlotListService context to its children.
|
|
8
8
|
*
|
|
9
9
|
* @component
|
|
10
10
|
* @example
|
|
11
11
|
* ```tsx
|
|
12
|
-
* <Root
|
|
13
|
-
* {
|
|
12
|
+
* <Root
|
|
13
|
+
* config={{ services, timeSlots, timezone }}
|
|
14
|
+
* navigateToBookingForm={async (selection) => {
|
|
15
|
+
* await navigateToBookingForm(selection);
|
|
16
|
+
* }}
|
|
17
|
+
* >
|
|
18
|
+
* {({ navigateToBookingForm }) => (
|
|
19
|
+
* // Your components that can use navigateToBookingForm
|
|
20
|
+
* )}
|
|
14
21
|
* </Root>
|
|
15
22
|
* ```
|
|
16
23
|
*/
|
|
17
24
|
export function Root(props) {
|
|
18
|
-
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(TimeSlotListServiceDefinition, TimeSlotListService, props.config), children: props.children }));
|
|
25
|
+
return (_jsx(WixServices, { servicesMap: createServicesMap().addService(TimeSlotListServiceDefinition, TimeSlotListService, props.config), children: _jsx(RootContent, { navigateToBookingForm: props.navigateToBookingForm, children: props.children }) }));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Internal component that wraps navigateToBookingForm to handle optional parameters
|
|
29
|
+
*/
|
|
30
|
+
function RootContent({ navigateToBookingForm: providedNavigateToBookingForm, children, }) {
|
|
31
|
+
// Get BookingService to use when timeSlot/service are not provided
|
|
32
|
+
let bookingService = null;
|
|
33
|
+
try {
|
|
34
|
+
bookingService = useService(BookingServiceDefinition);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// BookingService not available - that's ok, user must provide timeSlot/service
|
|
38
|
+
bookingService = null;
|
|
39
|
+
}
|
|
40
|
+
// Wrap the provided navigateToBookingForm to handle optional parameters
|
|
41
|
+
const navigateToBookingForm = async ({ timeSlot, service, }) => {
|
|
42
|
+
// If timeSlot or service are not provided, try to get them from BookingService
|
|
43
|
+
let resolvedTimeSlot = timeSlot;
|
|
44
|
+
let resolvedService = service;
|
|
45
|
+
if ((!resolvedTimeSlot || !resolvedService) && bookingService) {
|
|
46
|
+
const serviceSelections = bookingService.serviceSelections.get();
|
|
47
|
+
if (serviceSelections.length > 0) {
|
|
48
|
+
const firstSelection = serviceSelections[0];
|
|
49
|
+
if (firstSelection) {
|
|
50
|
+
resolvedService = resolvedService || firstSelection.service;
|
|
51
|
+
resolvedTimeSlot = resolvedTimeSlot || firstSelection.timeSlot;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Validate that we have both timeSlot and service
|
|
56
|
+
if (!resolvedTimeSlot) {
|
|
57
|
+
throw new Error('timeSlot is required. Either provide it as a parameter or ensure BookingService has a service selection with a timeSlot.');
|
|
58
|
+
}
|
|
59
|
+
if (!resolvedService) {
|
|
60
|
+
throw new Error('service is required. Either provide it as a parameter or ensure BookingService has a service selection.');
|
|
61
|
+
}
|
|
62
|
+
// Call the provided function with resolved values
|
|
63
|
+
return providedNavigateToBookingForm({
|
|
64
|
+
timeSlot: resolvedTimeSlot,
|
|
65
|
+
service: resolvedService,
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
return _jsx(_Fragment, { children: children({ navigateToBookingForm }) });
|
|
19
69
|
}
|
|
20
70
|
// ============================================================================
|
|
21
71
|
// Timezone Component
|
|
@@ -6,7 +6,9 @@ import React from 'react';
|
|
|
6
6
|
import { ListVariant } from '@wix/headless-components/react';
|
|
7
7
|
import { AsChildChildren } from '@wix/headless-utils/react';
|
|
8
8
|
import type { TimeSlot as TimeSlotType } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
9
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
9
10
|
import type { TimeSlotListServiceConfig } from '../../services/time-slot-list/time-slot-list.def.js';
|
|
11
|
+
import { ServiceSelectionTimeSlot } from '../../services/booking/booking.js';
|
|
10
12
|
export type { StartDateProps as TimeSlotStartDateProps, EndDateProps as TimeSlotEndDateProps, DurationProps as TimeSlotDurationProps, SelectProps as TimeSlotSelectProps, LocationNameProps as TimeSlotLocationNameProps, StaffMembersProps as TimeSlotStaffMembersProps, StaffMemberRepeaterProps as TimeSlotStaffMemberRepeaterProps, StaffMemberNameProps as TimeSlotStaffMemberNameProps, SelectStaffMemberProps as TimeSlotSelectStaffMemberProps, ClearStaffSelectionProps as TimeSlotClearStaffSelectionProps, } from './TimeSlot.js';
|
|
11
13
|
/**
|
|
12
14
|
* Render props for TimeSlotList.Timezone component
|
|
@@ -49,8 +51,23 @@ export declare const Timezone: React.ForwardRefExoticComponent<TimezoneProps & R
|
|
|
49
51
|
* Props for TimeSlotList.Root component
|
|
50
52
|
*/
|
|
51
53
|
export interface RootProps {
|
|
52
|
-
children: React.ReactNode
|
|
54
|
+
children: React.ReactNode | ((data: {
|
|
55
|
+
navigateToBookingForm: ({ timeSlot, service, }: {
|
|
56
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
57
|
+
service?: Service;
|
|
58
|
+
}) => Promise<void>;
|
|
59
|
+
}) => React.ReactNode);
|
|
53
60
|
config: TimeSlotListServiceConfig;
|
|
61
|
+
/**
|
|
62
|
+
* Function to navigate to the booking form.
|
|
63
|
+
* The timeSlot and service parameters are optional - if not provided,
|
|
64
|
+
* BookingService will be used to get them from the current service selections.
|
|
65
|
+
* If not provided, will use the default navigation utility.
|
|
66
|
+
*/
|
|
67
|
+
navigateToBookingForm?: ({ timeSlot, service, }: {
|
|
68
|
+
timeSlot?: ServiceSelectionTimeSlot;
|
|
69
|
+
service?: Service;
|
|
70
|
+
}) => Promise<void>;
|
|
54
71
|
className?: string;
|
|
55
72
|
variant?: ListVariant;
|
|
56
73
|
}
|
|
@@ -62,15 +79,21 @@ export interface RootProps {
|
|
|
62
79
|
* @example
|
|
63
80
|
* ```tsx
|
|
64
81
|
* import { TimeSlotList } from '@wix/bookings/components';
|
|
82
|
+
* import { navigateToBookingForm } from '@wix/headless-bookings/utils';
|
|
65
83
|
*
|
|
66
84
|
* function TimeSlotsPage({ config }) {
|
|
67
85
|
* return (
|
|
68
|
-
* <TimeSlotList.Root
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
86
|
+
* <TimeSlotList.Root
|
|
87
|
+
* config={config}
|
|
88
|
+
* navigateToBookingForm={navigateToBookingForm}
|
|
89
|
+
* >
|
|
90
|
+
* {({ navigateToBookingForm }) => (
|
|
91
|
+
* <TimeSlotList.TimeSlots>
|
|
92
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
93
|
+
* {children}
|
|
94
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
95
|
+
* </TimeSlotList.TimeSlots>
|
|
96
|
+
* )}
|
|
74
97
|
* </TimeSlotList.Root>
|
|
75
98
|
* );
|
|
76
99
|
* }
|
|
@@ -9,6 +9,7 @@ import { AsChildSlot } from '@wix/headless-utils/react';
|
|
|
9
9
|
import * as CoreTimeSlotList from '../core/time-slot-list/TimeSlotList.js';
|
|
10
10
|
import * as CoreTimeSlot from '../core/time-slot-list/TimeSlot.js';
|
|
11
11
|
import { StartDate as TimeSlotStartDate, EndDate as TimeSlotEndDate, Duration, Actions as TimeSlotActions, Location, StaffMembers, StaffMemberRepeater, StaffMember, Root as TimeSlotRoot, } from './TimeSlot.js';
|
|
12
|
+
import { navigateToBookingForm as defaultNavigateToBookingForm } from '../../utils/navigation.js';
|
|
12
13
|
// ============================================================================
|
|
13
14
|
// Utilities
|
|
14
15
|
// ============================================================================
|
|
@@ -28,6 +29,7 @@ var TestIds;
|
|
|
28
29
|
TestIds["timeSlotListTimeSlot"] = "time-slot-list-time-slot";
|
|
29
30
|
TestIds["timeSlotListTimezone"] = "time-slot-list-timezone";
|
|
30
31
|
TestIds["timeSlotListLoadMore"] = "time-slot-list-load-more";
|
|
32
|
+
TestIds["timeSlotListContinue"] = "time-slot-list-continue";
|
|
31
33
|
TestIds["timeSlotListDateRangeInput"] = "time-slot-list-date-range-input";
|
|
32
34
|
})(TestIds || (TestIds = {}));
|
|
33
35
|
/**
|
|
@@ -62,23 +64,44 @@ Timezone.displayName = 'TimeSlotList.Timezone';
|
|
|
62
64
|
* @example
|
|
63
65
|
* ```tsx
|
|
64
66
|
* import { TimeSlotList } from '@wix/bookings/components';
|
|
67
|
+
* import { navigateToBookingForm } from '@wix/headless-bookings/utils';
|
|
65
68
|
*
|
|
66
69
|
* function TimeSlotsPage({ config }) {
|
|
67
70
|
* return (
|
|
68
|
-
* <TimeSlotList.Root
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
71
|
+
* <TimeSlotList.Root
|
|
72
|
+
* config={config}
|
|
73
|
+
* navigateToBookingForm={navigateToBookingForm}
|
|
74
|
+
* >
|
|
75
|
+
* {({ navigateToBookingForm }) => (
|
|
76
|
+
* <TimeSlotList.TimeSlots>
|
|
77
|
+
* <TimeSlotList.TimeSlotRepeater>
|
|
78
|
+
* {children}
|
|
79
|
+
* </TimeSlotList.TimeSlotRepeater>
|
|
80
|
+
* </TimeSlotList.TimeSlots>
|
|
81
|
+
* )}
|
|
74
82
|
* </TimeSlotList.Root>
|
|
75
83
|
* );
|
|
76
84
|
* }
|
|
77
85
|
* ```
|
|
78
86
|
*/
|
|
79
87
|
export const Root = React.forwardRef((props, ref) => {
|
|
80
|
-
const { children, config, className, variant } = props;
|
|
81
|
-
|
|
88
|
+
const { children, config, className, variant, navigateToBookingForm: providedNavigateToBookingForm, } = props;
|
|
89
|
+
// Wrap defaultNavigateToBookingForm to match optional parameter signature
|
|
90
|
+
// The core component will handle getting timeSlot/service from BookingService if not provided
|
|
91
|
+
const navigateToBookingForm = providedNavigateToBookingForm ||
|
|
92
|
+
(async ({ timeSlot, service, }) => {
|
|
93
|
+
// This will be handled by the core component's wrapper
|
|
94
|
+
// which will resolve timeSlot/service from BookingService if needed
|
|
95
|
+
if (!timeSlot || !service) {
|
|
96
|
+
throw new Error('timeSlot and service are required when using default navigation. Either provide them or ensure BookingService has service selections.');
|
|
97
|
+
}
|
|
98
|
+
return defaultNavigateToBookingForm({ timeSlot, service });
|
|
99
|
+
});
|
|
100
|
+
return (_jsx(CoreTimeSlotList.Root, { config: config, navigateToBookingForm: navigateToBookingForm, children: (coreData) => (_jsx(RootContent, { className: className, ref: ref, variant: variant, children: typeof children === 'function'
|
|
101
|
+
? children({
|
|
102
|
+
navigateToBookingForm: coreData.navigateToBookingForm,
|
|
103
|
+
})
|
|
104
|
+
: children })) }));
|
|
82
105
|
});
|
|
83
106
|
Root.displayName = 'TimeSlotList.Root';
|
|
84
107
|
/**
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ServiceSelectionTimeSlot } from '../services/booking/booking.js';
|
|
2
|
+
import type { Service } from '@wix/auto_sdk_bookings_services';
|
|
3
|
+
export declare function navigateToCheckout(checkoutId: string): Promise<void>;
|
|
4
|
+
export declare function navigateToBookingForm({ timeSlot, service, }: {
|
|
5
|
+
timeSlot: ServiceSelectionTimeSlot;
|
|
6
|
+
service: Service;
|
|
7
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { redirects } from '@wix/redirects';
|
|
2
|
+
import { LocationType as TimeSlotLocationType } from '@wix/auto_sdk_bookings_availability-time-slots';
|
|
3
|
+
import { LocationType as BookingsLocationType } from '@wix/auto_sdk_redirects_redirects';
|
|
4
|
+
export async function navigateToCheckout(checkoutId) {
|
|
5
|
+
const { redirectSession } = await redirects.createRedirectSession({
|
|
6
|
+
ecomCheckout: { checkoutId },
|
|
7
|
+
callbacks: {
|
|
8
|
+
postFlowUrl: window.location.href,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
if (redirectSession?.fullUrl) {
|
|
12
|
+
window.location.href = redirectSession.fullUrl;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
throw new Error('Failed to create redirect session');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function mapTimeSlotLocationToBookingLocation(timeSlotLocationType) {
|
|
19
|
+
switch (timeSlotLocationType) {
|
|
20
|
+
case TimeSlotLocationType.BUSINESS:
|
|
21
|
+
return BookingsLocationType.OWNER_BUSINESS;
|
|
22
|
+
case TimeSlotLocationType.CUSTOMER:
|
|
23
|
+
return BookingsLocationType.CUSTOM;
|
|
24
|
+
case TimeSlotLocationType.CUSTOM:
|
|
25
|
+
return BookingsLocationType.OWNER_CUSTOM;
|
|
26
|
+
default:
|
|
27
|
+
return BookingsLocationType.UNDEFINED;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function navigateToBookingForm({ timeSlot, service, }) {
|
|
31
|
+
if (!timeSlot) {
|
|
32
|
+
throw new Error('No time slot provided');
|
|
33
|
+
}
|
|
34
|
+
if (!service) {
|
|
35
|
+
throw new Error('No service provided');
|
|
36
|
+
}
|
|
37
|
+
// Get the first resource (staff member) if available
|
|
38
|
+
const selectedResource = timeSlot.resources?.[0];
|
|
39
|
+
const { redirectSession } = await redirects.createRedirectSession({
|
|
40
|
+
bookingsCheckout: {
|
|
41
|
+
slotAvailability: {
|
|
42
|
+
bookable: true,
|
|
43
|
+
slot: {
|
|
44
|
+
...timeSlot,
|
|
45
|
+
serviceId: service._id ?? undefined,
|
|
46
|
+
scheduleId: timeSlot.scheduleId,
|
|
47
|
+
startDate: timeSlot.startDate,
|
|
48
|
+
endDate: timeSlot.endDate,
|
|
49
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
50
|
+
resource: selectedResource
|
|
51
|
+
? {
|
|
52
|
+
_id: selectedResource._id,
|
|
53
|
+
name: selectedResource.name,
|
|
54
|
+
}
|
|
55
|
+
: undefined,
|
|
56
|
+
location: {
|
|
57
|
+
_id: timeSlot.location?._id,
|
|
58
|
+
name: timeSlot.location?.name,
|
|
59
|
+
formattedAddress: timeSlot.location?.formattedAddress,
|
|
60
|
+
locationType: mapTimeSlotLocationToBookingLocation(timeSlot.location?.locationType),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
callbacks: {
|
|
66
|
+
postFlowUrl: window.location.href,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
if (redirectSession?.fullUrl) {
|
|
70
|
+
window.location.href = redirectSession.fullUrl;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new Error('Failed to create redirect session');
|
|
74
|
+
}
|
|
75
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/headless-bookings",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.62",
|
|
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": "
|
|
75
|
+
"falconPackageHash": "a7ee3575b035403add534d60cde7f1bc57053324c9c08aa82811ca8b"
|
|
76
76
|
}
|