@seatlayer/js 0.50.1 → 0.51.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/dist/index.cjs +371 -251
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +371 -251
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2248,6 +2248,10 @@ var DEFAULT_MAX_SELECTION2 = 10;
|
|
|
2248
2248
|
var EXTEND_PROMPT_MS = 6e4;
|
|
2249
2249
|
var MAX_3D_SEATS_DEFAULT = 6e4;
|
|
2250
2250
|
var MAX_3D_SECTION_PILLS = 12;
|
|
2251
|
+
function tfStatic(key, fallback) {
|
|
2252
|
+
const v = t2(key);
|
|
2253
|
+
return v === key ? fallback : v;
|
|
2254
|
+
}
|
|
2251
2255
|
function pointInPolygon(x, y, poly) {
|
|
2252
2256
|
let inside = false;
|
|
2253
2257
|
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
@@ -2422,11 +2426,30 @@ var CSS = (
|
|
|
2422
2426
|
.sl-picker[data-layout="narrow"] .sl-map{min-height:0;flex:1}
|
|
2423
2427
|
.sl-picker[data-layout="narrow"] .sl-side{width:100%;border-left:0;border-top:1px solid var(--sl-line);
|
|
2424
2428
|
flex:none;height:min(72%,480px);overflow:hidden;transition:height .3s cubic-bezier(.2,.8,.2,1);overscroll-behavior:contain}
|
|
2425
|
-
.sl-picker[data-layout="narrow"][data-sheet="open"][data-has-selection="false"] .sl-side{height:min(
|
|
2429
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"][data-has-selection="false"] .sl-side{height:min(380px,64%)}
|
|
2430
|
+
/* With the price list expanded the sheet takes the with-selection height so
|
|
2431
|
+
the tray (cart + best-seats) is never crushed under the fixed-size list. */
|
|
2432
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-side{height:min(480px,74%)}
|
|
2426
2433
|
.sl-picker[data-layout="narrow"][data-sheet="peek"] .sl-side{height:76px;overflow:hidden}
|
|
2427
2434
|
.sl-picker[data-layout="narrow"][data-sheet="peek"] .sl-side > :not(.sl-sheet-head){display:none}
|
|
2428
|
-
.sl-picker[data-layout="narrow"] .sl-tray{flex:1;min-height:
|
|
2435
|
+
.sl-picker[data-layout="narrow"] .sl-tray{flex:1;min-height:96px;overflow-y:auto;overscroll-behavior:contain}
|
|
2436
|
+
.sl-picker[data-layout="narrow"][data-prices-open="true"] .sl-tray{min-height:48px}
|
|
2437
|
+
.sl-picker[data-layout="narrow"] .sl-prices{max-height:150px;overflow-y:auto;overscroll-behavior:contain}
|
|
2429
2438
|
.sl-picker[data-layout="narrow"] .sl-foot{position:static;background:var(--sl-bg)}
|
|
2439
|
+
/* NARROW FOOT SAYS EVERYTHING ONCE (owner report: with a hold the footer ate
|
|
2440
|
+
~190px and the ticket list got a sliver). The sheet head already carries
|
|
2441
|
+
"N tickets \xB7 $total" and the header pill already ticks the clock \u2014 so the
|
|
2442
|
+
total row hides, the secured note collapses to one compact line, and the
|
|
2443
|
+
badge tucks in. The tray gets the pixels; a thin scrollbar shows there is
|
|
2444
|
+
more to scroll. */
|
|
2445
|
+
.sl-picker[data-layout="narrow"] .sl-total{display:none}
|
|
2446
|
+
.sl-picker[data-layout="narrow"] .sl-foot{padding:8px 12px 8px}
|
|
2447
|
+
.sl-picker[data-layout="narrow"] .sl-hold-note{margin-bottom:6px;padding:5px 9px}
|
|
2448
|
+
.sl-picker[data-layout="narrow"] .sl-hold-note svg{display:none}
|
|
2449
|
+
.sl-picker[data-layout="narrow"] .sl-hold-note b{display:inline;margin-right:6px;font-size:11px}
|
|
2450
|
+
.sl-picker[data-layout="narrow"] .sl-hold-copy{display:inline;white-space:normal;font-size:10.5px}
|
|
2451
|
+
.sl-picker[data-layout="narrow"] .sl-powered{margin-top:4px;padding:2px 8px;font-size:11px}
|
|
2452
|
+
.sl-picker[data-layout="narrow"] .sl-tray{scrollbar-width:thin}
|
|
2430
2453
|
.sl-picker[data-layout="narrow"] .sl-foot.empty{display:none}
|
|
2431
2454
|
.sl-picker[data-layout="narrow"] .sl-sheet-head{order:0}
|
|
2432
2455
|
.sl-picker[data-layout="narrow"] .sl-seats-sec{display:none}
|
|
@@ -2434,6 +2457,7 @@ var CSS = (
|
|
|
2434
2457
|
.sl-picker[data-layout="narrow"] .sl-filtersec{order:3}
|
|
2435
2458
|
.sl-picker[data-layout="narrow"] .sl-filters{order:4}
|
|
2436
2459
|
.sl-picker[data-layout="narrow"] .sl-prices-sec{order:5}
|
|
2460
|
+
.sl-picker[data-layout="narrow"] .sl-prices-hint{order:6}
|
|
2437
2461
|
.sl-picker[data-layout="narrow"] .sl-pricef{order:6}
|
|
2438
2462
|
.sl-picker[data-layout="narrow"] .sl-prices{order:7}
|
|
2439
2463
|
.sl-picker[data-layout="narrow"] .sl-foot{order:8}
|
|
@@ -2441,6 +2465,7 @@ var CSS = (
|
|
|
2441
2465
|
.sl-picker[data-layout="narrow"] .sl-filtersec,
|
|
2442
2466
|
.sl-picker[data-layout="narrow"] .sl-filters,
|
|
2443
2467
|
.sl-picker[data-layout="narrow"] .sl-prices-sec,
|
|
2468
|
+
.sl-picker[data-layout="narrow"] .sl-prices-hint,
|
|
2444
2469
|
.sl-picker[data-layout="narrow"] .sl-prices{display:none!important}
|
|
2445
2470
|
.sl-picker[data-layout="narrow"][data-has-selection="true"] .sl-filtersec,
|
|
2446
2471
|
.sl-picker[data-layout="narrow"][data-has-selection="true"] .sl-filters,
|
|
@@ -2458,7 +2483,13 @@ var CSS = (
|
|
|
2458
2483
|
head is the tap/swipe toggle target (min 44px), so it reads as one control. */
|
|
2459
2484
|
.sl-sheet-head{display:none;flex-direction:column;justify-content:center;padding:6px 12px 8px;min-height:56px;
|
|
2460
2485
|
cursor:pointer;touch-action:none;user-select:none;-webkit-user-select:none;flex:none}
|
|
2461
|
-
.sl-picker[data-layout="narrow"] .sl-sheet-head{display:flex;min-height:
|
|
2486
|
+
.sl-picker[data-layout="narrow"] .sl-sheet-head{display:flex;min-height:52px;padding:3px 10px 5px}
|
|
2487
|
+
/* OPEN sheet: the head is context, not controls \u2014 the pill it carries at peek
|
|
2488
|
+
("Best seats"/"Continue") duplicates the card and CTA right below it, and
|
|
2489
|
+
every saved pixel is tray room (owner call 2026-08-14). */
|
|
2490
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"] .sl-sheet-head{min-height:42px}
|
|
2491
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"] .sl-sheet-bar{min-height:32px}
|
|
2492
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"] .sl-sheet-peek .go{display:none}
|
|
2462
2493
|
.sl-picker[data-layout="narrow"][data-sheet="peek"] .sl-sheet-head{height:100%}
|
|
2463
2494
|
.sl-sheet-grab{width:36px;height:4px;border-radius:999px;background:var(--sl-muted);opacity:.55;margin:1px auto 5px}
|
|
2464
2495
|
.sl-sheet-bar{display:flex;align-items:center;gap:8px;min-height:44px}
|
|
@@ -2499,9 +2530,19 @@ var CSS = (
|
|
|
2499
2530
|
sheet brings it back, exactly like the filters row above. The tray hint comes
|
|
2500
2531
|
back with it: the first-time buyer on a phone needs the instruction more than
|
|
2501
2532
|
the desktop buyer, not less. */
|
|
2502
|
-
.sl-picker[data-layout="narrow"][data-sheet="open"] .sl-prices-sec{display:flex!important}
|
|
2503
|
-
|
|
2533
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-prices-sec{display:flex!important}
|
|
2534
|
+
/* MOBILE SPACE BELONGS TO THE CART (owner call 2026-08-14): the price list is
|
|
2535
|
+
one tap away behind the "Ticket prices" row, not a permanent tenant. Zone
|
|
2536
|
+
flags and section taps already answer "what does it cost" in context. */
|
|
2537
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-prices-hint{display:block!important}
|
|
2538
|
+
.sl-picker[data-layout="narrow"][data-sheet="open"][data-prices-open="true"] .sl-prices{display:flex!important}
|
|
2504
2539
|
.sl-picker[data-layout="narrow"][data-sheet="open"] .sl-tray-hint{display:block!important}
|
|
2540
|
+
/* The row reads as the toggle it is on narrow: chevron + pointer. */
|
|
2541
|
+
.sl-picker[data-layout="narrow"] .sl-prices-sec{cursor:pointer}
|
|
2542
|
+
.sl-picker[data-layout="narrow"] .sl-prices-sec::after{content:'';width:8px;height:8px;flex:none;margin-left:auto;
|
|
2543
|
+
border-right:2px solid var(--sl-muted);border-bottom:2px solid var(--sl-muted);
|
|
2544
|
+
transform:rotate(45deg);transition:transform .2s cubic-bezier(.2,.8,.2,1)}
|
|
2545
|
+
.sl-picker[data-layout="narrow"][data-prices-open="true"] .sl-prices-sec::after{transform:rotate(-135deg)}
|
|
2505
2546
|
.sl-cbbtn{width:32px;height:32px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);
|
|
2506
2547
|
color:var(--sl-text);display:flex;align-items:center;justify-content:center;transition:border-color .15s}
|
|
2507
2548
|
.sl-cbbtn:hover{border-color:var(--sl-muted)}
|
|
@@ -2520,7 +2561,13 @@ var CSS = (
|
|
|
2520
2561
|
.sl-sec{padding:14px 14px 4px;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:700}
|
|
2521
2562
|
.sl-prices-sec{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:13px}
|
|
2522
2563
|
.sl-price-select{min-height:32px;max-width:130px;padding:5px 28px 5px 9px;border:1px solid var(--sl-line);border-radius:9px;
|
|
2523
|
-
background:var(--sl-surface);color:var(--sl-text);font:inherit;font-size:11px;font-weight:750;letter-spacing:0;text-transform:none}
|
|
2564
|
+
background-color:var(--sl-surface);color:var(--sl-text);font:inherit;font-size:11px;font-weight:750;letter-spacing:0;text-transform:none}
|
|
2565
|
+
/* One sentence that teaches the whole colour code \u2014 a first-time buyer sees
|
|
2566
|
+
"Head Tables \xB7 $165" and coloured dots with nothing connecting them. Gone
|
|
2567
|
+
the moment they have seats (they've learned it) and while sales are closed. */
|
|
2568
|
+
.sl-prices-hint{padding:0 14px 7px;font-size:11px;line-height:1.45;color:var(--sl-muted)}
|
|
2569
|
+
.sl-picker[data-has-selection="true"] .sl-prices-hint,
|
|
2570
|
+
.sl-picker[data-sales-closed="true"] .sl-prices-hint{display:none}
|
|
2524
2571
|
.sl-prices{display:flex;flex-direction:column;padding:4px 14px 8px;border-bottom:1px solid var(--sl-line)}
|
|
2525
2572
|
.sl-prices-sec,.sl-prices,.sl-seats-sec{flex:none}
|
|
2526
2573
|
.sl-price-row{display:flex;align-items:center;gap:7px;min-height:28px;font-size:12px;
|
|
@@ -2680,11 +2727,11 @@ var CSS = (
|
|
|
2680
2727
|
color:var(--sl-text);font-size:17px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}
|
|
2681
2728
|
.sl-zoom button:hover{border-color:var(--sl-muted)}
|
|
2682
2729
|
.sl-zoom svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
2683
|
-
/* Full-screen promotion
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
region beside Map|3D
|
|
2687
|
-
|
|
2730
|
+
/* Full-screen promotion: the capability existed (native + iOS overlay +
|
|
2731
|
+
framed-host paths) but hid as the 4th unlabelled glyph in a corner stack \u2014
|
|
2732
|
+
even the owner could not pick it out. dockLayoutChrome docks the SAME
|
|
2733
|
+
button into the top-right region beside Map|3D on EVERY layout and this
|
|
2734
|
+
class dresses it as a labelled pill. */
|
|
2688
2735
|
.sl-zfs-lbl{display:none}
|
|
2689
2736
|
.sl-fs-pill.sl-fs-pill{display:inline-flex;align-items:center;justify-content:center;width:auto;min-height:40px;height:auto;
|
|
2690
2737
|
padding:0 13px;gap:6px;border-radius:999px;font-size:11px;font-weight:800;
|
|
@@ -2692,6 +2739,16 @@ var CSS = (
|
|
|
2692
2739
|
.sl-fs-pill.sl-fs-pill:hover{border-color:var(--sl-muted)}
|
|
2693
2740
|
.sl-fs-pill svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
2694
2741
|
.sl-fs-pill .sl-zfs-lbl{display:inline;letter-spacing:.02em;white-space:nowrap}
|
|
2742
|
+
/* In the header, icons carry it (owner call): square Full screen glyph, and
|
|
2743
|
+
on narrow a price-tag toggle that opens the sheet with the list expanded. */
|
|
2744
|
+
.sl-head .sl-fs-pill{min-height:34px;min-width:34px;width:34px;padding:0;flex:none}
|
|
2745
|
+
.sl-head .sl-fs-pill .sl-zfs-lbl{display:none}
|
|
2746
|
+
.sl-prices-btn{display:none;align-items:center;justify-content:center;width:34px;min-height:34px;flex:none;
|
|
2747
|
+
border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);transition:border-color .15s}
|
|
2748
|
+
.sl-prices-btn:hover{border-color:var(--sl-muted)}
|
|
2749
|
+
.sl-prices-btn svg{width:15px;height:15px;stroke:currentColor;stroke-width:1.8;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
2750
|
+
.sl-prices-btn[aria-pressed="true"]{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}
|
|
2751
|
+
.sl-picker[data-layout="narrow"] .sl-prices-btn{display:inline-flex}
|
|
2695
2752
|
|
|
2696
2753
|
/* toast + boot states (toast flows in the bottom-center region) */
|
|
2697
2754
|
.sl-toast{transform:translateY(6px) scale(.98);max-width:100%;
|
|
@@ -2819,8 +2876,21 @@ var CSS = (
|
|
|
2819
2876
|
.sl-confirm-add svg{width:16px;height:16px;stroke:currentColor;stroke-width:2.8;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
2820
2877
|
.sl-confirm-cancel{background:color-mix(in srgb,var(--sl-line) 44%,transparent)!important;border:1px solid var(--sl-line)!important;color:var(--sl-muted)!important}
|
|
2821
2878
|
.sl-confirm-cancel:hover{color:var(--sl-text)}
|
|
2822
|
-
.sl-picker[data-layout="narrow"] .sl-confirm{left:50%!important;top:auto!important;bottom:14px;width:min(
|
|
2879
|
+
.sl-picker[data-layout="narrow"] .sl-confirm{left:50%!important;top:auto!important;bottom:14px;width:min(310px,calc(100% - 24px));
|
|
2823
2880
|
transform:translateX(-50%);animation:slConfirmMobileIn .24s cubic-bezier(.2,.8,.2,1) both}
|
|
2881
|
+
/* Phone-size confirm card (owner call 2026-08-14): same content \u2014 identity,
|
|
2882
|
+
price band, view photo, 3D link \u2014 on a tighter grid. The values stay large
|
|
2883
|
+
enough to double-check against the map; buttons keep tap-size. */
|
|
2884
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-field{padding:9px 9px 8px}
|
|
2885
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-value{font-size:15px}
|
|
2886
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-cat{padding:8px 10px}
|
|
2887
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-cat-name{font-size:12.5px}
|
|
2888
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-price{font-size:15px}
|
|
2889
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-body{padding:9px 10px 10px}
|
|
2890
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-thumbwrap{height:62px;margin-bottom:6px}
|
|
2891
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-3d{margin-top:7px;padding:6px}
|
|
2892
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-row{margin-top:8px}
|
|
2893
|
+
.sl-picker[data-layout="narrow"] .sl-confirm-row button{min-height:42px}
|
|
2824
2894
|
|
|
2825
2895
|
/* Atomic whole/variable-table chooser. Lives inside the widget so the same
|
|
2826
2896
|
accessible dialog works in inline, modal, desktop and 390px mobile hosts. */
|
|
@@ -2896,8 +2966,11 @@ var CSS = (
|
|
|
2896
2966
|
.sl-ba-premium.on{color:var(--sl-premium-ink);background:linear-gradient(135deg,#f0cf6b,#e0b23f);border-color:transparent;
|
|
2897
2967
|
box-shadow:0 6px 16px color-mix(in srgb,var(--sl-premium) 26%,transparent)}
|
|
2898
2968
|
.sl-ba-premium.on .star{color:#5a4410}
|
|
2899
|
-
.sl-ba select
|
|
2900
|
-
|
|
2969
|
+
.sl-ba select,.sl-price-select{appearance:none;-webkit-appearance:none;
|
|
2970
|
+
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23949ca9' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
2971
|
+
background-repeat:no-repeat;background-position:right 10px center}
|
|
2972
|
+
.sl-ba select{background-color:var(--sl-surface);color:var(--sl-text);border:1px solid var(--sl-line);border-radius:8px;
|
|
2973
|
+
font:inherit;font-size:11px;padding:7px 26px 7px 8px;min-width:0;width:100%;max-width:none}
|
|
2901
2974
|
.sl-ba-qty{display:flex;align-items:center;gap:7px;padding:3px;border:1px solid var(--sl-line);border-radius:9px;background:var(--sl-surface)}
|
|
2902
2975
|
.sl-ba-qty button{width:25px;height:25px;border-radius:7px;background:color-mix(in srgb,var(--sl-line) 35%,transparent);border:0;
|
|
2903
2976
|
font-size:14px;font-weight:800;display:flex;align-items:center;justify-content:center}
|
|
@@ -2927,9 +3000,23 @@ var CSS = (
|
|
|
2927
3000
|
.sl-picker[data-layout="narrow"] .sl-ba-copy{display:none}
|
|
2928
3001
|
.sl-picker[data-layout="narrow"] .sl-ba-copy .wide{display:none}
|
|
2929
3002
|
.sl-picker[data-layout="narrow"] .sl-ba-copy .narrow{display:inline}
|
|
2930
|
-
.sl-picker[data-layout="narrow"] .sl-ba
|
|
3003
|
+
.sl-picker[data-layout="narrow"] .sl-ba{grid-template-columns:auto minmax(0,1fr)}
|
|
3004
|
+
.sl-picker[data-layout="narrow"] .sl-ba select{grid-column:1/-1;min-height:38px}
|
|
2931
3005
|
.sl-picker[data-layout="narrow"] .sl-ba-qty button{width:30px;height:30px}
|
|
2932
|
-
|
|
3006
|
+
/* Quantity and Go share ONE row: a full-width row holding only "\u2212 2 +" was
|
|
3007
|
+
dead space, and the Find button still gets the lion's share. */
|
|
3008
|
+
.sl-picker[data-layout="narrow"] .sl-ba-qty{grid-column:1}
|
|
3009
|
+
.sl-picker[data-layout="narrow"] .sl-ba-go{grid-column:2;min-height:40px}
|
|
3010
|
+
/* Re-entry to best-available once the cart has seats (the card yields its
|
|
3011
|
+
space to chips, but the accelerator must stay reachable) + the quiet way
|
|
3012
|
+
back out of a reopened card. */
|
|
3013
|
+
.sl-ba-reopen{align-self:flex-start;display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:5px 12px;margin-top:2px;
|
|
3014
|
+
border:1px dashed color-mix(in srgb,var(--sl-accent) 40%,var(--sl-line));border-radius:999px;
|
|
3015
|
+
color:var(--sl-accent);font-size:11.5px;font-weight:750;transition:border-color .15s,background .15s}
|
|
3016
|
+
.sl-ba-reopen:hover,.sl-ba-reopen:focus-visible{background:color-mix(in srgb,var(--sl-accent) 8%,transparent)}
|
|
3017
|
+
.sl-ba-back{grid-column:1/-1;justify-self:start;min-height:30px;padding:3px 0;color:var(--sl-muted);
|
|
3018
|
+
font-size:11px;font-weight:700;text-decoration:underline;text-underline-offset:3px;transition:color .15s}
|
|
3019
|
+
.sl-ba-back:hover,.sl-ba-back:focus-visible{color:var(--sl-text)}
|
|
2933
3020
|
|
|
2934
3021
|
/* Sales-closed is a designed state, not a set of disables: one statement in
|
|
2935
3022
|
the tray where the buying flow was, carrying the event's own date so the
|
|
@@ -2948,9 +3035,9 @@ var CSS = (
|
|
|
2948
3035
|
(the cart chip's remove/view rail) instead get real height on narrow. */
|
|
2949
3036
|
@media (pointer:coarse){
|
|
2950
3037
|
.sl-zoom button,.sl-cbbtn,.sl-close,.sl-ga-qty button,.sl-ba-qty button,.sl-price-more,
|
|
2951
|
-
.sl-hold-change,.sl-seccard-x,.sl-fs-pill,.sl-side-toggle{position:relative}
|
|
3038
|
+
.sl-hold-change,.sl-seccard-x,.sl-fs-pill,.sl-side-toggle,.sl-ba-reopen{position:relative}
|
|
2952
3039
|
.sl-zoom button::after,.sl-cbbtn::after,.sl-close::after,.sl-ga-qty button::after,.sl-ba-qty button::after,
|
|
2953
|
-
.sl-price-more::after,.sl-hold-change::after,.sl-seccard-x::after,.sl-fs-pill::after,.sl-side-toggle::after{
|
|
3040
|
+
.sl-price-more::after,.sl-hold-change::after,.sl-seccard-x::after,.sl-fs-pill::after,.sl-side-toggle::after,.sl-ba-reopen::after{
|
|
2954
3041
|
content:'';position:absolute;top:50%;left:50%;width:max(100%,44px);height:max(100%,44px);
|
|
2955
3042
|
transform:translate(-50%,-50%)}
|
|
2956
3043
|
/* The chip rail stacks remove over view in ~53px \u2014 pseudo-targets would
|
|
@@ -3053,12 +3140,6 @@ var CSS = (
|
|
|
3053
3140
|
border-radius:999px;font:700 11.5px/1 inherit;color:#eef1f8;background:rgba(12,18,32,.86);
|
|
3054
3141
|
border:1px solid rgba(150,165,205,.45);backdrop-filter:blur(6px);cursor:pointer}
|
|
3055
3142
|
.sl-view3d-nav select:focus-visible{outline:2px solid var(--sl-accent);outline-offset:2px}
|
|
3056
|
-
.sl-view3d-nav .sl-view3d-locator{display:grid;grid-template-columns:minmax(150px,1.25fr) minmax(110px,.8fr) minmax(105px,.7fr) auto;
|
|
3057
|
-
width:min(720px,100%);overflow:visible}
|
|
3058
|
-
.sl-view3d-nav.is-seat-focused .sl-view3d-locator{display:none}
|
|
3059
|
-
.sl-view3d-locator select{width:100%;min-width:0}
|
|
3060
|
-
.sl-picker[data-layout="narrow"] .sl-view3d-nav .sl-view3d-locator{display:flex;width:100%;overflow-x:auto}
|
|
3061
|
-
.sl-picker[data-layout="narrow"] .sl-view3d-locator select{flex:0 0 155px}
|
|
3062
3143
|
/* On phones the library owns the bottom edge for seat/panorama/overview actions.
|
|
3063
3144
|
Keep venue navigation in a separate top rail so those control families never
|
|
3064
3145
|
stack over one another. */
|
|
@@ -3068,9 +3149,6 @@ var CSS = (
|
|
|
3068
3149
|
.sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open{left:12px;top:68px;max-width:calc(100% - 24px);padding:8px;
|
|
3069
3150
|
border:1px solid rgba(150,165,205,.35);border-radius:14px;background:rgba(8,12,22,.9);backdrop-filter:blur(10px)}
|
|
3070
3151
|
.sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open>div{display:flex}
|
|
3071
|
-
.sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open .sl-view3d-locator{display:grid;grid-template-columns:1fr 1fr;width:100%;overflow:visible}
|
|
3072
|
-
.sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open .sl-view3d-locator select{width:100%;min-width:0;flex:auto}
|
|
3073
|
-
.sl-picker[data-layout="narrow"] .sl-view3d-nav.is-open .sl-view3d-locator button{width:100%}
|
|
3074
3152
|
/* Seat-eye is a decision state, not another venue-navigation state. Once the
|
|
3075
3153
|
buyer arrives, clear the floor/area/locator rails and the module's duplicate
|
|
3076
3154
|
Overview action. The picker-owned Back button becomes the one predictable
|
|
@@ -3496,6 +3574,15 @@ var SeatPicker = class _SeatPicker {
|
|
|
3496
3574
|
this.baZone = "";
|
|
3497
3575
|
/** "★ Best seats" premium quick-pick toggle — biases best-available to premium seats. */
|
|
3498
3576
|
this.baPremium = false;
|
|
3577
|
+
/**
|
|
3578
|
+
* The buyer re-opened the best-seats form with seats already in the cart
|
|
3579
|
+
* ("I picked one, actually find us three together"). The card normally
|
|
3580
|
+
* yields this space to the ticket chips the moment anything is selected —
|
|
3581
|
+
* which removed the accelerator at exactly the moment a one-handed phone
|
|
3582
|
+
* buyer wants it. Cleared when the cart empties, a hold lands, or the
|
|
3583
|
+
* buyer backs out.
|
|
3584
|
+
*/
|
|
3585
|
+
this.baReopen = false;
|
|
3499
3586
|
this.bestAvailableConfirm = false;
|
|
3500
3587
|
this.releasingHold = false;
|
|
3501
3588
|
/** Event sales window is closed (read-only load state / live close). */
|
|
@@ -3568,9 +3655,12 @@ var SeatPicker = class _SeatPicker {
|
|
|
3568
3655
|
this.fsEscHandler = null;
|
|
3569
3656
|
/** Host-level event chrome owns the duplicate identity outside full screen. */
|
|
3570
3657
|
this.eventDetailsHidden = false;
|
|
3658
|
+
/** True while the hold note reads "N more selected" — the tick must not overwrite it. */
|
|
3659
|
+
this.holdCopyPending = false;
|
|
3571
3660
|
/** Wide-layout ticket panel collapsed (map owns the full width). */
|
|
3572
3661
|
this.sideCollapsed = false;
|
|
3573
3662
|
this.sideToggleEl = null;
|
|
3663
|
+
this.pricesBtnEl = null;
|
|
3574
3664
|
/** True once we've asked the host page to pin us fullscreen (framed, no native). */
|
|
3575
3665
|
this.framedFs = false;
|
|
3576
3666
|
/** Last height (px) posted to a host frame; dedupes redundant reports. */
|
|
@@ -3683,7 +3773,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3683
3773
|
if (this.tableDialog?.physicalSeatIds.includes(seat.id)) this.dismissTableDialog();
|
|
3684
3774
|
},
|
|
3685
3775
|
onSelectionLimit: () => {
|
|
3686
|
-
this.toast(
|
|
3776
|
+
this.toast(t2("picker.maxTicketsForOrder", { count: this.maxTickets }), "warning");
|
|
3687
3777
|
},
|
|
3688
3778
|
onViewChange: () => {
|
|
3689
3779
|
this.reanchorConfirm();
|
|
@@ -3799,8 +3889,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
3799
3889
|
return `<span class="sl-cx-mark" role="img" aria-label="${title}" title="${title}">\u25D0</span>`;
|
|
3800
3890
|
}
|
|
3801
3891
|
wheelchairProvisionLabel(type) {
|
|
3802
|
-
if (type === "no-seat") return "Empty wheelchair space";
|
|
3803
|
-
if (type === "seat-present") return "Accessible physical seat";
|
|
3892
|
+
if (type === "no-seat") return this.tf("picker.emptyWheelchairSpace", "Empty wheelchair space");
|
|
3893
|
+
if (type === "seat-present") return this.tf("picker.accessiblePhysicalSeat", "Accessible physical seat");
|
|
3804
3894
|
return "";
|
|
3805
3895
|
}
|
|
3806
3896
|
wheelchairConfirmHtml(type) {
|
|
@@ -3881,9 +3971,9 @@ var SeatPicker = class _SeatPicker {
|
|
|
3881
3971
|
const hideEventDetails = this.eventDetailsHidden && !active;
|
|
3882
3972
|
this.root?.setAttribute("data-event-details-hidden", String(hideEventDetails));
|
|
3883
3973
|
this.els.zfs?.setAttribute("aria-pressed", String(active));
|
|
3884
|
-
this.els.zfs?.setAttribute("title", active ? "Exit full screen" : "Full screen");
|
|
3974
|
+
this.els.zfs?.setAttribute("title", active ? this.tf("picker.exitFullScreen", "Exit full screen") : this.tf("picker.fullScreen", "Full screen"));
|
|
3885
3975
|
const zfsLabel = this.els.zfs?.querySelector(".sl-zfs-lbl");
|
|
3886
|
-
if (zfsLabel) zfsLabel.textContent = active ? "Exit full screen" : "Full screen";
|
|
3976
|
+
if (zfsLabel) zfsLabel.textContent = active ? this.tf("picker.exitFullScreen", "Exit full screen") : this.tf("picker.fullScreen", "Full screen");
|
|
3887
3977
|
this.view3dEl?.querySelector(".sl-view3d-fs")?.setAttribute("aria-pressed", String(active));
|
|
3888
3978
|
}
|
|
3889
3979
|
/**
|
|
@@ -3948,7 +4038,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3948
4038
|
frame.className = "sl-modal-frame";
|
|
3949
4039
|
frame.setAttribute("role", "dialog");
|
|
3950
4040
|
frame.setAttribute("aria-modal", "true");
|
|
3951
|
-
frame.setAttribute("aria-label", "Seat selection");
|
|
4041
|
+
frame.setAttribute("aria-label", tfStatic("picker.seatSelection", "Seat selection"));
|
|
3952
4042
|
frame.tabIndex = -1;
|
|
3953
4043
|
scrim.appendChild(frame);
|
|
3954
4044
|
document.body.appendChild(scrim);
|
|
@@ -4108,7 +4198,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4108
4198
|
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
|
|
4109
4199
|
<span data-ref="closedPillText"></span>
|
|
4110
4200
|
</span>
|
|
4111
|
-
<button type="button" class="sl-close" data-ref="close" aria-label="Close">
|
|
4201
|
+
<button type="button" class="sl-close" data-ref="close" aria-label="${this.tf("picker.close", "Close")}">
|
|
4112
4202
|
<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
4113
4203
|
</button>
|
|
4114
4204
|
</div>
|
|
@@ -4116,17 +4206,17 @@ var SeatPicker = class _SeatPicker {
|
|
|
4116
4206
|
<div class="sl-map">
|
|
4117
4207
|
<div class="sl-map-host" data-ref="map"></div>
|
|
4118
4208
|
<div class="sl-zoom" data-ref="zoom">
|
|
4119
|
-
<button type="button" aria-label="Zoom in" title="Zoom in" data-ref="zin">+</button>
|
|
4120
|
-
<button type="button" aria-label="Zoom out" title="Zoom out" data-ref="zout">\u2212</button>
|
|
4121
|
-
<button type="button" aria-label="Fit to screen" title="Fit to screen" data-ref="zfit">
|
|
4209
|
+
<button type="button" aria-label="${this.tf("picker.zoomIn", "Zoom in")}" title="${this.tf("picker.zoomIn", "Zoom in")}" data-ref="zin">+</button>
|
|
4210
|
+
<button type="button" aria-label="${this.tf("picker.zoomOut", "Zoom out")}" title="${this.tf("picker.zoomOut", "Zoom out")}" data-ref="zout">\u2212</button>
|
|
4211
|
+
<button type="button" aria-label="${this.tf("picker.fitToScreen", "Fit to screen")}" title="${this.tf("picker.fitToScreen", "Fit to screen")}" data-ref="zfit">
|
|
4122
4212
|
<svg viewBox="0 0 24 24"><path d="M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3"/></svg>
|
|
4123
4213
|
</button>
|
|
4124
|
-
<button type="button" aria-label="Full screen" title="Full screen" aria-pressed="false" data-ref="zfs">
|
|
4214
|
+
<button type="button" aria-label="${this.tf("picker.fullScreen", "Full screen")}" title="${this.tf("picker.fullScreen", "Full screen")}" aria-pressed="false" data-ref="zfs">
|
|
4125
4215
|
<svg viewBox="0 0 24 24"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
|
|
4126
|
-
<span class="sl-zfs-lbl" aria-hidden="true"
|
|
4216
|
+
<span class="sl-zfs-lbl" aria-hidden="true">${this.tf("picker.fullScreen", "Full screen")}</span>
|
|
4127
4217
|
</button>
|
|
4128
4218
|
</div>
|
|
4129
|
-
<div class="sl-boot" data-ref="boot"><span class="sl-boot-spin"></span
|
|
4219
|
+
<div class="sl-boot" data-ref="boot"><span class="sl-boot-spin"></span>${this.tf("picker.loadingSeatMap", "Loading seat map\u2026")}</div>
|
|
4130
4220
|
<div class="sl-toast" data-ref="toast" role="status" aria-live="polite"></div>
|
|
4131
4221
|
</div>
|
|
4132
4222
|
<div class="sl-side" data-ref="side">
|
|
@@ -4134,24 +4224,25 @@ var SeatPicker = class _SeatPicker {
|
|
|
4134
4224
|
<div class="sl-sheet-grab"></div>
|
|
4135
4225
|
<div class="sl-sheet-bar">
|
|
4136
4226
|
<div class="sl-sheet-peek" data-ref="peek"></div>
|
|
4137
|
-
<button type="button" class="sl-sheet-toggle" data-ref="sheetToggle" aria-label="Open ticket panel" aria-expanded="false">
|
|
4227
|
+
<button type="button" class="sl-sheet-toggle" data-ref="sheetToggle" aria-label="${this.tf("picker.openTicketPanel", "Open ticket panel")}" aria-expanded="false">
|
|
4138
4228
|
<svg viewBox="0 0 24 24"><path d="M6 15l6-6 6 6"/></svg>
|
|
4139
4229
|
</button>
|
|
4140
4230
|
</div>
|
|
4141
4231
|
</div>
|
|
4142
|
-
<div class="sl-sec sl-filtersec" data-ref="filtersSec"
|
|
4232
|
+
<div class="sl-sec sl-filtersec" data-ref="filtersSec">${this.tf("picker.filters", "Filters")}</div>
|
|
4143
4233
|
<div class="sl-filters" data-ref="filters"></div>
|
|
4144
4234
|
<div class="sl-offer" data-ref="offer" role="status" aria-live="polite"></div>
|
|
4145
|
-
<div class="sl-sec sl-prices-sec" data-ref="pricesSec"><span
|
|
4235
|
+
<div class="sl-sec sl-prices-sec" data-ref="pricesSec"><span>${this.tf("picker.ticketPrices", "Ticket prices")}</span></div>
|
|
4236
|
+
<div class="sl-prices-hint" data-ref="pricesHint"></div>
|
|
4146
4237
|
<div class="sl-prices" data-ref="prices"></div>
|
|
4147
|
-
<div class="sl-live" data-ref="live" role="status" aria-live="polite"><span class="dot" aria-hidden="true"></span><span data-ref="liveText"
|
|
4148
|
-
<div class="sl-sec sl-seats-sec"><span
|
|
4238
|
+
<div class="sl-live" data-ref="live" role="status" aria-live="polite"><span class="dot" aria-hidden="true"></span><span data-ref="liveText">${this.tf("picker.liveAvailability", "Live availability \u2014 seats update in real time")}</span></div>
|
|
4239
|
+
<div class="sl-sec sl-seats-sec"><span>${this.tf("picker.yourSeats", "Your seats")}</span><span class="sl-seat-summary" data-ref="seatSummary"></span></div>
|
|
4149
4240
|
<div class="sl-tray" data-ref="tray"></div>
|
|
4150
4241
|
<div class="sl-foot" data-ref="foot">
|
|
4151
4242
|
<div class="sl-hold-note" data-ref="holdNote" role="status" aria-live="polite">
|
|
4152
4243
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
|
4153
|
-
<span><b data-ref="holdTitle"
|
|
4154
|
-
<button type="button" class="sl-hold-change" data-ref="holdChange" aria-label="Release held tickets and choose different seats"
|
|
4244
|
+
<span><b data-ref="holdTitle">${this.tf("picker.seatsSecured", "Seats secured")}</b><span class="sl-hold-copy" data-ref="holdCopy">${this.tf("picker.notChargedYet", "You won\u2019t be charged yet.")}</span></span>
|
|
4245
|
+
<button type="button" class="sl-hold-change" data-ref="holdChange" aria-label="${this.tf("picker.releaseHeldTickets", "Release held tickets and choose different seats")}">${this.tf("picker.change", "Change")}</button>
|
|
4155
4246
|
</div>
|
|
4156
4247
|
<div class="sl-total"><span data-ref="count"></span><b data-ref="total"></b></div>
|
|
4157
4248
|
<button type="button" class="sl-cta" data-ref="cta" disabled></button>
|
|
@@ -4202,7 +4293,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4202
4293
|
const setSheet = (open) => {
|
|
4203
4294
|
root.dataset.sheet = open ? "open" : "peek";
|
|
4204
4295
|
toggle?.setAttribute("aria-expanded", String(open));
|
|
4205
|
-
toggle?.setAttribute("aria-label", open ? "Collapse ticket panel" : "Open ticket panel");
|
|
4296
|
+
toggle?.setAttribute("aria-label", open ? this.tf("picker.collapseTicketPanel", "Collapse ticket panel") : this.tf("picker.openTicketPanel", "Open ticket panel"));
|
|
4206
4297
|
};
|
|
4207
4298
|
setSheet(root.dataset.sheet === "open");
|
|
4208
4299
|
toggle?.addEventListener("click", (e) => {
|
|
@@ -4248,6 +4339,39 @@ var SeatPicker = class _SeatPicker {
|
|
|
4248
4339
|
head.releasePointerCapture?.(e.pointerId);
|
|
4249
4340
|
});
|
|
4250
4341
|
}
|
|
4342
|
+
const togglePrices = () => {
|
|
4343
|
+
if (this.root?.dataset.layout !== "narrow") return;
|
|
4344
|
+
const open = this.root.getAttribute("data-prices-open") === "true";
|
|
4345
|
+
this.root.setAttribute("data-prices-open", String(!open));
|
|
4346
|
+
this.els.pricesSec?.setAttribute("aria-expanded", String(!open));
|
|
4347
|
+
this.pricesBtnEl?.setAttribute("aria-pressed", String(!open));
|
|
4348
|
+
if (!open && this.root.dataset.sheet !== "open") {
|
|
4349
|
+
this.root.dataset.sheet = "open";
|
|
4350
|
+
const sheetToggle = this.els.sheetToggle;
|
|
4351
|
+
sheetToggle?.setAttribute("aria-expanded", "true");
|
|
4352
|
+
sheetToggle?.setAttribute("aria-label", "Collapse ticket panel");
|
|
4353
|
+
}
|
|
4354
|
+
};
|
|
4355
|
+
this.els.pricesSec?.addEventListener("click", (e) => {
|
|
4356
|
+
if (e.target.closest("select,button")) return;
|
|
4357
|
+
togglePrices();
|
|
4358
|
+
});
|
|
4359
|
+
this.els.pricesSec?.addEventListener("keydown", (e) => {
|
|
4360
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
4361
|
+
if (e.target.closest("select,button")) return;
|
|
4362
|
+
e.preventDefault();
|
|
4363
|
+
togglePrices();
|
|
4364
|
+
});
|
|
4365
|
+
const pricesBtn = document.createElement("button");
|
|
4366
|
+
pricesBtn.type = "button";
|
|
4367
|
+
pricesBtn.className = "sl-prices-btn";
|
|
4368
|
+
pricesBtn.setAttribute("aria-label", this.tf("picker.ticketPrices", "Ticket prices"));
|
|
4369
|
+
pricesBtn.setAttribute("title", this.tf("picker.ticketPrices", "Ticket prices"));
|
|
4370
|
+
pricesBtn.setAttribute("aria-pressed", "false");
|
|
4371
|
+
pricesBtn.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.6 13.4 13.4 20.6a2 2 0 0 1-2.8 0L3 13V5a2 2 0 0 1 2-2h8l7.6 7.6a2 2 0 0 1 0 2.8z"/><circle cx="7.5" cy="7.5" r="1.3"/></svg>';
|
|
4372
|
+
pricesBtn.addEventListener("click", () => togglePrices());
|
|
4373
|
+
this.els.headInfo?.parentElement?.insertBefore(pricesBtn, this.els.hold ?? null);
|
|
4374
|
+
this.pricesBtnEl = pricesBtn;
|
|
4251
4375
|
this.tipEl = document.createElement("div");
|
|
4252
4376
|
this.tipEl.setAttribute("role", "tooltip");
|
|
4253
4377
|
this.tipEl.className = "sl-tip";
|
|
@@ -4265,7 +4389,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4265
4389
|
const info = await this.controller.render(canvasHost);
|
|
4266
4390
|
if (this.destroyed) return this;
|
|
4267
4391
|
if (!info) {
|
|
4268
|
-
this.els.boot.innerHTML =
|
|
4392
|
+
this.els.boot.innerHTML = `<div class="sl-boot-title">${this.tf("picker.mapDidNotLoad", "The seat map didn\u2019t load")}</div><div>${this.tf("picker.checkConnection", "Check your connection and try again.")}</div><button type="button" class="sl-boot-retry">${this.tf("picker.accessRetry", "Try again")}</button>`;
|
|
4269
4393
|
this.els.boot.querySelector("button").addEventListener("click", () => {
|
|
4270
4394
|
const container = this.opts.container;
|
|
4271
4395
|
const opts = this.opts;
|
|
@@ -4300,6 +4424,12 @@ var SeatPicker = class _SeatPicker {
|
|
|
4300
4424
|
const when = info.startsAt ? formatWhen(info.startsAt, info.timezone ?? null, this.opts.locale) : "";
|
|
4301
4425
|
this.eventWhenText = when || null;
|
|
4302
4426
|
this.els.meta.textContent = [info.venue, when].filter(Boolean).join(" \xB7 ");
|
|
4427
|
+
if (this.els.pricesHint) {
|
|
4428
|
+
this.els.pricesHint.textContent = this.tf(
|
|
4429
|
+
"picker.priceHint",
|
|
4430
|
+
"Colours on the map are ticket types \u2014 tap one below to show just those seats."
|
|
4431
|
+
);
|
|
4432
|
+
}
|
|
4303
4433
|
this.buildBadge(chartTheme);
|
|
4304
4434
|
const present = /* @__PURE__ */ new Set();
|
|
4305
4435
|
let hasLimitedView = false;
|
|
@@ -4326,7 +4456,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4326
4456
|
const mk = (key, label) => `<button type="button" class="sl-chip-f${key === "all" ? " on" : ""}" data-a11y="1" data-f="${key}">${label}</button>`;
|
|
4327
4457
|
chips.insertAdjacentHTML(
|
|
4328
4458
|
"beforeend",
|
|
4329
|
-
mk("all", "All seats") + ACCESSIBILITY_TYPES.filter(({ key }) => present.has(key)).map(({ key, short, icon }) => mk(key, `${icon} ${short}`)).join("")
|
|
4459
|
+
mk("all", this.tf("picker.allSeats", "All seats")) + ACCESSIBILITY_TYPES.filter(({ key }) => present.has(key)).map(({ key, short, icon }) => mk(key, `${icon} ${short}`)).join("")
|
|
4330
4460
|
);
|
|
4331
4461
|
const active = /* @__PURE__ */ new Set();
|
|
4332
4462
|
const syncChips = () => {
|
|
@@ -4372,7 +4502,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4372
4502
|
cb.type = "button";
|
|
4373
4503
|
cb.className = "sl-cbbtn";
|
|
4374
4504
|
this.cbEl = cb;
|
|
4375
|
-
cb.setAttribute("aria-label", "Toggle colorblind-friendly colors");
|
|
4505
|
+
cb.setAttribute("aria-label", this.tf("picker.toggleColorblindColors", "Toggle colorblind-friendly colors"));
|
|
4376
4506
|
cb.setAttribute("aria-pressed", String(this.cbSafe));
|
|
4377
4507
|
cb.innerHTML = '<svg viewBox="0 0 24 24"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg>';
|
|
4378
4508
|
this.els.zfit.parentElement.appendChild(cb);
|
|
@@ -4458,8 +4588,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
4458
4588
|
if (!btn) return;
|
|
4459
4589
|
const collapsed = this.sideCollapsed;
|
|
4460
4590
|
btn.setAttribute("aria-expanded", String(!collapsed));
|
|
4461
|
-
btn.setAttribute("aria-label", collapsed ? "Show the ticket panel" : "Hide the ticket panel");
|
|
4462
|
-
btn.innerHTML = collapsed ?
|
|
4591
|
+
btn.setAttribute("aria-label", collapsed ? this.tf("picker.showTicketPanel", "Show the ticket panel") : this.tf("picker.hideTicketPanel", "Hide the ticket panel"));
|
|
4592
|
+
btn.innerHTML = collapsed ? `<svg viewBox="0 0 24 24"><path d="M15 6l-6 6 6 6"/></svg><span>${this.tf("picker.tickets", "Tickets")}</span>` : `<svg viewBox="0 0 24 24"><path d="M9 6l6 6-6 6"/></svg><span>${this.tf("picker.hidePanel", "Hide panel")}</span>`;
|
|
4463
4593
|
}
|
|
4464
4594
|
/**
|
|
4465
4595
|
* Collapse or reopen the wide-layout ticket panel in place (host-drivable —
|
|
@@ -4485,13 +4615,24 @@ var SeatPicker = class _SeatPicker {
|
|
|
4485
4615
|
const narrow = this.root?.dataset.layout === "narrow";
|
|
4486
4616
|
this.applyPanelCollapsed();
|
|
4487
4617
|
const zfs = this.els.zfs;
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4618
|
+
const head = this.els.headInfo?.parentElement;
|
|
4619
|
+
if (zfs && head && zfs.parentElement !== head) {
|
|
4620
|
+
zfs.classList.add("sl-fs-pill");
|
|
4621
|
+
head.insertBefore(zfs, this.els.hold ?? null);
|
|
4622
|
+
}
|
|
4623
|
+
const pricesSec = this.els.pricesSec;
|
|
4624
|
+
if (pricesSec) {
|
|
4625
|
+
if (narrow) {
|
|
4626
|
+
pricesSec.setAttribute("role", "button");
|
|
4627
|
+
pricesSec.tabIndex = 0;
|
|
4628
|
+
pricesSec.setAttribute(
|
|
4629
|
+
"aria-expanded",
|
|
4630
|
+
String(this.root?.getAttribute("data-prices-open") === "true")
|
|
4631
|
+
);
|
|
4632
|
+
} else {
|
|
4633
|
+
pricesSec.removeAttribute("role");
|
|
4634
|
+
pricesSec.removeAttribute("aria-expanded");
|
|
4635
|
+
pricesSec.tabIndex = -1;
|
|
4495
4636
|
}
|
|
4496
4637
|
}
|
|
4497
4638
|
const filters = this.els.filters;
|
|
@@ -4518,7 +4659,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4518
4659
|
this.extendEl = el;
|
|
4519
4660
|
this.els.extendTxt = el.querySelector('[data-ref="extendTxt"]');
|
|
4520
4661
|
this.els.extendBtn = el.querySelector('[data-ref="extendBtn"]');
|
|
4521
|
-
this.els.extendBtn.textContent = "Add time";
|
|
4662
|
+
this.els.extendBtn.textContent = this.tf("picker.addTime", "Add time");
|
|
4522
4663
|
this.els.extendBtn.addEventListener("click", () => void this.handleExtend());
|
|
4523
4664
|
}
|
|
4524
4665
|
/** Success overlay + onBooked fire when the held seats settle to booked. */
|
|
@@ -4527,7 +4668,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4527
4668
|
el.className = "sl-booked";
|
|
4528
4669
|
el.setAttribute("role", "status");
|
|
4529
4670
|
el.setAttribute("aria-live", "polite");
|
|
4530
|
-
el.innerHTML = `<div class="sl-booked-badge"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></div><div class="sl-booked-title"
|
|
4671
|
+
el.innerHTML = `<div class="sl-booked-badge"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg></div><div class="sl-booked-title">${this.tf("picker.allSetTitle", "You're all set")}</div><div class="sl-booked-sub" data-ref="bookedSub"></div>`;
|
|
4531
4672
|
this.root.appendChild(el);
|
|
4532
4673
|
this.bookedEl = el;
|
|
4533
4674
|
this.els.bookedSub = el.querySelector('[data-ref="bookedSub"]');
|
|
@@ -4538,8 +4679,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4538
4679
|
* host `messages` override (which makes `t()` return the override, not the key).
|
|
4539
4680
|
*/
|
|
4540
4681
|
tf(key, fallback) {
|
|
4541
|
-
|
|
4542
|
-
return v === key ? fallback : v;
|
|
4682
|
+
return tfStatic(key, fallback);
|
|
4543
4683
|
}
|
|
4544
4684
|
/** Sold-out overlay — an informational state with no unavailable action. */
|
|
4545
4685
|
buildSoldoutOverlay() {
|
|
@@ -4724,7 +4864,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4724
4864
|
}
|
|
4725
4865
|
canAddTicket() {
|
|
4726
4866
|
if (this.totalTicketCount() < this.maxTickets) return true;
|
|
4727
|
-
this.toast(
|
|
4867
|
+
this.toast(t2("picker.maxTicketsForOrder", { count: this.maxTickets }), "warning");
|
|
4728
4868
|
return false;
|
|
4729
4869
|
}
|
|
4730
4870
|
pendingGATotal(gaAreas) {
|
|
@@ -4747,30 +4887,32 @@ var SeatPicker = class _SeatPicker {
|
|
|
4747
4887
|
}
|
|
4748
4888
|
if (this.confirmSeat || this.tableDialog && !this.tableDialogHeld) {
|
|
4749
4889
|
cta.disabled = true;
|
|
4750
|
-
cta.textContent = this.tableDialog ? "Confirm your table" : "Confirm or cancel this seat";
|
|
4890
|
+
cta.textContent = this.tableDialog ? this.tf("picker.confirmYourTable", "Confirm your table") : this.tf("picker.confirmOrCancelSeat", "Confirm or cancel this seat");
|
|
4751
4891
|
return;
|
|
4752
4892
|
}
|
|
4753
4893
|
if (this.ctaPhase === "holding") {
|
|
4754
4894
|
cta.disabled = true;
|
|
4755
|
-
cta.innerHTML =
|
|
4895
|
+
cta.innerHTML = `<span class="sl-cta-spin" aria-hidden="true"></span>${this.tf("picker.securingSeats", "Securing your seats\u2026")}`;
|
|
4756
4896
|
return;
|
|
4757
4897
|
}
|
|
4758
4898
|
if (this.ctaPhase === "checkout") {
|
|
4759
4899
|
cta.disabled = true;
|
|
4760
|
-
cta.innerHTML =
|
|
4900
|
+
cta.innerHTML = `<span class="sl-cta-spin" aria-hidden="true"></span>${this.tf("picker.openingCheckout", "Opening secure checkout\u2026")}`;
|
|
4761
4901
|
return;
|
|
4762
4902
|
}
|
|
4763
4903
|
cta.disabled = count === 0;
|
|
4764
|
-
cta.textContent = this.hold ? pending ?
|
|
4904
|
+
cta.textContent = this.hold ? pending ? t2("picker.secureMoreAndCheckout", { count: pending }) : this.tf("picker.continueToCheckout", "Continue to checkout") : count ? this.tf("picker.holdSeatsAndCheckout", "Hold seats & checkout") : this.tf("picker.selectSeats", "Select seats");
|
|
4765
4905
|
}
|
|
4766
4906
|
setCtaPhase(phase) {
|
|
4767
4907
|
this.ctaPhase = phase;
|
|
4768
4908
|
this.syncCta();
|
|
4909
|
+
this.renderPeek(this.lastTrayCount, this.lastTrayTotal, this.pendingSelectionCount());
|
|
4769
4910
|
if (phase === "checkout") {
|
|
4770
4911
|
this.scheduleMotion(() => {
|
|
4771
4912
|
if (this.ctaPhase !== "checkout") return;
|
|
4772
4913
|
this.ctaPhase = "idle";
|
|
4773
4914
|
this.syncCta();
|
|
4915
|
+
this.renderPeek(this.lastTrayCount, this.lastTrayTotal, this.pendingSelectionCount());
|
|
4774
4916
|
}, 1100);
|
|
4775
4917
|
}
|
|
4776
4918
|
}
|
|
@@ -4820,7 +4962,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4820
4962
|
this.syncTray();
|
|
4821
4963
|
this.emitHoldChange();
|
|
4822
4964
|
this.opts.onHoldRestored?.(restored, restored.seats ?? [], this.buildHandoff(restored));
|
|
4823
|
-
if (automatic) this.toast("Your held tickets have been restored.", "success");
|
|
4965
|
+
if (automatic) this.toast(this.tf("picker.heldTicketsRestored", "Your held tickets have been restored."), "success");
|
|
4824
4966
|
return restored;
|
|
4825
4967
|
} catch (error) {
|
|
4826
4968
|
const status = error?.status;
|
|
@@ -5038,8 +5180,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
5038
5180
|
if (bands.length < 2) return;
|
|
5039
5181
|
const select = document.createElement("select");
|
|
5040
5182
|
select.className = "sl-price-select";
|
|
5041
|
-
select.setAttribute("aria-label", "Filter and focus seats by price");
|
|
5042
|
-
select.innerHTML = `<option value="all"
|
|
5183
|
+
select.setAttribute("aria-label", this.tf("picker.filterAndFocusByPrice", "Filter and focus seats by price"));
|
|
5184
|
+
select.innerHTML = `<option value="all">${this.tf("picker.allPrices", "All prices")}</option>` + bands.map((band) => `<option value="${band.id}">${band.label}</option>`).join("");
|
|
5043
5185
|
this.els.pricesSec.appendChild(select);
|
|
5044
5186
|
select.addEventListener("change", () => {
|
|
5045
5187
|
const band = bands.find((candidate) => candidate.id === select.value);
|
|
@@ -5066,8 +5208,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
5066
5208
|
const projection = document.createElement("div");
|
|
5067
5209
|
projection.className = "sl-projection";
|
|
5068
5210
|
projection.setAttribute("role", "group");
|
|
5069
|
-
projection.setAttribute("aria-label", "Venue view");
|
|
5070
|
-
projection.innerHTML =
|
|
5211
|
+
projection.setAttribute("aria-label", this.tf("picker.venueView", "Venue view"));
|
|
5212
|
+
projection.innerHTML = `<button type="button" data-view="map" aria-pressed="true" title="${this.tf("picker.flat2dMap", "Flat 2D map")}">${this.tf("picker.map", "Map")}</button><button type="button" data-view="venue3d" aria-pressed="false" title="${this.tf("picker.interactive3dVenueView", "Interactive 3D venue view")}">3D</button>`;
|
|
5071
5213
|
projection.querySelectorAll("button").forEach((button) => {
|
|
5072
5214
|
button.addEventListener("click", () => {
|
|
5073
5215
|
this.setBuyerView(button.dataset.view);
|
|
@@ -5190,6 +5332,10 @@ var SeatPicker = class _SeatPicker {
|
|
|
5190
5332
|
renderSectionCard(summary) {
|
|
5191
5333
|
if (!this.els.map) return;
|
|
5192
5334
|
this.secCardEl?.remove();
|
|
5335
|
+
if (this.root?.dataset.layout === "narrow" && (this.hold || this.committedSelection().length || this.pendingGACount())) {
|
|
5336
|
+
this.lastSection = null;
|
|
5337
|
+
return;
|
|
5338
|
+
}
|
|
5193
5339
|
const paid = summary.categories.length ? summary.categories.map((c) => this.paidPrice(c.key, null, c.price)) : [summary.priceMin, summary.priceMax];
|
|
5194
5340
|
const paidMin = Math.min(...paid);
|
|
5195
5341
|
const paidMax = Math.max(...paid);
|
|
@@ -5290,13 +5436,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
5290
5436
|
}
|
|
5291
5437
|
const cat = this.controller.doc?.categories.find((c) => c.key === seat.categoryKey);
|
|
5292
5438
|
const status = this.controller.getStatus(seat.id) ?? "free";
|
|
5293
|
-
const statusText = status === "free" ? "available" : status === "held" ? "on hold" : "taken";
|
|
5439
|
+
const statusText = status === "free" ? this.tf("picker.statusAvailable", "available") : status === "held" ? this.tf("picker.statusOnHold", "on hold") : this.tf("picker.statusTaken2", "taken");
|
|
5294
5440
|
const price = cat ? this.catPrice(cat) : void 0;
|
|
5295
5441
|
const table = this.controller.tableSelection(seat.id);
|
|
5296
5442
|
const details = table ?? this.controller.seatDetails(seat.id);
|
|
5297
5443
|
const typeWord = this.rowTypeWord(details);
|
|
5298
5444
|
const buyerName = details?.rowLabel ?? details?.displayLabel ?? seat.displayLabel ?? seat.label;
|
|
5299
|
-
const identity = table ? `${typeWord} ${buyerName}, ${table.bookingMode === "variable" ?
|
|
5445
|
+
const identity = table ? `${typeWord} ${buyerName}, ${table.bookingMode === "variable" ? t2("picker.minToMaxGuests", { min: table.minOccupancy, max: table.maxOccupancy }) : t2("picker.capacityGuests", { count: table.capacity })}` : details?.objectType === "booth" ? `${typeWord} ${buyerName}` : details?.objectType === "table" ? `${typeWord} ${buyerName}, ${t2("picker.seatNumberLower", { label: details.seatNumber ?? seat.label })}` : t2("picker.seatLabel", { label: details?.displayLabel ?? seat.displayLabel ?? seat.label });
|
|
5300
5446
|
this.srEl.textContent = `${identity}, ${cat?.label ?? seat.categoryKey}${price != null ? `, ${this.money(price)}` : ""}, ${statusText}`;
|
|
5301
5447
|
}
|
|
5302
5448
|
// ---- atomic table confirmation / guest quantity ---------------------------
|
|
@@ -5317,7 +5463,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5317
5463
|
const typeWord = this.rowTypeWord(table);
|
|
5318
5464
|
const el = document.createElement("div");
|
|
5319
5465
|
el.className = "sl-table-scrim";
|
|
5320
|
-
el.innerHTML = `<section class="sl-table-dialog" role="dialog" aria-modal="true" aria-labelledby="sl-table-title" aria-describedby="sl-table-copy"><div class="sl-table-head"><div class="sl-table-eyebrow">${esc(variable ?
|
|
5466
|
+
el.innerHTML = `<section class="sl-table-dialog" role="dialog" aria-modal="true" aria-labelledby="sl-table-title" aria-describedby="sl-table-copy"><div class="sl-table-head"><div class="sl-table-eyebrow">${esc(variable ? t2("picker.flexiblePartyTypeWord", { typeWord }) : t2("picker.wholeTypeWord", { typeWord }))}</div><h2 class="sl-table-title" id="sl-table-title">${esc(table.displayLabel ?? table.label)}</h2><p class="sl-table-copy" id="sl-table-copy">${variable ? this.tf("picker.chooseGuestsCopy", "Choose how many guests will sit together. This table is held exclusively for your party.") : t2("picker.allPlacesBookedTogether", { count: table.capacity })}</p></div><div class="sl-table-body"><div class="sl-table-summary"><span>${esc(cat?.label ?? table.categoryKey)}</span><b data-table-unit>${t2("picker.perGuestPrice", { price: this.money(this.paidPrice(table.categoryKey, table.tierId ?? null, table.price)) })}</b><span class="muted">${this.tf("picker.tableCapacity", "Table capacity")}</span><span>${t2("picker.guestsCount", { count: table.capacity })}</span><span class="muted">${this.tf("picker.total", "Total")}</span><b data-table-total></b></div>` + (variable ? `<label class="sl-table-qtylabel" id="sl-table-qty-label">${this.tf("picker.numberOfGuests", "Number of guests")}</label><div class="sl-table-stepper" role="group" aria-labelledby="sl-table-qty-label"><button type="button" data-table-step="-1" aria-label="${this.tf("picker.fewerGuests", "Fewer guests")}">\u2212</button><output aria-live="polite" data-table-qty>${table.quantity}</output><button type="button" data-table-step="1" aria-label="${this.tf("picker.moreGuests", "More guests")}">+</button></div><div class="sl-table-range">${t2("picker.chooseMinMaxGuests", { min: table.minOccupancy, max: table.maxOccupancy })}</div>` : `<input type="hidden" data-table-qty value="${table.capacity}">`) + `<div class="sl-table-actions"><button type="button" class="sl-table-cancel">${t2("common.cancel")}</button><button type="button" class="sl-table-confirm">${held ? this.tf("picker.updateTable", "Update table") : variable ? this.tf("picker.selectTable", "Select table") : this.tf("picker.selectWholeTable", "Select whole table")}</button></div></div></section>`;
|
|
5321
5467
|
this.root.appendChild(el);
|
|
5322
5468
|
this.tableDialogEl = el;
|
|
5323
5469
|
this.renderTableDialogState();
|
|
@@ -5376,17 +5522,17 @@ var SeatPicker = class _SeatPicker {
|
|
|
5376
5522
|
const button = this.tableDialogEl?.querySelector(".sl-table-confirm");
|
|
5377
5523
|
if (button) {
|
|
5378
5524
|
button.disabled = true;
|
|
5379
|
-
button.textContent = held ? "Updating\u2026" : "Selecting\u2026";
|
|
5525
|
+
button.textContent = held ? this.tf("picker.updatingEllipsis", "Updating\u2026") : this.tf("picker.selectingEllipsis", "Selecting\u2026");
|
|
5380
5526
|
}
|
|
5381
5527
|
if (held) {
|
|
5382
5528
|
try {
|
|
5383
5529
|
const updated = await this.controller.replaceTableQuantity(table.label, table.quantity, this.opts.holdTtlMs);
|
|
5384
5530
|
if (!updated) {
|
|
5385
|
-
this.toast("That guest count could not be secured. Your current table hold is unchanged.", "warning");
|
|
5531
|
+
this.toast(this.tf("picker.guestCountCouldNotBeSecured", "That guest count could not be secured. Your current table hold is unchanged."), "warning");
|
|
5386
5532
|
this.renderTableDialogState();
|
|
5387
5533
|
if (button) {
|
|
5388
5534
|
button.disabled = false;
|
|
5389
|
-
button.textContent = "Update table";
|
|
5535
|
+
button.textContent = this.tf("picker.updateTable", "Update table");
|
|
5390
5536
|
}
|
|
5391
5537
|
return;
|
|
5392
5538
|
}
|
|
@@ -5400,13 +5546,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
5400
5546
|
this.dismissTableDialog();
|
|
5401
5547
|
this.syncTray();
|
|
5402
5548
|
this.emitHoldChange();
|
|
5403
|
-
this.toast(
|
|
5549
|
+
this.toast(t2("picker.tableUpdatedForGuests", { label: table.label, count: table.quantity }), "success");
|
|
5404
5550
|
} catch (error) {
|
|
5405
5551
|
this.opts.onError?.(error);
|
|
5406
|
-
this.toast("That guest count is no longer available. Your current hold is unchanged.", "error");
|
|
5552
|
+
this.toast(this.tf("picker.guestCountNoLongerAvailable", "That guest count is no longer available. Your current hold is unchanged."), "error");
|
|
5407
5553
|
if (button) {
|
|
5408
5554
|
button.disabled = false;
|
|
5409
|
-
button.textContent = "Update table";
|
|
5555
|
+
button.textContent = this.tf("picker.updateTable", "Update table");
|
|
5410
5556
|
}
|
|
5411
5557
|
}
|
|
5412
5558
|
return;
|
|
@@ -5414,7 +5560,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5414
5560
|
if (!this.controller.setTableQuantity(table.label, table.quantity)) {
|
|
5415
5561
|
if (button) {
|
|
5416
5562
|
button.disabled = false;
|
|
5417
|
-
button.textContent = table.bookingMode === "variable" ? "Select table" : "Select whole table";
|
|
5563
|
+
button.textContent = table.bookingMode === "variable" ? this.tf("picker.selectTable", "Select table") : this.tf("picker.selectWholeTable", "Select whole table");
|
|
5418
5564
|
}
|
|
5419
5565
|
return;
|
|
5420
5566
|
}
|
|
@@ -5460,16 +5606,16 @@ var SeatPicker = class _SeatPicker {
|
|
|
5460
5606
|
'"': """
|
|
5461
5607
|
})[char]);
|
|
5462
5608
|
const identityFields = [
|
|
5463
|
-
details?.sectionLabel ? `<div class="sl-confirm-field"><span class="sl-confirm-key"
|
|
5609
|
+
details?.sectionLabel ? `<div class="sl-confirm-field"><span class="sl-confirm-key">${this.tf("picker.section", "Section")}</span><span class="sl-confirm-value">${safe(details.sectionLabel)}</span></div>` : "",
|
|
5464
5610
|
details?.rowLabel || details?.objectType === "booth" ? `<div class="sl-confirm-field"><span class="sl-confirm-key">${safe(this.rowTypeWord(details))}</span><span class="sl-confirm-value">${safe(this.rowShort(details) ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>` : "",
|
|
5465
|
-
details?.objectType !== "booth" ? `<div class="sl-confirm-field"><span class="sl-confirm-key"
|
|
5611
|
+
details?.objectType !== "booth" ? `<div class="sl-confirm-field"><span class="sl-confirm-key">${this.tf("picker.seat", "Seat")}</span><span class="sl-confirm-value">${safe(details?.seatNumber ?? details?.displayLabel ?? seat.displayLabel ?? seat.label)}</span></div>` : ""
|
|
5466
5612
|
].filter(Boolean).join("");
|
|
5467
5613
|
const el = document.createElement("div");
|
|
5468
5614
|
el.className = "sl-confirm";
|
|
5469
5615
|
el.setAttribute("role", "dialog");
|
|
5470
|
-
el.setAttribute("aria-label",
|
|
5616
|
+
el.setAttribute("aria-label", t2("picker.confirmSeatLabel", { label: seat.label }));
|
|
5471
5617
|
el.style.setProperty("--sl-cat", cat?.color ?? "#6e7bff");
|
|
5472
|
-
el.innerHTML = `<div class="sl-confirm-grid">` + identityFields + `</div><div class="sl-confirm-cat"><span class="sl-dot" style="background:${cat?.color ?? "#6e7bff"}"></span><span class="sl-confirm-cat-name">${safe(details?.categoryLabel ?? cat?.label ?? seat.categoryKey)}</span>` + (price != null ? `<span class="sl-confirm-price">${this.money(price)}</span>` : "") + `</div><div class="sl-confirm-body">` + this.wheelchairConfirmHtml(details?.wheelchairSpaceType) + this.commercialConfirmHtml(seat.commercial) + (this.seatViewEnabled() && this.buyerView !== "venue3d" ? this.confirmThumbHtml(seat) : "") + (this.buyerView === "venue3d" ? `${this.seatConfidenceConfirmHtml(seat, `${details?.displayLabel ?? seat.displayLabel ?? seat.label} \xB7 ${price == null ? this.tf("picker.priceNotSupplied", "Price not supplied") : this.money(price)}`)}<div class="sl-confirm-inspect-row">${this.view3dCompareConfirmHtml(seat)}${this.see3dConfirmHtml()}</div>` : this.see3dConfirmHtml()) + `<div class="sl-confirm-row"><button type="button" class="sl-confirm-cancel"
|
|
5618
|
+
el.innerHTML = `<div class="sl-confirm-grid">` + identityFields + `</div><div class="sl-confirm-cat"><span class="sl-dot" style="background:${cat?.color ?? "#6e7bff"}"></span><span class="sl-confirm-cat-name">${safe(details?.categoryLabel ?? cat?.label ?? seat.categoryKey)}</span>` + (price != null ? `<span class="sl-confirm-price">${this.money(price)}</span>` : "") + `</div><div class="sl-confirm-body">` + this.wheelchairConfirmHtml(details?.wheelchairSpaceType) + this.commercialConfirmHtml(seat.commercial) + (this.seatViewEnabled() && this.buyerView !== "venue3d" ? this.confirmThumbHtml(seat) : "") + (this.buyerView === "venue3d" ? `${this.seatConfidenceConfirmHtml(seat, `${details?.displayLabel ?? seat.displayLabel ?? seat.label} \xB7 ${price == null ? this.tf("picker.priceNotSupplied", "Price not supplied") : this.money(price)}`)}<div class="sl-confirm-inspect-row">${this.view3dCompareConfirmHtml(seat)}${this.see3dConfirmHtml()}</div>` : this.see3dConfirmHtml()) + `<div class="sl-confirm-row"><button type="button" class="sl-confirm-cancel">${t2("common.cancel")}</button><button type="button" class="sl-confirm-add"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4 4L19 7"/></svg>${this.tf("picker.select", "Select")}</button></div></div>`;
|
|
5473
5619
|
this.els.map.appendChild(el);
|
|
5474
5620
|
this.confirmEl = el;
|
|
5475
5621
|
const thumb = el.querySelector(".sl-confirm-thumb");
|
|
@@ -5622,7 +5768,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5622
5768
|
el.className = "sl-view";
|
|
5623
5769
|
el.setAttribute("role", "dialog");
|
|
5624
5770
|
el.setAttribute("aria-label", t2("picker.viewFromSeat", { label: seat.label }));
|
|
5625
|
-
el.innerHTML = `<div class="sl-view-head"><span class="sl-view-title">${t2("picker.viewFromSeat", { label: seat.label })}</span><span class="sl-view-cap">${caption}</span><button type="button" class="sl-view-x" aria-label="Close"><svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="sl-view-pano"><span class="sl-view-badge">${real ? t2("picker.real360") : t2("picker.preview")}</span><span class="sl-view-hint"
|
|
5771
|
+
el.innerHTML = `<div class="sl-view-head"><span class="sl-view-title">${t2("picker.viewFromSeat", { label: seat.label })}</span><span class="sl-view-cap">${caption}</span><button type="button" class="sl-view-x" aria-label="${this.tf("picker.close", "Close")}"><svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="sl-view-pano"><span class="sl-view-badge">${real ? t2("picker.real360") : t2("picker.preview")}</span><span class="sl-view-hint">${this.tf("picker.dragToLookAround", "Drag to look around \xB7 scroll to zoom")}</span></div>`;
|
|
5626
5772
|
this.root.appendChild(el);
|
|
5627
5773
|
this.viewEl = el;
|
|
5628
5774
|
const pano = el.querySelector(".sl-view-pano");
|
|
@@ -5818,27 +5964,27 @@ var SeatPicker = class _SeatPicker {
|
|
|
5818
5964
|
copy.className = "sl-offer-copy";
|
|
5819
5965
|
const kicker = document.createElement("span");
|
|
5820
5966
|
kicker.className = "sl-offer-kicker";
|
|
5821
|
-
kicker.textContent = active ? "Current ticket offer" : "Upcoming ticket offer";
|
|
5967
|
+
kicker.textContent = active ? this.tf("picker.currentTicketOffer", "Current ticket offer") : this.tf("picker.upcomingTicketOffer", "Upcoming ticket offer");
|
|
5822
5968
|
const name = document.createElement("strong");
|
|
5823
5969
|
name.className = "sl-offer-name";
|
|
5824
|
-
name.textContent = offer.name || (active ? "Current offer" : "Scheduled offer");
|
|
5970
|
+
name.textContent = offer.name || (active ? this.tf("picker.currentOffer", "Current offer") : this.tf("picker.scheduledOffer", "Scheduled offer"));
|
|
5825
5971
|
const line = document.createElement("span");
|
|
5826
5972
|
line.className = "sl-offer-line";
|
|
5827
5973
|
const facts = [];
|
|
5828
5974
|
if (active && availability.fromPrice != null) facts.push(this.money(availability.fromPrice / 100));
|
|
5829
|
-
if (active && offer.remaining != null) facts.push(
|
|
5830
|
-
if (active && offer.endsAt != null) facts.push(
|
|
5831
|
-
if (upcoming?.startsAt != null) facts.push(
|
|
5975
|
+
if (active && offer.remaining != null) facts.push(t2("picker.offerRemainingAvailable", { count: offer.remaining }));
|
|
5976
|
+
if (active && offer.endsAt != null) facts.push(t2("picker.offerUntil", { time: formatWhen(offer.endsAt, this.eventTimezone, this.opts.locale) }));
|
|
5977
|
+
if (upcoming?.startsAt != null) facts.push(t2("picker.offerStarts", { time: formatWhen(upcoming.startsAt, this.eventTimezone, this.opts.locale) }));
|
|
5832
5978
|
line.textContent = facts.join(" \xB7 ");
|
|
5833
5979
|
copy.append(kicker, name, line);
|
|
5834
5980
|
const info = document.createElement("details");
|
|
5835
5981
|
info.className = "sl-offer-info";
|
|
5836
5982
|
const summary = document.createElement("summary");
|
|
5837
|
-
summary.setAttribute("aria-label",
|
|
5983
|
+
summary.setAttribute("aria-label", t2("picker.howOfferWorks", { name: name.textContent ?? "" }));
|
|
5838
5984
|
summary.textContent = "i";
|
|
5839
5985
|
const detail = document.createElement("div");
|
|
5840
5986
|
detail.className = "sl-offer-detail";
|
|
5841
|
-
detail.textContent = active ?
|
|
5987
|
+
detail.textContent = active ? this.tf("picker.offerDetailActive", "This price applies automatically to eligible seats. Tickets in active carts temporarily reduce the available quantity; released or expired holds return it. When the offer ends, the next matching offer or normal ticket price takes over.") : this.tf("picker.offerDetailUpcoming", "Tickets are available at their normal price now. This scheduled offer will apply automatically to eligible seats when it starts.");
|
|
5842
5988
|
info.append(summary, detail);
|
|
5843
5989
|
main.append(copy, info);
|
|
5844
5990
|
host.replaceChildren(main);
|
|
@@ -5874,8 +6020,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
5874
6020
|
const previous = offer?.previousPrice != null && offer.previousPrice > offer.price ? offer.previousPrice : null;
|
|
5875
6021
|
const active = this.focusedCatKey === c.key;
|
|
5876
6022
|
const dim = this.priceBandKeys != null && !this.priceBandKeys.has(c.key);
|
|
5877
|
-
return `<div class="sl-price-row${dim ? " sl-dim" : ""}${active ? " sl-active" : ""}" data-cat="${escapeOption(c.key)}" role="button" tabindex="0" aria-pressed="${active}" title="${escapeOption(active ? "Show all seats" :
|
|
5878
|
-
}).join("") + (overflow > 1 ? `<button type="button" class="sl-price-more" aria-expanded="${!collapsed}">` + (collapsed ?
|
|
6023
|
+
return `<div class="sl-price-row${dim ? " sl-dim" : ""}${active ? " sl-active" : ""}" data-cat="${escapeOption(c.key)}" role="button" tabindex="0" aria-pressed="${active}" title="${escapeOption(active ? this.tf("picker.showAllSeats", "Show all seats") : t2("picker.showLabelSeatsOnMap", { label: c.label }))}"><span class="sl-dot" style="background:${escapeOption(c.color)}"></span><span class="sl-price-label">${escapeOption(c.label)}` + (offer?.offerName ? `<small class="sl-price-offer">${escapeOption(offer.offerName)}</small>` : "") + `</span><span class="sl-price-left">${tCount("picker.leftCount", left[c.key] ?? 0)}</span>` + (previous != null ? `<span class="sl-price-was">${escapeOption(this.money(previous))}</span>` : "") + (price != null ? `<span class="sl-price-amt">${this.money(price)}</span>` : "") + `</div>`;
|
|
6024
|
+
}).join("") + (overflow > 1 ? `<button type="button" class="sl-price-more" aria-expanded="${!collapsed}">` + (collapsed ? t2("picker.showAllTicketTypes", { count: doc.categories.length }) : this.tf("picker.showFewer", "Show fewer")) + `</button>` : "") + `<div class="sl-status-key" aria-label="${this.tf("picker.seatStatusLegend", "Seat status legend")}"><span class="sl-status-item"><i class="sl-status-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></i>${this.tf("picker.temporarilyHeld", "Temporarily held")}</span><span class="sl-status-item"><i class="sl-status-icon sold" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M7 17L17 7"/></svg></i>${this.tf("picker.sold", "Sold")}</span></div>`;
|
|
5879
6025
|
this.els.prices.querySelectorAll(".sl-price-row").forEach((row) => {
|
|
5880
6026
|
row.addEventListener("mouseenter", () => this.controller.getRenderer()?.setCategoryHighlight?.(row.dataset.cat ?? null));
|
|
5881
6027
|
row.addEventListener("mouseleave", () => this.controller.getRenderer()?.setCategoryHighlight?.(null));
|
|
@@ -5933,7 +6079,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5933
6079
|
const now = left[cat.key] ?? 0;
|
|
5934
6080
|
if (before === void 0 || now >= before) continue;
|
|
5935
6081
|
const taken = before - now;
|
|
5936
|
-
textEl.textContent =
|
|
6082
|
+
textEl.textContent = tCount("picker.seatsJustTakenInCategory", taken, { label: cat.label, left: now });
|
|
5937
6083
|
this.els.live?.classList.remove("on");
|
|
5938
6084
|
void this.els.live?.offsetWidth;
|
|
5939
6085
|
this.els.live?.classList.add("on");
|
|
@@ -5951,12 +6097,17 @@ var SeatPicker = class _SeatPicker {
|
|
|
5951
6097
|
const gone = this.controller.getSelection().filter((s) => !ownLabels.has(s.label) && (this.controller.getStatus(s.id) ?? "free") !== "free");
|
|
5952
6098
|
if (!gone.length) return;
|
|
5953
6099
|
this.controller.deselect(gone.map((s) => s.id));
|
|
5954
|
-
this.toast(
|
|
6100
|
+
this.toast(t2("picker.seatJustTakenByAnother", { label: gone[0].label }), "error");
|
|
5955
6101
|
}
|
|
5956
6102
|
syncTray() {
|
|
5957
6103
|
if (!this.els.tray) return;
|
|
5958
6104
|
this.updateSelectionCapacity();
|
|
5959
6105
|
const seats = this.committedSelection();
|
|
6106
|
+
if (this.root?.dataset.layout === "narrow" && this.secCardEl && (this.hold || seats.length || this.pendingGACount())) {
|
|
6107
|
+
this.secCardEl.remove();
|
|
6108
|
+
this.secCardEl = null;
|
|
6109
|
+
this.lastSection = null;
|
|
6110
|
+
}
|
|
5960
6111
|
const gaAreas = this.controller.getGAAreas();
|
|
5961
6112
|
const heldItems = this.hold?.items ?? [];
|
|
5962
6113
|
const parts = [];
|
|
@@ -5967,18 +6118,22 @@ var SeatPicker = class _SeatPicker {
|
|
|
5967
6118
|
`<div class="sl-closed-note" role="status"><b>${this.tf("picker.salesClosedPill", "Sales are closed")}</b><span>${this.tf("picker.salesClosedCopy", "Ticket sales for this event have ended.")}${closedWhen}</span></div>`
|
|
5968
6119
|
);
|
|
5969
6120
|
} else if (!seats.length && !heldItems.length && !gaAreas.length) {
|
|
5970
|
-
parts.push(`<div class="sl-tray-hint"
|
|
6121
|
+
parts.push(`<div class="sl-tray-hint">${this.tf("picker.trayHintTapOrBest", "Tap a seat on the map, or let us pick the best available for you.")}</div>`);
|
|
5971
6122
|
} else if (!seats.length && !heldItems.length) {
|
|
5972
|
-
parts.push(`<div class="sl-tray-hint"
|
|
6123
|
+
parts.push(`<div class="sl-tray-hint">${this.tf("picker.trayHintTapOrStanding", "Tap a seat on the map \u2014 or grab standing tickets below.")}</div>`);
|
|
5973
6124
|
}
|
|
5974
6125
|
const noPicks = !seats.length && !heldItems.length && !this.pendingGACount();
|
|
5975
|
-
if (
|
|
6126
|
+
if (noPicks) this.baReopen = false;
|
|
6127
|
+
if (!this.salesClosed && !this.hold && (noPicks || this.baReopen || this.bestAvailableBusy || this.bestAvailableConfirm)) {
|
|
5976
6128
|
const cats = this.controller.doc?.categories ?? [];
|
|
5977
6129
|
const zones = this.controller.getBestAvailableZones();
|
|
5978
6130
|
if (this.baZone && !zones.some((zone) => zone.id === this.baZone)) this.baZone = "";
|
|
5979
|
-
parts.push(this.bestAvailableConfirm ? `<div class="sl-ba" role="alert"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span
|
|
6131
|
+
parts.push(this.bestAvailableConfirm ? `<div class="sl-ba" role="alert"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>${this.tf("picker.replaceCurrentChoices", "Replace your current choices?")}</div><div class="sl-ba-replace"><b>${t2("picker.willFindSeatsTogether", { count: this.baQty })}</b><span>${this.tf("picker.manualTicketsRemovedNote", "Your manually selected tickets will be removed only after a new group is secured.")}</span></div><div class="sl-ba-actions"><button type="button" data-ba-cancel>${this.tf("picker.keepMine", "Keep mine")}</button><button type="button" class="replace" data-ba-replace>${this.tf("picker.findNewSeats", "Find new seats")}</button></div></div>` : `<div class="sl-ba"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>${this.tf("picker.findBestSeatsTogether", "Find the best seats together")}</div><div class="sl-ba-copy"><span class="wide">${this.tf("picker.willChooseClosestGroup", "We\u2019ll choose the closest available group for you.")}</span><span class="narrow">${this.tf("picker.closestGroupChosenInstantly", "Closest available group, chosen instantly.")}</span></div>` + // Premium quick-pick — present only when the chart actually has premium
|
|
5980
6132
|
// seats (same present-only philosophy as the a11y filter chips).
|
|
5981
|
-
(this.controller.hasPremiumSeats() ? `<button type="button" class="sl-ba-premium${this.baPremium ? " on" : ""}" data-ba-premium aria-pressed="${this.baPremium ? "true" : "false"}"><span class="star" aria-hidden="true">\u2605</span>${this.tf("picker.bestSeatsPremium", "Best seats")}</button>` : "") + (cats.length > 1 ? `<select aria-label="Preferred ticket type" data-ba-cat><option value=""
|
|
6133
|
+
(this.controller.hasPremiumSeats() ? `<button type="button" class="sl-ba-premium${this.baPremium ? " on" : ""}" data-ba-premium aria-pressed="${this.baPremium ? "true" : "false"}"><span class="star" aria-hidden="true">\u2605</span>${this.tf("picker.bestSeatsPremium", "Best seats")}</button>` : "") + (cats.length > 1 ? `<select aria-label="${this.tf("picker.preferredTicketType", "Preferred ticket type")}" data-ba-cat><option value="">${this.tf("picker.anyTicketType", "Any ticket type")}</option>` + cats.map((c) => `<option value="${c.key}"${this.baCat === c.key ? " selected" : ""}>${c.label}</option>`).join("") + `</select>` : `<span aria-hidden="true"></span>`) + (zones.length ? `<select aria-label="${this.tf("picker.preferredVenueZone", "Preferred venue zone")}" data-ba-zone><option value="">${this.tf("picker.anyVenueZone", "Any venue zone")}</option>` + zones.map((zone) => `<option value="${escapeOption(zone.id)}"${this.baZone === zone.id ? " selected" : ""}>${escapeOption(zone.label)}</option>`).join("") + `</select>` : "") + `<div class="sl-ba-qty"><button type="button" data-ba="-1" aria-label="${this.tf("picker.fewerSeats", "Fewer seats")}">\u2212</button><span>${this.baQty}</span><button type="button" data-ba="1" aria-label="${this.tf("picker.moreSeats", "More seats")}">+</button></div><button type="button" class="sl-ba-go${this.bestAvailableBusy ? " sl-busy" : ""}"${this.bestAvailableBusy ? " disabled" : ""}>` + (this.bestAvailableBusy ? `<span class="sl-ba-spin" aria-hidden="true"></span>${this.tf("picker.findingBestSeats", "Finding the best seats\u2026")}` : tCount("picker.findBestSeatsCount", this.baQty)) + `</button>` + // Reopened over an existing selection: the buyer needs the way back
|
|
6134
|
+
// stated as plainly as the way forward (Go routes through the
|
|
6135
|
+
// "Replace your current choices?" confirm, so nothing is lost yet).
|
|
6136
|
+
(this.baReopen ? `<button type="button" class="sl-ba-back" data-ba-close>${this.tf("picker.keepMyPicks", "Keep my picks")}</button>` : "") + `</div>`);
|
|
5982
6137
|
}
|
|
5983
6138
|
const idGrid = (seatId, label, objectType, quantity = 1, objectId, identity) => {
|
|
5984
6139
|
const esc = (value) => String(value ?? "\u2014").replace(/[&<>"]/g, (char) => ({
|
|
@@ -5990,21 +6145,21 @@ var SeatPicker = class _SeatPicker {
|
|
|
5990
6145
|
const d = seatId ? this.controller.seatDetails(seatId) : null;
|
|
5991
6146
|
const area = objectType === "ga" ? gaAreas.find((candidate) => candidate.id === objectId) : void 0;
|
|
5992
6147
|
const effectiveType = objectType === "ga" ? "ga" : d?.objectType ?? objectType;
|
|
5993
|
-
const typeWord = identity?.displayType?.trim() || d?.displayType?.trim() || area?.displayType?.trim() || (effectiveType === "table" ? "Table" : effectiveType === "booth" ? "Booth" : effectiveType === "ga" ? "General admission" : "Row");
|
|
6148
|
+
const typeWord = identity?.displayType?.trim() || d?.displayType?.trim() || area?.displayType?.trim() || (effectiveType === "table" ? this.tf("picker.table", "Table") : effectiveType === "booth" ? this.tf("picker.booth", "Booth") : effectiveType === "ga" ? this.tf("picker.generalAdmission", "General admission") : this.tf("picker.row", "Row"));
|
|
5994
6149
|
const buyerName = identity?.rowLabel ?? identity?.displayLabel ?? d?.rowLabel ?? d?.displayLabel ?? area?.displayLabel ?? area?.label ?? label;
|
|
5995
6150
|
if (effectiveType === "table" && identity?.bookingMode) {
|
|
5996
|
-
return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span><span class="fld mid"><span class="sl-chip-eb"
|
|
6151
|
+
return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span><span class="fld mid"><span class="sl-chip-eb">${this.tf("picker.guests", "Guests")}</span><span class="val">${quantity}</span></span></div>`;
|
|
5997
6152
|
}
|
|
5998
6153
|
if (effectiveType === "ga") {
|
|
5999
|
-
return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span>` + (quantity > 1 ? `<span class="fld mid"><span class="sl-chip-eb"
|
|
6154
|
+
return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span>` + (quantity > 1 ? `<span class="fld mid"><span class="sl-chip-eb">${this.tf("picker.tickets", "Tickets")}</span><span class="val">${quantity}</span></span>` : "") + `</div>`;
|
|
6000
6155
|
}
|
|
6001
6156
|
if (effectiveType === "booth") {
|
|
6002
|
-
return `<div class="sl-chip-id">` + (d?.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb"
|
|
6157
|
+
return `<div class="sl-chip-id">` + (d?.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb">${this.tf("picker.section", "Section")}</span><span class="val">${esc(d.sectionLabel)}</span></span>` : "") + `<span class="fld mid"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(buyerName)}</span></span></div>`;
|
|
6003
6158
|
}
|
|
6004
6159
|
if (!d?.sectionLabel && !d?.rowLabel && !d?.seatNumber) {
|
|
6005
|
-
return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb"
|
|
6160
|
+
return `<div class="sl-chip-id"><span class="fld sec"><span class="sl-chip-eb">${this.tf("picker.seat", "Seat")}</span><span class="val">${esc(buyerName)}</span></span></div>`;
|
|
6006
6161
|
}
|
|
6007
|
-
return `<div class="sl-chip-id">` + (d.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb"
|
|
6162
|
+
return `<div class="sl-chip-id">` + (d.sectionLabel ? `<span class="fld sec"><span class="sl-chip-eb">${this.tf("picker.section", "Section")}</span><span class="val">${esc(d.sectionLabel)}</span></span>` : "") + (d.rowLabel ? `<span class="fld mid"><span class="sl-chip-eb">${esc(typeWord)}</span><span class="val">${esc(this.rowShort(d))}</span></span>` : "") + (d.seatNumber ? `<span class="fld mid"><span class="sl-chip-eb">${this.tf("picker.seat", "Seat")}</span><span class="val">${esc(d.seatNumber)}</span></span>` : "") + `</div>`;
|
|
6008
6163
|
};
|
|
6009
6164
|
const iconRail = (rmAria, viewLabel) => `<div class="sl-chip-rail"><button type="button" class="rm" aria-label="${rmAria}"><svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>` + (viewLabel ? `<button type="button" class="view" data-view-label="${viewLabel}" aria-label="${t2("picker.viewFromSeat", { label: viewLabel })}"><svg viewBox="0 0 24 24"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg></button>` : "") + `</div>`;
|
|
6010
6165
|
for (const item of heldItems) {
|
|
@@ -6016,7 +6171,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6016
6171
|
const table = item.objectType === "table" ? this.controller.tableSelection(item.label) : null;
|
|
6017
6172
|
const canView2 = this.seatViewEnabled() && !!heldSeat && item.objectType !== "table";
|
|
6018
6173
|
parts.push(
|
|
6019
|
-
`<div class="sl-chip sl-held${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-held="${encodeURIComponent(item.label)}"${heldSeat ? ` data-locate="${heldSeat.id}"` : ""}><div class="sl-chip-main">` + idGrid(heldSeat?.id ?? null, item.label, item.objectType, item.quantity ?? 1, item.objectId, table ?? void 0) + `<div class="sl-chip-sub"><span class="sl-ticket-state held" aria-label="Held for you" title="Held for you"><svg viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></span><span class="cat">${cat?.label ?? item.categoryKey}${tierName ? ` \xB7 ${tierName}` : ""}</span>` + (table?.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(item.label)}">${item.quantity ?? 1}
|
|
6174
|
+
`<div class="sl-chip sl-held${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-held="${encodeURIComponent(item.label)}"${heldSeat ? ` data-locate="${heldSeat.id}"` : ""}><div class="sl-chip-main">` + idGrid(heldSeat?.id ?? null, item.label, item.objectType, item.quantity ?? 1, item.objectId, table ?? void 0) + `<div class="sl-chip-sub"><span class="sl-ticket-state held" aria-label="${this.tf("picker.heldForYou", "Held for you")}" title="${this.tf("picker.heldForYou", "Held for you")}"><svg viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg></span><span class="cat">${cat?.label ?? item.categoryKey}${tierName ? ` \xB7 ${tierName}` : ""}</span>` + (table?.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(item.label)}">${t2("picker.guestsCountEdit", { count: item.quantity ?? 1 })}</button>` : "") + this.wheelchairChipMarker(heldSeat?.wheelchairSpaceType) + this.commercialChipMarker(heldSeat?.commercial) + `<span class="amt">${this.money(this.paidPrice(item.categoryKey, item.tierId, item.unitPrice) * (item.quantity ?? 1))}</span></div></div>` + iconRail(t2("picker.removeHeldTicketLabel", { label: item.label }), canView2 ? item.label : null) + `</div>`
|
|
6020
6175
|
);
|
|
6021
6176
|
}
|
|
6022
6177
|
const heldLabels = new Set(heldItems.map((item) => item.label));
|
|
@@ -6027,13 +6182,18 @@ var SeatPicker = class _SeatPicker {
|
|
|
6027
6182
|
const cat = this.controller.doc?.categories.find((c) => c.key === s.categoryKey);
|
|
6028
6183
|
const tierSelect = s.tiers && s.tiers.length ? `<select class="tier" data-tier="${s.id}" aria-label="${t2("picker.ticketTierFor", { label: s.label })}">` + s.tiers.map((ti) => `<option value="${ti.id}"${ti.id === s.tierId ? " selected" : ""}>${ti.name} \xB7 ${this.money(this.paidPrice(s.categoryKey, ti.id, ti.price))}</option>`).join("") + `</select>` : "";
|
|
6029
6184
|
parts.push(
|
|
6030
|
-
`<div class="sl-chip${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-seat="${s.id}" data-locate="${s.id}"><div class="sl-chip-main">` + idGrid(s.id, s.label, s.objectType, s.quantity ?? 1, s.objectId, s) + `<div class="sl-chip-sub"><span class="sl-ticket-state" aria-label="Selected" title="Selected"><svg viewBox="0 0 24 24"><path d="M5 12l4 4L19 6"/></svg></span><span class="cat">${cat?.label ?? s.categoryKey}</span>` + (s.objectType === "table" && s.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(s.label)}">${s.quantity ?? 1}
|
|
6185
|
+
`<div class="sl-chip${this.lastTrayKeys.has(itemKey) ? "" : " sl-enter"}" data-key="${itemKey}" data-seat="${s.id}" data-locate="${s.id}"><div class="sl-chip-main">` + idGrid(s.id, s.label, s.objectType, s.quantity ?? 1, s.objectId, s) + `<div class="sl-chip-sub"><span class="sl-ticket-state" aria-label="${this.tf("picker.selected", "Selected")}" title="${this.tf("picker.selected", "Selected")}"><svg viewBox="0 0 24 24"><path d="M5 12l4 4L19 6"/></svg></span><span class="cat">${cat?.label ?? s.categoryKey}</span>` + (s.objectType === "table" && s.bookingMode === "variable" ? `<button type="button" class="sl-table-edit" data-table-edit="${encodeURIComponent(s.label)}">${t2("picker.guestsCountEdit", { count: s.quantity ?? 1 })}</button>` : "") + `${this.wheelchairChipMarker(s.wheelchairSpaceType)}${this.commercialChipMarker(s.commercial)}${tierSelect}<span class="amt">${this.money(this.paidPrice(s.categoryKey, s.tierId ?? null, s.price) * (s.quantity ?? 1))}</span></div></div>` + iconRail(t2("picker.removeSeatLabel", { label: s.label }), canView && s.objectType !== "table" ? s.label : null) + `</div>`
|
|
6031
6186
|
);
|
|
6032
6187
|
}
|
|
6033
6188
|
for (const area of gaAreas) {
|
|
6034
6189
|
const qty = this.gaQty.get(area.id) ?? 0;
|
|
6035
6190
|
parts.push(
|
|
6036
|
-
`<div class="sl-ga" data-ga="${area.id}"><div class="sl-ga-info"><div class="sl-ga-name">${area.displayLabel ?? area.label}</div><div class="sl-ga-sub">${area.displayType ?? "General admission"} \xB7 ${this.money(this.paidPrice(area.categoryKey, null, area.price))} \xB7 ${area.available}
|
|
6191
|
+
`<div class="sl-ga" data-ga="${area.id}"><div class="sl-ga-info"><div class="sl-ga-name">${area.displayLabel ?? area.label}</div><div class="sl-ga-sub">${area.displayType ?? this.tf("picker.generalAdmission", "General admission")} \xB7 ${this.money(this.paidPrice(area.categoryKey, null, area.price))} \xB7 ${tCount("picker.leftCount", area.available)}</div></div><div class="sl-ga-qty"><button type="button" data-d="-1" aria-label="${this.tf("picker.fewer", "Fewer")}">\u2212</button><span>${qty}</span><button type="button" data-d="1" aria-label="${this.tf("picker.more", "More")}">+</button></div></div>`
|
|
6192
|
+
);
|
|
6193
|
+
}
|
|
6194
|
+
if (!this.salesClosed && !this.hold && !noPicks && !this.baReopen && !this.bestAvailableBusy && !this.bestAvailableConfirm) {
|
|
6195
|
+
parts.push(
|
|
6196
|
+
`<button type="button" class="sl-ba-reopen" data-ba-reopen><span aria-hidden="true">\u2726</span>${this.tf("picker.findTogetherInstead", "Find seats together instead")}</button>`
|
|
6037
6197
|
);
|
|
6038
6198
|
}
|
|
6039
6199
|
this.els.tray.innerHTML = parts.join("");
|
|
@@ -6068,6 +6228,16 @@ var SeatPicker = class _SeatPicker {
|
|
|
6068
6228
|
this.syncTray();
|
|
6069
6229
|
this.els.tray.querySelector(".sl-ba-go")?.focus();
|
|
6070
6230
|
});
|
|
6231
|
+
this.els.tray.querySelector("[data-ba-reopen]")?.addEventListener("click", () => {
|
|
6232
|
+
this.baReopen = true;
|
|
6233
|
+
this.syncTray();
|
|
6234
|
+
this.els.tray.querySelector(".sl-ba-go")?.focus();
|
|
6235
|
+
});
|
|
6236
|
+
this.els.tray.querySelector("[data-ba-close]")?.addEventListener("click", () => {
|
|
6237
|
+
this.baReopen = false;
|
|
6238
|
+
this.syncTray();
|
|
6239
|
+
this.els.tray.querySelector("[data-ba-reopen]")?.focus();
|
|
6240
|
+
});
|
|
6071
6241
|
this.els.tray.querySelector("[data-ba-replace]")?.addEventListener("click", () => {
|
|
6072
6242
|
this.bestAvailableConfirm = false;
|
|
6073
6243
|
void this.bestAvailable(this.baQty, this.baCat || void 0, { preferPremium: this.baPremium, zoneId: this.baZone || void 0 });
|
|
@@ -6080,15 +6250,15 @@ var SeatPicker = class _SeatPicker {
|
|
|
6080
6250
|
return;
|
|
6081
6251
|
}
|
|
6082
6252
|
const id = chip.dataset.seat;
|
|
6083
|
-
const label = this.controller.getSelection().find((sel) => sel.id === id)?.label ?? "Seat";
|
|
6253
|
+
const label = this.controller.getSelection().find((sel) => sel.id === id)?.label ?? this.tf("picker.seat", "Seat");
|
|
6084
6254
|
const remove = () => {
|
|
6085
6255
|
this.controller.deselect([id]);
|
|
6086
|
-
this.toast(
|
|
6087
|
-
label: "Undo",
|
|
6256
|
+
this.toast(t2("picker.labelRemoved", { label }), "neutral", {
|
|
6257
|
+
label: this.tf("picker.undo", "Undo"),
|
|
6088
6258
|
onClick: () => {
|
|
6089
6259
|
const restored = this.controller.select([id]);
|
|
6090
6260
|
this.toast(
|
|
6091
|
-
restored.length ?
|
|
6261
|
+
restored.length ? t2("picker.labelRestored", { label }) : t2("picker.labelNoLongerAvailable", { label }),
|
|
6092
6262
|
restored.length ? "success" : "warning"
|
|
6093
6263
|
);
|
|
6094
6264
|
}
|
|
@@ -6160,30 +6330,31 @@ var SeatPicker = class _SeatPicker {
|
|
|
6160
6330
|
const pendingCount = this.pendingSelectionCount();
|
|
6161
6331
|
const previousCount = this.lastTrayCount;
|
|
6162
6332
|
const previousTotal = this.lastTrayTotal;
|
|
6163
|
-
this.els.count.textContent = count ?
|
|
6333
|
+
this.els.count.textContent = count ? tCount("picker.ticketsCount", count) : this.tf("picker.noSeatsSelected", "No seats selected");
|
|
6164
6334
|
this.els.total.textContent = count ? this.money(total) : "";
|
|
6165
6335
|
this.root?.setAttribute("data-has-selection", String(count > 0));
|
|
6166
6336
|
this.root?.setAttribute(
|
|
6167
6337
|
"data-ba-active",
|
|
6168
|
-
String(this.bestAvailableConfirm || this.bestAvailableBusy)
|
|
6338
|
+
String(this.bestAvailableConfirm || this.bestAvailableBusy || this.baReopen)
|
|
6169
6339
|
);
|
|
6170
6340
|
this.els.foot?.classList.toggle("empty", count === 0);
|
|
6171
6341
|
if (this.els.seatSummary) {
|
|
6172
|
-
this.els.seatSummary.textContent = count ?
|
|
6342
|
+
this.els.seatSummary.textContent = count ? tCount("picker.seatsSelectedCount", count) : "";
|
|
6173
6343
|
}
|
|
6174
6344
|
this.syncCta(count, pendingCount);
|
|
6175
6345
|
if (this.hold) {
|
|
6176
6346
|
const securedCount = heldCount || this.hold.seats?.length || 0;
|
|
6177
6347
|
if (this.els.holdTitle) {
|
|
6178
|
-
this.els.holdTitle.textContent =
|
|
6348
|
+
this.els.holdTitle.textContent = t2("picker.securedCount", { count: securedCount });
|
|
6179
6349
|
}
|
|
6180
6350
|
if (this.els.holdCopy) {
|
|
6181
|
-
this.
|
|
6351
|
+
this.holdCopyPending = pendingCount > 0;
|
|
6352
|
+
this.els.holdCopy.textContent = pendingCount ? t2("picker.moreSelectedCount", { count: pendingCount }) : this.holdReassuranceText();
|
|
6182
6353
|
}
|
|
6183
6354
|
const change = this.els.holdChange;
|
|
6184
6355
|
if (change) {
|
|
6185
6356
|
change.disabled = this.releasingHold;
|
|
6186
|
-
change.textContent = this.releasingHold ? "Releasing\u2026" : "Change";
|
|
6357
|
+
change.textContent = this.releasingHold ? this.tf("picker.releasingEllipsis", "Releasing\u2026") : this.tf("picker.change", "Change");
|
|
6187
6358
|
}
|
|
6188
6359
|
}
|
|
6189
6360
|
if (count !== previousCount) this.animateOnce(this.els.count, "sl-value-pop", 380);
|
|
@@ -6192,21 +6363,39 @@ var SeatPicker = class _SeatPicker {
|
|
|
6192
6363
|
this.animateOnce(this.els.cta, "sl-ready", 520);
|
|
6193
6364
|
if (this.sideCollapsed && this.root?.dataset.layout !== "narrow") this.setPanelCollapsed(false);
|
|
6194
6365
|
}
|
|
6195
|
-
|
|
6196
|
-
if (count) {
|
|
6197
|
-
const holding = !!this.hold && !pendingCount;
|
|
6198
|
-
this.els.peek.innerHTML = `<span>${count} ${count === 1 ? "ticket" : "tickets"} \xB7 ${this.money(total)}</span><button type="button" class="go sl-sheet-go" data-act="${holding ? "checkout" : "open"}">${this.hold ? pendingCount ? "Secure more" : "Continue" : "Review"}</button>`;
|
|
6199
|
-
} else if (this.salesClosed) {
|
|
6200
|
-
this.els.peek.innerHTML = `<span>${this.tf("picker.salesClosedPill", "Sales are closed")}</span>`;
|
|
6201
|
-
} else {
|
|
6202
|
-
const prices = (this.controller.doc?.categories ?? []).map((c) => this.catPrice(c)).filter((p) => p != null);
|
|
6203
|
-
this.els.peek.innerHTML = (prices.length ? `<span>From ${this.money(Math.min(...prices))}</span>` : "<span>Pick your seats</span>") + `<button type="button" class="go sl-sheet-go" data-act="open">\u2726 Best seats</button>`;
|
|
6204
|
-
}
|
|
6205
|
-
}
|
|
6366
|
+
this.renderPeek(count, total, pendingCount);
|
|
6206
6367
|
this.lastTrayCount = count;
|
|
6207
6368
|
this.lastTrayTotal = total;
|
|
6208
6369
|
this.opts.onSelectionChange?.(seats);
|
|
6209
6370
|
}
|
|
6371
|
+
/**
|
|
6372
|
+
* The bottom-sheet's collapsed one-liner. Called from syncTray on every
|
|
6373
|
+
* repaint AND from setCtaPhase: while the widget is securing seats or
|
|
6374
|
+
* opening checkout, the peek is the phone buyer's ONLY line of sight, and a
|
|
6375
|
+
* pill still reading "Continue" at the moment money is about to move is the
|
|
6376
|
+
* emotional trapdoor the audit flagged. The phase lines restate what is
|
|
6377
|
+
* secured and promise no charge yet.
|
|
6378
|
+
*/
|
|
6379
|
+
renderPeek(count, total, pendingCount) {
|
|
6380
|
+
if (!this.els.peek) return;
|
|
6381
|
+
if (count && this.ctaPhase === "holding") {
|
|
6382
|
+
this.els.peek.innerHTML = `<span>${this.tf("picker.securingSeats", "Securing your seats\u2026")}</span>`;
|
|
6383
|
+
return;
|
|
6384
|
+
}
|
|
6385
|
+
if (count && this.ctaPhase === "checkout") {
|
|
6386
|
+
this.els.peek.innerHTML = `<span>${t2("picker.peekSecured", { count, total: this.money(total) })}</span>`;
|
|
6387
|
+
return;
|
|
6388
|
+
}
|
|
6389
|
+
if (count) {
|
|
6390
|
+
const toCheckout = !!this.hold;
|
|
6391
|
+
this.els.peek.innerHTML = `<span>${tCount("picker.peekTicketsTotal", count, { total: this.money(total) })}</span><button type="button" class="go sl-sheet-go" data-act="${toCheckout ? "checkout" : "open"}">${this.hold ? pendingCount ? this.tf("picker.secureMore", "Secure more") : this.tf("picker.continue", "Continue") : this.tf("picker.review", "Review")}</button>`;
|
|
6392
|
+
} else if (this.salesClosed) {
|
|
6393
|
+
this.els.peek.innerHTML = `<span>${this.tf("picker.salesClosedPill", "Sales are closed")}</span>`;
|
|
6394
|
+
} else {
|
|
6395
|
+
const prices = (this.controller.doc?.categories ?? []).map((c) => this.catPrice(c)).filter((p) => p != null);
|
|
6396
|
+
this.els.peek.innerHTML = (prices.length ? `<span>${t2("picker.peekFromPrice", { price: this.money(Math.min(...prices)) })}</span>` : `<span>${this.tf("picker.pickYourSeats", "Pick your seats")}</span>`) + `<button type="button" class="go sl-sheet-go" data-act="open">${this.tf("picker.bestSeatsStar", "\u2726 Best seats")}</button>`;
|
|
6397
|
+
}
|
|
6398
|
+
}
|
|
6210
6399
|
async removeHeldLabel(label, chip) {
|
|
6211
6400
|
if (!label || this.releasingLabels.has(label)) return false;
|
|
6212
6401
|
this.releasingLabels.add(label);
|
|
@@ -6217,7 +6406,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6217
6406
|
const preserveAcrossNavigation = this.handedOff;
|
|
6218
6407
|
const released = await this.controller.releaseLabels([label]);
|
|
6219
6408
|
if (!released) {
|
|
6220
|
-
this.toast(
|
|
6409
|
+
this.toast(t2("picker.couldNotRemoveLabel", { label }), "error");
|
|
6221
6410
|
return false;
|
|
6222
6411
|
}
|
|
6223
6412
|
const remaining = this.controller.currentHold();
|
|
@@ -6233,7 +6422,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6233
6422
|
}
|
|
6234
6423
|
this.syncTray();
|
|
6235
6424
|
this.emitHoldChange();
|
|
6236
|
-
this.toast(
|
|
6425
|
+
this.toast(t2("picker.labelRemovedFromHold", { label }), "success");
|
|
6237
6426
|
return true;
|
|
6238
6427
|
} finally {
|
|
6239
6428
|
this.releasingLabels.delete(label);
|
|
@@ -6247,23 +6436,23 @@ var SeatPicker = class _SeatPicker {
|
|
|
6247
6436
|
const button = this.els.holdChange;
|
|
6248
6437
|
if (button) {
|
|
6249
6438
|
button.disabled = true;
|
|
6250
|
-
button.textContent = "Releasing\u2026";
|
|
6439
|
+
button.textContent = this.tf("picker.releasingEllipsis", "Releasing\u2026");
|
|
6251
6440
|
}
|
|
6252
6441
|
try {
|
|
6253
6442
|
await this.release();
|
|
6254
|
-
if (!this.hold) this.toast("Held tickets released. Choose your new seats.", "success");
|
|
6443
|
+
if (!this.hold) this.toast(this.tf("picker.heldTicketsReleased", "Held tickets released. Choose your new seats."), "success");
|
|
6255
6444
|
} finally {
|
|
6256
6445
|
this.releasingHold = false;
|
|
6257
6446
|
if (button?.isConnected) {
|
|
6258
6447
|
button.disabled = false;
|
|
6259
|
-
button.textContent = "Change";
|
|
6448
|
+
button.textContent = this.tf("picker.change", "Change");
|
|
6260
6449
|
}
|
|
6261
6450
|
}
|
|
6262
6451
|
}
|
|
6263
6452
|
async handleCta() {
|
|
6264
6453
|
if (this.salesClosed) return;
|
|
6265
6454
|
if (this.totalTicketCount() > this.maxTickets) {
|
|
6266
|
-
this.toast(
|
|
6455
|
+
this.toast(t2("picker.removeTicketsUntilOrFewer", { count: this.maxTickets }), "warning");
|
|
6267
6456
|
return;
|
|
6268
6457
|
}
|
|
6269
6458
|
const committed = this.committedSelection();
|
|
@@ -6289,7 +6478,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6289
6478
|
hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : hold;
|
|
6290
6479
|
}
|
|
6291
6480
|
if (!hold) {
|
|
6292
|
-
this.toast("One or more seats were just taken. Please pick again.", "error");
|
|
6481
|
+
this.toast(this.tf("picker.seatsJustTaken", "One or more seats were just taken. Please pick again."), "error");
|
|
6293
6482
|
this.setCtaPhase("idle");
|
|
6294
6483
|
this.syncTray();
|
|
6295
6484
|
return;
|
|
@@ -6306,7 +6495,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6306
6495
|
const problem = err;
|
|
6307
6496
|
const labels = (problem.conflicts ?? []).map((conflict) => conflict.label).filter(Boolean).slice(0, 3);
|
|
6308
6497
|
if (problem.reason === "event_closed") this.setSalesClosed(true);
|
|
6309
|
-
const message = problem.reason === "event_closed" ? "Seat sales have closed for this event." : labels.length ?
|
|
6498
|
+
const message = problem.reason === "event_closed" ? this.tf("picker.seatSalesClosedForEvent", "Seat sales have closed for this event.") : labels.length ? labels.length === 1 ? t2("picker.labelsNoLongerAvailable.one", { labels: labels.join(", ") }) : t2("picker.labelsNoLongerAvailable.other", { labels: labels.join(", ") }) : this.tf("picker.seatsJustTaken", "One or more seats were just taken. Please pick again.");
|
|
6310
6499
|
this.toast(message, "error");
|
|
6311
6500
|
this.setCtaPhase("idle");
|
|
6312
6501
|
} finally {
|
|
@@ -6315,12 +6504,19 @@ var SeatPicker = class _SeatPicker {
|
|
|
6315
6504
|
this.syncTray();
|
|
6316
6505
|
}
|
|
6317
6506
|
}
|
|
6507
|
+
/** "Yours for m:ss — you won't be charged yet." — the hold note's promise. */
|
|
6508
|
+
holdReassuranceText() {
|
|
6509
|
+
const ms = Math.max(0, this.holdExpiresAt - Date.now());
|
|
6510
|
+
const m = Math.floor(ms / 6e4);
|
|
6511
|
+
const s = String(Math.floor(ms % 6e4 / 1e3)).padStart(2, "0");
|
|
6512
|
+
return t2("picker.holdReassurance", { time: `${m}:${s}` });
|
|
6513
|
+
}
|
|
6318
6514
|
startHoldTimer(expiresAt) {
|
|
6319
6515
|
this.stopHoldTimer();
|
|
6320
6516
|
this.holdExpiresAt = expiresAt;
|
|
6321
6517
|
if (this.hold) this.rememberHold(this.hold);
|
|
6322
6518
|
const pill = this.els.hold;
|
|
6323
|
-
pill.innerHTML =
|
|
6519
|
+
pill.innerHTML = `<span class="sl-hold-dot" aria-hidden="true"></span><span>${this.tf("picker.held", "Held")}</span><span class="sl-hold-time" data-ref="holdTime"></span>`;
|
|
6324
6520
|
const time = pill.querySelector('[data-ref="holdTime"]');
|
|
6325
6521
|
this.els.holdNote?.classList.add("on");
|
|
6326
6522
|
const tick = () => {
|
|
@@ -6328,6 +6524,9 @@ var SeatPicker = class _SeatPicker {
|
|
|
6328
6524
|
const m = Math.floor(ms / 6e4);
|
|
6329
6525
|
const s = String(Math.floor(ms % 6e4 / 1e3)).padStart(2, "0");
|
|
6330
6526
|
if (time) time.textContent = `${m}:${s}`;
|
|
6527
|
+
if (!this.holdCopyPending && this.els.holdCopy) {
|
|
6528
|
+
this.els.holdCopy.textContent = this.holdReassuranceText();
|
|
6529
|
+
}
|
|
6331
6530
|
pill.classList.add("on");
|
|
6332
6531
|
pill.classList.toggle("is-expiring", ms > 0 && ms <= EXTEND_PROMPT_MS);
|
|
6333
6532
|
this.setExtendPrompt(ms > 0 && ms <= EXTEND_PROMPT_MS, ms);
|
|
@@ -6347,8 +6546,10 @@ var SeatPicker = class _SeatPicker {
|
|
|
6347
6546
|
setExtendPrompt(show, ms) {
|
|
6348
6547
|
if (!this.extendEl) return;
|
|
6349
6548
|
if (show && this.controller.currentHold() && !this.bookedShown) {
|
|
6350
|
-
const
|
|
6351
|
-
|
|
6549
|
+
const totalSecs = Math.ceil(ms / 1e3);
|
|
6550
|
+
const m = Math.floor(totalSecs / 60);
|
|
6551
|
+
const s = String(totalSecs % 60).padStart(2, "0");
|
|
6552
|
+
this.els.extendTxt.innerHTML = t2("picker.seatsHeldForNeedMoreTime", { time: `${m}:${s}` });
|
|
6352
6553
|
this.extendEl.classList.add("on");
|
|
6353
6554
|
} else {
|
|
6354
6555
|
this.extendEl.classList.remove("on");
|
|
@@ -6358,7 +6559,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6358
6559
|
const btn = this.els.extendBtn;
|
|
6359
6560
|
btn.disabled = true;
|
|
6360
6561
|
const prev = btn.textContent;
|
|
6361
|
-
btn.textContent = "Adding\u2026";
|
|
6562
|
+
btn.textContent = this.tf("picker.addingEllipsis", "Adding\u2026");
|
|
6362
6563
|
try {
|
|
6363
6564
|
const h = await this.controller.extendHold(this.opts.holdTtlMs);
|
|
6364
6565
|
if (h) {
|
|
@@ -6367,13 +6568,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
6367
6568
|
this.extendEl?.classList.remove("on");
|
|
6368
6569
|
this.rememberHold(this.hold);
|
|
6369
6570
|
this.emitHoldChange();
|
|
6370
|
-
this.toast("More time added \u2014 your seats are still held.", "success");
|
|
6571
|
+
this.toast(this.tf("picker.moreTimeAdded", "More time added \u2014 your seats are still held."), "success");
|
|
6371
6572
|
} else {
|
|
6372
|
-
this.toast("Couldn't add more time \u2014 please head to checkout now.", "warning");
|
|
6573
|
+
this.toast(this.tf("picker.couldNotAddMoreTime", "Couldn't add more time \u2014 please head to checkout now."), "warning");
|
|
6373
6574
|
}
|
|
6374
6575
|
} catch (err) {
|
|
6375
6576
|
this.opts.onError?.(err);
|
|
6376
|
-
this.toast("Couldn't add more time \u2014 please head to checkout now.", "warning");
|
|
6577
|
+
this.toast(this.tf("picker.couldNotAddMoreTime", "Couldn't add more time \u2014 please head to checkout now."), "warning");
|
|
6377
6578
|
} finally {
|
|
6378
6579
|
btn.disabled = false;
|
|
6379
6580
|
btn.textContent = prev;
|
|
@@ -6400,7 +6601,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6400
6601
|
this.forgetHold();
|
|
6401
6602
|
const n = handoff.lineItems.reduce((sum, i) => sum + i.quantity, 0);
|
|
6402
6603
|
if (this.els.bookedSub) {
|
|
6403
|
-
this.els.bookedSub.innerHTML = `<span class="sl-booked-seats">${n} ${
|
|
6604
|
+
this.els.bookedSub.innerHTML = `<span class="sl-booked-seats">${tCount("picker.ticketsCount", n)}</span> ${this.tf("picker.confirmedAndOnWay", "confirmed. A confirmation is on its way.")}`;
|
|
6404
6605
|
}
|
|
6405
6606
|
this.bookedEl?.classList.add("on");
|
|
6406
6607
|
this.opts.onBooked?.(handoff);
|
|
@@ -6482,7 +6683,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6482
6683
|
({ mountCheckout } = await loadHostedCheckout());
|
|
6483
6684
|
} catch (err) {
|
|
6484
6685
|
this.opts.onError?.(err);
|
|
6485
|
-
this.toast("Checkout could not be opened. Your seats are still held \u2014 please try again.", "error");
|
|
6686
|
+
this.toast(this.tf("picker.checkoutCouldNotBeOpened", "Checkout could not be opened. Your seats are still held \u2014 please try again."), "error");
|
|
6486
6687
|
this.setCtaPhase("idle");
|
|
6487
6688
|
return;
|
|
6488
6689
|
}
|
|
@@ -6597,9 +6798,9 @@ var SeatPicker = class _SeatPicker {
|
|
|
6597
6798
|
rowTypeWord(details) {
|
|
6598
6799
|
const authored = details?.displayType?.trim() || details?.rowType?.trim();
|
|
6599
6800
|
if (authored) return authored;
|
|
6600
|
-
if (details?.objectType === "table") return "Table";
|
|
6601
|
-
if (details?.objectType === "booth") return "Booth";
|
|
6602
|
-
return "Row";
|
|
6801
|
+
if (details?.objectType === "table") return this.tf("picker.table", "Table");
|
|
6802
|
+
if (details?.objectType === "booth") return this.tf("picker.booth", "Booth");
|
|
6803
|
+
return this.tf("picker.row", "Row");
|
|
6603
6804
|
}
|
|
6604
6805
|
rowShort(details) {
|
|
6605
6806
|
const row = details?.rowLabel;
|
|
@@ -6622,7 +6823,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6622
6823
|
const isGroupedTable = details.objectType === "table" && !!details.bookingMode;
|
|
6623
6824
|
const isBooth = details.objectType === "booth";
|
|
6624
6825
|
const hasLoc = details.sectionLabel || details.rowLabel || details.seatNumber;
|
|
6625
|
-
const grid = isGroupedTable ? `<div class="sl-tip-grid"><div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div><div class="sl-tip-field"><span class="sl-tip-key"
|
|
6826
|
+
const grid = isGroupedTable ? `<div class="sl-tip-grid"><div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div><div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.guests", "Guests")}</span><span class="sl-tip-val">${details.bookingMode === "variable" ? `${details.minOccupancy}\u2013${details.maxOccupancy}` : details.capacity}</span></div></div>` : isBooth ? `<div class="sl-tip-grid">` + (details.sectionLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.section", "Section")}</span><span class="sl-tip-val">${esc(details.sectionLabel)}</span></div>` : "") + `<div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(details.rowLabel ?? details.displayLabel ?? details.label)}</span></div></div>` : hasLoc ? `<div class="sl-tip-grid">` + (details.sectionLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.section", "Section")}</span><span class="sl-tip-val">${esc(details.sectionLabel)}</span></div>` : "") + (details.rowLabel ? `<div class="sl-tip-field"><span class="sl-tip-key">${esc(this.rowTypeWord(details))}</span><span class="sl-tip-val">${esc(this.rowShort(details))}</span></div>` : "") + (details.seatNumber ? `<div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.seat", "Seat")}</span><span class="sl-tip-val">${esc(details.seatNumber)}</span></div>` : "") + `</div>` : `<div class="sl-tip-grid one"><div class="sl-tip-field"><span class="sl-tip-key">${this.tf("picker.seat", "Seat")}</span><span class="sl-tip-val">${esc(details.displayLabel ?? details.label)}</span></div></div>`;
|
|
6626
6827
|
const statusLine = details.status === "free" ? "" : `<div class="sl-tip-status">${details.status === "held" ? t2("map.statusHeld") : t2("map.statusTaken")}</div>`;
|
|
6627
6828
|
const limited = this.limitedViewLabel(details.commercial);
|
|
6628
6829
|
const cxLine = limited ? `<div class="sl-tip-cx"><span class="g" aria-hidden="true">\u25D0</span>${esc(limited)}</div>` : "";
|
|
@@ -6913,7 +7114,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6913
7114
|
const identity = details?.displayLabel ?? seat.displayLabel ?? seat.label;
|
|
6914
7115
|
const section = details?.sectionLabel;
|
|
6915
7116
|
const row = this.rowShort(details);
|
|
6916
|
-
const location2 = [section, row ?
|
|
7117
|
+
const location2 = [section, row ? t2("picker.rowLabel", { label: row }) : null, identity].filter(Boolean).join(" \xB7 ");
|
|
6917
7118
|
const copy = status === "held" ? {
|
|
6918
7119
|
title: this.tf("picker.temporarilyHeld", "Temporarily held"),
|
|
6919
7120
|
message: this.tf("picker.heldSeatExplanation", "Another buyer is holding this seat. It may become available again.")
|
|
@@ -7009,7 +7210,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7009
7210
|
chip = document.createElement("div");
|
|
7010
7211
|
chip.className = "sl-view3d-compare-saved";
|
|
7011
7212
|
chip.setAttribute("role", "group");
|
|
7012
|
-
chip.setAttribute("aria-label", "Saved seat comparison");
|
|
7213
|
+
chip.setAttribute("aria-label", this.tf("picker.savedSeatComparison", "Saved seat comparison"));
|
|
7013
7214
|
const main2 = document.createElement("button");
|
|
7014
7215
|
main2.type = "button";
|
|
7015
7216
|
main2.className = "main";
|
|
@@ -7021,7 +7222,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7021
7222
|
clear.type = "button";
|
|
7022
7223
|
clear.className = "clear";
|
|
7023
7224
|
clear.textContent = "\xD7";
|
|
7024
|
-
clear.setAttribute("aria-label", "Clear saved seat comparison");
|
|
7225
|
+
clear.setAttribute("aria-label", this.tf("picker.clearSavedSeatComparison", "Clear saved seat comparison"));
|
|
7025
7226
|
clear.addEventListener("click", () => this.clearView3dComparison());
|
|
7026
7227
|
chip.append(main2, clear);
|
|
7027
7228
|
overlay.appendChild(chip);
|
|
@@ -7030,8 +7231,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
7030
7231
|
const count = this.view3dCompareSeatIds.length;
|
|
7031
7232
|
const main = chip.querySelector(".main");
|
|
7032
7233
|
if (main) {
|
|
7033
|
-
main.textContent = count > 1 ?
|
|
7034
|
-
main.setAttribute("aria-label", count > 1 ?
|
|
7234
|
+
main.textContent = count > 1 ? t2("picker.compareCount", { count }) : this.tf("picker.oneSeatSaved", "1 seat saved");
|
|
7235
|
+
main.setAttribute("aria-label", count > 1 ? t2("picker.openComparisonOfSeats", { count }) : this.tf("picker.oneSeatSavedChooseAnother", "One seat saved; choose another to compare"));
|
|
7035
7236
|
}
|
|
7036
7237
|
}
|
|
7037
7238
|
view3dComparisonSnapshot(seatId) {
|
|
@@ -7308,8 +7509,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7308
7509
|
const wantFloors = floors.length > 1;
|
|
7309
7510
|
const wantZones = zones.length > 1;
|
|
7310
7511
|
const wantSections = sections.length > 1;
|
|
7311
|
-
|
|
7312
|
-
if (!wantFloors && !wantZones && !wantSections && !wantLocator) return;
|
|
7512
|
+
if (!wantFloors && !wantZones && !wantSections) return;
|
|
7313
7513
|
const nav = document.createElement("div");
|
|
7314
7514
|
nav.className = "sl-view3d-nav";
|
|
7315
7515
|
const finderToggle = document.createElement("button");
|
|
@@ -7319,7 +7519,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7319
7519
|
const setFinderOpen = (open) => {
|
|
7320
7520
|
nav.classList.toggle("is-open", open);
|
|
7321
7521
|
finderToggle.setAttribute("aria-expanded", String(open));
|
|
7322
|
-
finderToggle.textContent = open ? "Close
|
|
7522
|
+
finderToggle.textContent = open ? this.tf("picker.closeVenueNav", "Close") : wantFloors && (wantZones || wantSections) ? this.tf("picker.levelsAndAreas", "Levels & areas") : wantFloors ? this.tf("picker.levels", "Levels") : this.tf("picker.areas", "Areas");
|
|
7323
7523
|
};
|
|
7324
7524
|
finderToggle.addEventListener("click", () => setFinderOpen(!nav.classList.contains("is-open")));
|
|
7325
7525
|
nav.addEventListener("keydown", (event) => {
|
|
@@ -7356,7 +7556,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7356
7556
|
row.appendChild(b);
|
|
7357
7557
|
};
|
|
7358
7558
|
add(this.tf("picker.allLevels", "All levels"), null);
|
|
7359
|
-
for (const f of floors) add(f.label ||
|
|
7559
|
+
for (const f of floors) add(f.label || t2("picker.levelNumber", { number: f.index + 1 }), f.index);
|
|
7360
7560
|
nav.appendChild(row);
|
|
7361
7561
|
}
|
|
7362
7562
|
if (wantZones || wantSections) {
|
|
@@ -7399,86 +7599,6 @@ var SeatPicker = class _SeatPicker {
|
|
|
7399
7599
|
}
|
|
7400
7600
|
nav.appendChild(row);
|
|
7401
7601
|
}
|
|
7402
|
-
if (wantLocator) {
|
|
7403
|
-
const locator = document.createElement("div");
|
|
7404
|
-
locator.className = "sl-view3d-locator";
|
|
7405
|
-
locator.setAttribute("role", "group");
|
|
7406
|
-
locator.setAttribute("aria-label", "Find an exact seat in 3D");
|
|
7407
|
-
const sectionSelect = document.createElement("select");
|
|
7408
|
-
sectionSelect.setAttribute("aria-label", "Choose section in 3D");
|
|
7409
|
-
const rowSelect = document.createElement("select");
|
|
7410
|
-
rowSelect.setAttribute("aria-label", "Choose row in 3D");
|
|
7411
|
-
const seatSelect = document.createElement("select");
|
|
7412
|
-
seatSelect.setAttribute("aria-label", "Choose seat in 3D");
|
|
7413
|
-
const view = document.createElement("button");
|
|
7414
|
-
view.type = "button";
|
|
7415
|
-
view.textContent = "Inspect seat";
|
|
7416
|
-
view.disabled = true;
|
|
7417
|
-
const fill = (select, placeholder, entries) => {
|
|
7418
|
-
select.replaceChildren();
|
|
7419
|
-
const first = document.createElement("option");
|
|
7420
|
-
first.value = "";
|
|
7421
|
-
first.textContent = placeholder;
|
|
7422
|
-
select.appendChild(first);
|
|
7423
|
-
for (const entry of entries) {
|
|
7424
|
-
const option = document.createElement("option");
|
|
7425
|
-
option.value = entry.id;
|
|
7426
|
-
option.textContent = entry.label;
|
|
7427
|
-
select.appendChild(option);
|
|
7428
|
-
}
|
|
7429
|
-
select.value = "";
|
|
7430
|
-
};
|
|
7431
|
-
fill(sectionSelect, "1. Section", allSections.map((section) => ({
|
|
7432
|
-
id: section.id,
|
|
7433
|
-
label: `${section.label} \xB7 ${section.seatCount.toLocaleString()} seats`
|
|
7434
|
-
})));
|
|
7435
|
-
fill(rowSelect, "2. Row", []);
|
|
7436
|
-
fill(seatSelect, "3. Seat", []);
|
|
7437
|
-
rowSelect.disabled = true;
|
|
7438
|
-
seatSelect.disabled = true;
|
|
7439
|
-
sectionSelect.addEventListener("change", () => {
|
|
7440
|
-
const sectionId = sectionSelect.value;
|
|
7441
|
-
view.disabled = true;
|
|
7442
|
-
fill(seatSelect, "3. Seat", []);
|
|
7443
|
-
seatSelect.disabled = true;
|
|
7444
|
-
if (!sectionId || !handle.focusSection(sectionId)) {
|
|
7445
|
-
fill(rowSelect, "2. Row", []);
|
|
7446
|
-
rowSelect.disabled = true;
|
|
7447
|
-
return;
|
|
7448
|
-
}
|
|
7449
|
-
const rows = handle.rows(sectionId);
|
|
7450
|
-
fill(rowSelect, "2. Row", rows.map((row) => ({
|
|
7451
|
-
id: row.id,
|
|
7452
|
-
label: `${row.label} \xB7 ${row.seatCount} seats`
|
|
7453
|
-
})));
|
|
7454
|
-
rowSelect.disabled = rows.length === 0;
|
|
7455
|
-
});
|
|
7456
|
-
rowSelect.addEventListener("change", () => {
|
|
7457
|
-
const rowId = rowSelect.value;
|
|
7458
|
-
view.disabled = true;
|
|
7459
|
-
if (!rowId || !handle.focusRow(rowId)) {
|
|
7460
|
-
fill(seatSelect, "3. Seat", []);
|
|
7461
|
-
seatSelect.disabled = true;
|
|
7462
|
-
return;
|
|
7463
|
-
}
|
|
7464
|
-
const seats = handle.seatsInRow(rowId);
|
|
7465
|
-
fill(seatSelect, "3. Seat", seats);
|
|
7466
|
-
seatSelect.disabled = seats.length === 0;
|
|
7467
|
-
});
|
|
7468
|
-
seatSelect.addEventListener("change", () => {
|
|
7469
|
-
const seatId = seatSelect.value;
|
|
7470
|
-
view.disabled = !seatId;
|
|
7471
|
-
});
|
|
7472
|
-
view.addEventListener("click", () => {
|
|
7473
|
-
const seatId = seatSelect.value;
|
|
7474
|
-
if (seatId) {
|
|
7475
|
-
setFinderOpen(false);
|
|
7476
|
-
this.onView3dSeatPick(seatId);
|
|
7477
|
-
}
|
|
7478
|
-
});
|
|
7479
|
-
locator.append(sectionSelect, rowSelect, seatSelect, view);
|
|
7480
|
-
nav.appendChild(locator);
|
|
7481
|
-
}
|
|
7482
7602
|
overlay.appendChild(nav);
|
|
7483
7603
|
}
|
|
7484
7604
|
async enter3d(flySeatId) {
|
|
@@ -7494,7 +7614,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7494
7614
|
const overlay = document.createElement("div");
|
|
7495
7615
|
overlay.className = "sl-view3d";
|
|
7496
7616
|
overlay.setAttribute("role", "group");
|
|
7497
|
-
overlay.setAttribute("aria-label", "Interactive 3D venue view");
|
|
7617
|
+
overlay.setAttribute("aria-label", this.tf("picker.interactive3dVenueView", "Interactive 3D venue view"));
|
|
7498
7618
|
const back = document.createElement("button");
|
|
7499
7619
|
back.type = "button";
|
|
7500
7620
|
back.className = "sl-view3d-back";
|
|
@@ -7520,7 +7640,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7520
7640
|
fullscreen.type = "button";
|
|
7521
7641
|
fullscreen.className = "sl-view3d-fs";
|
|
7522
7642
|
fullscreen.textContent = "\u26F6";
|
|
7523
|
-
fullscreen.setAttribute("aria-label", "Full screen");
|
|
7643
|
+
fullscreen.setAttribute("aria-label", this.tf("picker.fullScreen", "Full screen"));
|
|
7524
7644
|
fullscreen.setAttribute("aria-pressed", String(!!document.fullscreenElement || this.fsFallback || this.framedFs));
|
|
7525
7645
|
fullscreen.addEventListener("click", () => this.toggleFullscreen());
|
|
7526
7646
|
overlay.appendChild(fullscreen);
|
|
@@ -7557,7 +7677,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7557
7677
|
onSeatInspect: (id) => this.onView3dSeatPick(id),
|
|
7558
7678
|
onSectionFocusChange: (sectionId) => {
|
|
7559
7679
|
const select = overlay.querySelector(
|
|
7560
|
-
'select[
|
|
7680
|
+
'select[data-locator="section"]'
|
|
7561
7681
|
);
|
|
7562
7682
|
const next = sectionId ?? "";
|
|
7563
7683
|
if (!select || select.value === next) return;
|
|
@@ -7654,7 +7774,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7654
7774
|
if (button) {
|
|
7655
7775
|
button.disabled = true;
|
|
7656
7776
|
button.classList.add("sl-busy");
|
|
7657
|
-
button.innerHTML =
|
|
7777
|
+
button.innerHTML = `<span class="sl-ba-spin" aria-hidden="true"></span>${this.tf("picker.findingEllipsis", "Finding\u2026")}`;
|
|
7658
7778
|
}
|
|
7659
7779
|
try {
|
|
7660
7780
|
const h = await this.controller.bestAvailable(qty, categoryKey, { ...opts, ttlMs: this.opts.holdTtlMs });
|
|
@@ -7676,7 +7796,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7676
7796
|
} catch (err) {
|
|
7677
7797
|
this.opts.onError?.(err);
|
|
7678
7798
|
const reason = err?.reason;
|
|
7679
|
-
const message = reason === "not_enough_together" ?
|
|
7799
|
+
const message = reason === "not_enough_together" ? t2("picker.couldNotFindSeatsTogether", { count: qty }) : reason === "sold_out" ? this.tf("picker.ticketTypeSoldOut", "That ticket type is sold out. Try another ticket type.") : reason === "event_closed" ? this.tf("picker.seatSalesClosedForEvent", "Seat sales have closed for this event.") : this.tf("picker.seatsNoLongerAvailableTryAnother", "Those seats are no longer available. Try another quantity or ticket type.");
|
|
7680
7800
|
this.toast(message, "error");
|
|
7681
7801
|
return null;
|
|
7682
7802
|
} finally {
|
|
@@ -7705,7 +7825,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7705
7825
|
}
|
|
7706
7826
|
}
|
|
7707
7827
|
if (!released) {
|
|
7708
|
-
this.toast("Couldn't release your tickets. Your hold is unchanged.", "error");
|
|
7828
|
+
this.toast(this.tf("picker.couldNotReleaseTickets", "Couldn't release your tickets. Your hold is unchanged."), "error");
|
|
7709
7829
|
return;
|
|
7710
7830
|
}
|
|
7711
7831
|
this.hold = null;
|