@code-collective/booking-widget 1.0.12 → 1.0.14
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/CHANGELOG.md +48 -46
- package/README.md +500 -500
- package/dist/booking-widget.css +1 -1
- package/dist/booking-widget.js +829 -707
- package/dist/booking-widget.min.js +24 -25
- package/dist/booking-widget.umd.cjs +5 -5
- package/package.json +58 -58
- package/src/lib/BookingProvider.svelte +21 -21
- package/src/lib/CartBar.svelte +26 -26
- package/src/lib/CartBarView.svelte +78 -78
- package/src/lib/CartExpiryGuard.svelte +416 -416
- package/src/lib/CartOverview.svelte +30 -30
- package/src/lib/CartOverviewButton.svelte +104 -104
- package/src/lib/Checkout.svelte +141 -141
- package/src/lib/CheckoutModal.css +179 -0
- package/src/lib/CheckoutModal.svelte +78 -573
- package/src/lib/CheckoutPanel.svelte +121 -121
- package/src/lib/PaymentPage.svelte +208 -191
- package/src/lib/ResultView.svelte +24 -4
- package/src/lib/TicketConfigurator.svelte +166 -166
- package/src/lib/api.ts +36 -5
- package/src/lib/booking-context.ts +33 -33
- package/src/lib/cart-overview.svelte.ts +97 -97
- package/src/lib/checkout-item-view.ts +63 -0
- package/src/lib/checkout-payment-flow.svelte.ts +523 -0
- package/src/lib/client-types.ts +22 -6
- package/src/lib/config.ts +162 -162
- package/src/lib/elements/bw-cart.svelte +49 -49
- package/src/lib/elements/bw-checkout.svelte +97 -97
- package/src/lib/elements/bw-configurator.svelte +72 -72
- package/src/lib/elements/register.ts +171 -171
- package/src/lib/elements/shared.ts +18 -18
- package/src/lib/generated-types.ts +94 -5
- package/src/lib/host.svelte.ts +336 -336
- package/src/lib/index.ts +242 -242
- package/src/lib/messages.ts +157 -157
- package/src/lib/peach-sdk.ts +86 -86
- package/src/lib/portal.ts +23 -23
package/src/lib/index.ts
CHANGED
|
@@ -1,242 +1,242 @@
|
|
|
1
|
-
import './app.css';
|
|
2
|
-
import { mount, unmount } from 'svelte';
|
|
3
|
-
import type { CartOverviewDisplay, CartOverviewState } from './config';
|
|
4
|
-
import type { BookingHost, BookingHostConfig } from './host.svelte';
|
|
5
|
-
import { createBookingHost } from './host.svelte';
|
|
6
|
-
import { ApiClient, ApiError } from './api';
|
|
7
|
-
import { SessionManager } from './session-manager';
|
|
8
|
-
import { CartManager } from './cart-manager';
|
|
9
|
-
import { onWidgetMessage } from './messages';
|
|
10
|
-
import TicketConfiguratorComponent from './TicketConfigurator.svelte';
|
|
11
|
-
import CheckoutComponent from './Checkout.svelte';
|
|
12
|
-
import CartOverviewComponent from './CartOverview.svelte';
|
|
13
|
-
|
|
14
|
-
// Re-export components for direct Svelte usage
|
|
15
|
-
export { default as TicketConfigurator } from './TicketConfigurator.svelte';
|
|
16
|
-
export { default as Checkout } from './Checkout.svelte';
|
|
17
|
-
export { default as CartOverview } from './CartOverview.svelte';
|
|
18
|
-
export { default as CartBar } from './CartBar.svelte';
|
|
19
|
-
export { default as CartOverviewButton } from './CartOverviewButton.svelte';
|
|
20
|
-
// Required if you are not using the elements build: it owns the "still shopping?" warning, the expired view
|
|
21
|
-
// and the payment-timeout hand-over, and nothing else on the page does. createBookingHost mounts it for you;
|
|
22
|
-
// export it for consumers composing everything by hand.
|
|
23
|
-
export { default as CartExpiryGuard } from './CartExpiryGuard.svelte';
|
|
24
|
-
// Supplies the host to everything beneath it, so components need no api/cartManager props of their own.
|
|
25
|
-
export { default as BookingProvider } from './BookingProvider.svelte';
|
|
26
|
-
|
|
27
|
-
// Re-export utilities
|
|
28
|
-
export { ApiClient, ApiError, SessionManager, CartManager };
|
|
29
|
-
export { resolveWizardPages, resolveEditPages, DEFAULT_WIZARD_PAGES } from './config';
|
|
30
|
-
export { createBookingHost, setBookingDefaults, getBookingDefaults, requestCheckoutOpen, requestCheckoutClose } from './host.svelte';
|
|
31
|
-
export { portal } from './portal';
|
|
32
|
-
export { setPeachSdk } from './peach-sdk';
|
|
33
|
-
export type { PeachEnv } from './peach-sdk';
|
|
34
|
-
export { getBookingHostContext } from './booking-context';
|
|
35
|
-
export { onWidgetMessage, postMessage } from './messages';
|
|
36
|
-
export type { BookingApi } from './api';
|
|
37
|
-
export type { BookingHost, BookingHostConfig, BookingDefaults, ResolvedBookingOptions } from './host.svelte';
|
|
38
|
-
export type {
|
|
39
|
-
WizardPages, WizardPageConfig, CartOverviewDisplay, CartOverviewState, CheckoutMode, WidgetMode, WizardWidgetType,
|
|
40
|
-
} from './config';
|
|
41
|
-
export type {
|
|
42
|
-
WidgetMessage, WidgetMessageType, CartChangeMessage, CartUpdatedMessage, CartExpiredMessage,
|
|
43
|
-
ModalOpenMessage, ModalCloseMessage, OrderCompleteMessage, PaymentStartedMessage, PaymentEndedMessage,
|
|
44
|
-
PaymentTimedOutMessage,
|
|
45
|
-
} from './messages';
|
|
46
|
-
export type { components, operations, paths } from './generated-types';
|
|
47
|
-
export type * from './client-types';
|
|
48
|
-
|
|
49
|
-
// --- Mount function configs ---
|
|
50
|
-
|
|
51
|
-
// Every mount function takes the same host options, so a consumer mounting more than one widget can hand all
|
|
52
|
-
// of them the same host and get one session, one cart and one expiry guard - see `host` below.
|
|
53
|
-
type BaseConfig = Omit<BookingHostConfig, 'onCheckoutOpenChange'> & {
|
|
54
|
-
// An existing host to mount into. Without one each mount function builds its own, which means its own
|
|
55
|
-
// session and its own cart - fine for a single widget on a page, wrong for two.
|
|
56
|
-
host?: BookingHost;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export interface ConfiguratorConfig extends BaseConfig {
|
|
60
|
-
productId: string;
|
|
61
|
-
currency?: string;
|
|
62
|
-
cancelable?: boolean;
|
|
63
|
-
// onCartChange and the other cart callbacks come from BookingHostConfig - see createBookingHost.
|
|
64
|
-
onCancel?: () => void;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface CheckoutConfig extends BaseConfig {
|
|
68
|
-
// Inline by default - the mount target is a container the consumer positioned itself. Pass 'modal' for the
|
|
69
|
-
// portalled overlay the custom-elements build shows.
|
|
70
|
-
mode?: 'inline' | 'modal';
|
|
71
|
-
onClose?: () => void;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface CartOverviewConfig extends BaseConfig {
|
|
75
|
-
display?: CartOverviewDisplay;
|
|
76
|
-
onCheckout?: () => void;
|
|
77
|
-
/** Distinguishes an empty cart from one that could not be read - see CartOverview. */
|
|
78
|
-
onStateChange?: (state: CartOverviewState) => void;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface MountedWidget {
|
|
82
|
-
destroy: () => void;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// --- Mount functions ---
|
|
86
|
-
|
|
87
|
-
interface MountContext {
|
|
88
|
-
host: BookingHost;
|
|
89
|
-
/** Tearing the widget down tears the host down too - but only the host this mount built itself. */
|
|
90
|
-
release: () => void;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Resolves the host a mount function will use. A host passed in is the consumer's to destroy - other widgets
|
|
95
|
-
* are probably still using it - so this mount only unsubscribes the callbacks it added to it.
|
|
96
|
-
*/
|
|
97
|
-
/**
|
|
98
|
-
* Waits for the session, releasing whatever the mount just acquired if it is refused. Without this a
|
|
99
|
-
* rejected ready - an unallowlisted checkout key, the failure consumers are told to expect - left the
|
|
100
|
-
* host's message subscription, its session-refresh interval and its expiry-guard refcount behind, and that
|
|
101
|
-
* leaked refcount pins CartExpiryGuard on <body> for the life of the page.
|
|
102
|
-
*/
|
|
103
|
-
async function readyOrRelease(context: MountContext): Promise<void> {
|
|
104
|
-
try {
|
|
105
|
-
await context.host.ready;
|
|
106
|
-
} catch (e) {
|
|
107
|
-
context.release();
|
|
108
|
-
throw e;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function hostFor(config: BaseConfig): MountContext {
|
|
113
|
-
if (!config.host) {
|
|
114
|
-
const host = createBookingHost(config);
|
|
115
|
-
return { host, release: () => host.destroy() };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// The host was built elsewhere and already carries its own callbacks, so the ones on this config would
|
|
119
|
-
// otherwise be dropped on the floor - a consumer following the documented `{ host, onOrderConfirmed }`
|
|
120
|
-
// shape would get a checkout that never reports a confirmed order. They are wired to the same messages
|
|
121
|
-
// the host itself listens to.
|
|
122
|
-
return { host: config.host, release: subscribeCallbacks(config) };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function subscribeCallbacks(config: BaseConfig): () => void {
|
|
126
|
-
const { onCartChange, onCartUpdated, onCartExpired, onOrderConfirmed } = config;
|
|
127
|
-
if (!onCartChange && !onCartUpdated && !onCartExpired && !onOrderConfirmed) return () => {};
|
|
128
|
-
|
|
129
|
-
return onWidgetMessage((d) => {
|
|
130
|
-
if (d.type === 'cart:change') {
|
|
131
|
-
onCartChange?.({
|
|
132
|
-
itemCount: d.itemCount,
|
|
133
|
-
cartItemId: d.cartItemId,
|
|
134
|
-
totalFormatted: d.totalFormatted,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
if (d.type === 'cart:updated') onCartUpdated?.(d.cart);
|
|
138
|
-
if (d.type === 'cart:expired') onCartExpired?.();
|
|
139
|
-
if (d.type === 'order:complete') {
|
|
140
|
-
onOrderConfirmed?.({ cartToken: d.cartToken, value: d.value, currency: d.currency });
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export async function mountConfigurator(target: HTMLElement, config: ConfiguratorConfig): Promise<MountedWidget> {
|
|
146
|
-
const context = hostFor(config);
|
|
147
|
-
const { host, release } = context;
|
|
148
|
-
|
|
149
|
-
await readyOrRelease(context);
|
|
150
|
-
|
|
151
|
-
const component = mount(TicketConfiguratorComponent, {
|
|
152
|
-
target,
|
|
153
|
-
props: {
|
|
154
|
-
api: host.api,
|
|
155
|
-
cartManager: host.cartManager,
|
|
156
|
-
productId: config.productId,
|
|
157
|
-
wizardPages: config.wizardPages ?? host.options.wizardPages,
|
|
158
|
-
autoSelectSingleTimeSlot: config.autoSelectSingleTimeSlot ?? host.options.autoSelectSingleTimeSlot,
|
|
159
|
-
// Stated per configurator so this and the host's own autoOpenCheckout meet in the same branch - see
|
|
160
|
-
// host.svelte.ts. Both have to say yes for an add to open checkout, which is what lets one configurator
|
|
161
|
-
// on a page opt out (the ES equivalent of the element's no-auto-checkout) without silencing the rest.
|
|
162
|
-
autoOpenCheckout: config.autoOpenCheckout !== false,
|
|
163
|
-
onCancel: config.onCancel,
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
return {
|
|
168
|
-
destroy() {
|
|
169
|
-
unmount(component);
|
|
170
|
-
release();
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export async function mountCheckout(target: HTMLElement, config: CheckoutConfig): Promise<MountedWidget> {
|
|
176
|
-
const context = hostFor(config);
|
|
177
|
-
const { host, release } = context;
|
|
178
|
-
|
|
179
|
-
await readyOrRelease(context);
|
|
180
|
-
|
|
181
|
-
const component = mount(CheckoutComponent, {
|
|
182
|
-
target,
|
|
183
|
-
props: {
|
|
184
|
-
api: host.api,
|
|
185
|
-
cartManager: host.cartManager,
|
|
186
|
-
wizardPages: config.wizardPages ?? host.options.wizardPages,
|
|
187
|
-
editPages: config.editPages ?? host.options.editPages,
|
|
188
|
-
autoSelectSingleTimeSlot: config.autoSelectSingleTimeSlot ?? host.options.autoSelectSingleTimeSlot,
|
|
189
|
-
mode: config.mode ?? 'inline',
|
|
190
|
-
// The modal opens and closes with the host, which is what an add-to-cart and the cart bar's button
|
|
191
|
-
// both reach. A consumer wanting to drive it directly can call host.openCheckout().
|
|
192
|
-
get open() {
|
|
193
|
-
return host.isCheckoutOpen;
|
|
194
|
-
},
|
|
195
|
-
// Fires for every dismissal, not just the scrim - Checkout answers the modal:close message rather
|
|
196
|
-
// than only its own overlay click.
|
|
197
|
-
onClose: config.onClose,
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
destroy() {
|
|
203
|
-
unmount(component);
|
|
204
|
-
release();
|
|
205
|
-
},
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export async function mountCartOverview(target: HTMLElement, config: CartOverviewConfig): Promise<MountedWidget> {
|
|
210
|
-
const context = hostFor(config);
|
|
211
|
-
const { host, release } = context;
|
|
212
|
-
|
|
213
|
-
await readyOrRelease(context);
|
|
214
|
-
|
|
215
|
-
const component = mount(CartOverviewComponent, {
|
|
216
|
-
target,
|
|
217
|
-
props: {
|
|
218
|
-
api: host.api,
|
|
219
|
-
cartManager: host.cartManager,
|
|
220
|
-
display: config.display ?? 'bar',
|
|
221
|
-
onStateChange: config.onStateChange,
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
const stopListening = config.onCheckout
|
|
226
|
-
? onCheckoutRequested(config.onCheckout)
|
|
227
|
-
: () => {};
|
|
228
|
-
|
|
229
|
-
return {
|
|
230
|
-
destroy() {
|
|
231
|
-
stopListening();
|
|
232
|
-
unmount(component);
|
|
233
|
-
release();
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function onCheckoutRequested(onCheckout: () => void): () => void {
|
|
239
|
-
return onWidgetMessage((d) => {
|
|
240
|
-
if (d.type === 'modal:open') onCheckout();
|
|
241
|
-
});
|
|
242
|
-
}
|
|
1
|
+
import './app.css';
|
|
2
|
+
import { mount, unmount } from 'svelte';
|
|
3
|
+
import type { CartOverviewDisplay, CartOverviewState } from './config';
|
|
4
|
+
import type { BookingHost, BookingHostConfig } from './host.svelte';
|
|
5
|
+
import { createBookingHost } from './host.svelte';
|
|
6
|
+
import { ApiClient, ApiError } from './api';
|
|
7
|
+
import { SessionManager } from './session-manager';
|
|
8
|
+
import { CartManager } from './cart-manager';
|
|
9
|
+
import { onWidgetMessage } from './messages';
|
|
10
|
+
import TicketConfiguratorComponent from './TicketConfigurator.svelte';
|
|
11
|
+
import CheckoutComponent from './Checkout.svelte';
|
|
12
|
+
import CartOverviewComponent from './CartOverview.svelte';
|
|
13
|
+
|
|
14
|
+
// Re-export components for direct Svelte usage
|
|
15
|
+
export { default as TicketConfigurator } from './TicketConfigurator.svelte';
|
|
16
|
+
export { default as Checkout } from './Checkout.svelte';
|
|
17
|
+
export { default as CartOverview } from './CartOverview.svelte';
|
|
18
|
+
export { default as CartBar } from './CartBar.svelte';
|
|
19
|
+
export { default as CartOverviewButton } from './CartOverviewButton.svelte';
|
|
20
|
+
// Required if you are not using the elements build: it owns the "still shopping?" warning, the expired view
|
|
21
|
+
// and the payment-timeout hand-over, and nothing else on the page does. createBookingHost mounts it for you;
|
|
22
|
+
// export it for consumers composing everything by hand.
|
|
23
|
+
export { default as CartExpiryGuard } from './CartExpiryGuard.svelte';
|
|
24
|
+
// Supplies the host to everything beneath it, so components need no api/cartManager props of their own.
|
|
25
|
+
export { default as BookingProvider } from './BookingProvider.svelte';
|
|
26
|
+
|
|
27
|
+
// Re-export utilities
|
|
28
|
+
export { ApiClient, ApiError, SessionManager, CartManager };
|
|
29
|
+
export { resolveWizardPages, resolveEditPages, DEFAULT_WIZARD_PAGES } from './config';
|
|
30
|
+
export { createBookingHost, setBookingDefaults, getBookingDefaults, requestCheckoutOpen, requestCheckoutClose } from './host.svelte';
|
|
31
|
+
export { portal } from './portal';
|
|
32
|
+
export { setPeachSdk } from './peach-sdk';
|
|
33
|
+
export type { PeachEnv } from './peach-sdk';
|
|
34
|
+
export { getBookingHostContext } from './booking-context';
|
|
35
|
+
export { onWidgetMessage, postMessage } from './messages';
|
|
36
|
+
export type { BookingApi } from './api';
|
|
37
|
+
export type { BookingHost, BookingHostConfig, BookingDefaults, ResolvedBookingOptions } from './host.svelte';
|
|
38
|
+
export type {
|
|
39
|
+
WizardPages, WizardPageConfig, CartOverviewDisplay, CartOverviewState, CheckoutMode, WidgetMode, WizardWidgetType,
|
|
40
|
+
} from './config';
|
|
41
|
+
export type {
|
|
42
|
+
WidgetMessage, WidgetMessageType, CartChangeMessage, CartUpdatedMessage, CartExpiredMessage,
|
|
43
|
+
ModalOpenMessage, ModalCloseMessage, OrderCompleteMessage, PaymentStartedMessage, PaymentEndedMessage,
|
|
44
|
+
PaymentTimedOutMessage,
|
|
45
|
+
} from './messages';
|
|
46
|
+
export type { components, operations, paths } from './generated-types';
|
|
47
|
+
export type * from './client-types';
|
|
48
|
+
|
|
49
|
+
// --- Mount function configs ---
|
|
50
|
+
|
|
51
|
+
// Every mount function takes the same host options, so a consumer mounting more than one widget can hand all
|
|
52
|
+
// of them the same host and get one session, one cart and one expiry guard - see `host` below.
|
|
53
|
+
type BaseConfig = Omit<BookingHostConfig, 'onCheckoutOpenChange'> & {
|
|
54
|
+
// An existing host to mount into. Without one each mount function builds its own, which means its own
|
|
55
|
+
// session and its own cart - fine for a single widget on a page, wrong for two.
|
|
56
|
+
host?: BookingHost;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export interface ConfiguratorConfig extends BaseConfig {
|
|
60
|
+
productId: string;
|
|
61
|
+
currency?: string;
|
|
62
|
+
cancelable?: boolean;
|
|
63
|
+
// onCartChange and the other cart callbacks come from BookingHostConfig - see createBookingHost.
|
|
64
|
+
onCancel?: () => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface CheckoutConfig extends BaseConfig {
|
|
68
|
+
// Inline by default - the mount target is a container the consumer positioned itself. Pass 'modal' for the
|
|
69
|
+
// portalled overlay the custom-elements build shows.
|
|
70
|
+
mode?: 'inline' | 'modal';
|
|
71
|
+
onClose?: () => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface CartOverviewConfig extends BaseConfig {
|
|
75
|
+
display?: CartOverviewDisplay;
|
|
76
|
+
onCheckout?: () => void;
|
|
77
|
+
/** Distinguishes an empty cart from one that could not be read - see CartOverview. */
|
|
78
|
+
onStateChange?: (state: CartOverviewState) => void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface MountedWidget {
|
|
82
|
+
destroy: () => void;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// --- Mount functions ---
|
|
86
|
+
|
|
87
|
+
interface MountContext {
|
|
88
|
+
host: BookingHost;
|
|
89
|
+
/** Tearing the widget down tears the host down too - but only the host this mount built itself. */
|
|
90
|
+
release: () => void;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Resolves the host a mount function will use. A host passed in is the consumer's to destroy - other widgets
|
|
95
|
+
* are probably still using it - so this mount only unsubscribes the callbacks it added to it.
|
|
96
|
+
*/
|
|
97
|
+
/**
|
|
98
|
+
* Waits for the session, releasing whatever the mount just acquired if it is refused. Without this a
|
|
99
|
+
* rejected ready - an unallowlisted checkout key, the failure consumers are told to expect - left the
|
|
100
|
+
* host's message subscription, its session-refresh interval and its expiry-guard refcount behind, and that
|
|
101
|
+
* leaked refcount pins CartExpiryGuard on <body> for the life of the page.
|
|
102
|
+
*/
|
|
103
|
+
async function readyOrRelease(context: MountContext): Promise<void> {
|
|
104
|
+
try {
|
|
105
|
+
await context.host.ready;
|
|
106
|
+
} catch (e) {
|
|
107
|
+
context.release();
|
|
108
|
+
throw e;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function hostFor(config: BaseConfig): MountContext {
|
|
113
|
+
if (!config.host) {
|
|
114
|
+
const host = createBookingHost(config);
|
|
115
|
+
return { host, release: () => host.destroy() };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// The host was built elsewhere and already carries its own callbacks, so the ones on this config would
|
|
119
|
+
// otherwise be dropped on the floor - a consumer following the documented `{ host, onOrderConfirmed }`
|
|
120
|
+
// shape would get a checkout that never reports a confirmed order. They are wired to the same messages
|
|
121
|
+
// the host itself listens to.
|
|
122
|
+
return { host: config.host, release: subscribeCallbacks(config) };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function subscribeCallbacks(config: BaseConfig): () => void {
|
|
126
|
+
const { onCartChange, onCartUpdated, onCartExpired, onOrderConfirmed } = config;
|
|
127
|
+
if (!onCartChange && !onCartUpdated && !onCartExpired && !onOrderConfirmed) return () => {};
|
|
128
|
+
|
|
129
|
+
return onWidgetMessage((d) => {
|
|
130
|
+
if (d.type === 'cart:change') {
|
|
131
|
+
onCartChange?.({
|
|
132
|
+
itemCount: d.itemCount,
|
|
133
|
+
cartItemId: d.cartItemId,
|
|
134
|
+
totalFormatted: d.totalFormatted,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (d.type === 'cart:updated') onCartUpdated?.(d.cart);
|
|
138
|
+
if (d.type === 'cart:expired') onCartExpired?.();
|
|
139
|
+
if (d.type === 'order:complete') {
|
|
140
|
+
onOrderConfirmed?.({ cartToken: d.cartToken, value: d.value, currency: d.currency });
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export async function mountConfigurator(target: HTMLElement, config: ConfiguratorConfig): Promise<MountedWidget> {
|
|
146
|
+
const context = hostFor(config);
|
|
147
|
+
const { host, release } = context;
|
|
148
|
+
|
|
149
|
+
await readyOrRelease(context);
|
|
150
|
+
|
|
151
|
+
const component = mount(TicketConfiguratorComponent, {
|
|
152
|
+
target,
|
|
153
|
+
props: {
|
|
154
|
+
api: host.api,
|
|
155
|
+
cartManager: host.cartManager,
|
|
156
|
+
productId: config.productId,
|
|
157
|
+
wizardPages: config.wizardPages ?? host.options.wizardPages,
|
|
158
|
+
autoSelectSingleTimeSlot: config.autoSelectSingleTimeSlot ?? host.options.autoSelectSingleTimeSlot,
|
|
159
|
+
// Stated per configurator so this and the host's own autoOpenCheckout meet in the same branch - see
|
|
160
|
+
// host.svelte.ts. Both have to say yes for an add to open checkout, which is what lets one configurator
|
|
161
|
+
// on a page opt out (the ES equivalent of the element's no-auto-checkout) without silencing the rest.
|
|
162
|
+
autoOpenCheckout: config.autoOpenCheckout !== false,
|
|
163
|
+
onCancel: config.onCancel,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
destroy() {
|
|
169
|
+
unmount(component);
|
|
170
|
+
release();
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export async function mountCheckout(target: HTMLElement, config: CheckoutConfig): Promise<MountedWidget> {
|
|
176
|
+
const context = hostFor(config);
|
|
177
|
+
const { host, release } = context;
|
|
178
|
+
|
|
179
|
+
await readyOrRelease(context);
|
|
180
|
+
|
|
181
|
+
const component = mount(CheckoutComponent, {
|
|
182
|
+
target,
|
|
183
|
+
props: {
|
|
184
|
+
api: host.api,
|
|
185
|
+
cartManager: host.cartManager,
|
|
186
|
+
wizardPages: config.wizardPages ?? host.options.wizardPages,
|
|
187
|
+
editPages: config.editPages ?? host.options.editPages,
|
|
188
|
+
autoSelectSingleTimeSlot: config.autoSelectSingleTimeSlot ?? host.options.autoSelectSingleTimeSlot,
|
|
189
|
+
mode: config.mode ?? 'inline',
|
|
190
|
+
// The modal opens and closes with the host, which is what an add-to-cart and the cart bar's button
|
|
191
|
+
// both reach. A consumer wanting to drive it directly can call host.openCheckout().
|
|
192
|
+
get open() {
|
|
193
|
+
return host.isCheckoutOpen;
|
|
194
|
+
},
|
|
195
|
+
// Fires for every dismissal, not just the scrim - Checkout answers the modal:close message rather
|
|
196
|
+
// than only its own overlay click.
|
|
197
|
+
onClose: config.onClose,
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
destroy() {
|
|
203
|
+
unmount(component);
|
|
204
|
+
release();
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function mountCartOverview(target: HTMLElement, config: CartOverviewConfig): Promise<MountedWidget> {
|
|
210
|
+
const context = hostFor(config);
|
|
211
|
+
const { host, release } = context;
|
|
212
|
+
|
|
213
|
+
await readyOrRelease(context);
|
|
214
|
+
|
|
215
|
+
const component = mount(CartOverviewComponent, {
|
|
216
|
+
target,
|
|
217
|
+
props: {
|
|
218
|
+
api: host.api,
|
|
219
|
+
cartManager: host.cartManager,
|
|
220
|
+
display: config.display ?? 'bar',
|
|
221
|
+
onStateChange: config.onStateChange,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const stopListening = config.onCheckout
|
|
226
|
+
? onCheckoutRequested(config.onCheckout)
|
|
227
|
+
: () => {};
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
destroy() {
|
|
231
|
+
stopListening();
|
|
232
|
+
unmount(component);
|
|
233
|
+
release();
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function onCheckoutRequested(onCheckout: () => void): () => void {
|
|
239
|
+
return onWidgetMessage((d) => {
|
|
240
|
+
if (d.type === 'modal:open') onCheckout();
|
|
241
|
+
});
|
|
242
|
+
}
|