@seatlayer/js 0.92.5 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/{channelsMode-B41tbE29.d.cts → channelsMode-DYwJ6sfR.d.cts} +200 -27
- package/dist/{channelsMode-B41tbE29.d.ts → channelsMode-DYwJ6sfR.d.ts} +200 -27
- package/dist/channelsMode-YJO6FOPD.js +1 -0
- package/dist/{chunk-5VGXB6GJ.js → chunk-DR5JXWLO.js} +208 -228
- package/dist/chunk-JELR6YYZ.js +1 -0
- package/dist/hostedCheckout-GQQF4XDN.js +58 -0
- package/dist/index.cjs +40 -28
- package/dist/index.d.cts +82 -26
- package/dist/index.d.ts +82 -26
- package/dist/index.js +40 -28
- package/dist/manager.cjs +516 -340
- package/dist/manager.d.cts +2 -2
- package/dist/manager.d.ts +2 -2
- package/dist/manager.js +316 -120
- package/package.json +2 -2
- package/dist/channelsMode-KZU235GN.js +0 -1
- package/dist/hostedCheckout-K6C42MCF.js +0 -58
package/dist/manager.js
CHANGED
|
@@ -1,14 +1,100 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D as Oe,E as De,F as Ve,G as Pe,H as je,I as qe,J as Ne,K as _e,L as Ke,M as Ue,N as We,O as Ge,P as Ze,Q as Ye,R as Xe,S as Qe,T as Je,V as et,a as S,b as _,c as w,d as I,e as K,f as U,g as W,h as G,i as F,j as L,k as x,l as Z,m as Y,n as X,o as Q,p as J,q as M,r as m,s as O,t as ee,u as D,v as Re,w as Ae,x as $e,y as He,z as ze}from"./chunk-DR5JXWLO.js";import{d as B,f as j}from"./chunk-RZ2VKZ44.js";import"./chunk-OSZ7DOEH.js";var te={hold:"Held",release:"Released",expire:"Expired",book:"Booked",unbook:"Cancelled",block:"Blocked",unblock:"Unblocked"},T=class{constructor(e,t){this.host=e;this.fetchPage=t;this.closed=!1;this.busy=!1;this.generation=0;this.entries=[];this.next=null;this.summary=document.createElement("div");this.list=document.createElement("div");this.message=document.createElement("div");this.older=document.createElement("button");this.latest=document.createElement("button");e.className="slm-seat-history",this.summary.className="slm-history-counts",this.list.className="slm-history-list",this.list.setAttribute("role","region"),this.list.setAttribute("aria-label","Seat history"),this.list.tabIndex=0,this.message.className="slm-note",this.message.setAttribute("role","status"),this.older.className=this.latest.className="slm-btn ghost",this.older.textContent="Load older",this.older.hidden=!0,this.latest.textContent="New activity \xB7 Show latest",this.latest.hidden=!0,this.older.onclick=()=>{this.load(!0)},this.latest.onclick=()=>{this.list.scrollTop=0,this.latest.hidden=!0,this.load()},e.append(this.summary,this.latest,this.list,this.message,this.older),this.load()}destroy(){this.closed=!0,this.generation++}refresh(){this.busy||this.load(!1,!0)}async load(e=!1,t=!1){if(this.closed||this.busy||e&&!this.next)return;this.busy=!0,this.older.disabled=!0;let s=this.generation;t||(this.message.textContent="Loading history\u2026");try{let i=await this.fetchPage(e?this.next:void 0,this.action);if(this.closed||s!==this.generation)return;if(this.paintCounts(i),t&&this.entries.length&&i.entries[0]?.id!==this.entries[0]?.id&&this.list.scrollTop>24){this.latest.hidden=!1;return}let o=!t||i.entries[0]?.id!==this.entries[0]?.id;e?(this.entries=[...this.entries,...i.entries.filter(a=>!this.entries.some(n=>n.id===a.id))],this.next=i.nextBefore):o&&(this.entries=i.entries,this.next=i.nextBefore),o&&this.paintRows(),this.older.hidden=this.next===null,this.message.textContent=this.entries.length?"":"No recorded activity for this seat."}catch{if(!this.closed){this.message.textContent="History could not be loaded. ";let i=document.createElement("button");i.className="slm-btn ghost",i.textContent="Retry",i.onclick=()=>{this.load(e)},this.message.append(i)}}finally{this.busy=!1,this.older.disabled=!1}}paintCounts(e){let t=[{action:"",count:e.total},...e.counts];this.summary.replaceChildren(...t.map(({action:s,count:i})=>{let o=document.createElement("button");return o.type="button",o.textContent=s?`${te[s]??s} ${i}`:`${i} changes`,o.setAttribute("aria-pressed",String((this.action??"")===s)),o.onclick=()=>{this.busy||(this.action=s||void 0,this.entries=[],this.next=null,this.list.scrollTop=0,this.latest.hidden=!0,this.load())},o}))}paintRows(){let e=this.list.scrollTop;this.list.replaceChildren(...this.entries.map(t=>{let s=document.createElement("div");s.className="slm-history-row",s.dataset.action=t.action;let i=document.createElement("time");i.dateTime=new Date(t.at).toISOString(),i.textContent=new Date(t.at).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),i.title=new Date(t.at).toString();let o=document.createElement("strong");return o.textContent=te[t.action]??t.action,s.append(i,o),s})),this.list.scrollTop=e}};var tt={held:"HOLD",booked:"BOOK",expired:"EXPIRE",released:"RELEASE",cancelled:"CANCEL",blocked:"BLOCK",unblocked:"ON SALE",available:"FREE"},se={held:"Held",booked:"Booked",expired:"Hold expired",released:"Hold released",cancelled:"Booking cancelled",blocked:"Blocked",unblocked:"Back on sale",available:"Available again"},C=class{constructor(e,t,s){this.host=e;this.locate=s;this.items=[];this.shown=new Set;this.paused=!1;this.limit=100;this.signature="unrendered";this.abort=new AbortController;e.innerHTML='<button class="slm-new-activity" hidden></button><div class="slm-activity-list" role="region" aria-label="Recent activity" tabindex="0"></div><button class="slm-more-activity" hidden>Show more activity</button>',this.list=e.querySelector(".slm-activity-list"),this.newer=e.querySelector(".slm-new-activity"),this.more=e.querySelector(".slm-more-activity");let i={signal:this.abort.signal},o=()=>{this.paused=!1,this.signature="unrendered",this.list.scrollTop=0,this.render()};this.list.addEventListener("scroll",()=>{this.list.scrollTop>24&&(this.paused=!0)},i),this.list.addEventListener("focusin",()=>{this.paused=!0},i),this.list.addEventListener("toggle",a=>{a.target.open&&(this.paused=!0)},{...i,capture:!0}),this.newer.addEventListener("click",o,i),this.more.addEventListener("click",()=>{this.limit=200,this.signature="unrendered",this.render(!0)},i)}update(e){this.items=e,this.render()}render(e=!1){let t=this.items,s=t.filter(a=>!this.shown.has(a.id)).length;if(this.newer.hidden=!this.paused,this.newer.textContent=s?`${s} new activit${s===1?"y":"ies"} \xB7 Back to live`:"Reading earlier activity \xB7 Back to live",this.paused&&!e)return;let i=t.slice(0,this.limit),o=i.map(a=>`${a.id}:${a.verb}`).join("|");if(o!==this.signature){if(this.signature=o,this.shown=new Set(t.map(a=>a.id)),this.list.replaceChildren(),!i.length){let a=document.createElement("p");a.className="slm-activity-empty",a.textContent=this.items.length?"No activity matches these filters.":"Waiting for activity. Holds, bookings and releases will appear here.",this.list.append(a)}for(let a of i){let n=document.createElement("article");n.className="slm-activity-entry",n.dataset.status=a.status;let c=document.createElement("button");c.type="button",c.className="slm-activity-row";let d=`${se[a.verb]??a.verb} \xB7 ${a.count} seat${a.count===1?"":"s"} \xB7 ${a.sectionLabels?.join(", ")||"Event inventory"} \xB7 ${a.labels.join(", ")} \xB7 ${new Date(a.at).toLocaleString()}`;c.title=`${d} \u2014 click to show seats on the map`,c.setAttribute("aria-label",`Show seats on map: ${d}`),c.addEventListener("click",()=>this.locate(a.id));let r=document.createElement("time");r.dateTime=new Date(a.at).toISOString(),r.textContent=new Date(a.at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});let h=document.createElement("strong");h.textContent=tt[a.verb]??a.verb,h.title=se[a.verb]??a.verb;let p=document.createElement("span");if(p.className="slm-activity-seats",p.textContent=a.labels.join(", "),c.append(r,h,p),n.append(c),a.count>1){let u=document.createElement("details");u.className="slm-activity-details";let g=document.createElement("summary");g.textContent="\u22EF",g.setAttribute("aria-label",`Show all ${a.count} seats`);let f=document.createElement("p");f.textContent=d,u.append(g,f),n.append(u)}this.list.append(n)}this.more.hidden=t.length<=this.limit}}destroy(){this.abort.abort()}};var E=class{constructor(e){this.host=e;this.moving=!1;this.space=!1;this.monitor=!1;this.selected=0;this.abort=new AbortController;let t=document.createElement("div");t.className="slm-navigation";let s=b=>`<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${b}</svg>`,i=s('<path d="M8 13V6a2 2 0 0 1 4 0v6-8a2 2 0 0 1 4 0v8-6a2 2 0 0 1 4 0v10c0 4-3 6-7 6-3 0-5-2-7-5l-3-4a2 2 0 0 1 3-2l2 2Z"/>'),o=s('<path d="m5 3 14 10-7 1-3 7-4-18Z"/>'),a=s('<circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 5 5"/>'),n=s('<path d="M7 6h10M12 1v10M7 18h10"/>'),c=s('<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M15 4v16"/>');t.innerHTML=`<div class="slm-navigation-tools" role="group" aria-label="Map navigation">
|
|
2
2
|
<button type="button" data-nav="move" aria-label="Move" aria-pressed="false" title="Drag to move the map; hold Space temporarily">${i}</button>
|
|
3
|
-
<button type="button" data-nav="select" aria-label="Select" aria-pressed="true" title="Drag to select seats \xB7 drag empty floor to move">${
|
|
4
|
-
<button type="button" data-nav="search" aria-label="Search" title="Search seats, rows or sections" aria-expanded="false">${
|
|
5
|
-
<button type="button" data-nav="zoom" aria-label="Zoom" title="Zoom controls" aria-expanded="false">${
|
|
3
|
+
<button type="button" data-nav="select" aria-label="Select" aria-pressed="true" title="Drag to select seats \xB7 drag empty floor to move">${o}</button>
|
|
4
|
+
<button type="button" data-nav="search" aria-label="Search" title="Search seats, rows or sections" aria-expanded="false">${a}</button>
|
|
5
|
+
<button type="button" data-nav="zoom" aria-label="Zoom" title="Zoom controls" aria-expanded="false">${n}</button>
|
|
6
6
|
<button type="button" hidden data-nav="out" aria-label="Zoom out">\u2212</button>
|
|
7
7
|
<button type="button" hidden data-nav="in" aria-label="Zoom in">+</button>
|
|
8
8
|
<span class="slm-navigation-count" role="status" aria-live="polite">0 selected</span>
|
|
9
9
|
<button type="button" class="slm-navigation-clear" data-nav="clear" hidden title="Clear the selection">Clear</button>
|
|
10
|
-
<button type="button" data-nav="rail" aria-label="Hide details" title="Hide details" aria-expanded="true">${
|
|
11
|
-
</div><div class="slm-navigation-search" hidden><input type="search" aria-label="Find section, row or seat" placeholder="Find section, row or seat"><div class="slm-navigation-results" hidden></div></div>`,e.map.after(t),this.bar=t,this.move=t.querySelector('[data-nav="move"]'),this.select=t.querySelector('[data-nav="select"]'),this.search=t.querySelector("input"),this.count=t.querySelector(".slm-navigation-count"),this.clear=t.querySelector('[data-nav="clear"]'),this.results=t.querySelector(".slm-navigation-results"),this.location=document.createElement("div"),this.location.className="slm-location",this.location.hidden=!0,this.location.setAttribute("role","status"),e.map.after(this.location);let
|
|
10
|
+
<button type="button" data-nav="rail" aria-label="Hide details" title="Hide details" aria-expanded="true">${c}</button>
|
|
11
|
+
</div><div class="slm-navigation-search" hidden><input type="search" aria-label="Find section, row or seat" placeholder="Find section, row or seat"><div class="slm-navigation-results" hidden></div></div>`,e.map.after(t),this.bar=t,this.move=t.querySelector('[data-nav="move"]'),this.select=t.querySelector('[data-nav="select"]'),this.search=t.querySelector("input"),this.count=t.querySelector(".slm-navigation-count"),this.clear=t.querySelector('[data-nav="clear"]'),this.results=t.querySelector(".slm-navigation-results"),this.location=document.createElement("div"),this.location.className="slm-location",this.location.hidden=!0,this.location.setAttribute("role","status"),e.map.after(this.location);let d={signal:this.abort.signal},r=t.querySelector('[data-nav="search"]'),h=t.querySelector(".slm-navigation-search"),p=()=>{h.hidden=!0,this.results.hidden=!0,r.setAttribute("aria-expanded","false"),r.focus()};r.addEventListener("click",()=>{let b=h.hidden;h.hidden=!b,r.setAttribute("aria-expanded",String(b)),b&&this.search.focus()},d);let u=t.querySelector('[data-nav="zoom"]');u.addEventListener("click",()=>{let b=u.getAttribute("aria-expanded")!=="true";u.setAttribute("aria-expanded",String(b));for(let y of["in","out"])t.querySelector(`[data-nav="${y}"]`).hidden=!b},d),this.search.addEventListener("keydown",b=>{b.key==="Escape"&&p()},d),this.move.addEventListener("click",()=>this.setMoving(!0),d),this.select.addEventListener("click",()=>this.setMoving(!1),d),this.clear.addEventListener("click",()=>this.host.clearSelection(),d),t.querySelector('[data-nav="in"]').addEventListener("click",()=>{this.location.hidden=!0,e.pauseFollow(),e.zoomIn()},d),t.querySelector('[data-nav="out"]').addEventListener("click",()=>{this.location.hidden=!0,e.pauseFollow(),e.zoomOut()},d);let g=t.querySelector('[data-nav="rail"]');g.addEventListener("click",()=>{let b=e.root.classList.toggle("details-hidden");g.setAttribute("aria-expanded",String(!b)),g.setAttribute("aria-label",b?"Show details":"Hide details"),g.title=b?"Show details":"Hide details"},d),this.search.addEventListener("input",()=>this.find(),d),this.search.addEventListener("keydown",b=>{b.key==="Escape"&&(this.results.hidden=!0),b.key==="ArrowDown"&&(b.preventDefault(),this.results.querySelector("button")?.focus())},d),e.map.addEventListener("pointerdown",()=>{this.location.hidden=!0,e.pauseFollow(),e.root.focus({preventScroll:!0}),this.results.hidden=!0},{...d,capture:!0}),e.root.querySelector(".slm-rail")?.addEventListener("pointerdown",()=>e.pauseFollow(),{...d,capture:!0}),e.map.addEventListener("wheel",()=>{this.location.hidden=!0,e.pauseFollow()},{...d,passive:!0,capture:!0}),e.root.addEventListener("keydown",b=>{b.target?.closest('input,textarea,select,button,[contenteditable="true"]')||b.code!=="Space"||b.ctrlKey||b.metaKey||b.altKey||(b.preventDefault(),this.space||(this.space=!0,e.pauseFollow(),e.setMoving(!0)))},d);let f=()=>{this.space&&(this.space=!1,e.setMoving(this.moving))};window.addEventListener("keyup",b=>{b.code==="Space"&&f()},d),window.addEventListener("blur",f,d),window.addEventListener("resize",()=>{this.location.hidden=!0},d),e.root.querySelector('[data-ref="zfit"]')?.addEventListener("click",()=>{this.location.hidden=!0},d),e.root.addEventListener("focusout",b=>{e.root.contains(b.relatedTarget)||f()},d)}setMoving(e){this.moving=e,this.host.pauseFollow(),this.host.setMoving(e||this.space),this.move.setAttribute("aria-pressed",String(e)),this.select.setAttribute("aria-pressed",String(!e))}update(e,t=!1){this.monitor=t,this.count.hidden=t,this.paintClear(),this.move.hidden=!e,this.select.hidden=!e}selectionChanged(e){this.selected=e,this.count.textContent=`${e.toLocaleString()} selected`,this.paintClear()}paintClear(){this.clear.hidden=this.monitor||this.selected<1}find(){let e=this.search.value.trim();if(this.results.replaceChildren(),this.results.hidden=!e,!e)return;let t=this.host.targets(e);for(let s of t){let i=document.createElement("button");i.type="button",i.textContent=`${s.label} \xB7 ${s.detail}`,i.addEventListener("click",()=>{this.host.pauseFollow(),s.locate(),this.location.textContent=`${s.label} \xB7 ${s.detail}`,this.location.hidden=!1,this.results.hidden=!0,this.host.root.focus({preventScroll:!0})}),this.results.append(i)}t.length||(this.results.textContent="No matching section, row or seat.")}destroy(){this.abort.abort(),this.bar.remove(),this.location.remove()}};import{SeatmapRenderer as dt,applyOrganizerSeatGlyph as ht,clearOrganizerSeatGlyph as mt,isOrganizerGlyphPainted as pt,expandChart as ut,computeSections as bt,floorsOf as Me,gaAreasOf as gt,gaUnitLabels as ft,UNGROUPED_ID as v}from"@seatlayer/core";var st=/^[a-zA-Z0-9._-]+$/;function it(l){let e;try{e=new URL(l,"https://seatlayer.invalid")}catch{return null}if(e.search||e.hash)return null;let t=/^\/v1\/events\/([^/]+)\/assets\/([^/]+)$/.exec(e.pathname);if(!t)return null;try{let s=decodeURIComponent(t[1]),i=decodeURIComponent(t[2]);return!s||!st.test(i)?null:{eventKey:s,asset:i}}catch{return null}}function ot(l){try{return/^\/v1\/events\/[^/]+\/assets(?:\/|$)/.test(new URL(l,"https://seatlayer.invalid").pathname)}catch{return!1}}var R=class{constructor(e,t){this.eventKey=e;this.load=t;this.pending=new Map;this.created=new Set;this.disposed=!1}resolve(e){let t=it(e);if(!t)return Promise.resolve(ot(e)?null:e);if(t.eventKey!==this.eventKey||this.disposed)return Promise.resolve(null);let s=`${t.eventKey}/${t.asset}`,i=this.pending.get(s);if(i)return i;let o=this.load(t.eventKey,t.asset).then(a=>{let n=URL.createObjectURL(a);return this.disposed?(URL.revokeObjectURL(n),null):(this.created.add(n),n)}).catch(a=>{throw this.pending.delete(s),a});return this.pending.set(s,o),o}async prepareRendererChart(e){let t=async o=>{if(!o?.url)return;let a=await this.resolve(o.url);if(!a)throw new Error("organizer_event_asset_scope_mismatch");o.url=a},s=async o=>{for(let a of o){if(a.type!=="decorImage")continue;let n=a,c=await this.resolve(n.href);if(!c)throw new Error("organizer_event_asset_scope_mismatch");n.href=c}},i=async o=>{await t(o.backgroundImage),await s(o.objects)};await i(e);for(let o of e.floors??[])await i(o);return e}dispose(){if(!this.disposed){this.disposed=!0;for(let e of this.created)URL.revokeObjectURL(e);this.created.clear(),this.pending.clear()}}};function ie(l,e,t,s={}){let i=s.previous?null:document.activeElement??null;s.previous?.scrim.remove();let o=document.createElement("div");o.className="slm-ch-scrim",o.innerHTML=`<div class="slm-ch-dialog" role="dialog" aria-modal="true"
|
|
12
|
+
aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,l.appendChild(o);let a=o.firstElementChild,n=!1,c={scrim:o,dialog:a,close:({restoreFocus:r=!0}={})=>{n||(n=!0,o.remove(),r&&i?.focus?.(),s.onClose?.())}};return a.querySelectorAll("[data-ch-close]").forEach(r=>{r.addEventListener("click",()=>c.close())}),o.addEventListener("keydown",r=>{if(r.key==="Escape"){r.stopPropagation(),c.close();return}if(r.key!=="Tab")return;let h=[...a.querySelectorAll('summary,button:not([disabled]),select:not([hidden]),input,textarea,a[href],[tabindex]:not([tabindex="-1"])')];if(!h.length)return;let p=h[0],u=h[h.length-1];r.shiftKey&&document.activeElement===p?(r.preventDefault(),u.focus()):!r.shiftKey&&document.activeElement===u&&(r.preventDefault(),p.focus())}),t(a),S(a),(a.querySelector("input,summary,button")??a).focus(),c}var oe=`
|
|
13
|
+
.slm{--slm-ch-scrim:rgba(0,0,0,.58)}
|
|
14
|
+
.slm[data-theme=light]{--slm-ch-scrim:rgba(23,32,51,.42)}
|
|
15
|
+
.slm-ch-scrim{position:absolute;inset:0;z-index:12;background:var(--slm-ch-scrim);display:grid;place-items:center;
|
|
16
|
+
padding:18px;animation:slm-ch-fade var(--slm-mo-quick) var(--slm-mo-out)}
|
|
17
|
+
.slm-ch-dialog{width:min(460px,100%);max-height:100%;overflow:auto;overscroll-behavior:contain;background:var(--slm-surface);color:var(--slm-text);border:1px solid var(--slm-line);
|
|
18
|
+
border-radius:14px;padding:20px;box-shadow:0 24px 70px rgba(0,0,0,.6);
|
|
19
|
+
animation:slm-ch-rise var(--slm-mo-base) var(--slm-mo-out)}
|
|
20
|
+
.slm-ch-dialog h3{margin:0 0 4px;font-size:16px;font-weight:800;letter-spacing:-.01em}
|
|
21
|
+
.slm-ch-dialog .sub{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:14px}
|
|
22
|
+
.slm-ch-dialog .foot{display:flex;gap:8px;margin-top:16px}
|
|
23
|
+
.slm-ch-dialog .foot .slm-btn{flex:1;min-width:0}
|
|
24
|
+
.slm-ch-dialog .foot .quiet{flex:none;padding:10px 14px;min-height:44px;color:var(--slm-muted);font-weight:700;font-size:13px}
|
|
25
|
+
@keyframes slm-ch-fade{from{opacity:0}to{opacity:1}}
|
|
26
|
+
@keyframes slm-ch-rise{from{opacity:0;transform:translateY(10px) scale(.985)}to{opacity:1;transform:none}}
|
|
27
|
+
.slm-ch-err{color:var(--slm-text);font-size:11.5px;margin-top:6px}
|
|
28
|
+
.slm-ch-seatlist{max-height:44vh;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);
|
|
29
|
+
border-radius:10px;background:var(--slm-surface);margin-top:10px}
|
|
30
|
+
.slm-ch-seatgroup{padding:8px 10px;border-bottom:1px solid var(--slm-line);display:flex;align-items:center;
|
|
31
|
+
justify-content:space-between;gap:8px;font-size:11px;font-weight:800;color:var(--slm-muted);position:sticky;top:0;
|
|
32
|
+
background:var(--slm-surface)}
|
|
33
|
+
.slm-ch-seatgroup button{color:var(--slm-accent);font-weight:800;font-size:11px;min-height:32px}
|
|
34
|
+
.slm-ch-seatitem{display:flex;width:100%;min-height:40px;align-items:center;gap:9px;padding:8px 10px;border-bottom:1px solid var(--slm-line);
|
|
35
|
+
text-align:left;font-size:12.5px;line-height:1.3;color:var(--slm-text)}
|
|
36
|
+
.slm-ch-seatitem:hover:not(:disabled){background:var(--slm-tint)}
|
|
37
|
+
.slm-ch-seatitem .box{width:16px;height:16px;border-radius:4px;border:1px solid var(--slm-muted);display:grid;
|
|
38
|
+
place-items:center;font-size:10px;font-weight:900;color:transparent;flex:none}
|
|
39
|
+
.slm-ch-seatitem[aria-checked="true"] .box{border-color:var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
40
|
+
.slm-ch-seatitem .meta{margin-left:auto;color:var(--slm-muted);font-size:10.5px}
|
|
41
|
+
.slm-ch-seatitem:disabled{opacity:.55;cursor:not-allowed}
|
|
42
|
+
.slm-ch-seatitem .dot{width:9px;height:9px;border-radius:999px;flex:none}
|
|
43
|
+
/* Seat list as the map reads: section \u2192 row line \u2192 seat chips tinted by status. */
|
|
44
|
+
/* The seat list gets a wider plate than the pickers: rows of chips need air. */
|
|
45
|
+
.slm-ch-dialog:has(.slm-ch-seatlist.grid){width:min(560px,100%);padding:22px 22px 20px}
|
|
46
|
+
.slm-ch-dialog:has(.slm-ch-seatlist.grid) .sub{margin-bottom:18px}
|
|
47
|
+
.slm-ch-seatlist-tools{display:flex;align-items:center;gap:14px;margin:0 0 14px}
|
|
48
|
+
.slm-ch-seatlist-tools .slm-find{flex:1;margin:0}
|
|
49
|
+
.slm-ch-seatlist-tools .slm-find .slm-input{min-height:34px}
|
|
50
|
+
.slm-ch-seatlegend{flex:none;display:flex;align-items:center;gap:4px 6px;flex-wrap:wrap;font-size:10.5px;color:var(--slm-muted);font-weight:700}
|
|
51
|
+
.slm-ch-seatlegend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:1px;vertical-align:-1px}
|
|
52
|
+
.slm-ch-seatlist.grid{max-height:52vh;margin-top:0}
|
|
53
|
+
.slm-ch-seatlist.grid .slm-ch-seatgroup{padding:10px 18px;letter-spacing:.06em;text-transform:uppercase;font-size:10.5px;background:var(--slm-tint)}
|
|
54
|
+
.slm-ch-seatlist.grid .slm-ch-seatgroup button{text-transform:none;letter-spacing:0}
|
|
55
|
+
.slm-ch-seatrow{display:grid;grid-template-columns:112px minmax(0,1fr);align-items:start;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slm-line)}
|
|
56
|
+
.slm-ch-seatrow.loose{grid-template-columns:minmax(0,1fr)}
|
|
57
|
+
.slm-ch-seatrow:last-child{border-bottom:0}
|
|
58
|
+
.slm-ch-rowcheck{display:flex;align-items:center;gap:8px;min-height:32px;padding:4px 6px;margin-left:-6px;border-radius:7px;font-size:12px;font-weight:800;color:var(--slm-text);text-align:left}
|
|
59
|
+
.slm-ch-rowcheck:hover{background:var(--slm-tint)}
|
|
60
|
+
.slm-ch-rowcheck .box{width:15px;height:15px;flex:none;display:grid;place-items:center;border:1.5px solid var(--slm-muted);border-radius:4px;color:transparent;font-size:9px;font-weight:900;box-sizing:border-box}
|
|
61
|
+
.slm-ch-rowcheck[aria-checked="true"] .box{border-color:var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
62
|
+
.slm-ch-rowcheck[aria-checked="mixed"] .box{border-color:var(--slm-accent);background:linear-gradient(var(--slm-accent),var(--slm-accent)) center/7px 2px no-repeat}
|
|
63
|
+
.slm-ch-rowcheck .name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
64
|
+
.slm-ch-rowcheck .meta{margin-left:auto;padding-left:8px;color:var(--slm-muted);font-size:10.5px;font-weight:700;font-variant-numeric:tabular-nums}
|
|
65
|
+
.slm-ch-seatchips{display:flex;flex-wrap:wrap;gap:7px;padding:1px 0}
|
|
66
|
+
.slm .slm-ch-seatchip{min-width:34px;height:34px;padding:0 9px;border-radius:9px;border:1.5px solid var(--slm-line);background:var(--slm-surface);color:var(--slm-text);
|
|
67
|
+
font-size:11.5px;font-weight:800;font-variant-numeric:tabular-nums;box-sizing:border-box;line-height:1;position:relative}
|
|
68
|
+
.slm-ch-seatchip:hover{border-color:var(--slm-muted)}
|
|
69
|
+
.slm-ch-seatchip:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
|
|
70
|
+
.slm .slm-ch-seatchip.is-free,.slm-ch-seatlegend .is-free{border:1.5px solid;border-color:color-mix(in srgb,var(--slm-accent) 45%,var(--slm-line));background:color-mix(in srgb,var(--slm-accent) 10%,var(--slm-surface))}
|
|
71
|
+
.slm .slm-ch-seatchip.is-held,.slm-ch-seatlegend .is-held{border:1.5px solid;border-color:#f4b740;background:color-mix(in srgb,#f4b740 22%,var(--slm-surface))}
|
|
72
|
+
.slm .slm-ch-seatchip.is-booked,.slm-ch-seatlegend .is-booked{border:1.5px solid transparent;background:color-mix(in srgb,var(--slm-muted) 35%,var(--slm-surface));color:var(--slm-muted)}
|
|
73
|
+
.slm .slm-ch-seatchip.is-blocked,.slm-ch-seatlegend .is-blocked{border:1.5px dashed;border-color:var(--slm-muted);color:var(--slm-muted);background:transparent}
|
|
74
|
+
.slm .slm-ch-seatchip[aria-checked="true"]{border:1.5px solid var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink);box-shadow:0 0 0 2px color-mix(in srgb,var(--slm-accent) 30%,transparent)}
|
|
75
|
+
.slm-ch-seatfoot{align-items:center;gap:10px;margin-top:18px;padding-top:16px;border-top:1px solid var(--slm-line)}
|
|
76
|
+
.slm-ch-seatfoot .slm-ch-seatcount{flex:1;min-width:0;font-size:12px;font-weight:700;color:var(--slm-muted);font-variant-numeric:tabular-nums}
|
|
77
|
+
.slm-ch-seatfoot .slm-btn{flex:none;min-width:110px}
|
|
78
|
+
.slm-ch-seatfoot .quiet:disabled{opacity:.45}
|
|
79
|
+
.slm-ch-scopebar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:10px;margin-top:12px}
|
|
80
|
+
.slm-ch-scopebar label{display:grid;gap:5px;color:var(--slm-muted);font-size:10.5px;font-weight:800}
|
|
81
|
+
.slm-ch-scopebar input{width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--slm-line);border-radius:8px;
|
|
82
|
+
background:var(--slm-surface);color:var(--slm-text);font:inherit}
|
|
83
|
+
.slm-ch-scopesummary{padding-bottom:10px;color:var(--slm-muted);font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
84
|
+
.slm-ch-scopegroup{position:sticky;top:0;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;
|
|
85
|
+
gap:6px;padding:6px 8px;border-bottom:1px solid var(--slm-line);background:var(--slm-surface)}
|
|
86
|
+
.slm-ch-groupcheck{display:flex;min-width:0;align-items:center;gap:8px;padding:5px 2px;text-align:left;font-size:11px;font-weight:800}
|
|
87
|
+
.slm-ch-groupcheck .box{width:16px;height:16px;flex:none;display:grid;place-items:center;border:1px solid var(--slm-muted);border-radius:4px;
|
|
88
|
+
color:transparent;font-size:10px}
|
|
89
|
+
.slm-ch-groupcheck[aria-checked="true"] .box,.slm-ch-groupcheck[aria-checked="mixed"] .box{border-color:var(--slm-accent);
|
|
90
|
+
background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
91
|
+
.slm-ch-groupcheck .meta{min-width:0;margin-left:auto;color:var(--slm-muted);font-size:10.5px;font-weight:600;white-space:nowrap}
|
|
92
|
+
.slm-ch-grouptoggle{min-height:32px;padding:5px 8px;color:var(--slm-accent);font-size:11px;font-weight:800}
|
|
93
|
+
.slm-ch-scopehint{padding:8px 10px;color:var(--slm-muted);font-size:10.5px;border-bottom:1px solid var(--slm-line)}
|
|
94
|
+
.slm-ch-scope-empty{padding:18px 12px;color:var(--slm-muted);font-size:11.5px;text-align:center}
|
|
95
|
+
@media(max-width:560px){.slm-ch-scopebar{grid-template-columns:1fr}.slm-ch-scopesummary{padding-bottom:0}}
|
|
96
|
+
@media (prefers-reduced-motion:reduce){.slm-ch-scrim,.slm-ch-dialog{animation:none!important}}
|
|
97
|
+
`;var ae="seatlayer-manager-style",ne="seatlayer-manager-channels-style",at=`${oe}
|
|
12
98
|
/* The floor was 480px, which trapped the cockpit in any host shorter than that:
|
|
13
99
|
every ancestor here is overflow:hidden, so the bottom of the rail (Create
|
|
14
100
|
channel, Show archived) was rendered but clipped away by the host and could
|
|
@@ -158,6 +244,41 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
158
244
|
.slm-map{position:relative;flex:1;min-width:0}
|
|
159
245
|
.slm-map-host{position:absolute;inset:0}
|
|
160
246
|
.slm-hud{position:absolute;left:12px;bottom:12px;display:flex;gap:8px}
|
|
247
|
+
/* Map chrome (plan item 7): crumb \xB7 zoom pills \xB7 minimap, one corner, bottom-right. */
|
|
248
|
+
.slm-mapchrome{position:absolute;right:12px;bottom:12px;z-index:5;display:flex;flex-direction:column;align-items:flex-end;gap:10px;pointer-events:none}
|
|
249
|
+
.slm-mapchrome>*{pointer-events:auto}
|
|
250
|
+
.slm-crumb{max-width:260px;padding:6px 11px;border-radius:999px;font-size:11.5px;font-weight:700;color:var(--slm-text);
|
|
251
|
+
background:color-mix(in srgb,var(--slm-surface) 88%,transparent);border:1px solid var(--slm-line);backdrop-filter:blur(8px);
|
|
252
|
+
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}
|
|
253
|
+
.slm-blocklegend{display:flex;gap:10px;padding:5px 10px;border-radius:999px;font-size:10.5px;font-weight:700;color:var(--slm-muted);
|
|
254
|
+
background:color-mix(in srgb,var(--slm-surface) 88%,transparent);border:1px solid var(--slm-line);backdrop-filter:blur(8px);white-space:nowrap}
|
|
255
|
+
.slm-blocklegend span{display:inline-flex;align-items:center;gap:5px}
|
|
256
|
+
.slm-blocklegend i{width:9px;height:9px;border-radius:3px;display:inline-block}
|
|
257
|
+
.slm-blocklegend[hidden]{display:none}
|
|
258
|
+
.slm-zoom{display:flex;flex-direction:column;gap:5px;align-items:flex-end}
|
|
259
|
+
.slm .slm-zoombtn{width:34px;height:34px;padding:0;border-radius:10px;border:1px solid var(--slm-line);background:color-mix(in srgb,var(--slm-surface) 88%,transparent);
|
|
260
|
+
backdrop-filter:blur(8px);color:var(--slm-text);font-size:17px;font-weight:700;line-height:1;box-shadow:0 8px 24px -14px rgba(0,0,0,.6);display:grid;place-items:center}
|
|
261
|
+
.slm .slm-zoombtn.slm-zoombtn-venue{width:auto;padding:0 11px;font-size:11.5px;font-weight:800;letter-spacing:.02em}
|
|
262
|
+
.slm .slm-zoombtn:hover:not(:disabled){border-color:var(--slm-muted)}
|
|
263
|
+
.slm .slm-zoombtn:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
|
|
264
|
+
.slm .slm-zoombtn:disabled{opacity:.42;cursor:default}
|
|
265
|
+
.slm-minimap-mount{line-height:0}
|
|
266
|
+
.slm-minimap-mount:empty{display:none}
|
|
267
|
+
.slm .sl-minimap{border:1px solid var(--slm-line);border-radius:9px;overflow:hidden;background:var(--slm-surface);
|
|
268
|
+
box-shadow:0 12px 34px -14px rgba(0,0,0,.55);line-height:0;touch-action:none}
|
|
269
|
+
.slm .sl-minimap-bar{min-height:24px;padding:3px 5px 3px 8px;display:flex;align-items:center;gap:6px;border-bottom:1px solid var(--slm-line);
|
|
270
|
+
color:var(--slm-muted);font-size:9px;font-weight:800;line-height:1.2;letter-spacing:.06em;text-transform:uppercase}
|
|
271
|
+
.slm .sl-minimap-label{min-width:0;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
272
|
+
.slm .sl-minimap-key{display:inline-flex;align-items:center;gap:3px;flex:none}
|
|
273
|
+
.slm .sl-minimap-key i{width:6px;height:6px;border-radius:999px;background:var(--slm-success,#22a06b)}
|
|
274
|
+
.slm .sl-minimap-key i.selected{background:var(--slm-accent)}
|
|
275
|
+
.slm .sl-minimap-key i.inactive{background:var(--slm-muted);opacity:.45}
|
|
276
|
+
.slm .sl-minimap-key i.focused{background:transparent;border:1.5px solid var(--slm-accent);width:7px;height:7px}
|
|
277
|
+
.slm .sl-minimap-close,.slm .sl-minimap-toggle{display:none}
|
|
278
|
+
.slm .sl-minimap canvas{display:block}
|
|
279
|
+
.slm .sl-minimap canvas:focus-visible{outline:2px solid var(--slm-accent);outline-offset:-3px}
|
|
280
|
+
.slm .sl-minimap canvas.sl-dragging{cursor:grabbing}
|
|
281
|
+
.slm.compact .slm-mapchrome{right:8px;bottom:8px}
|
|
161
282
|
.slm .slm-hud-chip{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:700;background:var(--slm-surface);
|
|
162
283
|
border:1px solid var(--slm-line);color:var(--slm-text)}
|
|
163
284
|
/* ONE top-centre lane. The zoom hint, the live-event pill and the Channels
|
|
@@ -171,6 +292,13 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
171
292
|
push the others down by its own height plus the gap. Taken out of flow
|
|
172
293
|
rather than display:none'd, so the fade in and out still runs. */
|
|
173
294
|
.slm-lane>:not(.on){position:absolute;top:0;pointer-events:none}
|
|
295
|
+
/* The session-ended card: the map stays painted under it; one way back. */
|
|
296
|
+
.slm-ended{display:flex;flex-direction:column;gap:8px;width:360px;max-width:calc(100vw - 48px);box-sizing:border-box;padding:16px 18px;border-radius:12px;pointer-events:auto;
|
|
297
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);box-shadow:0 18px 48px rgba(0,0,0,.3);color:var(--slm-text);text-align:left}
|
|
298
|
+
.slm-ended strong{font-size:14px;font-weight:800}
|
|
299
|
+
.slm-ended span{font-size:12.5px;line-height:1.5;color:var(--slm-muted)}
|
|
300
|
+
.slm-ended .slm-btn{align-self:flex-start;min-width:0;flex:none;margin-top:4px}
|
|
301
|
+
.slm-ended[data-busy="true"] .slm-btn{opacity:.6;pointer-events:none}
|
|
174
302
|
.slm-zoomhint{padding:6px 13px;border-radius:999px;
|
|
175
303
|
background:color-mix(in srgb,var(--slm-surface) 92%,transparent);color:var(--slm-text);
|
|
176
304
|
border:1px solid var(--slm-line);font-size:12px;font-weight:700;pointer-events:none;opacity:0;
|
|
@@ -226,6 +354,77 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
226
354
|
|
|
227
355
|
/* block toolbar */
|
|
228
356
|
.slm-selbar{display:flex;align-items:baseline;gap:6px;margin-bottom:6px}
|
|
357
|
+
.slm-selbar .slm-selclear{margin-left:auto}
|
|
358
|
+
/* The shared seat chooser (plan item 5). Chips read as one quiet group \u2014 a
|
|
359
|
+
pill row, not four grey boxes \u2014 Find sits under them with its glyph, and
|
|
360
|
+
the selection bar is one line: the count, the tool's words, then two
|
|
361
|
+
small ghost buttons rather than link text in the accent colour (which
|
|
362
|
+
read as "disabled" next to the primary action). Tokens only, so the light
|
|
363
|
+
ground gets its own surface, line and ink. */
|
|
364
|
+
.slm-chooser{display:flex;flex-direction:column;gap:6px;margin-top:6px}
|
|
365
|
+
.slm-chooser .slm-ch-row2{display:flex;flex-wrap:wrap;gap:6px;margin:0}
|
|
366
|
+
.slm-chooser .slm-ch-row2 .slm-btn{flex:0 1 auto;min-width:0;min-height:32px;padding:6px 12px;border-radius:999px;
|
|
367
|
+
font-size:12px;font-weight:700;line-height:1.2;letter-spacing:0;
|
|
368
|
+
background:var(--slm-tint);border:1px solid var(--slm-line);color:var(--slm-text);box-shadow:none}
|
|
369
|
+
.slm-chooser .slm-ch-row2 .slm-btn:hover{border-color:var(--slm-muted);background:var(--slm-tint-strong)}
|
|
370
|
+
.slm-chooser .slm-ch-row2 .slm-btn:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
|
|
371
|
+
.slm-chooser .slm-ch-row2 .slm-btn:not(.ghost){background:var(--slm-accent);color:var(--slm-accent-ink);border-color:var(--slm-accent)}
|
|
372
|
+
.slm-find{position:relative;margin:2px 0 0}
|
|
373
|
+
.slm-find::before{content:"";position:absolute;left:11px;top:50%;width:13px;height:13px;transform:translateY(-50%);pointer-events:none;
|
|
374
|
+
background:currentColor;color:var(--slm-muted);
|
|
375
|
+
-webkit-mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.5-3.5'/></svg>") center/contain no-repeat;
|
|
376
|
+
mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.5-3.5'/></svg>") center/contain no-repeat}
|
|
377
|
+
.slm-find .slm-input{width:100%;box-sizing:border-box;margin:0;min-height:36px;padding:8px 10px 8px 32px;border-radius:10px;
|
|
378
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);color:var(--slm-text);font-size:12.5px}
|
|
379
|
+
.slm-find .slm-input::placeholder{color:var(--slm-muted)}
|
|
380
|
+
.slm-find .slm-input:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px;border-color:var(--slm-accent)}
|
|
381
|
+
.slm-find-count{display:block;min-height:16px;margin:4px 0 0 2px;font-size:11px;color:var(--slm-muted);font-variant-numeric:tabular-nums}
|
|
382
|
+
.slm-find-count:empty{display:none}
|
|
383
|
+
.slm-selbar{display:flex;align-items:center;gap:8px;margin:10px 0 6px;padding:8px 0;border-top:1px solid var(--slm-line);border-bottom:1px solid var(--slm-line)}
|
|
384
|
+
.slm-selbar .slm-selactions{margin-left:auto;display:flex;gap:6px}
|
|
385
|
+
.slm-selbar .slm-selactions .slm-linkbtn,.slm-selbar .slm-selclear{min-height:28px;padding:4px 10px;border:1px solid var(--slm-line);border-radius:999px;white-space:nowrap;flex:none;
|
|
386
|
+
background:var(--slm-surface);color:var(--slm-text)!important;font-size:11.5px!important;font-weight:700!important;text-align:center}
|
|
387
|
+
.slm-selbar .slm-sellabel{min-width:0;line-height:1.3}
|
|
388
|
+
.slm-selbar .slm-selactions .slm-linkbtn:hover,.slm-selbar .slm-selclear:hover{border-color:var(--slm-muted);background:var(--slm-tint)}
|
|
389
|
+
.slm-selbar .slm-selclear{margin-left:0}
|
|
390
|
+
.slm-selbar .slm-selclear:disabled,.slm-selbar .slm-selactions .slm-linkbtn:disabled{opacity:.45}
|
|
391
|
+
.slm-catreset{margin-top:14px;padding-top:12px;border-top:1px solid var(--slm-line)}
|
|
392
|
+
.slm-catreset .slm-btn{width:100%}
|
|
393
|
+
.slm-catreset .slm-note{margin-top:6px}
|
|
394
|
+
/* The shared seat chooser (plan item 5): chip rows and the Find box under them. */
|
|
395
|
+
.slm-chooser{margin-top:2px}
|
|
396
|
+
.slm-find{position:relative;margin-top:8px}
|
|
397
|
+
.slm-find .slm-input{width:100%;box-sizing:border-box;margin:0;padding-right:8px}
|
|
398
|
+
.slm-find-count{display:block;min-height:16px;margin-top:4px;font-size:11px;color:var(--slm-muted);font-variant-numeric:tabular-nums}
|
|
399
|
+
.slm-find-count:empty{display:none}
|
|
400
|
+
/* Reading aids in the bar (plan item 5, slice D): the bar's Find and the View menu. */
|
|
401
|
+
.slm-findbar{flex:0 1 250px;min-width:150px}
|
|
402
|
+
.slm-findbar .slm-find{margin:0}
|
|
403
|
+
.slm-findbar .slm-find .slm-input{min-height:30px;padding:5px 9px 5px 30px;border-radius:8px;font-size:12px}
|
|
404
|
+
.slm-findbar .slm-find::before{left:10px;width:12px;height:12px}
|
|
405
|
+
.slm-findbar .slm-find-count{position:absolute;left:0;top:calc(100% + 3px);margin:0;padding:3px 9px;border-radius:7px;white-space:nowrap;z-index:5;
|
|
406
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);color:var(--slm-text);font-size:11px;box-shadow:0 8px 24px rgba(0,0,0,.18)}
|
|
407
|
+
.slm-view{position:relative;flex:none}
|
|
408
|
+
.slm-view > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:5px;min-height:30px;padding:5px 10px;border-radius:8px;font-size:12px;user-select:none}
|
|
409
|
+
.slm-view > summary::-webkit-details-marker{display:none}
|
|
410
|
+
.slm-view > summary.away::after{content:"";width:6px;height:6px;border-radius:50%;background:var(--slm-accent)}
|
|
411
|
+
.slm-view[open] > summary{border-color:var(--slm-muted);background:var(--slm-tint)}
|
|
412
|
+
.slm-view-caret{font-size:10px;opacity:.7}
|
|
413
|
+
.slm-view-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:238px;padding:6px;border-radius:12px;
|
|
414
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);box-shadow:0 14px 40px rgba(0,0,0,.28)}
|
|
415
|
+
.slm-view-item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 9px;border-radius:8px;border:0;background:transparent;color:var(--slm-text);font-size:12.5px;font-weight:600;text-align:left;cursor:pointer}
|
|
416
|
+
.slm-view-item:hover:not(:disabled){background:var(--slm-tint)}
|
|
417
|
+
.slm-view-item:focus-visible{outline:2px solid var(--slm-accent);outline-offset:-2px}
|
|
418
|
+
.slm-view-item:disabled{opacity:.45;cursor:default}
|
|
419
|
+
.slm-view-check{flex:none;width:15px;height:15px;border-radius:4px;border:1.5px solid var(--slm-muted);box-sizing:border-box}
|
|
420
|
+
.slm-view-item.on .slm-view-check{border-color:var(--slm-accent);background:var(--slm-accent);
|
|
421
|
+
-webkit-mask:none;mask:none;
|
|
422
|
+
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2.5 6.4 5 8.9l4.6-5.6'/></svg>");background-size:11px;background-position:center;background-repeat:no-repeat}
|
|
423
|
+
.slm[data-theme="light"] .slm-view-item.on .slm-view-check{background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%230b1220' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2.5 6.4 5 8.9l4.6-5.6'/></svg>")}
|
|
424
|
+
.slm-view-label{flex:1;min-width:0}
|
|
425
|
+
.slm-view-kbd{flex:none;font:600 10.5px/1 var(--slm-mono,ui-monospace,monospace);color:var(--slm-muted);padding:3px 5px;border:1px solid var(--slm-line);border-radius:5px}
|
|
426
|
+
.slm-view-note{margin:4px 3px 2px;padding:6px 8px 2px;border-top:1px solid var(--slm-line);font-size:11px;line-height:1.4;color:var(--slm-muted)}
|
|
427
|
+
.slm.compact .slm-findbar{flex:1 1 100%;min-width:0}
|
|
229
428
|
.slm-selnum{font-size:26px;font-weight:800;font-variant-numeric:tabular-nums}
|
|
230
429
|
.slm-sellabel{font-size:12px;color:var(--slm-muted);font-weight:600}
|
|
231
430
|
.slm-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
|
|
@@ -449,34 +648,59 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
449
648
|
transition:none!important;
|
|
450
649
|
scroll-behavior:auto!important}
|
|
451
650
|
}
|
|
452
|
-
`;function
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
651
|
+
`;function le(){if(typeof document>"u"||document.getElementById(ae))return;let l=document.createElement("style");l.id=ae,l.textContent=at,document.head.appendChild(l)}function re(l){if(typeof document>"u"||document.getElementById(ne))return;let e=document.createElement("style");e.id=ne,e.textContent=l,document.head.appendChild(e)}function ce(l){return l.total==null||l.free==null?l.label:l.free<=0?`${l.label} \xB7 sold out`:`${l.label} \xB7 ${l.free.toLocaleString()} of ${l.total.toLocaleString()} free`}function de(l){let t=q({focusedSection:l.focused?l.focused.label:null,seatsRevealed:l.seatsRevealed,atVenueFit:l.atVenueFit})==="none";return{crumb:l.focused?l.floor?`${l.floor} \xB7 ${ce(l.focused)}`:ce(l.focused):l.floor??"Venue",crumbShown:!!l.focused||!!l.floor,zoomInEnabled:!l.atCeiling,zoomOutEnabled:!t,venueEnabled:!t}}function he(l={}){return`
|
|
652
|
+
<div class="slm-mapchrome" data-ref="mapchrome">
|
|
653
|
+
${l.legend??""}
|
|
654
|
+
<div class="slm-crumb" data-ref="crumb" role="status" hidden></div>
|
|
655
|
+
<div class="slm-zoom" role="group" aria-label="Zoom">
|
|
656
|
+
<button type="button" class="slm-zoombtn" data-ref="zin" aria-label="Zoom in" title="Zoom in">+</button>
|
|
657
|
+
<button type="button" class="slm-zoombtn" data-ref="zout" aria-label="Zoom out one step" title="Zoom out one step (section, then venue)">\u2212</button>
|
|
658
|
+
<button type="button" class="slm-zoombtn slm-zoombtn-venue" data-ref="zfit" title="Whole venue">Venue</button>
|
|
659
|
+
</div>
|
|
660
|
+
<div class="slm-minimap-mount" data-ref="minimap"></div>
|
|
661
|
+
</div>`}function me(l,e){l.crumb&&(l.crumb.textContent=e.crumb,l.crumb.hidden=!e.crumbShown);let t=(s,i)=>{s&&(s.disabled=!i,s.setAttribute("aria-disabled",String(!i)))};t(l.zin,e.zoomInEnabled),t(l.zout,e.zoomOutEnabled),t(l.zfit,e.venueEnabled)}var k={plenty:{min:.5,color:"#22a06b",label:"Over half free"},tight:{min:.15,color:"#f4b740",label:"Under half free"},gone:{min:0,color:"#d9534f",label:"Nearly gone"}};function nt(l,e){let t=e>0?l/e:0;return t>=k.plenty.min?"plenty":t>=k.tight.min?"tight":"gone"}function lt(l,e,t,s=Date.now()){return l?.mode==="closed"||t?"Closed":l?.mode==="timed"&&l.revealAt&&l.revealAt>s?`Hidden until ${rt(l.revealAt,s)}`:l?.mode==="threshold"&&e?`Hidden until ${l.thresholdPct??0}% sold`:l?.mode==="hidden"||e?"Hidden":null}function rt(l,e){let t=new Date(l),s=t.toLocaleTimeString(void 0,{hour:"numeric",minute:t.getMinutes()?"2-digit":void 0}),i=(l-e)/864e5;return i<1&&t.getDate()===new Date(e).getDate()?s:i<6?`${t.toLocaleDateString(void 0,{weekday:"short"})} ${s}`:t.toLocaleDateString(void 0,{day:"numeric",month:"short"})}function pe(l,e){let t=l.state==="sold-out"?"Sold out":lt(e.rule,e.hiddenNow,e.closedNow);return{tint:t==="Closed"||t==="Sold out"?null:k[nt(l.free,l.total)].color,stateWord:t}}function ue(){return`<div class="slm-blocklegend" data-ref="blocklegend" aria-label="Block colours: share of seats free">${Object.keys(k).map(l=>`<span><i style="background:${k[l].color}"></i>${k[l].label}</span>`).join("")}</div>`}var be=[{key:"seatLabels",label:"Seat labels",letter:"S",hint:"Seat numbers where the zoom can carry them"},{key:"rowLabels",label:"Row labels",letter:"R",hint:"Row letters beside each row"},{key:"categoryColours",label:"Category colours",letter:"G",hint:"Off paints every category the same, so status is the only colour"},{key:"channelColours",label:"Channel colours",letter:"H",hint:"Channel flags and tints \u2014 the Channels tool\u2019s overlay"},{key:"momentum",label:"Booking momentum",letter:"M",hint:"Warm the sections booking fastest in the selected window"}],ge="seatlayer.controlRoom.mapView";function A(){return{seatLabels:!0,rowLabels:!0,categoryColours:!0,channelColours:!0,momentum:!1}}function fe(l){return be.find(t=>t.letter.toLowerCase()===l)?.key??null}function ve(l=xe()){let e=A();if(!l)return e;try{let t=l.getItem(ge);if(!t)return e;let s=JSON.parse(t),i={...e};for(let o of Object.keys(e))typeof s[o]=="boolean"&&(i[o]=s[o]);return i}catch{return e}}function ye(l,e=xe()){if(e)try{e.setItem(ge,JSON.stringify(l))}catch{}}function xe(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function we(l,e){e.renderer?.setLabelLayers?.({seatLabels:l.seatLabels,rowLabels:l.rowLabels}),e.renderer?.setCategoryColours?.(l.categoryColours),e.channelsOverlay(l.channelColours)}function ke(){return`
|
|
662
|
+
<details class="slm-view" data-ref="view">
|
|
663
|
+
<summary class="slm-barbtn slm-view-summary" aria-haspopup="menu" title="How the map reads: labels, colours, momentum">View <span class="slm-view-caret" aria-hidden="true">\u25BE</span></summary>
|
|
664
|
+
<div class="slm-view-menu" role="menu" aria-label="Map view">${be.map(e=>`
|
|
665
|
+
<button type="button" class="slm-view-item" role="menuitemcheckbox" data-view="${e.key}" aria-checked="false" title="${e.hint}">
|
|
666
|
+
<span class="slm-view-check" aria-hidden="true"></span>
|
|
667
|
+
<span class="slm-view-label">${e.label}</span>
|
|
668
|
+
<kbd class="slm-view-kbd" aria-hidden="true">\u21E7${e.letter}</kbd>
|
|
669
|
+
</button>`).join("")}
|
|
670
|
+
<div class="slm-view-note" data-ref="viewnote" hidden></div>
|
|
671
|
+
</div>
|
|
672
|
+
</details>`}function Se(l,e,t){let s=A(),i=!1;l.querySelectorAll("[data-view]").forEach(n=>{let c=n.dataset.view,d=e[c];n.setAttribute("aria-checked",String(d)),n.classList.toggle("on",d);let r=c==="channelColours"&&!t.channelColoursAvailable;n.disabled=r,n.setAttribute("aria-disabled",String(r)),!r&&d!==s[c]&&(i=!0)}),l.querySelector("summary")?.classList.toggle("away",i);let a=l.querySelector('[data-ref="viewnote"]');if(a){let n=[];t.channelColoursAvailable||n.push("Channel colours: open the Channels tool."),t.momentumLoading&&n.push("Booking momentum: loading the first snapshot\u2026"),a.hidden=!n.length,a.textContent=n.join(" ")}}import{UNGROUPED_ID as ct}from"@seatlayer/core";function V(l){return Object.entries(l).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function $(l){let e=l.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=l.doc?.zones??[],s=new Map,i=[];for(let d of e.sections)if(d.zone&&t.some(r=>r.id===d.zone)){let r=s.get(d.zone)??[];r.push(d),s.set(d.zone,r)}else i.push(d);let o=[],a=0,n=0,c=(d,r,h,p=!1)=>{let u=l.availabilityRules[r.id]??null,g=l.effectiveClosed.has(r.id)||p,f=l.effectiveHidden.has(r.id)||h&&!g;d==="section"&&f&&(a+=1),d==="section"&&g&&(n+=1),o.push({kind:d,id:r.id,label:r.label,seatCount:r.seatCount,seatLabels:r.seatLabels,rule:u,hidden:f,closed:g,followsZone:d==="section"&&h})};for(let d of t){let r=s.get(d.id);if(!r||!r.length)continue;let h={id:d.id,label:d.label||"Zone",seatCount:r.reduce((g,f)=>g+f.seatCount,0),seatLabels:r.flatMap(g=>g.seatLabels)},p=!!l.availabilityRules[d.id],u=l.availabilityRules[d.id]?.mode==="closed";c("zone",h,!1);for(let g of r)c("section",g,p,u)}for(let d of i)c("section",d,!1);if(e.ungrouped){let d=e.ungrouped;c("section",{id:ct,label:d.label,seatCount:d.seatCount,seatLabels:d.seatLabels},!1)}return{rows:o,hiddenSections:a,closedSections:n}}function Le(l,e){let t=K(l.rule),s=`slm-availrow${l.kind==="zone"?" zone":""}${l.hidden?" hidden":""}${l.closed?" closed":""}`,i=e?" disabled":"",o=[["open","Open","Available to buy"],["closed","Closed","Visible on the map, unavailable to buy"],["hidden","Hidden","Removed from the buyer map"],["timed","Scheduled reveal","Open at a specific date and time"],["threshold","Demand-based reveal","Open when sales reach a percentage"]],a=l.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<details class="slm-availpicker" data-avail-picker>
|
|
673
|
+
<summary aria-label="Availability for ${m(l.label)}" ${e?'aria-disabled="true"':""}>${o.find(r=>r[0]===t)[1]}<span aria-hidden="true">\u2304</span></summary>
|
|
674
|
+
<div class="slm-availchoices" aria-label="Availability options for ${m(l.label)}">
|
|
675
|
+
${o.map(([r,h,p])=>`<button type="button" data-avail-id="${m(l.id)}" data-avail-value="${r}" aria-pressed="${t===r}"${i}><span><b>${h}</b><small>${p}</small></span><span aria-hidden="true">${t===r?"\u2713":""}</span></button>`).join("")}
|
|
456
676
|
</div>
|
|
457
|
-
</details>`,
|
|
458
|
-
<input type="datetime-local" class="slm-input" data-avail-reveal="${
|
|
459
|
-
</div>`}else if(!
|
|
677
|
+
</details>`,n="";if(!l.followsZone&&t==="timed"){let r=l.rule?.revealAt?m(W(l.rule.revealAt)):"";n=`<div class="slm-availdetail">
|
|
678
|
+
<input type="datetime-local" class="slm-input" data-avail-reveal="${m(l.id)}" value="${r}"${i} aria-label="Reveal time for ${m(l.label)}" />
|
|
679
|
+
</div>`}else if(!l.followsZone&&t==="threshold"){let r=l.rule?.thresholdPct??80;n=`<div class="slm-availdetail">
|
|
460
680
|
<span class="slm-availpctlabel">Reveal at</span>
|
|
461
|
-
<input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${
|
|
681
|
+
<input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${m(l.id)}" value="${m(r)}"${i} aria-label="Percent sold to reveal ${m(l.label)}" />
|
|
462
682
|
<span class="slm-availpctlabel">% sold</span>
|
|
463
|
-
</div>`}let
|
|
683
|
+
</div>`}let c=l.closed?'<span class="slm-availbadge closed">Closed</span>':l.hidden?'<span class="slm-availbadge hidden">Hidden</span>':"",d=l.kind==="zone"?`<span class="slm-availcaret" aria-hidden="true">${l.hidden?"\u25B8":"\u25BE"}</span>`:"";return`<div class="${s}">
|
|
464
684
|
<div class="slm-availhead">
|
|
465
|
-
<span class="slm-availlabel">${
|
|
466
|
-
${
|
|
467
|
-
<span class="slm-availcount">${
|
|
685
|
+
<span class="slm-availlabel">${d}${m(l.label)}</span>
|
|
686
|
+
${c}
|
|
687
|
+
<span class="slm-availcount">${l.seatCount.toLocaleString()}</span>
|
|
468
688
|
</div>
|
|
469
|
-
${
|
|
470
|
-
${
|
|
471
|
-
</div>`}var We="https://api.seatlayer.io",$=200,ie=16,ae=4,oe=[{key:"watch",label:"Watch",tools:[{mode:"view",label:"Monitor",shortcut:"M",title:"Live board \u2014 inventory, activity and booking momentum. Read-only."},{mode:"inspect",label:"Inspect",shortcut:"I",title:"Click one seat to read its live status and booking context. Read-only."}]},{key:"manage",label:"Manage",tools:[{mode:"block",label:"Block",shortcut:"B",title:"Take seats off sale for this event, or put them back."},{mode:"sections",label:"Sections",shortcut:"S",title:"Open, close or hide sections for this event, on a schedule or on demand."},{mode:"categories",label:"Categories",shortcut:"G",title:"Move seats to a different price category for this event only."},{mode:"tables",label:"Tables",shortcut:"T",title:"Sell each table per chair or as one whole-table booking."},{mode:"channels",label:"Channels",shortcut:"C",title:"Allocate inventory to sales channels and share their links."}]},{key:"host",label:"Host tools",tools:[{mode:"select",label:"Select",shortcut:"X",title:"Select seats for your own back-office operation. The selection is handed to your app; nothing changes here."},{mode:"filterSections",label:"Filter",shortcut:"L",title:"Filter the map to one section for your own reporting."}]}],Ze=Object.fromEntries(oe.flatMap(h=>h.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),F=class{constructor(e){this.els={};this.renderer=null;this.doc=null;this.selectObserver=null;this.seatHistoryPanel=null;this.activityPanel=null;this.navigation=null;this.movingMap=!1;this.socketSnapshotSeen=!1;this.monitorRefreshTimer=null;this.themeMode=null;this.colorSchemeStop=null;this.inventoryModelVersion=1;this.selectableObjectLabels=new Set;this.lastSelectionLabels=new Set;this.selectionWasValid=null;this.initialSelectionApplied=!1;this.labelToId=new Map;this.labelToSeat=new Map;this.allIds=[];this.gaUnitLabelSet=new Set;this.status=new Map;this.counts={held:0,booked:0,blocked:0};this.modelVersion=0;this.currency="USD";this.authoritativeCurrency=null;this.authoritativeGrossRevenue=0;this.revenueStatus="loading";this.revenueRequest=0;this.controlRoomSnapshot=null;this.serverBaseline=null;this.livePresence=null;this.liveGross=null;this.paintHandle=null;this.trendWindowMinutes=15;this.heatEnabled=!1;this.lastKpiValues=new Map;this.activeKpiDeltas=new Map;this.ws=null;this.reconnectTimer=null;this.attempt=0;this.closed=!1;this.connectionStatus="reconnecting";this.lastMessageAt=null;this.ready=!1;this.feed=[];this.feedTimer=null;this.toastTimer=null;this.liveEventTimer=null;this.kpiCleanupTimer=null;this.followLiveTimer=null;this.followSeatTimer=null;this.releaseAt=null;this.layoutObserver=null;this.tokenExpiresAt=null;this.tokenRefreshTimer=null;this.tokenRefreshInFlight=!1;this.sectionByObject=new Map;this.sectionLabelById=new Map;this.sectionsBase=null;this.filteredSectionLabel=null;this.availabilityRules={};this.effectiveHidden=new Set;this.effectiveClosed=new Set;this.availabilitySaving=!1;this.lastSyncedAt=null;this.blockBrowse=!1;this.blockedQuery="";this.blockedSection="";this.blockedResultLimit=100;this.unblockAllConfirmTimer=null;this.channels=null;this.channelCaps={view:!1,manage:!1};this.categoryCanManage=!1;this.tableCanManage=!1;this.tableBookingSaving=!1;this.channelCapabilityResolution=0;this.channelsLoading=null;this.onFullscreenChange=()=>{this.paintFullscreenButton(),this.updateContainerLayout(),this.renderer?.forceDraw()};this.onKeyDown=e=>{if(e.metaKey||e.ctrlKey||e.altKey||e.target?.matches('input,select,textarea,[contenteditable="true"]'))return;let s=e.key.toLowerCase(),i=Ze[s];if(i){if(!this.toolAvailable(i))return;this.setMode(i)}else if(s==="f")this.toggleFullscreen();else if(s==="escape"){if(!this.channels?.handleBack())if(this.getSelection().length)this.clearSelection();else return}else return;e.preventDefault()};this.onRailClick=e=>{let t=e.target,s=t?.closest("[data-section-focus]");if(s?.dataset.sectionFocus){this.locateSection(s.dataset.sectionFocus);return}let i=t?.closest("[data-feed-id]");i?.dataset.feedId&&this.locateActivity(i.dataset.feedId)};this.sectionOptions=[];I(e.token),this.assertSelectionOptions(e.maxSelectedObjects,e.numberOfPlacesToSelect),this.opts=e,this.key=e.eventKey,this.mode=e.mode??"view",this.selectableObjectLabels=new Set(e.selectableObjects??[]),this.categoryCanManage=new Set(e.capabilities??[]).has("event:categories:manage"),this.tableCanManage=new Set(e.capabilities??[]).has("event:tables:manage"),this.keepLive=e.keepLiveWhileHidden??!0,this.themeMode=e.themeMode??null,this.followLive=e.followLive??!1,this.currency=e.currency??"USD",this.tokenExpiresAt=e.tokenExpiresAt??null,this.api=new z(e.apiBase??We,e.token),this.organizerAssetUrls=new M(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=Z(e.container)}assertSelectionOptions(e,t){let s=i=>i===void 0||Number.isInteger(i)&&i>0;if(!s(e))throw new TypeError("maxSelectedObjects must be a positive integer");if(!s(t))throw new TypeError("numberOfPlacesToSelect must be a positive integer");if(e!==void 0&&t!==void 0&&e<t)throw new TypeError("maxSelectedObjects cannot be lower than numberOfPlacesToSelect")}async render(){V(),this.buildChrome();try{let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1,this.doc=await this.organizerAssetUrls.prepareRendererChart(e.doc),this.authoritativeCurrency=e.event.currency??null,this.currency=this.authoritativeCurrency??this.opts.currency??this.currency,this.buildUnitUniverse(this.doc),this.buildRenderer(),this.buildSectionOptions(),this.settleMode();let[,t]=await Promise.all([this.resnapshot(),this.refreshControlRoom().catch(s=>this.opts.onError?.(s)),this.refreshAvailability()]);t?.activity?this.seedFeed(t.activity):this.api.log(this.key,{limit:24}).then(s=>this.seedFeed(s.entries)).catch(()=>{}),this.connect(),this.startFeedClock(),this.ready=!0,await this.resolveChannelCapabilities(),this.setMode(this.mode),this.applyInitialSelection(),this.scheduleTokenRefresh(),this.opts.onReady?.()}catch(e){this.fail(e)}return this}setMode(e){this.toolAvailable(e)||(e="view"),e==="channels"&&!this.channels&&this.ensureChannels();let t=e!==this.mode,s=this.mode==="channels",i=this.mode==="filterSections";this.mode=e,t&&e!=="view"&&this.setFollowLive(!1),!this.renderer&&this.doc?this.buildRenderer():this.updateRendererInteraction(),t&&(this.renderer?.clearSelection(),this.syncSelection()),s&&e!=="channels"&&this.channels?.leave(),this.paintModeTabs(),this.paintRail(),this.applySectionCanvasTreatment(),i&&e!=="filterSections"&&this.renderer?.zoomToFit(),e==="channels"&&this.channels?.enter(),e==="select"&&this.applyInitialSelection(),t&&this.opts.onModeChange?.(e)}async resolveChannelCapabilities(){let e=++this.channelCapabilityResolution,t=this.opts.capabilities,s;if(t){let i=new Set(t);s={view:i.has("event:channels:view"),manage:i.has("event:channels:view")&&i.has("event:channels:manage")}}else s={view:!1,manage:!1};if(!s.view&&!t)try{await this.api.channels(this.key),s={view:!0,manage:!1}}catch{s={view:!1,manage:!1}}if(e===this.channelCapabilityResolution){if(this.channelCaps=s,!this.channelCaps.view){this.channels?.destroy(),this.channels=null,this.mode==="channels"?this.setMode("view"):this.paintModeTabs();return}this.channels?.setCapabilities(this.channelCaps),this.paintModeTabs()}}ensureChannels(){if(this.channelsLoading)return this.channelsLoading;if(this.channels)return Promise.resolve();let e=(async()=>{try{let t=await import("./channelsMode-KZU235GN.js");if(this.closed||!this.channelCaps.view||(this.channels||(U(t.CHANNELS_CSS),this.channels=new t.ChannelsMode(this.buildChannelsHost(),this.channelCaps),this.channels.onInteractionChange=()=>this.updateRendererInteraction()),this.mode!=="channels"))return;this.updateRendererInteraction(),this.paintRail(),this.channels.enter()}catch(t){if(this.closed)return;this.channelsLoading=null,this.mode==="channels"&&this.paintRail(),this.opts.onError?.(t)}})();return this.channelsLoading=e,e}buildChannelsHost(){return{eventKey:this.key,api:this.api,rail:this.els.rail,mapLayer:this.root.querySelector(".slm-map"),pillLane:this.els.lane,root:this.root,seats:()=>[...this.labelToSeat.values()].map(e=>({id:e.id,label:e.label,x:e.x,y:e.y})),statusOf:e=>this.status.get(e)??(this.labelToSeat.has(e)?"free":void 0),selectionLabels:()=>this.selectionLabels(),selectByLabels:e=>{this.selectByLabels(e)},clearSelection:()=>this.clearSelection(),selectSection:e=>{this.selectSection(e)},sections:()=>this.sectionOptions,labelsInSection:e=>this.renderer?.getSelectableInSection(e).map(t=>t.label)??[],rows:()=>{let e=new Map((this.doc?.objects??[]).map(s=>[s.id,s])),t=new Map;for(let s of this.labelToSeat.values()){let i=e.get(s.rowId);if(!i||i.type!=="row"&&i.type!=="table")continue;let a=s.logicalRowId??s.rowId,o=this.sectionByObject.get(s.rowId)??x,l=t.get(a)??{id:a,label:i.type==="row"?i.segmentedRow?.displayLabel??i.displayLabel??i.label:i.displayLabel??i.label,sectionId:o,sectionLabel:this.sectionLabelById.get(o)??"Other seats",labels:[]};l.labels.push(s.label),t.set(a,l)}return[...t.values()].sort((s,i)=>s.sectionLabel.localeCompare(i.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(i.label,void 0,{numeric:!0,sensitivity:"base"}))},categories:()=>(this.doc?.categories??[]).map(e=>({key:e.key,label:e.label??e.key,color:e.color,price:e.price,tiers:e.tiers?.map(t=>({id:t.id,name:t.name,price:t.price}))})),labelsInCategory:e=>[...this.labelToSeat.entries()].filter(([,t])=>t.categoryKey===e).map(([t])=>t),sectionOfLabel:e=>{let t=this.labelToSeat.get(e);if(!t)return null;let s=this.sectionByObject.get(t.rowId)??x;return{id:s,label:this.sectionLabelById.get(s)??"Other seats"}},worldToScreen:e=>this.renderer?.worldToScreen(e)??null,seatPixelSize:()=>this.seatPixelSize(),isSeatDetail:()=>this.renderer?.getRung?.()==="seats",showSectionOverview:()=>{this.renderer?.clearSectionFocus(),this.renderer?.setRung?.("sections")},focusSection:e=>this.renderer?.focusSection(e),isCompact:()=>!!this.root?.classList.contains("compact"),setMapInert:e=>{this.mapHost.toggleAttribute("inert",e),this.mapHost.setAttribute("aria-hidden",String(e))},toast:(e,t)=>this.toast(e,t),onError:e=>this.opts.onError?.(e)}}seatPixelSize(){let e=this.renderer?.getVisibleWorldRect?.(),t=this.mapHost?.clientWidth??0;return!e?.width||!t?6:Math.max(3,t/e.width*18)}setHeatOverlay(e){this.heatEnabled=e,this.applyHeatOverlay(),this.paintHeatButton()}setFollowLive(e){let t=this.followLive!==e;this.followLive=e,e||(this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=null,this.followSeatTimer=null),this.paintFollowLiveButton(),t&&this.opts.onFollowLiveChange?.(e)}setKeepLiveWhileHidden(e){this.keepLive=e??!0,this.opts.keepLiveWhileHidden=e}setCurrency(e){this.opts.currency=e,!this.authoritativeCurrency&&(this.currency=e??"USD",this.ready&&this.recomputeTallies())}setTheme(e){this.opts.theme=e,this.applyThemeVars()}applyThemeVars(){if(!this.root)return;let e=B(this.themeMode);for(let[t,s]of Object.entries(Q(this.opts.theme,e)))this.root.style.setProperty(t,s);e?this.root.dataset.theme=e:delete this.root.dataset.theme}watchThemeMode(){this.colorSchemeStop?.(),this.colorSchemeStop=null,this.themeMode==="auto"&&(this.colorSchemeStop=j(()=>{this.closed||this.repaintForThemeMode()}))}repaintForThemeMode(){this.applyThemeVars();let e=this.renderer;if(!e||!this.doc)return;let t=e.getSelection().map(a=>a.id),s=e.getCameraPose(),i=e.getFocusedSection();e.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),t.length&&e.select(t),i&&e.focusSection(i),e.setCameraPose(s),this.updateZoomHint()}setThemeMode(e){let t=e??null;this.closed||t===this.themeMode||(this.themeMode=t,this.opts.themeMode=t??void 0,this.watchThemeMode(),this.repaintForThemeMode())}getThemeMode(){return this.themeMode}themedDoc(){let e=this.doc,t=J(B(this.themeMode));return t?{...e,theme:{...e.theme??{},background:t}}:e}setCapabilities(e){this.opts.capabilities=e,this.categoryCanManage=new Set(e??[]).has("event:categories:manage"),this.tableCanManage=new Set(e??[]).has("event:tables:manage"),!this.categoryCanManage&&this.mode==="categories"||!this.tableCanManage&&this.mode==="tables"?this.setMode("view"):this.paintModeTabs(),this.ready&&this.resolveChannelCapabilities()}setTokenRefresh(e){this.opts.onTokenRefresh=e,this.scheduleTokenRefresh()}setTrendWindow(e){let t=Number.isFinite(e)?Math.floor(e):15;return this.trendWindowMinutes=Math.max(5,Math.min(60,t)),this.paintTrendWindow(),this.refreshControlRoom()}async enterFullscreen(){!this.root?.requestFullscreen||this.isFullscreen()||(await this.root.requestFullscreen(),this.root.focus({preventScroll:!0}))}async exitFullscreen(){typeof document>"u"||!this.isFullscreen()||await document.exitFullscreen()}isFullscreen(){return typeof document<"u"&&document.fullscreenElement===this.root}toggleFullscreen(){(this.isFullscreen()?this.exitFullscreen():this.enterFullscreen()).catch(t=>this.opts.onError?.(t))}setToken(e,t){I(e),this.api.setToken(e),this.opts.token=e,this.opts.tokenExpiresAt=t,this.tokenExpiresAt=t??null,this.scheduleTokenRefresh(),this.ready&&this.resolveChannelCapabilities()}scheduleTokenRefresh(){this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.tokenRefreshTimer=null;let e=this.opts.onTokenRefresh,t=this.tokenExpiresAt;if(this.closed||!e||!t||!Number.isFinite(t))return;let s=t-Date.now(),i=Math.min(12e4,Math.max(3e4,s*.2)),a=Math.max(0,s-i);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},a)}async rotateToken(){if(!(this.closed||this.tokenRefreshInFlight||!this.opts.onTokenRefresh)){this.tokenRefreshInFlight=!0;try{let e=await this.opts.onTokenRefresh();if(!e?.token||!Number.isFinite(e.expiresAt))throw new Error("invalid_token_refresh_result");this.setToken(e.token,e.expiresAt)}catch(e){this.opts.onError?.(e),this.closed||(this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},3e4))}finally{this.tokenRefreshInFlight=!1}}}async block(e,t={}){let s=(e??this.selectionLabels()).filter(a=>this.status.get(a)==="free");if(!s.length)return;let i=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:i}),this.clearSelection(),this.done("block",s,i?`Blocked ${s.length} \u2014 auto-release ${new Date(i).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(a){this.setSeatsLocal(s,"free"),this.toastErr(a instanceof S&&a.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(a)}}async unblock(e){let t=(e??this.selectionLabels()).filter(s=>this.status.get(s)==="blocked");if(t.length){this.setSeatsLocal(t,"free");try{await this.api.unblock(this.key,t),this.clearSelection(),this.done("unblock",t,`Unblocked ${t.length} seat${t.length===1?"":"s"}.`)}catch(s){this.setSeatsLocal(t,"blocked"),this.toastErr("Couldn't unblock those seats."),this.opts.onError?.(s)}}}async unblockAll(){let e=[...this.status.entries()].filter(([,t])=>t==="blocked").map(([t])=>t);if(e.length){this.setSeatsLocal(e,"free");try{let t=await this.api.unblockAll(this.key);this.clearSelection(),this.done("unblockAll",e,`Unblocked ${t.freed} seat${t.freed===1?"":"s"}.`)}catch(t){await this.resnapshot(),this.toastErr("Couldn't mark everything for sale."),this.opts.onError?.(t)}}}async cancelBooking(e,t){let s=e.filter(i=>this.status.get(i)==="booked");if(!(!s.length||!t)){this.setSeatsLocal(s,"free");try{await this.api.unbook(this.key,s,t),this.clearSelection(),this.done("cancelBooking",s,`Released ${s.length} booked unit${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(i)}}}async setCategory(e,t){let s=this.doc?.categories.find(a=>a.key===e),i=[...new Set(t??this.selectionLabels())].filter(a=>this.labelToSeat.has(a));if(!(!s||!i.length))try{let a=await this.withAuthRetry(()=>this.api.setCategory(this.key,i,e)),o={};for(let l of a.labels){let r=this.labelToSeat.get(l),c=this.labelToId.get(l);r&&(r.categoryKey=e),c&&(o[c]=e)}this.renderer?.setSeatCategories?.(o),this.clearSelection(),this.done("setCategory",a.labels,`Assigned ${a.labels.length.toLocaleString()} object${a.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(a){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(a)}}async setTableBooking(e,t,s={}){let i=[...new Set(e)].filter(Boolean);if(!(!i.length||this.tableBookingSaving)){if(this.inventoryModelVersion!==2){this.toastErr("Table booking controls require inventory model 2 for this event.");return}this.tableBookingSaving=!0,this.mode==="tables"&&this.renderTablesRail();try{let a=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,i,t,s));await this.reloadEventChart(),this.done("setTableBooking",a.tableIds,`Updated ${a.tableIds.length.toLocaleString()} table${a.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(a){let o=a instanceof S&&a.code==="table_inventory_in_use";this.toastErr(o?"Release held, booked, or blocked table inventory before changing its booking mode.":"Couldn't update table booking. No table mode was changed."),this.opts.onError?.(a)}finally{this.tableBookingSaving=!1,this.mode==="tables"&&this.renderTablesRail()}}}async reloadEventChart(){let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1;let t=await this.organizerAssetUrls.prepareRendererChart(e.doc);this.renderer?.destroy(),this.renderer=null,this.doc=t,this.labelToId.clear(),this.labelToSeat.clear(),this.allIds=[],this.gaUnitLabelSet.clear(),this.status.clear(),this.counts={held:0,booked:0,blocked:0},this.serverBaseline=null,this.lastSelectionLabels.clear(),this.buildUnitUniverse(t),this.buildRenderer(),this.buildSectionOptions(),this.settleMode(),await Promise.all([this.resnapshot(),this.refreshAvailability()]),this.paintRail()}selectAll(){if(this.mode==="select")return this.selectByLabels([...this.labelToSeat.values()].filter(t=>this.canSelectObject(t)).map(t=>t.label));let e=this.renderer?.selectAllSelectable()??[];return this.syncSelection(),e}selectSection(e){if(!this.renderer)return[];let t=this.renderer.getSelectableInSection(e);return this.renderer.selectByLabels(t.map(s=>s.label)),this.syncSelection(),this.renderer.getSelection()}setFilteredSection(e){let t=e.trim(),s=this.filterableSections().filter(o=>o.label===t);if(!s.length)throw new Error(`Unknown event section: ${e}`);let i=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let a=s.map(({id:o,label:l,seatCount:r,zone:c})=>({id:o,label:l,seatCount:r,...c?{zone:c}:{}}));return i&&this.opts.onFilteredSectionChange?.(a),a}clearFilteredSection(){let e=this.filteredSectionLabel!==null;this.filteredSectionLabel=null,this.renderer?.setDimmedSections(null),this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit(),this.mode==="filterSections"&&this.renderFilterSectionsRail(),e&&this.opts.onFilteredSectionChange?.([])}getFilteredSections(){return this.filteredSectionLabel?this.filterableSections().filter(e=>e.label===this.filteredSectionLabel).map(({id:e,label:t,seatCount:s,zone:i})=>({id:e,label:t,seatCount:s,...i?{zone:i}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),i=this.selectionCap(),a=[...new Set(e)].filter(l=>!s.has(l)).map(l=>this.labelToSeat.get(l)).filter(l=>!!l&&this.canSelectObject(l)),o=Math.max(0,i-s.size);a.length>o&&this.opts.onSelectionLimit?.(i),t=a.slice(0,o).map(l=>l.label)}return this.renderer?.selectByLabels(t),this.syncSelection(),this.getSelection()}selectObjects(e){return this.selectByLabels(e)}deselectObjects(e){let t=e.map(s=>this.labelToId.get(s)).filter(s=>!!s);return this.renderer?.deselect(t),this.syncSelection(),this.getSelection()}selectCategories(e){let t=new Set(e);return this.selectByLabels([...this.labelToSeat.values()].filter(s=>t.has(s.categoryKey)).map(s=>s.label))}deselectCategories(e){let t=new Set(e);return this.deselectObjects(this.getSelection().filter(s=>t.has(s.categoryKey)).map(s=>s.label))}setSelectableObjects(e){this.opts.selectableObjects=[...e],this.selectableObjectLabels=new Set(e),this.reconcileSelectPolicy()}setUnavailableObjectsSelectable(e){this.opts.unavailableObjectsSelectable=e,this.reconcileSelectPolicy()}setObjectSelectable(e){this.opts.isObjectSelectable=e,this.reconcileSelectPolicy()}setMaxSelectedObjects(e){this.assertSelectionOptions(e,this.opts.numberOfPlacesToSelect),this.opts.maxSelectedObjects=e,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}setNumberOfPlacesToSelect(e){this.assertSelectionOptions(this.opts.maxSelectedObjects,e),this.opts.numberOfPlacesToSelect=e,this.selectionWasValid=null,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}getSelectionValidity(){let e=this.opts.numberOfPlacesToSelect;if(e===void 0)return null;let t=this.getSelection(),s=t.length;return{isValid:s===e,count:s,required:e,remaining:Math.max(0,e-s),objects:t}}clearSelection(){this.renderer?.clearSelection(),this.syncSelection()}getSelection(){return this.renderer?.getSelection()??[]}getReport(){return this.api.report(this.key).then(e=>(this.applyReportRevenue(e),e))}getControlRoomSnapshot(e=this.trendWindowMinutes){return this.setTrendWindow(e)}getConnection(){return{status:this.connectionStatus,lastMessageAt:this.lastMessageAt}}getLog(e={}){return this.api.log(this.key,e)}async setHoldTtl(e){try{await this.api.setHoldTtl(this.key,e),this.done("setHoldTtl",[],e?`Hold window set to ${Math.round(e/6e4)} min.`:"Hold window reset.")}catch(t){this.toastErr("Couldn't update the hold window."),this.opts.onError?.(t)}}zoomToFit(){if(this.mode==="filterSections"&&this.filteredSectionLabel){this.clearFilteredSection();return}this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit()}destroy(){if(this.selectObserver?.disconnect(),this.closed=!0,this.monitorRefreshTimer&&clearTimeout(this.monitorRefreshTimer),this.monitorRefreshTimer=null,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.feedTimer&&clearInterval(this.feedTimer),this.toastTimer&&clearTimeout(this.toastTimer),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.paintHandle!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.paintHandle),this.paintHandle=null,this.channels?.destroy(),this.channels=null,this.channelsLoading=null,this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.layoutObserver?.disconnect(),this.layoutObserver=null,this.colorSchemeStop?.(),this.colorSchemeStop=null,this.root?.removeEventListener("keydown",this.onKeyDown),this.els.rail?.removeEventListener("click",this.onRailClick),typeof document<"u"&&document.removeEventListener("fullscreenchange",this.onFullscreenChange),this.ws){try{this.ws.close()}catch{}this.ws=null}this.seatHistoryPanel?.destroy(),this.seatHistoryPanel=null,this.activityPanel?.destroy(),this.activityPanel=null,this.navigation?.destroy(),this.navigation=null,this.renderer?.destroy(),this.renderer=null,this.organizerAssetUrls.dispose(),this.root&&this.root.parentNode===this.host&&this.host.removeChild(this.root)}buildRenderer(){if(!this.doc)return;let e=this.isBulkSelectMode();this.renderer=new De(this.mapHost,{manageMode:!0,organizerGlyph:{apply:Ne,clear:qe,isPainted:_e},marqueeSelect:e&&!this.movingMap,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses(),currency:this.currency,onSelect:t=>this.handleSeatSelect(t),onDeselect:()=>this.syncSelection(),onSelectionLimit:t=>this.opts.onSelectionLimit?.(t),onMarquee:()=>this.syncSelection(),onSectionTap:t=>{if(this.mode==="filterSections"){let s=this.filterableSections().find(i=>i.id===t);s&&this.setFilteredSection(s.label);return}this.renderer?.focusSection(t),this.channels?.handleSectionFocus(t)},onViewChange:()=>{this.updateZoomHint(),this.channels?.handleViewChange()}}),this.renderer.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),this.updateZoomHint()}isBulkSelectMode(){return this.mode==="block"||this.mode==="categories"||this.mode==="channels"&&this.channels?.usesMarqueeSelection()===!0}selectableStatuses(){return this.mode==="block"?["free","not_for_sale"]:this.mode==="select"||this.mode==="categories"||this.mode==="inspect"||this.isBulkSelectMode()||this.mode==="channels"&&this.channels?.canSelect()===!0?["free","held","booked","not_for_sale"]:[]}updateRendererInteraction(){let e=this.isBulkSelectMode();this.renderer?.setManageInteraction({manageMode:!0,organizerStatus:this.mode!=="channels",marqueeSelect:e&&!this.movingMap,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses()}),this.navigation?.update(e,this.mode==="view"),this.updateZoomHint()}handleSeatSelect(e){if(this.mode==="select"&&!this.canSelectObject(e)){this.renderer?.deselect([e.id]),this.syncSelection();return}if(this.mode==="inspect"){let t=this.getSelection().filter(s=>s.id!==e.id).map(s=>s.id);t.length&&this.renderer?.deselect(t)}this.syncSelection()}buildUnitUniverse(e){for(let t of Ve(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of Ke(e))for(let s of Ge(t))this.labelToId.has(s)||this.gaUnitLabelSet.add(s)}unitTotal(){return this.allIds.length+this.gaUnitLabelSet.size}knownLabels(){return[...this.labelToId.keys(),...this.gaUnitLabelSet]}repaintAll(){let e=this.renderer;if(!e)return;this.allIds.length&&e.setStatus(this.allIds,"free");let t={free:[],held:[],booked:[],not_for_sale:[]};for(let[s,i]of this.status.entries()){let a=this.labelToId.get(s);a&&t[E(i)].push(a)}["held","booked","not_for_sale"].forEach(s=>{t[s].length&&e.setStatus(t[s],s)})}async connect(){if(this.closed)return;let e;try{if(e=(await this.withAuthRetry(()=>this.api.subscribeTicket(this.key))).protocols,!e.length)throw new Error("manage_subscribe_ticket_missing")}catch(s){this.setLive(!1),this.opts.onError?.(s),this.scheduleReconnect();return}if(this.closed)return;let t;try{t=new WebSocket(this.api.socketUrl(this.key),e)}catch(s){this.opts.onError?.(s),this.scheduleReconnect();return}this.ws=t,this.socketSnapshotSeen=!1,t.onopen=()=>{this.attempt=0,this.setLive(!0),this.resnapshot().then(()=>this.refreshControlRoom()).catch(s=>this.opts.onError?.(s)),this.refreshAvailability()},t.onmessage=s=>this.onMessage(s),t.onclose=()=>{this.ws===t&&(this.ws=null),this.setLive(!1),this.scheduleReconnect()},t.onerror=()=>{try{t.close()}catch{}}}scheduleReconnect(){if(this.closed||this.reconnectTimer)return;let e=Math.min(1e3*2**Math.min(this.attempt++,5),15e3);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},e)}onMessage(e){let t;try{t=JSON.parse(typeof e.data=="string"?e.data:"")}catch{return}if(!t||typeof t!="object")return;this.lastMessageAt=Date.now();let s=t;if((Array.isArray(s.hidden)||Array.isArray(s.closed))&&this.updateEffectiveAvailability(s.hidden,s.closed),s.type==="presence"){typeof s.shoppingSessions=="number"&&typeof s.activeHolds=="number"&&(this.livePresence={at:Date.now(),value:{shoppingSessions:s.shoppingSessions,activeHolds:s.activeHolds}},this.controlRoomSnapshot&&(this.controlRoomSnapshot={...this.controlRoomSnapshot,presence:this.livePresence.value},this.opts.onControlRoom?.(this.controlRoomSnapshot)),this.lastSyncedAt=Date.now(),this.recomputeTallies(),this.paintMonitorInsights());return}if(s.type!=="hidden"){if(s.seats&&typeof s.seats=="object")this.applySocketSnapshot(s.seats,typeof s.default=="string"?s.default:void 0);else if(Array.isArray(s.changes)){let i=[],a=new Map;for(let l of s.changes){let r=["free","held","booked","blocked"].includes(l.status)?l.status:"free",c=this.status.get(l.label)??"free";if(c===r)continue;this.setStatusLabel(l.label,r,c);let n=this.labelToId.get(l.label);n&&(this.renderer?.setStatus([n],E(r)),i.push(n));let d=this.verbFor(c,r),m=`${d}:${r}`,b=a.get(m)??{labels:[],verb:d,status:r};b.labels.push(l.label),a.set(m,b)}for(let l of a.values()){let r=this.pushActivity(l.labels,l.verb,l.status);r&&this.paintSpatialActivity(r)}a.size&&this.scheduleMonitorRefresh(),i.length&&(this.lastSyncedAt=Date.now(),this.afterPaint());let o=typeof s.bookedValue?.gross=="number"?s.bookedValue.gross:s.revenue?.gross;typeof o=="number"&&Number.isFinite(o)&&this.applyLiveGross(o),this.recomputeTallies()}}}applyLiveGross(e){if(this.liveGross={at:Date.now(),value:e},this.authoritativeGrossRevenue=e,this.revenueStatus="current",this.controlRoomSnapshot){let s={...this.controlRoomSnapshot.bookedValue??this.controlRoomSnapshot.revenue,gross:e};this.controlRoomSnapshot={...this.controlRoomSnapshot,bookedValue:s,revenue:s},this.opts.onControlRoom?.(this.controlRoomSnapshot)}}setStatusLabel(e,t,s=this.status.get(e)??"free"){this.status.set(e,t),s!==t&&(s!=="free"&&(this.counts[s]-=1),t!=="free"&&(this.counts[t]+=1))}applySocketSnapshot(e,t){let s=this.socketSnapshotSeen?this.status:null;if(this.applySnapshot(e,t),this.socketSnapshotSeen=!0,!s)return;let i=new Map;for(let a of new Set([...s.keys(),...this.status.keys()])){let o=s.get(a)??"free",l=this.status.get(a)??"free";if(o===l)continue;let r=this.verbFor(o,l),c=`${r}:${l}`,n=i.get(c)??{labels:[],verb:r,status:l};n.labels.push(a),i.set(c,n)}for(let a of i.values()){let o=this.pushActivity(a.labels,a.verb,a.status);o&&this.paintSpatialActivity(o)}i.size&&this.scheduleMonitorRefresh()}scheduleMonitorRefresh(){this.monitorRefreshTimer||(this.monitorRefreshTimer=setTimeout(()=>{this.monitorRefreshTimer=null,this.closed||this.refreshControlRoom().catch(e=>this.opts.onError?.(e))},150))}async resnapshot(){try{let e=await this.api.objects(this.key);this.applySnapshot(e.seats),this.updateEffectiveAvailability(e.hidden,e.closed),this.lastMessageAt=Date.now()}catch{}}applySnapshot(e,t){let s=a=>["free","held","booked","blocked"].includes(a)?a:"free",i=new Map;if(t!==void 0){let a=s(t);for(let o of this.knownLabels())i.set(o,a)}for(let[a,o]of Object.entries(e))i.set(a,s(o));this.status=i,this.modelVersion+=1,this.recountAll(),this.lastSyncedAt=Date.now(),this.repaintAll(),this.afterPaint(),this.recomputeTallies()}recountAll(){let e={held:0,booked:0,blocked:0};for(let t of this.status.values())t!=="free"&&(e[t]+=1);this.counts=e}setSeatsLocal(e,t){let s=[];for(let i of e){this.setStatusLabel(i,t);let a=this.labelToId.get(i);a&&s.push(a)}s.length&&this.renderer?.setStatus(s,E(t)),this.afterPaint(),this.recomputeTallies()}afterPaint(){this.keepLive&&typeof document<"u"&&document.hidden&&this.renderer?.forceDraw()}activityColor(e){return e==="held"?y.held:e==="booked"?y.booked:e==="blocked"?y.blocked:y.free}sectionsForLabels(e){let t=new Set;for(let i of e){let a=this.labelToSeat.get(i);if(!a)continue;let o=this.sectionByObject.get(a.rowId);o&&o!==x&&t.add(o)}let s=[...t];return{ids:s,labels:s.map(i=>this.sectionLabelById.get(i)??i)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let i of e.slice(0,ie)){let a=this.labelToId.get(i);a&&this.renderer?.flashSeat(a,s)}}paintSpatialActivity(e){let t=e.sectionIds??this.sectionsForLabels(e.labels).ids,s=this.renderer?.getFocusedSection()??null;if(this.followLive&&t.length===1&&(e.status==="held"||e.status==="booked")){let a=this.root?.querySelector('[data-ref="followstatus"]');a&&(a.textContent=`Following ${e.labels.length===1?e.labels[0]:`${e.labels.length} seats`} \xB7 ${e.status}`),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=setTimeout(()=>{this.followLiveTimer=null,this.focusActivitySeats(e.labels,t[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(e.labels,e.status)},520)},220);return}if(!s&&t.length){let a=this.activityColor(e.status);for(let o of t.slice(0,ae))this.renderer?.flashSection(o,a);return}(!t.length||s&&t.includes(s))&&this.pulseSeatLabels(e.labels,e.status)}locateSection(e){this.renderer?.focusSection(e)}focusActivitySeats(e,t){this.renderer?.focusSection(t);let s=e.slice(0,ie).map(r=>this.labelToSeat.get(r)).filter(r=>!!r);if(!s.length)return;let i=s.map(r=>r.x),a=s.map(r=>r.y),o=Math.min(...i),l=Math.min(...a);this.renderer?.focusRegion({x:o-150,y:l-100,width:Math.max(...i)-o+300,height:Math.max(...a)-l+200})}locateActivity(e){let t=this.feed.find(i=>i.id===e);if(!t)return;let s=t.sectionIds??this.sectionsForLabels(t.labels).ids;if(this.followSeatTimer&&clearTimeout(this.followSeatTimer),s.length===1){this.focusActivitySeats(t.labels,s[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(t.labels,t.status)},520);return}this.zoomToFit(),this.followSeatTimer=setTimeout(()=>{if(this.followSeatTimer=null,s.length){let i=this.activityColor(t.status);for(let a of s.slice(0,ae))this.renderer?.flashSection(a,i)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],i=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,a=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
|
|
472
|
-
<
|
|
473
|
-
<span
|
|
689
|
+
${a}
|
|
690
|
+
${n}
|
|
691
|
+
</div>`}var vt="https://api.seatlayer.io",H=200,Te=16,Ce=4,Ee=[{key:"watch",label:"Watch",tools:[{mode:"view",label:"Monitor",shortcut:"M",title:"Live board \u2014 inventory, activity and booking momentum. Read-only."},{mode:"inspect",label:"Inspect",shortcut:"I",title:"Click one seat to read its live status and booking context. Read-only."}]},{key:"manage",label:"Manage",tools:[{mode:"block",label:"Block",shortcut:"B",title:"Take seats off sale for this event, or put them back."},{mode:"sections",label:"Sections",shortcut:"S",title:"Open, close or hide sections for this event, on a schedule or on demand."},{mode:"categories",label:"Categories",shortcut:"G",title:"Move seats to a different price category for this event only."},{mode:"tables",label:"Tables",shortcut:"T",title:"Sell each table per chair or as one whole-table booking."},{mode:"channels",label:"Channels",shortcut:"C",title:"Allocate inventory to sales channels and share their links."}]},{key:"host",label:"Host tools",tools:[{mode:"select",label:"Select",shortcut:"X",title:"Select seats for your own back-office operation. The selection is handed to your app; nothing changes here."},{mode:"filterSections",label:"Filter",shortcut:"L",title:"Filter the map to one section for your own reporting."}]}],yt=3;function xt(l){let e=l?.status;return e===401||e===403}var wt=Object.fromEntries(Ee.flatMap(l=>l.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),P=class{constructor(e){this.els={};this.renderer=null;this.doc=null;this.selectObserver=null;this.seatHistoryPanel=null;this.activityPanel=null;this.navigation=null;this.movingMap=!1;this.marqueeShape="box";this.socketSnapshotSeen=!1;this.monitorRefreshTimer=null;this.themeMode=null;this.colorSchemeStop=null;this.inventoryModelVersion=1;this.selectableObjectLabels=new Set;this.lastSelectionLabels=new Set;this.selectionWasValid=null;this.initialSelectionApplied=!1;this.labelToId=new Map;this.labelToSeat=new Map;this.allIds=[];this.gaUnitLabelSet=new Set;this.status=new Map;this.counts={held:0,booked:0,blocked:0};this.modelVersion=0;this.currency="USD";this.authoritativeCurrency=null;this.authoritativeGrossRevenue=0;this.revenueStatus="loading";this.revenueRequest=0;this.controlRoomSnapshot=null;this.serverBaseline=null;this.livePresence=null;this.liveGross=null;this.paintHandle=null;this.trendWindowMinutes=15;this.heatEnabled=!1;this.mapView=A();this.barFind=null;this.minimap=null;this.lastKpiValues=new Map;this.activeKpiDeltas=new Map;this.ws=null;this.reconnectTimer=null;this.attempt=0;this.closed=!1;this.connectionStatus="reconnecting";this.lastMessageAt=null;this.ready=!1;this.feed=[];this.feedTimer=null;this.toastTimer=null;this.liveEventTimer=null;this.kpiCleanupTimer=null;this.followLiveTimer=null;this.followSeatTimer=null;this.releaseAt=null;this.layoutObserver=null;this.tokenExpiresAt=null;this.tokenRefreshTimer=null;this.tokenRefreshInFlight=!1;this.tokenRefreshFailures=0;this.sessionEnded=!1;this.sectionByObject=new Map;this.sectionLabelById=new Map;this.sectionsBase=null;this.filteredSectionLabel=null;this.availabilityRules={};this.effectiveHidden=new Set;this.effectiveClosed=new Set;this.availabilitySaving=!1;this.lastSyncedAt=null;this.blockBrowse=!1;this.blockedQuery="";this.blockedSection="";this.blockedResultLimit=100;this.unblockAllConfirmTimer=null;this.channels=null;this.chooser=null;this.chooserDialog=null;this.categoryDifferences=null;this.channelCaps={view:!1,manage:!1};this.categoryCanManage=!1;this.tableCanManage=!1;this.tableBookingSaving=!1;this.channelCapabilityResolution=0;this.channelsLoading=null;this.onFullscreenChange=()=>{this.paintFullscreenButton(),this.updateContainerLayout(),this.renderer?.forceDraw()};this.onKeyDown=e=>{if(e.metaKey||e.ctrlKey||e.altKey||e.target?.matches('input,select,textarea,[contenteditable="true"]'))return;let s=e.key.toLowerCase(),i=e.shiftKey?fe(s):null;if(i){this.toggleMapView(i),e.preventDefault();return}if(s==="/"){let a=this.els.findbar?.querySelector("[data-ch-find-input]");a&&(a.focus(),a.select(),e.preventDefault());return}let o=wt[s];if(o){if(!this.toolAvailable(o))return;this.setMode(o)}else if(s==="f")this.toggleFullscreen();else if(s==="escape"){let a=this.els.view;if(a?.open)a.open=!1,a.querySelector("summary")?.focus();else if(!this.channels?.handleBack())if(this.getSelection().length)this.clearSelection();else return}else return;e.preventDefault()};this.onRailClick=e=>{let t=e.target,s=t?.closest("[data-section-focus]");if(s?.dataset.sectionFocus){this.locateSection(s.dataset.sectionFocus);return}let i=t?.closest("[data-feed-id]");i?.dataset.feedId&&this.locateActivity(i.dataset.feedId)};this.sectionOptions=[];F(e.token),this.assertSelectionOptions(e.maxSelectedObjects,e.numberOfPlacesToSelect),this.opts=e,this.key=e.eventKey,this.mode=e.mode??"view",this.selectableObjectLabels=new Set(e.selectableObjects??[]),this.categoryCanManage=new Set(e.capabilities??[]).has("event:categories:manage"),this.tableCanManage=new Set(e.capabilities??[]).has("event:tables:manage"),this.keepLive=e.keepLiveWhileHidden??!0,this.themeMode=e.themeMode??null,this.followLive=e.followLive??!1,this.currency=e.currency??"USD",this.tokenExpiresAt=e.tokenExpiresAt??null,this.api=new I(e.apiBase??vt,e.token),this.organizerAssetUrls=new R(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=G(e.container)}assertSelectionOptions(e,t){let s=i=>i===void 0||Number.isInteger(i)&&i>0;if(!s(e))throw new TypeError("maxSelectedObjects must be a positive integer");if(!s(t))throw new TypeError("numberOfPlacesToSelect must be a positive integer");if(e!==void 0&&t!==void 0&&e<t)throw new TypeError("maxSelectedObjects cannot be lower than numberOfPlacesToSelect")}async render(){le(),this.buildChrome();try{let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1,this.doc=await this.organizerAssetUrls.prepareRendererChart(e.doc),this.authoritativeCurrency=e.event.currency??null,this.currency=this.authoritativeCurrency??this.opts.currency??this.currency,this.buildUnitUniverse(this.doc),this.buildRenderer(),this.buildSectionOptions(),this.settleMode();let[,t]=await Promise.all([this.resnapshot(),this.refreshControlRoom().catch(s=>this.opts.onError?.(s)),this.refreshAvailability()]);t?.activity?this.seedFeed(t.activity):this.api.log(this.key,{limit:24}).then(s=>this.seedFeed(s.entries)).catch(()=>{}),this.connect(),this.startFeedClock(),this.ready=!0,await this.resolveChannelCapabilities(),this.setMode(this.mode),this.applyInitialSelection(),this.scheduleTokenRefresh(),this.opts.onReady?.()}catch(e){this.fail(e)}return this}setMode(e){this.toolAvailable(e)||(e="view"),e==="channels"&&!this.channels&&this.ensureChannels();let t=e!==this.mode,s=this.mode==="channels",i=this.mode==="filterSections";this.mode=e,t&&e!=="view"&&this.setFollowLive(!1),!this.renderer&&this.doc?this.buildRenderer():this.updateRendererInteraction(),t&&(this.renderer?.clearSelection(),this.syncSelection()),s&&e!=="channels"&&this.channels?.leave(),t&&(this.highlightLabels(null),this.wireBarFind()),this.paintModeTabs(),this.paintRail(),this.paintMapViewMenu(),this.applyMapView(),this.applySectionCanvasTreatment(),i&&e!=="filterSections"&&this.renderer?.zoomToFit(),e==="channels"&&this.channels?.enter(),e==="select"&&this.applyInitialSelection(),t&&this.opts.onModeChange?.(e)}async resolveChannelCapabilities(){let e=++this.channelCapabilityResolution,t=this.opts.capabilities,s;if(t){let i=new Set(t);s={view:i.has("event:channels:view"),manage:i.has("event:channels:view")&&i.has("event:channels:manage")}}else s={view:!1,manage:!1};if(!s.view&&!t)try{await this.api.channels(this.key),s={view:!0,manage:!1}}catch{s={view:!1,manage:!1}}if(e===this.channelCapabilityResolution){if(this.channelCaps=s,!this.channelCaps.view){this.channels?.destroy(),this.channels=null,this.mode==="channels"?this.setMode("view"):this.paintModeTabs();return}this.channels?.setCapabilities(this.channelCaps),this.paintModeTabs()}}ensureChannels(){if(this.channelsLoading)return this.channelsLoading;if(this.channels)return Promise.resolve();let e=(async()=>{try{let t=await import("./channelsMode-YJO6FOPD.js");if(this.closed||!this.channelCaps.view||(this.channels||(re(t.CHANNELS_CSS),this.channels=new t.ChannelsMode(this.buildChannelsHost(),this.channelCaps),this.channels.onInteractionChange=()=>this.updateRendererInteraction()),this.mode!=="channels"))return;this.updateRendererInteraction(),this.paintRail(),this.channels.enter(),this.applyMapView(),this.paintMapViewMenu()}catch(t){if(this.closed)return;this.channelsLoading=null,this.mode==="channels"&&this.paintRail(),this.opts.onError?.(t)}})();return this.channelsLoading=e,e}buildChooserHost(){let e=s=>{let i=this.labelToSeat.get(s);return i?this.mode==="block"?this.isBlockSelectable(s):this.mode==="select"?this.canSelectObject(i):!0:!1};return{selectionLabels:()=>this.selectionLabels(),selectByLabels:s=>{this.selectByLabels(s)},clearSelection:()=>this.clearSelection(),selectSection:s=>{this.selectSection(s)},sections:()=>this.sectionOptions,labelsInSection:s=>(this.renderer?.getSelectableInSection(s)??[]).map(i=>i.label).filter(e),rows:()=>{let s=new Map((this.doc?.objects??[]).map(o=>[o.id,o])),i=new Map;for(let o of this.labelToSeat.values()){if(!e(o.label))continue;let a=s.get(o.rowId);if(!a||a.type!=="row"&&a.type!=="table")continue;let n=o.logicalRowId??o.rowId,c=this.sectionByObject.get(o.rowId)??v,d=i.get(n)??{id:n,label:a.type==="row"?a.segmentedRow?.displayLabel??a.displayLabel??a.label:a.displayLabel??a.label,sectionId:c,sectionLabel:this.sectionLabelById.get(c)??"Other seats",labels:[]};d.labels.push(o.label),i.set(n,d)}return[...i.values()].sort((o,a)=>o.sectionLabel.localeCompare(a.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||o.label.localeCompare(a.label,void 0,{numeric:!0,sensitivity:"base"}))},categories:()=>(this.doc?.categories??[]).map(s=>({key:s.key,label:s.label??s.key,color:s.color})),labelsInCategory:s=>[...this.labelToSeat.values()].filter(i=>i.categoryKey===s&&e(i.label)).map(i=>i.label),seats:()=>[...this.labelToSeat.values()].filter(s=>e(s.label)).map(s=>({label:s.label})),statusOf:s=>this.status.get(s)??(this.labelToSeat.has(s)?"free":void 0),sectionOfLabel:s=>{let i=this.labelToSeat.get(s);if(!i)return null;let o=this.sectionByObject.get(i.rowId)??v;return{id:o,label:this.sectionLabelById.get(o)??"Other seats"}},openDialog:(s,i)=>{this.chooserDialog=ie(this.root,s,i,{previous:this.chooserDialog,onClose:()=>{this.chooserDialog=null}})},closeDialog:()=>this.chooserDialog?.close(),highlight:s=>this.highlightLabels(s),...this.mode==="select"?{cap:this.selectionCap()}:{}}}wireBarFind(){let e=this.els.findbar;e&&(e.innerHTML=O({compact:!0}),this.barFind=new D({...this.buildChooserHost(),seats:()=>[...this.labelToSeat.values()].map(t=>({label:t.label})),frame:t=>this.frameLabels(t)}),this.barFind.wireFind(e,{enter:this.isChoosingTool()?"select":"frame"}))}isChoosingTool(){return this.isBulkSelectMode()||this.mode==="select"}frameLabels(e){let t=e.map(s=>this.labelToSeat.get(s)?.id).filter(s=>!!s);t.length&&(this.setFollowLive(!1),this.renderer?.focusSeats?.(t,{animate:!0}))}highlightLabels(e){if(!e){this.renderer?.setSeatHighlight?.(null);return}this.renderer?.setSeatHighlight?.(e.map(t=>this.labelToSeat.get(t)?.id).filter(t=>!!t))}toolChooser(){return this.chooserDialog?.close({restoreFocus:!1}),this.chooser=new D(this.buildChooserHost()),this.chooser}toolSelectionBar(e,t,s,i){return ee({count:0,noun:"selected",breakdown:`<span class="slm-selactions"><button type="button" class="slm-linkbtn" data-ref="${i}">Select all</button></span>`,clearAttr:`data-ref="${s}"`}).replace('class="slm-selnum"',`class="slm-selnum" data-ref="${e}"`).replace('class="slm-sellabel"',`class="slm-sellabel" data-ref="${t}"`)}buildChannelsHost(){return{eventKey:this.key,api:this.api,rail:this.els.rail,mapLayer:this.root.querySelector(".slm-map"),pillLane:this.els.lane,root:this.root,seats:()=>[...this.labelToSeat.values()].map(e=>({id:e.id,label:e.label,x:e.x,y:e.y})),statusOf:e=>this.status.get(e)??(this.labelToSeat.has(e)?"free":void 0),selectionLabels:()=>this.selectionLabels(),selectByLabels:e=>{this.selectByLabels(e)},clearSelection:()=>this.clearSelection(),selectSection:e=>{this.selectSection(e)},sections:()=>this.sectionOptions,labelsInSection:e=>this.renderer?.getSelectableInSection(e).map(t=>t.label)??[],rows:()=>{let e=new Map((this.doc?.objects??[]).map(s=>[s.id,s])),t=new Map;for(let s of this.labelToSeat.values()){let i=e.get(s.rowId);if(!i||i.type!=="row"&&i.type!=="table")continue;let o=s.logicalRowId??s.rowId,a=this.sectionByObject.get(s.rowId)??v,n=t.get(o)??{id:o,label:i.type==="row"?i.segmentedRow?.displayLabel??i.displayLabel??i.label:i.displayLabel??i.label,sectionId:a,sectionLabel:this.sectionLabelById.get(a)??"Other seats",labels:[]};n.labels.push(s.label),t.set(o,n)}return[...t.values()].sort((s,i)=>s.sectionLabel.localeCompare(i.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(i.label,void 0,{numeric:!0,sensitivity:"base"}))},categories:()=>(this.doc?.categories??[]).map(e=>({key:e.key,label:e.label??e.key,color:e.color,price:e.price,tiers:e.tiers?.map(t=>({id:t.id,name:t.name,price:t.price}))})),labelsInCategory:e=>[...this.labelToSeat.entries()].filter(([,t])=>t.categoryKey===e).map(([t])=>t),sectionOfLabel:e=>{let t=this.labelToSeat.get(e);if(!t)return null;let s=this.sectionByObject.get(t.rowId)??v;return{id:s,label:this.sectionLabelById.get(s)??"Other seats"}},worldToScreen:e=>this.renderer?.worldToScreen(e)??null,seatPixelSize:()=>this.seatPixelSize(),isSeatDetail:()=>this.renderer?.getRung?.()==="seats",showSectionOverview:()=>{this.renderer?.clearSectionFocus(),this.renderer?.setRung?.("sections")},focusSection:e=>this.renderer?.focusSection(e),isCompact:()=>!!this.root?.classList.contains("compact"),setMapInert:e=>{this.mapHost.toggleAttribute("inert",e),this.mapHost.setAttribute("aria-hidden",String(e))},toast:(e,t)=>this.toast(e,t),onError:e=>this.opts.onError?.(e)}}seatPixelSize(){let e=this.renderer?.getVisibleWorldRect?.(),t=this.mapHost?.clientWidth??0;return!e?.width||!t?6:Math.max(3,t/e.width*18)}setHeatOverlay(e){this.heatEnabled=e,this.mapView.momentum!==e&&this.setMapView({momentum:e}),this.applyHeatOverlay(),this.paintHeatButton()}setMapView(e){let t={...this.mapView,...e};Object.keys(t).some(i=>t[i]!==this.mapView[i])&&(this.mapView=t,ye(t),t.momentum!==this.heatEnabled&&this.setHeatOverlay(t.momentum),this.applyMapView(),this.paintMapViewMenu())}getMapView(){return{...this.mapView}}toggleMapView(e){e==="channelColours"&&!this.channelColoursAvailable()||this.setMapView({[e]:!this.mapView[e]})}channelColoursAvailable(){return this.mode==="channels"&&this.channels!=null}applyMapView(){we(this.mapView,{renderer:this.renderer,channelsOverlay:e=>this.channels?.setOverlayVisible(e)})}paintMapViewMenu(){let e=this.els.view;e&&Se(e,this.mapView,{channelColoursAvailable:this.channelColoursAvailable(),momentumLoading:this.mapView.momentum&&!this.controlRoomSnapshot})}setFollowLive(e){let t=this.followLive!==e;this.followLive=e,e||(this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=null,this.followSeatTimer=null),this.paintFollowLiveButton(),t&&this.opts.onFollowLiveChange?.(e)}setKeepLiveWhileHidden(e){this.keepLive=e??!0,this.opts.keepLiveWhileHidden=e}setCurrency(e){this.opts.currency=e,!this.authoritativeCurrency&&(this.currency=e??"USD",this.ready&&this.recomputeTallies())}setTheme(e){this.opts.theme=e,this.applyThemeVars()}applyThemeVars(){if(!this.root)return;let e=B(this.themeMode);for(let[t,s]of Object.entries(X(this.opts.theme,e)))this.root.style.setProperty(t,s);e?this.root.dataset.theme=e:delete this.root.dataset.theme}watchThemeMode(){this.colorSchemeStop?.(),this.colorSchemeStop=null,this.themeMode==="auto"&&(this.colorSchemeStop=j(()=>{this.closed||this.repaintForThemeMode()}))}repaintForThemeMode(){this.applyThemeVars();let e=this.renderer;if(!e||!this.doc)return;let t=e.getSelection().map(o=>o.id),s=e.getCameraPose(),i=e.getFocusedSection();e.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),t.length&&e.select(t),i&&e.focusSection(i),e.setCameraPose(s),this.updateZoomHint()}setThemeMode(e){let t=e??null;this.closed||t===this.themeMode||(this.themeMode=t,this.opts.themeMode=t??void 0,this.watchThemeMode(),this.repaintForThemeMode())}getThemeMode(){return this.themeMode}themedDoc(){let e=this.doc,t=Q(B(this.themeMode));return t?{...e,theme:{...e.theme??{},background:t}}:e}setCapabilities(e){this.opts.capabilities=e,this.categoryCanManage=new Set(e??[]).has("event:categories:manage"),this.tableCanManage=new Set(e??[]).has("event:tables:manage"),!this.categoryCanManage&&this.mode==="categories"||!this.tableCanManage&&this.mode==="tables"?this.setMode("view"):this.paintModeTabs(),this.ready&&this.resolveChannelCapabilities()}setTokenRefresh(e){this.opts.onTokenRefresh=e,this.scheduleTokenRefresh()}setTrendWindow(e){let t=Number.isFinite(e)?Math.floor(e):15;return this.trendWindowMinutes=Math.max(5,Math.min(60,t)),this.paintTrendWindow(),this.refreshControlRoom()}async enterFullscreen(){!this.root?.requestFullscreen||this.isFullscreen()||(await this.root.requestFullscreen(),this.root.focus({preventScroll:!0}))}async exitFullscreen(){typeof document>"u"||!this.isFullscreen()||await document.exitFullscreen()}isFullscreen(){return typeof document<"u"&&document.fullscreenElement===this.root}toggleFullscreen(){(this.isFullscreen()?this.exitFullscreen():this.enterFullscreen()).catch(t=>this.opts.onError?.(t))}setToken(e,t){F(e),this.api.setToken(e),this.opts.token=e,this.opts.tokenExpiresAt=t,this.tokenExpiresAt=t??null,this.scheduleTokenRefresh(),this.ready&&this.resolveChannelCapabilities()}scheduleTokenRefresh(){this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.tokenRefreshTimer=null;let e=this.opts.onTokenRefresh,t=this.tokenExpiresAt;if(this.closed||!e||!t||!Number.isFinite(t))return;let s=t-Date.now(),i=Math.min(12e4,Math.max(3e4,s*.2)),o=Math.max(0,s-i);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},o)}async rotateToken(){if(!(this.closed||this.sessionEnded||this.tokenRefreshInFlight||!this.opts.onTokenRefresh)){this.tokenRefreshInFlight=!0;try{let e=await this.opts.onTokenRefresh();if(!e?.token||!Number.isFinite(e.expiresAt))throw new Error("invalid_token_refresh_result");this.tokenRefreshFailures=0,this.setToken(e.token,e.expiresAt)}catch(e){this.opts.onError?.(e),this.tokenRefreshFailures+=1,!this.closed&&(this.tokenRefreshFailures>=yt||xt(e))?this.endSession():this.closed||(this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},3e4))}finally{this.tokenRefreshInFlight=!1}}}endSession(){if(this.sessionEnded)return;this.sessionEnded=!0,this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.tokenRefreshTimer=null,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.monitorRefreshTimer&&clearTimeout(this.monitorRefreshTimer),this.monitorRefreshTimer=null;let e=this.ws;if(this.ws=null,e){e.onclose=null;try{e.close()}catch{}}this.setLive(!1),this.paintSessionEnded()}async retrySession(){if(this.closed||!this.sessionEnded)return!this.sessionEnded;if(!this.opts.onTokenRefresh)return!1;this.sessionEnded=!1,this.tokenRefreshFailures=0;let e=this.root?.querySelector('[data-ref="ended"]');return e?.setAttribute("data-busy","true"),await this.rotateToken(),this.sessionEnded?(e?.removeAttribute("data-busy"),!1):(e?.remove(),this.attempt=0,this.connect(),!0)}paintSessionEnded(){let e=this.els.lane;if(!e||e.querySelector('[data-ref="ended"]'))return;let t=document.createElement("div");t.className="slm-ended",t.setAttribute("data-ref","ended"),t.setAttribute("role","alertdialog"),t.setAttribute("aria-labelledby","slm-ended-title"),t.innerHTML=`
|
|
692
|
+
<strong id="slm-ended-title">This session ended</strong>
|
|
693
|
+
<span>The map is as it was when the connection stopped. Sign in again, then try again to pick the live stream back up.</span>
|
|
694
|
+
<button type="button" class="slm-btn" data-ref="ended-retry">Try again</button>`,t.querySelector('[data-ref="ended-retry"]').addEventListener("click",()=>{this.retrySession()}),e.appendChild(t)}async block(e,t={}){let s=(e??this.selectionLabels()).filter(o=>this.status.get(o)==="free");if(!s.length)return;let i=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:i}),this.clearSelection(),this.done("block",s,i?`Blocked ${s.length} \u2014 auto-release ${new Date(i).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(o){this.setSeatsLocal(s,"free"),this.toastErr(o instanceof w&&o.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(o)}}async unblock(e){let t=(e??this.selectionLabels()).filter(s=>this.status.get(s)==="blocked");if(t.length){this.setSeatsLocal(t,"free");try{await this.api.unblock(this.key,t),this.clearSelection(),this.done("unblock",t,`Unblocked ${t.length} seat${t.length===1?"":"s"}.`)}catch(s){this.setSeatsLocal(t,"blocked"),this.toastErr("Couldn't unblock those seats."),this.opts.onError?.(s)}}}async unblockAll(){let e=[...this.status.entries()].filter(([,t])=>t==="blocked").map(([t])=>t);if(e.length){this.setSeatsLocal(e,"free");try{let t=await this.api.unblockAll(this.key);this.clearSelection(),this.done("unblockAll",e,`Unblocked ${t.freed} seat${t.freed===1?"":"s"}.`)}catch(t){await this.resnapshot(),this.toastErr("Couldn't mark everything for sale."),this.opts.onError?.(t)}}}async cancelBooking(e,t){let s=e.filter(i=>this.status.get(i)==="booked");if(!(!s.length||!t)){this.setSeatsLocal(s,"free");try{await this.api.unbook(this.key,s,t),this.clearSelection(),this.done("cancelBooking",s,`Released ${s.length} booked unit${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(i)}}}async setCategory(e,t){let s=this.doc?.categories.find(o=>o.key===e),i=[...new Set(t??this.selectionLabels())].filter(o=>this.labelToSeat.has(o));if(!(!s||!i.length))try{let o=await this.withAuthRetry(()=>this.api.setCategory(this.key,i,e)),a={};for(let n of o.labels){let c=this.labelToSeat.get(n),d=this.labelToId.get(n);c&&(c.categoryKey=e),d&&(a[d]=e)}this.renderer?.setSeatCategories?.(a),this.clearSelection(),this.mode==="categories"&&this.loadCategoryDifferences(),this.done("setCategory",o.labels,`Assigned ${o.labels.length.toLocaleString()} object${o.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(o){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(o)}}async setTableBooking(e,t,s={}){let i=[...new Set(e)].filter(Boolean);if(!(!i.length||this.tableBookingSaving)){if(this.inventoryModelVersion!==2){this.toastErr("Table booking controls require inventory model 2 for this event.");return}this.tableBookingSaving=!0,this.mode==="tables"&&this.renderTablesRail();try{let o=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,i,t,s));await this.reloadEventChart(),this.done("setTableBooking",o.tableIds,`Updated ${o.tableIds.length.toLocaleString()} table${o.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(o){let a=o instanceof w&&o.code==="table_inventory_in_use";this.toastErr(a?"Release held, booked, or blocked table inventory before changing its booking mode.":"Couldn't update table booking. No table mode was changed."),this.opts.onError?.(o)}finally{this.tableBookingSaving=!1,this.mode==="tables"&&this.renderTablesRail()}}}async reloadEventChart(){let e=await this.withAuthRetry(()=>this.api.chart(this.key));this.inventoryModelVersion=e.event.inventoryModelVersion===2?2:1;let t=await this.organizerAssetUrls.prepareRendererChart(e.doc);this.renderer?.destroy(),this.renderer=null,this.doc=t,this.labelToId.clear(),this.labelToSeat.clear(),this.allIds=[],this.gaUnitLabelSet.clear(),this.status.clear(),this.counts={held:0,booked:0,blocked:0},this.serverBaseline=null,this.lastSelectionLabels.clear(),this.buildUnitUniverse(t),this.buildRenderer(),this.buildSectionOptions(),this.settleMode(),await Promise.all([this.resnapshot(),this.refreshAvailability()]),this.paintRail()}selectAll(){if(this.mode==="select")return this.selectByLabels([...this.labelToSeat.values()].filter(t=>this.canSelectObject(t)).map(t=>t.label));let e=this.renderer?.selectAllSelectable()??[];return this.syncSelection(),e}selectSection(e){if(!this.renderer)return[];let t=this.renderer.getSelectableInSection(e);return this.renderer.selectByLabels(t.map(s=>s.label)),this.syncSelection(),this.renderer.getSelection()}setFilteredSection(e){let t=e.trim(),s=this.filterableSections().filter(a=>a.label===t);if(!s.length)throw new Error(`Unknown event section: ${e}`);let i=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let o=s.map(({id:a,label:n,seatCount:c,zone:d})=>({id:a,label:n,seatCount:c,...d?{zone:d}:{}}));return i&&this.opts.onFilteredSectionChange?.(o),o}clearFilteredSection(){let e=this.filteredSectionLabel!==null;this.filteredSectionLabel=null,this.renderer?.setDimmedSections(null),this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit(),this.mode==="filterSections"&&this.renderFilterSectionsRail(),e&&this.opts.onFilteredSectionChange?.([])}getFilteredSections(){return this.filteredSectionLabel?this.filterableSections().filter(e=>e.label===this.filteredSectionLabel).map(({id:e,label:t,seatCount:s,zone:i})=>({id:e,label:t,seatCount:s,...i?{zone:i}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),i=this.selectionCap(),o=[...new Set(e)].filter(n=>!s.has(n)).map(n=>this.labelToSeat.get(n)).filter(n=>!!n&&this.canSelectObject(n)),a=Math.max(0,i-s.size);o.length>a&&this.opts.onSelectionLimit?.(i),t=o.slice(0,a).map(n=>n.label)}return this.renderer?.selectByLabels(t),this.syncSelection(),this.getSelection()}selectObjects(e){return this.selectByLabels(e)}deselectObjects(e){let t=e.map(s=>this.labelToId.get(s)).filter(s=>!!s);return this.renderer?.deselect(t),this.syncSelection(),this.getSelection()}selectCategories(e){let t=new Set(e);return this.selectByLabels([...this.labelToSeat.values()].filter(s=>t.has(s.categoryKey)).map(s=>s.label))}deselectCategories(e){let t=new Set(e);return this.deselectObjects(this.getSelection().filter(s=>t.has(s.categoryKey)).map(s=>s.label))}setSelectableObjects(e){this.opts.selectableObjects=[...e],this.selectableObjectLabels=new Set(e),this.reconcileSelectPolicy()}setUnavailableObjectsSelectable(e){this.opts.unavailableObjectsSelectable=e,this.reconcileSelectPolicy()}setObjectSelectable(e){this.opts.isObjectSelectable=e,this.reconcileSelectPolicy()}setMaxSelectedObjects(e){this.assertSelectionOptions(e,this.opts.numberOfPlacesToSelect),this.opts.maxSelectedObjects=e,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}setNumberOfPlacesToSelect(e){this.assertSelectionOptions(this.opts.maxSelectedObjects,e),this.opts.numberOfPlacesToSelect=e,this.selectionWasValid=null,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}getSelectionValidity(){let e=this.opts.numberOfPlacesToSelect;if(e===void 0)return null;let t=this.getSelection(),s=t.length;return{isValid:s===e,count:s,required:e,remaining:Math.max(0,e-s),objects:t}}clearSelection(){this.renderer?.clearSelection(),this.syncSelection()}getSelection(){return this.renderer?.getSelection()??[]}getReport(){return this.api.report(this.key).then(e=>(this.applyReportRevenue(e),e))}getControlRoomSnapshot(e=this.trendWindowMinutes){return this.setTrendWindow(e)}getConnection(){return{status:this.connectionStatus,lastMessageAt:this.lastMessageAt}}getLog(e={}){return this.api.log(this.key,e)}async setHoldTtl(e){try{await this.api.setHoldTtl(this.key,e),this.done("setHoldTtl",[],e?`Hold window set to ${Math.round(e/6e4)} min.`:"Hold window reset.")}catch(t){this.toastErr("Couldn't update the hold window."),this.opts.onError?.(t)}}zoomToFit(){if(this.mode==="filterSections"&&this.filteredSectionLabel){this.clearFilteredSection();return}this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit()}zoomOutStep(){let e=this.renderer;if(!e)return;if(!e.zoomOutLevel)return void e.zoomOut();let t=!!e.getFocusedSection?.();e.zoomOutLevel()==="venue"&&t&&e.clearSectionFocus()}paintMapChrome(){let e=this.renderer;if(!e||!this.els.crumb)return;let t=e.getFocusedSection?.()??null,s=t?e.getMinimapSnapshot?.().sections.find(n=>n.id===t)??null:null,i=e.getFloors?.()??[],o=i.length>1?e.isFloorOverview?.()?"All floors":i.find(n=>n.id===e.getActiveFloorId?.())?.name??null:null,a=this.els.blocklegend;a&&(a.hidden=e.getRung?.()==="seats"||!e.getMinimapSnapshot?.().sections.length),me(this.els,de({focused:s?{label:s.label,free:s.free,total:s.total}:null,floor:o,seatsRevealed:e.seatsRevealed?.()??!0,atVenueFit:e.atVenueFit?.(),atCeiling:e.canZoomIn?.()===!1||e.seatsPickable?.()===!0}))}mapCamera(){return{getViewport:()=>{let e=this.renderer;return!e?.getVisibleWorldRect||!e.getWorldBounds?null:{visible:e.getVisibleWorldRect(),bounds:e.getWorldBounds()}},getMinimapSnapshot:()=>this.renderer?.getMinimapSnapshot?.()??{sections:[],seats:[]},panToWorld:e=>{this.setFollowLive(!1),this.renderer?.panToWorld?.(e)},clearSectionFocus:()=>this.renderer?.clearSectionFocus?.(),focusSection:e=>{this.setFollowLive(!1),this.renderer?.focusSection(e),this.channels?.handleSectionFocus(e)},overview:()=>{this.setFollowLive(!1),this.zoomToFit()},getFloors:()=>this.renderer?.getFloors?.()??[],getActiveFloorId:()=>this.renderer?.getActiveFloorId?.()??"",isFloorOverview:()=>this.renderer?.isFloorOverview?.()??!1,getRenderer:()=>this.renderer}}syncMinimap(){let e=this.els.minimapMount,t=!!this.root?.classList.contains("compact");if(!e||!this.renderer||t){this.minimap?.dispose(),this.minimap=null;return}if(this.minimap){this.minimap.refreshMinimap();return}this.minimap=N({controller:this.mapCamera(),root:()=>this.root,cssVar:s=>this.cssVar(s.replace(/^--sl-/,"--slm-")),focusedSectionLabel:()=>{},tint:s=>this.renderer?.categoryDisplayColor?.(s)||void 0},e),this.minimap.refreshMinimap()}cssVar(e){return this.root?getComputedStyle(this.root).getPropertyValue(e).trim():""}destroy(){if(this.selectObserver?.disconnect(),this.closed=!0,this.minimap?.dispose(),this.minimap=null,this.monitorRefreshTimer&&clearTimeout(this.monitorRefreshTimer),this.monitorRefreshTimer=null,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.feedTimer&&clearInterval(this.feedTimer),this.toastTimer&&clearTimeout(this.toastTimer),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.paintHandle!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.paintHandle),this.paintHandle=null,this.channels?.destroy(),this.channels=null,this.channelsLoading=null,this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.layoutObserver?.disconnect(),this.layoutObserver=null,this.colorSchemeStop?.(),this.colorSchemeStop=null,this.root?.removeEventListener("keydown",this.onKeyDown),this.els.rail?.removeEventListener("click",this.onRailClick),typeof document<"u"&&document.removeEventListener("fullscreenchange",this.onFullscreenChange),this.ws){try{this.ws.close()}catch{}this.ws=null}this.seatHistoryPanel?.destroy(),this.seatHistoryPanel=null,this.activityPanel?.destroy(),this.activityPanel=null,this.navigation?.destroy(),this.navigation=null,this.renderer?.destroy(),this.renderer=null,this.organizerAssetUrls.dispose(),this.root&&this.root.parentNode===this.host&&this.host.removeChild(this.root)}buildRenderer(){if(!this.doc)return;let e=this.isBulkSelectMode();this.renderer=new dt(this.mapHost,{manageMode:!0,organizerGlyph:{apply:ht,clear:mt,isPainted:pt},marqueeSelect:e&&!this.movingMap,marqueeShape:this.marqueeShape,rowLabelSelect:this.rowLabelSelectable(),maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses(),currency:this.currency,onSelect:t=>this.handleSeatSelect(t),onDeselect:()=>this.syncSelection(),onSelectionLimit:t=>this.opts.onSelectionLimit?.(t),onMarquee:()=>this.syncSelection(),onSectionTap:t=>{if(this.mode==="filterSections"){let s=this.filterableSections().find(i=>i.id===t);s&&this.setFilteredSection(s.label);return}this.renderer?.focusSection(t),this.channels?.handleSectionFocus(t)},onViewChange:()=>{this.updateZoomHint(),this.paintMapChrome(),this.minimap?.drawMinimapRect(),this.channels?.handleViewChange()},onFocusedSectionChange:()=>{this.paintMapChrome(),this.minimap?.refreshMinimap()},hoverFacts:t=>this.hoverFactsFor(t),blockPaint:t=>pe(t,{rule:this.availabilityRules[t.id],hiddenNow:this.effectiveHidden.has(t.id),closedNow:this.effectiveClosed.has(t.id)}),openAtSectionsWhenDense:!0}),this.renderer.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),this.applyMapView(),this.updateZoomHint(),this.minimap?.dispose(),this.minimap=null,this.syncMinimap(),this.paintMapChrome()}hoverFactsFor(e){let t=[...this.labelToSeat.values()].find(r=>r.id===e);if(!t)return null;let s=this.status.get(t.label)??"free",o=[{caption:"Status",value:{free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"}[s]}],a=this.channels?.channelNameForLabel(t.label)??null;a&&o.push({caption:"Channel",value:a});let n=this.sectionByObject.get(t.rowId)??v,c=this.doc?.categories.find(r=>r.key===t.categoryKey),d=s==="free"&&!this.effectiveHidden.has(n)&&!this.effectiveClosed.has(n)&&c?.notForSale!==!0;return o.push({caption:"For sale",value:d?"Yes":s==="free"?"No":"\u2014"}),o}rowLabelSelectable(){return this.isBulkSelectMode()||this.mode==="select"}marqueeShapeChipsHtml(){let e=(t,s)=>`<button type="button" class="slm-btn${this.marqueeShape===t?"":" ghost"}" data-ref="shape-${t}"
|
|
695
|
+
aria-pressed="${this.marqueeShape===t}" title="${t==="box"?"Drag a rectangle over seats":"Draw a loop around seats"}">${s}</button>`;return`${e("box","Drag box")}${e("lasso","Lasso")}`}wireMarqueeShapeChips(){this.els.rail.querySelectorAll('[data-ref^="shape-"]').forEach(e=>{e.addEventListener("click",()=>{let t=e.dataset.ref==="shape-lasso"?"lasso":"box";t!==this.marqueeShape&&(this.marqueeShape=t,this.updateRendererInteraction(),this.els.rail.querySelectorAll('[data-ref^="shape-"]').forEach(s=>{let i=s.dataset.ref===`shape-${t}`;s.classList.toggle("ghost",!i),s.setAttribute("aria-pressed",String(i))}))})})}isBulkSelectMode(){return this.mode==="block"||this.mode==="categories"||this.mode==="channels"&&this.channels?.usesMarqueeSelection()===!0}selectableStatuses(){return this.mode==="block"?["free","not_for_sale"]:this.mode==="select"||this.mode==="categories"||this.mode==="inspect"||this.isBulkSelectMode()||this.mode==="channels"&&this.channels?.canSelect()===!0?["free","held","booked","not_for_sale"]:[]}updateRendererInteraction(){let e=this.isBulkSelectMode();this.renderer?.setManageInteraction({manageMode:!0,organizerStatus:this.mode!=="channels",marqueeSelect:e&&!this.movingMap,marqueeShape:this.marqueeShape,rowLabelSelect:this.rowLabelSelectable(),maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses()}),this.navigation?.update(e,this.mode==="view"),this.updateZoomHint()}handleSeatSelect(e){if(this.mode==="select"&&!this.canSelectObject(e)){this.renderer?.deselect([e.id]),this.syncSelection();return}if(this.mode==="inspect"){let t=this.getSelection().filter(s=>s.id!==e.id).map(s=>s.id);t.length&&this.renderer?.deselect(t)}this.syncSelection()}buildUnitUniverse(e){for(let t of ut(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of gt(e))for(let s of ft(t))this.labelToId.has(s)||this.gaUnitLabelSet.add(s)}unitTotal(){return this.allIds.length+this.gaUnitLabelSet.size}knownLabels(){return[...this.labelToId.keys(),...this.gaUnitLabelSet]}repaintAll(){let e=this.renderer;if(!e)return;this.allIds.length&&e.setStatus(this.allIds,"free");let t={free:[],held:[],booked:[],not_for_sale:[]};for(let[s,i]of this.status.entries()){let o=this.labelToId.get(s);o&&t[L(i)].push(o)}["held","booked","not_for_sale"].forEach(s=>{t[s].length&&e.setStatus(t[s],s)})}async connect(){if(this.closed||this.sessionEnded)return;let e;try{if(e=(await this.withAuthRetry(()=>this.api.subscribeTicket(this.key))).protocols,!e.length)throw new Error("manage_subscribe_ticket_missing")}catch(s){this.setLive(!1),this.opts.onError?.(s),this.scheduleReconnect();return}if(this.closed)return;let t;try{t=new WebSocket(this.api.socketUrl(this.key),e)}catch(s){this.opts.onError?.(s),this.scheduleReconnect();return}this.ws=t,this.socketSnapshotSeen=!1,t.onopen=()=>{this.attempt=0,this.setLive(!0),this.resnapshot().then(()=>this.refreshControlRoom()).catch(s=>this.opts.onError?.(s)),this.refreshAvailability()},t.onmessage=s=>this.onMessage(s),t.onclose=()=>{this.ws===t&&(this.ws=null),this.setLive(!1),this.scheduleReconnect()},t.onerror=()=>{try{t.close()}catch{}}}scheduleReconnect(){if(this.closed||this.sessionEnded||this.reconnectTimer)return;let e=Math.min(1e3*2**Math.min(this.attempt++,5),15e3);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},e)}onMessage(e){let t;try{t=JSON.parse(typeof e.data=="string"?e.data:"")}catch{return}if(!t||typeof t!="object")return;this.lastMessageAt=Date.now();let s=t;if((Array.isArray(s.hidden)||Array.isArray(s.closed))&&this.updateEffectiveAvailability(s.hidden,s.closed),s.type==="presence"){typeof s.shoppingSessions=="number"&&typeof s.activeHolds=="number"&&(this.livePresence={at:Date.now(),value:{shoppingSessions:s.shoppingSessions,activeHolds:s.activeHolds}},this.controlRoomSnapshot&&(this.controlRoomSnapshot={...this.controlRoomSnapshot,presence:this.livePresence.value},this.opts.onControlRoom?.(this.controlRoomSnapshot)),this.lastSyncedAt=Date.now(),this.recomputeTallies(),this.paintMonitorInsights());return}if(s.type!=="hidden"){if(s.seats&&typeof s.seats=="object")this.applySocketSnapshot(s.seats,typeof s.default=="string"?s.default:void 0);else if(Array.isArray(s.changes)){let i=[],o=new Map;for(let n of s.changes){let c=["free","held","booked","blocked"].includes(n.status)?n.status:"free",d=this.status.get(n.label)??"free";if(d===c)continue;this.setStatusLabel(n.label,c,d);let r=this.labelToId.get(n.label);r&&(this.renderer?.setStatus([r],L(c)),i.push(r));let h=this.verbFor(d,c),p=`${h}:${c}`,u=o.get(p)??{labels:[],verb:h,status:c};u.labels.push(n.label),o.set(p,u)}for(let n of o.values()){let c=this.pushActivity(n.labels,n.verb,n.status);c&&this.paintSpatialActivity(c)}o.size&&this.scheduleMonitorRefresh(),i.length&&(this.lastSyncedAt=Date.now(),this.afterPaint());let a=typeof s.bookedValue?.gross=="number"?s.bookedValue.gross:s.revenue?.gross;typeof a=="number"&&Number.isFinite(a)&&this.applyLiveGross(a),this.recomputeTallies()}}}applyLiveGross(e){if(this.liveGross={at:Date.now(),value:e},this.authoritativeGrossRevenue=e,this.revenueStatus="current",this.controlRoomSnapshot){let s={...this.controlRoomSnapshot.bookedValue??this.controlRoomSnapshot.revenue,gross:e};this.controlRoomSnapshot={...this.controlRoomSnapshot,bookedValue:s,revenue:s},this.opts.onControlRoom?.(this.controlRoomSnapshot)}}setStatusLabel(e,t,s=this.status.get(e)??"free"){this.status.set(e,t),s!==t&&(s!=="free"&&(this.counts[s]-=1),t!=="free"&&(this.counts[t]+=1))}applySocketSnapshot(e,t){let s=this.socketSnapshotSeen?this.status:null;if(this.applySnapshot(e,t),this.socketSnapshotSeen=!0,!s)return;let i=new Map;for(let o of new Set([...s.keys(),...this.status.keys()])){let a=s.get(o)??"free",n=this.status.get(o)??"free";if(a===n)continue;let c=this.verbFor(a,n),d=`${c}:${n}`,r=i.get(d)??{labels:[],verb:c,status:n};r.labels.push(o),i.set(d,r)}for(let o of i.values()){let a=this.pushActivity(o.labels,o.verb,o.status);a&&this.paintSpatialActivity(a)}i.size&&this.scheduleMonitorRefresh()}scheduleMonitorRefresh(){this.monitorRefreshTimer||(this.monitorRefreshTimer=setTimeout(()=>{this.monitorRefreshTimer=null,this.closed||this.refreshControlRoom().catch(e=>this.opts.onError?.(e))},150))}async resnapshot(){try{let e=await this.api.objects(this.key);this.applySnapshot(e.seats),this.updateEffectiveAvailability(e.hidden,e.closed),this.lastMessageAt=Date.now()}catch{}}applySnapshot(e,t){let s=o=>["free","held","booked","blocked"].includes(o)?o:"free",i=new Map;if(t!==void 0){let o=s(t);for(let a of this.knownLabels())i.set(a,o)}for(let[o,a]of Object.entries(e))i.set(o,s(a));this.status=i,this.modelVersion+=1,this.recountAll(),this.lastSyncedAt=Date.now(),this.repaintAll(),this.afterPaint(),this.recomputeTallies()}recountAll(){let e={held:0,booked:0,blocked:0};for(let t of this.status.values())t!=="free"&&(e[t]+=1);this.counts=e}setSeatsLocal(e,t){let s=[];for(let i of e){this.setStatusLabel(i,t);let o=this.labelToId.get(i);o&&s.push(o)}s.length&&this.renderer?.setStatus(s,L(t)),this.afterPaint(),this.recomputeTallies()}afterPaint(){this.keepLive&&typeof document<"u"&&document.hidden&&this.renderer?.forceDraw()}activityColor(e){return e==="held"?x.held:e==="booked"?x.booked:e==="blocked"?x.blocked:x.free}sectionsForLabels(e){let t=new Set;for(let i of e){let o=this.labelToSeat.get(i);if(!o)continue;let a=this.sectionByObject.get(o.rowId);a&&a!==v&&t.add(a)}let s=[...t];return{ids:s,labels:s.map(i=>this.sectionLabelById.get(i)??i)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let i of e.slice(0,Te)){let o=this.labelToId.get(i);o&&this.renderer?.flashSeat(o,s)}}paintSpatialActivity(e){let t=e.sectionIds??this.sectionsForLabels(e.labels).ids,s=this.renderer?.getFocusedSection()??null;if(this.followLive&&t.length===1&&(e.status==="held"||e.status==="booked")){let o=this.root?.querySelector('[data-ref="followstatus"]');o&&(o.textContent=`Following ${e.labels.length===1?e.labels[0]:`${e.labels.length} seats`} \xB7 ${e.status}`),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=setTimeout(()=>{this.followLiveTimer=null,this.focusActivitySeats(e.labels,t[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(e.labels,e.status)},520)},220);return}if(!s&&t.length){let o=this.activityColor(e.status);for(let a of t.slice(0,Ce))this.renderer?.flashSection(a,o);return}(!t.length||s&&t.includes(s))&&this.pulseSeatLabels(e.labels,e.status)}locateSection(e){this.renderer?.focusSection(e)}focusActivitySeats(e,t){this.renderer?.focusSection(t);let s=e.slice(0,Te).map(c=>this.labelToSeat.get(c)).filter(c=>!!c);if(!s.length)return;let i=s.map(c=>c.x),o=s.map(c=>c.y),a=Math.min(...i),n=Math.min(...o);this.renderer?.focusRegion({x:a-150,y:n-100,width:Math.max(...i)-a+300,height:Math.max(...o)-n+200})}locateActivity(e){let t=this.feed.find(i=>i.id===e);if(!t)return;let s=t.sectionIds??this.sectionsForLabels(t.labels).ids;if(this.followSeatTimer&&clearTimeout(this.followSeatTimer),s.length===1){this.focusActivitySeats(t.labels,s[0]),this.followSeatTimer=setTimeout(()=>{this.followSeatTimer=null,this.pulseSeatLabels(t.labels,t.status)},520);return}this.zoomToFit(),this.followSeatTimer=setTimeout(()=>{if(this.followSeatTimer=null,s.length){let i=this.activityColor(t.status);for(let o of s.slice(0,Ce))this.renderer?.flashSection(o,i)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],i=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,o=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
|
|
696
|
+
<span class="slm-liveeventcopy">${m(i)} \xB7 ${e.count.toLocaleString()} ${o} ${m(e.verb)}</span>
|
|
697
|
+
<span class="slm-liveeventhint">Live</span>`,t.classList.add("on"),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.liveEventTimer=setTimeout(()=>{this.liveEventTimer=null,t.classList.remove("on"),t.innerHTML=""},2800)}applyReportRevenue(e){this.authoritativeGrossRevenue=e.report.byCategory.reduce((t,s)=>{let i=Number.isFinite(s.bookedValue)?s.bookedValue:s.bookedRevenue;return t+(Number.isFinite(i)?i:0)},0),this.revenueStatus="current",this.recomputeTallies()}async refreshControlRoom(){let e=++this.revenueRequest,t=Date.now();try{let s=await this.api.controlRoom(this.key,this.trendWindowMinutes),i=s.bookedValue??s.revenue??{gross:0,bySection:[]},o=(i.bySection??[]).map(c=>{let d=Number.isFinite(c.bookedValue)?c.bookedValue:c.bookedRevenue;return{...c,bookedValue:d??0,bookedRevenue:d??0}}),a={...i,bySection:o},n={...s,bookedValue:a,revenue:a};if(e===this.revenueRequest){if(this.livePresence&&this.livePresence.at>=t?n={...n,presence:this.livePresence.value}:this.livePresence=null,this.liveGross&&this.liveGross.at>=t){let r={...n.bookedValue,gross:this.liveGross.value};n={...n,bookedValue:r,revenue:r}}else this.liveGross=null;this.controlRoomSnapshot=n,n.activity&&this.seedFeed(n.activity),this.rebaseServerTotals(n),this.lastSyncedAt=Date.now(),this.authoritativeGrossRevenue=n.bookedValue.gross,this.authoritativeCurrency=n.currency,this.currency=n.currency,this.revenueStatus="current",this.recomputeTallies(),this.applyHeatOverlay(),this.paintMonitorInsights(),this.seatHistoryPanel?.refresh();let c=this.getSelection().slice(-1)[0],d=this.els.rail?.querySelector("[data-seat-status]");c&&d&&(d.textContent=this.status.get(c.label)??"free"),this.opts.onControlRoom?.(n)}return n}catch(s){throw e===this.revenueRequest&&(this.revenueStatus="stale",this.recomputeTallies()),s}}rebaseServerTotals(e){let t=e.totals;if(!t||["free","held","booked","blocked"].some(s=>!Number.isFinite(t[s]))){this.serverBaseline=null;return}this.serverBaseline={model:this.modelVersion,server:{free:t.free,held:t.held,booked:t.booked,blocked:t.blocked},client:this.clientTallies()}}clientTallies(){let{held:e,booked:t,blocked:s}=this.counts;return{held:e,booked:t,blocked:s,free:Math.max(0,this.unitTotal()-e-t-s)}}buildTallies(){let e=this.clientTallies(),t=this.serverBaseline?.model===this.modelVersion?this.serverBaseline:null,s=n=>t?Math.max(0,t.server[n]+(e[n]-t.client[n])):e[n],i=this.controlRoomSnapshot?.event?.seatTotal,o={free:s("free"),held:s("held"),booked:s("booked"),blocked:s("blocked"),total:Number.isFinite(i)?i:this.unitTotal(),capacityPct:0,sellThroughPct:0,bookedValue:this.authoritativeGrossRevenue,grossRevenue:this.authoritativeGrossRevenue,bookedValueStatus:this.revenueStatus,revenueStatus:this.revenueStatus,currency:this.currency};o.capacityPct=o.total?Math.round(o.booked/o.total*100):0;let a=o.total-o.blocked;return o.sellThroughPct=a>0?Math.round(o.booked/a*100):0,o}recomputeTallies(){if(!this.closed){if(typeof requestAnimationFrame!="function"){this.flushTallies();return}this.paintHandle===null&&(this.paintHandle=requestAnimationFrame(()=>{this.paintHandle=null,this.flushTallies()}))}}flushTallies(){if(this.closed)return;let e=this.buildTallies();this.paintKpis(e),this.mode==="view"?(this.paintLegend(e),this.paintMonitorInsights()):this.mode==="inspect"?this.renderInspectRail(this.getSelection()):this.mode==="block"?this.paintSelBar(this.getSelection()):this.mode==="channels"&&this.channels?.handleSelectionChange(),this.opts.onTallies?.(e)}verbFor(e,t){return t==="held"?"held":t==="booked"?"booked":t==="blocked"?"blocked":t==="free"?e==="blocked"?"unblocked":e==="booked"?"cancelled":"available":t}pushActivity(e,t,s,i=Date.now()){let o=e[0];if(!o)return null;let a=this.sectionsForLabels(e),n={id:`${o}:${i}:${Math.random().toString(36).slice(2,6)}`,at:i,label:o,labels:[...e],count:e.length,verb:t,status:s,sectionIds:a.ids,sectionLabels:a.labels};return this.controlRoomSnapshot?.activity||this.feed.unshift(n),this.feed.length>H&&(this.feed.length=H),this.mode==="view"&&this.paintFeed(),this.showLiveEvent(n),this.opts.onActivity?.(n),n}seedFeed(e){this.controlRoomSnapshot?.activity&&(this.feed=this.feed.filter(i=>i.id.startsWith("log:")));let t={hold:"held",book:"booked",release:"released",expire:"expired",block:"blocked",unblock:"unblocked",unbook:"cancelled"},s={hold:"held",book:"booked",release:"free",expire:"free",block:"blocked",unblock:"free",unbook:"free"};for(let i of e){if(this.feed.some(c=>c.id===`log:${i.id}`))continue;let o=i.labels[0];if(!o)continue;let a=this.sectionsForLabels(i.labels),n={id:`log:${i.id}`,at:i.at,label:o,labels:[...i.labels],count:i.labels.length,verb:t[i.action]??i.action,status:s[i.action]??"free",sectionIds:a.ids,sectionLabels:a.labels};this.feed.push(n),this.opts.onActivity?.(n)}this.feed.sort((i,o)=>o.at-i.at),this.feed.length>H&&(this.feed.length=H),this.mode==="view"&&this.paintFeed()}startFeedClock(){this.feedTimer=setInterval(()=>{this.mode==="view"&&(this.paintFeed(),this.paintMonitorInsights())},1e4)}selectionCap(){return this.mode!=="select"?1e6:this.opts.numberOfPlacesToSelect??this.opts.maxSelectedObjects??1e6}canSelectObject(e){let t=this.status.get(e.label)??"free",s=this.opts.unavailableObjectsSelectable??!0,i=t==="free"||s||this.selectableObjectLabels.has(e.label);if(!this.opts.isObjectSelectable)return i;try{return this.opts.isObjectSelectable(e,i)===!0}catch(o){return this.opts.onError?.(o),!1}}applyInitialSelection(){this.initialSelectionApplied||this.mode!=="select"||!this.renderer||(this.initialSelectionApplied=!0,this.selectByLabels(this.opts.selectedObjects??[]))}trimSelectionToCap(){if(this.mode!=="select")return;let e=this.getSelection(),t=this.selectionCap();e.length<=t||this.renderer?.deselect(e.slice(t).map(s=>s.id))}reconcileSelectPolicy(){if(this.mode!=="select")return;let e=this.getSelection().filter(t=>!this.canSelectObject(t));e.length&&this.renderer?.deselect(e.map(t=>t.id)),this.trimSelectionToCap(),this.syncSelection()}selectionLabels(){return this.getSelection().map(e=>e.label)}syncSelection(){let e=this.getSelection();this.mode==="block"?this.paintSelBar(e):this.mode==="inspect"?this.renderInspectRail(e):this.mode==="select"?this.paintSelectSelection(e):this.mode==="categories"?this.paintCategorySelection(e):this.mode==="channels"&&this.channels?.handleSelectionChange();let t=new Map(e.map(s=>[s.label,s]));if(this.mode==="select"){for(let[i,o]of t)this.lastSelectionLabels.has(i)||this.opts.onObjectSelected?.(o);for(let i of this.lastSelectionLabels)if(!t.has(i)){let o=this.labelToSeat.get(i);o&&this.opts.onObjectDeselected?.(o)}let s=this.getSelectionValidity();s&&(this.opts.onSelectionValidityChange?.(s),this.selectionWasValid!==s.isValid&&(s.isValid?this.opts.onSelectionValid?.(s):this.opts.onSelectionInvalid?.(s)),this.selectionWasValid=s.isValid)}this.lastSelectionLabels=new Set(t.keys()),this.navigation?.selectionChanged(e.length),this.opts.onSelectionChange?.(e)}buildChrome(){let e=document.createElement("div");e.className="slm",e.tabIndex=0,e.setAttribute("role","region"),e.setAttribute("aria-label","SeatLayer live control room"),e.innerHTML=`
|
|
474
698
|
<div class="slm-bar">
|
|
475
699
|
<div class="slm-modes" data-ref="modes" role="tablist" aria-label="Control room tools">
|
|
476
|
-
${
|
|
477
|
-
<span class="slm-modegroup-label" aria-hidden="true">${
|
|
478
|
-
${i.tools.map(
|
|
479
|
-
title="${
|
|
700
|
+
${Ee.map(i=>`<div class="slm-modegroup" data-group="${i.key}" role="presentation" hidden>
|
|
701
|
+
<span class="slm-modegroup-label" aria-hidden="true">${m(i.label)}</span>
|
|
702
|
+
${i.tools.map(o=>`<button class="slm-mode" role="tab" data-mode="${o.mode}"
|
|
703
|
+
title="${m(o.title)} (${o.shortcut})" aria-keyshortcuts="${o.shortcut}" hidden>${m(o.label)}</button>`).join("")}
|
|
480
704
|
</div>`).join("")}
|
|
481
705
|
</div>
|
|
482
706
|
<select class="slm-tools" data-ref="tools" aria-label="Control room tools"></select>
|
|
@@ -484,9 +708,8 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
484
708
|
<div class="slm-bar-actions">
|
|
485
709
|
<button class="slm-barbtn follow" data-ref="follow" aria-label="Follow live" aria-pressed="false"
|
|
486
710
|
title="Stay on the current map view unless enabled">Auto-follow</button>
|
|
487
|
-
<
|
|
488
|
-
|
|
489
|
-
title="Highlight sections booking fastest in the selected time window">Heatmap</button>
|
|
711
|
+
<div data-ref="findbar" class="slm-findbar">${O({compact:!0})}</div>
|
|
712
|
+
${ke()}
|
|
490
713
|
<button class="slm-barbtn" data-ref="fullscreen" title="Full screen (F)" aria-keyshortcuts="F">Full screen</button>
|
|
491
714
|
</div>
|
|
492
715
|
<div class="slm-kpis" data-ref="kpis"></div>
|
|
@@ -500,16 +723,16 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
500
723
|
</div>
|
|
501
724
|
<div class="slm-heat-status" data-ref="heatstatus" role="status" hidden></div>
|
|
502
725
|
<div class="slm-follow-status" data-ref="followstatus" role="status" hidden></div>
|
|
503
|
-
|
|
726
|
+
${he({legend:ue()})}
|
|
504
727
|
</div>
|
|
505
728
|
<aside class="slm-rail"><div class="slm-railscroll" data-ref="rail"></div></aside>
|
|
506
729
|
</div>
|
|
507
730
|
<div class="slm-toast" data-ref="toast"></div>
|
|
508
|
-
`,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let i=e.querySelector(".slm-rail");i&&
|
|
509
|
-
<p class="slm-hint">${s}</p>`}paintFollowLiveButton(){let e=this.els.follow;if(!e)return;e.classList.toggle("on",this.followLive),e.setAttribute("aria-pressed",String(this.followLive)),e.textContent="Auto-follow";let t=this.root?.querySelector('[data-ref="followstatus"]');t&&(t.hidden=!this.followLive,t.textContent="Waiting for new holds or bookings"),e.setAttribute("title",this.followLive?"Following new holds and bookings. Turn off to keep the current view.":"Stay on the current map view. Enable to follow new holds and bookings.")}paintHeatButton(){
|
|
510
|
-
<b>${
|
|
511
|
-
${
|
|
512
|
-
</div>`}).join(""),
|
|
731
|
+
`,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let i=e.querySelector(".slm-rail");i&&(S(i),_(i))});let t=e.querySelector(".slm-rail");t&&this.selectObserver.observe(t,{childList:!0,subtree:!0}),this.applyThemeVars(),this.watchThemeMode(),this.updateContainerLayout(),typeof ResizeObserver<"u"&&(this.layoutObserver=new ResizeObserver(()=>this.updateContainerLayout()),this.layoutObserver.observe(e));let s=i=>e.querySelector(`[data-ref="${i}"]`);this.mapHost=s("maphost"),this.els={modes:s("modes"),tools:s("tools"),livetext:s("livetext"),kpis:s("kpis"),follow:s("follow"),view:s("view"),findbar:s("findbar"),fullscreen:s("fullscreen"),lane:s("lane"),zoomhint:s("zoomhint"),liveevent:s("liveevent"),rail:s("rail"),toast:s("toast"),mapchrome:s("mapchrome"),crumb:s("crumb"),zin:s("zin"),zout:s("zout"),zfit:s("zfit"),minimapMount:s("minimap"),blocklegend:s("blocklegend")},this.els.modes.querySelectorAll("[data-mode]").forEach(i=>i.addEventListener("click",()=>this.setMode(i.dataset.mode))),this.els.tools.addEventListener("change",()=>this.setMode(this.els.tools.value)),this.els.zfit.addEventListener("click",()=>{this.setFollowLive(!1),this.zoomToFit()}),this.els.zin.addEventListener("click",()=>{this.setFollowLive(!1),this.renderer?.zoomIn()}),this.els.zout.addEventListener("click",()=>{this.setFollowLive(!1),this.zoomOutStep()}),this.els.follow.addEventListener("click",()=>this.setFollowLive(!this.followLive)),this.els.view.addEventListener("click",i=>{let o=i.target?.closest("[data-view]");o?.dataset.view&&this.toggleMapView(o.dataset.view)}),e.addEventListener("pointerdown",i=>{let o=this.els.view;o.open&&!o.contains(i.target)&&(o.open=!1)}),this.mapView=ve(),this.heatEnabled=this.mapView.momentum,this.applyMapView(),this.wireBarFind(),this.els.fullscreen.addEventListener("click",()=>this.toggleFullscreen()),e.addEventListener("keydown",this.onKeyDown),this.els.rail.addEventListener("click",this.onRailClick),document.addEventListener("fullscreenchange",this.onFullscreenChange),this.paintModeTabs(),this.paintFollowLiveButton(),this.paintHeatButton(),this.paintMapViewMenu(),this.paintFullscreenButton(),this.navigation=new E({root:e,map:this.mapHost,setMoving:i=>{this.movingMap=i,this.updateRendererInteraction()},pauseFollow:()=>{this.followLive&&this.setFollowLive(!1)},clearSelection:()=>this.clearSelection(),zoomIn:()=>this.renderer?.zoomIn(),zoomOut:()=>this.renderer?.zoomOut(),targets:i=>this.navigationTargets(i)}),this.navigation.update(this.isBulkSelectMode(),this.mode==="view")}navigationTargets(e){let t=e.toLocaleLowerCase(),s=[];for(let o of this.sectionOptions)if(o.label.toLocaleLowerCase().includes(t)&&s.push({label:o.label,detail:"Section",locate:()=>this.locateSection(o.id)}),s.length>=20)return s;let i=new Map;for(let o of this.labelToSeat.values()){let a=i.get(o.rowId)??{minX:o.x,minY:o.y,maxX:o.x,maxY:o.y};a.minX=Math.min(a.minX,o.x),a.minY=Math.min(a.minY,o.y),a.maxX=Math.max(a.maxX,o.x),a.maxY=Math.max(a.maxY,o.y),i.set(o.rowId,a)}for(let o of this.doc?Me(this.doc).flatMap(a=>a.objects):[]){if(o.type!=="row"||!(o.displayLabel??o.label).toLocaleLowerCase().includes(t))continue;let a=i.get(o.id);if(!a)continue;let{minX:n,minY:c,maxX:d,maxY:r}=a;if(s.push({label:o.displayLabel??o.label,detail:"Row",locate:()=>{let h=this.sectionByObject.get(o.id);h&&this.renderer?.focusSection(h),this.renderer?.focusRegion({x:n-30,y:c-30,width:d-n+60,height:r-c+60},{minScale:1.2,animate:!1})}}),s.length>=20)return s}for(let o of this.labelToSeat.values())if(o.label.toLocaleLowerCase().includes(t)&&(s.push({label:o.label,detail:"Seat",locate:()=>{let a=this.sectionByObject.get(o.rowId);a&&this.renderer?.focusSection(a),this.renderer?.focusRegion({x:o.x-180,y:o.y-120,width:360,height:240},{animate:!1,minScale:1.5}),this.renderer?.flashSeat(o.id,this.activityColor(this.status.get(o.label)??"free"))}}),s.length>=20))break;return s}updateContainerLayout(){let e=this.root?.getBoundingClientRect().width||this.host.clientWidth;this.root?.classList.toggle("compact",e>0&&e<800),this.channels?.handleLayoutChange(),this.syncMinimap()}filterableSections(){return this.sectionsBase?[...this.sectionsBase.sections,...this.sectionsBase.ungrouped?[this.sectionsBase.ungrouped]:[]]:[]}applyFilteredSectionCanvas(e=this.filterableSections().filter(t=>t.label===this.filteredSectionLabel)){if(!this.renderer||this.mode!=="filterSections"||!e.length)return;let t=new Set(e.map(r=>r.id)),s=this.filterableSections().filter(r=>!t.has(r.id)).map(r=>r.id);this.renderer.clearSectionFocus(),this.renderer.setClosedSections(null),this.renderer.setDimmedSections(s);let i=e.flatMap(r=>r.seatLabels).map(r=>this.labelToSeat.get(r)).filter(r=>!!r&&Number.isFinite(r.x)&&Number.isFinite(r.y));if(!i.length){this.renderer.focusRegion(e[0].id);return}let o=Math.min(...i.map(r=>r.x)),a=Math.min(...i.map(r=>r.y)),n=Math.max(...i.map(r=>r.x)),c=Math.max(...i.map(r=>r.y)),d=Math.max(40,Math.max(n-o,c-a)*.08);this.renderer.focusRegion({x:o-d,y:a-d,width:Math.max(1,n-o)+d*2,height:Math.max(1,c-a)+d*2})}buildSectionOptions(){if(this.doc)try{let e=bt(this.doc);this.sectionsBase=e,this.sectionOptions=[],this.sectionByObject=new Map(e.objectToSection),this.sectionLabelById.clear();for(let t of e.sections)this.sectionOptions.push({id:t.id,label:t.label}),this.sectionLabelById.set(t.id,t.label);e.ungrouped&&(this.sectionOptions.push({id:v,label:e.ungrouped.label}),this.sectionLabelById.set(v,e.ungrouped.label))}catch{}}toolAvailable(e){return e==="view"?!0:e==="channels"&&!this.channelCaps.view||e==="categories"&&!this.categoryCanManage||e==="tables"&&(!this.tableCanManage||!this.tables().length)?!1:!this.opts.tools||this.opts.tools.includes(e)}settleMode(){this.toolAvailable(this.mode)?this.paintModeTabs():this.setMode("view")}tables(){return(this.doc?Me(this.doc):[]).flatMap(e=>e.objects).filter(e=>e.type==="table")}paintModeTabs(){let e=[];this.els.modes?.querySelectorAll(".slm-modegroup").forEach(s=>{let i=[];s.querySelectorAll("[data-mode]").forEach(o=>{let a=o.dataset.mode,n=this.toolAvailable(a);if(o.hidden=!n,!n)return;i.push({mode:a,label:o.textContent??a});let c=a===this.mode;o.classList.toggle("on",c),o.setAttribute("aria-selected",String(c)),o.tabIndex=c?0:-1}),s.hidden=i.length===0,i.length&&e.push({label:s.querySelector(".slm-modegroup-label")?.textContent??"",tools:i})});let t=this.els.tools;t&&(t.innerHTML=e.map(s=>`<optgroup label="${m(s.label)}">${s.tools.map(i=>`<option value="${i.mode}"${i.mode===this.mode?" selected":""}>${m(i.label)}</option>`).join("")}</optgroup>`).join(""),t.value=this.mode),this.root?.classList.toggle("block-mode",this.mode==="block")}railHeader(e,t,s){let i=t==="read"?"Read-only":t==="event"?"This event only":"Your app";return`<div class="slm-railhead"><p class="slm-eyebrow">${m(e)}</p><span class="slm-scope ${t}">${i}</span></div>
|
|
732
|
+
<p class="slm-hint">${s}</p>`}paintFollowLiveButton(){let e=this.els.follow;if(!e)return;e.classList.toggle("on",this.followLive),e.setAttribute("aria-pressed",String(this.followLive)),e.textContent="Auto-follow";let t=this.root?.querySelector('[data-ref="followstatus"]');t&&(t.hidden=!this.followLive,t.textContent="Waiting for new holds or bookings"),e.setAttribute("title",this.followLive?"Following new holds and bookings. Turn off to keep the current view.":"Stay on the current map view. Enable to follow new holds and bookings.")}paintHeatButton(){this.paintMapViewMenu(),this.paintMomentumHelp()}paintMomentumHelp(){let e=this.root?.querySelector('[data-ref="heatstatus"]');if(e){e.hidden=!this.heatEnabled;let o=this.controlRoomSnapshot?.velocity.bySection.some(a=>a.netBooked>0);e.textContent=this.controlRoomSnapshot?o?`Booking heatmap \xB7 last ${this.trendWindowMinutes}m \xB7 warmer = higher net booking rate`:`No positive net bookings in the last ${this.trendWindowMinutes}m`:"Loading booking heatmap\u2026"}let t=this.els.rail?.querySelector('[data-ref="momentumhelp"]');if(!t)return;t.hidden=!this.heatEnabled;let s=t.querySelector('[data-ref="momentumcopy"]');if(!s)return;let i=this.controlRoomSnapshot?.velocity.bySection.some(o=>o.netBooked>0);s.textContent=i?"Warmer sections have more completed bookings, adjusted for section size. Holds and viewers are not counted.":`No completed bookings in the last ${this.trendWindowMinutes} minutes.`}paintFullscreenButton(){this.els.fullscreen&&(this.els.fullscreen.textContent=this.isFullscreen()?"Exit full screen":"Full screen")}paintTrendWindow(){this.els.rail?.querySelectorAll("[data-window]").forEach(e=>{let t=Number(e.dataset.window);e.classList.toggle("on",t===this.trendWindowMinutes)})}setLive(e){this.root?.classList.toggle("live",e),this.els.livetext&&(this.els.livetext.textContent=e?"LIVE":"RECONNECTING"),this.paintMonitorInsights();let t=e?"live":this.sessionEnded?"ended":"reconnecting";if(this.els.livetext&&!e&&this.sessionEnded&&(this.els.livetext.textContent="ENDED"),t!==this.connectionStatus){this.connectionStatus=t;try{this.opts.onConnectionChange?.(this.getConnection())}catch(s){this.opts.onError?.(s)}}}updateZoomHint(){let e=this.els.zoomhint;if(!e)return;let t=this.isBulkSelectMode()&&!this.movingMap&&this.renderer?.getRung?.()!=="seats";e.classList.toggle("on",!!t)}formatKpiDelta(e,t,s){let i=t>0?"+":"\u2212",o=Math.abs(t);return e==="booked-value"?`${i}${M(o,s)}`:e==="booked-pct"?`${i}${o.toLocaleString()}pt`:`${i}${o.toLocaleString()}`}paintKpis(e){if(!this.els.kpis)return;let t=e.bookedValueStatus==="current"?M(e.bookedValue,e.currency):"\u2014",s=this.presenceCounts(),i=[{key:"booked-inventory",raw:e.booked,n:e.booked.toLocaleString(),l:"Booked inventory",dot:x.booked,title:"Inventory units booked"},{key:"held-seats",raw:e.held,n:e.held.toLocaleString(),l:"Held inventory",dot:x.held,title:"Inventory currently held"},{key:"free-seats",raw:e.free,n:e.free.toLocaleString(),l:"Available",dot:x.free,title:"Inventory available to book"},{key:"blocked",raw:e.blocked,n:e.blocked.toLocaleString(),l:"Blocked",dot:x.blocked,title:"Inventory withheld from booking"},{key:"viewing-map",raw:s?.shoppingSessions??null,n:s?s.shoppingSessions.toLocaleString():"\u2014",l:"Viewing map",title:"Active map sessions right now"},{key:"active-holds",raw:s?.activeHolds??null,n:s?s.activeHolds.toLocaleString():"\u2014",l:"Active holds",title:"Sessions currently holding inventory"},{key:"booked-pct",raw:e.capacityPct,n:`${e.capacityPct}%`,l:"Booked",title:"Booked inventory as a share of the whole event"},{key:"booked-value",raw:e.bookedValueStatus==="current"?e.bookedValue:null,n:t,l:"Booked value",title:"Configured value attached to booked inventory"}],o=!1;this.els.kpis.innerHTML=i.map(a=>{let n=this.lastKpiValues.get(a.key),c=a.raw!=null&&n!=null&&a.raw!==n,d=c?a.raw-n:0;c&&(o=!0,this.activeKpiDeltas.set(a.key,{text:this.formatKpiDelta(a.key,d,e.currency),down:d<0})),a.raw!=null&&this.lastKpiValues.set(a.key,a.raw);let r=this.activeKpiDeltas.get(a.key);return`<div class="slm-kpi${r?" changed":""}" data-kpi="${a.key}" title="${m(a.title)}">
|
|
733
|
+
<b>${a.dot?`<span class="dot" style="background:${a.dot}"></span>`:""}${a.n}</b><span>${a.l}</span>
|
|
734
|
+
${r?`<span class="slm-kpidelta${r.down?" down":""}">${r.text}</span>`:""}
|
|
735
|
+
</div>`}).join(""),o&&(this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.kpiCleanupTimer=setTimeout(()=>{this.kpiCleanupTimer=null,this.activeKpiDeltas.clear(),this.els.kpis?.querySelectorAll(".slm-kpidelta").forEach(a=>a.remove()),this.els.kpis?.querySelectorAll(".slm-kpi.changed").forEach(a=>a.classList.remove("changed"))},1500))}paintRail(){this.root?.classList.toggle("monitor-view",this.mode==="view"||this.mode==="inspect"),this.seatHistoryPanel?.destroy(),this.seatHistoryPanel=null,this.activityPanel?.destroy(),this.activityPanel=null,this.mode==="view"?this.renderViewRail():this.mode==="inspect"?this.renderInspectRail(this.getSelection()):this.mode==="select"?this.renderSelectRail():this.mode==="filterSections"?this.renderFilterSectionsRail():this.mode==="sections"?this.renderSectionsRail():this.mode==="categories"?this.renderCategoriesRail():this.mode==="tables"?this.renderTablesRail():this.mode==="channels"?this.channels?this.channels.paintRail():this.channelsLoading?this.els.rail.innerHTML='<div class="slm-empty" role="status">Loading sales channels\u2026</div>':this.els.rail.innerHTML='<div class="slm-empty" role="alert">Sales channels could not be loaded. Switch away and back to try again.</div>':this.renderBlockRail(),this.updateZoomHint()}renderViewRail(){this.els.rail.innerHTML=`
|
|
513
736
|
<div class="slm-monitor-head"><h2>Live activity</h2><span data-ref="presence" class="slm-monitor-connection"></span></div>
|
|
514
737
|
<div class="slm-monitor-tabs" role="tablist" aria-label="Monitor details">
|
|
515
738
|
<button role="tab" aria-selected="true" data-monitor-tab="activity">Activity</button>
|
|
@@ -528,120 +751,93 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
528
751
|
</div>
|
|
529
752
|
<div class="slm-sectionlist" data-ref="sections"></div>
|
|
530
753
|
</div>
|
|
531
|
-
`,this.els.presence=this.els.rail.querySelector('[data-ref="presence"]'),this.els.legend=this.els.rail.querySelector('[data-ref="legend"]'),this.els.sections=this.els.rail.querySelector('[data-ref="sections"]'),this.els.feed=this.els.rail.querySelector('[data-ref="feed"]'),this.activityPanel=new
|
|
532
|
-
<span class="slm-sectiontop"><span>${
|
|
533
|
-
<span class="slm-sectionmeta"><span>${i.booked.toLocaleString()}/${i.total.toLocaleString()} booked \xB7 ${
|
|
534
|
-
</button>`}).join(""):'<div class="slm-empty">No section metrics are available for this chart.</div>',this.paintTrendWindow(),this.paintMomentumHelp()}applyHeatOverlay(){let e=this.controlRoomSnapshot;if(!this.heatEnabled||!e){this.renderer?.setSectionHeat(null);return}let t=new Map(e.bookedValue.bySection.map(
|
|
754
|
+
`,this.els.presence=this.els.rail.querySelector('[data-ref="presence"]'),this.els.legend=this.els.rail.querySelector('[data-ref="legend"]'),this.els.sections=this.els.rail.querySelector('[data-ref="sections"]'),this.els.feed=this.els.rail.querySelector('[data-ref="feed"]'),this.activityPanel=new C(this.els.feed,this.sectionOptions,e=>{this.setFollowLive(!1),this.locateActivity(e)}),this.els.rail.querySelectorAll("[data-monitor-tab]").forEach(e=>e.addEventListener("click",()=>{let t=e.dataset.monitorTab;this.els.rail.querySelectorAll("[data-monitor-tab]").forEach(s=>s.setAttribute("aria-selected",String(s.dataset.monitorTab===t))),this.els.rail.querySelectorAll("[data-monitor-panel]").forEach(s=>{s.hidden=s.dataset.monitorPanel!==t})})),this.els.rail.querySelectorAll("[data-window]").forEach(e=>e.addEventListener("click",()=>{let t=Number(e.dataset.window);this.setTrendWindow(t).catch(s=>this.opts.onError?.(s))})),this.recomputeTallies(),this.paintMonitorInsights(),this.paintTrendWindow(),this.paintMomentumHelp(),this.paintFeed()}presenceCounts(){return this.livePresence?.value??this.controlRoomSnapshot?.presence??null}paintMonitorInsights(){if(this.mode!=="view")return;let e=this.controlRoomSnapshot;if(this.els.presence){let i=this.root?.classList.contains("live"),o=this.lastSyncedAt?J(this.lastSyncedAt,Date.now()):"waiting";this.els.presence.textContent=i?"\u25CF Live":"Reconnecting",this.els.presence.title=`Last data received: ${o}`}if(!this.els.sections)return;if(!e){this.els.sections.innerHTML='<div class="slm-empty">Loading authoritative section metrics\u2026</div>';return}let t=new Map(e.velocity.bySection.map(i=>[i.sectionId,i])),s=[...e.bookedValue.bySection].sort((i,o)=>{let a=t.get(i.sectionId)?.netBooked??0;return(t.get(o.sectionId)?.netBooked??0)-a||o.bookedValue-i.bookedValue});this.els.sections.innerHTML=s.length?s.map(i=>{let o=t.get(i.sectionId),a=o?.netBooked??0,n=`${a>0?"+":""}${a}`,c=o?.trend==="rising"||o?.trend==="cooling"?o.trend:"steady";return`<button type="button" class="slm-sectionrow" data-section-focus="${m(i.sectionId)}" title="Focus ${m(i.sectionLabel)} on the map">
|
|
755
|
+
<span class="slm-sectiontop"><span>${m(i.sectionLabel)}</span><span title="Configured value of currently booked inventory">${M(i.bookedValue,e.currency)}</span></span>
|
|
756
|
+
<span class="slm-sectionmeta"><span>${i.booked.toLocaleString()}/${i.total.toLocaleString()} booked \xB7 ${n} net in ${e.velocity.windowMinutes}m</span><span class="slm-trend ${c}">${c}</span><span class="slm-sectionlocate">Locate</span></span>
|
|
757
|
+
</button>`}).join(""):'<div class="slm-empty">No section metrics are available for this chart.</div>',this.paintTrendWindow(),this.paintMomentumHelp()}applyHeatOverlay(){let e=this.controlRoomSnapshot;if(!this.heatEnabled||!e){this.renderer?.setSectionHeat(null);return}let t=new Map(e.bookedValue.bySection.map(a=>[a.sectionId,Math.max(1,a.total)])),s=e.velocity.bySection.map(a=>({sectionId:a.sectionId,rate:Math.max(0,a.netBooked)/(t.get(a.sectionId)??1)/e.velocity.windowMinutes})),i=Math.max(0,...s.map(a=>a.rate)),o={};for(let a of s)o[a.sectionId]=i>0?Math.sqrt(a.rate/i):0;this.renderer?.setSectionHeat(o)}renderSelectRail(){let e=this.opts.numberOfPlacesToSelect,t=this.selectionCap(),s=this.toolChooser();this.els.rail.innerHTML=`
|
|
535
758
|
${this.railHeader("Select","host","Pick seats for your own back-office operation \u2014 the selection is handed to your app. This tool is read-only inside the control room: it never books, releases or blocks seats by itself.")}
|
|
536
|
-
<
|
|
537
|
-
<p class="slm-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
</div>
|
|
542
|
-
${e.length?`<p class="slm-eyebrow" style="margin-top:8px">Select by category</p>
|
|
543
|
-
<div class="slm-chipgrid">${e.map(i=>`
|
|
544
|
-
<button class="slm-chip" type="button" data-select-cat="${p(i.key)}" aria-pressed="false">
|
|
545
|
-
<span class="dot" style="background:${p(i.color??"#6e7bff")}"></span>
|
|
546
|
-
<span>${p(i.label??i.key)}</span>
|
|
547
|
-
<span class="slm-chipcount" data-cat-count>0</span>
|
|
548
|
-
<span class="slm-chipcheck" aria-hidden="true">\u2713</span>
|
|
549
|
-
</button>`).join("")}</div>`:""}`,this.els.selectnum=this.els.rail.querySelector('[data-ref="selectnum"]'),this.els.selectmeta=this.els.rail.querySelector('[data-ref="selectmeta"]'),this.els.selectvalidity=this.els.rail.querySelector('[data-ref="selectvalidity"]'),this.els.selectclear=this.els.rail.querySelector('[data-ref="selectclear"]'),this.els.rail.querySelector('[data-ref="selectall"]')?.addEventListener("click",()=>this.selectAll()),this.els.selectclear.addEventListener("click",()=>this.clearSelection()),this.els.rail.querySelectorAll("[data-select-cat]").forEach(i=>{i.addEventListener("click",()=>{let a=i.dataset.selectCat,o=[...this.labelToSeat.values()].filter(r=>r.categoryKey===a&&this.canSelectObject(r)),l=new Set(this.selectionLabels());o.length>0&&o.every(r=>l.has(r.label))?this.deselectCategories([a]):this.selectCategories([a])})}),this.paintSelectSelection(this.getSelection())}paintSelectSelection(e){if(!this.els.selectnum||!this.els.selectmeta)return;let t=e.length;this.els.selectnum.textContent=t.toLocaleString(),this.els.selectmeta.textContent=t===1?"object selected":"objects selected",this.els.selectclear.disabled=t===0;let s=this.getSelectionValidity();this.els.selectvalidity&&(this.els.selectvalidity.textContent=s?s.isValid?`Ready \u2014 exactly ${s.required.toLocaleString()} selected.`:`Select ${s.remaining.toLocaleString()} more to continue.`:`${Math.max(0,this.selectionCap()-t).toLocaleString()} selections remaining.`);let i=new Set(e.map(a=>a.label));this.els.rail?.querySelectorAll("[data-select-cat]").forEach(a=>{let o=a.dataset.selectCat,l=[...this.labelToSeat.values()].filter(d=>d.categoryKey===o&&this.canSelectObject(d)),r=l.filter(d=>i.has(d.label)).length,c=l.length>0&&r===l.length;a.classList.toggle("on",c),a.setAttribute("aria-pressed",String(c));let n=a.querySelector("[data-cat-count]");n&&(n.textContent=r?`${r}/${l.length}`:l.length.toLocaleString()),a.disabled=l.length===0})}renderFilterSectionsRail(){let e=new Map;for(let t of this.filterableSections())e.set(t.label,[...e.get(t.label)??[],t]);this.els.rail.innerHTML=`
|
|
759
|
+
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
760
|
+
<p class="slm-selecthelp">Tap seats on the map, tap a row label for the whole row, press \u2318A for all, or pick a category, section or rows below.</p>
|
|
761
|
+
${s.chipsHtml()}
|
|
762
|
+
${this.toolSelectionBar("selectnum","selectmeta","selectclear","selectall")}
|
|
763
|
+
<p class="slm-note" data-ref="selectvalidity">${e?`Select exactly ${e.toLocaleString()} object${e===1?"":"s"}.`:`Up to ${t.toLocaleString()} objects may be selected.`}</p>`,this.els.selectnum=this.els.rail.querySelector('[data-ref="selectnum"]'),this.els.selectmeta=this.els.rail.querySelector('[data-ref="selectmeta"]'),this.els.selectvalidity=this.els.rail.querySelector('[data-ref="selectvalidity"]'),this.els.selectclear=this.els.rail.querySelector('[data-ref="selectclear"]'),this.els.rail.querySelector('[data-ref="selectall"]')?.addEventListener("click",()=>this.selectAll()),this.els.selectclear.addEventListener("click",()=>this.clearSelection()),s.wire(this.els.rail),this.paintSelectSelection(this.getSelection())}paintSelectSelection(e){if(!this.els.selectnum||!this.els.selectmeta)return;let t=e.length;this.els.selectnum.textContent=t.toLocaleString(),this.els.selectmeta.textContent=t===1?"object selected":"objects selected",this.els.selectclear.disabled=t===0;let s=this.getSelectionValidity();this.els.selectvalidity&&(this.els.selectvalidity.textContent=s?s.isValid?`Ready \u2014 exactly ${s.required.toLocaleString()} selected.`:`Select ${s.remaining.toLocaleString()} more to continue.`:`${Math.max(0,this.selectionCap()-t).toLocaleString()} selections remaining.`)}renderFilterSectionsRail(){let e=new Map;for(let t of this.filterableSections())e.set(t.label,[...e.get(t.label)??[],t]);this.els.rail.innerHTML=`
|
|
550
764
|
${this.railHeader("Filter sections","host","Narrow the map to one section for your own reporting. Sections sharing a label stay together and the map frames their combined inventory. Nothing changes for buyers.")}
|
|
551
|
-
${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let i=t===this.filteredSectionLabel,
|
|
552
|
-
<span class="slm-sectiontop"><span>${
|
|
765
|
+
${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let i=t===this.filteredSectionLabel,o=s.reduce((a,n)=>a+n.seatCount,0);return`<button type="button" class="slm-sectionrow${i?" on":""}" data-filter-section="${m(t)}" aria-pressed="${i}">
|
|
766
|
+
<span class="slm-sectiontop"><span>${m(t)}</span><span>${o.toLocaleString()}</span></span>
|
|
553
767
|
<span class="slm-sectionmeta"><span>${s.length===1?"One section":`${s.length.toLocaleString()} matching sections`}</span><span class="slm-sectionlocate">${i?"Filtered":"Filter"}</span></span>
|
|
554
768
|
</button>`}).join("")}</div>
|
|
555
|
-
<button type="button" class="slm-btn ghost" data-clear-filter ${this.filteredSectionLabel?"":"disabled"}>Clear filter</button>`:'<div class="slm-empty">This chart has no filterable sections.</div>'}`,this.els.rail.querySelectorAll("[data-filter-section]").forEach(t=>{t.addEventListener("click",()=>this.setFilteredSection(t.dataset.filterSection))}),this.els.rail.querySelector("[data-clear-filter]")?.addEventListener("click",()=>this.clearFilteredSection())}categorySeats(e){return[...this.labelToSeat.values()].filter(t=>t.categoryKey===e&&this.canSelectObject(t))}renderCategoriesRail(){let e=this.doc?.categories??[];this.els.rail.innerHTML=`
|
|
769
|
+
<button type="button" class="slm-btn ghost" data-clear-filter ${this.filteredSectionLabel?"":"disabled"}>Clear filter</button>`:'<div class="slm-empty">This chart has no filterable sections.</div>'}`,this.els.rail.querySelectorAll("[data-filter-section]").forEach(t=>{t.addEventListener("click",()=>this.setFilteredSection(t.dataset.filterSection))}),this.els.rail.querySelector("[data-clear-filter]")?.addEventListener("click",()=>this.clearFilteredSection())}categorySeats(e){return[...this.labelToSeat.values()].filter(t=>t.categoryKey===e&&this.canSelectObject(t))}renderCategoriesRail(){let e=this.doc?.categories??[],t=this.toolChooser();this.els.rail.innerHTML=`
|
|
556
770
|
${this.railHeader("Categories","event","Move seats to a different price category for this event only. The reusable chart keeps its design, and seats already held or booked keep the price they were sold at.")}
|
|
557
771
|
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
558
|
-
<p class="slm-selecthelp">Click
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
<span class="dot" style="background:${p(s.color??"#6e7bff")}"></span>
|
|
562
|
-
<span>${p(s.label??s.key)}</span>
|
|
563
|
-
<span class="slm-chipcount" data-cat-count>0</span>
|
|
564
|
-
<span class="slm-chipcheck" aria-hidden="true">\u2713</span>
|
|
565
|
-
</button>`).join(""):'<span class="slm-empty">This chart has no categories.</span>'}</div>
|
|
566
|
-
<div class="slm-selbar" aria-live="polite">
|
|
567
|
-
<span class="slm-selnum" data-ref="categorynum">0</span>
|
|
568
|
-
<span class="slm-sellabel" data-ref="categorymeta">selected</span>
|
|
569
|
-
</div>
|
|
570
|
-
<div class="slm-row">
|
|
571
|
-
<button class="slm-btn ghost" data-ref="categoryall">Select all</button>
|
|
572
|
-
<button class="slm-btn ghost" data-ref="categoryclear" disabled>Clear</button>
|
|
573
|
-
</div>
|
|
772
|
+
<p class="slm-selecthelp">Click seats, drag a box or draw a lasso on the map, tap a row label for the whole row, press \u2318A for all, or pick below.</p>
|
|
773
|
+
${t.chipsHtml({intents:this.marqueeShapeChipsHtml()})}
|
|
774
|
+
${this.toolSelectionBar("categorynum","categorymeta","categoryclear","categoryall")}
|
|
574
775
|
<p class="slm-eyebrow slm-step" style="margin-top:14px"><span class="slm-stepnum">2</span>Move them to</p>
|
|
575
776
|
<p class="slm-selecthelp" data-ref="categoryhelp">Select seats first \u2014 then pick the category they should sell under.</p>
|
|
576
|
-
<div class="slm-categoryassign">${e.map(
|
|
577
|
-
<button type="button" class="slm-categoryrow" data-assign-category="${
|
|
578
|
-
<span class="dot" style="background:${
|
|
579
|
-
<span class="slm-categorycopy"><b>${
|
|
777
|
+
<div class="slm-categoryassign">${e.length?e.map(i=>`
|
|
778
|
+
<button type="button" class="slm-categoryrow" data-assign-category="${m(i.key)}" disabled>
|
|
779
|
+
<span class="dot" style="background:${m(i.color??"#6e7bff")}"></span>
|
|
780
|
+
<span class="slm-categorycopy"><b>${m(i.label??i.key)}</b><small data-cat-current>0 seats now</small></span>
|
|
580
781
|
<span class="slm-categoryact" data-cat-action>Move here</span>
|
|
581
|
-
</button>`).join("")
|
|
782
|
+
</button>`).join(""):'<span class="slm-empty">This chart has no categories.</span>'}</div>
|
|
783
|
+
<div class="slm-catreset">
|
|
784
|
+
<button type="button" class="slm-btn ghost" data-ref="categoryreset" disabled>Reset to chart defaults</button>
|
|
785
|
+
<p class="slm-note" data-ref="categoryresetnote">Checking what differs from the chart\u2026</p>
|
|
786
|
+
</div>`;let s=i=>this.els.rail.querySelector(`[data-ref="${i}"]`);this.els.categorynum=s("categorynum"),this.els.categorymeta=s("categorymeta"),this.els.categoryhelp=s("categoryhelp"),this.els.categoryclear=s("categoryclear"),s("categoryall").addEventListener("click",()=>this.selectAll()),this.els.categoryclear.addEventListener("click",()=>this.clearSelection()),this.els.rail.querySelectorAll("[data-assign-category]").forEach(i=>{i.addEventListener("click",()=>{this.setCategory(i.dataset.assignCategory)})}),s("categoryreset").addEventListener("click",()=>{this.resetCategoriesToChart()}),t.wire(this.els.rail),this.wireMarqueeShapeChips(),this.paintCategorySelection(this.getSelection()),this.loadCategoryDifferences()}async loadCategoryDifferences(){let e=this.els.rail;if(!e||this.closed)return;let t=e.querySelector('[data-ref="categoryreset"]'),s=e.querySelector('[data-ref="categoryresetnote"]');if(!(!t||!s))try{let i=await this.withAuthRetry(()=>this.api.categoryDifferences(this.key));if(!t.isConnected)return;this.categoryDifferences=i.differing,this.paintCategoryReset()}catch(i){if(!t.isConnected)return;s.textContent="Could not check the chart\u2019s defaults. Reset is unavailable until it can.",this.opts.onError?.(i)}}paintCategoryReset(){let e=this.els.rail;if(!e)return;let t=e.querySelector('[data-ref="categoryreset"]'),s=e.querySelector('[data-ref="categoryresetnote"]');if(!t||!s)return;let i=this.categoryDifferences;i!=null&&(t.disabled=i===0,t.textContent=i?`Reset to chart defaults \xB7 ${i.toLocaleString()} seat${i===1?"":"s"}`:"Reset to chart defaults",s.textContent=i?"Puts every seat this event moved back in its chart category. Held and booked seats keep the price they were sold at.":"Every seat sells under its chart category.")}async resetCategoriesToChart(){let e=this.els.rail.querySelector('[data-ref="categoryreset"]');e&&(e.disabled=!0,e.textContent="Resetting\u2026");try{let t=await this.withAuthRetry(()=>this.api.resetCategoriesToChart(this.key));t.changed&&await this.reloadEventChart(),this.categoryDifferences=0,this.clearSelection(),this.mode==="categories"&&this.paintRail(),this.paintCategoryReset(),this.done("resetCategories",t.labels,t.changed?`Put ${t.labels.length.toLocaleString()} seat${t.labels.length===1?"":"s"} back on the chart\u2019s categories.`:"Every seat already sells under its chart category.")}catch(t){this.paintCategoryReset(),this.toastErr("Couldn\u2019t reset those categories. Nothing changed."),this.opts.onError?.(t)}}paintCategorySelection(e){if(!this.els.categorynum)return;let t=e.length;this.els.categorynum.textContent=t.toLocaleString(),this.els.categoryclear.disabled=t===0;let s=new Map;for(let o of e)s.set(o.categoryKey,(s.get(o.categoryKey)??0)+1);let i=o=>this.doc?.categories.find(a=>a.key===o)?.label??o;this.els.categorymeta&&(this.els.categorymeta.textContent=t===0?"selected":`${t===1?"seat":"seats"} selected \xB7 ${[...s].map(([o,a])=>`${a.toLocaleString()} ${i(o)}`).join(", ")}`),this.els.categoryhelp&&(this.els.categoryhelp.textContent=t===0?"Select seats first \u2014 then pick the category they should sell under.":`Choose the category the ${t===1?"selected seat":`${t.toLocaleString()} selected seats`} should sell under. Applies immediately.`),this.els.rail?.querySelectorAll("[data-assign-category]").forEach(o=>{let a=o.dataset.assignCategory,n=[...this.labelToSeat.values()].filter(p=>p.categoryKey===a).length,c=s.get(a)??0,d=t>0&&c===t;o.disabled=t===0||d,o.classList.toggle("current",d);let r=o.querySelector("[data-cat-current]");r&&(r.textContent=`${n.toLocaleString()} ${n===1?"seat":"seats"} now`);let h=o.querySelector("[data-cat-action]");h&&(h.textContent=t===0?"Move here":d?"Already here":`Move ${(t-c).toLocaleString()} here`)})}renderTablesRail(){let e=this.tables(),t="Decide how each table sells for this event: every chair on its own, or the whole table as one booking. A table with held, booked, or blocked chairs is locked until that inventory is released, and channel allocations are kept.";if(this.inventoryModelVersion!==2){this.els.rail.innerHTML=`
|
|
582
787
|
${this.railHeader("Tables","event",t)}
|
|
583
788
|
<div class="slm-empty">This event still uses the older inventory model, which cannot switch tables between per-chair and whole-table selling. Upgrade the event's inventory model to unlock this tool.</div>`;return}if(!e.length){this.els.rail.innerHTML=`
|
|
584
789
|
${this.railHeader("Tables","event",t)}
|
|
585
|
-
<div class="slm-empty">This chart has no tables. Add tables in the designer and they will appear here.</div>`;return}let s=
|
|
790
|
+
<div class="slm-empty">This chart has no tables. Add tables in the designer and they will appear here.</div>`;return}let s=h=>h.variableOccupancy?"variable":h.bookAsWhole?"whole":"individual",i=h=>{let p=0,u=0,g=0;for(let[b,y]of this.labelToSeat){if(y.rowId!==h.id)continue;let z=this.status.get(b);z==="held"?p++:z==="booked"?u++:z==="blocked"&&g++}let f=[u&&`${u} booked`,p&&`${p} held`,g&&`${g} blocked`].filter(Boolean);return f.length?f.join(" \xB7 "):null},o=e.map(h=>({table:h,current:s(h),locked:i(h)})),a=o.filter(h=>h.current==="individual").length,n=o.filter(h=>h.current==="whole").length,c=o.length-a-n,d=[`${a.toLocaleString()} per chair`,`${n.toLocaleString()} whole table`,c?`${c.toLocaleString()} flexible group`:""].filter(Boolean).join(" \xB7 "),r=this.tableBookingSaving;this.els.rail.innerHTML=`
|
|
586
791
|
${this.railHeader("Tables","event",t)}
|
|
587
|
-
<div class="slm-tablesummary"><b>${
|
|
792
|
+
<div class="slm-tablesummary"><b>${o.length.toLocaleString()} ${o.length===1?"table":"tables"}</b><span>${m(d)}</span></div>
|
|
588
793
|
<p class="slm-eyebrow" style="margin-top:12px">Set every table at once</p>
|
|
589
794
|
<div class="slm-row">
|
|
590
|
-
<button class="slm-btn ghost" data-table-all="individual"${
|
|
591
|
-
<button class="slm-btn ghost" data-table-all="whole"${
|
|
795
|
+
<button class="slm-btn ghost" data-table-all="individual"${r?" disabled":""} title="Sell every chair on its own">All per chair</button>
|
|
796
|
+
<button class="slm-btn ghost" data-table-all="whole"${r?" disabled":""} title="Sell every table as one booking">All whole table</button>
|
|
592
797
|
</div>
|
|
593
798
|
<p class="slm-eyebrow" style="margin-top:12px">Or one table at a time</p>
|
|
594
|
-
<div class="slm-tablelist">${
|
|
595
|
-
<span class="slm-tablecopy"><b>${
|
|
596
|
-
<select class="slm-select" data-table-mode="${
|
|
597
|
-
${
|
|
598
|
-
<option value="individual"${
|
|
599
|
-
<option value="whole"${
|
|
600
|
-
${
|
|
799
|
+
<div class="slm-tablelist">${o.map(({table:h,current:p,locked:u})=>`<div class="slm-tablerow${u?" locked":""}">
|
|
800
|
+
<span class="slm-tablecopy"><b>${m(h.displayLabel??h.label)}</b><small>${h.seatCount.toLocaleString()} chairs${u?` \xB7 <span class="slm-tablelock">Locked: ${m(u)}</span>`:""}</small></span>
|
|
801
|
+
<select class="slm-select" data-table-mode="${m(h.id)}" aria-label="Booking mode for ${m(h.displayLabel??h.label)}"
|
|
802
|
+
${r||u?"disabled":""} ${u?`title="Release the ${m(u)} chairs before changing how this table sells"`:""}>
|
|
803
|
+
<option value="individual"${p==="individual"?" selected":""}>Per chair</option>
|
|
804
|
+
<option value="whole"${p==="whole"?" selected":""}>Whole table</option>
|
|
805
|
+
${p==="variable"?'<option value="variable" selected>Flexible group</option>':""}
|
|
601
806
|
</select>
|
|
602
807
|
</div>`).join("")}</div>
|
|
603
|
-
<p class="slm-note">Changes apply immediately to this event. Flexible group sizes (minimum and maximum guests) are set through the API, never guessed here.</p>`,this.els.rail.querySelectorAll("[data-table-all]").forEach(
|
|
808
|
+
<p class="slm-note">Changes apply immediately to this event. Flexible group sizes (minimum and maximum guests) are set through the API, never guessed here.</p>`,this.els.rail.querySelectorAll("[data-table-all]").forEach(h=>{h.addEventListener("click",()=>{this.setTableBooking(o.filter(p=>!p.locked).map(p=>p.table.id),h.dataset.tableAll)})}),this.els.rail.querySelectorAll("[data-table-mode]").forEach(h=>{h.addEventListener("change",()=>{this.setTableBooking([h.dataset.tableMode],h.value)})})}renderInspectRail(e){let t=e[e.length-1];if(!t){this.els.rail.innerHTML=`
|
|
604
809
|
${this.railHeader("Inspect","read","Click one seat on the map to read its live status, category, section and booking context. Nothing changes in this view.")}
|
|
605
|
-
<div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",i={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},
|
|
606
|
-
<div class="slm-seat-heading"><h2>${
|
|
607
|
-
<p class="slm-note">${
|
|
608
|
-
<div data-ref="seat-history"></div>`;let
|
|
810
|
+
<div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",i={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},o=this.sectionByObject.get(t.rowId)??v,a=this.sectionLabelById.get(o)??"Other seats",n=this.doc?.categories.find(d=>d.key===t.categoryKey);this.els.rail.innerHTML=`
|
|
811
|
+
<div class="slm-seat-heading"><h2>${m(t.label)}</h2><span data-seat-status>${i[s]}</span></div>
|
|
812
|
+
<p class="slm-note">${m(a)} \xB7 ${m(n?.label??t.categoryKey)}</p>
|
|
813
|
+
<div data-ref="seat-history"></div>`;let c=this.els.rail.querySelector('[data-ref="seat-history"]');this.seatHistoryPanel=new T(c,(d,r)=>this.withAuthRetry(()=>this.api.seatHistory(this.key,t.label,d,r)))}async refreshAvailability(){try{let e=await this.withAuthRetry(()=>this.api.availability(this.key));this.availabilityRules=e.rules??{},this.effectiveClosed=new Set(V(this.availabilityRules)),this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment()}catch(e){this.opts.onError?.(e)}}async withAuthRetry(e){try{return await e()}catch(t){if(t instanceof w&&t.status===401&&this.opts.onTokenRefresh&&!this.tokenRefreshInFlight){if(await this.rotateToken(),this.sessionEnded)throw t;return e()}throw t instanceof w&&t.status===401&&!this.opts.onTokenRefresh&&this.endSession(),t}}updateEffectiveAvailability(e,t){let s=!1;Array.isArray(e)&&(this.effectiveHidden=new Set(e.filter(i=>typeof i=="string")),s=!0),Array.isArray(t)&&(this.effectiveClosed=new Set(t.filter(i=>typeof i=="string")),s=!0),s&&(this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment())}applySectionCanvasTreatment(){this.renderer&&(this.renderer.refreshBlockPaint?.(),this.mode==="sections"?(this.renderer.setDimmedSections([...this.effectiveHidden]),this.renderer.setClosedSections([...this.effectiveClosed])):this.mode==="filterSections"&&this.filteredSectionLabel?this.applyFilteredSectionCanvas():(this.renderer.setDimmedSections(null),this.renderer.setClosedSections(null)))}sectionRowsInput(){return{sectionsBase:this.sectionsBase,doc:this.doc,availabilityRules:this.availabilityRules,effectiveHidden:this.effectiveHidden,effectiveClosed:this.effectiveClosed}}renderSectionsRail(){let{rows:e,hiddenSections:t,closedSections:s}=$(this.sectionRowsInput());if(!e.length){this.els.rail.innerHTML=`
|
|
609
814
|
${this.railHeader("Sections","event","Draw sections or zones in the designer to schedule availability per area. This chart has none yet.")}
|
|
610
|
-
<div class="slm-empty">No sections on this chart.</div>`;return}let i=[];t&&i.push(`${t} hidden`),s&&i.push(`${s} closed`);let
|
|
815
|
+
<div class="slm-empty">No sections on this chart.</div>`;return}let i=[];t&&i.push(`${t} hidden`),s&&i.push(`${s} closed`);let o=i.length?i.join(" \xB7 "):"All sections open and on sale",a=t>0||s>0;this.els.rail.innerHTML=`
|
|
611
816
|
${this.railHeader("Sections","event","Decide when each zone or section goes on sale for this event. Keep it hidden, reveal it at a set time, or <b>auto-reveal once the rest sells past a threshold</b>. Hidden seats vanish for buyers; closed seats stay on the map (flat grey) but can't be bought.")}
|
|
612
|
-
<div class="slm-availlist" data-ref="availlist">${e.map(
|
|
817
|
+
<div class="slm-availlist" data-ref="availlist">${e.map(n=>Le(n,this.availabilitySaving)).join("")}</div>
|
|
613
818
|
<div class="slm-availsummary">
|
|
614
|
-
<span class="slm-availdot${
|
|
615
|
-
<span>${
|
|
819
|
+
<span class="slm-availdot${a?" warn":""}"></span>
|
|
820
|
+
<span>${m(o)}</span>
|
|
616
821
|
</div>
|
|
617
822
|
<div class="slm-availcallout">
|
|
618
823
|
<span class="slm-availstar" aria-hidden="true">\u2726</span>
|
|
619
824
|
<p><b>Auto-reveal at % sold</b> is demand-triggered release: the balcony opens itself the moment the stalls cross the threshold \u2014 no one has to be watching.</p>
|
|
620
|
-
</div>`,this.wireSectionRail(),this.applySectionCanvasTreatment()}wireSectionRail(){let e=this.els.rail;e&&(e.querySelectorAll("[data-avail-id]").forEach(t=>{t.addEventListener("click",()=>this.setSectionMode(t.dataset.availId,t.dataset.availValue))}),e.querySelectorAll("[data-avail-picker]").forEach(t=>{t.querySelector("summary").addEventListener("click",s=>{this.availabilitySaving&&s.preventDefault(),e.querySelectorAll("[data-avail-picker]").forEach(i=>{i!==t&&(i.open=!1)})}),t.addEventListener("focusout",s=>{t.contains(s.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",s=>{if(s.key==="Escape"&&(t.open=!1,t.querySelector("summary").focus(),s.preventDefault()),s.key==="ArrowDown"||s.key==="ArrowUp"){if(this.availabilitySaving)return;s.preventDefault(),t.open=!0;let i=[...t.querySelectorAll("button")],
|
|
621
|
-
<span class="slm-leglabel">${t.label}</span><span class="slm-legcount">${e[t.key].toLocaleString()}</span></div>`).join(""))}paintFeed(){this.activityPanel?.update(this.feed)}renderBlockRail(){let
|
|
622
|
-
<span class="dot" style="background:${p(n.color??"#6e7bff")}"></span>
|
|
623
|
-
<span>${p(n.label??n.key)}</span>
|
|
624
|
-
<span class="slm-chipcount" data-cat-count>0</span>
|
|
625
|
-
<span class="slm-chipcheck" aria-hidden="true">\u2713</span>
|
|
626
|
-
</button>`).join(""),s=this.sectionOptions.length?`<div class="slm-field"><label>Select a whole section</label>
|
|
627
|
-
<select class="slm-select" data-ref="section"><option value="">Choose a section\u2026</option>
|
|
628
|
-
${this.sectionOptions.map(n=>`<option value="${p(n.id)}">${p(n.label)}</option>`).join("")}</select></div>`:"",i=this.sectionOptions.map(n=>`<option value="${p(n.id)}">${p(n.label)}</option>`).join("");this.els.rail.innerHTML=`
|
|
825
|
+
</div>`,this.wireSectionRail(),this.applySectionCanvasTreatment()}wireSectionRail(){let e=this.els.rail;e&&(e.querySelectorAll("[data-avail-id]").forEach(t=>{t.addEventListener("click",()=>this.setSectionMode(t.dataset.availId,t.dataset.availValue))}),e.querySelectorAll("[data-avail-picker]").forEach(t=>{t.querySelector("summary").addEventListener("click",s=>{this.availabilitySaving&&s.preventDefault(),e.querySelectorAll("[data-avail-picker]").forEach(i=>{i!==t&&(i.open=!1)})}),t.addEventListener("focusout",s=>{t.contains(s.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",s=>{if(s.key==="Escape"&&(t.open=!1,t.querySelector("summary").focus(),s.preventDefault()),s.key==="ArrowDown"||s.key==="ArrowUp"){if(this.availabilitySaving)return;s.preventDefault(),t.open=!0;let i=[...t.querySelectorAll("button")],o=i.indexOf(document.activeElement);i[(o+(s.key==="ArrowDown"?1:i.length-1)+i.length)%i.length]?.focus()}})}),e.querySelectorAll("[data-avail-reveal]").forEach(t=>{t.addEventListener("change",()=>{let s=new Date(t.value).getTime();Number.isFinite(s)&&this.setSectionRulePatch(t.dataset.availReveal,{revealAt:s})})}),e.querySelectorAll("[data-avail-pct]").forEach(t=>{t.addEventListener("change",()=>{let s=Math.max(1,Math.min(100,Number(t.value)||0));this.setSectionRulePatch(t.dataset.availPct,{thresholdPct:s})})}))}setSectionMode(e,t){let s=$(this.sectionRowsInput()).rows.find(n=>n.id===e),i=s?.seatLabels??this.availabilityRules[e]?.labels??[],o={...this.availabilityRules},a=U(t,i,this.availabilityRules[e]);if(a?o[e]=a:delete o[e],s?.kind==="zone"&&this.sectionsBase)for(let n of this.sectionsBase.sections)n.zone===e&&delete o[n.id];this.persistAvailability(o)}setSectionRulePatch(e,t){let s=this.availabilityRules[e];if(!s)return;let o=$(this.sectionRowsInput()).rows.find(a=>a.id===e)?.seatLabels??s.labels??[];this.persistAvailability({...this.availabilityRules,[e]:{...s,...t,labels:o}})}async persistAvailability(e){let t=this.availabilityRules;this.availabilityRules=e,this.availabilitySaving=!0,this.mode==="sections"&&this.renderSectionsRail();try{let s=await this.withAuthRetry(()=>this.api.setAvailability(this.key,e));this.availabilityRules=s.rules,this.effectiveHidden=new Set(s.hidden),this.effectiveClosed=new Set(V(s.rules)),this.availabilitySaving=!1,this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment()}catch(s){this.availabilityRules=t,this.availabilitySaving=!1,this.mode==="sections"&&this.renderSectionsRail(),this.toastErr("Couldn't update availability. Try again."),this.opts.onError?.(s)}}paintLegend(e){this.els.legend&&(this.els.legend.innerHTML=Y.map(t=>`<div class="slm-legrow"><span class="slm-legdot" style="background:${t.color}"></span>
|
|
826
|
+
<span class="slm-leglabel">${t.label}</span><span class="slm-legcount">${e[t.key].toLocaleString()}</span></div>`).join(""))}paintFeed(){this.activityPanel?.update(this.feed)}renderBlockRail(){let e=this.toolChooser(),t=this.sectionOptions.map(n=>`<option value="${m(n.id)}">${m(n.label)}</option>`).join("");this.els.rail.innerHTML=`
|
|
629
827
|
<div class="slm-monitor-tabs" role="tablist" aria-label="Blocking tools"><button role="tab" data-block-tab="edit" aria-selected="${!this.blockBrowse}">Block seats</button><button role="tab" data-block-tab="browse" aria-selected="${this.blockBrowse}">Find blocked</button></div>
|
|
630
|
-
<p class="slm-note">${
|
|
631
|
-
<div
|
|
828
|
+
<p class="slm-note">${Z}</p>
|
|
829
|
+
<div data-block-editor ${this.blockBrowse?"hidden":""}>
|
|
830
|
+
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
831
|
+
<p class="slm-selecthelp">Zoom into a section, then drag a box or draw a lasso on the map, tap a row label for the whole row, press \u2318A for all of it, or pick below.</p>
|
|
832
|
+
${e.chipsHtml({intents:this.marqueeShapeChipsHtml()})}
|
|
833
|
+
</div>
|
|
834
|
+
${this.toolSelectionBar("selnum","selmeta","clearsel","selall")}
|
|
835
|
+
<p class="slm-eyebrow slm-step" data-block-editor-step ${this.blockBrowse?"hidden":""}><span class="slm-stepnum">2</span>Then</p>
|
|
632
836
|
<div class="slm-row">
|
|
633
837
|
<button class="slm-btn" data-ref="doblock" disabled>Block</button>
|
|
634
838
|
<button class="slm-btn ghost" data-ref="dounblock" disabled>Put back on sale</button>
|
|
635
839
|
</div>
|
|
636
840
|
<div data-block-editor ${this.blockBrowse?"hidden":""}>
|
|
637
|
-
<div class="slm-row">
|
|
638
|
-
<button class="slm-btn ghost" data-ref="selall">Select all</button>
|
|
639
|
-
<button class="slm-btn ghost" data-ref="clearsel">Clear</button>
|
|
640
|
-
</div>
|
|
641
|
-
<p class="slm-eyebrow" style="margin-top:8px">Select by category</p>
|
|
642
|
-
<p class="slm-selecthelp">Choose one or more. A checked category is selected; click it again to remove it.</p>
|
|
643
|
-
<div class="slm-chiprow">${t||'<span class="slm-empty">No categories.</span>'}</div>
|
|
644
|
-
${s}
|
|
645
841
|
<div class="slm-field">
|
|
646
842
|
<label>Auto-release blocks at (optional)</label>
|
|
647
843
|
<input type="datetime-local" class="slm-input" data-ref="release" />
|
|
@@ -657,7 +853,7 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
657
853
|
<div class="slm-blockedtools">
|
|
658
854
|
<input type="search" class="slm-input" data-ref="blockedsearch" placeholder="Find seat, row or category" aria-label="Search blocked seats" />
|
|
659
855
|
<select class="slm-select" data-ref="blockedsection" aria-label="Filter blocked seats by section">
|
|
660
|
-
<option value="">All sections</option>${
|
|
856
|
+
<option value="">All sections</option>${t}
|
|
661
857
|
</select>
|
|
662
858
|
</div>
|
|
663
859
|
<div class="slm-blockedsummary">
|
|
@@ -670,5 +866,5 @@ import{c as H,d as B,f as j}from"./chunk-RZ2VKZ44.js";import{A as Re,B as Ae,D a
|
|
|
670
866
|
<button class="slm-btn ghost" data-ref="markall" style="width:100%" disabled>Put all blocked seats on sale</button>
|
|
671
867
|
<p class="slm-note slm-allnote" data-ref="markallnote">For a full reset only. You will be asked to confirm.</p>
|
|
672
868
|
</div></details>
|
|
673
|
-
`,this.els.rail.querySelectorAll("[data-block-tab]").forEach(n=>n.addEventListener("click",()=>{this.blockBrowse=n.dataset.blockTab==="browse",this.renderBlockRail()}));let
|
|
674
|
-
<details><summary>Choose seats</summary>${
|
|
869
|
+
`,this.els.rail.querySelectorAll("[data-block-tab]").forEach(n=>n.addEventListener("click",()=>{this.blockBrowse=n.dataset.blockTab==="browse",this.renderBlockRail()}));let s=n=>this.els.rail.querySelector(`[data-ref="${n}"]`);this.els.selnum=s("selnum"),this.els.doblock=s("doblock"),this.els.dounblock=s("dounblock"),this.els.selmeta=s("selmeta"),this.els.blockedcount=s("blockedcount"),this.els.blockedshowing=s("blockedshowing"),this.els.blockedlist=s("blockedlist"),this.els.selblocked=s("selblocked"),this.els.markall=s("markall"),this.els.markallnote=s("markallnote"),s("doblock").addEventListener("click",()=>{this.block()}),s("dounblock").addEventListener("click",()=>{this.unblock()}),s("selall").addEventListener("click",()=>this.selectAll()),s("clearsel").addEventListener("click",()=>this.clearSelection()),s("markall").addEventListener("click",()=>this.confirmUnblockAll()),e.wire(this.els.rail),this.wireMarqueeShapeChips();let i=s("blockedsearch"),o=s("blockedsection");i.value=this.blockedQuery,o.value=this.blockedSection,i.addEventListener("input",()=>{this.blockedQuery=i.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),o.addEventListener("change",()=>{this.blockedSection=o.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),s("selblocked").addEventListener("click",()=>{this.toggleLabels(this.filteredBlockedSeats().map(n=>n.label))}),s("blockedlist").addEventListener("click",n=>{let c=n.target,d=c.closest("[data-block-seat-find]");if(d?.dataset.blockSeatFind){let u=this.labelToSeat.get(d.dataset.blockSeatFind);u&&(this.setFollowLive(!1),this.focusActivitySeats([u.label],this.sectionByObject.get(u.rowId)??v));return}let r=c.closest("[data-block-locate]"),h=c.closest("[data-block-group]");if(r||h){let u=r?.dataset.blockLocate??h?.dataset.blockGroup,g=this.filteredBlockedSeats().filter(f=>f.rowId===u);r&&g.length&&(this.setFollowLive(!1),this.focusActivitySeats(g.map(f=>f.label),this.sectionByObject.get(g[0].rowId)??v)),h&&this.toggleLabels(g.map(f=>f.label));return}let p=c.closest("[data-blocked-label]");p?.dataset.blockedLabel?this.toggleLabels([p.dataset.blockedLabel]):c.closest("[data-blocked-more]")&&(this.blockedResultLimit+=100,this.paintBlockedInventory())});let a=s("release");a.addEventListener("change",()=>{let n=a.value?new Date(a.value).getTime():NaN;this.releaseAt=Number.isFinite(n)&&n>Date.now()?n:null;let c=s("releasenote");c.textContent=this.releaseAt?`New blocks auto-release ${new Date(this.releaseAt).toLocaleString()}.`:a.value?"Pick a time in the future.":"Leave empty to block permanently."}),this.paintSelBar(this.getSelection())}toggleLabels(e){if(!this.renderer)return;let t=e.filter(o=>this.labelToSeat.has(o)&&this.isBlockSelectable(o));if(!t.length)return;let s=new Set(this.selectionLabels());if(t.every(o=>s.has(o))){let o=t.map(a=>this.labelToId.get(a)).filter(a=>!!a);this.renderer.deselect(o)}else this.renderer.selectByLabels(t);this.syncSelection()}isBlockSelectable(e){let t=this.status.get(e)??"free";return t==="free"||t==="blocked"}paintSelBar(e){if(!this.els.selnum)return;this.els.selnum.textContent=e.length.toLocaleString();let t=e.filter(a=>(this.status.get(a.label)??"free")==="free").length,s=e.filter(a=>this.status.get(a.label)==="blocked").length;this.els.selmeta.textContent=e.length?`${t.toLocaleString()} available \xB7 ${s.toLocaleString()} blocked`:"selected";let i=this.els.doblock,o=this.els.dounblock;i.disabled=t===0,o.disabled=s===0,i.textContent=t?`Block ${t.toLocaleString()}`:"Block selected",o.textContent=s?`Put ${s.toLocaleString()} on sale`:"Put back on sale",this.paintBlockedInventory()}filteredBlockedSeats(){let e=this.blockedQuery.trim().toLocaleLowerCase(),t=[];for(let[s,i]of this.labelToSeat.entries()){if(this.status.get(s)!=="blocked")continue;let o=this.sectionByObject.get(i.rowId)??v;if(!(this.blockedSection&&o!==this.blockedSection)){if(e){let a=this.doc?.categories.find(h=>h.key===i.categoryKey)?.label??i.categoryKey,n=this.sectionLabelById.get(o)??"Other seats",c=this.doc?.objects.find(h=>h.id===i.rowId),d=c?.type==="row"||c?.type==="table"?c.label:"";if(!`${s} ${a} ${n} ${d}`.toLocaleLowerCase().includes(e))continue}t.push(i)}}return t.sort((s,i)=>s.label.localeCompare(i.label,void 0,{numeric:!0,sensitivity:"base"}))}paintBlockedInventory(){if(!this.els.blockedlist)return;let e=[...this.status.entries()].filter(([,h])=>h==="blocked").length,t=this.filteredBlockedSeats(),s=t.slice(0,this.blockedResultLimit),i=new Set(this.selectionLabels()),o=t.filter(h=>i.has(h.label)).length,a=t.length>0&&o===t.length;this.els.blockedcount.textContent=e.toLocaleString(),this.els.blockedshowing.textContent=t.length?`Showing ${s.length.toLocaleString()} of ${t.length.toLocaleString()}`:e?"No matches":"No blocked seats";let n=this.els.selblocked;n.disabled=t.length===0,n.textContent=a?`Remove ${t.length.toLocaleString()} results`:`Select ${t.length.toLocaleString()} results`;let c=new Map;for(let h of t){let p=c.get(h.rowId)??[];p.push(h),c.set(h.rowId,p)}this.els.blockedshowing.textContent=`${t.length.toLocaleString()} seats \xB7 ${c.size} rows`,this.els.blockedlist.innerHTML=[...c.entries()].slice(0,this.blockedResultLimit).map(([h,p])=>{let u=this.sectionByObject.get(h)??v,g=this.sectionLabelById.get(u)??"Other seats",f=this.doc?.objects.find(y=>y.id===h),b=f&&"label"in f?f.label:p[0].label;return`<div class="slm-block-group"><div class="slm-block-grouphead"><button type="button" data-block-locate="${m(h)}" title="Show this row and nearby seats on the map"><b>${m(b)}</b><small>${m(g)} \xB7 ${p.length} blocked</small></button><button type="button" data-block-group="${m(h)}">Select row</button></div>
|
|
870
|
+
<details><summary>Choose seats</summary>${p.map(y=>`<div class="slm-block-seatline"><button type="button" class="slm-blockeditem${i.has(y.label)?" on":""}" data-blocked-label="${m(y.label)}" aria-pressed="${i.has(y.label)}"><span class="slm-blockedcheck" aria-hidden="true">\u2713</span><span>${m(y.label)}</span></button><button type="button" data-block-seat-find="${m(y.label)}" aria-label="Show ${m(y.label)} and nearby seats">Show</button></div>`).join("")}</details></div>`}).join("")||'<div class="slm-blockedempty">No blocked seats match.</div>',c.size>this.blockedResultLimit&&(this.els.blockedlist.innerHTML+="<button data-blocked-more>Show more rows</button>");let d=this.els.markall,r=d.dataset.confirm==="true";d.disabled=e===0,d.textContent=r?`Confirm: put all ${e.toLocaleString()} on sale`:`Put all ${e.toLocaleString()} blocked seats on sale`}confirmUnblockAll(){let e=this.els.markall;if(!(!e||e.disabled)){if(e.dataset.confirm==="true"){this.resetUnblockAllConfirm(),this.unblockAll();return}e.dataset.confirm="true",e.classList.add("danger"),this.els.markallnote.textContent="This changes every blocked seat. Click the red button again to confirm.",this.paintBlockedInventory(),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.unblockAllConfirmTimer=setTimeout(()=>this.resetUnblockAllConfirm(),6e3)}}resetUnblockAllConfirm(){this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.unblockAllConfirmTimer=null;let e=this.els.markall;e&&(delete e.dataset.confirm,e.classList.remove("danger"),this.els.markallnote&&(this.els.markallnote.textContent="For a full reset only. You will be asked to confirm."),this.paintBlockedInventory())}done(e,t,s){if(this.toastOk(s),t.length){let i=e==="block"?this.pushActivity(t,"blocked","blocked"):e==="unblock"||e==="unblockAll"?this.pushActivity(t,"unblocked","free"):e==="cancelBooking"?this.pushActivity(t,"cancelled","free"):null;i&&this.paintSpatialActivity(i)}e!=="setHoldTtl"&&this.refreshControlRoom().catch(i=>this.opts.onError?.(i)),this.opts.onActionComplete?.({action:e,labels:t,count:t.length})}toastOk(e){this.toast(e,"ok")}toastErr(e){this.toast(e,"err")}toast(e,t){let s=this.els.toast;s&&(s.textContent=e,s.className=`slm-toast on ${t}`,this.toastTimer&&clearTimeout(this.toastTimer),this.toastTimer=setTimeout(()=>{s.className="slm-toast"},3200))}fail(e){this.opts.onError?.(e),this.els.rail&&(this.els.rail.innerHTML=`<div class="slm-empty">Couldn't load this event. Check the event key and token.</div>`)}};export{Ue as ACCESS_LINK_DEFAULTS,et as ChannelsMode,I as ManageApi,w as ManageApiError,Re as PUBLIC_CHANNEL_ID,Ae as PUBLIC_CHANNEL_NAME,P as SeatManager,Ne as accessIntentDescription,qe as accessIntentLabel,je as accessLine,We as accessLinkBadge,Ye as accessLinkErrorCopy,Ge as accessLinkIsLive,Ze as accessLinkPolicyLines,Ve as bucketRows,Je as bucketRowsHtml,Xe as dropReviewRows,_e as intentForbidsCopy,Ke as intentSwitchBlockedCopy,$e as isPublicChannelId,He as markerLetter,Be as markerOf,Oe as mutationCount,De as needsMoveConfirmation,Fe as planAssignment,Pe as retryAfterCopy,Ie as selectionSources,Qe as stateBadge,ze as suggestMarker};
|