@seatlayer/js 0.50.2 → 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 +330 -245
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +330 -245
- 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). */
|
|
@@ -3573,6 +3660,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3573
3660
|
/** Wide-layout ticket panel collapsed (map owns the full width). */
|
|
3574
3661
|
this.sideCollapsed = false;
|
|
3575
3662
|
this.sideToggleEl = null;
|
|
3663
|
+
this.pricesBtnEl = null;
|
|
3576
3664
|
/** True once we've asked the host page to pin us fullscreen (framed, no native). */
|
|
3577
3665
|
this.framedFs = false;
|
|
3578
3666
|
/** Last height (px) posted to a host frame; dedupes redundant reports. */
|
|
@@ -3685,7 +3773,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3685
3773
|
if (this.tableDialog?.physicalSeatIds.includes(seat.id)) this.dismissTableDialog();
|
|
3686
3774
|
},
|
|
3687
3775
|
onSelectionLimit: () => {
|
|
3688
|
-
this.toast(
|
|
3776
|
+
this.toast(t2("picker.maxTicketsForOrder", { count: this.maxTickets }), "warning");
|
|
3689
3777
|
},
|
|
3690
3778
|
onViewChange: () => {
|
|
3691
3779
|
this.reanchorConfirm();
|
|
@@ -3801,8 +3889,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
3801
3889
|
return `<span class="sl-cx-mark" role="img" aria-label="${title}" title="${title}">\u25D0</span>`;
|
|
3802
3890
|
}
|
|
3803
3891
|
wheelchairProvisionLabel(type) {
|
|
3804
|
-
if (type === "no-seat") return "Empty wheelchair space";
|
|
3805
|
-
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");
|
|
3806
3894
|
return "";
|
|
3807
3895
|
}
|
|
3808
3896
|
wheelchairConfirmHtml(type) {
|
|
@@ -3883,9 +3971,9 @@ var SeatPicker = class _SeatPicker {
|
|
|
3883
3971
|
const hideEventDetails = this.eventDetailsHidden && !active;
|
|
3884
3972
|
this.root?.setAttribute("data-event-details-hidden", String(hideEventDetails));
|
|
3885
3973
|
this.els.zfs?.setAttribute("aria-pressed", String(active));
|
|
3886
|
-
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"));
|
|
3887
3975
|
const zfsLabel = this.els.zfs?.querySelector(".sl-zfs-lbl");
|
|
3888
|
-
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");
|
|
3889
3977
|
this.view3dEl?.querySelector(".sl-view3d-fs")?.setAttribute("aria-pressed", String(active));
|
|
3890
3978
|
}
|
|
3891
3979
|
/**
|
|
@@ -3950,7 +4038,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3950
4038
|
frame.className = "sl-modal-frame";
|
|
3951
4039
|
frame.setAttribute("role", "dialog");
|
|
3952
4040
|
frame.setAttribute("aria-modal", "true");
|
|
3953
|
-
frame.setAttribute("aria-label", "Seat selection");
|
|
4041
|
+
frame.setAttribute("aria-label", tfStatic("picker.seatSelection", "Seat selection"));
|
|
3954
4042
|
frame.tabIndex = -1;
|
|
3955
4043
|
scrim.appendChild(frame);
|
|
3956
4044
|
document.body.appendChild(scrim);
|
|
@@ -4110,7 +4198,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4110
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>
|
|
4111
4199
|
<span data-ref="closedPillText"></span>
|
|
4112
4200
|
</span>
|
|
4113
|
-
<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")}">
|
|
4114
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>
|
|
4115
4203
|
</button>
|
|
4116
4204
|
</div>
|
|
@@ -4118,17 +4206,17 @@ var SeatPicker = class _SeatPicker {
|
|
|
4118
4206
|
<div class="sl-map">
|
|
4119
4207
|
<div class="sl-map-host" data-ref="map"></div>
|
|
4120
4208
|
<div class="sl-zoom" data-ref="zoom">
|
|
4121
|
-
<button type="button" aria-label="Zoom in" title="Zoom in" data-ref="zin">+</button>
|
|
4122
|
-
<button type="button" aria-label="Zoom out" title="Zoom out" data-ref="zout">\u2212</button>
|
|
4123
|
-
<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">
|
|
4124
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>
|
|
4125
4213
|
</button>
|
|
4126
|
-
<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">
|
|
4127
4215
|
<svg viewBox="0 0 24 24"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
|
|
4128
|
-
<span class="sl-zfs-lbl" aria-hidden="true"
|
|
4216
|
+
<span class="sl-zfs-lbl" aria-hidden="true">${this.tf("picker.fullScreen", "Full screen")}</span>
|
|
4129
4217
|
</button>
|
|
4130
4218
|
</div>
|
|
4131
|
-
<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>
|
|
4132
4220
|
<div class="sl-toast" data-ref="toast" role="status" aria-live="polite"></div>
|
|
4133
4221
|
</div>
|
|
4134
4222
|
<div class="sl-side" data-ref="side">
|
|
@@ -4136,24 +4224,25 @@ var SeatPicker = class _SeatPicker {
|
|
|
4136
4224
|
<div class="sl-sheet-grab"></div>
|
|
4137
4225
|
<div class="sl-sheet-bar">
|
|
4138
4226
|
<div class="sl-sheet-peek" data-ref="peek"></div>
|
|
4139
|
-
<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">
|
|
4140
4228
|
<svg viewBox="0 0 24 24"><path d="M6 15l6-6 6 6"/></svg>
|
|
4141
4229
|
</button>
|
|
4142
4230
|
</div>
|
|
4143
4231
|
</div>
|
|
4144
|
-
<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>
|
|
4145
4233
|
<div class="sl-filters" data-ref="filters"></div>
|
|
4146
4234
|
<div class="sl-offer" data-ref="offer" role="status" aria-live="polite"></div>
|
|
4147
|
-
<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>
|
|
4148
4237
|
<div class="sl-prices" data-ref="prices"></div>
|
|
4149
|
-
<div class="sl-live" data-ref="live" role="status" aria-live="polite"><span class="dot" aria-hidden="true"></span><span data-ref="liveText"
|
|
4150
|
-
<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>
|
|
4151
4240
|
<div class="sl-tray" data-ref="tray"></div>
|
|
4152
4241
|
<div class="sl-foot" data-ref="foot">
|
|
4153
4242
|
<div class="sl-hold-note" data-ref="holdNote" role="status" aria-live="polite">
|
|
4154
4243
|
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
|
4155
|
-
<span><b data-ref="holdTitle"
|
|
4156
|
-
<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>
|
|
4157
4246
|
</div>
|
|
4158
4247
|
<div class="sl-total"><span data-ref="count"></span><b data-ref="total"></b></div>
|
|
4159
4248
|
<button type="button" class="sl-cta" data-ref="cta" disabled></button>
|
|
@@ -4204,7 +4293,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4204
4293
|
const setSheet = (open) => {
|
|
4205
4294
|
root.dataset.sheet = open ? "open" : "peek";
|
|
4206
4295
|
toggle?.setAttribute("aria-expanded", String(open));
|
|
4207
|
-
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"));
|
|
4208
4297
|
};
|
|
4209
4298
|
setSheet(root.dataset.sheet === "open");
|
|
4210
4299
|
toggle?.addEventListener("click", (e) => {
|
|
@@ -4250,6 +4339,39 @@ var SeatPicker = class _SeatPicker {
|
|
|
4250
4339
|
head.releasePointerCapture?.(e.pointerId);
|
|
4251
4340
|
});
|
|
4252
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;
|
|
4253
4375
|
this.tipEl = document.createElement("div");
|
|
4254
4376
|
this.tipEl.setAttribute("role", "tooltip");
|
|
4255
4377
|
this.tipEl.className = "sl-tip";
|
|
@@ -4267,7 +4389,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4267
4389
|
const info = await this.controller.render(canvasHost);
|
|
4268
4390
|
if (this.destroyed) return this;
|
|
4269
4391
|
if (!info) {
|
|
4270
|
-
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>`;
|
|
4271
4393
|
this.els.boot.querySelector("button").addEventListener("click", () => {
|
|
4272
4394
|
const container = this.opts.container;
|
|
4273
4395
|
const opts = this.opts;
|
|
@@ -4302,6 +4424,12 @@ var SeatPicker = class _SeatPicker {
|
|
|
4302
4424
|
const when = info.startsAt ? formatWhen(info.startsAt, info.timezone ?? null, this.opts.locale) : "";
|
|
4303
4425
|
this.eventWhenText = when || null;
|
|
4304
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
|
+
}
|
|
4305
4433
|
this.buildBadge(chartTheme);
|
|
4306
4434
|
const present = /* @__PURE__ */ new Set();
|
|
4307
4435
|
let hasLimitedView = false;
|
|
@@ -4328,7 +4456,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4328
4456
|
const mk = (key, label) => `<button type="button" class="sl-chip-f${key === "all" ? " on" : ""}" data-a11y="1" data-f="${key}">${label}</button>`;
|
|
4329
4457
|
chips.insertAdjacentHTML(
|
|
4330
4458
|
"beforeend",
|
|
4331
|
-
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("")
|
|
4332
4460
|
);
|
|
4333
4461
|
const active = /* @__PURE__ */ new Set();
|
|
4334
4462
|
const syncChips = () => {
|
|
@@ -4374,7 +4502,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4374
4502
|
cb.type = "button";
|
|
4375
4503
|
cb.className = "sl-cbbtn";
|
|
4376
4504
|
this.cbEl = cb;
|
|
4377
|
-
cb.setAttribute("aria-label", "Toggle colorblind-friendly colors");
|
|
4505
|
+
cb.setAttribute("aria-label", this.tf("picker.toggleColorblindColors", "Toggle colorblind-friendly colors"));
|
|
4378
4506
|
cb.setAttribute("aria-pressed", String(this.cbSafe));
|
|
4379
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>';
|
|
4380
4508
|
this.els.zfit.parentElement.appendChild(cb);
|
|
@@ -4460,8 +4588,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
4460
4588
|
if (!btn) return;
|
|
4461
4589
|
const collapsed = this.sideCollapsed;
|
|
4462
4590
|
btn.setAttribute("aria-expanded", String(!collapsed));
|
|
4463
|
-
btn.setAttribute("aria-label", collapsed ? "Show the ticket panel" : "Hide the ticket panel");
|
|
4464
|
-
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>`;
|
|
4465
4593
|
}
|
|
4466
4594
|
/**
|
|
4467
4595
|
* Collapse or reopen the wide-layout ticket panel in place (host-drivable —
|
|
@@ -4487,13 +4615,24 @@ var SeatPicker = class _SeatPicker {
|
|
|
4487
4615
|
const narrow = this.root?.dataset.layout === "narrow";
|
|
4488
4616
|
this.applyPanelCollapsed();
|
|
4489
4617
|
const zfs = this.els.zfs;
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
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;
|
|
4497
4636
|
}
|
|
4498
4637
|
}
|
|
4499
4638
|
const filters = this.els.filters;
|
|
@@ -4520,7 +4659,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4520
4659
|
this.extendEl = el;
|
|
4521
4660
|
this.els.extendTxt = el.querySelector('[data-ref="extendTxt"]');
|
|
4522
4661
|
this.els.extendBtn = el.querySelector('[data-ref="extendBtn"]');
|
|
4523
|
-
this.els.extendBtn.textContent = "Add time";
|
|
4662
|
+
this.els.extendBtn.textContent = this.tf("picker.addTime", "Add time");
|
|
4524
4663
|
this.els.extendBtn.addEventListener("click", () => void this.handleExtend());
|
|
4525
4664
|
}
|
|
4526
4665
|
/** Success overlay + onBooked fire when the held seats settle to booked. */
|
|
@@ -4529,7 +4668,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4529
4668
|
el.className = "sl-booked";
|
|
4530
4669
|
el.setAttribute("role", "status");
|
|
4531
4670
|
el.setAttribute("aria-live", "polite");
|
|
4532
|
-
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>`;
|
|
4533
4672
|
this.root.appendChild(el);
|
|
4534
4673
|
this.bookedEl = el;
|
|
4535
4674
|
this.els.bookedSub = el.querySelector('[data-ref="bookedSub"]');
|
|
@@ -4540,8 +4679,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4540
4679
|
* host `messages` override (which makes `t()` return the override, not the key).
|
|
4541
4680
|
*/
|
|
4542
4681
|
tf(key, fallback) {
|
|
4543
|
-
|
|
4544
|
-
return v === key ? fallback : v;
|
|
4682
|
+
return tfStatic(key, fallback);
|
|
4545
4683
|
}
|
|
4546
4684
|
/** Sold-out overlay — an informational state with no unavailable action. */
|
|
4547
4685
|
buildSoldoutOverlay() {
|
|
@@ -4726,7 +4864,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4726
4864
|
}
|
|
4727
4865
|
canAddTicket() {
|
|
4728
4866
|
if (this.totalTicketCount() < this.maxTickets) return true;
|
|
4729
|
-
this.toast(
|
|
4867
|
+
this.toast(t2("picker.maxTicketsForOrder", { count: this.maxTickets }), "warning");
|
|
4730
4868
|
return false;
|
|
4731
4869
|
}
|
|
4732
4870
|
pendingGATotal(gaAreas) {
|
|
@@ -4749,21 +4887,21 @@ var SeatPicker = class _SeatPicker {
|
|
|
4749
4887
|
}
|
|
4750
4888
|
if (this.confirmSeat || this.tableDialog && !this.tableDialogHeld) {
|
|
4751
4889
|
cta.disabled = true;
|
|
4752
|
-
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");
|
|
4753
4891
|
return;
|
|
4754
4892
|
}
|
|
4755
4893
|
if (this.ctaPhase === "holding") {
|
|
4756
4894
|
cta.disabled = true;
|
|
4757
|
-
cta.innerHTML =
|
|
4895
|
+
cta.innerHTML = `<span class="sl-cta-spin" aria-hidden="true"></span>${this.tf("picker.securingSeats", "Securing your seats\u2026")}`;
|
|
4758
4896
|
return;
|
|
4759
4897
|
}
|
|
4760
4898
|
if (this.ctaPhase === "checkout") {
|
|
4761
4899
|
cta.disabled = true;
|
|
4762
|
-
cta.innerHTML =
|
|
4900
|
+
cta.innerHTML = `<span class="sl-cta-spin" aria-hidden="true"></span>${this.tf("picker.openingCheckout", "Opening secure checkout\u2026")}`;
|
|
4763
4901
|
return;
|
|
4764
4902
|
}
|
|
4765
4903
|
cta.disabled = count === 0;
|
|
4766
|
-
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");
|
|
4767
4905
|
}
|
|
4768
4906
|
setCtaPhase(phase) {
|
|
4769
4907
|
this.ctaPhase = phase;
|
|
@@ -4824,7 +4962,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4824
4962
|
this.syncTray();
|
|
4825
4963
|
this.emitHoldChange();
|
|
4826
4964
|
this.opts.onHoldRestored?.(restored, restored.seats ?? [], this.buildHandoff(restored));
|
|
4827
|
-
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");
|
|
4828
4966
|
return restored;
|
|
4829
4967
|
} catch (error) {
|
|
4830
4968
|
const status = error?.status;
|
|
@@ -5042,8 +5180,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
5042
5180
|
if (bands.length < 2) return;
|
|
5043
5181
|
const select = document.createElement("select");
|
|
5044
5182
|
select.className = "sl-price-select";
|
|
5045
|
-
select.setAttribute("aria-label", "Filter and focus seats by price");
|
|
5046
|
-
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("");
|
|
5047
5185
|
this.els.pricesSec.appendChild(select);
|
|
5048
5186
|
select.addEventListener("change", () => {
|
|
5049
5187
|
const band = bands.find((candidate) => candidate.id === select.value);
|
|
@@ -5070,8 +5208,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
5070
5208
|
const projection = document.createElement("div");
|
|
5071
5209
|
projection.className = "sl-projection";
|
|
5072
5210
|
projection.setAttribute("role", "group");
|
|
5073
|
-
projection.setAttribute("aria-label", "Venue view");
|
|
5074
|
-
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>`;
|
|
5075
5213
|
projection.querySelectorAll("button").forEach((button) => {
|
|
5076
5214
|
button.addEventListener("click", () => {
|
|
5077
5215
|
this.setBuyerView(button.dataset.view);
|
|
@@ -5194,6 +5332,10 @@ var SeatPicker = class _SeatPicker {
|
|
|
5194
5332
|
renderSectionCard(summary) {
|
|
5195
5333
|
if (!this.els.map) return;
|
|
5196
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
|
+
}
|
|
5197
5339
|
const paid = summary.categories.length ? summary.categories.map((c) => this.paidPrice(c.key, null, c.price)) : [summary.priceMin, summary.priceMax];
|
|
5198
5340
|
const paidMin = Math.min(...paid);
|
|
5199
5341
|
const paidMax = Math.max(...paid);
|
|
@@ -5294,13 +5436,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
5294
5436
|
}
|
|
5295
5437
|
const cat = this.controller.doc?.categories.find((c) => c.key === seat.categoryKey);
|
|
5296
5438
|
const status = this.controller.getStatus(seat.id) ?? "free";
|
|
5297
|
-
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");
|
|
5298
5440
|
const price = cat ? this.catPrice(cat) : void 0;
|
|
5299
5441
|
const table = this.controller.tableSelection(seat.id);
|
|
5300
5442
|
const details = table ?? this.controller.seatDetails(seat.id);
|
|
5301
5443
|
const typeWord = this.rowTypeWord(details);
|
|
5302
5444
|
const buyerName = details?.rowLabel ?? details?.displayLabel ?? seat.displayLabel ?? seat.label;
|
|
5303
|
-
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 });
|
|
5304
5446
|
this.srEl.textContent = `${identity}, ${cat?.label ?? seat.categoryKey}${price != null ? `, ${this.money(price)}` : ""}, ${statusText}`;
|
|
5305
5447
|
}
|
|
5306
5448
|
// ---- atomic table confirmation / guest quantity ---------------------------
|
|
@@ -5321,7 +5463,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5321
5463
|
const typeWord = this.rowTypeWord(table);
|
|
5322
5464
|
const el = document.createElement("div");
|
|
5323
5465
|
el.className = "sl-table-scrim";
|
|
5324
|
-
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>`;
|
|
5325
5467
|
this.root.appendChild(el);
|
|
5326
5468
|
this.tableDialogEl = el;
|
|
5327
5469
|
this.renderTableDialogState();
|
|
@@ -5380,17 +5522,17 @@ var SeatPicker = class _SeatPicker {
|
|
|
5380
5522
|
const button = this.tableDialogEl?.querySelector(".sl-table-confirm");
|
|
5381
5523
|
if (button) {
|
|
5382
5524
|
button.disabled = true;
|
|
5383
|
-
button.textContent = held ? "Updating\u2026" : "Selecting\u2026";
|
|
5525
|
+
button.textContent = held ? this.tf("picker.updatingEllipsis", "Updating\u2026") : this.tf("picker.selectingEllipsis", "Selecting\u2026");
|
|
5384
5526
|
}
|
|
5385
5527
|
if (held) {
|
|
5386
5528
|
try {
|
|
5387
5529
|
const updated = await this.controller.replaceTableQuantity(table.label, table.quantity, this.opts.holdTtlMs);
|
|
5388
5530
|
if (!updated) {
|
|
5389
|
-
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");
|
|
5390
5532
|
this.renderTableDialogState();
|
|
5391
5533
|
if (button) {
|
|
5392
5534
|
button.disabled = false;
|
|
5393
|
-
button.textContent = "Update table";
|
|
5535
|
+
button.textContent = this.tf("picker.updateTable", "Update table");
|
|
5394
5536
|
}
|
|
5395
5537
|
return;
|
|
5396
5538
|
}
|
|
@@ -5404,13 +5546,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
5404
5546
|
this.dismissTableDialog();
|
|
5405
5547
|
this.syncTray();
|
|
5406
5548
|
this.emitHoldChange();
|
|
5407
|
-
this.toast(
|
|
5549
|
+
this.toast(t2("picker.tableUpdatedForGuests", { label: table.label, count: table.quantity }), "success");
|
|
5408
5550
|
} catch (error) {
|
|
5409
5551
|
this.opts.onError?.(error);
|
|
5410
|
-
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");
|
|
5411
5553
|
if (button) {
|
|
5412
5554
|
button.disabled = false;
|
|
5413
|
-
button.textContent = "Update table";
|
|
5555
|
+
button.textContent = this.tf("picker.updateTable", "Update table");
|
|
5414
5556
|
}
|
|
5415
5557
|
}
|
|
5416
5558
|
return;
|
|
@@ -5418,7 +5560,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5418
5560
|
if (!this.controller.setTableQuantity(table.label, table.quantity)) {
|
|
5419
5561
|
if (button) {
|
|
5420
5562
|
button.disabled = false;
|
|
5421
|
-
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");
|
|
5422
5564
|
}
|
|
5423
5565
|
return;
|
|
5424
5566
|
}
|
|
@@ -5464,16 +5606,16 @@ var SeatPicker = class _SeatPicker {
|
|
|
5464
5606
|
'"': """
|
|
5465
5607
|
})[char]);
|
|
5466
5608
|
const identityFields = [
|
|
5467
|
-
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>` : "",
|
|
5468
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>` : "",
|
|
5469
|
-
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>` : ""
|
|
5470
5612
|
].filter(Boolean).join("");
|
|
5471
5613
|
const el = document.createElement("div");
|
|
5472
5614
|
el.className = "sl-confirm";
|
|
5473
5615
|
el.setAttribute("role", "dialog");
|
|
5474
|
-
el.setAttribute("aria-label",
|
|
5616
|
+
el.setAttribute("aria-label", t2("picker.confirmSeatLabel", { label: seat.label }));
|
|
5475
5617
|
el.style.setProperty("--sl-cat", cat?.color ?? "#6e7bff");
|
|
5476
|
-
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>`;
|
|
5477
5619
|
this.els.map.appendChild(el);
|
|
5478
5620
|
this.confirmEl = el;
|
|
5479
5621
|
const thumb = el.querySelector(".sl-confirm-thumb");
|
|
@@ -5626,7 +5768,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5626
5768
|
el.className = "sl-view";
|
|
5627
5769
|
el.setAttribute("role", "dialog");
|
|
5628
5770
|
el.setAttribute("aria-label", t2("picker.viewFromSeat", { label: seat.label }));
|
|
5629
|
-
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>`;
|
|
5630
5772
|
this.root.appendChild(el);
|
|
5631
5773
|
this.viewEl = el;
|
|
5632
5774
|
const pano = el.querySelector(".sl-view-pano");
|
|
@@ -5822,27 +5964,27 @@ var SeatPicker = class _SeatPicker {
|
|
|
5822
5964
|
copy.className = "sl-offer-copy";
|
|
5823
5965
|
const kicker = document.createElement("span");
|
|
5824
5966
|
kicker.className = "sl-offer-kicker";
|
|
5825
|
-
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");
|
|
5826
5968
|
const name = document.createElement("strong");
|
|
5827
5969
|
name.className = "sl-offer-name";
|
|
5828
|
-
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"));
|
|
5829
5971
|
const line = document.createElement("span");
|
|
5830
5972
|
line.className = "sl-offer-line";
|
|
5831
5973
|
const facts = [];
|
|
5832
5974
|
if (active && availability.fromPrice != null) facts.push(this.money(availability.fromPrice / 100));
|
|
5833
|
-
if (active && offer.remaining != null) facts.push(
|
|
5834
|
-
if (active && offer.endsAt != null) facts.push(
|
|
5835
|
-
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) }));
|
|
5836
5978
|
line.textContent = facts.join(" \xB7 ");
|
|
5837
5979
|
copy.append(kicker, name, line);
|
|
5838
5980
|
const info = document.createElement("details");
|
|
5839
5981
|
info.className = "sl-offer-info";
|
|
5840
5982
|
const summary = document.createElement("summary");
|
|
5841
|
-
summary.setAttribute("aria-label",
|
|
5983
|
+
summary.setAttribute("aria-label", t2("picker.howOfferWorks", { name: name.textContent ?? "" }));
|
|
5842
5984
|
summary.textContent = "i";
|
|
5843
5985
|
const detail = document.createElement("div");
|
|
5844
5986
|
detail.className = "sl-offer-detail";
|
|
5845
|
-
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.");
|
|
5846
5988
|
info.append(summary, detail);
|
|
5847
5989
|
main.append(copy, info);
|
|
5848
5990
|
host.replaceChildren(main);
|
|
@@ -5878,8 +6020,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
5878
6020
|
const previous = offer?.previousPrice != null && offer.previousPrice > offer.price ? offer.previousPrice : null;
|
|
5879
6021
|
const active = this.focusedCatKey === c.key;
|
|
5880
6022
|
const dim = this.priceBandKeys != null && !this.priceBandKeys.has(c.key);
|
|
5881
|
-
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" :
|
|
5882
|
-
}).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>`;
|
|
5883
6025
|
this.els.prices.querySelectorAll(".sl-price-row").forEach((row) => {
|
|
5884
6026
|
row.addEventListener("mouseenter", () => this.controller.getRenderer()?.setCategoryHighlight?.(row.dataset.cat ?? null));
|
|
5885
6027
|
row.addEventListener("mouseleave", () => this.controller.getRenderer()?.setCategoryHighlight?.(null));
|
|
@@ -5937,7 +6079,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
5937
6079
|
const now = left[cat.key] ?? 0;
|
|
5938
6080
|
if (before === void 0 || now >= before) continue;
|
|
5939
6081
|
const taken = before - now;
|
|
5940
|
-
textEl.textContent =
|
|
6082
|
+
textEl.textContent = tCount("picker.seatsJustTakenInCategory", taken, { label: cat.label, left: now });
|
|
5941
6083
|
this.els.live?.classList.remove("on");
|
|
5942
6084
|
void this.els.live?.offsetWidth;
|
|
5943
6085
|
this.els.live?.classList.add("on");
|
|
@@ -5955,12 +6097,17 @@ var SeatPicker = class _SeatPicker {
|
|
|
5955
6097
|
const gone = this.controller.getSelection().filter((s) => !ownLabels.has(s.label) && (this.controller.getStatus(s.id) ?? "free") !== "free");
|
|
5956
6098
|
if (!gone.length) return;
|
|
5957
6099
|
this.controller.deselect(gone.map((s) => s.id));
|
|
5958
|
-
this.toast(
|
|
6100
|
+
this.toast(t2("picker.seatJustTakenByAnother", { label: gone[0].label }), "error");
|
|
5959
6101
|
}
|
|
5960
6102
|
syncTray() {
|
|
5961
6103
|
if (!this.els.tray) return;
|
|
5962
6104
|
this.updateSelectionCapacity();
|
|
5963
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
|
+
}
|
|
5964
6111
|
const gaAreas = this.controller.getGAAreas();
|
|
5965
6112
|
const heldItems = this.hold?.items ?? [];
|
|
5966
6113
|
const parts = [];
|
|
@@ -5971,18 +6118,22 @@ var SeatPicker = class _SeatPicker {
|
|
|
5971
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>`
|
|
5972
6119
|
);
|
|
5973
6120
|
} else if (!seats.length && !heldItems.length && !gaAreas.length) {
|
|
5974
|
-
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>`);
|
|
5975
6122
|
} else if (!seats.length && !heldItems.length) {
|
|
5976
|
-
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>`);
|
|
5977
6124
|
}
|
|
5978
6125
|
const noPicks = !seats.length && !heldItems.length && !this.pendingGACount();
|
|
5979
|
-
if (
|
|
6126
|
+
if (noPicks) this.baReopen = false;
|
|
6127
|
+
if (!this.salesClosed && !this.hold && (noPicks || this.baReopen || this.bestAvailableBusy || this.bestAvailableConfirm)) {
|
|
5980
6128
|
const cats = this.controller.doc?.categories ?? [];
|
|
5981
6129
|
const zones = this.controller.getBestAvailableZones();
|
|
5982
6130
|
if (this.baZone && !zones.some((zone) => zone.id === this.baZone)) this.baZone = "";
|
|
5983
|
-
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
|
|
5984
6132
|
// seats (same present-only philosophy as the a11y filter chips).
|
|
5985
|
-
(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>`);
|
|
5986
6137
|
}
|
|
5987
6138
|
const idGrid = (seatId, label, objectType, quantity = 1, objectId, identity) => {
|
|
5988
6139
|
const esc = (value) => String(value ?? "\u2014").replace(/[&<>"]/g, (char) => ({
|
|
@@ -5994,21 +6145,21 @@ var SeatPicker = class _SeatPicker {
|
|
|
5994
6145
|
const d = seatId ? this.controller.seatDetails(seatId) : null;
|
|
5995
6146
|
const area = objectType === "ga" ? gaAreas.find((candidate) => candidate.id === objectId) : void 0;
|
|
5996
6147
|
const effectiveType = objectType === "ga" ? "ga" : d?.objectType ?? objectType;
|
|
5997
|
-
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"));
|
|
5998
6149
|
const buyerName = identity?.rowLabel ?? identity?.displayLabel ?? d?.rowLabel ?? d?.displayLabel ?? area?.displayLabel ?? area?.label ?? label;
|
|
5999
6150
|
if (effectiveType === "table" && identity?.bookingMode) {
|
|
6000
|
-
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>`;
|
|
6001
6152
|
}
|
|
6002
6153
|
if (effectiveType === "ga") {
|
|
6003
|
-
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>`;
|
|
6004
6155
|
}
|
|
6005
6156
|
if (effectiveType === "booth") {
|
|
6006
|
-
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>`;
|
|
6007
6158
|
}
|
|
6008
6159
|
if (!d?.sectionLabel && !d?.rowLabel && !d?.seatNumber) {
|
|
6009
|
-
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>`;
|
|
6010
6161
|
}
|
|
6011
|
-
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>`;
|
|
6012
6163
|
};
|
|
6013
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>`;
|
|
6014
6165
|
for (const item of heldItems) {
|
|
@@ -6020,7 +6171,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6020
6171
|
const table = item.objectType === "table" ? this.controller.tableSelection(item.label) : null;
|
|
6021
6172
|
const canView2 = this.seatViewEnabled() && !!heldSeat && item.objectType !== "table";
|
|
6022
6173
|
parts.push(
|
|
6023
|
-
`<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>`
|
|
6024
6175
|
);
|
|
6025
6176
|
}
|
|
6026
6177
|
const heldLabels = new Set(heldItems.map((item) => item.label));
|
|
@@ -6031,13 +6182,18 @@ var SeatPicker = class _SeatPicker {
|
|
|
6031
6182
|
const cat = this.controller.doc?.categories.find((c) => c.key === s.categoryKey);
|
|
6032
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>` : "";
|
|
6033
6184
|
parts.push(
|
|
6034
|
-
`<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>`
|
|
6035
6186
|
);
|
|
6036
6187
|
}
|
|
6037
6188
|
for (const area of gaAreas) {
|
|
6038
6189
|
const qty = this.gaQty.get(area.id) ?? 0;
|
|
6039
6190
|
parts.push(
|
|
6040
|
-
`<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>`
|
|
6041
6197
|
);
|
|
6042
6198
|
}
|
|
6043
6199
|
this.els.tray.innerHTML = parts.join("");
|
|
@@ -6072,6 +6228,16 @@ var SeatPicker = class _SeatPicker {
|
|
|
6072
6228
|
this.syncTray();
|
|
6073
6229
|
this.els.tray.querySelector(".sl-ba-go")?.focus();
|
|
6074
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
|
+
});
|
|
6075
6241
|
this.els.tray.querySelector("[data-ba-replace]")?.addEventListener("click", () => {
|
|
6076
6242
|
this.bestAvailableConfirm = false;
|
|
6077
6243
|
void this.bestAvailable(this.baQty, this.baCat || void 0, { preferPremium: this.baPremium, zoneId: this.baZone || void 0 });
|
|
@@ -6084,15 +6250,15 @@ var SeatPicker = class _SeatPicker {
|
|
|
6084
6250
|
return;
|
|
6085
6251
|
}
|
|
6086
6252
|
const id = chip.dataset.seat;
|
|
6087
|
-
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");
|
|
6088
6254
|
const remove = () => {
|
|
6089
6255
|
this.controller.deselect([id]);
|
|
6090
|
-
this.toast(
|
|
6091
|
-
label: "Undo",
|
|
6256
|
+
this.toast(t2("picker.labelRemoved", { label }), "neutral", {
|
|
6257
|
+
label: this.tf("picker.undo", "Undo"),
|
|
6092
6258
|
onClick: () => {
|
|
6093
6259
|
const restored = this.controller.select([id]);
|
|
6094
6260
|
this.toast(
|
|
6095
|
-
restored.length ?
|
|
6261
|
+
restored.length ? t2("picker.labelRestored", { label }) : t2("picker.labelNoLongerAvailable", { label }),
|
|
6096
6262
|
restored.length ? "success" : "warning"
|
|
6097
6263
|
);
|
|
6098
6264
|
}
|
|
@@ -6164,31 +6330,31 @@ var SeatPicker = class _SeatPicker {
|
|
|
6164
6330
|
const pendingCount = this.pendingSelectionCount();
|
|
6165
6331
|
const previousCount = this.lastTrayCount;
|
|
6166
6332
|
const previousTotal = this.lastTrayTotal;
|
|
6167
|
-
this.els.count.textContent = count ?
|
|
6333
|
+
this.els.count.textContent = count ? tCount("picker.ticketsCount", count) : this.tf("picker.noSeatsSelected", "No seats selected");
|
|
6168
6334
|
this.els.total.textContent = count ? this.money(total) : "";
|
|
6169
6335
|
this.root?.setAttribute("data-has-selection", String(count > 0));
|
|
6170
6336
|
this.root?.setAttribute(
|
|
6171
6337
|
"data-ba-active",
|
|
6172
|
-
String(this.bestAvailableConfirm || this.bestAvailableBusy)
|
|
6338
|
+
String(this.bestAvailableConfirm || this.bestAvailableBusy || this.baReopen)
|
|
6173
6339
|
);
|
|
6174
6340
|
this.els.foot?.classList.toggle("empty", count === 0);
|
|
6175
6341
|
if (this.els.seatSummary) {
|
|
6176
|
-
this.els.seatSummary.textContent = count ?
|
|
6342
|
+
this.els.seatSummary.textContent = count ? tCount("picker.seatsSelectedCount", count) : "";
|
|
6177
6343
|
}
|
|
6178
6344
|
this.syncCta(count, pendingCount);
|
|
6179
6345
|
if (this.hold) {
|
|
6180
6346
|
const securedCount = heldCount || this.hold.seats?.length || 0;
|
|
6181
6347
|
if (this.els.holdTitle) {
|
|
6182
|
-
this.els.holdTitle.textContent =
|
|
6348
|
+
this.els.holdTitle.textContent = t2("picker.securedCount", { count: securedCount });
|
|
6183
6349
|
}
|
|
6184
6350
|
if (this.els.holdCopy) {
|
|
6185
6351
|
this.holdCopyPending = pendingCount > 0;
|
|
6186
|
-
this.els.holdCopy.textContent = pendingCount ?
|
|
6352
|
+
this.els.holdCopy.textContent = pendingCount ? t2("picker.moreSelectedCount", { count: pendingCount }) : this.holdReassuranceText();
|
|
6187
6353
|
}
|
|
6188
6354
|
const change = this.els.holdChange;
|
|
6189
6355
|
if (change) {
|
|
6190
6356
|
change.disabled = this.releasingHold;
|
|
6191
|
-
change.textContent = this.releasingHold ? "Releasing\u2026" : "Change";
|
|
6357
|
+
change.textContent = this.releasingHold ? this.tf("picker.releasingEllipsis", "Releasing\u2026") : this.tf("picker.change", "Change");
|
|
6192
6358
|
}
|
|
6193
6359
|
}
|
|
6194
6360
|
if (count !== previousCount) this.animateOnce(this.els.count, "sl-value-pop", 380);
|
|
@@ -6213,21 +6379,21 @@ var SeatPicker = class _SeatPicker {
|
|
|
6213
6379
|
renderPeek(count, total, pendingCount) {
|
|
6214
6380
|
if (!this.els.peek) return;
|
|
6215
6381
|
if (count && this.ctaPhase === "holding") {
|
|
6216
|
-
this.els.peek.innerHTML = `<span
|
|
6382
|
+
this.els.peek.innerHTML = `<span>${this.tf("picker.securingSeats", "Securing your seats\u2026")}</span>`;
|
|
6217
6383
|
return;
|
|
6218
6384
|
}
|
|
6219
6385
|
if (count && this.ctaPhase === "checkout") {
|
|
6220
|
-
this.els.peek.innerHTML = `<span
|
|
6386
|
+
this.els.peek.innerHTML = `<span>${t2("picker.peekSecured", { count, total: this.money(total) })}</span>`;
|
|
6221
6387
|
return;
|
|
6222
6388
|
}
|
|
6223
6389
|
if (count) {
|
|
6224
|
-
const
|
|
6225
|
-
this.els.peek.innerHTML = `<span>${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>`;
|
|
6226
6392
|
} else if (this.salesClosed) {
|
|
6227
6393
|
this.els.peek.innerHTML = `<span>${this.tf("picker.salesClosedPill", "Sales are closed")}</span>`;
|
|
6228
6394
|
} else {
|
|
6229
6395
|
const prices = (this.controller.doc?.categories ?? []).map((c) => this.catPrice(c)).filter((p) => p != null);
|
|
6230
|
-
this.els.peek.innerHTML = (prices.length ? `<span
|
|
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>`;
|
|
6231
6397
|
}
|
|
6232
6398
|
}
|
|
6233
6399
|
async removeHeldLabel(label, chip) {
|
|
@@ -6240,7 +6406,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6240
6406
|
const preserveAcrossNavigation = this.handedOff;
|
|
6241
6407
|
const released = await this.controller.releaseLabels([label]);
|
|
6242
6408
|
if (!released) {
|
|
6243
|
-
this.toast(
|
|
6409
|
+
this.toast(t2("picker.couldNotRemoveLabel", { label }), "error");
|
|
6244
6410
|
return false;
|
|
6245
6411
|
}
|
|
6246
6412
|
const remaining = this.controller.currentHold();
|
|
@@ -6256,7 +6422,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6256
6422
|
}
|
|
6257
6423
|
this.syncTray();
|
|
6258
6424
|
this.emitHoldChange();
|
|
6259
|
-
this.toast(
|
|
6425
|
+
this.toast(t2("picker.labelRemovedFromHold", { label }), "success");
|
|
6260
6426
|
return true;
|
|
6261
6427
|
} finally {
|
|
6262
6428
|
this.releasingLabels.delete(label);
|
|
@@ -6270,23 +6436,23 @@ var SeatPicker = class _SeatPicker {
|
|
|
6270
6436
|
const button = this.els.holdChange;
|
|
6271
6437
|
if (button) {
|
|
6272
6438
|
button.disabled = true;
|
|
6273
|
-
button.textContent = "Releasing\u2026";
|
|
6439
|
+
button.textContent = this.tf("picker.releasingEllipsis", "Releasing\u2026");
|
|
6274
6440
|
}
|
|
6275
6441
|
try {
|
|
6276
6442
|
await this.release();
|
|
6277
|
-
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");
|
|
6278
6444
|
} finally {
|
|
6279
6445
|
this.releasingHold = false;
|
|
6280
6446
|
if (button?.isConnected) {
|
|
6281
6447
|
button.disabled = false;
|
|
6282
|
-
button.textContent = "Change";
|
|
6448
|
+
button.textContent = this.tf("picker.change", "Change");
|
|
6283
6449
|
}
|
|
6284
6450
|
}
|
|
6285
6451
|
}
|
|
6286
6452
|
async handleCta() {
|
|
6287
6453
|
if (this.salesClosed) return;
|
|
6288
6454
|
if (this.totalTicketCount() > this.maxTickets) {
|
|
6289
|
-
this.toast(
|
|
6455
|
+
this.toast(t2("picker.removeTicketsUntilOrFewer", { count: this.maxTickets }), "warning");
|
|
6290
6456
|
return;
|
|
6291
6457
|
}
|
|
6292
6458
|
const committed = this.committedSelection();
|
|
@@ -6312,7 +6478,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6312
6478
|
hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : hold;
|
|
6313
6479
|
}
|
|
6314
6480
|
if (!hold) {
|
|
6315
|
-
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");
|
|
6316
6482
|
this.setCtaPhase("idle");
|
|
6317
6483
|
this.syncTray();
|
|
6318
6484
|
return;
|
|
@@ -6329,7 +6495,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6329
6495
|
const problem = err;
|
|
6330
6496
|
const labels = (problem.conflicts ?? []).map((conflict) => conflict.label).filter(Boolean).slice(0, 3);
|
|
6331
6497
|
if (problem.reason === "event_closed") this.setSalesClosed(true);
|
|
6332
|
-
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.");
|
|
6333
6499
|
this.toast(message, "error");
|
|
6334
6500
|
this.setCtaPhase("idle");
|
|
6335
6501
|
} finally {
|
|
@@ -6343,14 +6509,14 @@ var SeatPicker = class _SeatPicker {
|
|
|
6343
6509
|
const ms = Math.max(0, this.holdExpiresAt - Date.now());
|
|
6344
6510
|
const m = Math.floor(ms / 6e4);
|
|
6345
6511
|
const s = String(Math.floor(ms % 6e4 / 1e3)).padStart(2, "0");
|
|
6346
|
-
return
|
|
6512
|
+
return t2("picker.holdReassurance", { time: `${m}:${s}` });
|
|
6347
6513
|
}
|
|
6348
6514
|
startHoldTimer(expiresAt) {
|
|
6349
6515
|
this.stopHoldTimer();
|
|
6350
6516
|
this.holdExpiresAt = expiresAt;
|
|
6351
6517
|
if (this.hold) this.rememberHold(this.hold);
|
|
6352
6518
|
const pill = this.els.hold;
|
|
6353
|
-
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>`;
|
|
6354
6520
|
const time = pill.querySelector('[data-ref="holdTime"]');
|
|
6355
6521
|
this.els.holdNote?.classList.add("on");
|
|
6356
6522
|
const tick = () => {
|
|
@@ -6383,7 +6549,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6383
6549
|
const totalSecs = Math.ceil(ms / 1e3);
|
|
6384
6550
|
const m = Math.floor(totalSecs / 60);
|
|
6385
6551
|
const s = String(totalSecs % 60).padStart(2, "0");
|
|
6386
|
-
this.els.extendTxt.innerHTML =
|
|
6552
|
+
this.els.extendTxt.innerHTML = t2("picker.seatsHeldForNeedMoreTime", { time: `${m}:${s}` });
|
|
6387
6553
|
this.extendEl.classList.add("on");
|
|
6388
6554
|
} else {
|
|
6389
6555
|
this.extendEl.classList.remove("on");
|
|
@@ -6393,7 +6559,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6393
6559
|
const btn = this.els.extendBtn;
|
|
6394
6560
|
btn.disabled = true;
|
|
6395
6561
|
const prev = btn.textContent;
|
|
6396
|
-
btn.textContent = "Adding\u2026";
|
|
6562
|
+
btn.textContent = this.tf("picker.addingEllipsis", "Adding\u2026");
|
|
6397
6563
|
try {
|
|
6398
6564
|
const h = await this.controller.extendHold(this.opts.holdTtlMs);
|
|
6399
6565
|
if (h) {
|
|
@@ -6402,13 +6568,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
6402
6568
|
this.extendEl?.classList.remove("on");
|
|
6403
6569
|
this.rememberHold(this.hold);
|
|
6404
6570
|
this.emitHoldChange();
|
|
6405
|
-
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");
|
|
6406
6572
|
} else {
|
|
6407
|
-
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");
|
|
6408
6574
|
}
|
|
6409
6575
|
} catch (err) {
|
|
6410
6576
|
this.opts.onError?.(err);
|
|
6411
|
-
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");
|
|
6412
6578
|
} finally {
|
|
6413
6579
|
btn.disabled = false;
|
|
6414
6580
|
btn.textContent = prev;
|
|
@@ -6435,7 +6601,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6435
6601
|
this.forgetHold();
|
|
6436
6602
|
const n = handoff.lineItems.reduce((sum, i) => sum + i.quantity, 0);
|
|
6437
6603
|
if (this.els.bookedSub) {
|
|
6438
|
-
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.")}`;
|
|
6439
6605
|
}
|
|
6440
6606
|
this.bookedEl?.classList.add("on");
|
|
6441
6607
|
this.opts.onBooked?.(handoff);
|
|
@@ -6517,7 +6683,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6517
6683
|
({ mountCheckout } = await loadHostedCheckout());
|
|
6518
6684
|
} catch (err) {
|
|
6519
6685
|
this.opts.onError?.(err);
|
|
6520
|
-
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");
|
|
6521
6687
|
this.setCtaPhase("idle");
|
|
6522
6688
|
return;
|
|
6523
6689
|
}
|
|
@@ -6632,9 +6798,9 @@ var SeatPicker = class _SeatPicker {
|
|
|
6632
6798
|
rowTypeWord(details) {
|
|
6633
6799
|
const authored = details?.displayType?.trim() || details?.rowType?.trim();
|
|
6634
6800
|
if (authored) return authored;
|
|
6635
|
-
if (details?.objectType === "table") return "Table";
|
|
6636
|
-
if (details?.objectType === "booth") return "Booth";
|
|
6637
|
-
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");
|
|
6638
6804
|
}
|
|
6639
6805
|
rowShort(details) {
|
|
6640
6806
|
const row = details?.rowLabel;
|
|
@@ -6657,7 +6823,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6657
6823
|
const isGroupedTable = details.objectType === "table" && !!details.bookingMode;
|
|
6658
6824
|
const isBooth = details.objectType === "booth";
|
|
6659
6825
|
const hasLoc = details.sectionLabel || details.rowLabel || details.seatNumber;
|
|
6660
|
-
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>`;
|
|
6661
6827
|
const statusLine = details.status === "free" ? "" : `<div class="sl-tip-status">${details.status === "held" ? t2("map.statusHeld") : t2("map.statusTaken")}</div>`;
|
|
6662
6828
|
const limited = this.limitedViewLabel(details.commercial);
|
|
6663
6829
|
const cxLine = limited ? `<div class="sl-tip-cx"><span class="g" aria-hidden="true">\u25D0</span>${esc(limited)}</div>` : "";
|
|
@@ -6948,7 +7114,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
6948
7114
|
const identity = details?.displayLabel ?? seat.displayLabel ?? seat.label;
|
|
6949
7115
|
const section = details?.sectionLabel;
|
|
6950
7116
|
const row = this.rowShort(details);
|
|
6951
|
-
const location2 = [section, row ?
|
|
7117
|
+
const location2 = [section, row ? t2("picker.rowLabel", { label: row }) : null, identity].filter(Boolean).join(" \xB7 ");
|
|
6952
7118
|
const copy = status === "held" ? {
|
|
6953
7119
|
title: this.tf("picker.temporarilyHeld", "Temporarily held"),
|
|
6954
7120
|
message: this.tf("picker.heldSeatExplanation", "Another buyer is holding this seat. It may become available again.")
|
|
@@ -7044,7 +7210,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7044
7210
|
chip = document.createElement("div");
|
|
7045
7211
|
chip.className = "sl-view3d-compare-saved";
|
|
7046
7212
|
chip.setAttribute("role", "group");
|
|
7047
|
-
chip.setAttribute("aria-label", "Saved seat comparison");
|
|
7213
|
+
chip.setAttribute("aria-label", this.tf("picker.savedSeatComparison", "Saved seat comparison"));
|
|
7048
7214
|
const main2 = document.createElement("button");
|
|
7049
7215
|
main2.type = "button";
|
|
7050
7216
|
main2.className = "main";
|
|
@@ -7056,7 +7222,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7056
7222
|
clear.type = "button";
|
|
7057
7223
|
clear.className = "clear";
|
|
7058
7224
|
clear.textContent = "\xD7";
|
|
7059
|
-
clear.setAttribute("aria-label", "Clear saved seat comparison");
|
|
7225
|
+
clear.setAttribute("aria-label", this.tf("picker.clearSavedSeatComparison", "Clear saved seat comparison"));
|
|
7060
7226
|
clear.addEventListener("click", () => this.clearView3dComparison());
|
|
7061
7227
|
chip.append(main2, clear);
|
|
7062
7228
|
overlay.appendChild(chip);
|
|
@@ -7065,8 +7231,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
7065
7231
|
const count = this.view3dCompareSeatIds.length;
|
|
7066
7232
|
const main = chip.querySelector(".main");
|
|
7067
7233
|
if (main) {
|
|
7068
|
-
main.textContent = count > 1 ?
|
|
7069
|
-
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"));
|
|
7070
7236
|
}
|
|
7071
7237
|
}
|
|
7072
7238
|
view3dComparisonSnapshot(seatId) {
|
|
@@ -7343,8 +7509,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7343
7509
|
const wantFloors = floors.length > 1;
|
|
7344
7510
|
const wantZones = zones.length > 1;
|
|
7345
7511
|
const wantSections = sections.length > 1;
|
|
7346
|
-
|
|
7347
|
-
if (!wantFloors && !wantZones && !wantSections && !wantLocator) return;
|
|
7512
|
+
if (!wantFloors && !wantZones && !wantSections) return;
|
|
7348
7513
|
const nav = document.createElement("div");
|
|
7349
7514
|
nav.className = "sl-view3d-nav";
|
|
7350
7515
|
const finderToggle = document.createElement("button");
|
|
@@ -7354,7 +7519,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7354
7519
|
const setFinderOpen = (open) => {
|
|
7355
7520
|
nav.classList.toggle("is-open", open);
|
|
7356
7521
|
finderToggle.setAttribute("aria-expanded", String(open));
|
|
7357
|
-
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");
|
|
7358
7523
|
};
|
|
7359
7524
|
finderToggle.addEventListener("click", () => setFinderOpen(!nav.classList.contains("is-open")));
|
|
7360
7525
|
nav.addEventListener("keydown", (event) => {
|
|
@@ -7391,7 +7556,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7391
7556
|
row.appendChild(b);
|
|
7392
7557
|
};
|
|
7393
7558
|
add(this.tf("picker.allLevels", "All levels"), null);
|
|
7394
|
-
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);
|
|
7395
7560
|
nav.appendChild(row);
|
|
7396
7561
|
}
|
|
7397
7562
|
if (wantZones || wantSections) {
|
|
@@ -7434,86 +7599,6 @@ var SeatPicker = class _SeatPicker {
|
|
|
7434
7599
|
}
|
|
7435
7600
|
nav.appendChild(row);
|
|
7436
7601
|
}
|
|
7437
|
-
if (wantLocator) {
|
|
7438
|
-
const locator = document.createElement("div");
|
|
7439
|
-
locator.className = "sl-view3d-locator";
|
|
7440
|
-
locator.setAttribute("role", "group");
|
|
7441
|
-
locator.setAttribute("aria-label", "Find an exact seat in 3D");
|
|
7442
|
-
const sectionSelect = document.createElement("select");
|
|
7443
|
-
sectionSelect.setAttribute("aria-label", "Choose section in 3D");
|
|
7444
|
-
const rowSelect = document.createElement("select");
|
|
7445
|
-
rowSelect.setAttribute("aria-label", "Choose row in 3D");
|
|
7446
|
-
const seatSelect = document.createElement("select");
|
|
7447
|
-
seatSelect.setAttribute("aria-label", "Choose seat in 3D");
|
|
7448
|
-
const view = document.createElement("button");
|
|
7449
|
-
view.type = "button";
|
|
7450
|
-
view.textContent = "Inspect seat";
|
|
7451
|
-
view.disabled = true;
|
|
7452
|
-
const fill = (select, placeholder, entries) => {
|
|
7453
|
-
select.replaceChildren();
|
|
7454
|
-
const first = document.createElement("option");
|
|
7455
|
-
first.value = "";
|
|
7456
|
-
first.textContent = placeholder;
|
|
7457
|
-
select.appendChild(first);
|
|
7458
|
-
for (const entry of entries) {
|
|
7459
|
-
const option = document.createElement("option");
|
|
7460
|
-
option.value = entry.id;
|
|
7461
|
-
option.textContent = entry.label;
|
|
7462
|
-
select.appendChild(option);
|
|
7463
|
-
}
|
|
7464
|
-
select.value = "";
|
|
7465
|
-
};
|
|
7466
|
-
fill(sectionSelect, "1. Section", allSections.map((section) => ({
|
|
7467
|
-
id: section.id,
|
|
7468
|
-
label: `${section.label} \xB7 ${section.seatCount.toLocaleString()} seats`
|
|
7469
|
-
})));
|
|
7470
|
-
fill(rowSelect, "2. Row", []);
|
|
7471
|
-
fill(seatSelect, "3. Seat", []);
|
|
7472
|
-
rowSelect.disabled = true;
|
|
7473
|
-
seatSelect.disabled = true;
|
|
7474
|
-
sectionSelect.addEventListener("change", () => {
|
|
7475
|
-
const sectionId = sectionSelect.value;
|
|
7476
|
-
view.disabled = true;
|
|
7477
|
-
fill(seatSelect, "3. Seat", []);
|
|
7478
|
-
seatSelect.disabled = true;
|
|
7479
|
-
if (!sectionId || !handle.focusSection(sectionId)) {
|
|
7480
|
-
fill(rowSelect, "2. Row", []);
|
|
7481
|
-
rowSelect.disabled = true;
|
|
7482
|
-
return;
|
|
7483
|
-
}
|
|
7484
|
-
const rows = handle.rows(sectionId);
|
|
7485
|
-
fill(rowSelect, "2. Row", rows.map((row) => ({
|
|
7486
|
-
id: row.id,
|
|
7487
|
-
label: `${row.label} \xB7 ${row.seatCount} seats`
|
|
7488
|
-
})));
|
|
7489
|
-
rowSelect.disabled = rows.length === 0;
|
|
7490
|
-
});
|
|
7491
|
-
rowSelect.addEventListener("change", () => {
|
|
7492
|
-
const rowId = rowSelect.value;
|
|
7493
|
-
view.disabled = true;
|
|
7494
|
-
if (!rowId || !handle.focusRow(rowId)) {
|
|
7495
|
-
fill(seatSelect, "3. Seat", []);
|
|
7496
|
-
seatSelect.disabled = true;
|
|
7497
|
-
return;
|
|
7498
|
-
}
|
|
7499
|
-
const seats = handle.seatsInRow(rowId);
|
|
7500
|
-
fill(seatSelect, "3. Seat", seats);
|
|
7501
|
-
seatSelect.disabled = seats.length === 0;
|
|
7502
|
-
});
|
|
7503
|
-
seatSelect.addEventListener("change", () => {
|
|
7504
|
-
const seatId = seatSelect.value;
|
|
7505
|
-
view.disabled = !seatId;
|
|
7506
|
-
});
|
|
7507
|
-
view.addEventListener("click", () => {
|
|
7508
|
-
const seatId = seatSelect.value;
|
|
7509
|
-
if (seatId) {
|
|
7510
|
-
setFinderOpen(false);
|
|
7511
|
-
this.onView3dSeatPick(seatId);
|
|
7512
|
-
}
|
|
7513
|
-
});
|
|
7514
|
-
locator.append(sectionSelect, rowSelect, seatSelect, view);
|
|
7515
|
-
nav.appendChild(locator);
|
|
7516
|
-
}
|
|
7517
7602
|
overlay.appendChild(nav);
|
|
7518
7603
|
}
|
|
7519
7604
|
async enter3d(flySeatId) {
|
|
@@ -7529,7 +7614,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7529
7614
|
const overlay = document.createElement("div");
|
|
7530
7615
|
overlay.className = "sl-view3d";
|
|
7531
7616
|
overlay.setAttribute("role", "group");
|
|
7532
|
-
overlay.setAttribute("aria-label", "Interactive 3D venue view");
|
|
7617
|
+
overlay.setAttribute("aria-label", this.tf("picker.interactive3dVenueView", "Interactive 3D venue view"));
|
|
7533
7618
|
const back = document.createElement("button");
|
|
7534
7619
|
back.type = "button";
|
|
7535
7620
|
back.className = "sl-view3d-back";
|
|
@@ -7555,7 +7640,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7555
7640
|
fullscreen.type = "button";
|
|
7556
7641
|
fullscreen.className = "sl-view3d-fs";
|
|
7557
7642
|
fullscreen.textContent = "\u26F6";
|
|
7558
|
-
fullscreen.setAttribute("aria-label", "Full screen");
|
|
7643
|
+
fullscreen.setAttribute("aria-label", this.tf("picker.fullScreen", "Full screen"));
|
|
7559
7644
|
fullscreen.setAttribute("aria-pressed", String(!!document.fullscreenElement || this.fsFallback || this.framedFs));
|
|
7560
7645
|
fullscreen.addEventListener("click", () => this.toggleFullscreen());
|
|
7561
7646
|
overlay.appendChild(fullscreen);
|
|
@@ -7592,7 +7677,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7592
7677
|
onSeatInspect: (id) => this.onView3dSeatPick(id),
|
|
7593
7678
|
onSectionFocusChange: (sectionId) => {
|
|
7594
7679
|
const select = overlay.querySelector(
|
|
7595
|
-
'select[
|
|
7680
|
+
'select[data-locator="section"]'
|
|
7596
7681
|
);
|
|
7597
7682
|
const next = sectionId ?? "";
|
|
7598
7683
|
if (!select || select.value === next) return;
|
|
@@ -7689,7 +7774,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7689
7774
|
if (button) {
|
|
7690
7775
|
button.disabled = true;
|
|
7691
7776
|
button.classList.add("sl-busy");
|
|
7692
|
-
button.innerHTML =
|
|
7777
|
+
button.innerHTML = `<span class="sl-ba-spin" aria-hidden="true"></span>${this.tf("picker.findingEllipsis", "Finding\u2026")}`;
|
|
7693
7778
|
}
|
|
7694
7779
|
try {
|
|
7695
7780
|
const h = await this.controller.bestAvailable(qty, categoryKey, { ...opts, ttlMs: this.opts.holdTtlMs });
|
|
@@ -7711,7 +7796,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7711
7796
|
} catch (err) {
|
|
7712
7797
|
this.opts.onError?.(err);
|
|
7713
7798
|
const reason = err?.reason;
|
|
7714
|
-
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.");
|
|
7715
7800
|
this.toast(message, "error");
|
|
7716
7801
|
return null;
|
|
7717
7802
|
} finally {
|
|
@@ -7740,7 +7825,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
7740
7825
|
}
|
|
7741
7826
|
}
|
|
7742
7827
|
if (!released) {
|
|
7743
|
-
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");
|
|
7744
7829
|
return;
|
|
7745
7830
|
}
|
|
7746
7831
|
this.hold = null;
|