@seatlayer/js 0.93.0 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{channelsMode-B41tbE29.d.cts → channelsMode-DYwJ6sfR.d.cts} +200 -27
- package/dist/{channelsMode-B41tbE29.d.ts → channelsMode-DYwJ6sfR.d.ts} +200 -27
- package/dist/channelsMode-YJO6FOPD.js +1 -0
- package/dist/{chunk-5VGXB6GJ.js → chunk-DR5JXWLO.js} +208 -228
- package/dist/chunk-JELR6YYZ.js +1 -0
- package/dist/index.cjs +18 -18
- package/dist/index.d.cts +81 -25
- package/dist/index.d.ts +81 -25
- package/dist/index.js +19 -19
- package/dist/manager.cjs +516 -340
- package/dist/manager.d.cts +2 -2
- package/dist/manager.d.ts +2 -2
- package/dist/manager.js +316 -120
- package/package.json +2 -2
- package/dist/channelsMode-KZU235GN.js +0 -1
package/dist/manager.cjs
CHANGED
|
@@ -1,25 +1,124 @@
|
|
|
1
|
-
"use strict";var He=Object.defineProperty;var zt=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var qt=Object.prototype.hasOwnProperty;var _=(l,e,t)=>()=>{if(t)throw t[0];try{return l&&(e=l(l=0)),e}catch(s){throw t=[s],s}};var Ke=(l,e)=>{for(var t in e)He(l,t,{get:e[t],enumerable:!0})},Nt=(l,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ft(e))!qt.call(l,n)&&n!==t&&He(l,n,{get:()=>e[n],enumerable:!(s=zt(e,n))||s.enumerable});return l};var _t=l=>Nt(He({},"__esModule",{value:!0}),l);function ie(l){l.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dataset.themed="true";let t=document.createElement("details");t.className="slm-themed-picker";let s=document.createElement("summary"),n=document.createElement("div");n.className="slm-themed-options";let i=e.getAttribute("aria-label")||Array.from(e.labels??[]).map(o=>o.textContent).join(" ")||"Choose option";s.setAttribute("aria-label",i.trim()),t.append(s,n),e.after(t),e.hidden=!0;let a=()=>{s.textContent=e.selectedOptions[0]?.textContent??"Choose\u2026",s.setAttribute("aria-disabled",String(e.disabled)),n.replaceChildren(...Array.from(e.options).map(o=>{let r=document.createElement("button");return r.type="button",r.textContent=o.textContent,r.setAttribute("aria-label",o.textContent??""),r.disabled=e.disabled||o.disabled,r.setAttribute("aria-pressed",String(o.selected)),r.onclick=()=>{e.value=o.value,t.open=!1,a(),s.focus(),e.dispatchEvent(new Event("change",{bubbles:!0})),a()},r}))};a(),e.addEventListener("change",a),s.onclick=o=>{if(e.disabled){o.preventDefault();return}a(),l.querySelectorAll(".slm-themed-picker").forEach(r=>{r!==t&&(r.open=!1)})},t.addEventListener("focusout",o=>{t.contains(o.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",o=>{if(o.key==="Escape"&&(o.preventDefault(),o.stopPropagation(),t.open=!1,s.focus()),o.key==="ArrowDown"||o.key==="ArrowUp"){if(e.disabled)return;o.preventDefault(),t.open=!0;let r=Array.from(n.querySelectorAll("button:not(:disabled)")),d=r.indexOf(document.activeElement);r[(d+(o.key==="ArrowDown"?1:r.length-1)+r.length)%r.length]?.focus()}})})}var Pe=_(()=>{"use strict"});async function We(l){let t=(l.headers.get("content-type")??"").includes("application/json")?await l.json().catch(()=>null):null;if(!l.ok){let s=t;throw new x(l.status,s?.error??`request_failed_${l.status}`,s?.code,s?.conflicts,s?.details,typeof s?.message=="string"?s.message:void 0)}return t}function $(l){return l&&typeof l=="object"?l:{}}function re(l,e,t=0){return typeof l=="number"&&Number.isFinite(l)?l:typeof e=="number"&&Number.isFinite(e)?e:t}function Xe(l,e){return l===null?null:typeof l=="number"&&Number.isFinite(l)?l:l!==void 0?null:typeof e=="number"&&Number.isFinite(e)?e:null}function Ze(l){let e=$(l),t=re(e.bookedValue,e.bookedRevenue);return{...e,bookedValue:t,bookedRevenue:t}}function Vt(l){let e=$(l),t=$(e.report),s=Array.isArray(t.byCategory)?t.byCategory.map(i=>{let a=$(i),o=re(a.bookedValue,a.bookedRevenue);return{...a,bookedValue:o,bookedRevenue:o}}):[],n=Array.isArray(t.bySection)?t.bySection.map(Ze):void 0;return{...e,report:{...t,byCategory:s,...n?{bySection:n}:{}}}}function Ut(l){let e=$(l),t=$(e.bookedValue),s=$(e.revenue),n=Object.keys(t).length?t:s,i=Array.isArray(t.bySection)?t.bySection:Array.isArray(s.bySection)?s.bySection:[],a={...n,gross:re(t.gross,s.gross),bySection:i.map(Ze)},o=$(e.velocity),r=Array.isArray(o.bySection)?o.bySection.map(d=>{let c=$(d),h=re(c.bookedValue,c.grossRevenue);return{...c,bookedValue:h,grossRevenue:h}}):[];return{...e,bookedValue:a,revenue:a,velocity:{...o,bySection:r}}}function Kt(l){let e=$(l),t=$(e.report),s=typeof t.includesBookedValue=="boolean"?t.includesBookedValue:t.includesRevenue===!0,n=Array.isArray(t.rows)?t.rows.map(o=>{let r=$(o),d=$(r.attribution),c=Xe(d.bookedValue,d.revenue);return{...r,attribution:{...d,bookedValue:c,revenue:c}}}):[],i=$(t.totals),a=Xe(i.bookedValue,i.revenue);return{...e,report:{...t,includesBookedValue:s,includesRevenue:s,rows:n,totals:{...i,bookedValue:a,revenue:a}}}}function Be(l){let e=$(l),t=typeof e.includesBookedValue=="boolean"?e.includesBookedValue:e.includesRevenue===!0;return{...e,includesBookedValue:t,includesRevenue:t}}var x,K,ce=_(()=>{"use strict";x=class extends Error{constructor(e,t,s,n,i,a){super(t),this.name="ManageApiError",this.status=e,this.code=s,this.conflicts=n,this.details=i,this.serverMessage=a}};K=class{constructor(e,t){this.base=e.replace(/\/+$/,""),this.token=t}setToken(e){this.token=e}auth(e,t={}){let s=t.method??"GET",n={Authorization:`Bearer ${this.token}`},i;return t.body!==void 0&&(n["Content-Type"]="application/json",i=JSON.stringify(t.body)),fetch(`${this.base}${e}`,{method:s,headers:n,body:i,credentials:"omit"}).then(a=>We(a))}async authBlob(e){let t=await fetch(`${this.base}${e}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});return t.ok||await We(t),t.blob()}chart(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/chart`)}asset(e,t){return/^[a-zA-Z0-9._-]+$/.test(t)?this.authBlob(`/v1/events/${encodeURIComponent(e)}/assets/${encodeURIComponent(t)}`):Promise.reject(new x(404,"not_found","not_found"))}objects(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/objects`)}subscribeTicket(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/subscribe-tickets`,{method:"POST"})}socketUrl(e){return`${this.base.replace(/^http/,"ws")}/pub/events/${encodeURIComponent(e)}/subscribe?surface=manager`}block(e,t,s={}){let n={labels:t};return typeof s.releaseAt=="number"&&(n.releaseAt=s.releaseAt),s.reason&&(n.reason=s.reason),this.auth(`/v1/events/${encodeURIComponent(e)}/block`,{method:"POST",body:n})}unblock(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock`,{method:"POST",body:{labels:t}})}unblockAll(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock-all`,{method:"POST"})}unbook(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/unbook`,{method:"POST",body:{labels:t,bookingRef:s}})}setHoldTtl(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/hold-ttl`,{method:"POST",body:{holdTtlMs:t}})}setCategory(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`,{method:"POST",body:{labels:t,categoryKey:s}})}setTableBooking(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/table-booking`,{method:"POST",body:{tableIds:t,mode:s,...n}})}bookings(e,t={}){let s=new URLSearchParams;t.q&&s.set("q",t.q),t.state&&s.set("state",t.state),t.cursor&&s.set("cursor",t.cursor),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings${n?`?${n}`:""}`)}booking(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings/${encodeURIComponent(t)}`)}listBookings(e,t={}){return this.bookings(e,t)}retrieveBooking(e,t){return this.booking(e,t)}availability(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`)}setAvailability(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`,{method:"POST",body:{rules:t}})}channels(e,t={}){let s=t.includeArchived?"?includeArchived=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels${s}`)}channelAllocation(e,t={}){let s=new URLSearchParams;t.afterLabel&&s.set("afterLabel",t.afterLabel),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/allocation${n?`?${n}`:""}`)}channelAudit(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/audit${n?`?${n}`:""}`)}createChannel(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels`,{method:"POST",body:t})}renameChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{name:s}})}updateChannelPricing(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{priceOverrides:s,expectedPricingVersion:n}})}setChannelPaused(e,t,s){let n=s?"pause":"unpause";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/${n}`,{method:"POST",body:{}})}archiveChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/archive`,{method:"POST",body:{destination:s}})}applyChannelAssignment(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/assignments`,{method:"POST",body:{targetChannelId:t.targetChannelId||null,labels:t.labels,assignmentVersion:t.assignmentVersion}})}channelPreview(e,t,s={}){let n=new URLSearchParams;t.length&&n.set("channelIds",t.join(",")),s.includePublic!=null&&n.set("includePublic",s.includePublic?"1":"0");let i=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/preview${i?`?${i}`:""}`)}setChannelAccessIntent(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{accessIntent:s,...n.acknowledgeLiveAccess?{acknowledgeLiveAccess:!0}:{},...n.reason?{reason:n.reason}:{}}})}createAccessLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`,{method:"POST",body:s})}accessLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`)}rotateAccessLink(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}/rotate`,{method:"POST",body:{endActiveSessions:n}})}revokeAccessLink(e,t,s,n=!1){let i=n?"?endActiveSessions=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}${i}`,{method:"DELETE"})}report(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/report`).then(Vt)}seatHistory(e,t,s,n){let i=new URLSearchParams({label:t});return s&&i.set("before",String(s)),n&&i.set("action",n),this.auth(`/v1/events/${encodeURIComponent(e)}/seat-history?${i}`)}controlRoom(e,t=15){return this.auth(`/v1/events/${encodeURIComponent(e)}/control-room?window=${t}`).then(Ut)}channelReport(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/report`).then(Kt)}createChannelReportLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`,{method:"POST",body:s}).then(n=>{let i=$(n);return{...i,link:Be(i.link)}})}channelReportLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`).then(s=>{let n=$(s);return{links:Array.isArray(n.links)?n.links.map(Be):[]}})}revokeChannelReportLink(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links/${encodeURIComponent(s)}`,{method:"DELETE"}).then(n=>{let i=$(n);return{...i,link:Be(i.link)}})}log(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/log${n?`?${n}`:""}`)}async reportCsv(e){let t=await fetch(`${this.base}/v1/events/${encodeURIComponent(e)}/report.csv`,{headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});if(!t.ok)throw new x(t.status,`request_failed_${t.status}`);return t.blob()}}});function D(l){return l==null||l===""||l===T}function z(l,e){let t=(l??"").trim();return((/\p{L}/u.exec(t)?.[0]??t[0]??"")||e).toUpperCase().slice(0,1)}function J(l,e){let t=new Set([...e].map(i=>z(i,"")).filter(Boolean)),s=z(l,"");return{letter:gt.includes(s)&&!t.has(s)?s:[...gt].find(i=>!t.has(i))??(s||"X"),color:ve[t.size%ve.length]}}function fe(l,e=0){return D(l.id)?{letter:z(l.marker,"P"),color:l.color||Jt}:{letter:z(l.marker||l.name,"?"),color:l.color||ve[e%ve.length]}}function ye(l,e,t){let s=new Map;for(let a of l){let o=Ne(e.get(a));s.set(o,(s.get(o)??0)+1)}let n=[{id:T,name:t?.publicSale?.name??M},...(t?.channels??[]).map(a=>({id:a.id,name:a.name}))],i=[];for(let a of n){let o=s.get(a.id);o&&i.push({channelId:a.id,name:a.name,count:o}),s.delete(a.id)}for(let[a,o]of s)i.push({channelId:a,name:D(a)?M:"Another channel",count:o});return i}function Ne(l){return D(l)?T:l}function qe(l){return{count:l.length,labels:l.slice(0,vt),truncated:l.length>vt}}function ke(l){let{labels:e,allocation:t,statusOf:s,nameOf:n}=l,i=Ne(l.targetChannelId),a=new Set,o=0,r=0,d=new Map,c=[],h=[],u=[];for(let v of e){if(a.has(v))continue;a.add(v);let g=s(v);if(!g){u.push(v);continue}let m=Ne(t.get(v));if(m===i){r+=1;continue}if(g==="held"){c.push(v);continue}if(g==="booked"){h.push(v);continue}m===T?o+=1:d.set(m,(d.get(m)??0)+1)}let f=[...d.entries()].map(([v,g])=>({channelId:v,name:n(v),count:g}));return{changedFromPublic:{count:o},movedFromOtherChannel:{count:f.reduce((v,g)=>v+g.count,0),channels:f},alreadyInTarget:{count:r},skippedHeld:qe(c),skippedBooked:qe(h),notFound:qe(u)}}function Y(l){return l.changedFromPublic.count+l.movedFromOtherChannel.count}function xe(l){return l.movedFromOtherChannel.count>0}function we(l,e){let t=[];l.changedFromPublic.count&&t.push({kind:"add",icon:"+",count:l.changedFromPublic.count,text:`${l.changedFromPublic.count.toLocaleString()} from ${M}`});for(let s of l.movedFromOtherChannel.channels)t.push({kind:"move",icon:"\u21C4",count:s.count,text:`${s.count.toLocaleString()} moved out of ${s.name??"another channel"}`,why:"needs this confirmation"});return l.alreadyInTarget.count&&t.push({kind:"same",icon:"=",count:l.alreadyInTarget.count,text:`${l.alreadyInTarget.count.toLocaleString()} already in ${e}`,why:"unchanged"}),l.skippedHeld.count&&t.push({kind:"skip",icon:"\u23F8",count:l.skippedHeld.count,text:`${l.skippedHeld.count.toLocaleString()} in a buyer's checkout`,why:"can't move while held",peek:ge(l.skippedHeld)}),l.skippedBooked.count&&t.push({kind:"skip",icon:"\u{1F512}",count:l.skippedBooked.count,text:`${l.skippedBooked.count.toLocaleString()} already sold`,why:"sales are never rewritten",peek:ge(l.skippedBooked)}),l.notFound.count&&t.push({kind:"skip",icon:"?",count:l.notFound.count,text:`${l.notFound.count.toLocaleString()} not on this map`,why:"these seats are no longer part of the event",peek:ge(l.notFound)}),t}function ge(l){if(!l.labels.length)return;let e=l.labels.slice(0,4).join(", ");return l.truncated||l.labels.length>4?`${e}\u2026`:e}function Se(l){let e=l?.retryAfterMs??(l?.latestHoldExpiresAt?Math.max(0,l.latestHoldExpiresAt-Date.now()):0);if(!e)return"in a moment";let t=Math.ceil(e/6e4);return t<=1?"in about a minute":`in about ${t} minutes`}function Le(l){if(!l||!l.intent)return"\u2014";let e=l.intent==="server"?"Website integration":l.intent==="hosted_link"?"Buyer link":l.intent==="internal"?"Your staff sell these":"Protected reserve",t=l.hasActiveGrants?"in use now":l.lastMintAt?`last used ${new Date(l.lastMintAt).toLocaleDateString()}`:null,s=l.detail??t;return s?`${e} \xB7 ${s}`:e}function F(l){return l==="internal"?"Sell through your own staff":l==="server"?"Integrate a website or app":l==="hosted_link"?"Sell with a buyer link":"Keep as protected reserve"}function Ce(l){switch(l){case"internal":return"Only your own box office can sell these seats, through your secret key. Buyer links and website integrations are refused.";case"server":return"Your website's backend mints each buyer a short-lived session for these seats. Buyer links are refused; the code lives on the Embed page.";case"hosted_link":return"SeatLayer makes a link you send to a named group. They open it and buy only these seats. No other route can sell them.";default:return"Nobody can buy these seats. Every way of letting a buyer in \u2014 a buyer link, your website, even your own staff \u2014 is refused while this is the route. The seats stay out of public sale."}}function es(l){return l==="hosted_link"?"hosted_link":l==="server"?"server":l==="staff"?"internal":null}function G(l){let e=_e(l?.accessIntent),t=es(l?.route),s=`This channel is set to "${F(e)}"`;return t?`${s}, so it cannot do that. Switch it to "${F(t)}" first.`:`${s}, so it cannot do that. Choose a different route for this channel first.`}function _e(l){return l==="internal"||l==="server"||l==="hosted_link"||l==="none"?l:"none"}function be(l,e,t){return`${l.toLocaleString()} ${l===1?e:t}`}function Te(l){let e=Math.max(0,l?.liveAccessLinks??0),t=Math.max(0,l?.activeSessions??0),s=_e(l?.from),n=_e(l?.to),a=`${[e?be(e,"buyer link is live","buyer links are live"):null,t?be(t,"buyer is in a checkout","buyers are in a checkout"):null].filter(Boolean).join(", and ")||"Buyers are inside this channel"} on "${F(s)}". Moving it to "${F(n)}" changes what happens to them.`,o=[];return e&&o.push(`${be(e,"buyer link closes","buyer links close")} immediately. Anyone who has not opened it yet never will \u2014 send a new link if you still need one.`),t&&o.push(`${be(t,"buyer who is already in a checkout keeps","buyers who are already in a checkout keep")} their seats and can finish paying. Nobody is thrown out. No new buyers come in this way, so the old route empties on its own within 12 hours.`),{headline:a,consequences:o}}function Re(l){switch(l.status??l.state){case"active":return{text:"Active",kind:"active"};case"expired":return{text:"Expired",kind:"archived"};case"exhausted":return{text:"All used",kind:"paused"};case"rotated":return{text:"Replaced",kind:"archived"};default:return{text:"Revoked",kind:"archived"}}}function te(l){return l.state==="active"&&l.status==="active"}function ts(l){return Number.isFinite(l)?new Date(l).toLocaleString(void 0,{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):"\u2014"}function se(l){return[{k:"Expires",v:ts(l.expiresAt)},{k:"Redemptions",v:`${l.redemptions.toLocaleString()} of ${l.maxRedemptions.toLocaleString()} used`},{k:"Seats per buyer",v:`${l.maxQuantity.toLocaleString()} seat${l.maxQuantity===1?"":"s"} maximum`},{k:"Covers",v:l.includePublic?"This channel's allocation and Public sale seats":"This channel's allocation only"}]}function j(l){let e=l?.serverMessage?.trim();switch(l?.code){case"invalid_expiry":case"invalid_max_redemptions":case"invalid_max_quantity":case"invalid_session_ttl":case"invalid_label":return e||"That setting is outside what a hosted link allows. Adjust it and try again.";case"too_many_access_links":return e||"This channel already has as many live links as it can hold. Revoke one before creating another.";case"access_link_not_active":return"That link is no longer active, so it cannot be rotated or revoked.";case"channel_unavailable":return"This channel is paused or archived, so it cannot let new buyers in. Resume it first.";case"channel_access_intent_forbids":return G(l?.details);case"end_active_sessions_required":return"Choose what happens to the buyers who already came in through this link.";case"not_found":return"That link is no longer here. Refresh and try again.";default:return l?.status===403?"Hosted access links need channel-management permission.":e||"That did not go through. Try again."}}function ft(l){return(l?.channels??[]).map(e=>({kind:"skip",icon:"\u26A0",count:e.count,text:`${e.count.toLocaleString()} would leave ${e.name??"a channel"}`,why:"the new chart no longer has these seats",peek:e.labels?.length?ge({count:e.count,labels:e.labels,truncated:e.truncated??!1}):void 0}))}function $e(l){return l==="builtin"?"Built-in":l==="active"?"Active":l==="paused"?"Paused":"Archived"}var T,M,ve,Jt,gt,vt,ee,Ee=_(()=>{"use strict";T="public",M="Public sale";ve=["#a78bfa","#2dd4bf","#fb923c","#60a5fa","#f472b6","#a3e635","#f87171","#38bdf8","#c084fc","#facc15"],Jt="#f4b740",gt="ABCDEFGHJKLMNPQRSTUVWXYZ";vt=12;ee={maxRedemptions:100,maxQuantity:4}});function W(l){return l.map((e,t)=>`
|
|
1
|
+
"use strict";var _e=Object.defineProperty;var ys=Object.getOwnPropertyDescriptor;var xs=Object.getOwnPropertyNames;var ks=Object.prototype.hasOwnProperty;var z=(o,e,t)=>()=>{if(t)throw t[0];try{return o&&(e=o(o=0)),e}catch(s){throw t=[s],s}};var it=(o,e)=>{for(var t in e)_e(o,t,{get:e[t],enumerable:!0})},ws=(o,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of xs(e))!ks.call(o,n)&&n!==t&&_e(o,n,{get:()=>e[n],enumerable:!(s=ys(e,n))||s.enumerable});return o};var Ss=o=>ws(_e({},"__esModule",{value:!0}),o);function W(o){o.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dataset.themed="true";let t=document.createElement("details");t.className="slm-themed-picker";let s=document.createElement("summary"),n=document.createElement("div");n.className="slm-themed-options";let i=e.getAttribute("aria-label")||Array.from(e.labels??[]).map(l=>l.textContent).join(" ")||"Choose option";s.setAttribute("aria-label",i.trim()),t.append(s,n),e.after(t),e.hidden=!0;let a=()=>{s.textContent=e.selectedOptions[0]?.textContent??"Choose\u2026",s.setAttribute("aria-disabled",String(e.disabled)),n.replaceChildren(...Array.from(e.options).map(l=>{let r=document.createElement("button");return r.type="button",r.textContent=l.textContent,r.setAttribute("aria-label",l.textContent??""),r.disabled=e.disabled||l.disabled,r.setAttribute("aria-pressed",String(l.selected)),r.onclick=()=>{e.value=l.value,t.open=!1,a(),s.focus(),e.dispatchEvent(new Event("change",{bubbles:!0})),a()},r}))};a(),e.addEventListener("change",a),s.onclick=l=>{if(e.disabled){l.preventDefault();return}a(),o.querySelectorAll(".slm-themed-picker").forEach(r=>{r!==t&&(r.open=!1)})},t.addEventListener("focusout",l=>{t.contains(l.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",l=>{if(l.key==="Escape"&&(l.preventDefault(),l.stopPropagation(),t.open=!1,s.focus()),l.key==="ArrowDown"||l.key==="ArrowUp"){if(e.disabled)return;l.preventDefault(),t.open=!0;let r=Array.from(n.querySelectorAll("button:not(:disabled)")),c=r.indexOf(document.activeElement);r[(c+(l.key==="ArrowDown"?1:r.length-1)+r.length)%r.length]?.focus()}})})}function at(o){o.querySelectorAll('input[type="date"],input[type="datetime-local"],input[type="time"]').forEach(e=>{e.dataset.slmPicker!=="1"&&(e.dataset.slmPicker="1",e.addEventListener("click",()=>{if(!(e.disabled||e.readOnly))try{e.showPicker?.()}catch{}}))})}var re=z(()=>{"use strict"});async function rt(o){let t=(o.headers.get("content-type")??"").includes("application/json")?await o.json().catch(()=>null):null;if(!o.ok){let s=t;throw new w(o.status,s?.error??`request_failed_${o.status}`,s?.code,s?.conflicts,s?.details,typeof s?.message=="string"?s.message:void 0)}return t}function A(o){return o&&typeof o=="object"?o:{}}function me(o,e,t=0){return typeof o=="number"&&Number.isFinite(o)?o:typeof e=="number"&&Number.isFinite(e)?e:t}function ct(o,e){return o===null?null:typeof o=="number"&&Number.isFinite(o)?o:o!==void 0?null:typeof e=="number"&&Number.isFinite(e)?e:null}function dt(o){let e=A(o),t=me(e.bookedValue,e.bookedRevenue);return{...e,bookedValue:t,bookedRevenue:t}}function Cs(o){let e=A(o),t=A(e.report),s=Array.isArray(t.byCategory)?t.byCategory.map(i=>{let a=A(i),l=me(a.bookedValue,a.bookedRevenue);return{...a,bookedValue:l,bookedRevenue:l}}):[],n=Array.isArray(t.bySection)?t.bySection.map(dt):void 0;return{...e,report:{...t,byCategory:s,...n?{bySection:n}:{}}}}function Ts(o){let e=A(o),t=A(e.bookedValue),s=A(e.revenue),n=Object.keys(t).length?t:s,i=Array.isArray(t.bySection)?t.bySection:Array.isArray(s.bySection)?s.bySection:[],a={...n,gross:me(t.gross,s.gross),bySection:i.map(dt)},l=A(e.velocity),r=Array.isArray(l.bySection)?l.bySection.map(c=>{let d=A(c),h=me(d.bookedValue,d.grossRevenue);return{...d,bookedValue:h,grossRevenue:h}}):[];return{...e,bookedValue:a,revenue:a,velocity:{...l,bySection:r}}}function Ms(o){let e=A(o),t=A(e.report),s=typeof t.includesBookedValue=="boolean"?t.includesBookedValue:t.includesRevenue===!0,n=Array.isArray(t.rows)?t.rows.map(l=>{let r=A(l),c=A(r.attribution),d=ct(c.bookedValue,c.revenue);return{...r,attribution:{...c,bookedValue:d,revenue:d}}}):[],i=A(t.totals),a=ct(i.bookedValue,i.revenue);return{...e,report:{...t,includesBookedValue:s,includesRevenue:s,rows:n,totals:{...i,bookedValue:a,revenue:a}}}}function Ne(o){let e=A(o),t=typeof e.includesBookedValue=="boolean"?e.includesBookedValue:e.includesRevenue===!0;return{...e,includesBookedValue:t,includesRevenue:t}}var w,Y,pe=z(()=>{"use strict";w=class extends Error{constructor(e,t,s,n,i,a){super(t),this.name="ManageApiError",this.status=e,this.code=s,this.conflicts=n,this.details=i,this.serverMessage=a}};Y=class{constructor(e,t){this.base=e.replace(/\/+$/,""),this.token=t}setToken(e){this.token=e}auth(e,t={}){let s=t.method??"GET",n={Authorization:`Bearer ${this.token}`},i;return t.body!==void 0&&(n["Content-Type"]="application/json",i=JSON.stringify(t.body)),fetch(`${this.base}${e}`,{method:s,headers:n,body:i,credentials:"omit"}).then(a=>rt(a))}async authBlob(e){let t=await fetch(`${this.base}${e}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});return t.ok||await rt(t),t.blob()}chart(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/chart`)}asset(e,t){return/^[a-zA-Z0-9._-]+$/.test(t)?this.authBlob(`/v1/events/${encodeURIComponent(e)}/assets/${encodeURIComponent(t)}`):Promise.reject(new w(404,"not_found","not_found"))}objects(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/objects`)}subscribeTicket(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/subscribe-tickets`,{method:"POST"})}socketUrl(e){return`${this.base.replace(/^http/,"ws")}/pub/events/${encodeURIComponent(e)}/subscribe?surface=manager`}block(e,t,s={}){let n={labels:t};return typeof s.releaseAt=="number"&&(n.releaseAt=s.releaseAt),s.reason&&(n.reason=s.reason),this.auth(`/v1/events/${encodeURIComponent(e)}/block`,{method:"POST",body:n})}unblock(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock`,{method:"POST",body:{labels:t}})}unblockAll(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/unblock-all`,{method:"POST"})}unbook(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/unbook`,{method:"POST",body:{labels:t,bookingRef:s}})}setHoldTtl(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/hold-ttl`,{method:"POST",body:{holdTtlMs:t}})}setCategory(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`,{method:"POST",body:{labels:t,categoryKey:s}})}categoryDifferences(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`)}resetCategoriesToChart(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`,{method:"POST",body:{mode:"chart",...t?{labels:t}:{}}})}setTableBooking(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/table-booking`,{method:"POST",body:{tableIds:t,mode:s,...n}})}bookings(e,t={}){let s=new URLSearchParams;t.q&&s.set("q",t.q),t.state&&s.set("state",t.state),t.cursor&&s.set("cursor",t.cursor),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings${n?`?${n}`:""}`)}booking(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings/${encodeURIComponent(t)}`)}listBookings(e,t={}){return this.bookings(e,t)}retrieveBooking(e,t){return this.booking(e,t)}availability(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`)}setAvailability(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/availability`,{method:"POST",body:{rules:t}})}channels(e,t={}){let s=t.includeArchived?"?includeArchived=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels${s}`)}channelAllocation(e,t={}){let s=new URLSearchParams;t.afterLabel&&s.set("afterLabel",t.afterLabel),t.limit!=null&&s.set("limit",String(t.limit));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/allocation${n?`?${n}`:""}`)}channelAudit(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/audit${n?`?${n}`:""}`)}createChannel(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels`,{method:"POST",body:t})}renameChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{name:s}})}updateChannelPricing(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{priceOverrides:s,expectedPricingVersion:n}})}setChannelPaused(e,t,s){let n=s?"pause":"unpause";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/${n}`,{method:"POST",body:{}})}archiveChannel(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/archive`,{method:"POST",body:{destination:s}})}applyChannelAssignment(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/assignments`,{method:"POST",body:{targetChannelId:t.targetChannelId||null,labels:t.labels,assignmentVersion:t.assignmentVersion}})}channelPreview(e,t,s={}){let n=new URLSearchParams;t.length&&n.set("channelIds",t.join(",")),s.includePublic!=null&&n.set("includePublic",s.includePublic?"1":"0");let i=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/preview${i?`?${i}`:""}`)}setChannelAccessIntent(e,t,s,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{accessIntent:s,...n.acknowledgeLiveAccess?{acknowledgeLiveAccess:!0}:{},...n.reason?{reason:n.reason}:{}}})}createAccessLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`,{method:"POST",body:s})}accessLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`)}rotateAccessLink(e,t,s,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}/rotate`,{method:"POST",body:{endActiveSessions:n}})}revokeAccessLink(e,t,s,n=!1){let i=n?"?endActiveSessions=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(s)}${i}`,{method:"DELETE"})}report(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/report`).then(Cs)}seatHistory(e,t,s,n){let i=new URLSearchParams({label:t});return s&&i.set("before",String(s)),n&&i.set("action",n),this.auth(`/v1/events/${encodeURIComponent(e)}/seat-history?${i}`)}controlRoom(e,t=15){return this.auth(`/v1/events/${encodeURIComponent(e)}/control-room?window=${t}`).then(Ts)}channelReport(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/report`).then(Ms)}createChannelReportLink(e,t,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`,{method:"POST",body:s}).then(n=>{let i=A(n);return{...i,link:Ne(i.link)}})}channelReportLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`).then(s=>{let n=A(s);return{links:Array.isArray(n.links)?n.links.map(Ne):[]}})}revokeChannelReportLink(e,t,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links/${encodeURIComponent(s)}`,{method:"DELETE"}).then(n=>{let i=A(n);return{...i,link:Ne(i.link)}})}log(e,t={}){let s=new URLSearchParams;t.limit!=null&&s.set("limit",String(t.limit)),t.before!=null&&s.set("before",String(t.before));let n=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/log${n?`?${n}`:""}`)}async reportCsv(e){let t=await fetch(`${this.base}/v1/events/${encodeURIComponent(e)}/report.csv`,{headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});if(!t.ok)throw new w(t.status,`request_failed_${t.status}`);return t.blob()}}});function Is(){try{return window.matchMedia?.("(prefers-color-scheme: dark)").matches===!0}catch{return!1}}function Ue(o){if(o)return o==="auto"?Is()?"dark":"light":o}function vt(o){let e;try{e=window.matchMedia?.("(prefers-color-scheme: dark)")}catch{return()=>{}}if(!e)return()=>{};let t=s=>o(s.matches);return typeof e.addEventListener=="function"?e.addEventListener("change",t):e.addListener?.(t),()=>{typeof e.removeEventListener=="function"?e.removeEventListener("change",t):e.removeListener?.(t)}}var ft,je,Ke=z(()=>{"use strict";ft=require("@seatlayer/core/core/color"),je={light:{background:"#ffffff",surface:"#f6f7fb",text:"#172033",muted:"#667085",line:"rgba(23,32,51,.16)",map:"#e9edf4"},dark:{background:"#0f1522",surface:"#1a2234",text:"#eef1f8",muted:"#a5aec2",line:"rgba(165,174,194,.24)",map:"#0f1522"}}});function xt(o){return o?o.mode:"open"}function kt(o,e,t){switch(o){case"open":return null;case"hidden":return{mode:"hidden",labels:e};case"closed":return{mode:"closed",labels:e};case"timed":return{mode:"timed",revealAt:t?.revealAt??Date.now()+36e5,labels:e};case"threshold":return{mode:"threshold",thresholdPct:t?.thresholdPct??80,labels:e}}}function wt(o){return new Date(o-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}function St(o){if(typeof o=="string"){let e=document.querySelector(o);if(!e)throw new Error(`seatmanager: container "${o}" not found`);return e}if(!(o instanceof HTMLElement))throw new Error("seatmanager: container must be a CSS selector or an HTMLElement");return o}function We(o){if(!o.startsWith("mse_"))throw new Error("seatmanager: token must be a short-lived event-scoped mse_ grant minted by your backend; tenant secret keys are unsupported in browsers")}function ge(o){return o==="blocked"?"not_for_sale":o}function Tt(o,e){let t=o??{},s=e?je[e]:null,n=e==="light";return{"--slm-bg":t.background??s?.background??"#0e1017","--slm-surface":s?.surface??"#181b24","--slm-text":s?.text??"#eef1f7","--slm-muted":s?.muted??"#8b93a7","--slm-line":s?.line??"rgba(255,255,255,.09)","--slm-tint":n?"rgba(23,32,51,.05)":"rgba(255,255,255,.035)","--slm-tint-strong":n?"rgba(23,32,51,.09)":"rgba(255,255,255,.07)","--slm-accent":t.accent??(n?"#4654c8":"#6e7bff"),"--slm-accent-ink":t.accentInk??"#ffffff","--slm-font":"-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif","--slm-radius":"14px"}}function Mt(o){return o?je[o].map:null}function Et(o,e){let t=Math.max(0,Math.round((e-o)/1e3));if(t<5)return"just now";if(t<60)return`${t}s ago`;let s=Math.round(t/60);return s<60?`${s}m ago`:`${Math.round(s/60)}h ago`}function fe(o,e){return(0,yt.formatMoney)(o,e,{maximumFractionDigits:0,fallback:(t,s)=>`${s} ${Math.round(t).toLocaleString()}`})}function b(o){return String(o??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var yt,Hs,H,be,Lt,Ct,ve=z(()=>{"use strict";yt=require("@seatlayer/core");Ke();Hs=["free","booked","held","blocked"],H={free:"#6e7bff",booked:"#9ca3af",held:"#f4b740",blocked:"#475569"},be={free:"Free",booked:"Sold",held:"Held",blocked:"Blocked"},Lt=[`<span class="slm-legmark" style="background:${H.free}"></span> Free = category colour`,`<span class="slm-legmark" style="background:${H.booked}"></span> ${be.booked}`,`<span class="slm-legmark" style="background:${H.held}"></span> ${be.held}`,`<span class="slm-legcross" style="color:${H.blocked}">\u2715</span> ${be.blocked}`].join(" \xB7 "),Ct=Hs.map(o=>({key:o,label:be[o],color:H[o]}))});function Bs(o,e){if(!o.labels.length)return"Nothing found";let t=[];o.sections&&t.push(`${o.sections.toLocaleString()} section${o.sections===1?"":"s"}`),o.rows&&t.push(`${o.rows.toLocaleString()} row${o.rows===1?"":"s"}`);let s=`${o.labels.length.toLocaleString()} seat${o.labels.length===1?"":"s"} found`,n=t.length?`${t.join(" \xB7 ")} \xB7 ${s}`:s;return e?`${n} \xB7 Enter to ${e==="frame"?"show":"select"}`:n}function xe(o={}){return`
|
|
2
|
+
<div class="slm-find${o.compact?" slm-find-bar":""}" data-ch-find>
|
|
3
|
+
<input type="search" class="slm-input" data-ch-find-input placeholder="Find seat, row or section" aria-label="Find seat, row or section" autocomplete="off"${o.compact?' aria-keyshortcuts="/"':""}>
|
|
4
|
+
<span class="slm-find-count" data-ch-find-count role="status"></span>
|
|
5
|
+
</div>`}function Rt(o,e){return o.toLocaleLowerCase().split(/\s+/).some(t=>e.length>=2?t.startsWith(e):t===e)}function Ds(o,e){let t=o.trim().toLocaleLowerCase();if(!t)return{labels:[],seats:0,rows:0,sections:0};let s=new Set,n=0,i=0;for(let d of e.sections)if(Rt(d.label,t)){n+=1;for(let h of d.labels)s.add(h)}let a=t.split(/\s+/),l=a[a.length-1],r=a.slice(0,-1).join(" ");for(let d of e.rows)if(d.label.toLocaleLowerCase()===l&&!(r&&!Rt(d.sectionLabel,r))){i+=1;for(let h of d.labels)s.add(h)}let c=0;for(let d of e.seatLabels){let h=d.toLocaleLowerCase();(h===t||h.startsWith(`${t}-`))&&(s.has(d)||(c+=1),s.add(d))}return{labels:[...s],seats:c,rows:i,sections:n}}function $t(o){let e=o.clearAttr?`<button type="button" class="slm-linkbtn slm-selclear" ${o.clearAttr}${o.count?"":" disabled"}>Clear</button>`:"";return`<div class="slm-selbar" aria-live="polite">
|
|
6
|
+
<span class="slm-selnum${o.bump?" bump":""}">${o.count.toLocaleString()}</span>
|
|
7
|
+
<span class="slm-sellabel">${b(o.noun??"selected")}</span>
|
|
8
|
+
${o.breakdown??""}${e}
|
|
9
|
+
</div>`}var ye,Ps,N,Ye=z(()=>{"use strict";ve();ye=300,Ps=200;N=class{constructor(e){this.host=e;this.seatListLimit=ye;this.rowsCache=null}rows(){return this.rowsCache||(this.rowsCache=this.host.rows()),this.rowsCache}reset(){this.rowsCache=null,this.seatListLimit=ye}chipsHtml(e={}){let t=this.host.sections().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-sections">Section</button>':"",s=this.rows().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-rows">Rows\u2026</button>':"",n=this.host.categories().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-category">Category</button>':"",i=e.find===!1?"":xe();return`
|
|
10
|
+
<div class="slm-chooser" data-ch-chooser>
|
|
11
|
+
<div class="slm-ch-row2">${e.intents??""}${t}${s}</div>
|
|
12
|
+
<div class="slm-ch-row2">${n}<button type="button" class="slm-btn ghost" data-ch-act="seatlist">Seat list \u2328</button></div>
|
|
13
|
+
${i}
|
|
14
|
+
</div>`}wire(e,t={}){this.wireChips(e),this.wireFind(e,t)}wireChips(e){e.querySelectorAll("[data-ch-act]").forEach(t=>{let s=t.dataset.chAct;s==="pick-sections"?t.addEventListener("click",()=>this.openSections()):s==="pick-rows"?t.addEventListener("click",()=>this.openRows()):s==="pick-category"?t.addEventListener("click",()=>this.openCategory()):s==="seatlist"&&t.addEventListener("click",()=>this.openSeatList())})}handleAction(e){if(e==="pick-sections")this.openSections();else if(e==="pick-rows")this.openRows();else if(e==="pick-category")this.openCategory();else if(e==="seatlist")this.openSeatList();else return!1;return!0}wireFind(e,t={}){let s=e.querySelector("[data-ch-find-input]"),n=e.querySelector("[data-ch-find-count]");if(!s||!n)return;let i={labels:[],seats:0,rows:0,sections:0},a=()=>{let l=s.value.trim();i=this.find(s.value),n.textContent=l?Bs(i,t.enter??"select"):"",this.host.highlight?.(l?i.labels:null),t.onFind?.(i)};s.addEventListener("input",a),s.addEventListener("keydown",l=>{if(l.key==="Escape"&&s.value){l.preventDefault(),l.stopPropagation(),s.value="",a();return}if(l.key!=="Enter"||(l.preventDefault(),!i.labels.length))return;if(t.enter==="frame"){this.host.frame?.(i.labels),n.textContent=`${i.labels.length.toLocaleString()} on the map`;return}let r=new Set([...this.host.selectionLabels(),...i.labels]);if(this.host.cap!=null&&r.size>this.host.cap){n.textContent=`That would make ${r.size.toLocaleString()} selected seats \u2014 the limit is ${this.host.cap.toLocaleString()}.`;return}this.host.selectByLabels(i.labels),n.textContent=`${i.labels.length.toLocaleString()} selected`}),s.addEventListener("search",a)}find(e){return Ds(e,{sections:this.host.sections().map(t=>({...t,labels:this.host.labelsInSection(t.id)})),rows:this.rows(),seatLabels:this.host.seats().map(t=>t.label)})}openCategory(){let e=this.host.categories();if(!e.length)return;let t=this.host.cap??1/0,s=e.map(c=>({key:c.key,label:c.label,color:c.color,labels:this.host.labelsInCategory(c.key)})),n=new Map(s.map(c=>[c.key,c])),i=new Set,a=new Set(this.host.selectionLabels()),l=()=>{let c=new Set(a);for(let d of i)for(let h of n.get(d)?.labels??[])c.add(h);return c},r=s.map(c=>{let d=c.labels.filter(m=>a.has(m)).length,h=c.labels.length===0,f=h?"not on this map":d?`${d.toLocaleString()} of ${c.labels.length.toLocaleString()} selected`:`${c.labels.length.toLocaleString()} seat${c.labels.length===1?"":"s"}`;return`<button type="button" class="slm-ch-seatitem" role="checkbox" aria-checked="false"
|
|
15
|
+
data-ch-category="${b(c.key)}"${h?" disabled":""}>
|
|
16
|
+
<span class="box" aria-hidden="true">\u2713</span>
|
|
17
|
+
<span class="dot" style="background:${b(c.color??"#6e7bff")}" aria-hidden="true"></span>
|
|
18
|
+
<span>${b(c.label)}</span>
|
|
19
|
+
<span class="meta">${b(f)}</span>
|
|
20
|
+
</button>`}).join("");this.host.openDialog(`
|
|
21
|
+
<h3 id="slm-ch-dlg-title">Choose categories</h3>
|
|
22
|
+
<p class="sub">Every seat in a ticked category is added to the seats already selected on the map.</p>
|
|
23
|
+
<div class="slm-ch-seatlist">${r}</div>
|
|
24
|
+
<p class="slm-ch-err" data-ch-error hidden></p>
|
|
25
|
+
<div class="foot">
|
|
26
|
+
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
27
|
+
<button type="button" class="slm-btn" data-ch-add-scope disabled>Add seats</button>
|
|
28
|
+
</div>`,c=>{let d=c.querySelector("[data-ch-add-scope]"),h=c.querySelector("[data-ch-error]"),f=()=>{let m=l(),p=m.size-a.size,v=m.size>t;d.disabled=p===0||v,d.textContent=v?`Maximum ${t.toLocaleString()} seats`:`Add ${p.toLocaleString()} seat${p===1?"":"s"}`,h.hidden=!v,h.textContent=v?`That would make ${m.size.toLocaleString()} selected seats. Choose fewer categories.`:""};c.querySelectorAll("[data-ch-category]").forEach(m=>{m.addEventListener("click",()=>{let p=m.dataset.chCategory;i.has(p)?i.delete(p):i.add(p),m.setAttribute("aria-checked",String(i.has(p))),f()})}),d.addEventListener("click",()=>{let m=[...l()];!i.size||m.length>t||(this.host.closeDialog(),this.host.selectByLabels(m))}),f()})}openSections(){this.openScope("sections")}openRows(){this.openScope("rows")}openScope(e){let t=this.host.cap??1/0,n=(e==="sections"?this.host.sections().map(m=>({id:m.id,label:m.label,group:"Sections",labels:this.host.labelsInSection(m.id)})):this.rows().map(m=>({id:m.id,label:m.label,group:m.sectionLabel,labels:m.labels}))).filter(m=>m.labels.length>0),i=new Map;for(let m of n){let p=i.get(m.group)??[];p.push(m),i.set(m.group,p)}let a=new Map(n.map(m=>[m.id,m])),l=new Set,r=new Set(this.host.selectionLabels()),c=()=>{let m=new Set(r);for(let p of l)for(let v of a.get(p)?.labels??[])m.add(v);return m},d=(m,p)=>{let v=c(),y=v.size-r.size,g=v.size>t;m.disabled=y===0||g,m.textContent=g?`Maximum ${t.toLocaleString()} seats`:`Add ${y.toLocaleString()} seat${y===1?"":"s"}`,p.hidden=!g,p.textContent=g?`That would make ${v.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:""},h=()=>{let m=[...c()];!l.size||m.length>t||(this.host.closeDialog(),this.host.selectByLabels(m))};if(e==="rows"){let m=[...i.entries()];this.host.openDialog(`
|
|
29
|
+
<h3 id="slm-ch-dlg-title">Choose rows</h3>
|
|
30
|
+
<p class="sub">Sections stay collapsed for speed. Select a whole section, expand only the rows you need, or search across every row.</p>
|
|
31
|
+
<div class="slm-ch-scopebar">
|
|
32
|
+
<label>Find section or row<input type="search" data-ch-scope-search placeholder="e.g. Orchestra or AA"></label>
|
|
33
|
+
<span class="slm-ch-scopesummary" data-ch-scope-summary aria-live="polite">0 rows selected</span>
|
|
34
|
+
</div>
|
|
35
|
+
<p class="slm-ch-scopehint" data-ch-scope-filter>Showing section groups. Expand one or search to see rows.</p>
|
|
36
|
+
<div class="slm-ch-seatlist" data-ch-scope-list></div>
|
|
37
|
+
<p class="slm-ch-err" data-ch-error hidden></p>
|
|
38
|
+
<div class="foot">
|
|
39
|
+
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
40
|
+
<button type="button" class="slm-btn" data-ch-add-scope disabled>Add seats</button>
|
|
41
|
+
</div>`,p=>{let v=new Set,y=p.querySelector("[data-ch-add-scope]"),g=p.querySelector("[data-ch-error]"),C=p.querySelector("[data-ch-scope-list]"),k=p.querySelector("[data-ch-scope-search]"),L=p.querySelector("[data-ch-scope-summary]"),M=p.querySelector("[data-ch-scope-filter]"),x="",E=()=>{d(y,g);let I=c().size-r.size;L.textContent=`${l.size.toLocaleString()} row${l.size===1?"":"s"} \xB7 ${I.toLocaleString()} seat${I===1?"":"s"} added`},T=()=>{let I=[],st=0,qe=0;m.forEach(([B,$],ee)=>{let U=B.toLocaleLowerCase(),K=x?$.filter(D=>`${U} ${D.label.toLocaleLowerCase()}`.includes(x)):$;if(x&&!K.length)return;st+=K.length;let nt=$.every(D=>l.has(D.id)),bs=!nt&&$.some(D=>l.has(D.id)),te=!!x||v.has(ee),gs=Math.max(0,Ps-qe),se=te?K.slice(0,gs):[];qe+=se.length;let fs=$.reduce((D,vs)=>D+vs.labels.length,0);I.push(`<div class="slm-ch-scopegroup">
|
|
42
|
+
<button type="button" class="slm-ch-groupcheck" role="checkbox" aria-checked="${nt?"true":bs?"mixed":"false"}"
|
|
43
|
+
aria-label="Select all ${$.length.toLocaleString()} rows in ${b(B)}" data-ch-scope-group="${ee}">
|
|
44
|
+
<span class="box" aria-hidden="true">\u2713</span><span>${b(B)}</span>
|
|
45
|
+
<span class="meta">${$.length.toLocaleString()} rows \xB7 ${fs.toLocaleString()} seats</span>
|
|
46
|
+
</button>
|
|
47
|
+
<button type="button" class="slm-ch-grouptoggle" aria-expanded="${te}" aria-label="${te?"Hide":"Show"} rows in ${b(B)}"
|
|
48
|
+
data-ch-scope-toggle="${ee}">${te?"Hide":"Show"}</button>
|
|
49
|
+
</div>`),I.push(...se.map(D=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
50
|
+
aria-checked="${l.has(D.id)}" data-ch-scope-id="${b(D.id)}">
|
|
51
|
+
<span class="box" aria-hidden="true">\u2713</span><span>${b(D.label)}</span>
|
|
52
|
+
<span class="meta">${D.labels.length.toLocaleString()} seat${D.labels.length===1?"":"s"}</span>
|
|
53
|
+
</button>`)),te&&K.length>se.length&&I.push(`<p class="slm-ch-scopehint">${(K.length-se.length).toLocaleString()} more row${K.length-se.length===1?"":"s"}. Search to narrow the list.</p>`)}),C.innerHTML=I.join("")||(x?`<div class="slm-ch-scope-empty" data-ch-state="scope-nomatch">No sections or rows match \u201C${b(x)}\u201D.</div>`:`<div class="slm-ch-scope-empty" data-ch-state="scope-empty">This chart has no rows with selectable seats.
|
|
54
|
+
Use Drag box or the seat list instead.</div>`),M.textContent=x?`Showing ${qe.toLocaleString()} of ${st.toLocaleString()} matching rows. Section checkboxes still select every row in that section.`:"Showing section groups. Expand one or search to see rows.",C.querySelectorAll("[data-ch-scope-group]").forEach(B=>B.addEventListener("click",()=>{let $=m[Number(B.dataset.chScopeGroup)]?.[1]??[],ee=$.every(U=>l.has(U.id));for(let U of $)ee?l.delete(U.id):l.add(U.id);T(),E()})),C.querySelectorAll("[data-ch-scope-toggle]").forEach(B=>B.addEventListener("click",()=>{let $=Number(B.dataset.chScopeToggle);v.has($)?v.delete($):v.add($),T()})),C.querySelectorAll("[data-ch-scope-id]").forEach(B=>B.addEventListener("click",()=>{let $=B.dataset.chScopeId;l.has($)?l.delete($):l.add($),T(),E()}))};k.addEventListener("input",()=>{x=k.value.trim().toLocaleLowerCase(),T(),E()}),y.addEventListener("click",h),T(),E()});return}let f=[...i.entries()].map(([m,p])=>`
|
|
55
|
+
<div class="slm-ch-seatgroup"><span>${b(m)}</span></div>
|
|
56
|
+
${p.map(v=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
57
|
+
aria-checked="false" data-ch-scope-id="${b(v.id)}">
|
|
58
|
+
<span class="box" aria-hidden="true">\u2713</span>
|
|
59
|
+
<span>${b(v.label)}</span>
|
|
60
|
+
<span class="meta">${v.labels.length.toLocaleString()} seat${v.labels.length===1?"":"s"}</span>
|
|
61
|
+
</button>`).join("")}`).join("");this.host.openDialog(`
|
|
62
|
+
<h3 id="slm-ch-dlg-title">Choose sections</h3>
|
|
63
|
+
<p class="sub">Choose one or more. They are added to the seats already selected on the map.</p>
|
|
64
|
+
<div class="slm-ch-seatlist">${f||`<div class="slm-ch-scope-empty" data-ch-state="scope-empty">This chart has no sections with selectable seats.
|
|
65
|
+
Use Drag box or the seat list instead.</div>`}</div>
|
|
66
|
+
<p class="slm-ch-err" data-ch-error hidden></p>
|
|
67
|
+
<div class="foot">
|
|
68
|
+
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
69
|
+
<button type="button" class="slm-btn" data-ch-add-scope disabled>Add seats</button>
|
|
70
|
+
</div>`,m=>{let p=m.querySelector("[data-ch-add-scope]"),v=m.querySelector("[data-ch-error]");m.querySelectorAll("[data-ch-scope-id]").forEach(y=>{y.addEventListener("click",()=>{let g=y.dataset.chScopeId;l.has(g)?l.delete(g):l.add(g),y.setAttribute("aria-checked",String(l.has(g))),d(p,v)})}),p.addEventListener("click",h),d(p,v)})}openSeatList(e=""){let t=new Set(this.host.selectionLabels()),s=e.trim().toLocaleLowerCase(),n=g=>!s||g.toLocaleLowerCase().includes(s),i=this.rows(),a=new Map;for(let g of i)for(let C of g.labels)a.set(C,g);let l=new Map,r=new Map,c=0,d=0;for(let g of this.host.seats()){if(!n(g.label)||(c+=1,c>this.seatListLimit))continue;d+=1;let C=this.host.sectionOfLabel(g.label),k=C?.id??"",L=l.get(k)??{label:C?.label??"Other seats",lines:[],loose:[]};l.set(k,L);let M=a.get(g.label);if(!M){L.loose.push(g.label);continue}let x=r.get(M.id)??{id:M.id,label:M.label,seats:[]};r.has(M.id)||(r.set(M.id,x),L.lines.push(x)),x.seats.push(g.label)}let h=g=>this.host.seatMeta?.(g)??this.host.statusOf(g)??"free",f=(g,C)=>{let k=this.host.statusOf(g)??"free",L=C&&g.startsWith(`${C}-`)?g.slice(C.length+1):g;return`<button type="button" class="slm-ch-seatchip is-${b(k)}" role="checkbox"
|
|
71
|
+
aria-checked="${t.has(g)}" aria-label="${b(g)} \xB7 ${b(h(g))}" title="${b(g)} \xB7 ${b(h(g))}"
|
|
72
|
+
data-ch-seat="${b(g)}">${b(L)}</button>`},m=g=>{let C=g.seats.filter(k=>t.has(k)).length;return C===0?"false":C===g.seats.length?"true":"mixed"},p=[...l.entries()].map(([g,C])=>`
|
|
73
|
+
<div class="slm-ch-seatgroup">
|
|
74
|
+
<span>${b(C.label)}</span>
|
|
75
|
+
${g?`<button type="button" data-ch-section="${b(g)}">Select section</button>`:""}
|
|
76
|
+
</div>
|
|
77
|
+
${C.lines.map(k=>`
|
|
78
|
+
<div class="slm-ch-seatrow">
|
|
79
|
+
<button type="button" class="slm-ch-rowcheck" role="checkbox" aria-checked="${m(k)}" data-ch-row="${b(k.id)}"
|
|
80
|
+
aria-label="Row ${b(k.label)} \xB7 ${k.seats.length} seats">
|
|
81
|
+
<span class="box" aria-hidden="true">\u2713</span><span class="name">${b(k.label)}</span>
|
|
82
|
+
<span class="meta">${k.seats.length.toLocaleString()}</span>
|
|
83
|
+
</button>
|
|
84
|
+
<div class="slm-ch-seatchips">${k.seats.map(L=>f(L,k.label)).join("")}</div>
|
|
85
|
+
</div>`).join("")}
|
|
86
|
+
${C.loose.length?`<div class="slm-ch-seatrow loose"><div class="slm-ch-seatchips">${C.loose.map(k=>f(k,null)).join("")}</div></div>`:""}`).join(""),v=s?`<div class="slm-empty">Nothing matches \u201C${b(e.trim())}\u201D.</div>`:'<div class="slm-empty">No seats on this chart.</div>',y=t.size?`${t.size.toLocaleString()} selected`:"Nothing selected yet";this.host.openDialog(`
|
|
87
|
+
<h3 id="slm-ch-dlg-title">Seat list</h3>
|
|
88
|
+
<p class="sub">The same selection as the map, as checkboxes: a row takes its whole row, a seat toggles itself. Space or Enter toggles.</p>
|
|
89
|
+
<div class="slm-ch-seatlist-tools">
|
|
90
|
+
<div class="slm-find" data-ch-seatfilter>
|
|
91
|
+
<input type="search" class="slm-input" data-ch-seatfilter-input placeholder="Filter seats" aria-label="Filter seats" autocomplete="off" value="${b(e)}">
|
|
92
|
+
</div>
|
|
93
|
+
<div class="slm-ch-seatlegend" aria-hidden="true"><i class="is-free"></i>free <i class="is-held"></i>held <i class="is-booked"></i>booked <i class="is-blocked"></i>blocked</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="slm-ch-seatlist grid">${d?p:v}</div>
|
|
96
|
+
${c>this.seatListLimit?`<div class="foot"><button type="button" class="slm-btn ghost" data-ch-more>Show ${Math.min(ye,c-this.seatListLimit).toLocaleString()} more seats</button></div>`:""}
|
|
97
|
+
<div class="foot slm-ch-seatfoot">
|
|
98
|
+
<span class="slm-ch-seatcount" data-ch-seatcount role="status">${y}</span>
|
|
99
|
+
<button type="button" class="quiet" data-ch-clear-all ${t.size?"":"disabled"}>Clear</button>
|
|
100
|
+
<button type="button" class="slm-btn" data-ch-close>Done</button>
|
|
101
|
+
</div>`,g=>{let C=L=>{this.host.clearSelection(),L.size&&this.host.selectByLabels([...L]),this.openSeatList(e)};g.querySelectorAll("[data-ch-seat]").forEach(L=>{L.addEventListener("click",()=>{let M=L.dataset.chSeat,x=new Set(this.host.selectionLabels());x.has(M)?x.delete(M):x.add(M),C(x)})}),g.querySelectorAll("[data-ch-row]").forEach(L=>{L.addEventListener("click",()=>{let M=r.get(L.dataset.chRow);if(!M)return;let x=new Set(this.host.selectionLabels()),E=M.seats.every(T=>x.has(T));for(let T of M.seats)E?x.delete(T):x.add(T);C(x)})}),g.querySelectorAll("[data-ch-section]").forEach(L=>{L.addEventListener("click",()=>{this.host.selectSection(L.dataset.chSection),this.openSeatList(e)})}),g.querySelector("[data-ch-clear-all]")?.addEventListener("click",()=>C(new Set)),g.querySelector("[data-ch-more]")?.addEventListener("click",()=>{this.seatListLimit+=ye,this.openSeatList(e)});let k=g.querySelector("[data-ch-seatfilter-input]");if(k){let L=null;k.addEventListener("input",()=>{L&&clearTimeout(L),L=setTimeout(()=>{this.openSeatList(k.value);let M=this.lastDialogInput();M&&(M.focus(),M.setSelectionRange(M.value.length,M.value.length))},120)}),e&&(k.focus(),k.setSelectionRange(k.value.length,k.value.length))}})}lastDialogInput(){return document.querySelector(".slm-ch-dialog [data-ch-seatfilter-input]")}}});function O(o){return o==null||o===""||o===R}function V(o,e){let t=(o??"").trim();return((/\p{L}/u.exec(t)?.[0]??t[0]??"")||e).toUpperCase().slice(0,1)}function ne(o,e){let t=new Set([...e].map(i=>V(i,"")).filter(Boolean)),s=V(o,"");return{letter:Qt.includes(s)&&!t.has(s)?s:[...Qt].find(i=>!t.has(i))??(s||"X"),color:Ce[t.size%Ce.length]}}function Te(o,e=0){return O(o.id)?{letter:V(o.marker,"P"),color:o.color||js}:{letter:V(o.marker||o.name,"?"),color:o.color||Ce[e%Ce.length]}}function Me(o,e,t){let s=new Map;for(let a of o){let l=Qe(e.get(a));s.set(l,(s.get(l)??0)+1)}let n=[{id:R,name:t?.publicSale?.name??P},...(t?.channels??[]).map(a=>({id:a.id,name:a.name}))],i=[];for(let a of n){let l=s.get(a.id);l&&i.push({channelId:a.id,name:a.name,count:l}),s.delete(a.id)}for(let[a,l]of s)i.push({channelId:a,name:O(a)?P:"Another channel",count:l});return i}function Qe(o){return O(o)?R:o}function Ze(o){return{count:o.length,labels:o.slice(0,Jt),truncated:o.length>Jt}}function Ee(o){let{labels:e,allocation:t,statusOf:s,nameOf:n}=o,i=Qe(o.targetChannelId),a=new Set,l=0,r=0,c=new Map,d=[],h=[],f=[];for(let p of e){if(a.has(p))continue;a.add(p);let v=s(p);if(!v){f.push(p);continue}let y=Qe(t.get(p));if(y===i){r+=1;continue}if(v==="held"){d.push(p);continue}if(v==="booked"){h.push(p);continue}y===R?l+=1:c.set(y,(c.get(y)??0)+1)}let m=[...c.entries()].map(([p,v])=>({channelId:p,name:n(p),count:v}));return{changedFromPublic:{count:l},movedFromOtherChannel:{count:m.reduce((p,v)=>p+v.count,0),channels:m},alreadyInTarget:{count:r},skippedHeld:Ze(d),skippedBooked:Ze(h),notFound:Ze(f)}}function Z(o){return o.changedFromPublic.count+o.movedFromOtherChannel.count}function Re(o){return o.movedFromOtherChannel.count>0}function $e(o,e){let t=[];o.changedFromPublic.count&&t.push({kind:"add",icon:"+",count:o.changedFromPublic.count,text:`${o.changedFromPublic.count.toLocaleString()} from ${P}`});for(let s of o.movedFromOtherChannel.channels)t.push({kind:"move",icon:"\u21C4",count:s.count,text:`${s.count.toLocaleString()} moved out of ${s.name??"another channel"}`,why:"needs this confirmation"});return o.alreadyInTarget.count&&t.push({kind:"same",icon:"=",count:o.alreadyInTarget.count,text:`${o.alreadyInTarget.count.toLocaleString()} already in ${e}`,why:"unchanged"}),o.skippedHeld.count&&t.push({kind:"skip",icon:"\u23F8",count:o.skippedHeld.count,text:`${o.skippedHeld.count.toLocaleString()} in a buyer's checkout`,why:"can't move while held",peek:Le(o.skippedHeld)}),o.skippedBooked.count&&t.push({kind:"skip",icon:"\u{1F512}",count:o.skippedBooked.count,text:`${o.skippedBooked.count.toLocaleString()} already sold`,why:"sales are never rewritten",peek:Le(o.skippedBooked)}),o.notFound.count&&t.push({kind:"skip",icon:"?",count:o.notFound.count,text:`${o.notFound.count.toLocaleString()} not on this map`,why:"these seats are no longer part of the event",peek:Le(o.notFound)}),t}function Le(o){if(!o.labels.length)return;let e=o.labels.slice(0,4).join(", ");return o.truncated||o.labels.length>4?`${e}\u2026`:e}function Ae(o){let e=o?.retryAfterMs??(o?.latestHoldExpiresAt?Math.max(0,o.latestHoldExpiresAt-Date.now()):0);if(!e)return"in a moment";let t=Math.ceil(e/6e4);return t<=1?"in about a minute":`in about ${t} minutes`}function Ie(o){if(!o||!o.intent)return"\u2014";let e=o.intent==="server"?"Website integration":o.intent==="hosted_link"?"Buyer link":o.intent==="internal"?"Your staff sell these":"Protected reserve",t=o.hasActiveGrants?"in use now":o.lastMintAt?`last used ${new Date(o.lastMintAt).toLocaleDateString()}`:null,s=o.detail??t;return s?`${e} \xB7 ${s}`:e}function q(o){return o==="internal"?"Sell through your own staff":o==="server"?"Integrate a website or app":o==="hosted_link"?"Sell with a buyer link":"Keep as protected reserve"}function He(o){switch(o){case"internal":return"Only your own box office can sell these seats, through your secret key. Buyer links and website integrations are refused.";case"server":return"Your website's backend mints each buyer a short-lived session for these seats. Buyer links are refused; the code lives on the Embed page.";case"hosted_link":return"SeatLayer makes a link you send to a named group. They open it and buy only these seats. No other route can sell them.";default:return"Nobody can buy these seats. Every way of letting a buyer in \u2014 a buyer link, your website, even your own staff \u2014 is refused while this is the route. The seats stay out of public sale."}}function Us(o){return o==="hosted_link"?"hosted_link":o==="server"?"server":o==="staff"?"internal":null}function Q(o){let e=Je(o?.accessIntent),t=Us(o?.route),s=`This channel is set to "${q(e)}"`;return t?`${s}, so it cannot do that. Switch it to "${q(t)}" first.`:`${s}, so it cannot do that. Choose a different route for this channel first.`}function Je(o){return o==="internal"||o==="server"||o==="hosted_link"||o==="none"?o:"none"}function Se(o,e,t){return`${o.toLocaleString()} ${o===1?e:t}`}function Pe(o){let e=Math.max(0,o?.liveAccessLinks??0),t=Math.max(0,o?.activeSessions??0),s=Je(o?.from),n=Je(o?.to),a=`${[e?Se(e,"buyer link is live","buyer links are live"):null,t?Se(t,"buyer is in a checkout","buyers are in a checkout"):null].filter(Boolean).join(", and ")||"Buyers are inside this channel"} on "${q(s)}". Moving it to "${q(n)}" changes what happens to them.`,l=[];return e&&l.push(`${Se(e,"buyer link closes","buyer links close")} immediately. Anyone who has not opened it yet never will \u2014 send a new link if you still need one.`),t&&l.push(`${Se(t,"buyer who is already in a checkout keeps","buyers who are already in a checkout keep")} their seats and can finish paying. Nobody is thrown out. No new buyers come in this way, so the old route empties on its own within 12 hours.`),{headline:a,consequences:l}}function Be(o){switch(o.status??o.state){case"active":return{text:"Active",kind:"active"};case"expired":return{text:"Expired",kind:"archived"};case"exhausted":return{text:"All used",kind:"paused"};case"rotated":return{text:"Replaced",kind:"archived"};default:return{text:"Revoked",kind:"archived"}}}function ae(o){return o.state==="active"&&o.status==="active"}function Ks(o){return Number.isFinite(o)?new Date(o).toLocaleString(void 0,{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):"\u2014"}function oe(o){return[{k:"Expires",v:Ks(o.expiresAt)},{k:"Redemptions",v:`${o.redemptions.toLocaleString()} of ${o.maxRedemptions.toLocaleString()} used`},{k:"Seats per buyer",v:`${o.maxQuantity.toLocaleString()} seat${o.maxQuantity===1?"":"s"} maximum`},{k:"Covers",v:o.includePublic?"This channel's allocation and Public sale seats":"This channel's allocation only"}]}function j(o){let e=o?.serverMessage?.trim();switch(o?.code){case"invalid_expiry":case"invalid_max_redemptions":case"invalid_max_quantity":case"invalid_session_ttl":case"invalid_label":return e||"That setting is outside what a hosted link allows. Adjust it and try again.";case"too_many_access_links":return e||"This channel already has as many live links as it can hold. Revoke one before creating another.";case"access_link_not_active":return"That link is no longer active, so it cannot be rotated or revoked.";case"channel_unavailable":return"This channel is paused or archived, so it cannot let new buyers in. Resume it first.";case"channel_access_intent_forbids":return Q(o?.details);case"end_active_sessions_required":return"Choose what happens to the buyers who already came in through this link.";case"not_found":return"That link is no longer here. Refresh and try again.";default:return o?.status===403?"Hosted access links need channel-management permission.":e||"That did not go through. Try again."}}function es(o){return(o?.channels??[]).map(e=>({kind:"skip",icon:"\u26A0",count:e.count,text:`${e.count.toLocaleString()} would leave ${e.name??"a channel"}`,why:"the new chart no longer has these seats",peek:e.labels?.length?Le({count:e.count,labels:e.labels,truncated:e.truncated??!1}):void 0}))}function De(o){return o==="builtin"?"Built-in":o==="active"?"Active":o==="paused"?"Paused":"Archived"}var R,P,Ce,js,Qt,Jt,ie,Oe=z(()=>{"use strict";R="public",P="Public sale";Ce=["#a78bfa","#2dd4bf","#fb923c","#60a5fa","#f472b6","#a3e635","#f87171","#38bdf8","#c084fc","#facc15"],js="#f4b740",Qt="ABCDEFGHJKLMNPQRSTUVWXYZ";Jt=12;ie={maxRedemptions:100,maxQuantity:4}});function J(o){return o.map((e,t)=>`
|
|
2
102
|
<div class="slm-ch-bucket" style="animation-delay:${Math.min(t,4)*30}ms">
|
|
3
|
-
<span class="ico ${e.kind}" aria-hidden="true">${
|
|
4
|
-
<span><b>${e.count.toLocaleString()}</b> ${
|
|
5
|
-
${e.why?`<span class="why">\u2014 ${
|
|
6
|
-
${e.peek?`<span class="peek">${
|
|
7
|
-
</div>`).join("")}function
|
|
103
|
+
<span class="ico ${e.kind}" aria-hidden="true">${u(e.icon)}</span>
|
|
104
|
+
<span><b>${e.count.toLocaleString()}</b> ${u(e.text.replace(/^[\d,.\s]+/,""))}
|
|
105
|
+
${e.why?`<span class="why">\u2014 ${u(e.why)}</span>`:""}</span>
|
|
106
|
+
${e.peek?`<span class="peek">${u(e.peek)}</span>`:"<span></span>"}
|
|
107
|
+
</div>`).join("")}function u(o){return String(o??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function ns(o){return new Date(o-new Date(o).getTimezoneOffset()*6e4).toISOString().slice(0,16)}function et(o,e){let t=o.querySelector(e)?.value.trim()??"",s=Number(t);return t!==""&&Number.isInteger(s)?s:null}function is(o,e){let t=typeof navigator>"u"?null:navigator.clipboard;return t?.writeText?t.writeText(e).then(()=>!0,()=>ts(o,e)):Promise.resolve(ts(o,e))}function ts(o,e){let t=o.querySelector("[data-ch-lk-sink]");if(t&&typeof document.execCommand=="function")try{t.value=e,t.select(),t.setSelectionRange(0,e.length);let s=document.execCommand("copy");if(t.value="",s)return!0}catch{t.value=""}return Ws(o),!1}function Ws(o){let e=o.querySelector("[data-ch-lk-url]");if(e)try{let t=document.createRange();t.selectNodeContents(e);let s=window.getSelection();s?.removeAllRanges(),s?.addRange(t)}catch{}}var ss,ze=z(()=>{"use strict";ss=`
|
|
8
108
|
<p class="slm-eyebrow" style="margin-top:18px">On your website</p>
|
|
9
109
|
<p class="slm-hint">There is nothing more to set up on this screen. Your own server mints a short-lived buyer
|
|
10
110
|
access session for this channel with the SeatLayer server SDK and hands it to the widget. A channel name
|
|
11
111
|
on its own never grants access.</p>
|
|
12
112
|
<p class="slm-note"><a class="slm-linkbtn" href="https://docs.seatlayer.io/server-api/channels"
|
|
13
|
-
target="_blank" rel="noreferrer noopener">Read the website integration guide \u2192</a></p>`});function
|
|
14
|
-
.slm{--slm-ch-marker-ink:#0e1017
|
|
113
|
+
target="_blank" rel="noreferrer noopener">Read the website integration guide \u2192</a></p>`});function Js(o){return o?.dataset?.theme==="light"?Qs:Zs}function ls(o){let e=o.canvas,t=o.layer;if(!e||!t)return;let s=o.host.mapLayer.getBoundingClientRect(),n=Math.max(1,Math.round(s.width)),i=Math.max(1,Math.round(s.height)),a=typeof devicePixelRatio=="number"?Math.min(3,Math.max(1,devicePixelRatio)):1;(e.width!==n*a||e.height!==i*a)&&(e.width=n*a,e.height=i*a);let l=o.resolveCtx();if(!l)return;l.setTransform(a,0,0,a,0,0),l.clearRect(0,0,n,i);let r=Js(o.host.root),c=o.host.isSeatDetail(),d=Math.max(3,o.host.seatPixelSize()),h=d/2,f=o.view==="preview"?o.previewProjection:null,m=f?new Set(f.available===!1?[]:f.eligible??[]):null,p=new Map,v=!c&&o.host.sections().length>1?new Map:null,y=o.view==="preview"&&c&&d<=15?new Map:null;for(let g of o.host.seats()){let C=o.host.statusOf(g.label)??"free",k=o.allocation.get(g.label)??R;if(k!==R){let E=p.get(k)??{x:0,y:0,n:0};E.x+=g.x,E.y+=g.y,E.n+=1,p.set(k,E)}if(!c){let E=o.host.sectionOfLabel(g.label),T=E?o.host.worldToScreen({x:g.x,y:g.y}):null;if(v&&E&&T){let I=v.get(E.id)??{label:E.label,minX:T.x,minY:T.y,maxX:T.x,maxY:T.y};I.minX=Math.min(I.minX,T.x),I.minY=Math.min(I.minY,T.y),I.maxX=Math.max(I.maxX,T.x),I.maxY=Math.max(I.maxY,T.y),v.set(E.id,I)}continue}if(C!=="free")continue;let L=null,M=null;if(o.view==="preview"?m?.has(g.label)?(L=Gs,M=Xs):(L=r.unavailableFill,M=r.unavailableStroke):k!==R&&(L=o.markerFor(k).color,M=r.allocationStroke),!L)continue;let x=o.host.worldToScreen({x:g.x,y:g.y});if(x&&!(x.x<-d||x.y<-d||x.x>n+d||x.y>i+d)){if(y){let E=o.host.sectionOfLabel(g.label);if(E){let T=y.get(E.id)??{label:E.label,minX:x.x,minY:x.y,maxX:x.x,maxY:x.y};T.minX=Math.min(T.minX,x.x),T.minY=Math.min(T.minY,x.y),T.maxX=Math.max(T.maxX,x.x),T.maxY=Math.max(T.maxY,x.y),y.set(E.id,T)}}if(l.fillStyle=L,o.view==="preview"||k!==R){let E=Math.max(2,h+Math.min(1.5,h*.06));l.globalAlpha=1,l.beginPath(),l.arc(x.x,x.y,E,0,Math.PI*2),l.fill(),l.strokeStyle=M??L,l.lineWidth=o.view==="preview"?Math.max(1,Math.min(1.75,d*.13)):Math.max(1,Math.min(1.5,d*.1)),l.stroke(),o.view==="preview"&&m?.has(g.label)&&d>=22&&en(l,g.label,x.x,x.y,E)}else l.globalAlpha=.85,l.fillRect(x.x-h,x.y-h,d,d)}}l.globalAlpha=1,y&&an(l,y,r),tn(v,o),on(p,o,l)}function en(o,e,t,s,n){let i=n*1.55,a=Math.min(13,Math.max(7,n*.55)),l=6;for(;a>=l&&(o.font=`800 ${a}px var(--slm-font, system-ui, sans-serif)`,!(o.measureText(e).width<=i));)a-=.5;a<l||(o.fillStyle="#ffffff",o.textAlign="center",o.textBaseline="middle",o.fillText(e,t,s))}function tn(o,e){let t=e.layer;if(t&&(t.querySelectorAll(".slm-ch-section-target").forEach(s=>s.remove()),!!o))for(let[s,n]of o){let i=n.maxX-n.minX,a=n.maxY-n.minY;if(i<20||a<20)continue;let l=document.createElement("button");l.type="button",l.className="slm-ch-section-target",l.style.left=`${n.minX-8}px`,l.style.top=`${n.minY-8}px`,l.style.width=`${i+16}px`,l.style.height=`${a+16}px`,l.setAttribute("aria-label",`Open ${n.label} seats`),nn(l,e,()=>e.onSectionTargetClick(s)),t.appendChild(l)}}function sn(o,e){let t={button:0,buttons:1,clientX:e.x,clientY:e.y,bubbles:!0,cancelable:!0,composed:!0};return typeof PointerEvent=="function"?new PointerEvent("pointerdown",{...t,pointerId:o.pointerId,pointerType:o.pointerType,isPrimary:!0}):new MouseEvent("pointerdown",t)}function os(o){return o.host.mapLayer.querySelector(".slm-map-host")??o.host.mapLayer}function nn(o,e,t){o.addEventListener("wheel",r=>{let c=os(e);c!==o&&(r.preventDefault(),c.dispatchEvent(new WheelEvent("wheel",{deltaX:r.deltaX,deltaY:r.deltaY,deltaZ:r.deltaZ,deltaMode:r.deltaMode,clientX:r.clientX,clientY:r.clientY,ctrlKey:r.ctrlKey,shiftKey:r.shiftKey,altKey:r.altKey,metaKey:r.metaKey,bubbles:!0,cancelable:!0,composed:!0})))},{passive:!1});let s=null,n=!1,i=()=>{s=null,e.layer?.classList.remove("panning"),window.removeEventListener("pointermove",a,!0),window.removeEventListener("pointerup",l,!0),window.removeEventListener("pointercancel",l,!0)};function a(r){if(!s||n||Math.abs(r.clientX-s.x)<as&&Math.abs(r.clientY-s.y)<as)return;n=!0;let c=s;e.layer?.classList.add("panning");let d=document.elementFromPoint?.(c.x,c.y)??null;(d&&d!==o?d:os(e)).dispatchEvent(sn(r,c))}function l(){i()}o.addEventListener("pointerdown",r=>{n=!1,s={x:r.clientX,y:r.clientY},window.addEventListener("pointermove",a,!0),window.addEventListener("pointerup",l,!0),window.addEventListener("pointercancel",l,!0)}),o.addEventListener("click",r=>{if(n){n=!1,r.preventDefault(),r.stopPropagation();return}t()})}function an(o,e,t){for(let s of e.values()){let n=s.maxX-s.minX,i=s.maxY-s.minY;if(n<52||i<26)continue;let a=(s.minX+s.maxX)/2,l=(s.minY+s.maxY)/2,r=Math.max(11,Math.min(15,i*.16));o.font=`800 ${r}px var(--slm-font, system-ui, sans-serif)`;let c=Math.min(n-8,o.measureText(s.label).width+18),d=r+10;o.fillStyle=t.sectionPlate,o.fillRect(a-c/2,l-d/2,c,d),o.fillStyle=t.sectionPlateInk,o.textAlign="center",o.textBaseline="middle",o.fillText(s.label,a,l)}}function on(o,e,t){let s=e.layer;if(!s||(s.querySelectorAll(".slm-ch-flag").forEach(i=>i.remove()),e.view==="preview"))return;let n=[...o.entries()].sort((i,a)=>a[1].n-i[1].n).slice(0,Ys);for(let[i,a]of n){let l=e.list?.channels.find(h=>h.id===i);if(!l)continue;let r=e.host.worldToScreen({x:a.x/a.n,y:a.y/a.n});if(!r)continue;let c=e.markerFor(i),d=document.createElement("span");d.className="slm-ch-flag",d.style.left=`${r.x}px`,d.style.top=`${r.y}px`,d.innerHTML=`<span class="mk" style="background:${u(c.color)}">${u(c.letter)}</span>${u(l.name)}${l.state==="paused"?" \xB7 Paused":""}`,s.appendChild(d)}}var Ys,Gs,Xs,Zs,Qs,as,rs=z(()=>{"use strict";Oe();ze();Ys=8,Gs="#6e7bff",Xs="#b9c0ff",Zs={unavailableFill:"#303846",unavailableStroke:"#4b5669",allocationStroke:"#101723",sectionPlate:"rgba(11,16,28,.88)",sectionPlateInk:"#f8fafc"},Qs={unavailableFill:"rgba(156,163,175,.55)",unavailableStroke:"rgba(107,114,128,.65)",allocationStroke:"#ffffff",sectionPlate:"rgba(255,255,255,.9)",sectionPlateInk:"#172033"};as=4});var cs,ds=z(()=>{"use strict";cs=`
|
|
114
|
+
.slm{--slm-ch-marker-ink:#0e1017;
|
|
15
115
|
--slm-mo-instant:80ms;--slm-mo-quick:140ms;--slm-mo-base:200ms;--slm-mo-slow:320ms;--slm-mo-ambient:2000ms;
|
|
16
116
|
--slm-mo-out:cubic-bezier(.2,.8,.2,1);--slm-mo-in-out:cubic-bezier(.4,0,.2,1);--slm-mo-exit:cubic-bezier(.4,0,1,1);
|
|
17
117
|
--slm-mo-spring:cubic-bezier(.34,1.3,.64,1)}
|
|
18
118
|
/* A channel's marker chip is painted in the CHANNEL's own colour, which is the
|
|
19
119
|
same in both themes, so its ink is a constant rather than a ground token \u2014
|
|
20
|
-
declared once here so a host can still override it. The scrim
|
|
21
|
-
|
|
22
|
-
.slm[data-theme=light]{--slm-ch-scrim:rgba(23,32,51,.42)}
|
|
120
|
+
declared once here so a host can still override it. The scrim and dialog
|
|
121
|
+
rules live in managerDialog.ts (MANAGER_DIALOG_CSS), always injected. */
|
|
23
122
|
|
|
24
123
|
/* map overlay: ONE layer, faded in as a whole (never per seat) */
|
|
25
124
|
.slm-ch-layer{position:absolute;inset:0;overflow:hidden;pointer-events:none;opacity:0;transition:opacity var(--slm-mo-base) var(--slm-mo-out)}
|
|
@@ -173,18 +272,6 @@
|
|
|
173
272
|
.slm-ch-live{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
174
273
|
|
|
175
274
|
/* dialogs */
|
|
176
|
-
.slm-ch-scrim{position:absolute;inset:0;z-index:12;background:var(--slm-ch-scrim);display:grid;place-items:center;
|
|
177
|
-
padding:18px;animation:slm-ch-fade var(--slm-mo-quick) var(--slm-mo-out)}
|
|
178
|
-
.slm-ch-dialog{width:min(460px,100%);max-height:100%;overflow:auto;overscroll-behavior:contain;background:var(--slm-surface);color:var(--slm-text);border:1px solid var(--slm-line);
|
|
179
|
-
border-radius:14px;padding:20px;box-shadow:0 24px 70px rgba(0,0,0,.6);
|
|
180
|
-
animation:slm-ch-rise var(--slm-mo-base) var(--slm-mo-out)}
|
|
181
|
-
.slm-ch-dialog h3{margin:0 0 4px;font-size:16px;font-weight:800;letter-spacing:-.01em}
|
|
182
|
-
.slm-ch-dialog .sub{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:14px}
|
|
183
|
-
.slm-ch-dialog .foot{display:flex;gap:8px;margin-top:16px}
|
|
184
|
-
.slm-ch-dialog .foot .slm-btn{flex:1;min-width:0}
|
|
185
|
-
.slm-ch-dialog .foot .quiet{flex:none;padding:10px 14px;min-height:44px;color:var(--slm-muted);font-weight:700;font-size:13px}
|
|
186
|
-
@keyframes slm-ch-fade{from{opacity:0}to{opacity:1}}
|
|
187
|
-
@keyframes slm-ch-rise{from{opacity:0;transform:translateY(10px) scale(.985)}to{opacity:1;transform:none}}
|
|
188
275
|
.slm-ch-bucket{display:grid;grid-template-columns:24px 1fr auto;align-items:center;gap:10px;padding:9px 4px;
|
|
189
276
|
border-top:1px solid var(--slm-line);font-size:12.5px;animation:slm-ch-bucket var(--slm-mo-base) var(--slm-mo-out) both}
|
|
190
277
|
.slm-ch-bucket:first-of-type{border-top:0}
|
|
@@ -207,7 +294,6 @@
|
|
|
207
294
|
border-radius:10px;background:rgba(244,183,64,.06);color:var(--slm-text);
|
|
208
295
|
font-family:ui-monospace,Menlo,monospace;font-size:11px;
|
|
209
296
|
overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
|
|
210
|
-
.slm-ch-err{color:var(--slm-text);font-size:11.5px;margin-top:6px}
|
|
211
297
|
.slm-ch-price-list{display:flex;flex-direction:column;gap:7px}
|
|
212
298
|
.slm-ch-price-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(100px,132px);align-items:center;gap:12px;
|
|
213
299
|
padding:9px 0;border-bottom:1px solid var(--slm-line)}
|
|
@@ -249,37 +335,6 @@
|
|
|
249
335
|
.slm-ch-radio input{flex:none;margin-top:2px}
|
|
250
336
|
.slm-ch-radio b{display:block;font-weight:800;margin-bottom:2px}
|
|
251
337
|
.slm-ch-radio .why{display:block;color:var(--slm-muted);font-size:11.5px;line-height:1.45}
|
|
252
|
-
.slm-ch-seatlist{max-height:44vh;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);
|
|
253
|
-
border-radius:10px;background:var(--slm-surface);margin-top:10px}
|
|
254
|
-
.slm-ch-seatgroup{padding:8px 10px;border-bottom:1px solid var(--slm-line);display:flex;align-items:center;
|
|
255
|
-
justify-content:space-between;gap:8px;font-size:11px;font-weight:800;color:var(--slm-muted);position:sticky;top:0;
|
|
256
|
-
background:var(--slm-surface)}
|
|
257
|
-
.slm-ch-seatgroup button{color:var(--slm-accent);font-weight:800;font-size:11px;min-height:32px}
|
|
258
|
-
.slm-ch-seatitem{display:flex;width:100%;align-items:center;gap:9px;padding:8px 10px;border-bottom:1px solid var(--slm-line);
|
|
259
|
-
text-align:left;font-size:12px}
|
|
260
|
-
.slm-ch-seatitem .box{width:16px;height:16px;border-radius:4px;border:1px solid var(--slm-muted);display:grid;
|
|
261
|
-
place-items:center;font-size:10px;font-weight:900;color:transparent;flex:none}
|
|
262
|
-
.slm-ch-seatitem[aria-checked="true"] .box{border-color:var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
263
|
-
.slm-ch-seatitem .meta{margin-left:auto;color:var(--slm-muted);font-size:10.5px}
|
|
264
|
-
|
|
265
|
-
/* scope chooser: whole sections or many rows in one additive pass */
|
|
266
|
-
.slm-ch-scopebar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:10px;margin-top:12px}
|
|
267
|
-
.slm-ch-scopebar label{display:grid;gap:5px;color:var(--slm-muted);font-size:10.5px;font-weight:800}
|
|
268
|
-
.slm-ch-scopebar input{width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--slm-line);border-radius:8px;
|
|
269
|
-
background:var(--slm-surface);color:var(--slm-text);font:inherit}
|
|
270
|
-
.slm-ch-scopesummary{padding-bottom:10px;color:var(--slm-muted);font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
271
|
-
.slm-ch-scopegroup{position:sticky;top:0;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;
|
|
272
|
-
gap:6px;padding:6px 8px;border-bottom:1px solid var(--slm-line);background:var(--slm-surface)}
|
|
273
|
-
.slm-ch-groupcheck{display:flex;min-width:0;align-items:center;gap:8px;padding:5px 2px;text-align:left;font-size:11px;font-weight:800}
|
|
274
|
-
.slm-ch-groupcheck .box{width:16px;height:16px;flex:none;display:grid;place-items:center;border:1px solid var(--slm-muted);border-radius:4px;
|
|
275
|
-
color:transparent;font-size:10px}
|
|
276
|
-
.slm-ch-groupcheck[aria-checked="true"] .box,.slm-ch-groupcheck[aria-checked="mixed"] .box{border-color:var(--slm-accent);
|
|
277
|
-
background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
278
|
-
.slm-ch-groupcheck .meta{min-width:0;margin-left:auto;color:var(--slm-muted);font-size:10.5px;font-weight:600;white-space:nowrap}
|
|
279
|
-
.slm-ch-grouptoggle{min-height:32px;padding:5px 8px;color:var(--slm-accent);font-size:11px;font-weight:800}
|
|
280
|
-
.slm-ch-scopehint{padding:8px 10px;color:var(--slm-muted);font-size:10.5px;border-bottom:1px solid var(--slm-line)}
|
|
281
|
-
.slm-ch-scope-empty{padding:18px 12px;color:var(--slm-muted);font-size:11.5px;text-align:center}
|
|
282
|
-
@media(max-width:560px){.slm-ch-scopebar{grid-template-columns:1fr}.slm-ch-scopesummary{padding-bottom:0}}
|
|
283
338
|
|
|
284
339
|
/* compact: bottom sheet with three detents (\xA713) */
|
|
285
340
|
.slm.compact.ch-sheet .slm-rail{position:absolute;left:0;right:0;bottom:0;z-index:8;border-top:1px solid var(--slm-line);
|
|
@@ -307,19 +362,19 @@
|
|
|
307
362
|
.slm-ch-staged.shake{outline:2px solid #e5484d;outline-offset:2px}
|
|
308
363
|
.slm-ch-staged.done{outline:2px solid #5bd39b;outline-offset:2px}
|
|
309
364
|
}
|
|
310
|
-
`});var
|
|
365
|
+
`});var hs={};it(hs,{CHANNELS_CSS:()=>cs,ChannelsMode:()=>le,bucketRowsHtml:()=>J});var ln,_,le,tt=z(()=>{"use strict";re();Ye();Oe();pe();rs();ze();ds();ze();ln=3e4,_=5e3,le=class{constructor(e,t){this.active=!1;this.list=null;this.allocation=new Map;this.assignmentVersion=0;this.loadError=null;this.loading=!0;this.view="inspect";this.mapIntent="pan";this.focusedSectionId=null;this.showArchived=!1;this.detailChannelId=null;this.assignOpen=!1;this.targetChannelId="";this.conflict=!1;this.dialog=null;this.detent="medium";this.links=[];this.linksChannelId=null;this.linksState="idle";this.listSeq=0;this.linksSeq=0;this.previewAudience=[];this.previewIncludePublic=!1;this.previewProjection=null;this.previewState="idle";this.pollTimer=null;this.layer=null;this.canvas=null;this.overlayVisible=!0;this.ctx=void 0;this.bannerEl=null;this.stagedEl=null;this.liveEl=null;this.scrimEl=null;this.lastFocus=null;this.stagedDoneTimer=null;this.lastSelectionCount=0;this.lastCounts=new Map;this.railHtml=null;this.allocationVersion=null;this.onVisibility=null;this.host=e,this.caps=t;let s={selectionLabels:()=>e.selectionLabels(),selectByLabels:n=>e.selectByLabels(n),clearSelection:()=>e.clearSelection(),selectSection:n=>e.selectSection(n),sections:()=>e.sections(),labelsInSection:n=>e.labelsInSection(n),rows:()=>e.rows(),categories:()=>e.categories(),labelsInCategory:n=>e.labelsInCategory(n),seats:()=>e.seats(),statusOf:n=>e.statusOf(n),sectionOfLabel:n=>e.sectionOfLabel(n),seatMeta:n=>{let i=this.allocation.get(n)??R;return`${this.nameOf(i)??P} \xB7 ${e.statusOf(n)??"free"}`},openDialog:(n,i)=>this.renderScrim(n,i),closeDialog:()=>this.closeDialog(),cap:_};this.chooser=new N(s)}enter(){this.active||(this.active=!0,this.mapIntent="pan",this.assignOpen=!1,this.focusedSectionId=null,this.chooser.reset(),this.railHtml=null,this.ensureLayer(),this.host.root.classList.add("ch-mode"),this.applySheetClasses(),this.host.sections().length>1&&this.host.showSectionOverview(),this.paintRail(),this.onInteractionChange?.(),this.refresh(),this.pollTimer=setInterval(()=>{typeof document<"u"&&document.hidden||this.refresh({quiet:!0})},ln),typeof document<"u"&&typeof document.addEventListener=="function"&&(this.onVisibility=()=>{this.active&&!document.hidden&&this.refresh({quiet:!0})},document.addEventListener("visibilitychange",this.onVisibility)))}leave(){this.active&&(this.active=!1,this.pollTimer&&clearInterval(this.pollTimer),this.pollTimer=null,this.onVisibility&&typeof document<"u"&&document.removeEventListener("visibilitychange",this.onVisibility),this.onVisibility=null,this.railHtml=null,this.closeDialog({restoreFocus:!1}),this.links=[],this.linksChannelId=null,this.linksState="idle",this.layer?.classList.remove("on"),this.host.root.classList.remove("ch-mode","ch-preview","ch-sheet","detent-collapsed","detent-medium","detent-full"),this.setBanner(!1),this.setStaged(null))}destroy(){this.leave(),this.stagedDoneTimer&&clearTimeout(this.stagedDoneTimer),this.layer?.remove(),this.layer=null,this.bannerEl?.remove(),this.bannerEl=null}setCapabilities(e){this.caps=e,this.active&&this.paintRail()}isActive(){return this.active}canSelect(){return this.caps.manage&&this.view==="inspect"}usesMarqueeSelection(){return this.canSelect()&&this.mapIntent==="assign"}handleSectionFocus(e){this.active&&(this.focusedSectionId=e,this.paintRail())}applyRealtimeHint(){this.active&&this.refresh({quiet:!0})}handleSelectionChange(){this.active&&(this.paintSelection(),this.paintStagedBar())}handleViewChange(){this.active&&this.paintOverlay()}handleLayoutChange(){this.active&&(this.applySheetClasses(),this.paintOverlay())}async refresh(e={}){if(!this.caps.view)return;let t=++this.listSeq,s=()=>t!==this.listSeq;try{let n=await this.host.api.channels(this.host.eventKey,{includeArchived:this.showArchived});if(s())return;if(this.list=n,this.assignmentVersion=n.assignmentVersion,this.loadError=null,this.targetChannelId||(this.targetChannelId=n.channels.find(i=>i.state==="active")?.id??R),this.allocationVersion!==n.assignmentVersion){if(await this.loadAllocation(t),s())return;this.allocationVersion=n.assignmentVersion}if(this.detailChannelId&&await this.loadLinks(this.detailChannelId),s())return;this.loading=!1,this.active&&(this.paintRail(),this.paintOverlay())}catch(n){if(s())return;this.loading=!1,n instanceof w&&n.status===403&&(this.caps={view:!1,manage:!1}),this.loadError=n,e.quiet||this.host.onError(n),this.active&&this.paintRail()}}async loadAllocation(e){let t=new Map,s;for(let n=0;n<200;n+=1){if(e!==void 0&&e!==this.listSeq)return;let i=await this.host.api.channelAllocation(this.host.eventKey,{afterLabel:s,limit:1e3});for(let a of i.allocations)O(a.channelId)||t.set(a.label,a.channelId);if(this.assignmentVersion=i.assignmentVersion,!i.nextAfterLabel)break;s=i.nextAfterLabel}e!==void 0&&e!==this.listSeq||(this.allocation=t)}channelById(e){if(O(e))return{id:R,name:this.list?.publicSale?.name??P,marker:"P",color:null};let t=this.list?.channels.find(s=>s.id===e);return t?{id:e,name:t.name,marker:t.marker,color:t.color}:null}nameOf(e){return this.channelById(e)?.name??null}channelNameForLabel(e){return this.list?this.nameOf(this.allocation.get(e)??R):null}markerFor(e){let t=Math.max(0,this.list?.channels.findIndex(n=>n.id===e)??0),s=this.channelById(e);return Te(s??{id:e,name:"?",marker:null,color:null},t)}assignableChannels(){return[{id:R,name:this.list?.publicSale.name??P},...(this.list?.channels??[]).filter(e=>e.state!=="archived").map(e=>({id:e.id,name:e.name}))]}currentPlan(){let e=this.host.selectionLabels(),t=Ee({labels:e,targetChannelId:this.targetChannelId,allocation:this.allocation,statusOf:s=>this.host.statusOf(s),nameOf:s=>this.nameOf(s)});return{labels:e,buckets:t,target:this.targetChannelId}}ensureLayer(){if(this.layer)return;let e=document.createElement("div");e.className="slm-ch-layer",e.innerHTML=`
|
|
311
366
|
<canvas class="slm-ch-canvas" data-ch="canvas" aria-hidden="true"></canvas>
|
|
312
367
|
<div class="slm-ch-banner" data-ch="banner" role="status"></div>
|
|
313
368
|
<div class="slm-ch-staged" data-ch="staged" role="group" aria-label="Staged channel changes"></div>
|
|
314
|
-
<div class="slm-ch-live" data-ch="live" role="status" aria-live="polite"></div>`,this.host.mapLayer.appendChild(e),this.layer=e,this.canvas=e.querySelector('[data-ch="canvas"]'),this.bannerEl=e.querySelector('[data-ch="banner"]'),this.bannerEl&&this.host.pillLane&&this.host.pillLane.appendChild(this.bannerEl),this.stagedEl=e.querySelector('[data-ch="staged"]'),this.liveEl=e.querySelector('[data-ch="live"]'),requestAnimationFrame(()=>e.classList.add("on"))}announce(e){this.liveEl&&(this.liveEl.textContent=e)}paintOverlay(){let e=this.canvas,t=this.layer;!e||!t||
|
|
315
|
-
<span>${
|
|
369
|
+
<div class="slm-ch-live" data-ch="live" role="status" aria-live="polite"></div>`,this.host.mapLayer.appendChild(e),this.layer=e,this.canvas=e.querySelector('[data-ch="canvas"]'),this.bannerEl=e.querySelector('[data-ch="banner"]'),this.bannerEl&&this.host.pillLane&&this.host.pillLane.appendChild(this.bannerEl),this.stagedEl=e.querySelector('[data-ch="staged"]'),this.liveEl=e.querySelector('[data-ch="live"]'),requestAnimationFrame(()=>e.classList.add("on"))}announce(e){this.liveEl&&(this.liveEl.textContent=e)}setOverlayVisible(e){if(this.overlayVisible===e)return;if(this.overlayVisible=e,e){this.active&&this.paintOverlay();return}let t=this.canvas;t&&(this.ctx??null)?.clearRect(0,0,t.width,t.height),this.layer?.querySelectorAll(".slm-ch-flag").forEach(s=>s.remove())}paintOverlay(){let e=this.canvas,t=this.layer;!e||!t||!this.overlayVisible||ls({layer:t,canvas:e,resolveCtx:()=>{if(this.ctx===void 0)try{this.ctx=e.getContext("2d")}catch{this.ctx=null}return this.ctx},host:this.host,view:this.view,previewProjection:this.previewProjection,allocation:this.allocation,focusedSectionId:this.focusedSectionId,list:this.list,markerFor:s=>this.markerFor(s),onSectionTargetClick:s=>{this.focusedSectionId=s,this.host.focusSection(s),this.paintRail()}})}setStaged(e,t=""){let s=this.stagedEl;if(s){if(!e){s.classList.remove("on","done","shake"),s.innerHTML="";return}s.innerHTML=e,s.className=`slm-ch-staged on${t?` ${t}`:""}`}}paintStagedBar(){if(!this.active||this.view==="preview"||!this.caps.manage){this.setStaged(null);return}let{labels:e,buckets:t}=this.currentPlan();if(this.host.onStagedChange?.(Z(t)),!e.length){this.setStaged(null);return}let s=this.nameOf(this.targetChannelId)??P,n=Z(t),i=e.length>_,a=t.skippedHeld.count+t.skippedBooked.count,l=[`<b>${e.length.toLocaleString()}</b> selected`,`<b>+${n.toLocaleString()}</b> to ${u(s)}`];t.alreadyInTarget.count&&l.push(`<b>${t.alreadyInTarget.count.toLocaleString()}</b> already in`),a&&l.push(`<b>${a.toLocaleString()}</b> can't move now`),this.setStaged(`
|
|
370
|
+
<span>${l.join(" \xB7 ")}</span>
|
|
316
371
|
<span class="grow"></span>
|
|
317
372
|
<button type="button" class="drop" data-ch-act="discard">Discard</button>
|
|
318
373
|
<button type="button" class="go" data-ch-act="review"${i?" disabled":""}>
|
|
319
|
-
${i?`Maximum ${
|
|
320
|
-
</button>`),this.stagedEl?.querySelectorAll("[data-ch-act]").forEach(r=>{r.addEventListener("click",()=>{r.dataset.chAct==="discard"?this.host.clearSelection():this.openDialog({kind:"review"})})})}setBanner(e,t="",s){let n=this.bannerEl;if(!n)return;if(this.host.root.classList.toggle("ch-preview",e),!e){n.classList.remove("on"),n.innerHTML="";return}let i=this.previewAudience.length===1?this.markerFor(this.previewAudience[0]):{color:"var(--slm-accent)",letter:""},a=s==null?"":` \xB7 ${s.toLocaleString()} ${s===1?"seat":"seats"} available now`;n.innerHTML=`<span class="dot" style="background:${
|
|
321
|
-
Previewing buyer access \xB7 ${
|
|
322
|
-
<button type="button" data-ch-act="exit-preview">Exit preview</button>`,n.classList.add("on"),n.querySelector('[data-ch-act="exit-preview"]')?.addEventListener("click",()=>this.setView("inspect"))}setView(e){if(this.view=e,e==="inspect")this.previewProjection=null,this.previewState="idle",this.setBanner(!1);else{if(!this.previewAudience.length){let t=this.list?.channels.find(s=>s.state==="active");this.previewAudience=[t?t.id:
|
|
374
|
+
${i?`Maximum ${_.toLocaleString()} seats`:"Review changes"}
|
|
375
|
+
</button>`),this.stagedEl?.querySelectorAll("[data-ch-act]").forEach(r=>{r.addEventListener("click",()=>{r.dataset.chAct==="discard"?this.host.clearSelection():this.openDialog({kind:"review"})})})}setBanner(e,t="",s){let n=this.bannerEl;if(!n)return;if(this.host.root.classList.toggle("ch-preview",e),!e){n.classList.remove("on"),n.innerHTML="";return}let i=this.previewAudience.length===1?this.markerFor(this.previewAudience[0]):{color:"var(--slm-accent)",letter:""},a=s==null?"":` \xB7 ${s.toLocaleString()} ${s===1?"seat":"seats"} available now`;n.innerHTML=`<span class="dot" style="background:${u(i.color)}"></span>
|
|
376
|
+
Previewing buyer access \xB7 ${u(t)}${a} \xB7 read-only
|
|
377
|
+
<button type="button" data-ch-act="exit-preview">Exit preview</button>`,n.classList.add("on"),n.querySelector('[data-ch-act="exit-preview"]')?.addEventListener("click",()=>this.setView("inspect"))}setView(e){if(this.view=e,e==="inspect")this.previewProjection=null,this.previewState="idle",this.setBanner(!1);else{if(!this.previewAudience.length){let t=this.list?.channels.find(s=>s.state==="active");this.previewAudience=[t?t.id:R]}this.loadPreview()}this.paintRail(),this.paintOverlay(),this.paintStagedBar(),this.onInteractionChange?.()}async loadPreview(){let e=[...this.previewAudience],t=e.map(s=>this.nameOf(s)??P).join(" + ");this.setBanner(!0,t),this.previewProjection=null,this.previewState="loading",this.active&&this.paintRail();try{this.previewProjection=await this.host.api.channelPreview(this.host.eventKey,e,{includePublic:this.previewIncludePublic||e.some(O)}),this.previewState="ready";let s=this.previewProjection.available===!1?void 0:this.previewProjection.counts?.eligible??this.previewProjection.eligible?.length;this.setBanner(!0,t,s)}catch(s){let n=s instanceof w?s.status:0;this.previewState=n===404||n===405||n===501?"unsupported":"error",this.previewProjection=null,this.previewState==="error"&&this.host.onError(s)}this.active&&(this.paintRail(),this.paintOverlay())}setRailHtml(e){if(e===this.railHtml)return!1;let t=this.host.rail,s=t.scrollTop;return t.innerHTML=e,this.railHtml=e,s&&(t.scrollTop=s),!0}paintRail(){if(!this.active)return;let e=this.host.rail;if(!this.caps.view){this.setRailHtml(`<p class="slm-eyebrow">Sales channels</p>
|
|
323
378
|
<p class="slm-hint">You need channel-management permission on this event to see allocations.</p>`);return}if(this.loading&&!this.list){this.setRailHtml(`<p class="slm-eyebrow">Sales channels</p>
|
|
324
379
|
<div class="slm-ch-busy" role="status" data-ch-state="list-loading">Loading channels and allocations\u2026</div>`);return}if(!this.list&&this.loadError){this.setRailHtml(`<p class="slm-eyebrow">Sales channels</p>
|
|
325
380
|
<div class="slm-ch-alert err" role="alert" data-ch-state="list-error"><span>\u26A0</span>
|
|
@@ -330,64 +385,57 @@
|
|
|
330
385
|
aria-pressed="${this.view==="inspect"}">Allocation</button>
|
|
331
386
|
<button type="button" class="${t.trim()}" data-ch-view="preview"
|
|
332
387
|
aria-pressed="${this.view==="preview"}">Buyer preview</button>
|
|
333
|
-
</div>${this.mapNavigationHtml()}`}mapNavigationHtml(){if(this.host.sections().length<2)return"";let e=this.focusedSectionId?this.host.sections().find(t=>t.id===this.focusedSectionId)?.label??"section":null;return e?`<div class="slm-ch-mapnav-head"><span>${
|
|
334
|
-
<button type="button" data-ch-act="sections">All sections</button></div>`:""}countsHtml(e,t){let s=(n,i,a,
|
|
388
|
+
</div>${this.mapNavigationHtml()}`}mapNavigationHtml(){if(this.host.sections().length<2)return"";let e=this.focusedSectionId?this.host.sections().find(t=>t.id===this.focusedSectionId)?.label??"section":null;return e?`<div class="slm-ch-mapnav-head"><span>${u(e)}</span>
|
|
389
|
+
<button type="button" data-ch-act="sections">All sections</button></div>`:""}countsHtml(e,t){let s=(n,i,a,l="")=>{let r=this.lastCounts.get(`${t}:${n}`),c=r!=null&&r!==i?" bump":"";return this.lastCounts.set(`${t}:${n}`,i),`<span class="${l}"><b class="${c.trim()}">${i.toLocaleString()}</b> ${a}</span>`};return`<span class="slm-ch-counts">
|
|
335
390
|
${s("allocated",e.allocated,"allocated")}
|
|
336
391
|
${s("free",e.free,"free","free")}
|
|
337
392
|
${s("booked",e.booked,"sold")}
|
|
338
393
|
${e.held?s("held",e.held,"held"):""}
|
|
339
|
-
</span>`}channelRowHtml(e,t={}){let s=this.markerFor(e.id),n=t.builtin?"builtin":e.state,i=e.state==="paused"||e.state==="archived"?" dim":"",a=!t.builtin&&this.caps.manage&&this.detailChannelId!==e.id,
|
|
340
|
-
aria-label="More actions for ${
|
|
341
|
-
aria-label="Open ${
|
|
394
|
+
</span>`}channelRowHtml(e,t={}){let s=this.markerFor(e.id),n=t.builtin?"builtin":e.state,i=e.state==="paused"||e.state==="archived"?" dim":"",a=!t.builtin&&this.caps.manage&&this.detailChannelId!==e.id,l=`slm-ch-row${t.builtin?" public":""}${e.state==="archived"?" archived":""}${this.detailChannelId===e.id?" on":""}${a?" open":""}`,r=!t.builtin&&this.caps.manage?`<button type="button" class="slm-ch-more" data-ch-menu="${u(e.id)}"
|
|
395
|
+
aria-label="More actions for ${u(e.name)}" aria-haspopup="dialog">\u22EF</button>`:"",c=a?` role="button" tabindex="0" data-ch-open="${u(e.id)}"
|
|
396
|
+
aria-label="Open ${u(e.name)}"`:"";return`<div class="${l}"${c}>
|
|
342
397
|
<span class="slm-ch-head">
|
|
343
|
-
<span class="slm-ch-mk${i}" style="background:${
|
|
344
|
-
<span class="slm-ch-name">${
|
|
345
|
-
<span class="slm-ch-badge ${n}">${
|
|
398
|
+
<span class="slm-ch-mk${i}" style="background:${u(s.color)}" aria-hidden="true">${u(s.letter)}</span>
|
|
399
|
+
<span class="slm-ch-name">${u(e.name)}</span>
|
|
400
|
+
<span class="slm-ch-badge ${n}">${u(De(t.builtin?"builtin":e.state))}</span>
|
|
346
401
|
${r}
|
|
347
402
|
</span>
|
|
348
403
|
${this.countsHtml(e.counts,e.id||"public")}
|
|
349
|
-
${t.builtin?"":`<span class="slm-ch-access">${
|
|
350
|
-
</div>`}listRailHtml(){let e=this.list,t=e.channels.filter(r=>r.state==="archived").length,s=e.channels.filter(r=>this.showArchived||r.state!=="archived"),n=[this.channelRowHtml(e.publicSale,{builtin:!0}),...s.map((r,
|
|
404
|
+
${t.builtin?"":`<span class="slm-ch-access">${u(Ie(e.access))}</span>`}
|
|
405
|
+
</div>`}listRailHtml(){let e=this.list,t=e.channels.filter(r=>r.state==="archived").length,s=e.channels.filter(r=>this.showArchived||r.state!=="archived"),n=[this.channelRowHtml(e.publicSale,{builtin:!0}),...s.map((r,c)=>this.channelRowHtml(r,{index:c}))].join(""),i=s.length?"":`<p class="slm-note" data-ch-state="list-empty">${t&&!this.showArchived?`No open channels \u2014 every seat is on public sale. ${t.toLocaleString()} archived channel${t===1?" is":"s are"} hidden below.`:"No private channels yet \u2014 every seat is on public sale."}</p>`,a=this.caps.manage?'<button type="button" class="slm-btn slm-ch-new" data-ch-act="create">+ New channel</button>':"",l=this.caps.manage?"":'<p class="slm-note">You can see how inventory is allocated. Changing it needs channel-management permission.</p>';return`
|
|
351
406
|
<div class="slm-ch-listhead"><h2>Sales channels</h2>${a}</div>
|
|
352
407
|
<div class="slm-ch-list">${n}</div>
|
|
353
408
|
${i}
|
|
354
|
-
${
|
|
409
|
+
${l}
|
|
355
410
|
${this.assignEntryHtml()}
|
|
356
411
|
<p class="slm-note" style="margin-top:10px" ${t||this.showArchived?"":"hidden"}>
|
|
357
412
|
<button type="button" class="slm-linkbtn" data-ch-act="toggle-archived" aria-pressed="${this.showArchived}"
|
|
358
413
|
style="text-align:left">${this.showArchived?"Hide":"Show"} archived${t?` (${t})`:""}</button>
|
|
359
414
|
</p>`}assignEntryHtml(){return this.caps.manage?this.assignOpen?`<div style="margin-top:8px">${this.assignmentToolsHtml({collapsible:!0})}</div>`:`
|
|
360
415
|
<button type="button" class="slm-btn" style="width:100%;margin-top:8px"
|
|
361
|
-
data-ch-act="assign-open" aria-expanded="false">Assign seats</button>`:""}assignmentToolsHtml(e={}){let t=this.assignableChannels().map(
|
|
416
|
+
data-ch-act="assign-open" aria-expanded="false">Assign seats</button>`:""}assignmentToolsHtml(e={}){let t=this.assignableChannels().map(i=>`<option value="${u(i.id)}"${i.id===this.targetChannelId?" selected":""}>${u(i.name)}</option>`).join(""),s=this.mapIntent==="assign"?"slm-btn":"slm-btn ghost";return`
|
|
362
417
|
<p class="slm-eyebrow">${e.collapsible?`<button type="button" class="slm-linkbtn" data-ch-act="assign-close"
|
|
363
418
|
aria-expanded="true" style="float:right;font-weight:800">Done</button>`:""}Assign inventory</p>
|
|
364
419
|
<div class="slm-field">
|
|
365
420
|
<label for="slm-ch-target">Assign to</label>
|
|
366
421
|
<select class="slm-select" id="slm-ch-target" data-ch-target>${t}</select>
|
|
367
422
|
</div>
|
|
368
|
-
<p class="slm-eyebrow" style="margin-top:12px">
|
|
369
|
-
|
|
370
|
-
${s}${n}
|
|
371
|
-
<button type="button" class="${i}" data-ch-act="drag-select">Drag box</button>
|
|
372
|
-
</div>
|
|
373
|
-
<div class="slm-ch-row2">
|
|
374
|
-
<button type="button" class="slm-btn ghost" data-ch-act="pick-category">Category</button>
|
|
375
|
-
<button type="button" class="slm-btn ghost" data-ch-act="seatlist">Seat list \u2328</button>
|
|
376
|
-
</div>
|
|
423
|
+
<p class="slm-eyebrow" style="margin-top:12px">Choose seats</p>
|
|
424
|
+
${this.chooser.chipsHtml({intents:`<button type="button" class="${s}" data-ch-act="drag-select">Drag box</button>`})}
|
|
377
425
|
<p class="slm-note" style="margin-bottom:18px">Choose a destination, then add whole sections,
|
|
378
|
-
|
|
426
|
+
rows, a dragged area, a category, or individual seats. Find selects what it matches on Enter.</p>`}selectionRailHtml(e){let t=Me(e,this.allocation,this.list),s=this.conflict?`<div class="slm-ch-alert err" role="alert"><span>\u26A0</span>
|
|
379
427
|
<span><b>Assignments changed while you were editing.</b> Nothing was applied.
|
|
380
428
|
Your ${e.length.toLocaleString()}-seat selection is kept.
|
|
381
|
-
<button type="button" data-ch-act="refresh-review">Refresh and review \u2192</button></span></div>`:"",n=e.length!==this.lastSelectionCount?" bump":"";this.lastSelectionCount=e.length;let i=e.length>
|
|
382
|
-
<span class="mk" style="background:${
|
|
383
|
-
<b>${
|
|
429
|
+
<button type="button" data-ch-act="refresh-review">Refresh and review \u2192</button></span></div>`:"",n=e.length!==this.lastSelectionCount?" bump":"";this.lastSelectionCount=e.length;let i=e.length>_,a=t.map(l=>{let r=this.markerFor(l.channelId);return`<div class="slm-ch-selsrc-row">
|
|
430
|
+
<span class="mk" style="background:${u(r.color)}" aria-hidden="true">${u(r.letter)}</span>
|
|
431
|
+
<b>${l.count.toLocaleString()}</b><span>${u(l.name)}</span></div>`}).join("");return`
|
|
384
432
|
${s}
|
|
385
433
|
${this.assignmentToolsHtml()}
|
|
386
434
|
<div class="slm-selbar"><span class="slm-selnum slm-ch-selnum${n}">${e.length.toLocaleString()}</span>
|
|
387
435
|
<span class="slm-sellabel">selected</span></div>
|
|
388
436
|
<div class="slm-ch-selsrc" aria-live="polite" aria-label="Selection sources">${a}</div>
|
|
389
437
|
${i?`<div class="slm-ch-alert warn" role="alert"><span>\u2139</span><span>
|
|
390
|
-
<b>This selection is too large to apply at once.</b> Choose at most ${
|
|
438
|
+
<b>This selection is too large to apply at once.</b> Choose at most ${_.toLocaleString()}
|
|
391
439
|
seats, for example by splitting the venue into row groups.</span></div>`:""}
|
|
392
440
|
<p class="slm-note">Changes are staged \u2014 nothing moves until you review and apply.
|
|
393
441
|
Seats in checkout or already sold are never moved.</p>
|
|
@@ -407,7 +455,7 @@
|
|
|
407
455
|
<button type="button" class="slm-btn ghost" data-ch-act="pause">${s.state==="paused"?"Resume":"Pause"}</button>
|
|
408
456
|
<button type="button" class="slm-btn ghost" data-ch-act="archive">Archive\u2026</button>
|
|
409
457
|
</div>
|
|
410
|
-
<p class="slm-note">Archive returns the allocation to a destination you choose. Nothing is ever deleted silently.</p>`:"",i=this.caps.manage?this.distributeHtml(s):"",a=s.priceOverrides?.length??0,
|
|
458
|
+
<p class="slm-note">Archive returns the allocation to a destination you choose. Nothing is ever deleted silently.</p>`:"",i=this.caps.manage?this.distributeHtml(s):"",a=s.priceOverrides?.length??0,l=this.caps.manage&&this.host.api.updateChannelPricing?`
|
|
411
459
|
<p class="slm-eyebrow" style="margin-top:14px">Prices</p>
|
|
412
460
|
<div class="slm-ch-price-summary">
|
|
413
461
|
<span>${a?`${a.toLocaleString()} custom price${a===1?"":"s"} override the event price for this channel.`:"This channel uses the event prices."}</span>
|
|
@@ -415,40 +463,40 @@
|
|
|
415
463
|
</div>
|
|
416
464
|
<p class="slm-note">Only buyers admitted to this channel see and pay these prices. Existing holds keep the price already promised.</p>`:"";return`
|
|
417
465
|
${t}
|
|
418
|
-
<p class="slm-eyebrow">Channel \xB7 ${
|
|
466
|
+
<p class="slm-eyebrow">Channel \xB7 ${u(s.name)}</p>
|
|
419
467
|
<div class="slm-ch-list">${this.channelRowHtml(s)}</div>
|
|
420
|
-
${
|
|
468
|
+
${l}
|
|
421
469
|
${i}
|
|
422
|
-
${n}`}distributeHtml(e){let t=e.access?.intent??"none",s=e.access?.hasActiveGrants===!0,n=this.linksState!=="unsupported",i=this.links.some(
|
|
423
|
-
<b>${
|
|
424
|
-
<span class="why">${
|
|
425
|
-
${
|
|
426
|
-
data-ch-act="${
|
|
470
|
+
${n}`}distributeHtml(e){let t=e.access?.intent??"none",s=e.access?.hasActiveGrants===!0,n=this.linksState!=="unsupported",i=this.links.some(ae),a=t==="none"?"Protected reserve \u2014 no route can sell these seats. Every buyer path is refused.":t==="internal"?"Your staff sell these seats. No buyer-facing route is open.":s?t==="server"?"Your website is letting buyers in. Only they can buy these seats.":"A buyer link is live. Only people with that link can buy these seats.":t==="server"?"Set up for your website \u2014 no buyer has come through yet. Seats stay reserved.":"Set up for buyer links \u2014 no buyer has come through yet. Seats stay reserved.",l=(r,c,d,h)=>{let f=r===t;return`<div class="slm-ch-dist${f?" on":""}" data-ch-route="${u(r)}">
|
|
471
|
+
<b>${u(q(r))}${f?'<span class="cur">Current route</span>':""}</b>
|
|
472
|
+
<span class="why">${u(He(r))}</span>
|
|
473
|
+
${f&&!d?"":`<button type="button" class="slm-btn${h&&!f?"":" ghost"}"
|
|
474
|
+
data-ch-act="${u(c)}">${u(d)}</button>`}
|
|
427
475
|
</div>`};return`
|
|
428
476
|
<p class="slm-eyebrow" style="margin-top:14px">Distribute</p>
|
|
429
|
-
<p class="slm-hint">${
|
|
430
|
-
${n?
|
|
431
|
-
${
|
|
432
|
-
${
|
|
433
|
-
${
|
|
477
|
+
<p class="slm-hint">${u(a)}</p>
|
|
478
|
+
${n?l("hosted_link","link-create",i?"Create another buyer link":"Create buyer link",!0):""}
|
|
479
|
+
${l("server","embed-code",t==="server"?"Get embed code":"Use a website or app",!1)}
|
|
480
|
+
${l("internal","route-internal",t==="internal"?"":"Hand to your staff",!1)}
|
|
481
|
+
${l("none","route-none",t==="none"?"":"Keep as reserve",!1)}
|
|
434
482
|
${this.hostedLinksHtml()}
|
|
435
|
-
${t==="server"?
|
|
483
|
+
${t==="server"?ss:""}`}async loadLinks(e){if(!this.caps.view)return;let t=++this.linksSeq,s=()=>t!==this.linksSeq||this.linksChannelId!==e;this.linksChannelId!==e&&(this.links=[],this.linksChannelId=e,this.linksState="loading");try{let n=await this.host.api.accessLinks(this.host.eventKey,e);if(s())return;this.links=n.links??[],this.linksState="ready"}catch(n){if(s())return;let i=n instanceof w?n.status:0;this.links=[],this.linksState=i===404||i===405||i===501?"unsupported":"error",this.linksState==="error"&&this.host.onError(n)}}hostedLinksHtml(){let e='<p class="slm-eyebrow" style="margin-top:18px">Buyer links</p>';return this.linksState==="unsupported"?`${e}<div class="slm-ch-alert warn" data-ch-state="links-unsupported"><span>\u2139</span>
|
|
436
484
|
<span><b>Buyer links need a newer server.</b> Everything else on this channel works normally.</span></div>`:this.linksState==="error"?`${e}<div class="slm-ch-alert err" role="alert" data-ch-state="links-error"><span>\u26A0</span>
|
|
437
485
|
<span><b>Couldn't load this channel's links.</b> This is a failed read, not an empty list \u2014
|
|
438
486
|
any live link is still working.
|
|
439
487
|
<button type="button" data-ch-act="link-reload">Try again</button></span></div>`:this.linksState==="idle"||this.linksState==="loading"&&!this.links.length?`${e}<div class="slm-ch-busy" role="status" data-ch-state="links-loading">Loading buyer links\u2026</div>`:this.links.length?`${e}
|
|
440
488
|
${this.links.map(t=>this.linkCardHtml(t)).join("")}
|
|
441
489
|
<p class="slm-note">A link is shown once, when you create it. SeatLayer keeps only a fingerprint of it, so it
|
|
442
|
-
can never be shown again \u2014 if a link is lost, rotate it and send the fresh one.</p>`:""}linkCardHtml(e){let t=
|
|
443
|
-
<span class="v">${
|
|
490
|
+
can never be shown again \u2014 if a link is lost, rotate it and send the fresh one.</p>`:""}linkCardHtml(e){let t=Be(e),s=e.maxRedemptions>0?Math.min(100,Math.round(e.redemptions/e.maxRedemptions*100)):0,n=oe(e).map(r=>`<div class="slm-ch-lkrow"><span class="k">${u(r.k)}</span>
|
|
491
|
+
<span class="v">${u(r.v)}</span></div>`).join(""),i=e.activeSessions?`<div class="slm-ch-lkrow"><span class="k">Buyers inside now</span>
|
|
444
492
|
<span class="v">${e.activeSessions.toLocaleString()}</span></div>`:"",a=e.lastRedeemedAt?`<div class="slm-ch-lkrow"><span class="k">Last opened</span>
|
|
445
|
-
<span class="v">${
|
|
446
|
-
<button type="button" class="slm-btn ghost" data-ch-rotate="${
|
|
447
|
-
<button type="button" class="slm-btn ghost" data-ch-revoke="${
|
|
493
|
+
<span class="v">${u(new Date(e.lastRedeemedAt).toLocaleString())}</span></div>`:"",l=this.caps.manage&&ae(e)?`<div class="slm-ch-row2">
|
|
494
|
+
<button type="button" class="slm-btn ghost" data-ch-rotate="${u(e.id)}">Rotate</button>
|
|
495
|
+
<button type="button" class="slm-btn ghost" data-ch-revoke="${u(e.id)}">Revoke</button>
|
|
448
496
|
</div>`:"";return`<div class="slm-ch-link">
|
|
449
497
|
<span class="lk-head">
|
|
450
|
-
<span class="lk-name">${
|
|
451
|
-
<span class="slm-ch-badge ${t.kind}">${
|
|
498
|
+
<span class="lk-name">${u(e.label||"Buyer link")}</span>
|
|
499
|
+
<span class="slm-ch-badge ${t.kind}">${u(t.text)}</span>
|
|
452
500
|
</span>
|
|
453
501
|
<div class="slm-ch-meter" role="img"
|
|
454
502
|
aria-label="${e.redemptions.toLocaleString()} of ${e.maxRedemptions.toLocaleString()} redemptions used">
|
|
@@ -456,16 +504,16 @@
|
|
|
456
504
|
${n}${i}${a}
|
|
457
505
|
<div class="slm-ch-lkrow"><span class="k">The URL</span>
|
|
458
506
|
<span class="v">Revealed once at creation \u2014 not recoverable</span></div>
|
|
459
|
-
${
|
|
460
|
-
</div>`}previewRailHtml(){let e=[{id:
|
|
507
|
+
${l}
|
|
508
|
+
</div>`}previewRailHtml(){let e=[{id:R,name:this.list?.publicSale.name??P},...(this.list?.channels??[]).filter(h=>h.state!=="archived").map(h=>({id:h.id,name:h.name}))],t=this.previewAudience[0]??R,s=e.map(h=>`<option value="${u(h.id)}"${h.id===t?" selected":""}>${u(h.name)}</option>`).join(""),n=this.previewState==="unsupported"?`<div class="slm-ch-alert warn" data-ch-state="preview-unsupported"><span>\u2139</span>
|
|
461
509
|
<span><b>Preview needs a newer server.</b> Allocation management works normally;
|
|
462
510
|
the buyer-view simulation will appear once this event's API is updated.</span></div>`:"",i=this.previewState==="loading"?'<div class="slm-ch-busy" role="status" data-ch-state="preview-loading">Asking the server what this audience sees\u2026</div>':"",a=this.previewState==="error"?`<div class="slm-ch-alert err" role="alert" data-ch-state="preview-error"><span>\u26A0</span>
|
|
463
511
|
<span><b>Couldn't load the buyer preview.</b> Nothing is wrong with this audience's seats \u2014
|
|
464
512
|
the simulation itself failed to load.
|
|
465
|
-
<button type="button" data-ch-act="preview-retry">Try again</button></span></div>`:"",
|
|
466
|
-
<span><b>This private sale is not available.</b> ${
|
|
467
|
-
A buyer arriving with this access sees this message, not these seats.</span></div>`:"",r=this.previewProjection?.counts?.eligible??this.previewProjection?.eligible?.length,
|
|
468
|
-
This is the exact buyer-visible allocation.${this.previewProjection?.includePublic===!1?" Public sale seats are <b>not</b> included in this access.":""}</span></div>`:"",
|
|
513
|
+
<button type="button" data-ch-act="preview-retry">Try again</button></span></div>`:"",l=this.previewProjection?.available===!1?`<div class="slm-ch-alert warn" role="status"><span>\u23F8</span>
|
|
514
|
+
<span><b>This private sale is not available.</b> ${u((this.previewProjection.unavailable??[]).map(h=>`${this.nameOf(h.channelId)??"This channel"} is ${h.state}`).join("; ")||"The audience cannot buy right now")}.
|
|
515
|
+
A buyer arriving with this access sees this message, not these seats.</span></div>`:"",r=this.previewProjection?.counts?.eligible??this.previewProjection?.eligible?.length,c=r!=null&&this.previewProjection?.available!==!1?`<div class="slm-ch-alert info"><span>\u2713</span><span><b>${r.toLocaleString()} ${r===1?"seat is":"seats are"} available now.</b>
|
|
516
|
+
This is the exact buyer-visible allocation.${this.previewProjection?.includePublic===!1?" Public sale seats are <b>not</b> included in this access.":""}</span></div>`:"",d=O(t)?"":`
|
|
469
517
|
<label class="slm-note" style="display:flex;gap:8px;align-items:center;margin:10px 0">
|
|
470
518
|
<input type="checkbox" data-ch-includepublic ${this.previewIncludePublic?"checked":""} />
|
|
471
519
|
Also include Public sale seats in this grant
|
|
@@ -475,83 +523,30 @@
|
|
|
475
523
|
<label for="slm-ch-audience">Audience</label>
|
|
476
524
|
<select class="slm-select" id="slm-ch-audience" data-ch-audience>${s}</select>
|
|
477
525
|
</div>
|
|
478
|
-
${
|
|
526
|
+
${d}
|
|
479
527
|
<p class="slm-hint">This is the same projection the buyer SDK receives for this audience \u2014 not a local
|
|
480
528
|
approximation. It is read-only: clicks open seat details, and no holds are created.</p>
|
|
481
|
-
${i}${a}${n}${
|
|
529
|
+
${i}${a}${n}${l}
|
|
482
530
|
<div class="slm-ch-legend">
|
|
483
531
|
<div class="r"><span class="sw" style="background:#6e7bff"></span> Eligible & free \u2014 buyable by this audience</div>
|
|
484
532
|
<div class="r"><span class="sw" style="background:#3a4051"></span> Unavailable to this audience (one neutral state)</div>
|
|
485
533
|
<div class="r"><span class="sw" style="background:#22a06b"></span> Sold \u2014 same as any buyer sees</div>
|
|
486
534
|
</div>
|
|
487
|
-
${
|
|
488
|
-
<h3 id="slm-ch-dlg-title"
|
|
489
|
-
<
|
|
490
|
-
<label for="slm-ch-choice">Choose one</label>
|
|
491
|
-
<select class="slm-select" id="slm-ch-choice">
|
|
492
|
-
${t.map(n=>`<option value="${p(n.value)}">${p(n.label)}</option>`).join("")}
|
|
493
|
-
</select>
|
|
494
|
-
</div>
|
|
495
|
-
<div class="foot">
|
|
496
|
-
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
497
|
-
<button type="button" class="slm-btn" data-ch-confirm>Select</button>
|
|
498
|
-
</div>`,n=>{n.querySelector("[data-ch-confirm]")?.addEventListener("click",()=>{let a=n.querySelector("#slm-ch-choice")?.value;this.closeDialog(),a&&s(a)})})}renderScopeDialog(e){let t=e.scope==="rows"?"rows":"sections",n=(t==="sections"?this.host.sections().map(o=>({id:o.id,label:o.label,group:"Sections",labels:this.host.labelsInSection(o.id)})):this.assignmentRows().map(o=>({id:o.id,label:o.label,group:o.sectionLabel,labels:o.labels}))).filter(o=>o.labels.length>0),i=new Map;for(let o of n){let r=i.get(o.group)??[];r.push(o),i.set(o.group,r)}if(t==="rows"){let o=[...i.entries()];this.renderScrim(`
|
|
499
|
-
<h3 id="slm-ch-dlg-title">Add multiple rows</h3>
|
|
500
|
-
<p class="sub">Sections stay collapsed for speed. Select a whole section, expand only the rows you need, or search across every row.</p>
|
|
501
|
-
<div class="slm-ch-scopebar">
|
|
502
|
-
<label>Find section or row<input type="search" data-ch-scope-search placeholder="e.g. Orchestra or AA"></label>
|
|
503
|
-
<span class="slm-ch-scopesummary" data-ch-scope-summary aria-live="polite">0 rows selected</span>
|
|
504
|
-
</div>
|
|
505
|
-
<p class="slm-ch-scopehint" data-ch-scope-filter>Showing section groups. Expand one or search to see rows.</p>
|
|
506
|
-
<div class="slm-ch-seatlist" data-ch-scope-list></div>
|
|
507
|
-
<p class="slm-ch-err" data-ch-error hidden></p>
|
|
508
|
-
<div class="foot">
|
|
509
|
-
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
510
|
-
<button type="button" class="slm-btn" data-ch-add-scope disabled>Add seats</button>
|
|
511
|
-
</div>`,r=>{let d=new Map(n.map(k=>[k.id,k])),c=new Set,h=new Set,u=new Set(this.host.selectionLabels()),f=r.querySelector("[data-ch-add-scope]"),v=r.querySelector("[data-ch-error]"),g=r.querySelector("[data-ch-scope-list]"),m=r.querySelector("[data-ch-scope-search]"),y=r.querySelector("[data-ch-scope-summary]"),H=r.querySelector("[data-ch-scope-filter]"),q=200,E="",N=()=>{let k=new Set(u);for(let C of c)for(let O of d.get(C)?.labels??[])k.add(O);return k},S=()=>{let k=N(),C=k.size-u.size,O=k.size>I;f.disabled=C===0||O,f.textContent=O?`Maximum ${I.toLocaleString()} seats`:`Add ${C.toLocaleString()} seat${C===1?"":"s"}`,v.hidden=!O,v.textContent=O?`That would make ${k.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:"",y.textContent=`${c.size.toLocaleString()} row${c.size===1?"":"s"} \xB7 ${C.toLocaleString()} seat${C===1?"":"s"} added`},L=()=>{let k=[],C=0,O=0;o.forEach(([P,R],X)=>{let V=P.toLocaleLowerCase(),U=E?R.filter(B=>`${V} ${B.label.toLocaleLowerCase()}`.includes(E)):R;if(E&&!U.length)return;C+=U.length;let Ue=R.every(B=>c.has(B.id)),Pt=!Ue&&R.some(B=>c.has(B.id)),Z=!!E||h.has(X),Bt=Math.max(0,q-O),Q=Z?U.slice(0,Bt):[];O+=Q.length;let Dt=R.reduce((B,Ot)=>B+Ot.labels.length,0);k.push(`<div class="slm-ch-scopegroup">
|
|
512
|
-
<button type="button" class="slm-ch-groupcheck" role="checkbox" aria-checked="${Ue?"true":Pt?"mixed":"false"}"
|
|
513
|
-
aria-label="Select all ${R.length.toLocaleString()} rows in ${p(P)}" data-ch-scope-group="${X}">
|
|
514
|
-
<span class="box" aria-hidden="true">\u2713</span><span>${p(P)}</span>
|
|
515
|
-
<span class="meta">${R.length.toLocaleString()} rows \xB7 ${Dt.toLocaleString()} seats</span>
|
|
516
|
-
</button>
|
|
517
|
-
<button type="button" class="slm-ch-grouptoggle" aria-expanded="${Z}" aria-label="${Z?"Hide":"Show"} rows in ${p(P)}"
|
|
518
|
-
data-ch-scope-toggle="${X}">${Z?"Hide":"Show"}</button>
|
|
519
|
-
</div>`),k.push(...Q.map(B=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
520
|
-
aria-checked="${c.has(B.id)}" data-ch-scope-id="${p(B.id)}">
|
|
521
|
-
<span class="box" aria-hidden="true">\u2713</span><span>${p(B.label)}</span>
|
|
522
|
-
<span class="meta">${B.labels.length.toLocaleString()} seat${B.labels.length===1?"":"s"}</span>
|
|
523
|
-
</button>`)),Z&&U.length>Q.length&&k.push(`<p class="slm-ch-scopehint">${(U.length-Q.length).toLocaleString()} more row${U.length-Q.length===1?"":"s"}. Search to narrow the list.</p>`)}),g.innerHTML=k.join("")||(E?`<div class="slm-ch-scope-empty" data-ch-state="scope-nomatch">No sections or rows match \u201C${p(E)}\u201D.</div>`:`<div class="slm-ch-scope-empty" data-ch-state="scope-empty">This chart has no rows with selectable seats.
|
|
524
|
-
Use Drag box or the seat list instead.</div>`),H.textContent=E?`Showing ${O.toLocaleString()} of ${C.toLocaleString()} matching rows. Section checkboxes still select every row in that section.`:"Showing section groups. Expand one or search to see rows.",g.querySelectorAll("[data-ch-scope-group]").forEach(P=>P.addEventListener("click",()=>{let R=o[Number(P.dataset.chScopeGroup)]?.[1]??[],X=R.every(V=>c.has(V.id));for(let V of R)X?c.delete(V.id):c.add(V.id);L(),S()})),g.querySelectorAll("[data-ch-scope-toggle]").forEach(P=>P.addEventListener("click",()=>{let R=Number(P.dataset.chScopeToggle);h.has(R)?h.delete(R):h.add(R),L()})),g.querySelectorAll("[data-ch-scope-id]").forEach(P=>P.addEventListener("click",()=>{let R=P.dataset.chScopeId;c.has(R)?c.delete(R):c.add(R),L(),S()}))};m.addEventListener("input",()=>{E=m.value.trim().toLocaleLowerCase(),L(),S()}),f.addEventListener("click",()=>{let k=[...N()];!c.size||k.length>I||(this.closeDialog(),this.host.selectByLabels(k))}),L(),S()});return}let a=[...i.entries()].map(([o,r])=>`
|
|
525
|
-
<div class="slm-ch-seatgroup"><span>${p(o)}</span></div>
|
|
526
|
-
${r.map(d=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
527
|
-
aria-checked="false" data-ch-scope-id="${p(d.id)}">
|
|
528
|
-
<span class="box" aria-hidden="true">\u2713</span>
|
|
529
|
-
<span>${p(d.label)}</span>
|
|
530
|
-
<span class="meta">${d.labels.length.toLocaleString()} seat${d.labels.length===1?"":"s"}</span>
|
|
531
|
-
</button>`).join("")}`).join("");this.renderScrim(`
|
|
532
|
-
<h3 id="slm-ch-dlg-title">Add whole sections</h3>
|
|
533
|
-
<p class="sub">Choose one or more. They are added to the seats already selected on the map.</p>
|
|
534
|
-
<div class="slm-ch-seatlist">${a||`<div class="slm-ch-scope-empty" data-ch-state="scope-empty">This chart has no sections with selectable seats.
|
|
535
|
-
Use Drag box or the seat list instead.</div>`}</div>
|
|
536
|
-
<p class="slm-ch-err" data-ch-error hidden></p>
|
|
537
|
-
<div class="foot">
|
|
538
|
-
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
539
|
-
<button type="button" class="slm-btn" data-ch-add-scope disabled>Add seats</button>
|
|
540
|
-
</div>`,o=>{let r=new Map(n.map(g=>[g.id,g])),d=new Set,c=new Set(this.host.selectionLabels()),h=o.querySelector("[data-ch-add-scope]"),u=o.querySelector("[data-ch-error]"),f=()=>{let g=new Set(c);for(let m of d)for(let y of r.get(m)?.labels??[])g.add(y);return g},v=()=>{let g=f(),m=g.size-c.size,y=g.size>I;h.disabled=m===0||y,h.textContent=y?`Maximum ${I.toLocaleString()} seats`:`Add ${m.toLocaleString()} seat${m===1?"":"s"}`,u.hidden=!y,u.textContent=y?`That would make ${g.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:""};o.querySelectorAll("[data-ch-scope-id]").forEach(g=>{g.addEventListener("click",()=>{let m=g.dataset.chScopeId;d.has(m)?d.delete(m):d.add(m),g.setAttribute("aria-checked",String(d.has(m))),v()})}),h.addEventListener("click",()=>{let g=[...f()];!d.size||g.length>I||(this.closeDialog(),this.host.selectByLabels(g))}),v()})}openDialog(e){this.dialog=e,this.renderDialog()}renderDialog(){let e=this.dialog;e&&(e.kind==="create"?this.renderCreateDialog(e):e.kind==="review"?this.renderReviewDialog(e):e.kind==="scope"?this.renderScopeDialog(e):e.kind==="archive"?this.renderArchiveDialog(e):e.kind==="rename"?this.renderRenameDialog(e):e.kind==="pricing"?this.renderPricingDialog(e):e.kind==="seatlist"?this.renderSeatListDialog():e.kind==="menu"?this.renderMenuDialog(e):e.kind==="linkCreate"?this.renderLinkCreateDialog(e):e.kind==="linkRotate"?this.renderLinkRotateDialog(e):e.kind==="linkRevoke"?this.renderLinkRevokeDialog(e):e.kind==="intentSwitch"&&this.renderIntentSwitchDialog(e))}renderIntentSwitchDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId),s=e.intentTo;if(!t||!s||!this.caps.manage){this.closeDialog();return}let{headline:n,consequences:i}=Te(e.switchBlocked);this.renderScrim(`
|
|
541
|
-
<h3 id="slm-ch-dlg-title">Change how ${p(t.name)} reaches buyers?</h3>
|
|
542
|
-
<p class="sub">${p(n)}</p>
|
|
535
|
+
${c}`}paintSelection(){this.caps.manage&&this.host.selectionLabels().length&&(this.assignOpen=!0),this.view==="inspect"&&!this.detailChannelId&&this.paintRail()}wireRail(){let e=this.host.rail;e.querySelectorAll("[data-ch-view]").forEach(a=>{a.addEventListener("click",()=>this.setView(a.dataset.chView))}),e.querySelectorAll("[data-ch-map]").forEach(a=>{a.addEventListener("click",()=>{this.mapIntent=a.dataset.chMap==="assign"?"assign":"pan",this.mapIntent==="assign"&&(this.assignOpen=!0),this.paintRail(),this.onInteractionChange?.()})}),e.querySelectorAll("[data-ch-open]").forEach(a=>{let l=()=>this.openChannel(a.dataset.chOpen);a.addEventListener("click",l),a.addEventListener("keydown",r=>{r.key!=="Enter"&&r.key!==" "&&r.key!=="Spacebar"||(r.preventDefault(),l())})}),e.querySelectorAll("[data-ch-menu]").forEach(a=>{a.addEventListener("click",l=>{l.stopPropagation(),this.openDialog({kind:"menu",channelId:a.dataset.chMenu})}),a.addEventListener("keydown",l=>{l.stopPropagation()})}),e.querySelectorAll("[data-ch-rotate]").forEach(a=>{a.addEventListener("click",()=>this.openDialog({kind:"linkRotate",channelId:this.detailChannelId,linkId:a.dataset.chRotate}))}),e.querySelectorAll("[data-ch-revoke]").forEach(a=>{a.addEventListener("click",()=>this.openDialog({kind:"linkRevoke",channelId:this.detailChannelId,linkId:a.dataset.chRevoke}))});let t=e.querySelector("[data-ch-target]");t?.addEventListener("change",()=>{this.targetChannelId=t.value,this.conflict=!1,this.paintRail()});let s=e.querySelector("[data-ch-audience]");s?.addEventListener("change",()=>{this.previewAudience=[s.value],this.loadPreview()});let n=e.querySelector("[data-ch-includepublic]");n?.addEventListener("change",()=>{this.previewIncludePublic=n.checked,this.loadPreview()}),e.querySelector(".slm-ch-grab")?.addEventListener("click",()=>this.cycleDetent()),e.querySelectorAll("[data-ch-act]").forEach(a=>{a.addEventListener("click",()=>this.railAction(a.dataset.chAct))}),this.chooser.wireFind(e)}openChannel(e){this.detailChannelId=e,this.paintRail(),this.loadLinks(e).then(()=>this.paintRail())}railAction(e){switch(e){case"sections":this.focusedSectionId=null,this.host.showSectionOverview(),this.paintRail();break;case"create":this.openDialog({kind:"create"});break;case"review":this.openDialog({kind:"review"});break;case"rename":this.openDialog({kind:"rename",channelId:this.detailChannelId});break;case"pricing":this.openDialog({kind:"pricing",channelId:this.detailChannelId});break;case"archive":this.openDialog({kind:"archive",channelId:this.detailChannelId});break;case"seatlist":this.openDialog({kind:"seatlist"});break;case"pause":this.togglePause();break;case"discard":this.host.clearSelection();break;case"back":this.detailChannelId=null,this.linksChannelId=null,this.links=[],this.linksState="idle",this.paintRail();break;case"link-create":this.openDialog({kind:"linkCreate",channelId:this.detailChannelId});break;case"embed-code":this.chooseWebsiteIntegration();break;case"route-internal":this.setAccessIntent("internal");break;case"route-none":this.setAccessIntent("none");break;case"link-reload":this.detailChannelId&&this.reloadLinks();break;case"retry":this.refresh();break;case"toggle-archived":this.showArchived=!this.showArchived,this.refresh();break;case"refresh-review":this.conflict=!1,this.refresh().then(()=>this.openDialog({kind:"review"}));break;case"pick-sections":this.openDialog({kind:"scope",scope:"sections"});break;case"pick-rows":this.openDialog({kind:"scope",scope:"rows"});break;case"drag-select":this.mapIntent="assign",this.paintRail(),this.onInteractionChange?.();break;case"pick-category":this.pickCategory();break;case"assign-open":this.assignOpen=!0,this.mapIntent="assign",this.paintRail(),this.onInteractionChange?.();break;case"assign-close":this.assignOpen=!1,this.mapIntent="pan",this.paintRail(),this.onInteractionChange?.();break;case"preview-retry":this.loadPreview();break;default:break}}pickCategory(){this.chooser.openCategory()}renderScopeDialog(e){e.scope==="rows"?this.chooser.openRows():this.chooser.openSections()}openDialog(e){this.dialog=e,this.renderDialog()}renderDialog(){let e=this.dialog;e&&(e.kind==="create"?this.renderCreateDialog(e):e.kind==="review"?this.renderReviewDialog(e):e.kind==="scope"?this.renderScopeDialog(e):e.kind==="archive"?this.renderArchiveDialog(e):e.kind==="rename"?this.renderRenameDialog(e):e.kind==="pricing"?this.renderPricingDialog(e):e.kind==="seatlist"?this.renderSeatListDialog():e.kind==="menu"?this.renderMenuDialog(e):e.kind==="linkCreate"?this.renderLinkCreateDialog(e):e.kind==="linkRotate"?this.renderLinkRotateDialog(e):e.kind==="linkRevoke"?this.renderLinkRevokeDialog(e):e.kind==="intentSwitch"&&this.renderIntentSwitchDialog(e))}renderIntentSwitchDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId),s=e.intentTo;if(!t||!s||!this.caps.manage){this.closeDialog();return}let{headline:n,consequences:i}=Pe(e.switchBlocked);this.renderScrim(`
|
|
536
|
+
<h3 id="slm-ch-dlg-title">Change how ${u(t.name)} reaches buyers?</h3>
|
|
537
|
+
<p class="sub">${u(n)}</p>
|
|
543
538
|
<div class="slm-ch-alert warn" role="alert"><span>\u26A0</span><span>
|
|
544
|
-
${i.map(a=>`<span style="display:block;margin-bottom:6px">${
|
|
539
|
+
${i.map(a=>`<span style="display:block;margin-bottom:6px">${u(a)}</span>`).join("")}
|
|
545
540
|
</span></div>
|
|
546
541
|
${e.pendingLink?`<p class="slm-note">Your new buyer link is created as soon as
|
|
547
542
|
the route changes \u2014 you will not have to fill the form in again.</p>`:""}
|
|
548
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
543
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
549
544
|
<div class="foot">
|
|
550
545
|
<button type="button" class="quiet" data-ch-close>Leave it as it is</button>
|
|
551
546
|
<button type="button" class="slm-btn" data-ch-intent-ack${e.busy?" disabled":""}>
|
|
552
|
-
${e.busy?"Changing\u2026":`Change to "${
|
|
547
|
+
${e.busy?"Changing\u2026":`Change to "${u(q(s))}"`}</button>
|
|
553
548
|
</div>`,a=>{a.querySelector("[data-ch-intent-ack]")?.addEventListener("click",()=>{this.acknowledgeIntentSwitch(s,e.pendingLink??null)})})}async acknowledgeIntentSwitch(e,t){let s=this.detailChannelId;if(!s){this.closeDialog();return}if(this.dialog&&(this.dialog.busy=!0,this.renderDialog()),!await this.setAccessIntent(e,{acknowledgeLiveAccess:!0})){this.dialog?.kind==="intentSwitch"&&(this.dialog.busy=!1,this.renderDialog());return}if(!t){this.closeDialog();return}this.dialog?.kind==="intentSwitch"&&(this.dialog.busy=!1,this.renderDialog()),await this.mintLink(s,t)}renderScrim(e,t){let s=this.scrimEl;s||(this.lastFocus=document.activeElement??null),s?.remove();let n=document.createElement("div");n.className="slm-ch-scrim",n.innerHTML=`<div class="slm-ch-dialog" role="dialog" aria-modal="true"
|
|
554
|
-
aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,this.host.root.appendChild(n),this.scrimEl=n;let i=n.firstElementChild;i.querySelectorAll("[data-ch-close]").forEach(
|
|
549
|
+
aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,this.host.root.appendChild(n),this.scrimEl=n;let i=n.firstElementChild;i.querySelectorAll("[data-ch-close]").forEach(l=>{l.addEventListener("click",()=>this.closeDialog())}),n.addEventListener("keydown",l=>{if(l.key==="Escape"){l.stopPropagation(),this.closeDialog();return}if(l.key!=="Tab")return;let r=[...i.querySelectorAll('summary,button:not([disabled]),select:not([hidden]),input,textarea,a[href],[tabindex]:not([tabindex="-1"])')];if(!r.length)return;let c=r[0],d=r[r.length-1];l.shiftKey&&document.activeElement===c?(l.preventDefault(),d.focus()):!l.shiftKey&&document.activeElement===d&&(l.preventDefault(),c.focus())}),t(i),W(i),(i.querySelector("input,summary,button")??i).focus()}closeDialog(e={}){this.dialog=null,this.scrimEl?.remove(),this.scrimEl=null,e.restoreFocus!==!1&&this.lastFocus?.focus?.(),this.lastFocus=null}renderCreateDialog(e){let t=(this.list?.channels??[]).map(n=>V(n.marker||n.name,"")),s=ne("",t);this.renderScrim(`
|
|
555
550
|
<h3 id="slm-ch-dlg-title">Create channel</h3>
|
|
556
551
|
<p class="sub">A named allocation only the right audience can buy from. You'll pick the seats next.</p>
|
|
557
552
|
<div class="slm-field">
|
|
@@ -562,7 +557,7 @@
|
|
|
562
557
|
<div class="slm-field">
|
|
563
558
|
<label>Marker</label>
|
|
564
559
|
<div style="display:flex;gap:8px;align-items:center">
|
|
565
|
-
<span class="slm-ch-mk" data-ch-marker style="background:${
|
|
560
|
+
<span class="slm-ch-mk" data-ch-marker style="background:${u(s.color)};width:28px;height:28px;font-size:13px">${u(s.letter)}</span>
|
|
566
561
|
<span class="slm-note" style="margin:0">Letter comes from the name; colour is chosen automatically from the next available palette. Buyers never see either.</span>
|
|
567
562
|
</div>
|
|
568
563
|
</div>
|
|
@@ -571,32 +566,32 @@
|
|
|
571
566
|
<input class="slm-input" id="slm-ch-ref" maxlength="120" placeholder="e.g. travel-agency-a" />
|
|
572
567
|
<p class="slm-note">A stable ID for your own system and webhooks.</p>
|
|
573
568
|
</div>
|
|
574
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
569
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
575
570
|
<div class="foot">
|
|
576
571
|
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
577
572
|
<button type="button" class="slm-btn ghost" data-ch-create="plain">Create without allocating</button>
|
|
578
573
|
<button type="button" class="slm-btn" data-ch-create="allocate">Create and allocate seats</button>
|
|
579
|
-
</div>`,n=>{let i=n.querySelector("#slm-ch-name"),a=n.querySelector("[data-ch-marker]");i.addEventListener("input",()=>{let
|
|
574
|
+
</div>`,n=>{let i=n.querySelector("#slm-ch-name"),a=n.querySelector("[data-ch-marker]");i.addEventListener("input",()=>{let l=ne(i.value,t);a.textContent=l.letter,a.style.background=l.color}),n.querySelectorAll("[data-ch-create]").forEach(l=>{l.addEventListener("click",()=>{let r=l.dataset.chCreate==="allocate";this.createChannel(i.value,a.textContent??"",a.style.background,n.querySelector("#slm-ch-ref")?.value??"",r)})})})}async createChannel(e,t,s,n,i){let a=e.trim();if(!a){this.showDialogError("Give the channel a name your team will recognise.");return}try{let l=await this.host.api.createChannel(this.host.eventKey,{name:a,marker:V(t,"")||null,color:s||null,externalRef:n.trim()||null});this.closeDialog(),await this.refresh(),this.targetChannelId=l.channel.id,this.detailChannelId=i?null:l.channel.id,this.announce(`Channel ${a} created with 0 seats allocated.`),this.host.toast(i?`${a} created. Select seats on the map to allocate them.`:`${a} created.`,"ok"),this.paintRail()}catch(l){let r=l instanceof w?l.code:void 0;this.showDialogError(r==="channel_name_taken"?"That name is already used on this event. Pick another.":"Couldn't create the channel. Try again."),this.host.onError(l)}}showDialogError(e){let t=this.scrimEl?.querySelector("[data-ch-error]");t&&(t.textContent=e,t.hidden=!1)}renderReviewDialog(e){let{labels:t,buckets:s}=this.currentPlan(),n=e.applied,i=n?n.buckets:s,a=this.nameOf(n?.targetChannelId??this.targetChannelId)??P,l=$e(i,a),r=n?n.applied:Z(s),c=!n&&t.length>0&&r===0,d=!n&&t.length>_,h=J(l),f=n?'<div class="foot"><button type="button" class="slm-btn" data-ch-close>Done</button></div>':`<div class="foot">
|
|
580
575
|
<button type="button" class="quiet" data-ch-close>Back</button>
|
|
581
|
-
<button type="button" class="slm-btn" data-ch-apply ${d||
|
|
576
|
+
<button type="button" class="slm-btn" data-ch-apply ${c||d||e.busy?"disabled":""}>
|
|
582
577
|
${e.busy?"Applying\u2026":`Apply ${r.toLocaleString()} change${r===1?"":"s"}`}
|
|
583
578
|
</button>
|
|
584
|
-
</div>`,
|
|
585
|
-
every seat is in a buyer's checkout, already sold, or already in ${
|
|
586
|
-
One Apply can cover at most ${
|
|
587
|
-
<h3 id="slm-ch-dlg-title">${n?`Moved ${n.applied.toLocaleString()} seat${n.applied===1?"":"s"} to ${
|
|
579
|
+
</div>`,m=!n&&Re(s)?'<p class="slm-note">Applying moves inventory out of another private channel. That is the line marked above.</p>':"",p=c?`<div class="slm-ch-alert warn"><span>\u2139</span><span>Nothing in this selection can move right now \u2014
|
|
580
|
+
every seat is in a buyer's checkout, already sold, or already in ${u(a)}.</span></div>`:"",v=d?`<div class="slm-ch-alert warn" role="alert"><span>\u2139</span><span><b>Choose fewer seats.</b>
|
|
581
|
+
One Apply can cover at most ${_.toLocaleString()} seats.</span></div>`:"";this.renderScrim(`
|
|
582
|
+
<h3 id="slm-ch-dlg-title">${n?`Moved ${n.applied.toLocaleString()} seat${n.applied===1?"":"s"} to ${u(a)}`:`Move ${t.length.toLocaleString()} selected seat${t.length===1?"":"s"} to ${u(a)}`}</h3>
|
|
588
583
|
<p class="sub">${n?"These are the exact counts the server applied.":"Every selected seat is in exactly one line below."}</p>
|
|
584
|
+
${p}
|
|
589
585
|
${v}
|
|
590
|
-
${g}
|
|
591
586
|
${h||'<div class="slm-empty">Nothing selected.</div>'}
|
|
592
|
-
${
|
|
593
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
594
|
-
${
|
|
595
|
-
<span>Assigned <b>${e.applied.toLocaleString()}</b> seat${e.applied===1?"":"s"} to ${
|
|
587
|
+
${m}
|
|
588
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
589
|
+
${f}`,y=>{y.querySelector("[data-ch-apply]")?.addEventListener("click",()=>{this.apply()})}),n&&this.announce(`Applied ${n.applied} change${n.applied===1?"":"s"} to ${a}.`)}async apply(){if(!this.dialog||!this.caps.manage)return;let{labels:e}=this.currentPlan();if(e.length){if(e.length>_){this.showDialogError(`Choose at most ${_.toLocaleString()} seats for one Apply.`);return}this.dialog={...this.dialog,busy:!0,error:null},this.renderDialog();try{let t=await this.host.api.applyChannelAssignment(this.host.eventKey,{targetChannelId:O(this.targetChannelId)?null:this.targetChannelId,labels:e,assignmentVersion:this.assignmentVersion});this.assignmentVersion=t.assignmentVersion,this.conflict=!1,await this.refresh({quiet:!0}),this.closeDialog({restoreFocus:!1}),this.host.clearSelection(),this.showApplied(t)}catch(t){if(t instanceof w&&t.status===409&&t.code==="channel_assignment_conflict"){this.conflict=!0,this.closeDialog(),this.shakeStaged(),this.paintRail(),this.announce("Assignments changed while you were editing. Nothing was applied and your selection is kept.");return}if(t instanceof w&&t.status===403){this.caps={view:this.caps.view,manage:!1},this.closeDialog(),this.paintRail(),this.host.toast("Changing channels needs channel-management permission.","err");return}this.dialog={kind:"review",busy:!1,error:"Couldn't apply those changes. Try again."},this.renderDialog(),this.host.onError(t)}}}showApplied(e){let t=this.nameOf(e.targetChannelId)??P,s=e.buckets.skippedHeld.count+e.buckets.skippedBooked.count+e.buckets.notFound.count;this.setStaged(`<span class="slm-ch-tick" aria-hidden="true">\u2713</span>
|
|
590
|
+
<span>Assigned <b>${e.applied.toLocaleString()}</b> seat${e.applied===1?"":"s"} to ${u(t)}
|
|
596
591
|
${s?` \xB7 ${s.toLocaleString()} skipped`:""}</span>
|
|
597
592
|
<span class="grow"></span>
|
|
598
593
|
<button type="button" class="drop" data-ch-applied-details>Details</button>`,"done"),this.stagedEl?.querySelector("[data-ch-applied-details]")?.addEventListener("click",()=>{this.openDialog({kind:"review",applied:e})}),this.announce(`Assigned ${e.applied} seat${e.applied===1?"":"s"} to ${t}${s?`; ${s} skipped`:""}.`),this.stagedDoneTimer&&clearTimeout(this.stagedDoneTimer),this.stagedDoneTimer=setTimeout(()=>this.setStaged(null),5e3)}shakeStaged(){let e=this.stagedEl;!e||!e.classList.contains("on")||(e.classList.remove("shake"),e.offsetWidth,e.classList.add("shake"))}renderMenuDialog(e){let t=this.list?.channels.find(n=>n.id===e.channelId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.state==="paused";this.renderScrim(`
|
|
599
|
-
<h3 id="slm-ch-dlg-title">${
|
|
594
|
+
<h3 id="slm-ch-dlg-title">${u(t.name)}</h3>
|
|
600
595
|
<p class="sub">Open the channel to allocate seats and hand out buyer access.
|
|
601
596
|
These are the rest of its actions.</p>
|
|
602
597
|
<div class="slm-ch-menu">
|
|
@@ -609,72 +604,57 @@
|
|
|
609
604
|
Archiving closes the channel for good and returns its free seats to a destination you choose.
|
|
610
605
|
Nothing is ever deleted silently.</p>
|
|
611
606
|
<div class="foot"><button type="button" class="quiet" data-ch-close>Cancel</button></div>`,n=>{n.querySelectorAll("[data-ch-menu-act]").forEach(i=>{i.addEventListener("click",()=>{let a=i.dataset.chMenuAct;if(a==="open"){this.closeDialog(),this.openChannel(t.id);return}if(a==="rename"){this.openDialog({kind:"rename",channelId:t.id});return}if(a==="archive"){this.openDialog({kind:"archive",channelId:t.id});return}this.closeDialog(),this.togglePause(t.id)})})})}renderRenameDialog(e){let t=this.list?.channels.find(s=>s.id===e.channelId);if(!t){this.closeDialog();return}this.renderScrim(`
|
|
612
|
-
<h3 id="slm-ch-dlg-title">Rename ${
|
|
607
|
+
<h3 id="slm-ch-dlg-title">Rename ${u(t.name)}</h3>
|
|
613
608
|
<p class="sub">Only your team and your reports see this name.</p>
|
|
614
609
|
<div class="slm-field">
|
|
615
610
|
<label for="slm-ch-newname">Name</label>
|
|
616
|
-
<input class="slm-input" id="slm-ch-newname" maxlength="80" value="${
|
|
611
|
+
<input class="slm-input" id="slm-ch-newname" maxlength="80" value="${u(t.name)}" />
|
|
617
612
|
</div>
|
|
618
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
613
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
619
614
|
<div class="foot">
|
|
620
615
|
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
621
616
|
<button type="button" class="slm-btn" data-ch-rename>Save name</button>
|
|
622
|
-
</div>`,s=>{s.querySelector("[data-ch-rename]")?.addEventListener("click",()=>{let n=s.querySelector("#slm-ch-newname")?.value??"";if(!n.trim()){this.showDialogError("A channel needs a name.");return}this.host.api.renameChannel(this.host.eventKey,t.id,n.trim()).then(()=>(this.closeDialog(),this.refresh())).catch(i=>{this.showDialogError(i instanceof
|
|
623
|
-
<span><b>${
|
|
617
|
+
</div>`,s=>{s.querySelector("[data-ch-rename]")?.addEventListener("click",()=>{let n=s.querySelector("#slm-ch-newname")?.value??"";if(!n.trim()){this.showDialogError("A channel needs a name.");return}this.host.api.renameChannel(this.host.eventKey,t.id,n.trim()).then(()=>(this.closeDialog(),this.refresh())).catch(i=>{this.showDialogError(i instanceof w&&i.code==="channel_name_taken"?"That name is already used on this event.":"Couldn't rename the channel."),this.host.onError(i)})})})}renderPricingDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId),s=this.host.api.updateChannelPricing;if(!t||!s||!this.caps.manage){this.closeDialog();return}let n=new Map((t.priceOverrides??[]).map(a=>[`${a.categoryKey}\0${a.tierId??""}`,a.price])),i=this.host.categories().flatMap(a=>(a.tiers?.length?a.tiers:[null]).map(r=>{let c=r?.id??null,d=`${a.key}\0${c??""}`,h=r?.price??a.price??0,f=n.get(d),m=r?`${a.label} \xB7 ${r.name}`:a.label;return`<label class="slm-ch-price-row">
|
|
618
|
+
<span><b>${u(m)}</b><small>Event price ${u(String(h))}</small></span>
|
|
624
619
|
<input class="slm-input" type="number" min="0" max="1000000" step="0.01"
|
|
625
|
-
inputmode="decimal" aria-label="Custom price for ${
|
|
626
|
-
data-ch-price-category="${
|
|
627
|
-
placeholder="${
|
|
620
|
+
inputmode="decimal" aria-label="Custom price for ${u(m)}"
|
|
621
|
+
data-ch-price-category="${u(a.key)}" data-ch-price-tier="${u(c??"")}"
|
|
622
|
+
placeholder="${u(String(h))}" value="${f===void 0?"":u(String(f))}"
|
|
628
623
|
${e.busy?"disabled":""} />
|
|
629
624
|
</label>`})).join("");this.renderScrim(`
|
|
630
|
-
<h3 id="slm-ch-dlg-title">Prices for ${
|
|
625
|
+
<h3 id="slm-ch-dlg-title">Prices for ${u(t.name)}</h3>
|
|
631
626
|
<p class="sub">Set only the prices that differ for this audience. Leave a field blank to use the event price.</p>
|
|
632
627
|
<div class="slm-ch-price-list">${i||'<p class="slm-empty">This event has no priced categories.</p>'}</div>
|
|
633
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
628
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
634
629
|
<div class="foot">
|
|
635
630
|
<button type="button" class="quiet" data-ch-close ${e.busy?"disabled":""}>Cancel</button>
|
|
636
631
|
<button type="button" class="slm-btn" data-ch-price-save ${e.busy||!i?"disabled":""}>
|
|
637
632
|
${e.busy?"Saving\u2026":"Save prices"}
|
|
638
633
|
</button>
|
|
639
|
-
</div>`,a=>{a.querySelector("[data-ch-price-save]")?.addEventListener("click",()=>{let
|
|
634
|
+
</div>`,a=>{a.querySelector("[data-ch-price-save]")?.addEventListener("click",()=>{let l=[];for(let r of a.querySelectorAll("[data-ch-price-category]")){let c=r.value.trim();if(!c)continue;let d=Number(c);if(!Number.isFinite(d)||d<0||d>1e6){r.focus(),this.showDialogError("Enter a price from 0 to 1,000,000, or leave the field blank.");return}l.push({categoryKey:r.dataset.chPriceCategory,tierId:r.dataset.chPriceTier||null,price:d})}this.saveChannelPricing(t,l)})})}async saveChannelPricing(e,t){let s=this.host.api.updateChannelPricing;if(!(!s||!this.dialog||this.dialog.kind!=="pricing")){this.dialog={...this.dialog,busy:!0,error:null},this.renderDialog();try{await s.call(this.host.api,this.host.eventKey,e.id,t,e.pricingVersion??0),this.closeDialog(),await this.refresh(),this.host.toast(t.length?`Custom prices saved for ${e.name}.`:`${e.name} now uses event prices.`,"ok")}catch(n){if(n instanceof w&&n.code==="channel_pricing_conflict"){await this.refresh({quiet:!0}),this.dialog={kind:"pricing",channelId:e.id,error:"Prices changed in another window. Latest values are shown \u2014 review and save again."},this.renderDialog();return}this.dialog={kind:"pricing",channelId:e.id,error:n instanceof w&&n.serverMessage?n.serverMessage:"Couldn't save these prices. Try again."},this.renderDialog(),this.host.onError(n)}}}async chooseWebsiteIntegration(){this.detailChannelId&&await this.setAccessIntent("server")}async setAccessIntent(e,t={}){let s=this.detailChannelId;if(!s||!this.caps.manage)return!1;try{let n=await this.host.api.setChannelAccessIntent(this.host.eventKey,s,e,t);return await this.refresh(),this.host.toast(this.intentSavedCopy(e,n?.intentSwitch),"ok"),!0}catch(n){return n instanceof w&&n.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:s,intentTo:e,switchBlocked:n.details}),!1):n instanceof w&&n.code==="channel_access_intent_forbids"?(this.host.toast(Q(n.details),"err"),!1):(this.host.toast("Couldn't change how this channel reaches buyers.","err"),this.host.onError(n),!1)}}intentSavedCopy(e,t){let s=e==="server"?"Set to your website or app. The embed code is on the Embed page.":e==="internal"?"Only your own staff can sell this channel now.":e==="hosted_link"?"Set to buyer links. Create one to let buyers in.":"Kept as a protected reserve. No route can sell these seats.";if(!t)return s;let n=t.closedLinks?` ${t.closedLinks.toLocaleString()} buyer link${t.closedLinks===1?"":"s"} closed.`:"",i=t.keptSessions?` ${t.keptSessions.toLocaleString()} buyer${t.keptSessions===1?"":"s"} already in a checkout can still finish.`:"";return`${s}${n}${i}`}async togglePause(e=this.detailChannelId){let t=this.list?.channels.find(n=>n.id===e);if(!t||!this.caps.manage)return;let s=t.state!=="paused";try{await this.host.api.setChannelPaused(this.host.eventKey,t.id,s),await this.refresh(),this.host.toast(s?`${t.name} paused. Existing checkouts can finish; no new buyer access is issued.`:`${t.name} resumed.`,"ok")}catch(n){this.host.toast("Couldn't change that channel.","err"),this.host.onError(n)}}renderArchiveDialog(e){let t=this.list?.channels.find(l=>l.id===e.channelId);if(!t){this.closeDialog();return}let s=e.archiveBlocked??null,n=!s&&t.counts.held>0,i=this.assignableChannels().filter(l=>l.id!==t.id),a=s?`<div class="slm-ch-alert warn" role="alert"><span>\u23F3</span>
|
|
640
635
|
<span><b>${(s.heldUnits??s.activeHolds??0).toLocaleString()} seats are in a buyer's checkout right now.</b>
|
|
641
|
-
Archive is unavailable while seats are held \u2014 try again ${
|
|
636
|
+
Archive is unavailable while seats are held \u2014 try again ${u(Ae(s))}.</span></div>`:n?`<div class="slm-ch-alert warn"><span>\u23F3</span>
|
|
642
637
|
<span>${t.counts.held.toLocaleString()} seats are in a buyer's checkout right now.
|
|
643
638
|
Archive is refused while any seat is held \u2014 you can try, and we'll tell you when to come back.</span></div>`:"";this.renderScrim(`
|
|
644
|
-
<h3 id="slm-ch-dlg-title">Archive ${
|
|
639
|
+
<h3 id="slm-ch-dlg-title">Archive ${u(t.name)}</h3>
|
|
645
640
|
<p class="sub">The channel closes for good. Its seats move to a destination you choose;
|
|
646
641
|
sales history keeps its attribution.</p>
|
|
647
642
|
${a}
|
|
648
643
|
<div class="slm-field">
|
|
649
644
|
<label for="slm-ch-dest">Move the ${t.counts.free.toLocaleString()} remaining free seats to</label>
|
|
650
645
|
<select class="slm-select" id="slm-ch-dest">
|
|
651
|
-
${i.map(
|
|
646
|
+
${i.map(l=>`<option value="${u(l.id)}">${u(l.name)}</option>`).join("")}
|
|
652
647
|
</select>
|
|
653
648
|
</div>
|
|
654
|
-
<p class="slm-note">${t.counts.booked.toLocaleString()} sold seats keep "${
|
|
649
|
+
<p class="slm-note">${t.counts.booked.toLocaleString()} sold seats keep "${u(t.name)}" on their sale
|
|
655
650
|
record. If one is cancelled later it returns to the destination above. Any buyer access for this channel
|
|
656
651
|
stops working.</p>
|
|
657
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
652
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
658
653
|
<div class="foot">
|
|
659
654
|
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
660
655
|
<button type="button" class="slm-btn danger" data-ch-archive ${s?"disabled":""}>Archive channel</button>
|
|
661
|
-
</div>`,
|
|
662
|
-
<
|
|
663
|
-
<span>${p(a.label)}</span>
|
|
664
|
-
${i?`<button type="button" data-ch-section="${p(i)}">Select section</button>`:""}
|
|
665
|
-
</div>
|
|
666
|
-
${a.seats.map(o=>{let r=this.allocation.get(o.label)??T,d=this.nameOf(r)??M;return`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
667
|
-
aria-checked="${e.has(o.label)}" data-ch-seat="${p(o.label)}">
|
|
668
|
-
<span class="box" aria-hidden="true">\u2713</span>
|
|
669
|
-
<span>${p(o.label)}</span>
|
|
670
|
-
<span class="meta">${p(d)} \xB7 ${p(o.status)}</span>
|
|
671
|
-
</button>`}).join("")}`).join("");this.renderScrim(`
|
|
672
|
-
<h3 id="slm-ch-dlg-title">Seat list</h3>
|
|
673
|
-
<p class="sub">The same selection as the map, with checkboxes. Space or Enter toggles a seat.</p>
|
|
674
|
-
<div class="slm-ch-seatlist">${n||'<div class="slm-empty">No seats on this chart.</div>'}</div>
|
|
675
|
-
${s>this.seatListLimit?'<div class="foot"><button type="button" class="slm-btn ghost" data-ch-more>Show more seats</button></div>':""}
|
|
676
|
-
<div class="foot"><button type="button" class="slm-btn" data-ch-close>Done</button></div>`,i=>{i.querySelectorAll("[data-ch-seat]").forEach(a=>{a.addEventListener("click",()=>{let o=a.dataset.chSeat,r=new Set(this.host.selectionLabels());r.has(o)?r.delete(o):r.add(o),this.host.clearSelection(),r.size&&this.host.selectByLabels([...r]),this.renderSeatListDialog()})}),i.querySelectorAll("[data-ch-section]").forEach(a=>{a.addEventListener("click",()=>{this.host.selectSection(a.dataset.chSection),this.renderSeatListDialog()})}),i.querySelector("[data-ch-more]")?.addEventListener("click",()=>{this.seatListLimit+=Et,this.renderSeatListDialog()})})}async reloadLinks(){let e=this.detailChannelId;e&&(this.linksState=this.links.length?this.linksState:"loading",await this.loadLinks(e),this.paintRail())}async reloadAfterLinkChange(e){if(this.detailChannelId===e){await this.refresh({quiet:!0});return}await this.loadLinks(e),this.active&&this.paintRail()}linkById(e){return this.links.find(t=>t.id===e)??null}renderLinkCreateDialog(e){let t=this.list?.channels.find(s=>s.id===e.channelId);if(!t||!this.caps.manage){this.closeDialog();return}this.renderScrim(`
|
|
677
|
-
<h3 id="slm-ch-dlg-title">Create a buyer link for ${p(t.name)}</h3>
|
|
656
|
+
</div>`,l=>{l.querySelector("[data-ch-archive]")?.addEventListener("click",()=>{let r=l.querySelector("#slm-ch-dest")?.value??"";this.archive(t.id,r||null)})})}async archive(e,t){try{await this.host.api.archiveChannel(this.host.eventKey,e,t),this.closeDialog(),this.detailChannelId=null,await this.refresh(),this.host.toast("Channel archived. Its remaining seats moved to the destination you chose.","ok")}catch(s){if(s instanceof w&&s.status===409&&s.code==="channel_archive_blocked_by_holds"){this.dialog={kind:"archive",channelId:e,archiveBlocked:s.details??{}},this.renderDialog();return}this.showDialogError("Couldn't archive that channel. Try again."),this.host.onError(s)}}renderSeatListDialog(){this.chooser.openSeatList()}async reloadLinks(){let e=this.detailChannelId;e&&(this.linksState=this.links.length?this.linksState:"loading",await this.loadLinks(e),this.paintRail())}async reloadAfterLinkChange(e){if(this.detailChannelId===e){await this.refresh({quiet:!0});return}await this.loadLinks(e),this.active&&this.paintRail()}linkById(e){return this.links.find(t=>t.id===e)??null}renderLinkCreateDialog(e){let t=this.list?.channels.find(s=>s.id===e.channelId);if(!t||!this.caps.manage){this.closeDialog();return}this.renderScrim(`
|
|
657
|
+
<h3 id="slm-ch-dlg-title">Create a buyer link for ${u(t.name)}</h3>
|
|
678
658
|
<p class="sub">Anyone who opens the link can buy from this channel's allocation \u2014 and only from it.
|
|
679
659
|
You'll see the link once, right after you create it.</p>
|
|
680
660
|
<div class="slm-field">
|
|
@@ -696,31 +676,31 @@
|
|
|
696
676
|
<div class="slm-field">
|
|
697
677
|
<label for="slm-ch-lk-redemptions">How many people can use it</label>
|
|
698
678
|
<input class="slm-input" type="number" id="slm-ch-lk-redemptions" inputmode="numeric"
|
|
699
|
-
value="${
|
|
679
|
+
value="${ie.maxRedemptions}" />
|
|
700
680
|
<p class="slm-note">Each buyer who opens the link uses one.</p>
|
|
701
681
|
</div>
|
|
702
682
|
<div class="slm-field">
|
|
703
683
|
<label for="slm-ch-lk-quantity">Seats per buyer</label>
|
|
704
684
|
<input class="slm-input" type="number" id="slm-ch-lk-quantity" inputmode="numeric"
|
|
705
|
-
value="${
|
|
685
|
+
value="${ie.maxQuantity}" />
|
|
706
686
|
</div>
|
|
707
687
|
<label class="slm-note" style="display:flex;gap:8px;align-items:center;margin:2px 0 6px">
|
|
708
688
|
<input type="checkbox" id="slm-ch-lk-public" />
|
|
709
689
|
Also let this link buy Public sale seats
|
|
710
690
|
</label>
|
|
711
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
691
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
712
692
|
<div class="foot">
|
|
713
693
|
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
714
694
|
<button type="button" class="slm-btn" data-ch-lk-create>Create link</button>
|
|
715
|
-
</div>`,s=>{let n=s.querySelector("[data-ch-lk-expiry]"),i=s.querySelector("[data-ch-lk-when-field]"),a=s.querySelector("#slm-ch-lk-when");n.addEventListener("change",()=>{let
|
|
716
|
-
<b>The old link has stopped working.</b> ${e.endedSessions?`${e.endedSessions.toLocaleString()} buyer${e.endedSessions===1?"":"s"} lost access immediately.`:"Buyers who already came in can finish; every new visit needs this link."}</span></div>`:"",i=
|
|
717
|
-
<span class="v">${
|
|
695
|
+
</div>`,s=>{let n=s.querySelector("[data-ch-lk-expiry]"),i=s.querySelector("[data-ch-lk-when-field]"),a=s.querySelector("#slm-ch-lk-when");n.addEventListener("change",()=>{let l=n.value==="custom";i.hidden=!l,l&&!a.value&&(a.value=ns(Date.now()+7*864e5))}),s.querySelector("[data-ch-lk-create]")?.addEventListener("click",()=>{let l=et(s,"#slm-ch-lk-redemptions"),r=et(s,"#slm-ch-lk-quantity");if(l==null||r==null){this.showDialogError("Those two settings need to be whole numbers.");return}let c;if(n.value==="custom"&&(c=Date.parse(a.value),!Number.isFinite(c))){this.showDialogError("Pick the date and time the link should stop working.");return}this.createLink(t.id,{label:s.querySelector("#slm-ch-lk-label")?.value.trim()||null,includePublic:s.querySelector("#slm-ch-lk-public")?.checked??!1,...c===void 0?{}:{expiresAt:c},maxRedemptions:l,maxQuantity:r})})})}async createLink(e,t){await this.ensureHostedLinkRoute(e,t)&&await this.mintLink(e,t)}async mintLink(e,t){try{let s=await this.host.api.createAccessLink(this.host.eventKey,e,t);this.revealLink(s,{channelId:e}),await this.reloadAfterLinkChange(e)}catch(s){this.showDialogError(j(s instanceof w?s:void 0)),s instanceof w||this.host.onError(s)}}async ensureHostedLinkRoute(e,t){if((this.list?.channels.find(n=>n.id===e)?.access?.intent??"none")==="hosted_link")return!0;try{return await this.host.api.setChannelAccessIntent(this.host.eventKey,e,"hosted_link"),await this.refresh(),!0}catch(n){return n instanceof w&&n.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:e,intentTo:"hosted_link",switchBlocked:n.details,pendingLink:t}),!1):(this.showDialogError(n instanceof w&&n.code==="channel_access_intent_forbids"?Q(n.details):"Couldn't set this channel up for buyer links. Try again."),n instanceof w||this.host.onError(n),!1)}}revealLink(e,t){let s=e.url;this.dialog=null;let n=t.rotated?`<div class="slm-ch-alert warn" role="status"><span>\u26A0</span><span>
|
|
696
|
+
<b>The old link has stopped working.</b> ${e.endedSessions?`${e.endedSessions.toLocaleString()} buyer${e.endedSessions===1?"":"s"} lost access immediately.`:"Buyers who already came in can finish; every new visit needs this link."}</span></div>`:"",i=oe(e.link).map(a=>`<div class="slm-ch-lkrow"><span class="k">${u(a.k)}</span>
|
|
697
|
+
<span class="v">${u(a.v)}</span></div>`).join("");this.renderScrim(`
|
|
718
698
|
<h3 id="slm-ch-dlg-title">Copy this link now</h3>
|
|
719
699
|
<p class="sub">This is the only time SeatLayer can show it. We keep just a fingerprint, so it cannot be
|
|
720
700
|
shown again \u2014 if it is lost, rotate the link for a fresh one.</p>
|
|
721
701
|
${n}
|
|
722
702
|
<div class="slm-ch-copyrow">
|
|
723
|
-
<div class="slm-ch-secret" data-ch-lk-url title="${
|
|
703
|
+
<div class="slm-ch-secret" data-ch-lk-url title="${u(s)}">${u(s)}</div>
|
|
724
704
|
<button type="button" class="slm-btn" data-ch-lk-copy aria-live="polite">Copy</button>
|
|
725
705
|
</div>
|
|
726
706
|
<input class="slm-ch-copysink" data-ch-lk-sink tabindex="-1" aria-hidden="true" readonly />
|
|
@@ -731,10 +711,10 @@
|
|
|
731
711
|
${i}
|
|
732
712
|
<div class="foot">
|
|
733
713
|
<button type="button" class="slm-btn" data-ch-close data-ch-lk-done>I've copied it</button>
|
|
734
|
-
</div>`,a=>{let
|
|
714
|
+
</div>`,a=>{let l=a.querySelector("[data-ch-lk-copy]"),r=null;l?.addEventListener("click",()=>{is(a,s).then(c=>{if(!c){l.textContent="Copy",l.classList.remove("copied"),this.announce("Copying was blocked. The link is selected \u2014 copy it by hand.");return}l.textContent="Copied",l.classList.add("copied"),this.announce("Buyer link copied."),r&&clearTimeout(r),r=setTimeout(()=>{l.textContent="Copy",l.classList.remove("copied")},1500)})})}),this.announce("Your buyer link is ready and is shown once.")}renderLinkRotateDialog(e){let t=this.linkById(e.linkId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.activeSessions??0,n=s?`<div class="slm-ch-alert warn"><span>\u26A0</span>
|
|
735
715
|
<span><b>${s.toLocaleString()} buyer${s===1?"":"s"}</b> got in with the current link
|
|
736
716
|
and still ${s===1?"has":"have"} active access.</span></div>`:"";this.renderScrim(`
|
|
737
|
-
<h3 id="slm-ch-dlg-title">Rotate the ${
|
|
717
|
+
<h3 id="slm-ch-dlg-title">Rotate the ${u(t.label||"buyer")} link?</h3>
|
|
738
718
|
<p class="sub">The current link stops opening immediately and cannot be restored. You will get a new
|
|
739
719
|
link to copy \u2014 shown once.</p>
|
|
740
720
|
${n}
|
|
@@ -749,12 +729,12 @@
|
|
|
749
729
|
Buyers part-way through choosing seats lose access.</span></span>
|
|
750
730
|
</label>
|
|
751
731
|
<p class="slm-note">Choose one \u2014 SeatLayer will not decide this for you.</p>
|
|
752
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
732
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
753
733
|
<div class="foot">
|
|
754
734
|
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
755
735
|
<button type="button" class="slm-btn" data-ch-lk-rotate disabled>Rotate and copy new link</button>
|
|
756
|
-
</div>`,i=>{let a=i.querySelector("[data-ch-lk-rotate]");i.querySelectorAll("[data-ch-rot]").forEach(
|
|
757
|
-
<h3 id="slm-ch-dlg-title">Revoke the ${
|
|
736
|
+
</div>`,i=>{let a=i.querySelector("[data-ch-lk-rotate]");i.querySelectorAll("[data-ch-rot]").forEach(l=>{l.addEventListener("change",()=>{a.disabled=!1})}),a.addEventListener("click",()=>{let l=[...i.querySelectorAll("[data-ch-rot]")].find(r=>r.checked);if(!l){this.showDialogError(j({code:"end_active_sessions_required"}));return}this.rotateLink(e.channelId,t.id,l.value==="end")})})}async rotateLink(e,t,s){try{let n=await this.host.api.rotateAccessLink(this.host.eventKey,e,t,s);this.revealLink(n,{channelId:e,rotated:!0}),await this.reloadAfterLinkChange(e)}catch(n){this.showDialogError(j(n instanceof w?n:void 0)),n instanceof w||this.host.onError(n)}}renderLinkRevokeDialog(e){let t=this.linkById(e.linkId);if(!t||!this.caps.manage){this.closeDialog();return}let s=t.activeSessions??0;this.renderScrim(`
|
|
737
|
+
<h3 id="slm-ch-dlg-title">Revoke the ${u(t.label||"buyer")} link?</h3>
|
|
758
738
|
<p class="sub">It stops opening immediately and cannot be restored \u2014 there is no undo, and no way to
|
|
759
739
|
bring the same URL back. Seats already bought through it keep their sale.</p>
|
|
760
740
|
${s?`<label class="slm-ch-radio">
|
|
@@ -763,21 +743,107 @@
|
|
|
763
743
|
buyer${s===1?"":"s"} already inside</b><span class="why">Leave this off and they can
|
|
764
744
|
finish what they started; new visits are refused either way.</span></span>
|
|
765
745
|
</label>`:""}
|
|
766
|
-
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${
|
|
746
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${u(e.error??"")}</p>
|
|
767
747
|
<div class="foot">
|
|
768
748
|
<button type="button" class="quiet" data-ch-close>Cancel</button>
|
|
769
749
|
<button type="button" class="slm-btn danger" data-ch-lk-revoke>Revoke link</button>
|
|
770
|
-
</div>`,n=>{n.querySelector("[data-ch-lk-revoke]")?.addEventListener("click",()=>{let i=n.querySelector("[data-ch-lk-endsessions]")?.checked??!1;this.revokeLink(e.channelId,t.id,i)})})}async revokeLink(e,t,s){try{let n=await this.host.api.revokeAccessLink(this.host.eventKey,e,t,s);this.closeDialog(),await this.reloadAfterLinkChange(e),this.host.toast(n.endedSessions?`Link revoked. ${n.endedSessions.toLocaleString()} buyer${n.endedSessions===1?"":"s"} lost access.`:"Link revoked. It no longer opens for anyone.","ok")}catch(n){this.showDialogError(j(n instanceof
|
|
750
|
+
</div>`,n=>{n.querySelector("[data-ch-lk-revoke]")?.addEventListener("click",()=>{let i=n.querySelector("[data-ch-lk-endsessions]")?.checked??!1;this.revokeLink(e.channelId,t.id,i)})})}async revokeLink(e,t,s){try{let n=await this.host.api.revokeAccessLink(this.host.eventKey,e,t,s);this.closeDialog(),await this.reloadAfterLinkChange(e),this.host.toast(n.endedSessions?`Link revoked. ${n.endedSessions.toLocaleString()} buyer${n.endedSessions===1?"":"s"} lost access.`:"Link revoked. It no longer opens for anyone.","ok")}catch(n){this.showDialogError(j(n instanceof w?n:void 0)),n instanceof w||this.host.onError(n)}}applySheetClasses(){let e=this.host.root,t=this.host.isCompact();e.classList.toggle("ch-sheet",t&&this.active);for(let s of["collapsed","medium","full"])e.classList.toggle(`detent-${s}`,t&&this.active&&this.detent===s);this.host.setMapInert(t&&this.active&&this.detent==="full")}cycleDetent(){let e=["collapsed","medium","full"];this.detent=e[(e.indexOf(this.detent)+1)%e.length],this.applySheetClasses()}handleBack(){return this.scrimEl?(this.closeDialog(),!0):this.host.isCompact()&&this.detent==="full"?(this.detent="medium",this.applySheetClasses(),!0):!1}}});var mn={};it(mn,{ACCESS_LINK_DEFAULTS:()=>ie,ChannelsMode:()=>le,ManageApi:()=>Y,ManageApiError:()=>w,PUBLIC_CHANNEL_ID:()=>R,PUBLIC_CHANNEL_NAME:()=>P,SeatManager:()=>Ve,accessIntentDescription:()=>He,accessIntentLabel:()=>q,accessLine:()=>Ie,accessLinkBadge:()=>Be,accessLinkErrorCopy:()=>j,accessLinkIsLive:()=>ae,accessLinkPolicyLines:()=>oe,bucketRows:()=>$e,bucketRowsHtml:()=>J,dropReviewRows:()=>es,intentForbidsCopy:()=>Q,intentSwitchBlockedCopy:()=>Pe,isPublicChannelId:()=>O,markerLetter:()=>V,markerOf:()=>Te,mutationCount:()=>Z,needsMoveConfirmation:()=>Re,planAssignment:()=>Ee,retryAfterCopy:()=>Ae,selectionSources:()=>Me,stateBadge:()=>De,suggestMarker:()=>ne});module.exports=Ss(mn);re();var ot={hold:"Held",release:"Released",expire:"Expired",book:"Booked",unbook:"Cancelled",block:"Blocked",unblock:"Unblocked"},ce=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 n=await this.fetchPage(e?this.next:void 0,this.action);if(this.closed||s!==this.generation)return;if(this.paintCounts(n),t&&this.entries.length&&n.entries[0]?.id!==this.entries[0]?.id&&this.list.scrollTop>24){this.latest.hidden=!1;return}let i=!t||n.entries[0]?.id!==this.entries[0]?.id;e?(this.entries=[...this.entries,...n.entries.filter(a=>!this.entries.some(l=>l.id===a.id))],this.next=n.nextBefore):i&&(this.entries=n.entries,this.next=n.nextBefore),i&&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 n=document.createElement("button");n.className="slm-btn ghost",n.textContent="Retry",n.onclick=()=>{this.load(e)},this.message.append(n)}}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:n})=>{let i=document.createElement("button");return i.type="button",i.textContent=s?`${ot[s]??s} ${n}`:`${n} changes`,i.setAttribute("aria-pressed",String((this.action??"")===s)),i.onclick=()=>{this.busy||(this.action=s||void 0,this.entries=[],this.next=null,this.list.scrollTop=0,this.latest.hidden=!0,this.load())},i}))}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 n=document.createElement("time");n.dateTime=new Date(t.at).toISOString(),n.textContent=new Date(t.at).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),n.title=new Date(t.at).toString();let i=document.createElement("strong");return i.textContent=ot[t.action]??t.action,s.append(n,i),s})),this.list.scrollTop=e}};var Ls={held:"HOLD",booked:"BOOK",expired:"EXPIRE",released:"RELEASE",cancelled:"CANCEL",blocked:"BLOCK",unblocked:"ON SALE",available:"FREE"},lt={held:"Held",booked:"Booked",expired:"Hold expired",released:"Hold released",cancelled:"Booking cancelled",blocked:"Blocked",unblocked:"Back on sale",available:"Available again"},de=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 n={signal:this.abort.signal},i=()=>{this.paused=!1,this.signature="unrendered",this.list.scrollTop=0,this.render()};this.list.addEventListener("scroll",()=>{this.list.scrollTop>24&&(this.paused=!0)},n),this.list.addEventListener("focusin",()=>{this.paused=!0},n),this.list.addEventListener("toggle",a=>{a.target.open&&(this.paused=!0)},{...n,capture:!0}),this.newer.addEventListener("click",i,n),this.more.addEventListener("click",()=>{this.limit=200,this.signature="unrendered",this.render(!0)},n)}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 n=t.slice(0,this.limit),i=n.map(a=>`${a.id}:${a.verb}`).join("|");if(i!==this.signature){if(this.signature=i,this.shown=new Set(t.map(a=>a.id)),this.list.replaceChildren(),!n.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 n){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=`${lt[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=Ls[a.verb]??a.verb,h.title=lt[a.verb]??a.verb;let f=document.createElement("span");if(f.className="slm-activity-seats",f.textContent=a.labels.join(", "),r.append(d,h,f),l.append(r),a.count>1){let m=document.createElement("details");m.className="slm-activity-details";let p=document.createElement("summary");p.textContent="\u22EF",p.setAttribute("aria-label",`Show all ${a.count} seats`);let v=document.createElement("p");v.textContent=c,m.append(p,v),l.append(m)}this.list.append(l)}this.more.hidden=t.length<=this.limit}}destroy(){this.abort.abort()}};var he=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=y=>`<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">${y}</svg>`,n=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"/>'),i=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">
|
|
771
751
|
<button type="button" data-nav="move" aria-label="Move" aria-pressed="false" title="Drag to move the map; hold Space temporarily">${n}</button>
|
|
772
752
|
<button type="button" data-nav="select" aria-label="Select" aria-pressed="true" title="Drag to select seats \xB7 drag empty floor to move">${i}</button>
|
|
773
753
|
<button type="button" data-nav="search" aria-label="Search" title="Search seats, rows or sections" aria-expanded="false">${a}</button>
|
|
774
|
-
<button type="button" data-nav="zoom" aria-label="Zoom" title="Zoom controls" aria-expanded="false">${
|
|
754
|
+
<button type="button" data-nav="zoom" aria-label="Zoom" title="Zoom controls" aria-expanded="false">${l}</button>
|
|
775
755
|
<button type="button" hidden data-nav="out" aria-label="Zoom out">\u2212</button>
|
|
776
756
|
<button type="button" hidden data-nav="in" aria-label="Zoom in">+</button>
|
|
777
757
|
<span class="slm-navigation-count" role="status" aria-live="polite">0 selected</span>
|
|
778
758
|
<button type="button" class="slm-navigation-clear" data-nav="clear" hidden title="Clear the selection">Clear</button>
|
|
779
759
|
<button type="button" data-nav="rail" aria-label="Hide details" title="Hide details" aria-expanded="true">${r}</button>
|
|
780
|
-
</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
|
|
760
|
+
</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"),f=()=>{h.hidden=!0,this.results.hidden=!0,d.setAttribute("aria-expanded","false"),d.focus()};d.addEventListener("click",()=>{let y=h.hidden;h.hidden=!y,d.setAttribute("aria-expanded",String(y)),y&&this.search.focus()},c);let m=t.querySelector('[data-nav="zoom"]');m.addEventListener("click",()=>{let y=m.getAttribute("aria-expanded")!=="true";m.setAttribute("aria-expanded",String(y));for(let g of["in","out"])t.querySelector(`[data-nav="${g}"]`).hidden=!y},c),this.search.addEventListener("keydown",y=>{y.key==="Escape"&&f()},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 p=t.querySelector('[data-nav="rail"]');p.addEventListener("click",()=>{let y=e.root.classList.toggle("details-hidden");p.setAttribute("aria-expanded",String(!y)),p.setAttribute("aria-label",y?"Show details":"Hide details"),p.title=y?"Show details":"Hide details"},c),this.search.addEventListener("input",()=>this.find(),c),this.search.addEventListener("keydown",y=>{y.key==="Escape"&&(this.results.hidden=!0),y.key==="ArrowDown"&&(y.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",y=>{y.target?.closest('input,textarea,select,button,[contenteditable="true"]')||y.code!=="Space"||y.ctrlKey||y.metaKey||y.altKey||(y.preventDefault(),this.space||(this.space=!0,e.pauseFollow(),e.setMoving(!0)))},c);let v=()=>{this.space&&(this.space=!1,e.setMoving(this.moving))};window.addEventListener("keyup",y=>{y.code==="Space"&&v()},c),window.addEventListener("blur",v,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",y=>{e.root.contains(y.relatedTarget)||v()},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 n=document.createElement("button");n.type="button",n.textContent=`${s.label} \xB7 ${s.detail}`,n.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(n)}t.length||(this.results.textContent="No matching section, row or seat.")}destroy(){this.abort.abort(),this.bar.remove(),this.location.remove()}};var S=require("@seatlayer/core");pe();var Es=/^[a-zA-Z0-9._-]+$/;function Rs(o){let e;try{e=new URL(o,"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]),n=decodeURIComponent(t[2]);return!s||!Es.test(n)?null:{eventKey:s,asset:n}}catch{return null}}function $s(o){try{return/^\/v1\/events\/[^/]+\/assets(?:\/|$)/.test(new URL(o,"https://seatlayer.invalid").pathname)}catch{return!1}}var ue=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=Rs(e);if(!t)return Promise.resolve($s(e)?null:e);if(t.eventKey!==this.eventKey||this.disposed)return Promise.resolve(null);let s=`${t.eventKey}/${t.asset}`,n=this.pending.get(s);if(n)return n;let i=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,i),i}async prepareRendererChart(e){let t=async i=>{if(!i?.url)return;let a=await this.resolve(i.url);if(!a)throw new Error("organizer_event_asset_scope_mismatch");i.url=a},s=async i=>{for(let a of i){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}},n=async i=>{await t(i.backgroundImage),await s(i.objects)};await n(e);for(let i of e.floors??[])await n(i);return e}dispose(){if(!this.disposed){this.disposed=!0;for(let e of this.created)URL.revokeObjectURL(e);this.created.clear(),this.pending.clear()}}};re();function ht(o,e,t,s={}){let n=s.previous?null:document.activeElement??null;s.previous?.scrim.remove();let i=document.createElement("div");i.className="slm-ch-scrim",i.innerHTML=`<div class="slm-ch-dialog" role="dialog" aria-modal="true"
|
|
761
|
+
aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,o.appendChild(i);let a=i.firstElementChild,l=!1,r={scrim:i,dialog:a,close:({restoreFocus:d=!0}={})=>{l||(l=!0,i.remove(),d&&n?.focus?.(),s.onClose?.())}};return a.querySelectorAll("[data-ch-close]").forEach(d=>{d.addEventListener("click",()=>r.close())}),i.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 f=h[0],m=h[h.length-1];d.shiftKey&&document.activeElement===f?(d.preventDefault(),m.focus()):!d.shiftKey&&document.activeElement===m&&(d.preventDefault(),f.focus())}),t(a),W(a),(a.querySelector("input,summary,button")??a).focus(),r}var mt=`
|
|
762
|
+
.slm{--slm-ch-scrim:rgba(0,0,0,.58)}
|
|
763
|
+
.slm[data-theme=light]{--slm-ch-scrim:rgba(23,32,51,.42)}
|
|
764
|
+
.slm-ch-scrim{position:absolute;inset:0;z-index:12;background:var(--slm-ch-scrim);display:grid;place-items:center;
|
|
765
|
+
padding:18px;animation:slm-ch-fade var(--slm-mo-quick) var(--slm-mo-out)}
|
|
766
|
+
.slm-ch-dialog{width:min(460px,100%);max-height:100%;overflow:auto;overscroll-behavior:contain;background:var(--slm-surface);color:var(--slm-text);border:1px solid var(--slm-line);
|
|
767
|
+
border-radius:14px;padding:20px;box-shadow:0 24px 70px rgba(0,0,0,.6);
|
|
768
|
+
animation:slm-ch-rise var(--slm-mo-base) var(--slm-mo-out)}
|
|
769
|
+
.slm-ch-dialog h3{margin:0 0 4px;font-size:16px;font-weight:800;letter-spacing:-.01em}
|
|
770
|
+
.slm-ch-dialog .sub{font-size:12.5px;color:var(--slm-muted);line-height:1.5;margin-bottom:14px}
|
|
771
|
+
.slm-ch-dialog .foot{display:flex;gap:8px;margin-top:16px}
|
|
772
|
+
.slm-ch-dialog .foot .slm-btn{flex:1;min-width:0}
|
|
773
|
+
.slm-ch-dialog .foot .quiet{flex:none;padding:10px 14px;min-height:44px;color:var(--slm-muted);font-weight:700;font-size:13px}
|
|
774
|
+
@keyframes slm-ch-fade{from{opacity:0}to{opacity:1}}
|
|
775
|
+
@keyframes slm-ch-rise{from{opacity:0;transform:translateY(10px) scale(.985)}to{opacity:1;transform:none}}
|
|
776
|
+
.slm-ch-err{color:var(--slm-text);font-size:11.5px;margin-top:6px}
|
|
777
|
+
.slm-ch-seatlist{max-height:44vh;overflow:auto;overscroll-behavior:contain;border:1px solid var(--slm-line);
|
|
778
|
+
border-radius:10px;background:var(--slm-surface);margin-top:10px}
|
|
779
|
+
.slm-ch-seatgroup{padding:8px 10px;border-bottom:1px solid var(--slm-line);display:flex;align-items:center;
|
|
780
|
+
justify-content:space-between;gap:8px;font-size:11px;font-weight:800;color:var(--slm-muted);position:sticky;top:0;
|
|
781
|
+
background:var(--slm-surface)}
|
|
782
|
+
.slm-ch-seatgroup button{color:var(--slm-accent);font-weight:800;font-size:11px;min-height:32px}
|
|
783
|
+
.slm-ch-seatitem{display:flex;width:100%;min-height:40px;align-items:center;gap:9px;padding:8px 10px;border-bottom:1px solid var(--slm-line);
|
|
784
|
+
text-align:left;font-size:12.5px;line-height:1.3;color:var(--slm-text)}
|
|
785
|
+
.slm-ch-seatitem:hover:not(:disabled){background:var(--slm-tint)}
|
|
786
|
+
.slm-ch-seatitem .box{width:16px;height:16px;border-radius:4px;border:1px solid var(--slm-muted);display:grid;
|
|
787
|
+
place-items:center;font-size:10px;font-weight:900;color:transparent;flex:none}
|
|
788
|
+
.slm-ch-seatitem[aria-checked="true"] .box{border-color:var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
789
|
+
.slm-ch-seatitem .meta{margin-left:auto;color:var(--slm-muted);font-size:10.5px}
|
|
790
|
+
.slm-ch-seatitem:disabled{opacity:.55;cursor:not-allowed}
|
|
791
|
+
.slm-ch-seatitem .dot{width:9px;height:9px;border-radius:999px;flex:none}
|
|
792
|
+
/* Seat list as the map reads: section \u2192 row line \u2192 seat chips tinted by status. */
|
|
793
|
+
/* The seat list gets a wider plate than the pickers: rows of chips need air. */
|
|
794
|
+
.slm-ch-dialog:has(.slm-ch-seatlist.grid){width:min(560px,100%);padding:22px 22px 20px}
|
|
795
|
+
.slm-ch-dialog:has(.slm-ch-seatlist.grid) .sub{margin-bottom:18px}
|
|
796
|
+
.slm-ch-seatlist-tools{display:flex;align-items:center;gap:14px;margin:0 0 14px}
|
|
797
|
+
.slm-ch-seatlist-tools .slm-find{flex:1;margin:0}
|
|
798
|
+
.slm-ch-seatlist-tools .slm-find .slm-input{min-height:34px}
|
|
799
|
+
.slm-ch-seatlegend{flex:none;display:flex;align-items:center;gap:4px 6px;flex-wrap:wrap;font-size:10.5px;color:var(--slm-muted);font-weight:700}
|
|
800
|
+
.slm-ch-seatlegend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:1px;vertical-align:-1px}
|
|
801
|
+
.slm-ch-seatlist.grid{max-height:52vh;margin-top:0}
|
|
802
|
+
.slm-ch-seatlist.grid .slm-ch-seatgroup{padding:10px 18px;letter-spacing:.06em;text-transform:uppercase;font-size:10.5px;background:var(--slm-tint)}
|
|
803
|
+
.slm-ch-seatlist.grid .slm-ch-seatgroup button{text-transform:none;letter-spacing:0}
|
|
804
|
+
.slm-ch-seatrow{display:grid;grid-template-columns:112px minmax(0,1fr);align-items:start;gap:16px;padding:12px 18px;border-bottom:1px solid var(--slm-line)}
|
|
805
|
+
.slm-ch-seatrow.loose{grid-template-columns:minmax(0,1fr)}
|
|
806
|
+
.slm-ch-seatrow:last-child{border-bottom:0}
|
|
807
|
+
.slm-ch-rowcheck{display:flex;align-items:center;gap:8px;min-height:32px;padding:4px 6px;margin-left:-6px;border-radius:7px;font-size:12px;font-weight:800;color:var(--slm-text);text-align:left}
|
|
808
|
+
.slm-ch-rowcheck:hover{background:var(--slm-tint)}
|
|
809
|
+
.slm-ch-rowcheck .box{width:15px;height:15px;flex:none;display:grid;place-items:center;border:1.5px solid var(--slm-muted);border-radius:4px;color:transparent;font-size:9px;font-weight:900;box-sizing:border-box}
|
|
810
|
+
.slm-ch-rowcheck[aria-checked="true"] .box{border-color:var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
811
|
+
.slm-ch-rowcheck[aria-checked="mixed"] .box{border-color:var(--slm-accent);background:linear-gradient(var(--slm-accent),var(--slm-accent)) center/7px 2px no-repeat}
|
|
812
|
+
.slm-ch-rowcheck .name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
813
|
+
.slm-ch-rowcheck .meta{margin-left:auto;padding-left:8px;color:var(--slm-muted);font-size:10.5px;font-weight:700;font-variant-numeric:tabular-nums}
|
|
814
|
+
.slm-ch-seatchips{display:flex;flex-wrap:wrap;gap:7px;padding:1px 0}
|
|
815
|
+
.slm .slm-ch-seatchip{min-width:34px;height:34px;padding:0 9px;border-radius:9px;border:1.5px solid var(--slm-line);background:var(--slm-surface);color:var(--slm-text);
|
|
816
|
+
font-size:11.5px;font-weight:800;font-variant-numeric:tabular-nums;box-sizing:border-box;line-height:1;position:relative}
|
|
817
|
+
.slm-ch-seatchip:hover{border-color:var(--slm-muted)}
|
|
818
|
+
.slm-ch-seatchip:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
|
|
819
|
+
.slm .slm-ch-seatchip.is-free,.slm-ch-seatlegend .is-free{border:1.5px solid;border-color:color-mix(in srgb,var(--slm-accent) 45%,var(--slm-line));background:color-mix(in srgb,var(--slm-accent) 10%,var(--slm-surface))}
|
|
820
|
+
.slm .slm-ch-seatchip.is-held,.slm-ch-seatlegend .is-held{border:1.5px solid;border-color:#f4b740;background:color-mix(in srgb,#f4b740 22%,var(--slm-surface))}
|
|
821
|
+
.slm .slm-ch-seatchip.is-booked,.slm-ch-seatlegend .is-booked{border:1.5px solid transparent;background:color-mix(in srgb,var(--slm-muted) 35%,var(--slm-surface));color:var(--slm-muted)}
|
|
822
|
+
.slm .slm-ch-seatchip.is-blocked,.slm-ch-seatlegend .is-blocked{border:1.5px dashed;border-color:var(--slm-muted);color:var(--slm-muted);background:transparent}
|
|
823
|
+
.slm .slm-ch-seatchip[aria-checked="true"]{border:1.5px solid var(--slm-accent);background:var(--slm-accent);color:var(--slm-accent-ink);box-shadow:0 0 0 2px color-mix(in srgb,var(--slm-accent) 30%,transparent)}
|
|
824
|
+
.slm-ch-seatfoot{align-items:center;gap:10px;margin-top:18px;padding-top:16px;border-top:1px solid var(--slm-line)}
|
|
825
|
+
.slm-ch-seatfoot .slm-ch-seatcount{flex:1;min-width:0;font-size:12px;font-weight:700;color:var(--slm-muted);font-variant-numeric:tabular-nums}
|
|
826
|
+
.slm-ch-seatfoot .slm-btn{flex:none;min-width:110px}
|
|
827
|
+
.slm-ch-seatfoot .quiet:disabled{opacity:.45}
|
|
828
|
+
.slm-ch-scopebar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:10px;margin-top:12px}
|
|
829
|
+
.slm-ch-scopebar label{display:grid;gap:5px;color:var(--slm-muted);font-size:10.5px;font-weight:800}
|
|
830
|
+
.slm-ch-scopebar input{width:100%;min-height:40px;padding:8px 10px;border:1px solid var(--slm-line);border-radius:8px;
|
|
831
|
+
background:var(--slm-surface);color:var(--slm-text);font:inherit}
|
|
832
|
+
.slm-ch-scopesummary{padding-bottom:10px;color:var(--slm-muted);font-size:11px;font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
833
|
+
.slm-ch-scopegroup{position:sticky;top:0;z-index:1;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;
|
|
834
|
+
gap:6px;padding:6px 8px;border-bottom:1px solid var(--slm-line);background:var(--slm-surface)}
|
|
835
|
+
.slm-ch-groupcheck{display:flex;min-width:0;align-items:center;gap:8px;padding:5px 2px;text-align:left;font-size:11px;font-weight:800}
|
|
836
|
+
.slm-ch-groupcheck .box{width:16px;height:16px;flex:none;display:grid;place-items:center;border:1px solid var(--slm-muted);border-radius:4px;
|
|
837
|
+
color:transparent;font-size:10px}
|
|
838
|
+
.slm-ch-groupcheck[aria-checked="true"] .box,.slm-ch-groupcheck[aria-checked="mixed"] .box{border-color:var(--slm-accent);
|
|
839
|
+
background:var(--slm-accent);color:var(--slm-accent-ink)}
|
|
840
|
+
.slm-ch-groupcheck .meta{min-width:0;margin-left:auto;color:var(--slm-muted);font-size:10.5px;font-weight:600;white-space:nowrap}
|
|
841
|
+
.slm-ch-grouptoggle{min-height:32px;padding:5px 8px;color:var(--slm-accent);font-size:11px;font-weight:800}
|
|
842
|
+
.slm-ch-scopehint{padding:8px 10px;color:var(--slm-muted);font-size:10.5px;border-bottom:1px solid var(--slm-line)}
|
|
843
|
+
.slm-ch-scope-empty{padding:18px 12px;color:var(--slm-muted);font-size:11.5px;text-align:center}
|
|
844
|
+
@media(max-width:560px){.slm-ch-scopebar{grid-template-columns:1fr}.slm-ch-scopesummary{padding-bottom:0}}
|
|
845
|
+
@media (prefers-reduced-motion:reduce){.slm-ch-scrim,.slm-ch-dialog{animation:none!important}}
|
|
846
|
+
`;var pt="seatlayer-manager-style",ut="seatlayer-manager-channels-style",As=`${mt}
|
|
781
847
|
/* The floor was 480px, which trapped the cockpit in any host shorter than that:
|
|
782
848
|
every ancestor here is overflow:hidden, so the bottom of the rail (Create
|
|
783
849
|
channel, Show archived) was rendered but clipped away by the host and could
|
|
@@ -927,6 +993,41 @@
|
|
|
927
993
|
.slm-map{position:relative;flex:1;min-width:0}
|
|
928
994
|
.slm-map-host{position:absolute;inset:0}
|
|
929
995
|
.slm-hud{position:absolute;left:12px;bottom:12px;display:flex;gap:8px}
|
|
996
|
+
/* Map chrome (plan item 7): crumb \xB7 zoom pills \xB7 minimap, one corner, bottom-right. */
|
|
997
|
+
.slm-mapchrome{position:absolute;right:12px;bottom:12px;z-index:5;display:flex;flex-direction:column;align-items:flex-end;gap:10px;pointer-events:none}
|
|
998
|
+
.slm-mapchrome>*{pointer-events:auto}
|
|
999
|
+
.slm-crumb{max-width:260px;padding:6px 11px;border-radius:999px;font-size:11.5px;font-weight:700;color:var(--slm-text);
|
|
1000
|
+
background:color-mix(in srgb,var(--slm-surface) 88%,transparent);border:1px solid var(--slm-line);backdrop-filter:blur(8px);
|
|
1001
|
+
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}
|
|
1002
|
+
.slm-blocklegend{display:flex;gap:10px;padding:5px 10px;border-radius:999px;font-size:10.5px;font-weight:700;color:var(--slm-muted);
|
|
1003
|
+
background:color-mix(in srgb,var(--slm-surface) 88%,transparent);border:1px solid var(--slm-line);backdrop-filter:blur(8px);white-space:nowrap}
|
|
1004
|
+
.slm-blocklegend span{display:inline-flex;align-items:center;gap:5px}
|
|
1005
|
+
.slm-blocklegend i{width:9px;height:9px;border-radius:3px;display:inline-block}
|
|
1006
|
+
.slm-blocklegend[hidden]{display:none}
|
|
1007
|
+
.slm-zoom{display:flex;flex-direction:column;gap:5px;align-items:flex-end}
|
|
1008
|
+
.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);
|
|
1009
|
+
backdrop-filter:blur(8px);color:var(--slm-text);font-size:17px;font-weight:700;line-height:1;box-shadow:0 8px 24px -14px rgba(0,0,0,.6);display:grid;place-items:center}
|
|
1010
|
+
.slm .slm-zoombtn.slm-zoombtn-venue{width:auto;padding:0 11px;font-size:11.5px;font-weight:800;letter-spacing:.02em}
|
|
1011
|
+
.slm .slm-zoombtn:hover:not(:disabled){border-color:var(--slm-muted)}
|
|
1012
|
+
.slm .slm-zoombtn:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
|
|
1013
|
+
.slm .slm-zoombtn:disabled{opacity:.42;cursor:default}
|
|
1014
|
+
.slm-minimap-mount{line-height:0}
|
|
1015
|
+
.slm-minimap-mount:empty{display:none}
|
|
1016
|
+
.slm .sl-minimap{border:1px solid var(--slm-line);border-radius:9px;overflow:hidden;background:var(--slm-surface);
|
|
1017
|
+
box-shadow:0 12px 34px -14px rgba(0,0,0,.55);line-height:0;touch-action:none}
|
|
1018
|
+
.slm .sl-minimap-bar{min-height:24px;padding:3px 5px 3px 8px;display:flex;align-items:center;gap:6px;border-bottom:1px solid var(--slm-line);
|
|
1019
|
+
color:var(--slm-muted);font-size:9px;font-weight:800;line-height:1.2;letter-spacing:.06em;text-transform:uppercase}
|
|
1020
|
+
.slm .sl-minimap-label{min-width:0;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
1021
|
+
.slm .sl-minimap-key{display:inline-flex;align-items:center;gap:3px;flex:none}
|
|
1022
|
+
.slm .sl-minimap-key i{width:6px;height:6px;border-radius:999px;background:var(--slm-success,#22a06b)}
|
|
1023
|
+
.slm .sl-minimap-key i.selected{background:var(--slm-accent)}
|
|
1024
|
+
.slm .sl-minimap-key i.inactive{background:var(--slm-muted);opacity:.45}
|
|
1025
|
+
.slm .sl-minimap-key i.focused{background:transparent;border:1.5px solid var(--slm-accent);width:7px;height:7px}
|
|
1026
|
+
.slm .sl-minimap-close,.slm .sl-minimap-toggle{display:none}
|
|
1027
|
+
.slm .sl-minimap canvas{display:block}
|
|
1028
|
+
.slm .sl-minimap canvas:focus-visible{outline:2px solid var(--slm-accent);outline-offset:-3px}
|
|
1029
|
+
.slm .sl-minimap canvas.sl-dragging{cursor:grabbing}
|
|
1030
|
+
.slm.compact .slm-mapchrome{right:8px;bottom:8px}
|
|
930
1031
|
.slm .slm-hud-chip{padding:6px 11px;border-radius:999px;font-size:12px;font-weight:700;background:var(--slm-surface);
|
|
931
1032
|
border:1px solid var(--slm-line);color:var(--slm-text)}
|
|
932
1033
|
/* ONE top-centre lane. The zoom hint, the live-event pill and the Channels
|
|
@@ -940,6 +1041,13 @@
|
|
|
940
1041
|
push the others down by its own height plus the gap. Taken out of flow
|
|
941
1042
|
rather than display:none'd, so the fade in and out still runs. */
|
|
942
1043
|
.slm-lane>:not(.on){position:absolute;top:0;pointer-events:none}
|
|
1044
|
+
/* The session-ended card: the map stays painted under it; one way back. */
|
|
1045
|
+
.slm-ended{display:flex;flex-direction:column;gap:8px;width:360px;max-width:calc(100vw - 48px);box-sizing:border-box;padding:16px 18px;border-radius:12px;pointer-events:auto;
|
|
1046
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);box-shadow:0 18px 48px rgba(0,0,0,.3);color:var(--slm-text);text-align:left}
|
|
1047
|
+
.slm-ended strong{font-size:14px;font-weight:800}
|
|
1048
|
+
.slm-ended span{font-size:12.5px;line-height:1.5;color:var(--slm-muted)}
|
|
1049
|
+
.slm-ended .slm-btn{align-self:flex-start;min-width:0;flex:none;margin-top:4px}
|
|
1050
|
+
.slm-ended[data-busy="true"] .slm-btn{opacity:.6;pointer-events:none}
|
|
943
1051
|
.slm-zoomhint{padding:6px 13px;border-radius:999px;
|
|
944
1052
|
background:color-mix(in srgb,var(--slm-surface) 92%,transparent);color:var(--slm-text);
|
|
945
1053
|
border:1px solid var(--slm-line);font-size:12px;font-weight:700;pointer-events:none;opacity:0;
|
|
@@ -995,6 +1103,77 @@
|
|
|
995
1103
|
|
|
996
1104
|
/* block toolbar */
|
|
997
1105
|
.slm-selbar{display:flex;align-items:baseline;gap:6px;margin-bottom:6px}
|
|
1106
|
+
.slm-selbar .slm-selclear{margin-left:auto}
|
|
1107
|
+
/* The shared seat chooser (plan item 5). Chips read as one quiet group \u2014 a
|
|
1108
|
+
pill row, not four grey boxes \u2014 Find sits under them with its glyph, and
|
|
1109
|
+
the selection bar is one line: the count, the tool's words, then two
|
|
1110
|
+
small ghost buttons rather than link text in the accent colour (which
|
|
1111
|
+
read as "disabled" next to the primary action). Tokens only, so the light
|
|
1112
|
+
ground gets its own surface, line and ink. */
|
|
1113
|
+
.slm-chooser{display:flex;flex-direction:column;gap:6px;margin-top:6px}
|
|
1114
|
+
.slm-chooser .slm-ch-row2{display:flex;flex-wrap:wrap;gap:6px;margin:0}
|
|
1115
|
+
.slm-chooser .slm-ch-row2 .slm-btn{flex:0 1 auto;min-width:0;min-height:32px;padding:6px 12px;border-radius:999px;
|
|
1116
|
+
font-size:12px;font-weight:700;line-height:1.2;letter-spacing:0;
|
|
1117
|
+
background:var(--slm-tint);border:1px solid var(--slm-line);color:var(--slm-text);box-shadow:none}
|
|
1118
|
+
.slm-chooser .slm-ch-row2 .slm-btn:hover{border-color:var(--slm-muted);background:var(--slm-tint-strong)}
|
|
1119
|
+
.slm-chooser .slm-ch-row2 .slm-btn:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px}
|
|
1120
|
+
.slm-chooser .slm-ch-row2 .slm-btn:not(.ghost){background:var(--slm-accent);color:var(--slm-accent-ink);border-color:var(--slm-accent)}
|
|
1121
|
+
.slm-find{position:relative;margin:2px 0 0}
|
|
1122
|
+
.slm-find::before{content:"";position:absolute;left:11px;top:50%;width:13px;height:13px;transform:translateY(-50%);pointer-events:none;
|
|
1123
|
+
background:currentColor;color:var(--slm-muted);
|
|
1124
|
+
-webkit-mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.5-3.5'/></svg>") center/contain no-repeat;
|
|
1125
|
+
mask:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.5-3.5'/></svg>") center/contain no-repeat}
|
|
1126
|
+
.slm-find .slm-input{width:100%;box-sizing:border-box;margin:0;min-height:36px;padding:8px 10px 8px 32px;border-radius:10px;
|
|
1127
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);color:var(--slm-text);font-size:12.5px}
|
|
1128
|
+
.slm-find .slm-input::placeholder{color:var(--slm-muted)}
|
|
1129
|
+
.slm-find .slm-input:focus-visible{outline:2px solid var(--slm-accent);outline-offset:1px;border-color:var(--slm-accent)}
|
|
1130
|
+
.slm-find-count{display:block;min-height:16px;margin:4px 0 0 2px;font-size:11px;color:var(--slm-muted);font-variant-numeric:tabular-nums}
|
|
1131
|
+
.slm-find-count:empty{display:none}
|
|
1132
|
+
.slm-selbar{display:flex;align-items:center;gap:8px;margin:10px 0 6px;padding:8px 0;border-top:1px solid var(--slm-line);border-bottom:1px solid var(--slm-line)}
|
|
1133
|
+
.slm-selbar .slm-selactions{margin-left:auto;display:flex;gap:6px}
|
|
1134
|
+
.slm-selbar .slm-selactions .slm-linkbtn,.slm-selbar .slm-selclear{min-height:28px;padding:4px 10px;border:1px solid var(--slm-line);border-radius:999px;white-space:nowrap;flex:none;
|
|
1135
|
+
background:var(--slm-surface);color:var(--slm-text)!important;font-size:11.5px!important;font-weight:700!important;text-align:center}
|
|
1136
|
+
.slm-selbar .slm-sellabel{min-width:0;line-height:1.3}
|
|
1137
|
+
.slm-selbar .slm-selactions .slm-linkbtn:hover,.slm-selbar .slm-selclear:hover{border-color:var(--slm-muted);background:var(--slm-tint)}
|
|
1138
|
+
.slm-selbar .slm-selclear{margin-left:0}
|
|
1139
|
+
.slm-selbar .slm-selclear:disabled,.slm-selbar .slm-selactions .slm-linkbtn:disabled{opacity:.45}
|
|
1140
|
+
.slm-catreset{margin-top:14px;padding-top:12px;border-top:1px solid var(--slm-line)}
|
|
1141
|
+
.slm-catreset .slm-btn{width:100%}
|
|
1142
|
+
.slm-catreset .slm-note{margin-top:6px}
|
|
1143
|
+
/* The shared seat chooser (plan item 5): chip rows and the Find box under them. */
|
|
1144
|
+
.slm-chooser{margin-top:2px}
|
|
1145
|
+
.slm-find{position:relative;margin-top:8px}
|
|
1146
|
+
.slm-find .slm-input{width:100%;box-sizing:border-box;margin:0;padding-right:8px}
|
|
1147
|
+
.slm-find-count{display:block;min-height:16px;margin-top:4px;font-size:11px;color:var(--slm-muted);font-variant-numeric:tabular-nums}
|
|
1148
|
+
.slm-find-count:empty{display:none}
|
|
1149
|
+
/* Reading aids in the bar (plan item 5, slice D): the bar's Find and the View menu. */
|
|
1150
|
+
.slm-findbar{flex:0 1 250px;min-width:150px}
|
|
1151
|
+
.slm-findbar .slm-find{margin:0}
|
|
1152
|
+
.slm-findbar .slm-find .slm-input{min-height:30px;padding:5px 9px 5px 30px;border-radius:8px;font-size:12px}
|
|
1153
|
+
.slm-findbar .slm-find::before{left:10px;width:12px;height:12px}
|
|
1154
|
+
.slm-findbar .slm-find-count{position:absolute;left:0;top:calc(100% + 3px);margin:0;padding:3px 9px;border-radius:7px;white-space:nowrap;z-index:5;
|
|
1155
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);color:var(--slm-text);font-size:11px;box-shadow:0 8px 24px rgba(0,0,0,.18)}
|
|
1156
|
+
.slm-view{position:relative;flex:none}
|
|
1157
|
+
.slm-view > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:5px;min-height:30px;padding:5px 10px;border-radius:8px;font-size:12px;user-select:none}
|
|
1158
|
+
.slm-view > summary::-webkit-details-marker{display:none}
|
|
1159
|
+
.slm-view > summary.away::after{content:"";width:6px;height:6px;border-radius:50%;background:var(--slm-accent)}
|
|
1160
|
+
.slm-view[open] > summary{border-color:var(--slm-muted);background:var(--slm-tint)}
|
|
1161
|
+
.slm-view-caret{font-size:10px;opacity:.7}
|
|
1162
|
+
.slm-view-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:238px;padding:6px;border-radius:12px;
|
|
1163
|
+
background:var(--slm-surface);border:1px solid var(--slm-line);box-shadow:0 14px 40px rgba(0,0,0,.28)}
|
|
1164
|
+
.slm-view-item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 9px;border-radius:8px;border:0;background:transparent;color:var(--slm-text);font-size:12.5px;font-weight:600;text-align:left;cursor:pointer}
|
|
1165
|
+
.slm-view-item:hover:not(:disabled){background:var(--slm-tint)}
|
|
1166
|
+
.slm-view-item:focus-visible{outline:2px solid var(--slm-accent);outline-offset:-2px}
|
|
1167
|
+
.slm-view-item:disabled{opacity:.45;cursor:default}
|
|
1168
|
+
.slm-view-check{flex:none;width:15px;height:15px;border-radius:4px;border:1.5px solid var(--slm-muted);box-sizing:border-box}
|
|
1169
|
+
.slm-view-item.on .slm-view-check{border-color:var(--slm-accent);background:var(--slm-accent);
|
|
1170
|
+
-webkit-mask:none;mask:none;
|
|
1171
|
+
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2.5 6.4 5 8.9l4.6-5.6'/></svg>");background-size:11px;background-position:center;background-repeat:no-repeat}
|
|
1172
|
+
.slm[data-theme="light"] .slm-view-item.on .slm-view-check{background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%230b1220' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2.5 6.4 5 8.9l4.6-5.6'/></svg>")}
|
|
1173
|
+
.slm-view-label{flex:1;min-width:0}
|
|
1174
|
+
.slm-view-kbd{flex:none;font:600 10.5px/1 var(--slm-mono,ui-monospace,monospace);color:var(--slm-muted);padding:3px 5px;border:1px solid var(--slm-line);border-radius:5px}
|
|
1175
|
+
.slm-view-note{margin:4px 3px 2px;padding:6px 8px 2px;border-top:1px solid var(--slm-line);font-size:11px;line-height:1.4;color:var(--slm-muted)}
|
|
1176
|
+
.slm.compact .slm-findbar{flex:1 1 100%;min-width:0}
|
|
998
1177
|
.slm-selnum{font-size:26px;font-weight:800;font-variant-numeric:tabular-nums}
|
|
999
1178
|
.slm-sellabel{font-size:12px;color:var(--slm-muted);font-weight:600}
|
|
1000
1179
|
.slm-row{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
|
|
@@ -1218,31 +1397,56 @@
|
|
|
1218
1397
|
transition:none!important;
|
|
1219
1398
|
scroll-behavior:auto!important}
|
|
1220
1399
|
}
|
|
1221
|
-
`;function et(){if(typeof document>"u"||document.getElementById(Qe))return;let l=document.createElement("style");l.id=Qe,l.textContent=Xt,document.head.appendChild(l)}function tt(l){if(typeof document>"u"||document.getElementById(Je))return;let e=document.createElement("style");e.id=Je,e.textContent=l,document.head.appendChild(e)}var it=require("@seatlayer/core");var st=require("@seatlayer/core/core/color");var De={light:{background:"#ffffff",surface:"#f6f7fb",text:"#172033",muted:"#667085",line:"rgba(23,32,51,.16)",map:"#e9edf4"},dark:{background:"#0f1522",surface:"#1a2234",text:"#eef1f8",muted:"#a5aec2",line:"rgba(165,174,194,.24)",map:"#0f1522"}};function Zt(){try{return window.matchMedia?.("(prefers-color-scheme: dark)").matches===!0}catch{return!1}}function Oe(l){if(l)return l==="auto"?Zt()?"dark":"light":l}function nt(l){let e;try{e=window.matchMedia?.("(prefers-color-scheme: dark)")}catch{return()=>{}}if(!e)return()=>{};let t=s=>l(s.matches);return typeof e.addEventListener=="function"?e.addEventListener("change",t):e.addListener?.(t),()=>{typeof e.removeEventListener=="function"?e.removeEventListener("change",t):e.removeListener?.(t)}}function at(l){return l?l.mode:"open"}function ot(l,e,t){switch(l){case"open":return null;case"hidden":return{mode:"hidden",labels:e};case"closed":return{mode:"closed",labels:e};case"timed":return{mode:"timed",revealAt:t?.revealAt??Date.now()+36e5,labels:e};case"threshold":return{mode:"threshold",thresholdPct:t?.thresholdPct??80,labels:e}}}function lt(l){return new Date(l-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}function rt(l){if(typeof l=="string"){let e=document.querySelector(l);if(!e)throw new Error(`seatmanager: container "${l}" not found`);return e}if(!(l instanceof HTMLElement))throw new Error("seatmanager: container must be a CSS selector or an HTMLElement");return l}function ze(l){if(!l.startsWith("mse_"))throw new Error("seatmanager: token must be a short-lived event-scoped mse_ grant minted by your backend; tenant secret keys are unsupported in browsers")}function pe(l){return l==="blocked"?"not_for_sale":l}var Qt=["free","booked","held","blocked"],A={free:"#6e7bff",booked:"#9ca3af",held:"#f4b740",blocked:"#475569"},he={free:"Free",booked:"Sold",held:"Held",blocked:"Blocked"},ct=[`<span class="slm-legmark" style="background:${A.free}"></span> Free = category colour`,`<span class="slm-legmark" style="background:${A.booked}"></span> ${he.booked}`,`<span class="slm-legmark" style="background:${A.held}"></span> ${he.held}`,`<span class="slm-legcross" style="color:${A.blocked}">\u2715</span> ${he.blocked}`].join(" \xB7 "),dt=Qt.map(l=>({key:l,label:he[l],color:A[l]}));function ht(l,e){let t=l??{},s=e?De[e]:null,n=e==="light";return{"--slm-bg":t.background??s?.background??"#0e1017","--slm-surface":s?.surface??"#181b24","--slm-text":s?.text??"#eef1f7","--slm-muted":s?.muted??"#8b93a7","--slm-line":s?.line??"rgba(255,255,255,.09)","--slm-tint":n?"rgba(23,32,51,.05)":"rgba(255,255,255,.035)","--slm-tint-strong":n?"rgba(23,32,51,.09)":"rgba(255,255,255,.07)","--slm-accent":t.accent??(n?"#4654c8":"#6e7bff"),"--slm-accent-ink":t.accentInk??"#ffffff","--slm-font":"-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif","--slm-radius":"14px"}}function pt(l){return l?De[l].map:null}function mt(l,e){let t=Math.max(0,Math.round((e-l)/1e3));if(t<5)return"just now";if(t<60)return`${t}s ago`;let s=Math.round(t/60);return s<60?`${s}m ago`:`${Math.round(s/60)}h ago`}function me(l,e){return(0,it.formatMoney)(l,e,{maximumFractionDigits:0,fallback:(t,s)=>`${s} ${Math.round(t).toLocaleString()}`})}function b(l){return String(l??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var ut=require("@seatlayer/core");function Fe(l){return Object.entries(l).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function ue(l){let e=l.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=l.doc?.zones??[],s=new Map,n=[];for(let d of e.sections)if(d.zone&&t.some(c=>c.id===d.zone)){let c=s.get(d.zone)??[];c.push(d),s.set(d.zone,c)}else n.push(d);let i=[],a=0,o=0,r=(d,c,h,u=!1)=>{let f=l.availabilityRules[c.id]??null,v=l.effectiveClosed.has(c.id)||u,g=l.effectiveHidden.has(c.id)||h&&!v;d==="section"&&g&&(a+=1),d==="section"&&v&&(o+=1),i.push({kind:d,id:c.id,label:c.label,seatCount:c.seatCount,seatLabels:c.seatLabels,rule:f,hidden:g,closed:v,followsZone:d==="section"&&h})};for(let d of t){let c=s.get(d.id);if(!c||!c.length)continue;let h={id:d.id,label:d.label||"Zone",seatCount:c.reduce((v,g)=>v+g.seatCount,0),seatLabels:c.flatMap(v=>v.seatLabels)},u=!!l.availabilityRules[d.id],f=l.availabilityRules[d.id]?.mode==="closed";r("zone",h,!1);for(let v of c)r("section",v,u,f)}for(let d of n)r("section",d,!1);if(e.ungrouped){let d=e.ungrouped;r("section",{id:ut.UNGROUPED_ID,label:d.label,seatCount:d.seatCount,seatLabels:d.seatLabels},!1)}return{rows:i,hiddenSections:a,closedSections:o}}function bt(l,e){let t=at(l.rule),s=`slm-availrow${l.kind==="zone"?" zone":""}${l.hidden?" hidden":""}${l.closed?" closed":""}`,n=e?" disabled":"",i=[["open","Open","Available to buy"],["closed","Closed","Visible on the map, unavailable to buy"],["hidden","Hidden","Removed from the buyer map"],["timed","Scheduled reveal","Open at a specific date and time"],["threshold","Demand-based reveal","Open when sales reach a percentage"]],a=l.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<details class="slm-availpicker" data-avail-picker>
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1400
|
+
`;function bt(){if(typeof document>"u"||document.getElementById(pt))return;let o=document.createElement("style");o.id=pt,o.textContent=As,document.head.appendChild(o)}function gt(o){if(typeof document>"u"||document.getElementById(ut))return;let e=document.createElement("style");e.id=ut,e.textContent=o,document.head.appendChild(e)}Ye();var It=require("@seatlayer/core"),G=require("@seatlayer/core/picker/minimapGeometry");var At=require("@seatlayer/core"),Os=require("@seatlayer/core/core/cdnAsset");var zs=require("@seatlayer/core/core/cdnAsset");function F(o,e){let t=(0,At.t)(o);return t===o?e:t}function Fs(o){let e={inactive:0,available:1,selected:2},t=new Map;for(let n of o){let i=t.get(n.id);(!i||e[n.state]>e[i])&&t.set(n.id,n.state)}let s={selected:0,available:0,inactive:0};for(let n of t.values())s[n]+=1;return s}function Vs(o,e){return o.x<=e.x&&o.y<=e.y&&o.x+o.width>=e.x+e.width&&o.y+o.height>=e.y+e.height}function Ht(o,e){let t=new Ge(o);return t.build(e),t}var Ge=class{constructor(e){this.host=e;this.miniCanvas=null;this.miniBase=null;this.miniWrap=null;this.miniToggle=null;this.miniLabel=null;this.miniTf=null;this.miniDrag=null;this.miniSuppressClick=!1;this.userClosed=!1}dispose(){this.miniToggle?.remove(),this.miniWrap?.remove(),this.miniToggle=null,this.miniWrap=null,this.miniCanvas=null,this.miniBase=null,this.miniLabel=null,this.miniTf=null,this.miniDrag=null,this.host.root()?.removeAttribute("data-minimap-open")}build(e){if(!this.host.controller.getViewport())return;let s=document.createElement("button");s.type="button",s.className="sl-minimap-toggle",s.setAttribute("aria-label",F("picker.openVenueMap","Open venue overview map")),s.setAttribute("aria-expanded","false"),s.innerHTML='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6l5-2 8 3 5-2v13l-5 2-8-3-5 2zM8 4v13M16 7v13"/></svg>',e.appendChild(s),this.miniToggle=s;let n=document.createElement("div");n.className="sl-minimap",n.setAttribute("role","group");let i=document.createElement("div");i.className="sl-minimap-bar";let a=document.createElement("span");a.className="sl-minimap-label";let l=document.createElement("span");l.className="sl-minimap-key",l.setAttribute("aria-label",F("picker.minimapStateKey","Focused, selected, available, and inactive sections")),l.innerHTML='<i class="focused" title="Focused"></i><i class="selected" title="Selected"></i><i title="Available"></i><i class="inactive" title="Inactive"></i>';let r=document.createElement("button");r.type="button",r.className="sl-minimap-close",r.setAttribute("aria-label",F("picker.closeVenueMap","Close venue overview map")),r.textContent="\xD7",i.append(a,l,r);let c=document.createElement("canvas");c.tabIndex=0,c.setAttribute("role","application"),c.setAttribute("aria-label",F("picker.venueMapInstructions","Venue overview map. Drag the viewport, click a section, or use arrow keys to pan.")),n.append(i,c),e.appendChild(n),this.miniWrap=n,this.miniLabel=a,this.miniCanvas=c;let d=document.createElement("canvas");this.miniBase=d,s.addEventListener("click",()=>{let h=this.host.root()?.dataset.minimapOpen==="true";this.userClosed=h,this.setMinimapOpen(!h)}),r.addEventListener("click",()=>{this.userClosed=!0,this.setMinimapOpen(!1)}),c.addEventListener("click",h=>{if(this.miniSuppressClick){this.miniSuppressClick=!1;return}this.minimapJump(h)}),c.addEventListener("pointerdown",h=>this.minimapPointerDown(h)),c.addEventListener("pointermove",h=>this.minimapPointerMove(h)),c.addEventListener("pointerup",h=>this.minimapPointerUp(h)),c.addEventListener("pointercancel",h=>this.minimapPointerUp(h)),c.addEventListener("keydown",h=>this.minimapKeydown(h)),this.layoutMinimap(),this.syncMinimapLabel(),this.drawMinimapStatic(),this.drawMinimapRect()}setAutoOpen(e){if(this.miniWrap){if(!e){this.userClosed=!1,this.host.root()?.dataset.minimapOpen==="true"&&this.setMinimapOpen(!1,!1);return}this.userClosed||this.host.root()?.dataset.minimapOpen==="true"||this.setMinimapOpen(!0,!1)}}setMinimapOpen(e,t=!0){this.host.root()?.setAttribute("data-minimap-open",String(e)),this.miniToggle?.setAttribute("aria-expanded",String(e)),t&&(e?this.miniCanvas?.focus():this.miniToggle?.focus())}layoutMinimap(){let e=this.miniCanvas,t=this.miniBase,s=this.host.controller.getViewport()?.bounds;if(!e||!t||!s||!(s.width>0&&s.height>0))return;let n=196,i=146,a=6,l=s.width/Math.max(1,s.height),r=n,c=Math.round(n/l);c>i&&(c=i,r=Math.round(i*l)),r=Math.max(64,r),c=Math.max(48,c);let d=Math.min(2,window.devicePixelRatio||1);e.width=Math.round(r*d),e.height=Math.round(c*d),e.style.width=`${r}px`,e.style.height=`${c}px`,t.width=e.width,t.height=e.height,this.miniTf=(0,G.createMinimapTransform)(s,e.width,e.height,d,a)}syncMinimapLabel(){if(!this.miniLabel||!this.miniWrap)return;let e=this.host.controller.getFloors(),t=this.host.controller.isFloorOverview()?F("picker.allFloors","All floors"):e.find(d=>d.id===this.host.controller.getActiveFloorId())?.name??F("picker.venueOverview","Venue overview"),s=this.host.controller.getMinimapSnapshot().sections,i=s.find(d=>d.active)?.label??this.host.focusedSectionLabel(),a=i?`${t} \xB7 ${i}`:t;this.miniLabel.textContent=a;let{selected:l,available:r,inactive:c}=Fs(s);this.miniWrap.setAttribute("aria-label",s.length?`${a}. ${l} selected, ${r} available, ${c} inactive sections.`:a),this.miniCanvas?.setAttribute("aria-label",s.length?`${a}. ${l} selected, ${r} available, ${c} inactive sections. ${F("picker.venueMapInstructions","The outlined region is the visible map area. Drag it, click a section, or use arrow keys to pan.")}`:`${a}. ${F("picker.venueMapInstructions","The outlined region is the visible map area. Drag it, click elsewhere, or use arrow keys to pan.")}`)}refreshMinimap(){this.miniBase&&(this.layoutMinimap(),this.syncMinimapLabel(),this.drawMinimapStatic(),this.drawMinimapRect())}drawMinimapStatic(){let e=this.miniBase,t=this.miniTf;if(!e||!t)return;let s=e.getContext("2d");if(!s)return;s.clearRect(0,0,e.width,e.height);let n=h=>h*t.scale+t.offX,i=h=>h*t.scale+t.offY,a=this.host.cssVar("--sl-line")||"rgba(139,147,167,.5)",l=this.host.cssVar("--sl-muted")||"#8b93a7",r=this.host.cssVar("--sl-accent")||"#6e7bff",c=this.host.cssVar("--sl-success")||"#22a06b",d=this.host.controller.getMinimapSnapshot();for(let h of d.sections){if(h.outline.length<3)continue;s.beginPath(),h.outline.forEach((m,p)=>p===0?s.moveTo(n(m.x),i(m.y)):s.lineTo(n(m.x),i(m.y))),s.closePath();let f=h.paint;if(s.globalAlpha=h.state==="inactive"?.5:.92,f?s.fillStyle=f.fill:(s.globalAlpha=h.state==="inactive"?.18:h.state==="selected"?.72:.34,s.fillStyle=h.state==="inactive"?l:h.state==="selected"?r:c),s.fill(),s.globalAlpha=.82,s.lineWidth=Math.max(1,t.dpr),s.strokeStyle=f?.stroke||a,s.stroke(),h.owned){s.globalAlpha=1,s.lineWidth=Math.max(2,t.dpr*1.5),s.strokeStyle=r,s.stroke();let m=h.outline.reduce((p,v)=>({x:p.x+v.x,y:p.y+v.y}),{x:0,y:0});s.beginPath(),s.arc(n(m.x/h.outline.length),i(m.y/h.outline.length),Math.max(1.5,t.dpr*1.6),0,Math.PI*2),s.fillStyle=r,s.fill(),s.beginPath(),h.outline.forEach((p,v)=>v===0?s.moveTo(n(p.x),i(p.y)):s.lineTo(n(p.x),i(p.y))),s.closePath()}h.active&&(s.globalAlpha=1,s.lineJoin="round",s.lineWidth=Math.max(4,t.dpr*3.5),s.strokeStyle=this.host.cssVar("--sl-surface")||"#fff",s.stroke(),s.lineWidth=Math.max(2,t.dpr*1.75),s.strokeStyle=r,s.stroke())}if(s.globalAlpha=1,!d.sections.length){let h=Math.max(1,t.dpr),f=new Map,m=p=>{let v=f.get(p);if(v)return v;let y=this.host.tint?.(p)||c;return f.set(p,y),y};for(let p of d.seats)s.globalAlpha=p.state==="inactive"?.22:.78,s.fillStyle=p.state==="inactive"?l:p.state==="selected"?r:m(p.categoryKey),s.beginPath(),s.arc(n(p.x),i(p.y),h,0,Math.PI*2),s.fill();s.globalAlpha=1}}drawMinimapRect(){let e=this.miniCanvas,t=this.miniBase,s=this.miniTf;if(!e||!t||!s)return;let n=e.getContext("2d");if(!n)return;n.clearRect(0,0,e.width,e.height),n.drawImage(t,0,0);let i=this.host.controller.getViewport();if(!i||Vs(i.visible,i.bounds))return;let a=(0,G.minimapViewportPlan)(i.visible,s,e.width,e.height,Math.max(2,s.dpr*2)),l=this.host.cssVar("--sl-text")||"#12151c",r=this.host.cssVar("--sl-surface")||"#fff";n.save(),n.globalAlpha=.1,n.fillStyle=l,n.fillRect(a.raw.x,a.raw.y,a.raw.width,a.raw.height),n.globalAlpha=.9,n.lineJoin="round",n.lineWidth=Math.max(4,s.dpr*3.25),n.strokeStyle=r,n.strokeRect(a.raw.x,a.raw.y,a.raw.width,a.raw.height),n.globalAlpha=1,n.lineWidth=Math.max(2,s.dpr*1.75),n.strokeStyle=l,n.strokeRect(a.raw.x,a.raw.y,a.raw.width,a.raw.height),a.clipped&&Object.values(a.clippedEdges).some(Boolean)&&(n.setLineDash([Math.max(3,s.dpr*3),Math.max(2,s.dpr*2)]),n.strokeRect(a.clipped.x,a.clipped.y,a.clipped.width,a.clipped.height)),n.restore()}minimapWorldPoint(e){let t=this.miniCanvas,s=this.miniTf;if(!t||!s)return null;let n=t.getBoundingClientRect(),i=(e.clientX-n.left)*(t.width/Math.max(1,n.width)),a=(e.clientY-n.top)*(t.height/Math.max(1,n.height));return{...(0,G.minimapPointToWorld)({x:i,y:a},s),px:i,py:a}}minimapPointerDown(e){let t=this.minimapWorldPoint(e),s=this.host.controller.getViewport()?.visible;!t||!s||!(t.x>=s.x&&t.x<=s.x+s.width&&t.y>=s.y&&t.y<=s.y+s.height)||(this.miniDrag={pointerId:e.pointerId,offsetX:t.x-(s.x+s.width/2),offsetY:t.y-(s.y+s.height/2),startX:e.clientX,startY:e.clientY,moved:!1},this.miniCanvas?.setPointerCapture(e.pointerId),this.miniCanvas?.classList.add("sl-dragging"),e.preventDefault())}minimapPointerMove(e){let t=this.miniDrag;if(!t||t.pointerId!==e.pointerId)return;let s=this.minimapWorldPoint(e);s&&(!t.moved&&Math.hypot(e.clientX-t.startX,e.clientY-t.startY)>2&&(t.moved=!0,this.host.controller.clearSectionFocus()),this.host.controller.panToWorld({x:s.x-t.offsetX,y:s.y-t.offsetY}),e.preventDefault())}minimapPointerUp(e){let t=this.miniDrag;!t||t.pointerId!==e.pointerId||(this.miniSuppressClick=t.moved,this.miniDrag=null,this.miniCanvas?.classList.remove("sl-dragging"),this.miniCanvas?.hasPointerCapture(e.pointerId)&&this.miniCanvas.releasePointerCapture(e.pointerId))}minimapKeydown(e){let t=this.host.controller.getViewport()?.visible;if(!t)return;if(e.key==="Home"){this.host.controller.overview(),e.preventDefault();return}let s=e.key==="ArrowLeft"?-t.width*.2:e.key==="ArrowRight"?t.width*.2:0,n=e.key==="ArrowUp"?-t.height*.2:e.key==="ArrowDown"?t.height*.2:0;!s&&!n||(this.host.controller.clearSectionFocus(),this.host.controller.panToWorld({x:t.x+t.width/2+s,y:t.y+t.height/2+n}),e.preventDefault())}minimapJump(e){let t=this.minimapWorldPoint(e);if(t){for(let s of this.host.controller.getMinimapSnapshot().sections)if(!(s.state==="inactive"||s.outline.length<3)&&(0,It.pointInPolygon)(t,s.outline)){this.host.controller.focusSection(s.id);return}this.host.controller.clearSectionFocus(),this.host.controller.panToWorld(t)}}};function Pt(o){return o.focusedSection!==null?o.deeperThanSectionFrame===!1?"venue":"section":o.atVenueFit!==void 0?o.atVenueFit?"none":"venue":o.seatsRevealed?"venue":"none"}function Bt(o){return o.total==null||o.free==null?o.label:o.free<=0?`${o.label} \xB7 sold out`:`${o.label} \xB7 ${o.free.toLocaleString()} of ${o.total.toLocaleString()} free`}function Dt(o){let t=Pt({focusedSection:o.focused?o.focused.label:null,seatsRevealed:o.seatsRevealed,atVenueFit:o.atVenueFit})==="none";return{crumb:o.focused?o.floor?`${o.floor} \xB7 ${Bt(o.focused)}`:Bt(o.focused):o.floor??"Venue",crumbShown:!!o.focused||!!o.floor,zoomInEnabled:!o.atCeiling,zoomOutEnabled:!t,venueEnabled:!t}}function Ot(o={}){return`
|
|
1401
|
+
<div class="slm-mapchrome" data-ref="mapchrome">
|
|
1402
|
+
${o.legend??""}
|
|
1403
|
+
<div class="slm-crumb" data-ref="crumb" role="status" hidden></div>
|
|
1404
|
+
<div class="slm-zoom" role="group" aria-label="Zoom">
|
|
1405
|
+
<button type="button" class="slm-zoombtn" data-ref="zin" aria-label="Zoom in" title="Zoom in">+</button>
|
|
1406
|
+
<button type="button" class="slm-zoombtn" data-ref="zout" aria-label="Zoom out one step" title="Zoom out one step (section, then venue)">\u2212</button>
|
|
1407
|
+
<button type="button" class="slm-zoombtn slm-zoombtn-venue" data-ref="zfit" title="Whole venue">Venue</button>
|
|
1408
|
+
</div>
|
|
1409
|
+
<div class="slm-minimap-mount" data-ref="minimap"></div>
|
|
1410
|
+
</div>`}function zt(o,e){o.crumb&&(o.crumb.textContent=e.crumb,o.crumb.hidden=!e.crumbShown);let t=(s,n)=>{s&&(s.disabled=!n,s.setAttribute("aria-disabled",String(!n)))};t(o.zin,e.zoomInEnabled),t(o.zout,e.zoomOutEnabled),t(o.zfit,e.venueEnabled)}var X={plenty:{min:.5,color:"#22a06b",label:"Over half free"},tight:{min:.15,color:"#f4b740",label:"Under half free"},gone:{min:0,color:"#d9534f",label:"Nearly gone"}};function qs(o,e){let t=e>0?o/e:0;return t>=X.plenty.min?"plenty":t>=X.tight.min?"tight":"gone"}function _s(o,e,t,s=Date.now()){return o?.mode==="closed"||t?"Closed":o?.mode==="timed"&&o.revealAt&&o.revealAt>s?`Hidden until ${Ns(o.revealAt,s)}`:o?.mode==="threshold"&&e?`Hidden until ${o.thresholdPct??0}% sold`:o?.mode==="hidden"||e?"Hidden":null}function Ns(o,e){let t=new Date(o),s=t.toLocaleTimeString(void 0,{hour:"numeric",minute:t.getMinutes()?"2-digit":void 0}),n=(o-e)/864e5;return n<1&&t.getDate()===new Date(e).getDate()?s:n<6?`${t.toLocaleDateString(void 0,{weekday:"short"})} ${s}`:t.toLocaleDateString(void 0,{day:"numeric",month:"short"})}function Ft(o,e){let t=o.state==="sold-out"?"Sold out":_s(e.rule,e.hiddenNow,e.closedNow);return{tint:t==="Closed"||t==="Sold out"?null:X[qs(o.free,o.total)].color,stateWord:t}}function Vt(){return`<div class="slm-blocklegend" data-ref="blocklegend" aria-label="Block colours: share of seats free">${Object.keys(X).map(o=>`<span><i style="background:${X[o].color}"></i>${X[o].label}</span>`).join("")}</div>`}var qt=[{key:"seatLabels",label:"Seat labels",letter:"S",hint:"Seat numbers where the zoom can carry them"},{key:"rowLabels",label:"Row labels",letter:"R",hint:"Row letters beside each row"},{key:"categoryColours",label:"Category colours",letter:"G",hint:"Off paints every category the same, so status is the only colour"},{key:"channelColours",label:"Channel colours",letter:"H",hint:"Channel flags and tints \u2014 the Channels tool\u2019s overlay"},{key:"momentum",label:"Booking momentum",letter:"M",hint:"Warm the sections booking fastest in the selected window"}],_t="seatlayer.controlRoom.mapView";function ke(){return{seatLabels:!0,rowLabels:!0,categoryColours:!0,channelColours:!0,momentum:!1}}function Nt(o){return qt.find(t=>t.letter.toLowerCase()===o)?.key??null}function jt(o=Kt()){let e=ke();if(!o)return e;try{let t=o.getItem(_t);if(!t)return e;let s=JSON.parse(t),n={...e};for(let i of Object.keys(e))typeof s[i]=="boolean"&&(n[i]=s[i]);return n}catch{return e}}function Ut(o,e=Kt()){if(e)try{e.setItem(_t,JSON.stringify(o))}catch{}}function Kt(){try{return typeof localStorage>"u"?null:localStorage}catch{return null}}function Wt(o,e){e.renderer?.setLabelLayers?.({seatLabels:o.seatLabels,rowLabels:o.rowLabels}),e.renderer?.setCategoryColours?.(o.categoryColours),e.channelsOverlay(o.channelColours)}function Yt(){return`
|
|
1411
|
+
<details class="slm-view" data-ref="view">
|
|
1412
|
+
<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>
|
|
1413
|
+
<div class="slm-view-menu" role="menu" aria-label="Map view">${qt.map(e=>`
|
|
1414
|
+
<button type="button" class="slm-view-item" role="menuitemcheckbox" data-view="${e.key}" aria-checked="false" title="${e.hint}">
|
|
1415
|
+
<span class="slm-view-check" aria-hidden="true"></span>
|
|
1416
|
+
<span class="slm-view-label">${e.label}</span>
|
|
1417
|
+
<kbd class="slm-view-kbd" aria-hidden="true">\u21E7${e.letter}</kbd>
|
|
1418
|
+
</button>`).join("")}
|
|
1419
|
+
<div class="slm-view-note" data-ref="viewnote" hidden></div>
|
|
1420
|
+
</div>
|
|
1421
|
+
</details>`}function Gt(o,e,t){let s=ke(),n=!1;o.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]&&(n=!0)}),o.querySelector("summary")?.classList.toggle("away",n);let a=o.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(" ")}}ve();Ke();var Xt=require("@seatlayer/core");ve();function Xe(o){return Object.entries(o).filter(([,e])=>e.mode==="closed").map(([e])=>e)}function we(o){let e=o.sectionsBase;if(!e)return{rows:[],hiddenSections:0,closedSections:0};let t=o.doc?.zones??[],s=new Map,n=[];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 n.push(c);let i=[],a=0,l=0,r=(c,d,h,f=!1)=>{let m=o.availabilityRules[d.id]??null,p=o.effectiveClosed.has(d.id)||f,v=o.effectiveHidden.has(d.id)||h&&!p;c==="section"&&v&&(a+=1),c==="section"&&p&&(l+=1),i.push({kind:c,id:d.id,label:d.label,seatCount:d.seatCount,seatLabels:d.seatLabels,rule:m,hidden:v,closed:p,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((p,v)=>p+v.seatCount,0),seatLabels:d.flatMap(p=>p.seatLabels)},f=!!o.availabilityRules[c.id],m=o.availabilityRules[c.id]?.mode==="closed";r("zone",h,!1);for(let p of d)r("section",p,f,m)}for(let c of n)r("section",c,!1);if(e.ungrouped){let c=e.ungrouped;r("section",{id:Xt.UNGROUPED_ID,label:c.label,seatCount:c.seatCount,seatLabels:c.seatLabels},!1)}return{rows:i,hiddenSections:a,closedSections:l}}function Zt(o,e){let t=xt(o.rule),s=`slm-availrow${o.kind==="zone"?" zone":""}${o.hidden?" hidden":""}${o.closed?" closed":""}`,n=e?" disabled":"",i=[["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=o.followsZone?'<span class="slm-availfollows">Follows zone</span>':`<details class="slm-availpicker" data-avail-picker>
|
|
1422
|
+
<summary aria-label="Availability for ${b(o.label)}" ${e?'aria-disabled="true"':""}>${i.find(d=>d[0]===t)[1]}<span aria-hidden="true">\u2304</span></summary>
|
|
1423
|
+
<div class="slm-availchoices" aria-label="Availability options for ${b(o.label)}">
|
|
1424
|
+
${i.map(([d,h,f])=>`<button type="button" data-avail-id="${b(o.id)}" data-avail-value="${d}" aria-pressed="${t===d}"${n}><span><b>${h}</b><small>${f}</small></span><span aria-hidden="true">${t===d?"\u2713":""}</span></button>`).join("")}
|
|
1225
1425
|
</div>
|
|
1226
|
-
</details>`,
|
|
1227
|
-
<input type="datetime-local" class="slm-input" data-avail-reveal="${b(
|
|
1228
|
-
</div>`}else if(!
|
|
1426
|
+
</details>`,l="";if(!o.followsZone&&t==="timed"){let d=o.rule?.revealAt?b(wt(o.rule.revealAt)):"";l=`<div class="slm-availdetail">
|
|
1427
|
+
<input type="datetime-local" class="slm-input" data-avail-reveal="${b(o.id)}" value="${d}"${n} aria-label="Reveal time for ${b(o.label)}" />
|
|
1428
|
+
</div>`}else if(!o.followsZone&&t==="threshold"){let d=o.rule?.thresholdPct??80;l=`<div class="slm-availdetail">
|
|
1229
1429
|
<span class="slm-availpctlabel">Reveal at</span>
|
|
1230
|
-
<input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${b(
|
|
1430
|
+
<input type="number" min="1" max="100" class="slm-input slm-availpct" data-avail-pct="${b(o.id)}" value="${b(d)}"${n} aria-label="Percent sold to reveal ${b(o.label)}" />
|
|
1231
1431
|
<span class="slm-availpctlabel">% sold</span>
|
|
1232
|
-
</div>`}let r=
|
|
1432
|
+
</div>`}let r=o.closed?'<span class="slm-availbadge closed">Closed</span>':o.hidden?'<span class="slm-availbadge hidden">Hidden</span>':"",c=o.kind==="zone"?`<span class="slm-availcaret" aria-hidden="true">${o.hidden?"\u25B8":"\u25BE"}</span>`:"";return`<div class="${s}">
|
|
1233
1433
|
<div class="slm-availhead">
|
|
1234
|
-
<span class="slm-availlabel">${
|
|
1434
|
+
<span class="slm-availlabel">${c}${b(o.label)}</span>
|
|
1235
1435
|
${r}
|
|
1236
|
-
<span class="slm-availcount">${
|
|
1436
|
+
<span class="slm-availcount">${o.seatCount.toLocaleString()}</span>
|
|
1237
1437
|
</div>
|
|
1238
1438
|
${a}
|
|
1239
|
-
${
|
|
1240
|
-
</div>`}var gs="https://api.seatlayer.io",Me=200,Mt=16,It=4,Ht=[{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."}]}],vs=Object.fromEntries(Ht.flatMap(l=>l.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),Ie=class{constructor(e){this.els={};this.renderer=null;this.doc=null;this.selectObserver=null;this.seatHistoryPanel=null;this.activityPanel=null;this.navigation=null;this.movingMap=!1;this.socketSnapshotSeen=!1;this.monitorRefreshTimer=null;this.themeMode=null;this.colorSchemeStop=null;this.inventoryModelVersion=1;this.selectableObjectLabels=new Set;this.lastSelectionLabels=new Set;this.selectionWasValid=null;this.initialSelectionApplied=!1;this.labelToId=new Map;this.labelToSeat=new Map;this.allIds=[];this.gaUnitLabelSet=new Set;this.status=new Map;this.counts={held:0,booked:0,blocked:0};this.modelVersion=0;this.currency="USD";this.authoritativeCurrency=null;this.authoritativeGrossRevenue=0;this.revenueStatus="loading";this.revenueRequest=0;this.controlRoomSnapshot=null;this.serverBaseline=null;this.livePresence=null;this.liveGross=null;this.paintHandle=null;this.trendWindowMinutes=15;this.heatEnabled=!1;this.lastKpiValues=new Map;this.activeKpiDeltas=new Map;this.ws=null;this.reconnectTimer=null;this.attempt=0;this.closed=!1;this.connectionStatus="reconnecting";this.lastMessageAt=null;this.ready=!1;this.feed=[];this.feedTimer=null;this.toastTimer=null;this.liveEventTimer=null;this.kpiCleanupTimer=null;this.followLiveTimer=null;this.followSeatTimer=null;this.releaseAt=null;this.layoutObserver=null;this.tokenExpiresAt=null;this.tokenRefreshTimer=null;this.tokenRefreshInFlight=!1;this.sectionByObject=new Map;this.sectionLabelById=new Map;this.sectionsBase=null;this.filteredSectionLabel=null;this.availabilityRules={};this.effectiveHidden=new Set;this.effectiveClosed=new Set;this.availabilitySaving=!1;this.lastSyncedAt=null;this.blockBrowse=!1;this.blockedQuery="";this.blockedSection="";this.blockedResultLimit=100;this.unblockAllConfirmTimer=null;this.channels=null;this.channelCaps={view:!1,manage:!1};this.categoryCanManage=!1;this.tableCanManage=!1;this.tableBookingSaving=!1;this.channelCapabilityResolution=0;this.channelsLoading=null;this.onFullscreenChange=()=>{this.paintFullscreenButton(),this.updateContainerLayout(),this.renderer?.forceDraw()};this.onKeyDown=e=>{if(e.metaKey||e.ctrlKey||e.altKey||e.target?.matches('input,select,textarea,[contenteditable="true"]'))return;let s=e.key.toLowerCase(),n=vs[s];if(n){if(!this.toolAvailable(n))return;this.setMode(n)}else if(s==="f")this.toggleFullscreen();else if(s==="escape"){if(!this.channels?.handleBack())if(this.getSelection().length)this.clearSelection();else return}else return;e.preventDefault()};this.onRailClick=e=>{let t=e.target,s=t?.closest("[data-section-focus]");if(s?.dataset.sectionFocus){this.locateSection(s.dataset.sectionFocus);return}let n=t?.closest("[data-feed-id]");n?.dataset.feedId&&this.locateActivity(n.dataset.feedId)};this.sectionOptions=[];ze(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 K(e.apiBase??gs,e.token),this.organizerAssetUrls=new de(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=rt(e.container)}assertSelectionOptions(e,t){let s=n=>n===void 0||Number.isInteger(n)&&n>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(){et(),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",n=this.mode==="filterSections";this.mode=e,t&&e!=="view"&&this.setFollowLive(!1),!this.renderer&&this.doc?this.buildRenderer():this.updateRendererInteraction(),t&&(this.renderer?.clearSelection(),this.syncSelection()),s&&e!=="channels"&&this.channels?.leave(),this.paintModeTabs(),this.paintRail(),this.applySectionCanvasTreatment(),n&&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 n=new Set(t);s={view:n.has("event:channels:view"),manage:n.has("event:channels:view")&&n.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 Promise.resolve().then(()=>(Ve(),At));if(this.closed||!this.channelCaps.view||(this.channels||(tt(t.CHANNELS_CSS),this.channels=new t.ChannelsMode(this.buildChannelsHost(),this.channelCaps),this.channels.onInteractionChange=()=>this.updateRendererInteraction()),this.mode!=="channels"))return;this.updateRendererInteraction(),this.paintRail(),this.channels.enter()}catch(t){if(this.closed)return;this.channelsLoading=null,this.mode==="channels"&&this.paintRail(),this.opts.onError?.(t)}})();return this.channelsLoading=e,e}buildChannelsHost(){return{eventKey:this.key,api:this.api,rail:this.els.rail,mapLayer:this.root.querySelector(".slm-map"),pillLane:this.els.lane,root:this.root,seats:()=>[...this.labelToSeat.values()].map(e=>({id:e.id,label:e.label,x:e.x,y:e.y})),statusOf:e=>this.status.get(e)??(this.labelToSeat.has(e)?"free":void 0),selectionLabels:()=>this.selectionLabels(),selectByLabels:e=>{this.selectByLabels(e)},clearSelection:()=>this.clearSelection(),selectSection:e=>{this.selectSection(e)},sections:()=>this.sectionOptions,labelsInSection:e=>this.renderer?.getSelectableInSection(e).map(t=>t.label)??[],rows:()=>{let e=new Map((this.doc?.objects??[]).map(s=>[s.id,s])),t=new Map;for(let s of this.labelToSeat.values()){let n=e.get(s.rowId);if(!n||n.type!=="row"&&n.type!=="table")continue;let i=s.logicalRowId??s.rowId,a=this.sectionByObject.get(s.rowId)??w.UNGROUPED_ID,o=t.get(i)??{id:i,label:n.type==="row"?n.segmentedRow?.displayLabel??n.displayLabel??n.label:n.displayLabel??n.label,sectionId:a,sectionLabel:this.sectionLabelById.get(a)??"Other seats",labels:[]};o.labels.push(s.label),t.set(i,o)}return[...t.values()].sort((s,n)=>s.sectionLabel.localeCompare(n.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(n.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)??w.UNGROUPED_ID;return{id:s,label:this.sectionLabelById.get(s)??"Other seats"}},worldToScreen:e=>this.renderer?.worldToScreen(e)??null,seatPixelSize:()=>this.seatPixelSize(),isSeatDetail:()=>this.renderer?.getRung?.()==="seats",showSectionOverview:()=>{this.renderer?.clearSectionFocus(),this.renderer?.setRung?.("sections")},focusSection:e=>this.renderer?.focusSection(e),isCompact:()=>!!this.root?.classList.contains("compact"),setMapInert:e=>{this.mapHost.toggleAttribute("inert",e),this.mapHost.setAttribute("aria-hidden",String(e))},toast:(e,t)=>this.toast(e,t),onError:e=>this.opts.onError?.(e)}}seatPixelSize(){let e=this.renderer?.getVisibleWorldRect?.(),t=this.mapHost?.clientWidth??0;return!e?.width||!t?6:Math.max(3,t/e.width*18)}setHeatOverlay(e){this.heatEnabled=e,this.applyHeatOverlay(),this.paintHeatButton()}setFollowLive(e){let t=this.followLive!==e;this.followLive=e,e||(this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.followLiveTimer=null,this.followSeatTimer=null),this.paintFollowLiveButton(),t&&this.opts.onFollowLiveChange?.(e)}setKeepLiveWhileHidden(e){this.keepLive=e??!0,this.opts.keepLiveWhileHidden=e}setCurrency(e){this.opts.currency=e,!this.authoritativeCurrency&&(this.currency=e??"USD",this.ready&&this.recomputeTallies())}setTheme(e){this.opts.theme=e,this.applyThemeVars()}applyThemeVars(){if(!this.root)return;let e=Oe(this.themeMode);for(let[t,s]of Object.entries(ht(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=nt(()=>{this.closed||this.repaintForThemeMode()}))}repaintForThemeMode(){this.applyThemeVars();let e=this.renderer;if(!e||!this.doc)return;let t=e.getSelection().map(i=>i.id),s=e.getCameraPose(),n=e.getFocusedSection();e.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),t.length&&e.select(t),n&&e.focusSection(n),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=pt(Oe(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){ze(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(),n=Math.min(12e4,Math.max(3e4,s*.2)),i=Math.max(0,s-n);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},i)}async rotateToken(){if(!(this.closed||this.tokenRefreshInFlight||!this.opts.onTokenRefresh)){this.tokenRefreshInFlight=!0;try{let e=await this.opts.onTokenRefresh();if(!e?.token||!Number.isFinite(e.expiresAt))throw new Error("invalid_token_refresh_result");this.setToken(e.token,e.expiresAt)}catch(e){this.opts.onError?.(e),this.closed||(this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},3e4))}finally{this.tokenRefreshInFlight=!1}}}async block(e,t={}){let s=(e??this.selectionLabels()).filter(i=>this.status.get(i)==="free");if(!s.length)return;let n=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:n}),this.clearSelection(),this.done("block",s,n?`Blocked ${s.length} \u2014 auto-release ${new Date(n).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"free"),this.toastErr(i instanceof x&&i.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(i)}}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(n=>this.status.get(n)==="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(n){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(n)}}}async setCategory(e,t){let s=this.doc?.categories.find(i=>i.key===e),n=[...new Set(t??this.selectionLabels())].filter(i=>this.labelToSeat.has(i));if(!(!s||!n.length))try{let i=await this.withAuthRetry(()=>this.api.setCategory(this.key,n,e)),a={};for(let o of i.labels){let r=this.labelToSeat.get(o),d=this.labelToId.get(o);r&&(r.categoryKey=e),d&&(a[d]=e)}this.renderer?.setSeatCategories?.(a),this.clearSelection(),this.done("setCategory",i.labels,`Assigned ${i.labels.length.toLocaleString()} object${i.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(i){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(i)}}async setTableBooking(e,t,s={}){let n=[...new Set(e)].filter(Boolean);if(!(!n.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 i=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,n,t,s));await this.reloadEventChart(),this.done("setTableBooking",i.tableIds,`Updated ${i.tableIds.length.toLocaleString()} table${i.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(i){let a=i instanceof x&&i.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?.(i)}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 n=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let i=s.map(({id:a,label:o,seatCount:r,zone:d})=>({id:a,label:o,seatCount:r,...d?{zone:d}:{}}));return n&&this.opts.onFilteredSectionChange?.(i),i}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:n})=>({id:e,label:t,seatCount:s,...n?{zone:n}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),n=this.selectionCap(),i=[...new Set(e)].filter(o=>!s.has(o)).map(o=>this.labelToSeat.get(o)).filter(o=>!!o&&this.canSelectObject(o)),a=Math.max(0,n-s.size);i.length>a&&this.opts.onSelectionLimit?.(n),t=i.slice(0,a).map(o=>o.label)}return this.renderer?.selectByLabels(t),this.syncSelection(),this.getSelection()}selectObjects(e){return this.selectByLabels(e)}deselectObjects(e){let t=e.map(s=>this.labelToId.get(s)).filter(s=>!!s);return this.renderer?.deselect(t),this.syncSelection(),this.getSelection()}selectCategories(e){let t=new Set(e);return this.selectByLabels([...this.labelToSeat.values()].filter(s=>t.has(s.categoryKey)).map(s=>s.label))}deselectCategories(e){let t=new Set(e);return this.deselectObjects(this.getSelection().filter(s=>t.has(s.categoryKey)).map(s=>s.label))}setSelectableObjects(e){this.opts.selectableObjects=[...e],this.selectableObjectLabels=new Set(e),this.reconcileSelectPolicy()}setUnavailableObjectsSelectable(e){this.opts.unavailableObjectsSelectable=e,this.reconcileSelectPolicy()}setObjectSelectable(e){this.opts.isObjectSelectable=e,this.reconcileSelectPolicy()}setMaxSelectedObjects(e){this.assertSelectionOptions(e,this.opts.numberOfPlacesToSelect),this.opts.maxSelectedObjects=e,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}setNumberOfPlacesToSelect(e){this.assertSelectionOptions(this.opts.maxSelectedObjects,e),this.opts.numberOfPlacesToSelect=e,this.selectionWasValid=null,this.trimSelectionToCap(),this.updateRendererInteraction(),this.syncSelection()}getSelectionValidity(){let e=this.opts.numberOfPlacesToSelect;if(e===void 0)return null;let t=this.getSelection(),s=t.length;return{isValid:s===e,count:s,required:e,remaining:Math.max(0,e-s),objects:t}}clearSelection(){this.renderer?.clearSelection(),this.syncSelection()}getSelection(){return this.renderer?.getSelection()??[]}getReport(){return this.api.report(this.key).then(e=>(this.applyReportRevenue(e),e))}getControlRoomSnapshot(e=this.trendWindowMinutes){return this.setTrendWindow(e)}getConnection(){return{status:this.connectionStatus,lastMessageAt:this.lastMessageAt}}getLog(e={}){return this.api.log(this.key,e)}async setHoldTtl(e){try{await this.api.setHoldTtl(this.key,e),this.done("setHoldTtl",[],e?`Hold window set to ${Math.round(e/6e4)} min.`:"Hold window reset.")}catch(t){this.toastErr("Couldn't update the hold window."),this.opts.onError?.(t)}}zoomToFit(){if(this.mode==="filterSections"&&this.filteredSectionLabel){this.clearFilteredSection();return}this.renderer?.clearSectionFocus(),this.renderer?.zoomToFit()}destroy(){if(this.selectObserver?.disconnect(),this.closed=!0,this.monitorRefreshTimer&&clearTimeout(this.monitorRefreshTimer),this.monitorRefreshTimer=null,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.feedTimer&&clearInterval(this.feedTimer),this.toastTimer&&clearTimeout(this.toastTimer),this.liveEventTimer&&clearTimeout(this.liveEventTimer),this.kpiCleanupTimer&&clearTimeout(this.kpiCleanupTimer),this.followLiveTimer&&clearTimeout(this.followLiveTimer),this.followSeatTimer&&clearTimeout(this.followSeatTimer),this.unblockAllConfirmTimer&&clearTimeout(this.unblockAllConfirmTimer),this.paintHandle!==null&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.paintHandle),this.paintHandle=null,this.channels?.destroy(),this.channels=null,this.channelsLoading=null,this.tokenRefreshTimer&&clearTimeout(this.tokenRefreshTimer),this.layoutObserver?.disconnect(),this.layoutObserver=null,this.colorSchemeStop?.(),this.colorSchemeStop=null,this.root?.removeEventListener("keydown",this.onKeyDown),this.els.rail?.removeEventListener("click",this.onRailClick),typeof document<"u"&&document.removeEventListener("fullscreenchange",this.onFullscreenChange),this.ws){try{this.ws.close()}catch{}this.ws=null}this.seatHistoryPanel?.destroy(),this.seatHistoryPanel=null,this.activityPanel?.destroy(),this.activityPanel=null,this.navigation?.destroy(),this.navigation=null,this.renderer?.destroy(),this.renderer=null,this.organizerAssetUrls.dispose(),this.root&&this.root.parentNode===this.host&&this.host.removeChild(this.root)}buildRenderer(){if(!this.doc)return;let e=this.isBulkSelectMode();this.renderer=new w.SeatmapRenderer(this.mapHost,{manageMode:!0,organizerGlyph:{apply:w.applyOrganizerSeatGlyph,clear:w.clearOrganizerSeatGlyph,isPainted:w.isOrganizerGlyphPainted},marqueeSelect:e&&!this.movingMap,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses(),currency:this.currency,onSelect:t=>this.handleSeatSelect(t),onDeselect:()=>this.syncSelection(),onSelectionLimit:t=>this.opts.onSelectionLimit?.(t),onMarquee:()=>this.syncSelection(),onSectionTap:t=>{if(this.mode==="filterSections"){let s=this.filterableSections().find(n=>n.id===t);s&&this.setFilteredSection(s.label);return}this.renderer?.focusSection(t),this.channels?.handleSectionFocus(t)},onViewChange:()=>{this.updateZoomHint(),this.channels?.handleViewChange()}}),this.renderer.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),this.updateZoomHint()}isBulkSelectMode(){return this.mode==="block"||this.mode==="categories"||this.mode==="channels"&&this.channels?.usesMarqueeSelection()===!0}selectableStatuses(){return this.mode==="block"?["free","not_for_sale"]:this.mode==="select"||this.mode==="categories"||this.mode==="inspect"||this.isBulkSelectMode()||this.mode==="channels"&&this.channels?.canSelect()===!0?["free","held","booked","not_for_sale"]:[]}updateRendererInteraction(){let e=this.isBulkSelectMode();this.renderer?.setManageInteraction({manageMode:!0,organizerStatus:this.mode!=="channels",marqueeSelect:e&&!this.movingMap,maxSelection:this.selectionCap(),selectableStatuses:this.selectableStatuses()}),this.navigation?.update(e,this.mode==="view"),this.updateZoomHint()}handleSeatSelect(e){if(this.mode==="select"&&!this.canSelectObject(e)){this.renderer?.deselect([e.id]),this.syncSelection();return}if(this.mode==="inspect"){let t=this.getSelection().filter(s=>s.id!==e.id).map(s=>s.id);t.length&&this.renderer?.deselect(t)}this.syncSelection()}buildUnitUniverse(e){for(let t of(0,w.expandChart)(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of(0,w.gaAreasOf)(e))for(let s of(0,w.gaUnitLabels)(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,n]of this.status.entries()){let i=this.labelToId.get(s);i&&t[pe(n)].push(i)}["held","booked","not_for_sale"].forEach(s=>{t[s].length&&e.setStatus(t[s],s)})}async connect(){if(this.closed)return;let e;try{if(e=(await this.withAuthRetry(()=>this.api.subscribeTicket(this.key))).protocols,!e.length)throw new Error("manage_subscribe_ticket_missing")}catch(s){this.setLive(!1),this.opts.onError?.(s),this.scheduleReconnect();return}if(this.closed)return;let t;try{t=new WebSocket(this.api.socketUrl(this.key),e)}catch(s){this.opts.onError?.(s),this.scheduleReconnect();return}this.ws=t,this.socketSnapshotSeen=!1,t.onopen=()=>{this.attempt=0,this.setLive(!0),this.resnapshot().then(()=>this.refreshControlRoom()).catch(s=>this.opts.onError?.(s)),this.refreshAvailability()},t.onmessage=s=>this.onMessage(s),t.onclose=()=>{this.ws===t&&(this.ws=null),this.setLive(!1),this.scheduleReconnect()},t.onerror=()=>{try{t.close()}catch{}}}scheduleReconnect(){if(this.closed||this.reconnectTimer)return;let e=Math.min(1e3*2**Math.min(this.attempt++,5),15e3);this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},e)}onMessage(e){let t;try{t=JSON.parse(typeof e.data=="string"?e.data:"")}catch{return}if(!t||typeof t!="object")return;this.lastMessageAt=Date.now();let s=t;if((Array.isArray(s.hidden)||Array.isArray(s.closed))&&this.updateEffectiveAvailability(s.hidden,s.closed),s.type==="presence"){typeof s.shoppingSessions=="number"&&typeof s.activeHolds=="number"&&(this.livePresence={at:Date.now(),value:{shoppingSessions:s.shoppingSessions,activeHolds:s.activeHolds}},this.controlRoomSnapshot&&(this.controlRoomSnapshot={...this.controlRoomSnapshot,presence:this.livePresence.value},this.opts.onControlRoom?.(this.controlRoomSnapshot)),this.lastSyncedAt=Date.now(),this.recomputeTallies(),this.paintMonitorInsights());return}if(s.type!=="hidden"){if(s.seats&&typeof s.seats=="object")this.applySocketSnapshot(s.seats,typeof s.default=="string"?s.default:void 0);else if(Array.isArray(s.changes)){let n=[],i=new Map;for(let o of s.changes){let r=["free","held","booked","blocked"].includes(o.status)?o.status:"free",d=this.status.get(o.label)??"free";if(d===r)continue;this.setStatusLabel(o.label,r,d);let c=this.labelToId.get(o.label);c&&(this.renderer?.setStatus([c],pe(r)),n.push(c));let h=this.verbFor(d,r),u=`${h}:${r}`,f=i.get(u)??{labels:[],verb:h,status:r};f.labels.push(o.label),i.set(u,f)}for(let o of i.values()){let r=this.pushActivity(o.labels,o.verb,o.status);r&&this.paintSpatialActivity(r)}i.size&&this.scheduleMonitorRefresh(),n.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 n=new Map;for(let i of new Set([...s.keys(),...this.status.keys()])){let a=s.get(i)??"free",o=this.status.get(i)??"free";if(a===o)continue;let r=this.verbFor(a,o),d=`${r}:${o}`,c=n.get(d)??{labels:[],verb:r,status:o};c.labels.push(i),n.set(d,c)}for(let i of n.values()){let a=this.pushActivity(i.labels,i.verb,i.status);a&&this.paintSpatialActivity(a)}n.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=i=>["free","held","booked","blocked"].includes(i)?i:"free",n=new Map;if(t!==void 0){let i=s(t);for(let a of this.knownLabels())n.set(a,i)}for(let[i,a]of Object.entries(e))n.set(i,s(a));this.status=n,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 n of e){this.setStatusLabel(n,t);let i=this.labelToId.get(n);i&&s.push(i)}s.length&&this.renderer?.setStatus(s,pe(t)),this.afterPaint(),this.recomputeTallies()}afterPaint(){this.keepLive&&typeof document<"u"&&document.hidden&&this.renderer?.forceDraw()}activityColor(e){return e==="held"?A.held:e==="booked"?A.booked:e==="blocked"?A.blocked:A.free}sectionsForLabels(e){let t=new Set;for(let n of e){let i=this.labelToSeat.get(n);if(!i)continue;let a=this.sectionByObject.get(i.rowId);a&&a!==w.UNGROUPED_ID&&t.add(a)}let s=[...t];return{ids:s,labels:s.map(n=>this.sectionLabelById.get(n)??n)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let n of e.slice(0,Mt)){let i=this.labelToId.get(n);i&&this.renderer?.flashSeat(i,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 i=this.root?.querySelector('[data-ref="followstatus"]');i&&(i.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 i=this.activityColor(e.status);for(let a of t.slice(0,It))this.renderer?.flashSection(a,i);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,Mt).map(r=>this.labelToSeat.get(r)).filter(r=>!!r);if(!s.length)return;let n=s.map(r=>r.x),i=s.map(r=>r.y),a=Math.min(...n),o=Math.min(...i);this.renderer?.focusRegion({x:a-150,y:o-100,width:Math.max(...n)-a+300,height:Math.max(...i)-o+200})}locateActivity(e){let t=this.feed.find(n=>n.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 n=this.activityColor(t.status);for(let i of s.slice(0,It))this.renderer?.flashSection(i,n)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],n=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,i=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
|
|
1439
|
+
${l}
|
|
1440
|
+
</div>`}var rn="https://api.seatlayer.io",Fe=200,ms=16,ps=4,us=[{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."}]}],cn=3;function dn(o){let e=o?.status;return e===401||e===403}var hn=Object.fromEntries(us.flatMap(o=>o.tools.map(e=>[e.shortcut.toLowerCase(),e.mode]))),Ve=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=ke();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(),n=e.shiftKey?Nt(s):null;if(n){this.toggleMapView(n),e.preventDefault();return}if(s==="/"){let a=this.els.findbar?.querySelector("[data-ch-find-input]");a&&(a.focus(),a.select(),e.preventDefault());return}let i=hn[s];if(i){if(!this.toolAvailable(i))return;this.setMode(i)}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 n=t?.closest("[data-feed-id]");n?.dataset.feedId&&this.locateActivity(n.dataset.feedId)};this.sectionOptions=[];We(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 Y(e.apiBase??rn,e.token),this.organizerAssetUrls=new ue(this.key,(t,s)=>this.withAuthRetry(()=>this.api.asset(t,s))),this.host=St(e.container)}assertSelectionOptions(e,t){let s=n=>n===void 0||Number.isInteger(n)&&n>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(){bt(),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",n=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(),n&&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 n=new Set(t);s={view:n.has("event:channels:view"),manage:n.has("event:channels:view")&&n.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 Promise.resolve().then(()=>(tt(),hs));if(this.closed||!this.channelCaps.view||(this.channels||(gt(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 n=this.labelToSeat.get(s);return n?this.mode==="block"?this.isBlockSelectable(s):this.mode==="select"?this.canSelectObject(n):!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(n=>n.label).filter(e),rows:()=>{let s=new Map((this.doc?.objects??[]).map(i=>[i.id,i])),n=new Map;for(let i of this.labelToSeat.values()){if(!e(i.label))continue;let a=s.get(i.rowId);if(!a||a.type!=="row"&&a.type!=="table")continue;let l=i.logicalRowId??i.rowId,r=this.sectionByObject.get(i.rowId)??S.UNGROUPED_ID,c=n.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(i.label),n.set(l,c)}return[...n.values()].sort((i,a)=>i.sectionLabel.localeCompare(a.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||i.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(n=>n.categoryKey===s&&e(n.label)).map(n=>n.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 n=this.labelToSeat.get(s);if(!n)return null;let i=this.sectionByObject.get(n.rowId)??S.UNGROUPED_ID;return{id:i,label:this.sectionLabelById.get(i)??"Other seats"}},openDialog:(s,n)=>{this.chooserDialog=ht(this.root,s,n,{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=xe({compact:!0}),this.barFind=new N({...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 N(this.buildChooserHost()),this.chooser}toolSelectionBar(e,t,s,n){return $t({count:0,noun:"selected",breakdown:`<span class="slm-selactions"><button type="button" class="slm-linkbtn" data-ref="${n}">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 n=e.get(s.rowId);if(!n||n.type!=="row"&&n.type!=="table")continue;let i=s.logicalRowId??s.rowId,a=this.sectionByObject.get(s.rowId)??S.UNGROUPED_ID,l=t.get(i)??{id:i,label:n.type==="row"?n.segmentedRow?.displayLabel??n.displayLabel??n.label:n.displayLabel??n.label,sectionId:a,sectionLabel:this.sectionLabelById.get(a)??"Other seats",labels:[]};l.labels.push(s.label),t.set(i,l)}return[...t.values()].sort((s,n)=>s.sectionLabel.localeCompare(n.sectionLabel,void 0,{numeric:!0,sensitivity:"base"})||s.label.localeCompare(n.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)??S.UNGROUPED_ID;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(n=>t[n]!==this.mapView[n])&&(this.mapView=t,Ut(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(){Wt(this.mapView,{renderer:this.renderer,channelsOverlay:e=>this.channels?.setOverlayVisible(e)})}paintMapViewMenu(){let e=this.els.view;e&&Gt(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=Ue(this.themeMode);for(let[t,s]of Object.entries(Tt(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=vt(()=>{this.closed||this.repaintForThemeMode()}))}repaintForThemeMode(){this.applyThemeVars();let e=this.renderer;if(!e||!this.doc)return;let t=e.getSelection().map(i=>i.id),s=e.getCameraPose(),n=e.getFocusedSection();e.setChart(this.themedDoc()),this.repaintAll(),this.applyHeatOverlay(),t.length&&e.select(t),n&&e.focusSection(n),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=Mt(Ue(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){We(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(),n=Math.min(12e4,Math.max(3e4,s*.2)),i=Math.max(0,s-n);this.tokenRefreshTimer=setTimeout(()=>{this.tokenRefreshTimer=null,this.rotateToken()},i)}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>=cn||dn(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=`
|
|
1441
|
+
<strong id="slm-ended-title">This session ended</strong>
|
|
1442
|
+
<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>
|
|
1443
|
+
<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(i=>this.status.get(i)==="free");if(!s.length)return;let n=t.releaseAt??this.releaseAt??void 0;this.setSeatsLocal(s,"blocked");try{await this.api.block(this.key,s,{...t,releaseAt:n}),this.clearSelection(),this.done("block",s,n?`Blocked ${s.length} \u2014 auto-release ${new Date(n).toLocaleString()}.`:`Blocked ${s.length} seat${s.length===1?"":"s"}.`)}catch(i){this.setSeatsLocal(s,"free"),this.toastErr(i instanceof w&&i.status===409?"Some seats were just taken. Try again.":"Couldn't block those seats."),this.opts.onError?.(i)}}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(n=>this.status.get(n)==="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(n){this.setSeatsLocal(s,"booked"),this.toastErr("Couldn't release that booked inventory. Check the booking reference."),this.opts.onError?.(n)}}}async setCategory(e,t){let s=this.doc?.categories.find(i=>i.key===e),n=[...new Set(t??this.selectionLabels())].filter(i=>this.labelToSeat.has(i));if(!(!s||!n.length))try{let i=await this.withAuthRetry(()=>this.api.setCategory(this.key,n,e)),a={};for(let l of i.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",i.labels,`Assigned ${i.labels.length.toLocaleString()} object${i.labels.length===1?"":"s"} to ${s.label??s.key}.`)}catch(i){this.toastErr("Couldn't update those event categories."),this.opts.onError?.(i)}}async setTableBooking(e,t,s={}){let n=[...new Set(e)].filter(Boolean);if(!(!n.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 i=await this.withAuthRetry(()=>this.api.setTableBooking(this.key,n,t,s));await this.reloadEventChart(),this.done("setTableBooking",i.tableIds,`Updated ${i.tableIds.length.toLocaleString()} table${i.tableIds.length===1?"":"s"} to ${t==="individual"?"per-chair":t==="whole"?"whole-table":"flexible-group"} booking.`)}catch(i){let a=i instanceof w&&i.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?.(i)}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 n=t!==this.filteredSectionLabel;this.filteredSectionLabel=t,this.mode==="filterSections"&&(this.applyFilteredSectionCanvas(s),this.renderFilterSectionsRail());let i=s.map(({id:a,label:l,seatCount:r,zone:c})=>({id:a,label:l,seatCount:r,...c?{zone:c}:{}}));return n&&this.opts.onFilteredSectionChange?.(i),i}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:n})=>({id:e,label:t,seatCount:s,...n?{zone:n}:{}})):[]}selectByLabels(e){let t=e;if(this.mode==="select"){let s=new Set(this.selectionLabels()),n=this.selectionCap(),i=[...new Set(e)].filter(l=>!s.has(l)).map(l=>this.labelToSeat.get(l)).filter(l=>!!l&&this.canSelectObject(l)),a=Math.max(0,n-s.size);i.length>a&&this.opts.onSelectionLimit?.(n),t=i.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,n=e.getFloors?.()??[],i=n.length>1?e.isFloorOverview?.()?"All floors":n.find(l=>l.id===e.getActiveFloorId?.())?.name??null:null,a=this.els.blocklegend;a&&(a.hidden=e.getRung?.()==="seats"||!e.getMinimapSnapshot?.().sections.length),zt(this.els,Dt({focused:s?{label:s.label,free:s.free,total:s.total}:null,floor:i,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=Ht({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 S.SeatmapRenderer(this.mapHost,{manageMode:!0,organizerGlyph:{apply:S.applyOrganizerSeatGlyph,clear:S.clearOrganizerSeatGlyph,isPainted:S.isOrganizerGlyphPainted},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(n=>n.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=>Ft(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(d=>d.id===e);if(!t)return null;let s=this.status.get(t.label)??"free",i=[{caption:"Status",value:{free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"}[s]}],a=this.channels?.channelNameForLabel(t.label)??null;a&&i.push({caption:"Channel",value:a});let l=this.sectionByObject.get(t.rowId)??S.UNGROUPED_ID,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 i.push({caption:"For sale",value:c?"Yes":s==="free"?"No":"\u2014"}),i}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}"
|
|
1444
|
+
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 n=s.dataset.ref===`shape-${t}`;s.classList.toggle("ghost",!n),s.setAttribute("aria-pressed",String(n))}))})})}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(0,S.expandChart)(e))this.labelToId.set(t.label,t.id),this.labelToSeat.set(t.label,t),this.allIds.push(t.id);for(let t of(0,S.gaAreasOf)(e))for(let s of(0,S.gaUnitLabels)(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,n]of this.status.entries()){let i=this.labelToId.get(s);i&&t[ge(n)].push(i)}["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 n=[],i=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.labelToId.get(l.label);d&&(this.renderer?.setStatus([d],ge(r)),n.push(d));let h=this.verbFor(c,r),f=`${h}:${r}`,m=i.get(f)??{labels:[],verb:h,status:r};m.labels.push(l.label),i.set(f,m)}for(let l of i.values()){let r=this.pushActivity(l.labels,l.verb,l.status);r&&this.paintSpatialActivity(r)}i.size&&this.scheduleMonitorRefresh(),n.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 n=new Map;for(let i of new Set([...s.keys(),...this.status.keys()])){let a=s.get(i)??"free",l=this.status.get(i)??"free";if(a===l)continue;let r=this.verbFor(a,l),c=`${r}:${l}`,d=n.get(c)??{labels:[],verb:r,status:l};d.labels.push(i),n.set(c,d)}for(let i of n.values()){let a=this.pushActivity(i.labels,i.verb,i.status);a&&this.paintSpatialActivity(a)}n.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=i=>["free","held","booked","blocked"].includes(i)?i:"free",n=new Map;if(t!==void 0){let i=s(t);for(let a of this.knownLabels())n.set(a,i)}for(let[i,a]of Object.entries(e))n.set(i,s(a));this.status=n,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 n of e){this.setStatusLabel(n,t);let i=this.labelToId.get(n);i&&s.push(i)}s.length&&this.renderer?.setStatus(s,ge(t)),this.afterPaint(),this.recomputeTallies()}afterPaint(){this.keepLive&&typeof document<"u"&&document.hidden&&this.renderer?.forceDraw()}activityColor(e){return e==="held"?H.held:e==="booked"?H.booked:e==="blocked"?H.blocked:H.free}sectionsForLabels(e){let t=new Set;for(let n of e){let i=this.labelToSeat.get(n);if(!i)continue;let a=this.sectionByObject.get(i.rowId);a&&a!==S.UNGROUPED_ID&&t.add(a)}let s=[...t];return{ids:s,labels:s.map(n=>this.sectionLabelById.get(n)??n)}}pulseSeatLabels(e,t){let s=this.activityColor(t);for(let n of e.slice(0,ms)){let i=this.labelToId.get(n);i&&this.renderer?.flashSeat(i,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 i=this.root?.querySelector('[data-ref="followstatus"]');i&&(i.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 i=this.activityColor(e.status);for(let a of t.slice(0,ps))this.renderer?.flashSection(a,i);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,ms).map(r=>this.labelToSeat.get(r)).filter(r=>!!r);if(!s.length)return;let n=s.map(r=>r.x),i=s.map(r=>r.y),a=Math.min(...n),l=Math.min(...i);this.renderer?.focusRegion({x:a-150,y:l-100,width:Math.max(...n)-a+300,height:Math.max(...i)-l+200})}locateActivity(e){let t=this.feed.find(n=>n.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 n=this.activityColor(t.status);for(let i of s.slice(0,ps))this.renderer?.flashSection(i,n)}else this.pulseSeatLabels(t.labels,t.status)},280)}showLiveEvent(e){let t=this.els.liveevent;if(!t)return;let s=e.sectionLabels??[],n=s.length===1?s[0]:s.length>1?`${s.length} sections`:e.label,i=e.count===1?"seat":"seats";t.innerHTML=`<span class="slm-liveeventdot" style="background:${this.activityColor(e.status)}"></span>
|
|
1241
1445
|
<span class="slm-liveeventcopy">${b(n)} \xB7 ${e.count.toLocaleString()} ${i} ${b(e.verb)}</span>
|
|
1242
|
-
<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 n=Number.isFinite(s.bookedValue)?s.bookedValue:s.bookedRevenue;return t+(Number.isFinite(n)?n: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),n=s.bookedValue??s.revenue??{gross:0,bySection:[]},i=(n.bySection??[]).map(r=>{let
|
|
1446
|
+
<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 n=Number.isFinite(s.bookedValue)?s.bookedValue:s.bookedRevenue;return t+(Number.isFinite(n)?n: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),n=s.bookedValue??s.revenue??{gross:0,bySection:[]},i=(n.bySection??[]).map(r=>{let c=Number.isFinite(r.bookedValue)?r.bookedValue:r.bookedRevenue;return{...r,bookedValue:c??0,bookedRevenue:c??0}}),a={...n,bySection:i},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],n=this.controlRoomSnapshot?.event?.seatTotal,i={free:s("free"),held:s("held"),booked:s("booked"),blocked:s("blocked"),total:Number.isFinite(n)?n:this.unitTotal(),capacityPct:0,sellThroughPct:0,bookedValue:this.authoritativeGrossRevenue,grossRevenue:this.authoritativeGrossRevenue,bookedValueStatus:this.revenueStatus,revenueStatus:this.revenueStatus,currency:this.currency};i.capacityPct=i.total?Math.round(i.booked/i.total*100):0;let a=i.total-i.blocked;return i.sellThroughPct=a>0?Math.round(i.booked/a*100):0,i}recomputeTallies(){if(!this.closed){if(typeof requestAnimationFrame!="function"){this.flushTallies();return}this.paintHandle===null&&(this.paintHandle=requestAnimationFrame(()=>{this.paintHandle=null,this.flushTallies()}))}}flushTallies(){if(this.closed)return;let e=this.buildTallies();this.paintKpis(e),this.mode==="view"?(this.paintLegend(e),this.paintMonitorInsights()):this.mode==="inspect"?this.renderInspectRail(this.getSelection()):this.mode==="block"?this.paintSelBar(this.getSelection()):this.mode==="channels"&&this.channels?.handleSelectionChange(),this.opts.onTallies?.(e)}verbFor(e,t){return t==="held"?"held":t==="booked"?"booked":t==="blocked"?"blocked":t==="free"?e==="blocked"?"unblocked":e==="booked"?"cancelled":"available":t}pushActivity(e,t,s,n=Date.now()){let i=e[0];if(!i)return null;let a=this.sectionsForLabels(e),l={id:`${i}:${n}:${Math.random().toString(36).slice(2,6)}`,at:n,label:i,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>Fe&&(this.feed.length=Fe),this.mode==="view"&&this.paintFeed(),this.showLiveEvent(l),this.opts.onActivity?.(l),l}seedFeed(e){this.controlRoomSnapshot?.activity&&(this.feed=this.feed.filter(n=>n.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 n of e){if(this.feed.some(r=>r.id===`log:${n.id}`))continue;let i=n.labels[0];if(!i)continue;let a=this.sectionsForLabels(n.labels),l={id:`log:${n.id}`,at:n.at,label:i,labels:[...n.labels],count:n.labels.length,verb:t[n.action]??n.action,status:s[n.action]??"free",sectionIds:a.ids,sectionLabels:a.labels};this.feed.push(l),this.opts.onActivity?.(l)}this.feed.sort((n,i)=>i.at-n.at),this.feed.length>Fe&&(this.feed.length=Fe),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,n=t==="free"||s||this.selectableObjectLabels.has(e.label);if(!this.opts.isObjectSelectable)return n;try{return this.opts.isObjectSelectable(e,n)===!0}catch(i){return this.opts.onError?.(i),!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[n,i]of t)this.lastSelectionLabels.has(n)||this.opts.onObjectSelected?.(i);for(let n of this.lastSelectionLabels)if(!t.has(n)){let i=this.labelToSeat.get(n);i&&this.opts.onObjectDeselected?.(i)}let s=this.getSelectionValidity();s&&(this.opts.onSelectionValidityChange?.(s),this.selectionWasValid!==s.isValid&&(s.isValid?this.opts.onSelectionValid?.(s):this.opts.onSelectionInvalid?.(s)),this.selectionWasValid=s.isValid)}this.lastSelectionLabels=new Set(t.keys()),this.navigation?.selectionChanged(e.length),this.opts.onSelectionChange?.(e)}buildChrome(){let e=document.createElement("div");e.className="slm",e.tabIndex=0,e.setAttribute("role","region"),e.setAttribute("aria-label","SeatLayer live control room"),e.innerHTML=`
|
|
1243
1447
|
<div class="slm-bar">
|
|
1244
1448
|
<div class="slm-modes" data-ref="modes" role="tablist" aria-label="Control room tools">
|
|
1245
|
-
${
|
|
1449
|
+
${us.map(n=>`<div class="slm-modegroup" data-group="${n.key}" role="presentation" hidden>
|
|
1246
1450
|
<span class="slm-modegroup-label" aria-hidden="true">${b(n.label)}</span>
|
|
1247
1451
|
${n.tools.map(i=>`<button class="slm-mode" role="tab" data-mode="${i.mode}"
|
|
1248
1452
|
title="${b(i.title)} (${i.shortcut})" aria-keyshortcuts="${i.shortcut}" hidden>${b(i.label)}</button>`).join("")}
|
|
@@ -1253,9 +1457,8 @@
|
|
|
1253
1457
|
<div class="slm-bar-actions">
|
|
1254
1458
|
<button class="slm-barbtn follow" data-ref="follow" aria-label="Follow live" aria-pressed="false"
|
|
1255
1459
|
title="Stay on the current map view unless enabled">Auto-follow</button>
|
|
1256
|
-
<
|
|
1257
|
-
|
|
1258
|
-
title="Highlight sections booking fastest in the selected time window">Heatmap</button>
|
|
1460
|
+
<div data-ref="findbar" class="slm-findbar">${xe({compact:!0})}</div>
|
|
1461
|
+
${Yt()}
|
|
1259
1462
|
<button class="slm-barbtn" data-ref="fullscreen" title="Full screen (F)" aria-keyshortcuts="F">Full screen</button>
|
|
1260
1463
|
</div>
|
|
1261
1464
|
<div class="slm-kpis" data-ref="kpis"></div>
|
|
@@ -1269,15 +1472,15 @@
|
|
|
1269
1472
|
</div>
|
|
1270
1473
|
<div class="slm-heat-status" data-ref="heatstatus" role="status" hidden></div>
|
|
1271
1474
|
<div class="slm-follow-status" data-ref="followstatus" role="status" hidden></div>
|
|
1272
|
-
|
|
1475
|
+
${Ot({legend:Vt()})}
|
|
1273
1476
|
</div>
|
|
1274
1477
|
<aside class="slm-rail"><div class="slm-railscroll" data-ref="rail"></div></aside>
|
|
1275
1478
|
</div>
|
|
1276
1479
|
<div class="slm-toast" data-ref="toast"></div>
|
|
1277
|
-
`,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let n=e.querySelector(".slm-rail");n&&
|
|
1278
|
-
<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(){
|
|
1480
|
+
`,this.host.appendChild(e),this.root=e,this.selectObserver=new MutationObserver(()=>{let n=e.querySelector(".slm-rail");n&&(W(n),at(n))});let t=e.querySelector(".slm-rail");t&&this.selectObserver.observe(t,{childList:!0,subtree:!0}),this.applyThemeVars(),this.watchThemeMode(),this.updateContainerLayout(),typeof ResizeObserver<"u"&&(this.layoutObserver=new ResizeObserver(()=>this.updateContainerLayout()),this.layoutObserver.observe(e));let s=n=>e.querySelector(`[data-ref="${n}"]`);this.mapHost=s("maphost"),this.els={modes:s("modes"),tools:s("tools"),livetext:s("livetext"),kpis:s("kpis"),follow:s("follow"),view:s("view"),findbar:s("findbar"),fullscreen:s("fullscreen"),lane:s("lane"),zoomhint:s("zoomhint"),liveevent:s("liveevent"),rail:s("rail"),toast:s("toast"),mapchrome:s("mapchrome"),crumb:s("crumb"),zin:s("zin"),zout:s("zout"),zfit:s("zfit"),minimapMount:s("minimap"),blocklegend:s("blocklegend")},this.els.modes.querySelectorAll("[data-mode]").forEach(n=>n.addEventListener("click",()=>this.setMode(n.dataset.mode))),this.els.tools.addEventListener("change",()=>this.setMode(this.els.tools.value)),this.els.zfit.addEventListener("click",()=>{this.setFollowLive(!1),this.zoomToFit()}),this.els.zin.addEventListener("click",()=>{this.setFollowLive(!1),this.renderer?.zoomIn()}),this.els.zout.addEventListener("click",()=>{this.setFollowLive(!1),this.zoomOutStep()}),this.els.follow.addEventListener("click",()=>this.setFollowLive(!this.followLive)),this.els.view.addEventListener("click",n=>{let i=n.target?.closest("[data-view]");i?.dataset.view&&this.toggleMapView(i.dataset.view)}),e.addEventListener("pointerdown",n=>{let i=this.els.view;i.open&&!i.contains(n.target)&&(i.open=!1)}),this.mapView=jt(),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 he({root:e,map:this.mapHost,setMoving:n=>{this.movingMap=n,this.updateRendererInteraction()},pauseFollow:()=>{this.followLive&&this.setFollowLive(!1)},clearSelection:()=>this.clearSelection(),zoomIn:()=>this.renderer?.zoomIn(),zoomOut:()=>this.renderer?.zoomOut(),targets:n=>this.navigationTargets(n)}),this.navigation.update(this.isBulkSelectMode(),this.mode==="view")}navigationTargets(e){let t=e.toLocaleLowerCase(),s=[];for(let i of this.sectionOptions)if(i.label.toLocaleLowerCase().includes(t)&&s.push({label:i.label,detail:"Section",locate:()=>this.locateSection(i.id)}),s.length>=20)return s;let n=new Map;for(let i of this.labelToSeat.values()){let a=n.get(i.rowId)??{minX:i.x,minY:i.y,maxX:i.x,maxY:i.y};a.minX=Math.min(a.minX,i.x),a.minY=Math.min(a.minY,i.y),a.maxX=Math.max(a.maxX,i.x),a.maxY=Math.max(a.maxY,i.y),n.set(i.rowId,a)}for(let i of this.doc?(0,S.floorsOf)(this.doc).flatMap(a=>a.objects):[]){if(i.type!=="row"||!(i.displayLabel??i.label).toLocaleLowerCase().includes(t))continue;let a=n.get(i.id);if(!a)continue;let{minX:l,minY:r,maxX:c,maxY:d}=a;if(s.push({label:i.displayLabel??i.label,detail:"Row",locate:()=>{let h=this.sectionByObject.get(i.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 i of this.labelToSeat.values())if(i.label.toLocaleLowerCase().includes(t)&&(s.push({label:i.label,detail:"Seat",locate:()=>{let a=this.sectionByObject.get(i.rowId);a&&this.renderer?.focusSection(a),this.renderer?.focusRegion({x:i.x-180,y:i.y-120,width:360,height:240},{animate:!1,minScale:1.5}),this.renderer?.flashSeat(i.id,this.activityColor(this.status.get(i.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(d=>d.id)),s=this.filterableSections().filter(d=>!t.has(d.id)).map(d=>d.id);this.renderer.clearSectionFocus(),this.renderer.setClosedSections(null),this.renderer.setDimmedSections(s);let n=e.flatMap(d=>d.seatLabels).map(d=>this.labelToSeat.get(d)).filter(d=>!!d&&Number.isFinite(d.x)&&Number.isFinite(d.y));if(!n.length){this.renderer.focusRegion(e[0].id);return}let i=Math.min(...n.map(d=>d.x)),a=Math.min(...n.map(d=>d.y)),l=Math.max(...n.map(d=>d.x)),r=Math.max(...n.map(d=>d.y)),c=Math.max(40,Math.max(l-i,r-a)*.08);this.renderer.focusRegion({x:i-c,y:a-c,width:Math.max(1,l-i)+c*2,height:Math.max(1,r-a)+c*2})}buildSectionOptions(){if(this.doc)try{let e=(0,S.computeSections)(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:S.UNGROUPED_ID,label:e.ungrouped.label}),this.sectionLabelById.set(S.UNGROUPED_ID,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?(0,S.floorsOf)(this.doc):[]).flatMap(e=>e.objects).filter(e=>e.type==="table")}paintModeTabs(){let e=[];this.els.modes?.querySelectorAll(".slm-modegroup").forEach(s=>{let n=[];s.querySelectorAll("[data-mode]").forEach(i=>{let a=i.dataset.mode,l=this.toolAvailable(a);if(i.hidden=!l,!l)return;n.push({mode:a,label:i.textContent??a});let r=a===this.mode;i.classList.toggle("on",r),i.setAttribute("aria-selected",String(r)),i.tabIndex=r?0:-1}),s.hidden=n.length===0,n.length&&e.push({label:s.querySelector(".slm-modegroup-label")?.textContent??"",tools:n})});let t=this.els.tools;t&&(t.innerHTML=e.map(s=>`<optgroup label="${b(s.label)}">${s.tools.map(n=>`<option value="${n.mode}"${n.mode===this.mode?" selected":""}>${b(n.label)}</option>`).join("")}</optgroup>`).join(""),t.value=this.mode),this.root?.classList.toggle("block-mode",this.mode==="block")}railHeader(e,t,s){let n=t==="read"?"Read-only":t==="event"?"This event only":"Your app";return`<div class="slm-railhead"><p class="slm-eyebrow">${b(e)}</p><span class="slm-scope ${t}">${n}</span></div>
|
|
1481
|
+
<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 i=this.controlRoomSnapshot?.velocity.bySection.some(a=>a.netBooked>0);e.textContent=this.controlRoomSnapshot?i?`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 n=this.controlRoomSnapshot?.velocity.bySection.some(i=>i.netBooked>0);s.textContent=n?"Warmer sections have more completed bookings, adjusted for section size. Holds and viewers are not counted.":`No completed bookings in the last ${this.trendWindowMinutes} minutes.`}paintFullscreenButton(){this.els.fullscreen&&(this.els.fullscreen.textContent=this.isFullscreen()?"Exit full screen":"Full screen")}paintTrendWindow(){this.els.rail?.querySelectorAll("[data-window]").forEach(e=>{let t=Number(e.dataset.window);e.classList.toggle("on",t===this.trendWindowMinutes)})}setLive(e){this.root?.classList.toggle("live",e),this.els.livetext&&(this.els.livetext.textContent=e?"LIVE":"RECONNECTING"),this.paintMonitorInsights();let t=e?"live":this.sessionEnded?"ended":"reconnecting";if(this.els.livetext&&!e&&this.sessionEnded&&(this.els.livetext.textContent="ENDED"),t!==this.connectionStatus){this.connectionStatus=t;try{this.opts.onConnectionChange?.(this.getConnection())}catch(s){this.opts.onError?.(s)}}}updateZoomHint(){let e=this.els.zoomhint;if(!e)return;let t=this.isBulkSelectMode()&&!this.movingMap&&this.renderer?.getRung?.()!=="seats";e.classList.toggle("on",!!t)}formatKpiDelta(e,t,s){let n=t>0?"+":"\u2212",i=Math.abs(t);return e==="booked-value"?`${n}${fe(i,s)}`:e==="booked-pct"?`${n}${i.toLocaleString()}pt`:`${n}${i.toLocaleString()}`}paintKpis(e){if(!this.els.kpis)return;let t=e.bookedValueStatus==="current"?fe(e.bookedValue,e.currency):"\u2014",s=this.presenceCounts(),n=[{key:"booked-inventory",raw:e.booked,n:e.booked.toLocaleString(),l:"Booked inventory",dot:H.booked,title:"Inventory units booked"},{key:"held-seats",raw:e.held,n:e.held.toLocaleString(),l:"Held inventory",dot:H.held,title:"Inventory currently held"},{key:"free-seats",raw:e.free,n:e.free.toLocaleString(),l:"Available",dot:H.free,title:"Inventory available to book"},{key:"blocked",raw:e.blocked,n:e.blocked.toLocaleString(),l:"Blocked",dot:H.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"}],i=!1;this.els.kpis.innerHTML=n.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&&(i=!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="${b(a.title)}">
|
|
1279
1482
|
<b>${a.dot?`<span class="dot" style="background:${a.dot}"></span>`:""}${a.n}</b><span>${a.l}</span>
|
|
1280
|
-
${
|
|
1483
|
+
${d?`<span class="slm-kpidelta${d.down?" down":""}">${d.text}</span>`:""}
|
|
1281
1484
|
</div>`}).join(""),i&&(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=`
|
|
1282
1485
|
<div class="slm-monitor-head"><h2>Live activity</h2><span data-ref="presence" class="slm-monitor-connection"></span></div>
|
|
1283
1486
|
<div class="slm-monitor-tabs" role="tablist" aria-label="Monitor details">
|
|
@@ -1297,88 +1500,70 @@
|
|
|
1297
1500
|
</div>
|
|
1298
1501
|
<div class="slm-sectionlist" data-ref="sections"></div>
|
|
1299
1502
|
</div>
|
|
1300
|
-
`,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
|
|
1301
|
-
<span class="slm-sectiontop"><span>${b(n.sectionLabel)}</span><span title="Configured value of currently booked inventory">${
|
|
1302
|
-
<span class="slm-sectionmeta"><span>${n.booked.toLocaleString()}/${n.total.toLocaleString()} booked \xB7 ${
|
|
1303
|
-
</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})),n=Math.max(0,...s.map(a=>a.rate)),i={};for(let a of s)i[a.sectionId]=n>0?Math.sqrt(a.rate/n):0;this.renderer?.setSectionHeat(i)}renderSelectRail(){let e=this.
|
|
1503
|
+
`,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 de(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 n=this.root?.classList.contains("live"),i=this.lastSyncedAt?Et(this.lastSyncedAt,Date.now()):"waiting";this.els.presence.textContent=n?"\u25CF Live":"Reconnecting",this.els.presence.title=`Last data received: ${i}`}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(n=>[n.sectionId,n])),s=[...e.bookedValue.bySection].sort((n,i)=>{let a=t.get(n.sectionId)?.netBooked??0;return(t.get(i.sectionId)?.netBooked??0)-a||i.bookedValue-n.bookedValue});this.els.sections.innerHTML=s.length?s.map(n=>{let i=t.get(n.sectionId),a=i?.netBooked??0,l=`${a>0?"+":""}${a}`,r=i?.trend==="rising"||i?.trend==="cooling"?i.trend:"steady";return`<button type="button" class="slm-sectionrow" data-section-focus="${b(n.sectionId)}" title="Focus ${b(n.sectionLabel)} on the map">
|
|
1504
|
+
<span class="slm-sectiontop"><span>${b(n.sectionLabel)}</span><span title="Configured value of currently booked inventory">${fe(n.bookedValue,e.currency)}</span></span>
|
|
1505
|
+
<span class="slm-sectionmeta"><span>${n.booked.toLocaleString()}/${n.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>
|
|
1506
|
+
</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})),n=Math.max(0,...s.map(a=>a.rate)),i={};for(let a of s)i[a.sectionId]=n>0?Math.sqrt(a.rate/n):0;this.renderer?.setSectionHeat(i)}renderSelectRail(){let e=this.opts.numberOfPlacesToSelect,t=this.selectionCap(),s=this.toolChooser();this.els.rail.innerHTML=`
|
|
1304
1507
|
${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.")}
|
|
1305
|
-
<
|
|
1306
|
-
<p class="slm-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
</div>
|
|
1311
|
-
${e.length?`<p class="slm-eyebrow" style="margin-top:8px">Select by category</p>
|
|
1312
|
-
<div class="slm-chipgrid">${e.map(n=>`
|
|
1313
|
-
<button class="slm-chip" type="button" data-select-cat="${b(n.key)}" aria-pressed="false">
|
|
1314
|
-
<span class="dot" style="background:${b(n.color??"#6e7bff")}"></span>
|
|
1315
|
-
<span>${b(n.label??n.key)}</span>
|
|
1316
|
-
<span class="slm-chipcount" data-cat-count>0</span>
|
|
1317
|
-
<span class="slm-chipcheck" aria-hidden="true">\u2713</span>
|
|
1318
|
-
</button>`).join("")}</div>`:""}`,this.els.selectnum=this.els.rail.querySelector('[data-ref="selectnum"]'),this.els.selectmeta=this.els.rail.querySelector('[data-ref="selectmeta"]'),this.els.selectvalidity=this.els.rail.querySelector('[data-ref="selectvalidity"]'),this.els.selectclear=this.els.rail.querySelector('[data-ref="selectclear"]'),this.els.rail.querySelector('[data-ref="selectall"]')?.addEventListener("click",()=>this.selectAll()),this.els.selectclear.addEventListener("click",()=>this.clearSelection()),this.els.rail.querySelectorAll("[data-select-cat]").forEach(n=>{n.addEventListener("click",()=>{let i=n.dataset.selectCat,a=[...this.labelToSeat.values()].filter(r=>r.categoryKey===i&&this.canSelectObject(r)),o=new Set(this.selectionLabels());a.length>0&&a.every(r=>o.has(r.label))?this.deselectCategories([i]):this.selectCategories([i])})}),this.paintSelectSelection(this.getSelection())}paintSelectSelection(e){if(!this.els.selectnum||!this.els.selectmeta)return;let t=e.length;this.els.selectnum.textContent=t.toLocaleString(),this.els.selectmeta.textContent=t===1?"object selected":"objects selected",this.els.selectclear.disabled=t===0;let s=this.getSelectionValidity();this.els.selectvalidity&&(this.els.selectvalidity.textContent=s?s.isValid?`Ready \u2014 exactly ${s.required.toLocaleString()} selected.`:`Select ${s.remaining.toLocaleString()} more to continue.`:`${Math.max(0,this.selectionCap()-t).toLocaleString()} selections remaining.`);let n=new Set(e.map(i=>i.label));this.els.rail?.querySelectorAll("[data-select-cat]").forEach(i=>{let a=i.dataset.selectCat,o=[...this.labelToSeat.values()].filter(h=>h.categoryKey===a&&this.canSelectObject(h)),r=o.filter(h=>n.has(h.label)).length,d=o.length>0&&r===o.length;i.classList.toggle("on",d),i.setAttribute("aria-pressed",String(d));let c=i.querySelector("[data-cat-count]");c&&(c.textContent=r?`${r}/${o.length}`:o.length.toLocaleString()),i.disabled=o.length===0})}renderFilterSectionsRail(){let e=new Map;for(let t of this.filterableSections())e.set(t.label,[...e.get(t.label)??[],t]);this.els.rail.innerHTML=`
|
|
1508
|
+
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
1509
|
+
<p class="slm-selecthelp">Tap seats on the map, tap a row label for the whole row, press \u2318A for all, or pick a category, section or rows below.</p>
|
|
1510
|
+
${s.chipsHtml()}
|
|
1511
|
+
${this.toolSelectionBar("selectnum","selectmeta","selectclear","selectall")}
|
|
1512
|
+
<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=`
|
|
1319
1513
|
${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.")}
|
|
1320
|
-
${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let n=t===this.filteredSectionLabel,i=s.reduce((a,
|
|
1514
|
+
${e.size?`<div class="slm-sectionlist">${[...e].map(([t,s])=>{let n=t===this.filteredSectionLabel,i=s.reduce((a,l)=>a+l.seatCount,0);return`<button type="button" class="slm-sectionrow${n?" on":""}" data-filter-section="${b(t)}" aria-pressed="${n}">
|
|
1321
1515
|
<span class="slm-sectiontop"><span>${b(t)}</span><span>${i.toLocaleString()}</span></span>
|
|
1322
1516
|
<span class="slm-sectionmeta"><span>${s.length===1?"One section":`${s.length.toLocaleString()} matching sections`}</span><span class="slm-sectionlocate">${n?"Filtered":"Filter"}</span></span>
|
|
1323
1517
|
</button>`}).join("")}</div>
|
|
1324
|
-
<button type="button" class="slm-btn ghost" data-clear-filter ${this.filteredSectionLabel?"":"disabled"}>Clear filter</button>`:'<div class="slm-empty">This chart has no filterable sections.</div>'}`,this.els.rail.querySelectorAll("[data-filter-section]").forEach(t=>{t.addEventListener("click",()=>this.setFilteredSection(t.dataset.filterSection))}),this.els.rail.querySelector("[data-clear-filter]")?.addEventListener("click",()=>this.clearFilteredSection())}categorySeats(e){return[...this.labelToSeat.values()].filter(t=>t.categoryKey===e&&this.canSelectObject(t))}renderCategoriesRail(){let e=this.doc?.categories??[];this.els.rail.innerHTML=`
|
|
1518
|
+
<button type="button" class="slm-btn ghost" data-clear-filter ${this.filteredSectionLabel?"":"disabled"}>Clear filter</button>`:'<div class="slm-empty">This chart has no filterable sections.</div>'}`,this.els.rail.querySelectorAll("[data-filter-section]").forEach(t=>{t.addEventListener("click",()=>this.setFilteredSection(t.dataset.filterSection))}),this.els.rail.querySelector("[data-clear-filter]")?.addEventListener("click",()=>this.clearFilteredSection())}categorySeats(e){return[...this.labelToSeat.values()].filter(t=>t.categoryKey===e&&this.canSelectObject(t))}renderCategoriesRail(){let e=this.doc?.categories??[],t=this.toolChooser();this.els.rail.innerHTML=`
|
|
1325
1519
|
${this.railHeader("Categories","event","Move seats to a different price category for this event only. The reusable chart keeps its design, and seats already held or booked keep the price they were sold at.")}
|
|
1326
1520
|
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
1327
|
-
<p class="slm-selecthelp">Click
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
<span class="dot" style="background:${b(s.color??"#6e7bff")}"></span>
|
|
1331
|
-
<span>${b(s.label??s.key)}</span>
|
|
1332
|
-
<span class="slm-chipcount" data-cat-count>0</span>
|
|
1333
|
-
<span class="slm-chipcheck" aria-hidden="true">\u2713</span>
|
|
1334
|
-
</button>`).join(""):'<span class="slm-empty">This chart has no categories.</span>'}</div>
|
|
1335
|
-
<div class="slm-selbar" aria-live="polite">
|
|
1336
|
-
<span class="slm-selnum" data-ref="categorynum">0</span>
|
|
1337
|
-
<span class="slm-sellabel" data-ref="categorymeta">selected</span>
|
|
1338
|
-
</div>
|
|
1339
|
-
<div class="slm-row">
|
|
1340
|
-
<button class="slm-btn ghost" data-ref="categoryall">Select all</button>
|
|
1341
|
-
<button class="slm-btn ghost" data-ref="categoryclear" disabled>Clear</button>
|
|
1342
|
-
</div>
|
|
1521
|
+
<p class="slm-selecthelp">Click seats, drag a box or draw a lasso on the map, tap a row label for the whole row, press \u2318A for all, or pick below.</p>
|
|
1522
|
+
${t.chipsHtml({intents:this.marqueeShapeChipsHtml()})}
|
|
1523
|
+
${this.toolSelectionBar("categorynum","categorymeta","categoryclear","categoryall")}
|
|
1343
1524
|
<p class="slm-eyebrow slm-step" style="margin-top:14px"><span class="slm-stepnum">2</span>Move them to</p>
|
|
1344
1525
|
<p class="slm-selecthelp" data-ref="categoryhelp">Select seats first \u2014 then pick the category they should sell under.</p>
|
|
1345
|
-
<div class="slm-categoryassign">${e.map(
|
|
1346
|
-
<button type="button" class="slm-categoryrow" data-assign-category="${b(
|
|
1347
|
-
<span class="dot" style="background:${b(
|
|
1348
|
-
<span class="slm-categorycopy"><b>${b(
|
|
1526
|
+
<div class="slm-categoryassign">${e.length?e.map(n=>`
|
|
1527
|
+
<button type="button" class="slm-categoryrow" data-assign-category="${b(n.key)}" disabled>
|
|
1528
|
+
<span class="dot" style="background:${b(n.color??"#6e7bff")}"></span>
|
|
1529
|
+
<span class="slm-categorycopy"><b>${b(n.label??n.key)}</b><small data-cat-current>0 seats now</small></span>
|
|
1349
1530
|
<span class="slm-categoryact" data-cat-action>Move here</span>
|
|
1350
|
-
</button>`).join("")
|
|
1531
|
+
</button>`).join(""):'<span class="slm-empty">This chart has no categories.</span>'}</div>
|
|
1532
|
+
<div class="slm-catreset">
|
|
1533
|
+
<button type="button" class="slm-btn ghost" data-ref="categoryreset" disabled>Reset to chart defaults</button>
|
|
1534
|
+
<p class="slm-note" data-ref="categoryresetnote">Checking what differs from the chart\u2026</p>
|
|
1535
|
+
</div>`;let s=n=>this.els.rail.querySelector(`[data-ref="${n}"]`);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(n=>{n.addEventListener("click",()=>{this.setCategory(n.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 n=await this.withAuthRetry(()=>this.api.categoryDifferences(this.key));if(!t.isConnected)return;this.categoryDifferences=n.differing,this.paintCategoryReset()}catch(n){if(!t.isConnected)return;s.textContent="Could not check the chart\u2019s defaults. Reset is unavailable until it can.",this.opts.onError?.(n)}}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 n=this.categoryDifferences;n!=null&&(t.disabled=n===0,t.textContent=n?`Reset to chart defaults \xB7 ${n.toLocaleString()} seat${n===1?"":"s"}`:"Reset to chart defaults",s.textContent=n?"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 i of e)s.set(i.categoryKey,(s.get(i.categoryKey)??0)+1);let n=i=>this.doc?.categories.find(a=>a.key===i)?.label??i;this.els.categorymeta&&(this.els.categorymeta.textContent=t===0?"selected":`${t===1?"seat":"seats"} selected \xB7 ${[...s].map(([i,a])=>`${a.toLocaleString()} ${n(i)}`).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(i=>{let a=i.dataset.assignCategory,l=[...this.labelToSeat.values()].filter(f=>f.categoryKey===a).length,r=s.get(a)??0,c=t>0&&r===t;i.disabled=t===0||c,i.classList.toggle("current",c);let d=i.querySelector("[data-cat-current]");d&&(d.textContent=`${l.toLocaleString()} ${l===1?"seat":"seats"} now`);let h=i.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=`
|
|
1351
1536
|
${this.railHeader("Tables","event",t)}
|
|
1352
1537
|
<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=`
|
|
1353
1538
|
${this.railHeader("Tables","event",t)}
|
|
1354
|
-
<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",n=h=>{let
|
|
1539
|
+
<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",n=h=>{let f=0,m=0,p=0;for(let[y,g]of this.labelToSeat){if(g.rowId!==h.id)continue;let C=this.status.get(y);C==="held"?f++:C==="booked"?m++:C==="blocked"&&p++}let v=[m&&`${m} booked`,f&&`${f} held`,p&&`${p} blocked`].filter(Boolean);return v.length?v.join(" \xB7 "):null},i=e.map(h=>({table:h,current:s(h),locked:n(h)})),a=i.filter(h=>h.current==="individual").length,l=i.filter(h=>h.current==="whole").length,r=i.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=`
|
|
1355
1540
|
${this.railHeader("Tables","event",t)}
|
|
1356
|
-
<div class="slm-tablesummary"><b>${i.length.toLocaleString()} ${i.length===1?"table":"tables"}</b><span>${b(
|
|
1541
|
+
<div class="slm-tablesummary"><b>${i.length.toLocaleString()} ${i.length===1?"table":"tables"}</b><span>${b(c)}</span></div>
|
|
1357
1542
|
<p class="slm-eyebrow" style="margin-top:12px">Set every table at once</p>
|
|
1358
1543
|
<div class="slm-row">
|
|
1359
|
-
<button class="slm-btn ghost" data-table-all="individual"${
|
|
1360
|
-
<button class="slm-btn ghost" data-table-all="whole"${
|
|
1544
|
+
<button class="slm-btn ghost" data-table-all="individual"${d?" disabled":""} title="Sell every chair on its own">All per chair</button>
|
|
1545
|
+
<button class="slm-btn ghost" data-table-all="whole"${d?" disabled":""} title="Sell every table as one booking">All whole table</button>
|
|
1361
1546
|
</div>
|
|
1362
1547
|
<p class="slm-eyebrow" style="margin-top:12px">Or one table at a time</p>
|
|
1363
|
-
<div class="slm-tablelist">${i.map(({table:h,current:
|
|
1364
|
-
<span class="slm-tablecopy"><b>${b(h.displayLabel??h.label)}</b><small>${h.seatCount.toLocaleString()} chairs${
|
|
1548
|
+
<div class="slm-tablelist">${i.map(({table:h,current:f,locked:m})=>`<div class="slm-tablerow${m?" locked":""}">
|
|
1549
|
+
<span class="slm-tablecopy"><b>${b(h.displayLabel??h.label)}</b><small>${h.seatCount.toLocaleString()} chairs${m?` \xB7 <span class="slm-tablelock">Locked: ${b(m)}</span>`:""}</small></span>
|
|
1365
1550
|
<select class="slm-select" data-table-mode="${b(h.id)}" aria-label="Booking mode for ${b(h.displayLabel??h.label)}"
|
|
1366
|
-
${
|
|
1367
|
-
<option value="individual"${
|
|
1368
|
-
<option value="whole"${
|
|
1369
|
-
${
|
|
1551
|
+
${d||m?"disabled":""} ${m?`title="Release the ${b(m)} chairs before changing how this table sells"`:""}>
|
|
1552
|
+
<option value="individual"${f==="individual"?" selected":""}>Per chair</option>
|
|
1553
|
+
<option value="whole"${f==="whole"?" selected":""}>Whole table</option>
|
|
1554
|
+
${f==="variable"?'<option value="variable" selected>Flexible group</option>':""}
|
|
1370
1555
|
</select>
|
|
1371
1556
|
</div>`).join("")}</div>
|
|
1372
|
-
<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(i.filter(
|
|
1557
|
+
<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(i.filter(f=>!f.locked).map(f=>f.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=`
|
|
1373
1558
|
${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.")}
|
|
1374
|
-
<div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",n={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},i=this.sectionByObject.get(t.rowId)??
|
|
1559
|
+
<div class="slm-empty">Select a seat on the map.</div>`;return}let s=this.status.get(t.label)??"free",n={free:"Free",held:"Held",booked:"Booked",blocked:"Blocked"},i=this.sectionByObject.get(t.rowId)??S.UNGROUPED_ID,a=this.sectionLabelById.get(i)??"Other seats",l=this.doc?.categories.find(c=>c.key===t.categoryKey);this.els.rail.innerHTML=`
|
|
1375
1560
|
<div class="slm-seat-heading"><h2>${b(t.label)}</h2><span data-seat-status>${n[s]}</span></div>
|
|
1376
|
-
<p class="slm-note">${b(a)} \xB7 ${b(
|
|
1377
|
-
<div data-ref="seat-history"></div>`;let r=this.els.rail.querySelector('[data-ref="seat-history"]');this.seatHistoryPanel=new
|
|
1561
|
+
<p class="slm-note">${b(a)} \xB7 ${b(l?.label??t.categoryKey)}</p>
|
|
1562
|
+
<div data-ref="seat-history"></div>`;let r=this.els.rail.querySelector('[data-ref="seat-history"]');this.seatHistoryPanel=new ce(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(Xe(this.availabilityRules)),this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment()}catch(e){this.opts.onError?.(e)}}async withAuthRetry(e){try{return await e()}catch(t){if(t instanceof w&&t.status===401&&this.opts.onTokenRefresh&&!this.tokenRefreshInFlight){if(await this.rotateToken(),this.sessionEnded)throw t;return e()}throw t instanceof w&&t.status===401&&!this.opts.onTokenRefresh&&this.endSession(),t}}updateEffectiveAvailability(e,t){let s=!1;Array.isArray(e)&&(this.effectiveHidden=new Set(e.filter(n=>typeof n=="string")),s=!0),Array.isArray(t)&&(this.effectiveClosed=new Set(t.filter(n=>typeof n=="string")),s=!0),s&&(this.mode==="sections"&&this.renderSectionsRail(),this.applySectionCanvasTreatment())}applySectionCanvasTreatment(){this.renderer&&(this.renderer.refreshBlockPaint?.(),this.mode==="sections"?(this.renderer.setDimmedSections([...this.effectiveHidden]),this.renderer.setClosedSections([...this.effectiveClosed])):this.mode==="filterSections"&&this.filteredSectionLabel?this.applyFilteredSectionCanvas():(this.renderer.setDimmedSections(null),this.renderer.setClosedSections(null)))}sectionRowsInput(){return{sectionsBase:this.sectionsBase,doc:this.doc,availabilityRules:this.availabilityRules,effectiveHidden:this.effectiveHidden,effectiveClosed:this.effectiveClosed}}renderSectionsRail(){let{rows:e,hiddenSections:t,closedSections:s}=we(this.sectionRowsInput());if(!e.length){this.els.rail.innerHTML=`
|
|
1378
1563
|
${this.railHeader("Sections","event","Draw sections or zones in the designer to schedule availability per area. This chart has none yet.")}
|
|
1379
1564
|
<div class="slm-empty">No sections on this chart.</div>`;return}let n=[];t&&n.push(`${t} hidden`),s&&n.push(`${s} closed`);let i=n.length?n.join(" \xB7 "):"All sections open and on sale",a=t>0||s>0;this.els.rail.innerHTML=`
|
|
1380
1565
|
${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.")}
|
|
1381
|
-
<div class="slm-availlist" data-ref="availlist">${e.map(
|
|
1566
|
+
<div class="slm-availlist" data-ref="availlist">${e.map(l=>Zt(l,this.availabilitySaving)).join("")}</div>
|
|
1382
1567
|
<div class="slm-availsummary">
|
|
1383
1568
|
<span class="slm-availdot${a?" warn":""}"></span>
|
|
1384
1569
|
<span>${b(i)}</span>
|
|
@@ -1386,31 +1571,22 @@
|
|
|
1386
1571
|
<div class="slm-availcallout">
|
|
1387
1572
|
<span class="slm-availstar" aria-hidden="true">\u2726</span>
|
|
1388
1573
|
<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>
|
|
1389
|
-
</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(n=>{n!==t&&(n.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 n=[...t.querySelectorAll("button")],i=n.indexOf(document.activeElement);n[(i+(s.key==="ArrowDown"?1:n.length-1)+n.length)%n.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=
|
|
1390
|
-
<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
|
|
1391
|
-
<span class="dot" style="background:${b(c.color??"#6e7bff")}"></span>
|
|
1392
|
-
<span>${b(c.label??c.key)}</span>
|
|
1393
|
-
<span class="slm-chipcount" data-cat-count>0</span>
|
|
1394
|
-
<span class="slm-chipcheck" aria-hidden="true">\u2713</span>
|
|
1395
|
-
</button>`).join(""),s=this.sectionOptions.length?`<div class="slm-field"><label>Select a whole section</label>
|
|
1396
|
-
<select class="slm-select" data-ref="section"><option value="">Choose a section\u2026</option>
|
|
1397
|
-
${this.sectionOptions.map(c=>`<option value="${b(c.id)}">${b(c.label)}</option>`).join("")}</select></div>`:"",n=this.sectionOptions.map(c=>`<option value="${b(c.id)}">${b(c.label)}</option>`).join("");this.els.rail.innerHTML=`
|
|
1574
|
+
</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(n=>{n!==t&&(n.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 n=[...t.querySelectorAll("button")],i=n.indexOf(document.activeElement);n[(i+(s.key==="ArrowDown"?1:n.length-1)+n.length)%n.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=we(this.sectionRowsInput()).rows.find(l=>l.id===e),n=s?.seatLabels??this.availabilityRules[e]?.labels??[],i={...this.availabilityRules},a=kt(t,n,this.availabilityRules[e]);if(a?i[e]=a:delete i[e],s?.kind==="zone"&&this.sectionsBase)for(let l of this.sectionsBase.sections)l.zone===e&&delete i[l.id];this.persistAvailability(i)}setSectionRulePatch(e,t){let s=this.availabilityRules[e];if(!s)return;let i=we(this.sectionRowsInput()).rows.find(a=>a.id===e)?.seatLabels??s.labels??[];this.persistAvailability({...this.availabilityRules,[e]:{...s,...t,labels:i}})}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(Xe(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=Ct.map(t=>`<div class="slm-legrow"><span class="slm-legdot" style="background:${t.color}"></span>
|
|
1575
|
+
<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="${b(l.id)}">${b(l.label)}</option>`).join("");this.els.rail.innerHTML=`
|
|
1398
1576
|
<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>
|
|
1399
|
-
<p class="slm-note">${
|
|
1400
|
-
<div
|
|
1577
|
+
<p class="slm-note">${Lt}</p>
|
|
1578
|
+
<div data-block-editor ${this.blockBrowse?"hidden":""}>
|
|
1579
|
+
<p class="slm-eyebrow slm-step"><span class="slm-stepnum">1</span>Choose seats</p>
|
|
1580
|
+
<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>
|
|
1581
|
+
${e.chipsHtml({intents:this.marqueeShapeChipsHtml()})}
|
|
1582
|
+
</div>
|
|
1583
|
+
${this.toolSelectionBar("selnum","selmeta","clearsel","selall")}
|
|
1584
|
+
<p class="slm-eyebrow slm-step" data-block-editor-step ${this.blockBrowse?"hidden":""}><span class="slm-stepnum">2</span>Then</p>
|
|
1401
1585
|
<div class="slm-row">
|
|
1402
1586
|
<button class="slm-btn" data-ref="doblock" disabled>Block</button>
|
|
1403
1587
|
<button class="slm-btn ghost" data-ref="dounblock" disabled>Put back on sale</button>
|
|
1404
1588
|
</div>
|
|
1405
1589
|
<div data-block-editor ${this.blockBrowse?"hidden":""}>
|
|
1406
|
-
<div class="slm-row">
|
|
1407
|
-
<button class="slm-btn ghost" data-ref="selall">Select all</button>
|
|
1408
|
-
<button class="slm-btn ghost" data-ref="clearsel">Clear</button>
|
|
1409
|
-
</div>
|
|
1410
|
-
<p class="slm-eyebrow" style="margin-top:8px">Select by category</p>
|
|
1411
|
-
<p class="slm-selecthelp">Choose one or more. A checked category is selected; click it again to remove it.</p>
|
|
1412
|
-
<div class="slm-chiprow">${t||'<span class="slm-empty">No categories.</span>'}</div>
|
|
1413
|
-
${s}
|
|
1414
1590
|
<div class="slm-field">
|
|
1415
1591
|
<label>Auto-release blocks at (optional)</label>
|
|
1416
1592
|
<input type="datetime-local" class="slm-input" data-ref="release" />
|
|
@@ -1426,7 +1602,7 @@
|
|
|
1426
1602
|
<div class="slm-blockedtools">
|
|
1427
1603
|
<input type="search" class="slm-input" data-ref="blockedsearch" placeholder="Find seat, row or category" aria-label="Search blocked seats" />
|
|
1428
1604
|
<select class="slm-select" data-ref="blockedsection" aria-label="Filter blocked seats by section">
|
|
1429
|
-
<option value="">All sections</option>${
|
|
1605
|
+
<option value="">All sections</option>${t}
|
|
1430
1606
|
</select>
|
|
1431
1607
|
</div>
|
|
1432
1608
|
<div class="slm-blockedsummary">
|
|
@@ -1439,5 +1615,5 @@
|
|
|
1439
1615
|
<button class="slm-btn ghost" data-ref="markall" style="width:100%" disabled>Put all blocked seats on sale</button>
|
|
1440
1616
|
<p class="slm-note slm-allnote" data-ref="markallnote">For a full reset only. You will be asked to confirm.</p>
|
|
1441
1617
|
</div></details>
|
|
1442
|
-
`,this.els.rail.querySelectorAll("[data-block-tab]").forEach(
|
|
1443
|
-
<details><summary>Choose seats</summary>${
|
|
1618
|
+
`,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 n=s("blockedsearch"),i=s("blockedsection");n.value=this.blockedQuery,i.value=this.blockedSection,n.addEventListener("input",()=>{this.blockedQuery=n.value,this.blockedResultLimit=100,this.paintBlockedInventory()}),i.addEventListener("change",()=>{this.blockedSection=i.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 m=this.labelToSeat.get(c.dataset.blockSeatFind);m&&(this.setFollowLive(!1),this.focusActivitySeats([m.label],this.sectionByObject.get(m.rowId)??S.UNGROUPED_ID));return}let d=r.closest("[data-block-locate]"),h=r.closest("[data-block-group]");if(d||h){let m=d?.dataset.blockLocate??h?.dataset.blockGroup,p=this.filteredBlockedSeats().filter(v=>v.rowId===m);d&&p.length&&(this.setFollowLive(!1),this.focusActivitySeats(p.map(v=>v.label),this.sectionByObject.get(p[0].rowId)??S.UNGROUPED_ID)),h&&this.toggleLabels(p.map(v=>v.label));return}let f=r.closest("[data-blocked-label]");f?.dataset.blockedLabel?this.toggleLabels([f.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(i=>this.labelToSeat.has(i)&&this.isBlockSelectable(i));if(!t.length)return;let s=new Set(this.selectionLabels());if(t.every(i=>s.has(i))){let i=t.map(a=>this.labelToId.get(a)).filter(a=>!!a);this.renderer.deselect(i)}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 n=this.els.doblock,i=this.els.dounblock;n.disabled=t===0,i.disabled=s===0,n.textContent=t?`Block ${t.toLocaleString()}`:"Block selected",i.textContent=s?`Put ${s.toLocaleString()} on sale`:"Put back on sale",this.paintBlockedInventory()}filteredBlockedSeats(){let e=this.blockedQuery.trim().toLocaleLowerCase(),t=[];for(let[s,n]of this.labelToSeat.entries()){if(this.status.get(s)!=="blocked")continue;let i=this.sectionByObject.get(n.rowId)??S.UNGROUPED_ID;if(!(this.blockedSection&&i!==this.blockedSection)){if(e){let a=this.doc?.categories.find(h=>h.key===n.categoryKey)?.label??n.categoryKey,l=this.sectionLabelById.get(i)??"Other seats",r=this.doc?.objects.find(h=>h.id===n.rowId),c=r?.type==="row"||r?.type==="table"?r.label:"";if(!`${s} ${a} ${l} ${c}`.toLocaleLowerCase().includes(e))continue}t.push(n)}}return t.sort((s,n)=>s.label.localeCompare(n.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),n=new Set(this.selectionLabels()),i=t.filter(h=>n.has(h.label)).length,a=t.length>0&&i===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 f=r.get(h.rowId)??[];f.push(h),r.set(h.rowId,f)}this.els.blockedshowing.textContent=`${t.length.toLocaleString()} seats \xB7 ${r.size} rows`,this.els.blockedlist.innerHTML=[...r.entries()].slice(0,this.blockedResultLimit).map(([h,f])=>{let m=this.sectionByObject.get(h)??S.UNGROUPED_ID,p=this.sectionLabelById.get(m)??"Other seats",v=this.doc?.objects.find(g=>g.id===h),y=v&&"label"in v?v.label:f[0].label;return`<div class="slm-block-group"><div class="slm-block-grouphead"><button type="button" data-block-locate="${b(h)}" title="Show this row and nearby seats on the map"><b>${b(y)}</b><small>${b(p)} \xB7 ${f.length} blocked</small></button><button type="button" data-block-group="${b(h)}">Select row</button></div>
|
|
1619
|
+
<details><summary>Choose seats</summary>${f.map(g=>`<div class="slm-block-seatline"><button type="button" class="slm-blockeditem${n.has(g.label)?" on":""}" data-blocked-label="${b(g.label)}" aria-pressed="${n.has(g.label)}"><span class="slm-blockedcheck" aria-hidden="true">\u2713</span><span>${b(g.label)}</span></button><button type="button" data-block-seat-find="${b(g.label)}" aria-label="Show ${b(g.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 n=e==="block"?this.pushActivity(t,"blocked","blocked"):e==="unblock"||e==="unblockAll"?this.pushActivity(t,"unblocked","free"):e==="cancelBooking"?this.pushActivity(t,"cancelled","free"):null;n&&this.paintSpatialActivity(n)}e!=="setHoldTtl"&&this.refreshControlRoom().catch(n=>this.opts.onError?.(n)),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>`)}};tt();Oe();pe();0&&(module.exports={ACCESS_LINK_DEFAULTS,ChannelsMode,ManageApi,ManageApiError,PUBLIC_CHANNEL_ID,PUBLIC_CHANNEL_NAME,SeatManager,accessIntentDescription,accessIntentLabel,accessLine,accessLinkBadge,accessLinkErrorCopy,accessLinkIsLive,accessLinkPolicyLines,bucketRows,bucketRowsHtml,dropReviewRows,intentForbidsCopy,intentSwitchBlockedCopy,isPublicChannelId,markerLetter,markerOf,mutationCount,needsMoveConfirmation,planAssignment,retryAfterCopy,selectionSources,stateBadge,suggestMarker});
|