@seatlayer/js 0.37.0 → 0.38.0
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/README.md +33 -0
- package/dist/chunk-HMLY7DHA.js +16 -0
- package/dist/chunk-HMLY7DHA.js.map +1 -0
- package/dist/hostedCheckout-PLHKPT6W.js +345 -0
- package/dist/hostedCheckout-PLHKPT6W.js.map +1 -0
- package/dist/index.cjs +745 -156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +182 -1
- package/dist/index.d.ts +182 -1
- package/dist/index.js +261 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
|
-
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
1
|
+
import {
|
|
2
|
+
__privateAdd,
|
|
3
|
+
__privateGet,
|
|
4
|
+
__privateMethod,
|
|
5
|
+
__privateSet
|
|
6
|
+
} from "./chunk-HMLY7DHA.js";
|
|
9
7
|
|
|
10
8
|
// src/SeatingChart.ts
|
|
11
9
|
import {
|
|
@@ -120,6 +118,41 @@ var PubApi = class {
|
|
|
120
118
|
body: { holdId, ...ttlMs ? { ttlMs } : {} }
|
|
121
119
|
});
|
|
122
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Which gateways this event can actually take money through — the question
|
|
123
|
+
* `checkout: 'hosted'` has to answer BEFORE it shows a buyer a Pay button, so
|
|
124
|
+
* the answer is never discovered by failing a payment.
|
|
125
|
+
*
|
|
126
|
+
* Anonymous, and it discloses no account, key, mode or currency for a gateway
|
|
127
|
+
* that did not match.
|
|
128
|
+
*/
|
|
129
|
+
paymentOptions(key) {
|
|
130
|
+
return this.request(`/pub/events/${encodeURIComponent(key)}/payment-options`);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Turn a live hold into an order and start a payment.
|
|
134
|
+
*
|
|
135
|
+
* The amount is NOT sent: the server recomputes it from the hold's own items,
|
|
136
|
+
* which is the only reason a browser cannot alter what it pays. Nor is the
|
|
137
|
+
* PROVIDER — the event row decides which gateway charges, and a `provider` in
|
|
138
|
+
* the body is checked rather than obeyed (409 `provider_mismatch`). Omitting
|
|
139
|
+
* it is the shape that cannot disagree.
|
|
140
|
+
*/
|
|
141
|
+
startCheckout(key, input) {
|
|
142
|
+
return this.request(`/pub/events/${encodeURIComponent(key)}/checkout`, {
|
|
143
|
+
method: "POST",
|
|
144
|
+
body: input
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Poll an order while its gateway webhook lands. The order id is an
|
|
149
|
+
* unguessable token the buyer already holds, so it acts as the capability —
|
|
150
|
+
* which is also why a buyer returning from a gateway page can be told what
|
|
151
|
+
* happened with nothing but the id in the return URL.
|
|
152
|
+
*/
|
|
153
|
+
orderStatus(orderId) {
|
|
154
|
+
return this.request(`/pub/orders/${encodeURIComponent(orderId)}/status`);
|
|
155
|
+
}
|
|
123
156
|
/**
|
|
124
157
|
* Mint a one-use subscribe ticket for the next socket attempt (protocol doc
|
|
125
158
|
* §3). The bearer travels here, over ordinary HTTPS where CORS and Origin
|
|
@@ -1673,7 +1706,8 @@ var EmbeddedDesigner = class {
|
|
|
1673
1706
|
}
|
|
1674
1707
|
buildSkeleton(overlay) {
|
|
1675
1708
|
const style = document.createElement("style");
|
|
1676
|
-
style.textContent =
|
|
1709
|
+
style.textContent = /* @sl-css */
|
|
1710
|
+
`
|
|
1677
1711
|
@media (prefers-reduced-motion: no-preference) {
|
|
1678
1712
|
@keyframes seatlayer-designer-shimmer {
|
|
1679
1713
|
0% { background-position: -320px 0; }
|
|
@@ -1799,7 +1833,6 @@ import {
|
|
|
1799
1833
|
PickerController as PickerController2,
|
|
1800
1834
|
ACCESSIBILITY_TYPES,
|
|
1801
1835
|
expandChart,
|
|
1802
|
-
generateSeatPanorama,
|
|
1803
1836
|
generateSeatThumb,
|
|
1804
1837
|
loadLocale as loadLocale2,
|
|
1805
1838
|
setStringOverrides as setStringOverrides2,
|
|
@@ -1862,20 +1895,45 @@ function hasWebGL2() {
|
|
|
1862
1895
|
}
|
|
1863
1896
|
return _webgl2Cache;
|
|
1864
1897
|
}
|
|
1898
|
+
function cdnChunkUrl(fileName) {
|
|
1899
|
+
const base = SEATLAYER_MODULE_URL ?? (typeof location !== "undefined" ? location.href : void 0);
|
|
1900
|
+
if (!base) throw new Error(`seatlayer: cannot resolve the ${fileName} chunk URL`);
|
|
1901
|
+
return new URL(`./${fileName}`, base).href;
|
|
1902
|
+
}
|
|
1865
1903
|
async function loadVenue3d() {
|
|
1866
1904
|
if (typeof __SEATLAYER_CDN__ !== "undefined" && __SEATLAYER_CDN__) {
|
|
1867
|
-
const base = SEATLAYER_MODULE_URL ?? (typeof location !== "undefined" ? location.href : void 0);
|
|
1868
|
-
if (!base) throw new Error("seatlayer: cannot resolve the 3D view chunk URL");
|
|
1869
|
-
const url = new URL("./seatlayer-view3d.mjs", base).href;
|
|
1870
1905
|
return import(
|
|
1871
1906
|
/* @vite-ignore */
|
|
1872
|
-
|
|
1907
|
+
cdnChunkUrl("seatlayer-view3d.mjs")
|
|
1873
1908
|
);
|
|
1874
1909
|
}
|
|
1875
1910
|
return import("@seatlayer/core/view3d");
|
|
1876
1911
|
}
|
|
1912
|
+
async function loadPanorama() {
|
|
1913
|
+
if (typeof __SEATLAYER_CDN__ !== "undefined" && __SEATLAYER_CDN__) {
|
|
1914
|
+
return import(
|
|
1915
|
+
/* @vite-ignore */
|
|
1916
|
+
cdnChunkUrl("seatlayer-panorama.mjs")
|
|
1917
|
+
);
|
|
1918
|
+
}
|
|
1919
|
+
return import("@seatlayer/core");
|
|
1920
|
+
}
|
|
1921
|
+
async function loadHostedCheckout() {
|
|
1922
|
+
if (typeof __SEATLAYER_CDN__ !== "undefined" && __SEATLAYER_CDN__) {
|
|
1923
|
+
return import(
|
|
1924
|
+
/* @vite-ignore */
|
|
1925
|
+
cdnChunkUrl("seatlayer-checkout.mjs")
|
|
1926
|
+
);
|
|
1927
|
+
}
|
|
1928
|
+
return import("./hostedCheckout-PLHKPT6W.js");
|
|
1929
|
+
}
|
|
1930
|
+
function paymentsOffReason(reason) {
|
|
1931
|
+
return reason === "unavailable_for_event" || reason === "payments_off_for_event" ? reason : "not_configured";
|
|
1932
|
+
}
|
|
1877
1933
|
var STYLE_ID = "seatlayer-picker-style";
|
|
1878
|
-
var CSS =
|
|
1934
|
+
var CSS = (
|
|
1935
|
+
/* @sl-css */
|
|
1936
|
+
`
|
|
1879
1937
|
.sl-picker{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:420px;overflow:hidden;
|
|
1880
1938
|
background:var(--sl-bg);color:var(--sl-text);font-family:var(--sl-font);border-radius:var(--sl-radius);
|
|
1881
1939
|
--sl-r-sm:calc(var(--sl-radius) * .55);
|
|
@@ -2612,7 +2670,8 @@ var CSS = `
|
|
|
2612
2670
|
.sl-modal-scrim{position:fixed;inset:0;z-index:2147483000;background:rgba(5,7,12,.66);display:flex;align-items:center;justify-content:center;padding:18px}
|
|
2613
2671
|
.sl-modal-frame{width:min(1200px,100%);height:min(820px,100%);border-radius:16px;overflow:hidden;box-shadow:0 40px 120px -30px rgba(0,0,0,.8)}
|
|
2614
2672
|
@media(max-width:640px){.sl-modal-scrim{padding:0}.sl-modal-frame{width:100%;height:100%;border-radius:0}}
|
|
2615
|
-
|
|
2673
|
+
`
|
|
2674
|
+
);
|
|
2616
2675
|
function ensureStyle() {
|
|
2617
2676
|
if (document.getElementById(STYLE_ID)) return;
|
|
2618
2677
|
const el = document.createElement("style");
|
|
@@ -2677,6 +2736,14 @@ var SeatPicker = class _SeatPicker {
|
|
|
2677
2736
|
this.handedOff = false;
|
|
2678
2737
|
/** Guards single onBooked + single success overlay per hold. */
|
|
2679
2738
|
this.bookedShown = false;
|
|
2739
|
+
/**
|
|
2740
|
+
* In-flight or settled `payment-options` for this event, started at render in
|
|
2741
|
+
* hosted mode. One request, kicked off while the buyer is still choosing, so
|
|
2742
|
+
* pressing Pay does not wait on a lookup whose answer never changes mid-session.
|
|
2743
|
+
*/
|
|
2744
|
+
this.paymentOptions = null;
|
|
2745
|
+
/** The mounted payment card, while one is up. */
|
|
2746
|
+
this.checkoutPanel = null;
|
|
2680
2747
|
this.extendEl = null;
|
|
2681
2748
|
this.bookedEl = null;
|
|
2682
2749
|
this.gaQty = /* @__PURE__ */ new Map();
|
|
@@ -2791,6 +2858,12 @@ var SeatPicker = class _SeatPicker {
|
|
|
2791
2858
|
onObjectUnavailable: (event) => this.opts.onSelectedObjectUnavailable?.(event)
|
|
2792
2859
|
});
|
|
2793
2860
|
this.api = options.transport ?? this.pubApi;
|
|
2861
|
+
if (options.checkout === "hosted" && !this.pubApi) {
|
|
2862
|
+
console.warn(
|
|
2863
|
+
'seatlayer: checkout: "hosted" needs the widget\'s own transport \u2014 a custom `transport` owns its backend, so the picker is staying on onCheckout for this mount.'
|
|
2864
|
+
);
|
|
2865
|
+
}
|
|
2866
|
+
this.checkoutMode = options.checkout === "hosted" && this.pubApi ? "hosted" : "handoff";
|
|
2794
2867
|
this.maxTickets = Math.max(1, Math.floor(options.maxSelection ?? DEFAULT_MAX_SELECTION2));
|
|
2795
2868
|
this.cbSafe = readStoredColorblind() ?? !!options.colorblindSafe;
|
|
2796
2869
|
this.controller = new PickerController2({
|
|
@@ -3154,6 +3227,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3154
3227
|
ensureStyle();
|
|
3155
3228
|
await loadLocale2(this.opts.locale);
|
|
3156
3229
|
if (this.opts.messages) setStringOverrides2(this.opts.messages);
|
|
3230
|
+
if (this.checkoutMode === "hosted") this.paymentOptions = this.pubApi.paymentOptions(this.opts.event);
|
|
3157
3231
|
const mount = resolveContainer3(this.opts.container);
|
|
3158
3232
|
const root = document.createElement("div");
|
|
3159
3233
|
root.className = "sl-picker";
|
|
@@ -3451,8 +3525,40 @@ var SeatPicker = class _SeatPicker {
|
|
|
3451
3525
|
if (this.salesClosed) this.applySalesClosed();
|
|
3452
3526
|
this.syncPrices();
|
|
3453
3527
|
this.syncTray();
|
|
3528
|
+
this.resumeHostedOrder();
|
|
3454
3529
|
return this;
|
|
3455
3530
|
}
|
|
3531
|
+
/**
|
|
3532
|
+
* A hosted gateway returned this buyer to a page that runs the widget, with
|
|
3533
|
+
* `?order=…&status=…` in the URL. Pick the order up and finish the story.
|
|
3534
|
+
*
|
|
3535
|
+
* Only `success` resumes. `cancelled` means the buyer backed out at the
|
|
3536
|
+
* gateway and their seats are still held — the map they are looking at IS the
|
|
3537
|
+
* right screen, and opening a card to say "you cancelled" would be noise.
|
|
3538
|
+
*
|
|
3539
|
+
* The two parameters are then stripped with `replaceState`, because they are a
|
|
3540
|
+
* one-shot instruction: leaving them in place would re-open the confirmation
|
|
3541
|
+
* on every later navigation, and would carry an order id into browser history
|
|
3542
|
+
* and any Referer this page later sends. `status` is only ever removed
|
|
3543
|
+
* alongside an `order` we actually consumed, so a host page that uses a
|
|
3544
|
+
* `status` parameter of its own keeps it.
|
|
3545
|
+
*/
|
|
3546
|
+
resumeHostedOrder() {
|
|
3547
|
+
if (this.checkoutMode !== "hosted" || typeof location === "undefined") return;
|
|
3548
|
+
const params = new URLSearchParams(location.search);
|
|
3549
|
+
const orderId = params.get("order");
|
|
3550
|
+
if (!orderId) return;
|
|
3551
|
+
const status = params.get("status");
|
|
3552
|
+
params.delete("order");
|
|
3553
|
+
params.delete("status");
|
|
3554
|
+
try {
|
|
3555
|
+
const query = params.toString();
|
|
3556
|
+
history.replaceState(history.state, "", `${location.pathname}${query ? `?${query}` : ""}${location.hash}`);
|
|
3557
|
+
} catch {
|
|
3558
|
+
}
|
|
3559
|
+
if (status !== "success") return;
|
|
3560
|
+
void this.openCheckoutPanel({ kind: "resume", orderId });
|
|
3561
|
+
}
|
|
3456
3562
|
/**
|
|
3457
3563
|
* Move layout-dependent chrome between its wide dock (map regions / zoom
|
|
3458
3564
|
* column) and its narrow dock (the sheet's consolidated Filters row), and
|
|
@@ -4432,7 +4538,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4432
4538
|
this.els.map.appendChild(el);
|
|
4433
4539
|
this.confirmEl = el;
|
|
4434
4540
|
this.reanchorConfirm();
|
|
4435
|
-
el.querySelector(".sl-confirm-view")?.addEventListener("click", () => this.openSeatView(seat));
|
|
4541
|
+
el.querySelector(".sl-confirm-view")?.addEventListener("click", () => void this.openSeatView(seat));
|
|
4436
4542
|
el.querySelector(".sl-confirm-3d")?.addEventListener("click", () => {
|
|
4437
4543
|
if (this.buyerView === "venue3d") {
|
|
4438
4544
|
void this.view3dHandle?.flyToSeat(seat.id);
|
|
@@ -4503,10 +4609,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
4503
4609
|
* uploaded photo (seat.viewUrl) when present, else a panorama generated from
|
|
4504
4610
|
* the chart geometry — the stage placed at this seat's true bearing + size.
|
|
4505
4611
|
* Zero extra dependencies: an equirectangular image panned with `repeat-x`.
|
|
4612
|
+
*
|
|
4613
|
+
* Async only because the generator is a lazy chunk (see `loadPanorama`); an
|
|
4614
|
+
* organizer photo needs no generator and never waits on it. The two callers
|
|
4615
|
+
* are click handlers, so nothing observes the promise.
|
|
4506
4616
|
*/
|
|
4507
|
-
openSeatView(seat) {
|
|
4617
|
+
async openSeatView(seat) {
|
|
4508
4618
|
if (!this.root || !this.seatViewEnabled()) return;
|
|
4509
|
-
this.closeSeatView();
|
|
4510
4619
|
const doc = this.controller.doc;
|
|
4511
4620
|
const activeId = this.controller.getActiveFloorId();
|
|
4512
4621
|
const focal = seat.focalPoint ?? doc?.floors?.find((f) => f.id === activeId)?.focalPoint ?? doc?.focalPoint ?? { x: 0, y: 0 };
|
|
@@ -4518,10 +4627,19 @@ var SeatPicker = class _SeatPicker {
|
|
|
4518
4627
|
caption = t2("picker.panorama360");
|
|
4519
4628
|
real = true;
|
|
4520
4629
|
} else {
|
|
4521
|
-
|
|
4630
|
+
let pano2;
|
|
4631
|
+
try {
|
|
4632
|
+
const { generateSeatPanorama } = await loadPanorama();
|
|
4633
|
+
pano2 = generateSeatPanorama(seat, focal, this.allSeats());
|
|
4634
|
+
} catch (err) {
|
|
4635
|
+
this.opts.onError?.(err);
|
|
4636
|
+
return;
|
|
4637
|
+
}
|
|
4638
|
+
if (!this.root || !this.seatViewEnabled()) return;
|
|
4522
4639
|
panoUrl = pano2.url;
|
|
4523
4640
|
caption = t2("picker.illustrationCaption", { m: pano2.distanceM });
|
|
4524
4641
|
}
|
|
4642
|
+
this.closeSeatView();
|
|
4525
4643
|
const el = document.createElement("div");
|
|
4526
4644
|
el.className = "sl-view";
|
|
4527
4645
|
el.setAttribute("role", "dialog");
|
|
@@ -4887,7 +5005,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4887
5005
|
this.els.tray.querySelectorAll(".sl-chip .view[data-view-label]").forEach((btn) => {
|
|
4888
5006
|
btn.addEventListener("click", () => {
|
|
4889
5007
|
const seat = this.controller.seatByLabel(btn.dataset.viewLabel);
|
|
4890
|
-
if (seat) this.openSeatView(seat);
|
|
5008
|
+
if (seat) void this.openSeatView(seat);
|
|
4891
5009
|
});
|
|
4892
5010
|
});
|
|
4893
5011
|
this.els.tray.querySelectorAll(".sl-chip[data-locate]").forEach((chip) => {
|
|
@@ -5030,7 +5148,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5030
5148
|
const seats = this.hold.seats ?? committed;
|
|
5031
5149
|
this.handedOff = true;
|
|
5032
5150
|
this.setCtaPhase("checkout");
|
|
5033
|
-
this.
|
|
5151
|
+
this.checkoutHandoff(this.hold, seats);
|
|
5034
5152
|
return;
|
|
5035
5153
|
}
|
|
5036
5154
|
this.holdingLabels = new Set(committed.map((seat) => seat.label));
|
|
@@ -5059,7 +5177,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5059
5177
|
this.flashHeldSeats(hold);
|
|
5060
5178
|
this.setCtaPhase("checkout");
|
|
5061
5179
|
this.emitHoldChange();
|
|
5062
|
-
this.
|
|
5180
|
+
this.checkoutHandoff(hold, hold.seats ?? chosenSeats);
|
|
5063
5181
|
} catch (err) {
|
|
5064
5182
|
this.opts.onError?.(err);
|
|
5065
5183
|
const problem = err;
|
|
@@ -5164,6 +5282,109 @@ var SeatPicker = class _SeatPicker {
|
|
|
5164
5282
|
this.bookedEl?.classList.add("on");
|
|
5165
5283
|
this.opts.onBooked?.(handoff);
|
|
5166
5284
|
}
|
|
5285
|
+
/**
|
|
5286
|
+
* The seats are held. Send the buyer wherever this picker's `checkout` option
|
|
5287
|
+
* says they go.
|
|
5288
|
+
*
|
|
5289
|
+
* The default branch is the literal call that stood here before hosted
|
|
5290
|
+
* checkout existed, unchanged, so nothing about an existing integration moves.
|
|
5291
|
+
*/
|
|
5292
|
+
checkoutHandoff(hold, seats) {
|
|
5293
|
+
if (this.checkoutMode === "hosted") {
|
|
5294
|
+
void this.startHostedCheckout(hold, seats);
|
|
5295
|
+
return;
|
|
5296
|
+
}
|
|
5297
|
+
this.opts.onCheckout?.(hold, seats, this.buildHandoff(hold));
|
|
5298
|
+
}
|
|
5299
|
+
/**
|
|
5300
|
+
* Take the money ourselves, through the organizer's own gateway.
|
|
5301
|
+
*
|
|
5302
|
+
* Order of operations matters: ASK FIRST, load second. `payment-options` is
|
|
5303
|
+
* already in flight from render, and its answer decides whether any payment
|
|
5304
|
+
* code is fetched at all — an event that cannot charge never downloads the
|
|
5305
|
+
* card that would have charged it.
|
|
5306
|
+
*
|
|
5307
|
+
* An empty list is not a failure and never dead-ends the buyer. It routes them
|
|
5308
|
+
* to whatever the host has: `onCheckoutUnavailable` (with the server's reason,
|
|
5309
|
+
* so the host can say the right one of three very different sentences), then
|
|
5310
|
+
* `onCheckout` with the ordinary handoff. A host that supplied neither gets
|
|
5311
|
+
* the widget's own honest card instead of a press that did nothing.
|
|
5312
|
+
*/
|
|
5313
|
+
async startHostedCheckout(hold, seats) {
|
|
5314
|
+
const handoff = this.buildHandoff(hold);
|
|
5315
|
+
let options = null;
|
|
5316
|
+
try {
|
|
5317
|
+
options = await (this.paymentOptions ??= this.pubApi.paymentOptions(this.opts.event));
|
|
5318
|
+
} catch (err) {
|
|
5319
|
+
this.opts.onError?.(err);
|
|
5320
|
+
}
|
|
5321
|
+
if (this.destroyed) return;
|
|
5322
|
+
const provider = options?.providers?.[0];
|
|
5323
|
+
if (!provider) {
|
|
5324
|
+
const reason = paymentsOffReason(options?.reason);
|
|
5325
|
+
const handled = !!this.opts.onCheckoutUnavailable || !!this.opts.onCheckout;
|
|
5326
|
+
this.opts.onCheckoutUnavailable?.({ reason, handoff });
|
|
5327
|
+
this.opts.onCheckout?.(hold, seats, handoff);
|
|
5328
|
+
if (!handled) {
|
|
5329
|
+
void this.openCheckoutPanel({
|
|
5330
|
+
kind: "unavailable",
|
|
5331
|
+
reason,
|
|
5332
|
+
seatCount: handoff.lineItems.reduce((sum, item) => sum + item.quantity, 0)
|
|
5333
|
+
});
|
|
5334
|
+
}
|
|
5335
|
+
return;
|
|
5336
|
+
}
|
|
5337
|
+
await this.openCheckoutPanel({
|
|
5338
|
+
kind: "pay",
|
|
5339
|
+
provider,
|
|
5340
|
+
order: {
|
|
5341
|
+
holdId: handoff.holdId,
|
|
5342
|
+
expiresAt: handoff.expiresAt,
|
|
5343
|
+
currency: handoff.currency,
|
|
5344
|
+
total: handoff.total,
|
|
5345
|
+
labels: handoff.lineItems.map((item) => item.displayLabel ?? item.label)
|
|
5346
|
+
}
|
|
5347
|
+
});
|
|
5348
|
+
}
|
|
5349
|
+
/**
|
|
5350
|
+
* Fetch the checkout chunk and put its card over the map.
|
|
5351
|
+
*
|
|
5352
|
+
* Every failure here lands the buyer back on a map with their seats still
|
|
5353
|
+
* held, which is a place they can act from — a blocked chunk request must not
|
|
5354
|
+
* leave them staring at a CTA that no longer does anything.
|
|
5355
|
+
*/
|
|
5356
|
+
async openCheckoutPanel(state) {
|
|
5357
|
+
let mountCheckout;
|
|
5358
|
+
try {
|
|
5359
|
+
({ mountCheckout } = await loadHostedCheckout());
|
|
5360
|
+
} catch (err) {
|
|
5361
|
+
this.opts.onError?.(err);
|
|
5362
|
+
this.toast("Checkout could not be opened. Your seats are still held \u2014 please try again.", "error");
|
|
5363
|
+
this.setCtaPhase("idle");
|
|
5364
|
+
return;
|
|
5365
|
+
}
|
|
5366
|
+
if (this.destroyed || !this.root) return;
|
|
5367
|
+
this.closeCheckoutPanel();
|
|
5368
|
+
this.checkoutPanel = mountCheckout({
|
|
5369
|
+
root: this.root,
|
|
5370
|
+
state,
|
|
5371
|
+
startSession: (input) => this.pubApi.startCheckout(this.opts.event, input),
|
|
5372
|
+
orderStatus: (orderId) => this.pubApi.orderStatus(orderId),
|
|
5373
|
+
onCancel: () => {
|
|
5374
|
+
this.checkoutPanel = null;
|
|
5375
|
+
if (!this.hold) this.setCtaPhase("idle");
|
|
5376
|
+
},
|
|
5377
|
+
onConfirmed: (order) => {
|
|
5378
|
+
this.opts.onOrderConfirmed?.(order);
|
|
5379
|
+
void this.controller.refresh();
|
|
5380
|
+
},
|
|
5381
|
+
onError: (err) => this.opts.onError?.(err)
|
|
5382
|
+
});
|
|
5383
|
+
}
|
|
5384
|
+
closeCheckoutPanel() {
|
|
5385
|
+
this.checkoutPanel?.destroy();
|
|
5386
|
+
this.checkoutPanel = null;
|
|
5387
|
+
}
|
|
5167
5388
|
/** Assemble the stable {@link CheckoutHandoff} from a hold's server line items. */
|
|
5168
5389
|
buildHandoff(hold) {
|
|
5169
5390
|
const items = hold.items ?? [];
|
|
@@ -5398,7 +5619,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5398
5619
|
}
|
|
5399
5620
|
/** Build the view-from-seat panorama the cinematic dissolves into — reuses the
|
|
5400
5621
|
* exact input path as the 2D `openSeatView` (organizer photo, else generated). */
|
|
5401
|
-
seatViewFor3d(seatId) {
|
|
5622
|
+
async seatViewFor3d(seatId) {
|
|
5402
5623
|
const seat = this.allSeats().find((s) => s.id === seatId);
|
|
5403
5624
|
if (!seat) return null;
|
|
5404
5625
|
if (seat.viewUrl) return { url: seat.viewUrl };
|
|
@@ -5407,6 +5628,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5407
5628
|
const activeId = this.controller.getActiveFloorId();
|
|
5408
5629
|
const focal = seat.focalPoint ?? doc.floors?.find((f) => f.id === activeId)?.focalPoint ?? doc.focalPoint ?? { x: 0, y: 0 };
|
|
5409
5630
|
try {
|
|
5631
|
+
const { generateSeatPanorama } = await loadPanorama();
|
|
5410
5632
|
return { url: generateSeatPanorama(seat, focal, this.allSeats()).url };
|
|
5411
5633
|
} catch {
|
|
5412
5634
|
return null;
|
|
@@ -5546,9 +5768,10 @@ var SeatPicker = class _SeatPicker {
|
|
|
5546
5768
|
// in orbit instead of dissolving into an empty overlay.
|
|
5547
5769
|
getSeatView: (id) => new Promise((resolve, reject) => {
|
|
5548
5770
|
const run = () => {
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5771
|
+
void this.seatViewFor3d(id).then((view) => {
|
|
5772
|
+
if (view) resolve(view);
|
|
5773
|
+
else reject(new Error("seat_view_unavailable"));
|
|
5774
|
+
});
|
|
5552
5775
|
};
|
|
5553
5776
|
const ric = globalThis.requestIdleCallback;
|
|
5554
5777
|
if (typeof ric === "function") ric(run, { timeout: 1500 });
|
|
@@ -5826,6 +6049,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5826
6049
|
this.closeConfirm();
|
|
5827
6050
|
this.dismissTableDialog(false);
|
|
5828
6051
|
this.closeSeatView();
|
|
6052
|
+
this.closeCheckoutPanel();
|
|
5829
6053
|
this.exit3d();
|
|
5830
6054
|
this.stopHoldTimer();
|
|
5831
6055
|
if (this.toastTimer) clearTimeout(this.toastTimer);
|
|
@@ -6552,7 +6776,9 @@ var PREVIEW_ELIGIBLE_STROKE = "#b9c0ff";
|
|
|
6552
6776
|
var PREVIEW_UNAVAILABLE_FILL = "#303846";
|
|
6553
6777
|
var PREVIEW_UNAVAILABLE_STROKE = "#4b5669";
|
|
6554
6778
|
var ALLOCATION_STROKE = "#101723";
|
|
6555
|
-
var CHANNELS_CSS =
|
|
6779
|
+
var CHANNELS_CSS = (
|
|
6780
|
+
/* @sl-css */
|
|
6781
|
+
`
|
|
6556
6782
|
.slm{--slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;--slm-mo-ambient:2000ms;
|
|
6557
6783
|
--slm-mo-out:cubic-bezier(.2,.8,.2,1);--slm-mo-in-out:cubic-bezier(.4,0,.2,1);--slm-mo-exit:cubic-bezier(.4,0,1,1);
|
|
6558
6784
|
--slm-mo-spring:cubic-bezier(.34,1.3,.64,1)}
|
|
@@ -6741,7 +6967,8 @@ var CHANNELS_CSS = `
|
|
|
6741
6967
|
.slm-ch-staged.shake{outline:2px solid #e5484d;outline-offset:2px}
|
|
6742
6968
|
.slm-ch-staged.done{outline:2px solid #5bd39b;outline-offset:2px}
|
|
6743
6969
|
}
|
|
6744
|
-
|
|
6970
|
+
`
|
|
6971
|
+
);
|
|
6745
6972
|
function bucketRowsHtml(rows) {
|
|
6746
6973
|
return rows.map((row, index) => `
|
|
6747
6974
|
<div class="slm-ch-bucket" style="animation-delay:${Math.min(index, 4) * 30}ms">
|
|
@@ -8639,7 +8866,9 @@ var LEGEND = [
|
|
|
8639
8866
|
{ key: "booked", label: "Booked", color: "#22a06b" },
|
|
8640
8867
|
{ key: "blocked", label: "Blocked", color: "#8b94ac" }
|
|
8641
8868
|
];
|
|
8642
|
-
var MANAGER_CSS =
|
|
8869
|
+
var MANAGER_CSS = (
|
|
8870
|
+
/* @sl-css */
|
|
8871
|
+
`
|
|
8643
8872
|
.slm{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:480px;overflow:hidden;
|
|
8644
8873
|
background:var(--slm-bg);color:var(--slm-text);font-family:var(--slm-font);border-radius:var(--slm-radius);
|
|
8645
8874
|
/* Motion tokens (motion-system \xA72), declared by the cockpit ROOT rather than
|
|
@@ -8881,7 +9110,8 @@ var MANAGER_CSS = `
|
|
|
8881
9110
|
transition:none!important;
|
|
8882
9111
|
scroll-behavior:auto!important}
|
|
8883
9112
|
}
|
|
8884
|
-
${CHANNELS_CSS}
|
|
9113
|
+
${CHANNELS_CSS}`
|
|
9114
|
+
);
|
|
8885
9115
|
function injectStyle() {
|
|
8886
9116
|
if (typeof document === "undefined" || document.getElementById(STYLE_ID2)) return;
|
|
8887
9117
|
const el = document.createElement("style");
|