@seatlayer/js 0.94.0 → 0.95.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 +9 -0
- package/dist/{channelsMode-DYwJ6sfR.d.cts → channelsMode-7x0h8OuH.d.cts} +88 -3
- package/dist/{channelsMode-DYwJ6sfR.d.ts → channelsMode-7x0h8OuH.d.ts} +88 -3
- package/dist/index.cjs +18 -18
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +17 -17
- package/dist/manager.cjs +114 -88
- package/dist/manager.d.cts +2 -2
- package/dist/manager.d.ts +2 -2
- package/dist/manager.js +87 -61
- package/package.json +2 -2
package/dist/manager.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import{s as
|
|
1
|
+
import{s as _,t as K}from"./chunk-JELR6YYZ.js";import{A as Ve,B as Pe,C as je,D as qe,E as Ne,F as _e,G as Ke,H as Ue,I as We,J as Ge,K as Ze,L as Ye,M as Xe,N as Qe,O as Je,P as et,Q as tt,R as st,S as it,T as ot,V as at,a as L,b as U,c as k,d as F,e as W,f as G,g as Z,h as Y,i as O,j as M,k as x,l as X,m as Q,n as J,o as ee,p as te,q as T,r as m,s as D,t as se,u as V,v as ze,w as Ie,x as Fe,y as Oe,z as De}from"./chunk-DR5JXWLO.js";import{d as I,f as N}from"./chunk-RZ2VKZ44.js";import"./chunk-OSZ7DOEH.js";var ie={hold:"Held",release:"Released",expire:"Expired",book:"Booked",unbook:"Cancelled",block:"Blocked",unblock:"Unblocked"},C=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(l=>l.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?`${ie[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=ie[t.action]??t.action,s.append(i,o),s})),this.list.scrollTop=e}};var lt={held:"HOLD",booked:"BOOK",expired:"EXPIRE",released:"RELEASE",cancelled:"CANCEL",blocked:"BLOCK",unblocked:"ON SALE",available:"FREE"},oe={held:"Held",booked:"Booked",expired:"Hold expired",released:"Hold released",cancelled:"Booking cancelled",blocked:"Blocked",unblocked:"Back on sale",available:"Available again"},E=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 l=document.createElement("article");l.className="slm-activity-entry",l.dataset.status=a.status;let r=document.createElement("button");r.type="button",r.className="slm-activity-row";let c=`${oe[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()}`;r.title=`${c} \u2014 click to show seats on the map`,r.setAttribute("aria-label",`Show seats on map: ${c}`),r.addEventListener("click",()=>this.locate(a.id));let d=document.createElement("time");d.dateTime=new Date(a.at).toISOString(),d.textContent=new Date(a.at).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});let h=document.createElement("strong");h.textContent=lt[a.verb]??a.verb,h.title=oe[a.verb]??a.verb;let p=document.createElement("span");if(p.className="slm-activity-seats",p.textContent=a.labels.join(", "),r.append(d,h,p),l.append(r),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=c,u.append(g,f),l.append(u)}this.list.append(l)}this.more.hidden=t.length<=this.limit}}destroy(){this.abort.abort()}};var R=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"/>'),l=s('<path d="M7 6h10M12 1v10M7 18h10"/>'),r=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
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
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">${
|
|
5
|
+
<button type="button" data-nav="zoom" aria-label="Zoom" title="Zoom controls" aria-expanded="false">${l}</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
|
|
12
|
-
aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,
|
|
10
|
+
<button type="button" data-nav="rail" aria-label="Hide details" title="Hide details" aria-expanded="true">${r}</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 c={signal:this.abort.signal},d=t.querySelector('[data-nav="search"]'),h=t.querySelector(".slm-navigation-search"),p=()=>{h.hidden=!0,this.results.hidden=!0,d.setAttribute("aria-expanded","false"),d.focus()};d.addEventListener("click",()=>{let b=h.hidden;h.hidden=!b,d.setAttribute("aria-expanded",String(b)),b&&this.search.focus()},c);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},c),this.search.addEventListener("keydown",b=>{b.key==="Escape"&&p()},c),this.move.addEventListener("click",()=>this.setMoving(!0),c),this.select.addEventListener("click",()=>this.setMoving(!1),c),this.clear.addEventListener("click",()=>this.host.clearSelection(),c),t.querySelector('[data-nav="in"]').addEventListener("click",()=>{this.location.hidden=!0,e.pauseFollow(),e.zoomIn()},c),t.querySelector('[data-nav="out"]').addEventListener("click",()=>{this.location.hidden=!0,e.pauseFollow(),e.zoomOut()},c);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"},c),this.search.addEventListener("input",()=>this.find(),c),this.search.addEventListener("keydown",b=>{b.key==="Escape"&&(this.results.hidden=!0),b.key==="ArrowDown"&&(b.preventDefault(),this.results.querySelector("button")?.focus())},c),e.map.addEventListener("pointerdown",()=>{this.location.hidden=!0,e.pauseFollow(),e.root.focus({preventScroll:!0}),this.results.hidden=!0},{...c,capture:!0}),e.root.querySelector(".slm-rail")?.addEventListener("pointerdown",()=>e.pauseFollow(),{...c,capture:!0}),e.map.addEventListener("wheel",()=>{this.location.hidden=!0,e.pauseFollow()},{...c,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)))},c);let f=()=>{this.space&&(this.space=!1,e.setMoving(this.moving))};window.addEventListener("keyup",b=>{b.code==="Space"&&f()},c),window.addEventListener("blur",f,c),window.addEventListener("resize",()=>{this.location.hidden=!0},c),e.root.querySelector('[data-ref="zfit"]')?.addEventListener("click",()=>{this.location.hidden=!0},c),e.root.addEventListener("focusout",b=>{e.root.contains(b.relatedTarget)||f()},c)}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 gt,applyOrganizerSeatGlyph as ft,clearOrganizerSeatGlyph as vt,isOrganizerGlyphPainted as yt,expandChart as xt,allObjects as wt,computeSections as kt,floorsOf as Ee,gaAreasOf as Re,gaUnitLabels as St,UNGROUPED_ID as v}from"@seatlayer/core";var nt=/^[a-zA-Z0-9._-]+$/;function rt(n){let e;try{e=new URL(n,"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||!nt.test(i)?null:{eventKey:s,asset:i}}catch{return null}}function ct(n){try{return/^\/v1\/events\/[^/]+\/assets(?:\/|$)/.test(new URL(n,"https://seatlayer.invalid").pathname)}catch{return!1}}var A=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=rt(e);if(!t)return Promise.resolve(ct(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 l=URL.createObjectURL(a);return this.disposed?(URL.revokeObjectURL(l),null):(this.created.add(l),l)}).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 l=a,r=await this.resolve(l.href);if(!r)throw new Error("organizer_event_asset_scope_mismatch");l.href=r}},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 ae(n,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>`,n.appendChild(o);let a=o.firstElementChild,l=!1,r={scrim:o,dialog:a,close:({restoreFocus:d=!0}={})=>{l||(l=!0,o.remove(),d&&i?.focus?.(),s.onClose?.())}};return a.querySelectorAll("[data-ch-close]").forEach(d=>{d.addEventListener("click",()=>r.close())}),o.addEventListener("keydown",d=>{if(d.key==="Escape"){d.stopPropagation(),r.close();return}if(d.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];d.shiftKey&&document.activeElement===p?(d.preventDefault(),u.focus()):!d.shiftKey&&document.activeElement===u&&(d.preventDefault(),p.focus())}),t(a),L(a),(a.querySelector("input,summary,button")??a).focus(),r}var le=`
|
|
13
13
|
.slm{--slm-ch-scrim:rgba(0,0,0,.58)}
|
|
14
14
|
.slm[data-theme=light]{--slm-ch-scrim:rgba(23,32,51,.42)}
|
|
15
15
|
.slm-ch-scrim{position:absolute;inset:0;z-index:12;background:var(--slm-ch-scrim);display:grid;place-items:center;
|
|
@@ -94,7 +94,7 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
94
94
|
.slm-ch-scope-empty{padding:18px 12px;color:var(--slm-muted);font-size:11.5px;text-align:center}
|
|
95
95
|
@media(max-width:560px){.slm-ch-scopebar{grid-template-columns:1fr}.slm-ch-scopesummary{padding-bottom:0}}
|
|
96
96
|
@media (prefers-reduced-motion:reduce){.slm-ch-scrim,.slm-ch-dialog{animation:none!important}}
|
|
97
|
-
`;var
|
|
97
|
+
`;var ne="seatlayer-manager-style",re="seatlayer-manager-channels-style",dt=`${le}
|
|
98
98
|
/* The floor was 480px, which trapped the cockpit in any host shorter than that:
|
|
99
99
|
every ancestor here is overflow:hidden, so the bottom of the rail (Create
|
|
100
100
|
channel, Show archived) was rendered but clipped away by the host and could
|
|
@@ -141,6 +141,7 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
141
141
|
.slm-navigation-results{position:absolute;top:100%;left:0;right:0;max-height:240px;overflow:auto;padding:6px;background:var(--slm-surface);border:1px solid var(--slm-line);border-radius:8px;box-shadow:0 8px 24px #0003}
|
|
142
142
|
.slm-navigation-results button{display:block;width:100%;text-align:left;margin-bottom:3px}
|
|
143
143
|
.slm.details-hidden .slm-rail{display:none}
|
|
144
|
+
.slm.slm-minimal .slm-bar,.slm.slm-minimal .slm-rail,.slm.slm-minimal .slm-railhead,.slm.slm-minimal .slm-navigation-tools,.slm.slm-minimal .slm-blocklegend,.slm.slm-minimal .slm-minimap-mount,.slm.slm-minimal .slm-hint,.slm.slm-minimal .slm-eyebrow,.slm.slm-minimal .slm-note{display:none}
|
|
144
145
|
.slm button:focus-visible,.slm input:focus-visible{outline:2px solid var(--slm-accent);outline-offset:2px}
|
|
145
146
|
.slm[data-theme="light"] .slm-scope.read{color:#465169}
|
|
146
147
|
.slm[data-theme="light"] .slm-scope.event,.slm[data-theme="light"] .slm-tablelock,.slm[data-theme="light"] .slm-kpidelta.down{color:#805500!important}
|
|
@@ -238,6 +239,13 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
238
239
|
.slm-follow-status,.slm-heat-status{position:absolute;bottom:14px;right:12px;max-width:calc(100% - 120px);padding:6px 9px;border:1px solid var(--slm-line);border-radius:8px;background:var(--slm-bg);color:var(--slm-text);font-size:11px;z-index:5;pointer-events:none}
|
|
239
240
|
.slm-heat-status{bottom:48px}
|
|
240
241
|
.slm-barbtn.follow.on{background:rgba(34,160,107,.13);border-color:#22a06b;color:#5bd39b}
|
|
242
|
+
/* Full screen wears the View summary's box. It is a real <button>, so the
|
|
243
|
+
".slm button" reset outranks the plain .slm-barbtn border \u2014 hence the
|
|
244
|
+
extra .slm here. Label hidden on the compact bar; the name is aria-label. */
|
|
245
|
+
.slm .slm-barbtn.slm-fullscreen{display:inline-flex;align-items:center;gap:6px;flex:none;white-space:nowrap;min-height:30px;padding:5px 10px;
|
|
246
|
+
border:1px solid var(--slm-line);border-radius:8px;font-size:12px}
|
|
247
|
+
.slm .slm-barbtn.slm-fullscreen:hover{border-color:var(--slm-muted)}
|
|
248
|
+
.slm-fullscreen-icon{display:inline-flex}
|
|
241
249
|
|
|
242
250
|
/* body */
|
|
243
251
|
.slm-body{display:flex;flex:1;min-height:0}
|
|
@@ -254,6 +262,15 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
254
262
|
background:color-mix(in srgb,var(--slm-surface) 88%,transparent);border:1px solid var(--slm-line);backdrop-filter:blur(8px);white-space:nowrap}
|
|
255
263
|
.slm-blocklegend span{display:inline-flex;align-items:center;gap:5px}
|
|
256
264
|
.slm-blocklegend i{width:9px;height:9px;border-radius:3px;display:inline-block}
|
|
265
|
+
/* Bottom-left of the map, clear of the zoom column and minimap on the right. */
|
|
266
|
+
.slm-blocklegend{position:absolute;left:12px;bottom:12px;z-index:5;align-items:center;flex-wrap:wrap;justify-content:flex-start;max-width:calc(100% - 250px);white-space:normal;row-gap:6px}
|
|
267
|
+
.slm.compact .slm-blocklegend{left:8px;bottom:8px;max-width:calc(100% - 96px)}
|
|
268
|
+
.slm-blocklegend i.seat{border-radius:50%}
|
|
269
|
+
.slm-legend-items{display:inline-flex;flex-wrap:wrap;align-items:center;gap:6px 10px}
|
|
270
|
+
.slm-colourby{display:inline-flex;padding:2px;border-radius:999px;background:var(--slm-line);gap:2px}
|
|
271
|
+
.slm .slm-colourby button{border:0;border-radius:999px;padding:3px 9px;font:inherit;font-size:10.5px;font-weight:700;color:var(--slm-muted);background:transparent;cursor:pointer}
|
|
272
|
+
.slm .slm-colourby button.on{color:var(--slm-text);background:var(--slm-surface);box-shadow:0 1px 2px rgba(0,0,0,.12)}
|
|
273
|
+
.slm .slm-colourby button:focus-visible{outline:2px solid var(--slm-accent,#6e7bff);outline-offset:1px}
|
|
257
274
|
.slm-blocklegend[hidden]{display:none}
|
|
258
275
|
.slm-zoom{display:flex;flex-direction:column;gap:5px;align-items:flex-end}
|
|
259
276
|
.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);
|
|
@@ -398,7 +415,7 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
398
415
|
.slm-find-count{display:block;min-height:16px;margin-top:4px;font-size:11px;color:var(--slm-muted);font-variant-numeric:tabular-nums}
|
|
399
416
|
.slm-find-count:empty{display:none}
|
|
400
417
|
/* 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:
|
|
418
|
+
.slm-findbar{flex:0 1 250px;min-width:120px}
|
|
402
419
|
.slm-findbar .slm-find{margin:0}
|
|
403
420
|
.slm-findbar .slm-find .slm-input{min-height:30px;padding:5px 9px 5px 30px;border-radius:8px;font-size:12px}
|
|
404
421
|
.slm-findbar .slm-find::before{left:10px;width:12px;height:12px}
|
|
@@ -498,7 +515,7 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
498
515
|
.slm-toast.ok{background:#1f7a4d;color:#fff;border-color:#1f7a4d}
|
|
499
516
|
|
|
500
517
|
/* control-room actions + insights */
|
|
501
|
-
.slm-bar-actions{display:flex;align-items:center;justify-self:end;gap:5px
|
|
518
|
+
.slm-bar-actions{display:flex;align-items:center;justify-self:end;gap:5px}
|
|
502
519
|
.slm-barbtn.on{background:rgba(244,183,64,.13);border-color:#f4b740;color:var(--slm-text)}
|
|
503
520
|
.slm-sectionlist{display:flex;flex-direction:column;gap:8px;margin-top:4px}
|
|
504
521
|
.slm-sectionlist + .slm-eyebrow{margin-top:18px}
|
|
@@ -627,8 +644,9 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
627
644
|
.slm.compact .slm-modes{display:none}
|
|
628
645
|
.slm.compact .slm-tools{display:block;width:100%;padding:9px 13px;min-height:44px;border:1px solid var(--slm-line);
|
|
629
646
|
border-radius:10px;background:var(--slm-surface);color:var(--slm-text);font-size:13px;font-weight:800}
|
|
630
|
-
.slm.compact .slm-live{justify-self:end}.slm.compact .slm-bar-actions{grid-column:1/-1;justify-self:stretch}
|
|
631
|
-
.slm.compact .slm-barbtn{flex:1;padding:6px 9px}
|
|
647
|
+
.slm.compact .slm-live{justify-self:end}.slm.compact .slm-bar-actions{grid-column:1/-1;justify-self:stretch;flex-wrap:wrap}
|
|
648
|
+
.slm.compact .slm-barbtn{flex:1;padding:6px 9px}
|
|
649
|
+
.slm.compact .slm-barbtn.slm-fullscreen{flex:none;justify-content:center;min-width:34px}.slm.compact .slm-fullscreen-label{display:none}.slm.compact .slm-kpis{grid-template-columns:repeat(4,minmax(0,1fr));gap:8px}
|
|
632
650
|
.slm.compact .slm-kpi[data-kpi="viewing-map"],.slm.compact .slm-kpi[data-kpi="active-holds"],
|
|
633
651
|
.slm.compact .slm-kpi[data-kpi="booked-pct"],.slm.compact .slm-kpi[data-kpi="booked-value"]{display:none}
|
|
634
652
|
/* Reduced motion, as a BLANKET over the cockpit subtree rather than a list of
|
|
@@ -648,9 +666,9 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
648
666
|
transition:none!important;
|
|
649
667
|
scroll-behavior:auto!important}
|
|
650
668
|
}
|
|
651
|
-
`;function
|
|
669
|
+
`;function ce(){if(typeof document>"u"||document.getElementById(ne))return;let n=document.createElement("style");n.id=ne,n.textContent=dt,document.head.appendChild(n)}function de(n){if(typeof document>"u"||document.getElementById(re))return;let e=document.createElement("style");e.id=re,e.textContent=n,document.head.appendChild(e)}function he(n){return n.total==null||n.free==null?n.label:n.free<=0?`${n.label} \xB7 sold out`:`${n.label} \xB7 ${n.free.toLocaleString()} of ${n.total.toLocaleString()} free`}function me(n){let t=_({focusedSection:n.focused?n.focused.label:null,seatsRevealed:n.seatsRevealed,atVenueFit:n.atVenueFit})==="none";return{crumb:n.focused?n.floor?`${n.floor} \xB7 ${he(n.focused)}`:he(n.focused):n.floor??"Venue",crumbShown:!!n.focused||!!n.floor,zoomInEnabled:!n.atCeiling,zoomOutEnabled:!t,venueEnabled:!t}}function pe(n={}){return`
|
|
652
670
|
<div class="slm-mapchrome" data-ref="mapchrome">
|
|
653
|
-
${
|
|
671
|
+
${n.legend??""}
|
|
654
672
|
<div class="slm-crumb" data-ref="crumb" role="status" hidden></div>
|
|
655
673
|
<div class="slm-zoom" role="group" aria-label="Zoom">
|
|
656
674
|
<button type="button" class="slm-zoombtn" data-ref="zin" aria-label="Zoom in" title="Zoom in">+</button>
|
|
@@ -658,10 +676,16 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
658
676
|
<button type="button" class="slm-zoombtn slm-zoombtn-venue" data-ref="zfit" title="Whole venue">Venue</button>
|
|
659
677
|
</div>
|
|
660
678
|
<div class="slm-minimap-mount" data-ref="minimap"></div>
|
|
661
|
-
</div>`}function
|
|
679
|
+
</div>`}function ue(n,e){n.crumb&&(n.crumb.textContent=e.crumb,n.crumb.hidden=!e.crumbShown);let t=(s,i)=>{s&&(s.disabled=!i,s.setAttribute("aria-disabled",String(!i)))};t(n.zin,e.zoomInEnabled),t(n.zout,e.zoomOutEnabled),t(n.zfit,e.venueEnabled)}var w={plenty:{min:.5,color:"#22a06b",label:"Plenty left",detail:"over half"},tight:{min:.15,color:"#f4b740",label:"Filling up",detail:"under half"},gone:{min:0,color:"#d9534f",label:"Nearly gone",detail:"under 15%"}},S={free:"#5b6db0",held:"#f4b740",sold:"#9ca3af"};function ht(n,e){let t=e>0?n/e:0;return t>=w.plenty.min?"plenty":t>=w.tight.min?"tight":"gone"}function mt(n,e,t,s=Date.now()){return n?.mode==="closed"||t?"Closed":n?.mode==="timed"&&n.revealAt&&n.revealAt>s?`Hidden until ${pt(n.revealAt,s)}`:n?.mode==="threshold"&&e?`Hidden until ${n.thresholdPct??0}% sold`:n?.mode==="hidden"||e?"Hidden":null}function pt(n,e){let t=new Date(n),s=t.toLocaleTimeString(void 0,{hour:"numeric",minute:t.getMinutes()?"2-digit":void 0}),i=(n-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 be(n,e){let t=n.state==="sold-out"?"Sold out":mt(e.rule,e.hiddenNow,e.closedNow);return{tint:t==="Closed"||t==="Sold out"?null:e.colourBy==="type"?e.typeTint??null:w[ht(n.free,n.total)].color,stateWord:t}}function ge(){return`<div class="slm-blocklegend" data-ref="blocklegend" role="group" aria-label="Map colours">
|
|
680
|
+
<span class="slm-colourby" role="radiogroup" aria-label="Colour by">
|
|
681
|
+
<button type="button" role="radio" data-colour-by="full" aria-checked="true">How full</button>
|
|
682
|
+
<button type="button" role="radio" data-colour-by="type" aria-checked="false">Ticket type</button>
|
|
683
|
+
</span>
|
|
684
|
+
<span class="slm-legend-items" data-ref="legenditems"></span>
|
|
685
|
+
</div>`}function ut(n){let e=n.seats;return n.colourBy==="full"&&!e?[...Object.keys(w).map(t=>({label:`${w[t].label} \xB7 ${w[t].detail}`,color:w[t].color,seat:!1})),{label:"Sold out",color:S.sold,seat:!1}]:n.colourBy==="full"?[{label:"Free",color:S.free,seat:!0},{label:"Held",color:S.held,seat:!0},{label:"Sold",color:S.sold,seat:!0}]:[...n.types.map(t=>({label:t.label,color:t.color,seat:e})),...e?[{label:"Held",color:S.held,seat:!0}]:[],{label:e?"Sold":"Sold out",color:S.sold,seat:e}]}function fe(n,e){n.querySelectorAll("[data-colour-by]").forEach(s=>{let i=s.dataset.colourBy===e.colourBy;s.setAttribute("aria-checked",String(i)),s.classList.toggle("on",i)});let t=n.querySelector('[data-ref="legenditems"]');t&&t.replaceChildren(...ut(e).map(s=>{let i=document.createElement("span"),o=document.createElement("i");return o.style.background=s.color,s.seat&&o.classList.add("seat"),i.append(o,document.createTextNode(s.label)),i}))}var ve=[{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:"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"}],ye="seatlayer.controlRoom.mapView";function $(){return{seatLabels:!0,rowLabels:!0,categoryColours:!1,channelColours:!0,momentum:!1}}function xe(n){return n==="g"?"categoryColours":ve.find(t=>t.letter.toLowerCase()===n)?.key??null}function we(n=Se()){let e=$();if(!n)return e;try{let t=n.getItem(ye);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 ke(n,e=Se()){if(e)try{e.setItem(ye,JSON.stringify(n))}catch{}}function Se(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function Le(n,e){e.renderer?.setLabelLayers?.({seatLabels:n.seatLabels,rowLabels:n.rowLabels}),e.renderer?.setCategoryColours?.(n.categoryColours),e.channelsOverlay(n.channelColours)}function Me(){return`
|
|
662
686
|
<details class="slm-view" data-ref="view">
|
|
663
687
|
<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">${
|
|
688
|
+
<div class="slm-view-menu" role="menu" aria-label="Map view">${ve.map(e=>`
|
|
665
689
|
<button type="button" class="slm-view-item" role="menuitemcheckbox" data-view="${e.key}" aria-checked="false" title="${e.hint}">
|
|
666
690
|
<span class="slm-view-check" aria-hidden="true"></span>
|
|
667
691
|
<span class="slm-view-label">${e.label}</span>
|
|
@@ -669,38 +693,38 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
669
693
|
</button>`).join("")}
|
|
670
694
|
<div class="slm-view-note" data-ref="viewnote" hidden></div>
|
|
671
695
|
</div>
|
|
672
|
-
</details>`}function
|
|
673
|
-
<summary aria-label="Availability for ${m(
|
|
674
|
-
<div class="slm-availchoices" aria-label="Availability options for ${m(
|
|
675
|
-
${o.map(([
|
|
696
|
+
</details>`}function Te(n,e,t){let s=$(),i=!1;n.querySelectorAll("[data-view]").forEach(l=>{let r=l.dataset.view,c=e[r];l.setAttribute("aria-checked",String(c)),l.classList.toggle("on",c);let d=r==="channelColours"&&!t.channelColoursAvailable;l.disabled=d,l.setAttribute("aria-disabled",String(d)),!d&&c!==s[r]&&(i=!0)}),n.querySelector("summary")?.classList.toggle("away",i);let a=n.querySelector('[data-ref="viewnote"]');if(a){let l=[];t.channelColoursAvailable||l.push("Channel colours: open the Channels tool."),t.momentumLoading&&l.push("Booking momentum: loading the first snapshot\u2026"),a.hidden=!l.length,a.textContent=l.join(" ")}}import{UNGROUPED_ID as bt}from"@seatlayer/core";function P(n){return Object.entries(n).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function B(n){let e=n.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=n.doc?.zones??[],s=new Map,i=[];for(let c of e.sections)if(c.zone&&t.some(d=>d.id===c.zone)){let d=s.get(c.zone)??[];d.push(c),s.set(c.zone,d)}else i.push(c);let o=[],a=0,l=0,r=(c,d,h,p=!1)=>{let u=n.availabilityRules[d.id]??null,g=n.effectiveClosed.has(d.id)||p,f=n.effectiveHidden.has(d.id)||h&&!g;c==="section"&&f&&(a+=1),c==="section"&&g&&(l+=1),o.push({kind:c,id:d.id,label:d.label,seatCount:d.seatCount,seatLabels:d.seatLabels,rule:u,hidden:f,closed:g,followsZone:c==="section"&&h})};for(let c of t){let d=s.get(c.id);if(!d||!d.length)continue;let h={id:c.id,label:c.label||"Zone",seatCount:d.reduce((g,f)=>g+f.seatCount,0),seatLabels:d.flatMap(g=>g.seatLabels)},p=!!n.availabilityRules[c.id],u=n.availabilityRules[c.id]?.mode==="closed";r("zone",h,!1);for(let g of d)r("section",g,p,u)}for(let c of i)r("section",c,!1);if(e.ungrouped){let c=e.ungrouped;r("section",{id:bt,label:c.label,seatCount:c.seatCount,seatLabels:c.seatLabels},!1)}return{rows:o,hiddenSections:a,closedSections:l}}function Ce(n,e){let t=W(n.rule),s=`slm-availrow${n.kind==="zone"?" zone":""}${n.hidden?" hidden":""}${n.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=n.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<details class="slm-availpicker" data-avail-picker>
|
|
697
|
+
<summary aria-label="Availability for ${m(n.label)}" ${e?'aria-disabled="true"':""}>${o.find(d=>d[0]===t)[1]}<span aria-hidden="true">\u2304</span></summary>
|
|
698
|
+
<div class="slm-availchoices" aria-label="Availability options for ${m(n.label)}">
|
|
699
|
+
${o.map(([d,h,p])=>`<button type="button" data-avail-id="${m(n.id)}" data-avail-value="${d}" aria-pressed="${t===d}"${i}><span><b>${h}</b><small>${p}</small></span><span aria-hidden="true">${t===d?"\u2713":""}</span></button>`).join("")}
|
|
676
700
|
</div>
|
|
677
|
-
</details>`,
|
|
678
|
-
<input type="datetime-local" class="slm-input" data-avail-reveal="${m(
|
|
679
|
-
</div>`}else if(!
|
|
701
|
+
</details>`,l="";if(!n.followsZone&&t==="timed"){let d=n.rule?.revealAt?m(Z(n.rule.revealAt)):"";l=`<div class="slm-availdetail">
|
|
702
|
+
<input type="datetime-local" class="slm-input" data-avail-reveal="${m(n.id)}" value="${d}"${i} aria-label="Reveal time for ${m(n.label)}" />
|
|
703
|
+
</div>`}else if(!n.followsZone&&t==="threshold"){let d=n.rule?.thresholdPct??80;l=`<div class="slm-availdetail">
|
|
680
704
|
<span class="slm-availpctlabel">Reveal at</span>
|
|
681
|
-
<input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${m(
|
|
705
|
+
<input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${m(n.id)}" value="${m(d)}"${i} aria-label="Percent sold to reveal ${m(n.label)}" />
|
|
682
706
|
<span class="slm-availpctlabel">% sold</span>
|
|
683
|
-
</div>`}let
|
|
707
|
+
</div>`}let r=n.closed?'<span class="slm-availbadge closed">Closed</span>':n.hidden?'<span class="slm-availbadge hidden">Hidden</span>':"",c=n.kind==="zone"?`<span class="slm-availcaret" aria-hidden="true">${n.hidden?"\u25B8":"\u25BE"}</span>`:"";return`<div class="${s}">
|
|
684
708
|
<div class="slm-availhead">
|
|
685
|
-
<span class="slm-availlabel">${
|
|
686
|
-
${
|
|
687
|
-
<span class="slm-availcount">${
|
|
709
|
+
<span class="slm-availlabel">${c}${m(n.label)}</span>
|
|
710
|
+
${r}
|
|
711
|
+
<span class="slm-availcount">${n.seatCount.toLocaleString()}</span>
|
|
688
712
|
</div>
|
|
689
713
|
${a}
|
|
690
|
-
${
|
|
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=`
|
|
714
|
+
${l}
|
|
715
|
+
</div>`}var Lt="https://api.seatlayer.io",H=200,Ae=16,$e=4,He=[{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."}]}],Mt=3;function Tt(n){let e=n?.status;return e===401||e===403}var Be=n=>`<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${n}</svg>`,j={enter:Be('<path d="M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5"/>'),exit:Be('<path d="M9 4v5H4M20 9h-5V4M15 20v-5h5M4 15h5v5"/>')},Ct=Object.fromEntries(He.flatMap(n=>n.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),q=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.tableChairIds=new Map;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=$();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?xe(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=Ct[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.typeKeyBySection=null;this.typeKeyBase=null;this.sectionOptions=[];O(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 F(e.apiBase??Lt,e.token),this.organizerAssetUrls=new A(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=Y(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(){ce(),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||(de(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 l=o.logicalRowId??o.rowId,r=this.sectionByObject.get(o.rowId)??v,c=i.get(l)??{id:l,label:a.type==="row"?a.segmentedRow?.displayLabel??a.displayLabel??a.label:a.displayLabel??a.label,sectionId:r,sectionLabel:this.sectionLabelById.get(r)??"Other seats",labels:[]};c.labels.push(o.label),i.set(l,c)}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=ae(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=D({compact:!0}),this.barFind=new V({...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 V(this.buildChooserHost()),this.chooser}toolSelectionBar(e,t,s,i){return se({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,l=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:[]};l.labels.push(s.label),t.set(o,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)??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};if(!Object.keys(t).some(o=>t[o]!==this.mapView[o]))return;let i=t.categoryColours!==this.mapView.categoryColours;this.mapView=t,ke(t),t.momentum!==this.heatEnabled&&this.setHeatOverlay(t.momentum),this.applyMapView(),this.paintMapViewMenu(),i&&(this.refreshBlockPaint(),this.paintMapChrome())}getColourBy(){return this.mapView.categoryColours?"type":"full"}setColourBy(e){this.setMapView({categoryColours:e==="type"})}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(){Le(this.mapView,{renderer:this.renderer,channelsOverlay:e=>this.channels?.setOverlayVisible(e)})}paintMapViewMenu(){let e=this.els.view;e&&Te(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=I(this.themeMode);for(let[t,s]of Object.entries(J(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=N(()=>{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=ee(I(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){O(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>=Mt||Tt(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
716
|
<strong id="slm-ended-title">This session ended</strong>
|
|
693
717
|
<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>
|
|
718
|
+
<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 k&&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 l of o.labels){let r=this.labelToSeat.get(l),c=this.labelToId.get(l);r&&(r.categoryKey=e),c&&(a[c]=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 k&&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.tableChairIds.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:l,seatCount:r,zone:c})=>({id:a,label:l,seatCount:r,...c?{zone:c}:{}}));return i&&this.opts.onFilteredSectionChange?.(o),o}focusSection(e){let t=e.trim(),s=this.filterableSections().filter(i=>i.label===t);return!this.renderer||!s.length?[]:(this.frameSections(s),s.map(({id:i,label:o,seatCount:a,zone:l})=>({id:i,label:o,seatCount:a,...l?{zone:l}:{}})))}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(l=>!s.has(l)).map(l=>this.labelToSeat.get(l)).filter(l=>!!l&&this.canSelectObject(l)),a=Math.max(0,i-s.size);o.length>a&&this.opts.onSelectionLimit?.(i),t=o.slice(0,a).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()}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(l=>l.id===t)??null:null,i=e.getFloors?.()??[],o=i.length>1?e.isFloorOverview?.()?"All floors":i.find(l=>l.id===e.getActiveFloorId?.())?.name??null:null,a=this.els.blocklegend;a&&fe(a,{colourBy:this.getColourBy(),seats:e.getRung?.()==="seats",types:this.legendTypes()}),ue(this.els,me({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}))}sectionTypeKeys(){if(this.typeKeyBySection&&this.typeKeyBase===this.sectionsBase)return this.typeKeyBySection;let e=new Map;for(let t of this.filterableSections()){let s=new Map;for(let o of t.seatLabels){let a=this.labelToSeat.get(o)?.categoryKey;a&&s.set(a,(s.get(a)??0)+1)}let i=null;for(let[o,a]of s)(!i||a>s.get(i))&&(i=o);i&&e.set(t.id,i)}return this.typeKeyBySection=e,this.typeKeyBase=this.sectionsBase,e}sectionTypeTint(e){let t=this.sectionTypeKeys().get(e);return t?this.renderer?.categoryDisplayColor?.(t)??null:null}legendTypes(){let e=new Set;for(let t of this.labelToSeat.values())e.add(t.categoryKey);return(this.doc?.categories??[]).filter(t=>e.has(t.key)).map(t=>({label:t.label,color:this.renderer?.categoryDisplayColor?.(t.key)??t.color}))}refreshBlockPaint(){this.renderer?.refreshBlockPaint?.(),this.minimap?.refreshMinimap()}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=K({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 gt(this.mapHost,{manageMode:!0,organizerGlyph:{apply:ft,clear:vt,isPainted:yt},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(),onGAClick:t=>{if(this.mode!=="select"||!this.opts.onAreaClick||!this.doc)return;let s=Re(this.doc).find(i=>i.id===t);s&&this.opts.onAreaClick({id:s.id,label:s.label,name:s.displayLabel?.trim()||s.label})},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=>be(t,{rule:this.availabilityRules[t.id],hiddenNow:this.effectiveHidden.has(t.id),closedNow:this.effectiveClosed.has(t.id),colourBy:this.getColourBy(),typeTint:this.sectionTypeTint(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(d=>d.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 l=this.sectionByObject.get(t.rowId)??v,r=this.doc?.categories.find(d=>d.key===t.categoryKey),c=s==="free"&&!this.effectiveHidden.has(l)&&!this.effectiveClosed.has(l)&&r?.notForSale!==!0;return o.push({caption:"For sale",value:c?"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}"
|
|
719
|
+
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){let t=new Map;for(let i of wt(e))i.type==="table"&&t.set(i.id,i.label);let s=new Map;for(let i of xt(e))if(this.labelToId.set(i.label,i.id),this.labelToSeat.set(i.label,i),this.allIds.push(i.id),t.has(i.rowId)){let o=s.get(i.rowId)??[];o.push(i.id),s.set(i.rowId,o)}for(let[i,o]of s){let a=t.get(i);this.labelToId.has(a)||this.tableChairIds.set(a,o)}for(let i of Re(e))for(let o of St(i))this.labelToId.has(o)||this.gaUnitLabelSet.add(o)}unitTotal(){return this.allIds.length+this.gaUnitLabelSet.size}paintIds(e){let t=this.labelToId.get(e);return t?[t]:this.tableChairIds.get(e)??[]}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())t[M(i)].push(...this.paintIds(s));["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 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 d=this.paintIds(l.label);d.length&&(this.renderer?.setStatus(d,M(r)),i.push(...d));let h=this.verbFor(c,r),p=`${h}:${r}`,u=o.get(p)??{labels:[],verb:h,status:r};u.labels.push(l.label),o.set(p,u)}for(let l of o.values()){let r=this.pushActivity(l.labels,l.verb,l.status);r&&this.paintSpatialActivity(r)}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",l=this.status.get(o)??"free";if(a===l)continue;let r=this.verbFor(a,l),c=`${r}:${l}`,d=i.get(c)??{labels:[],verb:r,status:l};d.labels.push(o),i.set(c,d)}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),s.push(...this.paintIds(i));s.length&&this.renderer?.setStatus(s,M(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,Ae)){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,$e))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,Ae).map(r=>this.labelToSeat.get(r)).filter(r=>!!r);if(!s.length)return;let i=s.map(r=>r.x),o=s.map(r=>r.y),a=Math.min(...i),l=Math.min(...o);this.renderer?.focusRegion({x:a-150,y:l-100,width:Math.max(...i)-a+300,height:Math.max(...o)-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 o of s.slice(0,$e))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
720
|
<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(
|
|
721
|
+
<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(r=>{let c=Number.isFinite(r.bookedValue)?r.bookedValue:r.bookedRevenue;return{...r,bookedValue:c??0,bookedRevenue:c??0}}),a={...i,bySection:o},l={...s,bookedValue:a,revenue:a};if(e===this.revenueRequest){if(this.livePresence&&this.livePresence.at>=t?l={...l,presence:this.livePresence.value}:this.livePresence=null,this.liveGross&&this.liveGross.at>=t){let d={...l.bookedValue,gross:this.liveGross.value};l={...l,bookedValue:d,revenue:d}}else this.liveGross=null;this.controlRoomSnapshot=l,l.activity&&this.seedFeed(l.activity),this.rebaseServerTotals(l),this.lastSyncedAt=Date.now(),this.authoritativeGrossRevenue=l.bookedValue.gross,this.authoritativeCurrency=l.currency,this.currency=l.currency,this.revenueStatus="current",this.recomputeTallies(),this.applyHeatOverlay(),this.paintMonitorInsights(),this.seatHistoryPanel?.refresh();let r=this.getSelection().slice(-1)[0],c=this.els.rail?.querySelector("[data-seat-status]");r&&c&&(c.textContent=this.status.get(r.label)??"free"),this.opts.onControlRoom?.(l)}return l}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=l=>t?Math.max(0,t.server[l]+(e[l]-t.client[l])):e[l],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.minimap?.refreshMinimap(),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),l={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(l),this.feed.length>H&&(this.feed.length=H),this.mode==="view"&&this.paintFeed(),this.showLiveEvent(l),this.opts.onActivity?.(l),l}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(r=>r.id===`log:${i.id}`))continue;let o=i.labels[0];if(!o)continue;let a=this.sectionsForLabels(i.labels),l={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(l),this.opts.onActivity?.(l)}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"),t=this.opts.chrome==="minimal";e.className=t?"slm slm-minimal":"slm",e.tabIndex=0,e.setAttribute("role","region"),e.setAttribute("aria-label",t?"Seat map":"SeatLayer live control room"),e.innerHTML=`
|
|
698
722
|
<div class="slm-bar">
|
|
699
723
|
<div class="slm-modes" data-ref="modes" role="tablist" aria-label="Control room tools">
|
|
700
|
-
${
|
|
701
|
-
<span class="slm-modegroup-label" aria-hidden="true">${m(
|
|
702
|
-
${
|
|
703
|
-
title="${m(
|
|
724
|
+
${He.map(o=>`<div class="slm-modegroup" data-group="${o.key}" role="presentation" hidden>
|
|
725
|
+
<span class="slm-modegroup-label" aria-hidden="true">${m(o.label)}</span>
|
|
726
|
+
${o.tools.map(a=>`<button class="slm-mode" role="tab" data-mode="${a.mode}"
|
|
727
|
+
title="${m(a.title)} (${a.shortcut})" aria-keyshortcuts="${a.shortcut}" hidden>${m(a.label)}</button>`).join("")}
|
|
704
728
|
</div>`).join("")}
|
|
705
729
|
</div>
|
|
706
730
|
<select class="slm-tools" data-ref="tools" aria-label="Control room tools"></select>
|
|
@@ -708,9 +732,10 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
708
732
|
<div class="slm-bar-actions">
|
|
709
733
|
<button class="slm-barbtn follow" data-ref="follow" aria-label="Follow live" aria-pressed="false"
|
|
710
734
|
title="Stay on the current map view unless enabled">Auto-follow</button>
|
|
711
|
-
<div data-ref="findbar" class="slm-findbar">${
|
|
712
|
-
${
|
|
713
|
-
<button class="slm-barbtn" data-ref="fullscreen" title="Full screen (F)" aria-
|
|
735
|
+
<div data-ref="findbar" class="slm-findbar">${D({compact:!0})}</div>
|
|
736
|
+
${Me()}
|
|
737
|
+
<button type="button" class="slm-barbtn slm-fullscreen" data-ref="fullscreen" title="Full screen (F)" aria-label="Full screen"
|
|
738
|
+
aria-keyshortcuts="F"><span class="slm-fullscreen-icon" aria-hidden="true">${j.enter}</span><span class="slm-fullscreen-label">Full screen</span></button>
|
|
714
739
|
</div>
|
|
715
740
|
<div class="slm-kpis" data-ref="kpis"></div>
|
|
716
741
|
</div>
|
|
@@ -723,15 +748,16 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
723
748
|
</div>
|
|
724
749
|
<div class="slm-heat-status" data-ref="heatstatus" role="status" hidden></div>
|
|
725
750
|
<div class="slm-follow-status" data-ref="followstatus" role="status" hidden></div>
|
|
726
|
-
${
|
|
751
|
+
${pe()}
|
|
752
|
+
${ge()}
|
|
727
753
|
</div>
|
|
728
754
|
<aside class="slm-rail"><div class="slm-railscroll" data-ref="rail"></div></aside>
|
|
729
755
|
</div>
|
|
730
756
|
<div class="slm-toast" data-ref="toast"></div>
|
|
731
|
-
`,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let
|
|
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
|
|
757
|
+
`,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let o=e.querySelector(".slm-rail");o&&(L(o),U(o))});let s=e.querySelector(".slm-rail");s&&this.selectObserver.observe(s,{childList:!0,subtree:!0}),this.applyThemeVars(),this.watchThemeMode(),this.updateContainerLayout(),typeof ResizeObserver<"u"&&(this.layoutObserver=new ResizeObserver(()=>this.updateContainerLayout()),this.layoutObserver.observe(e));let i=o=>e.querySelector(`[data-ref="${o}"]`);this.mapHost=i("maphost"),this.els={modes:i("modes"),tools:i("tools"),livetext:i("livetext"),kpis:i("kpis"),follow:i("follow"),view:i("view"),findbar:i("findbar"),fullscreen:i("fullscreen"),lane:i("lane"),zoomhint:i("zoomhint"),liveevent:i("liveevent"),rail:i("rail"),toast:i("toast"),mapchrome:i("mapchrome"),crumb:i("crumb"),zin:i("zin"),zout:i("zout"),zfit:i("zfit"),minimapMount:i("minimap"),blocklegend:i("blocklegend")},this.els.modes.querySelectorAll("[data-mode]").forEach(o=>o.addEventListener("click",()=>this.setMode(o.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.blocklegend?.addEventListener("click",o=>{let a=o.target?.closest("[data-colour-by]");a?.dataset.colourBy&&this.setColourBy(a.dataset.colourBy)}),this.els.view.addEventListener("click",o=>{let a=o.target?.closest("[data-view]");a?.dataset.view&&this.toggleMapView(a.dataset.view)}),e.addEventListener("pointerdown",o=>{let a=this.els.view;a.open&&!a.contains(o.target)&&(a.open=!1)}),this.mapView=we(),this.opts.colourBy&&(this.mapView={...this.mapView,categoryColours:this.opts.colourBy==="type"}),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 R({root:e,map:this.mapHost,setMoving:o=>{this.movingMap=o,this.updateRendererInteraction()},pauseFollow:()=>{this.followLive&&this.setFollowLive(!1)},clearSelection:()=>this.clearSelection(),zoomIn:()=>this.renderer?.zoomIn(),zoomOut:()=>this.renderer?.zoomOut(),targets:o=>this.navigationTargets(o)}),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?Ee(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:l,minY:r,maxX:c,maxY:d}=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:l-30,y:r-30,width:c-l+60,height:d-r+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(i=>i.id)),s=this.filterableSections().filter(i=>!t.has(i.id)).map(i=>i.id);this.renderer.clearSectionFocus(),this.renderer.setClosedSections(null),this.renderer.setDimmedSections(s),this.frameSections(e)}frameSections(e){if(!this.renderer||!e.length)return;let t=e.flatMap(r=>r.seatLabels).map(r=>this.labelToSeat.get(r)).filter(r=>!!r&&Number.isFinite(r.x)&&Number.isFinite(r.y));if(!t.length){this.renderer.focusRegion(e[0].id);return}let s=Math.min(...t.map(r=>r.x)),i=Math.min(...t.map(r=>r.y)),o=Math.max(...t.map(r=>r.x)),a=Math.max(...t.map(r=>r.y)),l=Math.max(40,Math.max(o-s,a-i)*.08);this.renderer.focusRegion({x:s-l,y:i-l,width:Math.max(1,o-s)+l*2,height:Math.max(1,a-i)+l*2})}buildSectionOptions(){if(this.doc)try{let e=kt(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?Ee(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,l=this.toolAvailable(a);if(o.hidden=!l,!l)return;i.push({mode:a,label:o.textContent??a});let r=a===this.mode;o.classList.toggle("on",r),o.setAttribute("aria-selected",String(r)),o.tabIndex=r?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>
|
|
758
|
+
<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(){let e=this.els.fullscreen;if(!e)return;let t=this.isFullscreen(),s=t?"Exit full screen":"Full screen";e.setAttribute("aria-label",s),e.title=`${s} (F)`;let i=e.querySelector(".slm-fullscreen-label");i&&(i.textContent=s);let o=e.querySelector(".slm-fullscreen-icon");o&&(o.innerHTML=t?j.exit:j.enter)}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}${T(o,s)}`:e==="booked-pct"?`${i}${o.toLocaleString()}pt`:`${i}${o.toLocaleString()}`}paintKpis(e){if(!this.els.kpis)return;let t=e.bookedValueStatus==="current"?T(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 l=this.lastKpiValues.get(a.key),r=a.raw!=null&&l!=null&&a.raw!==l,c=r?a.raw-l:0;r&&(o=!0,this.activeKpiDeltas.set(a.key,{text:this.formatKpiDelta(a.key,c,e.currency),down:c<0})),a.raw!=null&&this.lastKpiValues.set(a.key,a.raw);let d=this.activeKpiDeltas.get(a.key);return`<div class="slm-kpi${d?" changed":""}" data-kpi="${a.key}" title="${m(a.title)}">
|
|
733
759
|
<b>${a.dot?`<span class="dot" style="background:${a.dot}"></span>`:""}${a.n}</b><span>${a.l}</span>
|
|
734
|
-
${
|
|
760
|
+
${d?`<span class="slm-kpidelta${d.down?" down":""}">${d.text}</span>`:""}
|
|
735
761
|
</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=`
|
|
736
762
|
<div class="slm-monitor-head"><h2>Live activity</h2><span data-ref="presence" class="slm-monitor-connection"></span></div>
|
|
737
763
|
<div class="slm-monitor-tabs" role="tablist" aria-label="Monitor details">
|
|
@@ -751,9 +777,9 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
751
777
|
</div>
|
|
752
778
|
<div class="slm-sectionlist" data-ref="sections"></div>
|
|
753
779
|
</div>
|
|
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
|
|
755
|
-
<span class="slm-sectiontop"><span>${m(i.sectionLabel)}</span><span title="Configured value of currently booked inventory">${
|
|
756
|
-
<span class="slm-sectionmeta"><span>${i.booked.toLocaleString()}/${i.total.toLocaleString()} booked \xB7 ${
|
|
780
|
+
`,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 E(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?te(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,l=`${a>0?"+":""}${a}`,r=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">
|
|
781
|
+
<span class="slm-sectiontop"><span>${m(i.sectionLabel)}</span><span title="Configured value of currently booked inventory">${T(i.bookedValue,e.currency)}</span></span>
|
|
782
|
+
<span class="slm-sectionmeta"><span>${i.booked.toLocaleString()}/${i.total.toLocaleString()} booked \xB7 ${l} net in ${e.velocity.windowMinutes}m</span><span class="slm-trend ${r}">${r}</span><span class="slm-sectionlocate">Locate</span></span>
|
|
757
783
|
</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=`
|
|
758
784
|
${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.")}
|
|
759
785
|
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
@@ -762,7 +788,7 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
762
788
|
${this.toolSelectionBar("selectnum","selectmeta","selectclear","selectall")}
|
|
763
789
|
<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=`
|
|
764
790
|
${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.")}
|
|
765
|
-
${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let i=t===this.filteredSectionLabel,o=s.reduce((a,
|
|
791
|
+
${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let i=t===this.filteredSectionLabel,o=s.reduce((a,l)=>a+l.seatCount,0);return`<button type="button" class="slm-sectionrow${i?" on":""}" data-filter-section="${m(t)}" aria-pressed="${i}">
|
|
766
792
|
<span class="slm-sectiontop"><span>${m(t)}</span><span>${o.toLocaleString()}</span></span>
|
|
767
793
|
<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>
|
|
768
794
|
</button>`}).join("")}</div>
|
|
@@ -783,23 +809,23 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
783
809
|
<div class="slm-catreset">
|
|
784
810
|
<button type="button" class="slm-btn ghost" data-ref="categoryreset" disabled>Reset to chart defaults</button>
|
|
785
811
|
<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,
|
|
812
|
+
</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,l=[...this.labelToSeat.values()].filter(p=>p.categoryKey===a).length,r=s.get(a)??0,c=t>0&&r===t;o.disabled=t===0||c,o.classList.toggle("current",c);let d=o.querySelector("[data-cat-current]");d&&(d.textContent=`${l.toLocaleString()} ${l===1?"seat":"seats"} now`);let h=o.querySelector("[data-cat-action]");h&&(h.textContent=t===0?"Move here":c?"Already here":`Move ${(t-r).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=`
|
|
787
813
|
${this.railHeader("Tables","event",t)}
|
|
788
814
|
<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=`
|
|
789
815
|
${this.railHeader("Tables","event",t)}
|
|
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,
|
|
816
|
+
<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,l=o.filter(h=>h.current==="whole").length,r=o.length-a-l,c=[`${a.toLocaleString()} per chair`,`${l.toLocaleString()} whole table`,r?`${r.toLocaleString()} flexible group`:""].filter(Boolean).join(" \xB7 "),d=this.tableBookingSaving;this.els.rail.innerHTML=`
|
|
791
817
|
${this.railHeader("Tables","event",t)}
|
|
792
|
-
<div class="slm-tablesummary"><b>${o.length.toLocaleString()} ${o.length===1?"table":"tables"}</b><span>${m(
|
|
818
|
+
<div class="slm-tablesummary"><b>${o.length.toLocaleString()} ${o.length===1?"table":"tables"}</b><span>${m(c)}</span></div>
|
|
793
819
|
<p class="slm-eyebrow" style="margin-top:12px">Set every table at once</p>
|
|
794
820
|
<div class="slm-row">
|
|
795
|
-
<button class="slm-btn ghost" data-table-all="individual"${
|
|
796
|
-
<button class="slm-btn ghost" data-table-all="whole"${
|
|
821
|
+
<button class="slm-btn ghost" data-table-all="individual"${d?" disabled":""} title="Sell every chair on its own">All per chair</button>
|
|
822
|
+
<button class="slm-btn ghost" data-table-all="whole"${d?" disabled":""} title="Sell every table as one booking">All whole table</button>
|
|
797
823
|
</div>
|
|
798
824
|
<p class="slm-eyebrow" style="margin-top:12px">Or one table at a time</p>
|
|
799
825
|
<div class="slm-tablelist">${o.map(({table:h,current:p,locked:u})=>`<div class="slm-tablerow${u?" locked":""}">
|
|
800
826
|
<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
827
|
<select class="slm-select" data-table-mode="${m(h.id)}" aria-label="Booking mode for ${m(h.displayLabel??h.label)}"
|
|
802
|
-
${
|
|
828
|
+
${d||u?"disabled":""} ${u?`title="Release the ${m(u)} chairs before changing how this table sells"`:""}>
|
|
803
829
|
<option value="individual"${p==="individual"?" selected":""}>Per chair</option>
|
|
804
830
|
<option value="whole"${p==="whole"?" selected":""}>Whole table</option>
|
|
805
831
|
${p==="variable"?'<option value="variable" selected>Flexible group</option>':""}
|
|
@@ -807,14 +833,14 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
807
833
|
</div>`).join("")}</div>
|
|
808
834
|
<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=`
|
|
809
835
|
${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.")}
|
|
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",
|
|
836
|
+
<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",l=this.doc?.categories.find(c=>c.key===t.categoryKey);this.els.rail.innerHTML=`
|
|
811
837
|
<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(
|
|
813
|
-
<div data-ref="seat-history"></div>`;let
|
|
838
|
+
<p class="slm-note">${m(a)} \xB7 ${m(l?.label??t.categoryKey)}</p>
|
|
839
|
+
<div data-ref="seat-history"></div>`;let r=this.els.rail.querySelector('[data-ref="seat-history"]');this.seatHistoryPanel=new C(r,(c,d)=>this.withAuthRetry(()=>this.api.seatHistory(this.key,t.label,c,d)))}async refreshAvailability(){try{let e=await this.withAuthRetry(()=>this.api.availability(this.key));this.availabilityRules=e.rules??{},this.effectiveClosed=new Set(P(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 k&&t.status===401&&this.opts.onTokenRefresh&&!this.tokenRefreshInFlight){if(await this.rotateToken(),this.sessionEnded)throw t;return e()}throw t instanceof k&&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.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}=B(this.sectionRowsInput());if(!e.length){this.els.rail.innerHTML=`
|
|
814
840
|
${this.railHeader("Sections","event","Draw sections or zones in the designer to schedule availability per area. This chart has none yet.")}
|
|
815
841
|
<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=`
|
|
816
842
|
${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.")}
|
|
817
|
-
<div class="slm-availlist" data-ref="availlist">${e.map(
|
|
843
|
+
<div class="slm-availlist" data-ref="availlist">${e.map(l=>Ce(l,this.availabilitySaving)).join("")}</div>
|
|
818
844
|
<div class="slm-availsummary">
|
|
819
845
|
<span class="slm-availdot${a?" warn":""}"></span>
|
|
820
846
|
<span>${m(o)}</span>
|
|
@@ -822,10 +848,10 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
822
848
|
<div class="slm-availcallout">
|
|
823
849
|
<span class="slm-availstar" aria-hidden="true">\u2726</span>
|
|
824
850
|
<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>
|
|
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
|
|
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(
|
|
851
|
+
</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=B(this.sectionRowsInput()).rows.find(l=>l.id===e),i=s?.seatLabels??this.availabilityRules[e]?.labels??[],o={...this.availabilityRules},a=G(t,i,this.availabilityRules[e]);if(a?o[e]=a:delete o[e],s?.kind==="zone"&&this.sectionsBase)for(let l of this.sectionsBase.sections)l.zone===e&&delete o[l.id];this.persistAvailability(o)}setSectionRulePatch(e,t){let s=this.availabilityRules[e];if(!s)return;let o=B(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(P(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=Q.map(t=>`<div class="slm-legrow"><span class="slm-legdot" style="background:${t.color}"></span>
|
|
852
|
+
<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(l=>`<option value="${m(l.id)}">${m(l.label)}</option>`).join("");this.els.rail.innerHTML=`
|
|
827
853
|
<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>
|
|
828
|
-
<p class="slm-note">${
|
|
854
|
+
<p class="slm-note">${X}</p>
|
|
829
855
|
<div data-block-editor ${this.blockBrowse?"hidden":""}>
|
|
830
856
|
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
831
857
|
<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>
|
|
@@ -866,5 +892,5 @@ import{s as q,t as N}from"./chunk-JELR6YYZ.js";import{A as Be,B as Ie,C as Fe,D
|
|
|
866
892
|
<button class="slm-btn ghost" data-ref="markall" style="width:100%" disabled>Put all blocked seats on sale</button>
|
|
867
893
|
<p class="slm-note slm-allnote" data-ref="markallnote">For a full reset only. You will be asked to confirm.</p>
|
|
868
894
|
</div></details>
|
|
869
|
-
`,this.els.rail.querySelectorAll("[data-block-tab]").forEach(
|
|
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>',
|
|
895
|
+
`,this.els.rail.querySelectorAll("[data-block-tab]").forEach(l=>l.addEventListener("click",()=>{this.blockBrowse=l.dataset.blockTab==="browse",this.renderBlockRail()}));let s=l=>this.els.rail.querySelector(`[data-ref="${l}"]`);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(l=>l.label))}),s("blockedlist").addEventListener("click",l=>{let r=l.target,c=r.closest("[data-block-seat-find]");if(c?.dataset.blockSeatFind){let u=this.labelToSeat.get(c.dataset.blockSeatFind);u&&(this.setFollowLive(!1),this.focusActivitySeats([u.label],this.sectionByObject.get(u.rowId)??v));return}let d=r.closest("[data-block-locate]"),h=r.closest("[data-block-group]");if(d||h){let u=d?.dataset.blockLocate??h?.dataset.blockGroup,g=this.filteredBlockedSeats().filter(f=>f.rowId===u);d&&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=r.closest("[data-blocked-label]");p?.dataset.blockedLabel?this.toggleLabels([p.dataset.blockedLabel]):r.closest("[data-blocked-more]")&&(this.blockedResultLimit+=100,this.paintBlockedInventory())});let a=s("release");a.addEventListener("change",()=>{let l=a.value?new Date(a.value).getTime():NaN;this.releaseAt=Number.isFinite(l)&&l>Date.now()?l:null;let r=s("releasenote");r.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,l=this.sectionLabelById.get(o)??"Other seats",r=this.doc?.objects.find(h=>h.id===i.rowId),c=r?.type==="row"||r?.type==="table"?r.label:"";if(!`${s} ${a} ${l} ${c}`.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 l=this.els.selblocked;l.disabled=t.length===0,l.textContent=a?`Remove ${t.length.toLocaleString()} results`:`Select ${t.length.toLocaleString()} results`;let r=new Map;for(let h of t){let p=r.get(h.rowId)??[];p.push(h),r.set(h.rowId,p)}this.els.blockedshowing.textContent=`${t.length.toLocaleString()} seats \xB7 ${r.size} rows`,this.els.blockedlist.innerHTML=[...r.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>
|
|
896
|
+
<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>',r.size>this.blockedResultLimit&&(this.els.blockedlist.innerHTML+="<button data-blocked-more>Show more rows</button>");let c=this.els.markall,d=c.dataset.confirm==="true";c.disabled=e===0,c.textContent=d?`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{Xe as ACCESS_LINK_DEFAULTS,at as ChannelsMode,F as ManageApi,k as ManageApiError,ze as PUBLIC_CHANNEL_ID,Ie as PUBLIC_CHANNEL_NAME,q as SeatManager,Ge as accessIntentDescription,We as accessIntentLabel,Ue as accessLine,Qe as accessLinkBadge,tt as accessLinkErrorCopy,Je as accessLinkIsLive,et as accessLinkPolicyLines,_e as bucketRows,ot as bucketRowsHtml,st as dropReviewRows,Ze as intentForbidsCopy,Ye as intentSwitchBlockedCopy,Fe as isPublicChannelId,Oe as markerLetter,Ve as markerOf,qe as mutationCount,Ne as needsMoveConfirmation,je as planAssignment,Ke as retryAfterCopy,Pe as selectionSources,it as stateBadge,De as suggestMarker};
|