@seatlayer/js 0.92.5 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/{channelsMode-B41tbE29.d.cts → channelsMode-DYwJ6sfR.d.cts} +200 -27
- package/dist/{channelsMode-B41tbE29.d.ts → channelsMode-DYwJ6sfR.d.ts} +200 -27
- package/dist/channelsMode-YJO6FOPD.js +1 -0
- package/dist/{chunk-5VGXB6GJ.js → chunk-DR5JXWLO.js} +208 -228
- package/dist/chunk-JELR6YYZ.js +1 -0
- package/dist/hostedCheckout-GQQF4XDN.js +58 -0
- package/dist/index.cjs +40 -28
- package/dist/index.d.cts +82 -26
- package/dist/index.d.ts +82 -26
- package/dist/index.js +40 -28
- package/dist/manager.cjs +516 -340
- package/dist/manager.d.cts +2 -2
- package/dist/manager.d.ts +2 -2
- package/dist/manager.js +316 -120
- package/package.json +2 -2
- package/dist/channelsMode-KZU235GN.js +0 -1
- package/dist/hostedCheckout-K6C42MCF.js +0 -58
|
@@ -1,25 +1,124 @@
|
|
|
1
|
-
function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dataset.themed="true";let t=document.createElement("details");t.className="slm-themed-picker";let n=document.createElement("summary"),s=document.createElement("div");s.className="slm-themed-options";let r=e.getAttribute("aria-label")||Array.from(e.labels??[]).map(a=>a.textContent).join(" ")||"Choose option";n.setAttribute("aria-label",r.trim()),t.append(n,s),e.after(t),e.hidden=!0;let o=()=>{n.textContent=e.selectedOptions[0]?.textContent??"Choose\u2026",n.setAttribute("aria-disabled",String(e.disabled)),s.replaceChildren(...Array.from(e.options).map(a=>{let l=document.createElement("button");return l.type="button",l.textContent=a.textContent,l.setAttribute("aria-label",a.textContent??""),l.disabled=e.disabled||a.disabled,l.setAttribute("aria-pressed",String(a.selected)),l.onclick=()=>{e.value=a.value,t.open=!1,o(),n.focus(),e.dispatchEvent(new Event("change",{bubbles:!0})),o()},l}))};o(),e.addEventListener("change",o),n.onclick=a=>{if(e.disabled){a.preventDefault();return}o(),i.querySelectorAll(".slm-themed-picker").forEach(l=>{l!==t&&(l.open=!1)})},t.addEventListener("focusout",a=>{t.contains(a.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",a=>{if(a.key==="Escape"&&(a.preventDefault(),a.stopPropagation(),t.open=!1,n.focus()),a.key==="ArrowDown"||a.key==="ArrowUp"){if(e.disabled)return;a.preventDefault(),t.open=!0;let l=Array.from(s.querySelectorAll("button:not(:disabled)")),h=l.indexOf(document.activeElement);l[(h+(a.key==="ArrowDown"?1:l.length-1)+l.length)%l.length]?.focus()}})})}var $="public",P="Public sale";function D(i){return i==null||i===""||i===$}var Y=["#a78bfa","#2dd4bf","#fb923c","#60a5fa","#f472b6","#a3e635","#f87171","#38bdf8","#c084fc","#facc15"],_e="#f4b740",ce="ABCDEFGHJKLMNPQRSTUVWXYZ";function B(i,e){let t=(i??"").trim();return((/\p{L}/u.exec(t)?.[0]??t[0]??"")||e).toUpperCase().slice(0,1)}function ee(i,e){let t=new Set([...e].map(r=>B(r,"")).filter(Boolean)),n=B(i,"");return{letter:ce.includes(n)&&!t.has(n)?n:[...ce].find(r=>!t.has(r))??(n||"X"),color:Y[t.size%Y.length]}}function de(i,e=0){return D(i.id)?{letter:B(i.marker,"P"),color:i.color||_e}:{letter:B(i.marker||i.name,"?"),color:i.color||Y[e%Y.length]}}function ue(i,e,t){let n=new Map;for(let o of i){let a=J(e.get(o));n.set(a,(n.get(a)??0)+1)}let s=[{id:$,name:t?.publicSale?.name??P},...(t?.channels??[]).map(o=>({id:o.id,name:o.name}))],r=[];for(let o of s){let a=n.get(o.id);a&&r.push({channelId:o.id,name:o.name,count:a}),n.delete(o.id)}for(let[o,a]of n)r.push({channelId:o,name:D(o)?P:"Another channel",count:a});return r}function J(i){return D(i)?$:i}var he=12;function Q(i){return{count:i.length,labels:i.slice(0,he),truncated:i.length>he}}function pe(i){let{labels:e,allocation:t,statusOf:n,nameOf:s}=i,r=J(i.targetChannelId),o=new Set,a=0,l=0,h=new Map,d=[],u=[],k=[];for(let v of e){if(o.has(v))continue;o.add(v);let m=n(v);if(!m){k.push(v);continue}let b=J(t.get(v));if(b===r){l+=1;continue}if(m==="held"){d.push(v);continue}if(m==="booked"){u.push(v);continue}b===$?a+=1:h.set(b,(h.get(b)??0)+1)}let L=[...h.entries()].map(([v,m])=>({channelId:v,name:s(v),count:m}));return{changedFromPublic:{count:a},movedFromOtherChannel:{count:L.reduce((v,m)=>v+m.count,0),channels:L},alreadyInTarget:{count:l},skippedHeld:Q(d),skippedBooked:Q(u),notFound:Q(k)}}function K(i){return i.changedFromPublic.count+i.movedFromOtherChannel.count}function me(i){return i.movedFromOtherChannel.count>0}function ge(i,e){let t=[];i.changedFromPublic.count&&t.push({kind:"add",icon:"+",count:i.changedFromPublic.count,text:`${i.changedFromPublic.count.toLocaleString()} from ${P}`});for(let n of i.movedFromOtherChannel.channels)t.push({kind:"move",icon:"\u21C4",count:n.count,text:`${n.count.toLocaleString()} moved out of ${n.name??"another channel"}`,why:"needs this confirmation"});return i.alreadyInTarget.count&&t.push({kind:"same",icon:"=",count:i.alreadyInTarget.count,text:`${i.alreadyInTarget.count.toLocaleString()} already in ${e}`,why:"unchanged"}),i.skippedHeld.count&&t.push({kind:"skip",icon:"\u23F8",count:i.skippedHeld.count,text:`${i.skippedHeld.count.toLocaleString()} in a buyer's checkout`,why:"can't move while held",peek:F(i.skippedHeld)}),i.skippedBooked.count&&t.push({kind:"skip",icon:"\u{1F512}",count:i.skippedBooked.count,text:`${i.skippedBooked.count.toLocaleString()} already sold`,why:"sales are never rewritten",peek:F(i.skippedBooked)}),i.notFound.count&&t.push({kind:"skip",icon:"?",count:i.notFound.count,text:`${i.notFound.count.toLocaleString()} not on this map`,why:"these seats are no longer part of the event",peek:F(i.notFound)}),t}function F(i){if(!i.labels.length)return;let e=i.labels.slice(0,4).join(", ");return i.truncated||i.labels.length>4?`${e}\u2026`:e}function be(i){let e=i?.retryAfterMs??(i?.latestHoldExpiresAt?Math.max(0,i.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 ve(i){if(!i||!i.intent)return"\u2014";let e=i.intent==="server"?"Website integration":i.intent==="hosted_link"?"Buyer link":i.intent==="internal"?"Your staff sell these":"Protected reserve",t=i.hasActiveGrants?"in use now":i.lastMintAt?`last used ${new Date(i.lastMintAt).toLocaleDateString()}`:null,n=i.detail??t;return n?`${e} \xB7 ${n}`:e}function q(i){return i==="internal"?"Sell through your own staff":i==="server"?"Integrate a website or app":i==="hosted_link"?"Sell with a buyer link":"Keep as protected reserve"}function fe(i){switch(i){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 ze(i){return i==="hosted_link"?"hosted_link":i==="server"?"server":i==="staff"?"internal":null}function X(i){let e=Z(i?.accessIntent),t=ze(i?.route),n=`This channel is set to "${q(e)}"`;return t?`${n}, so it cannot do that. Switch it to "${q(t)}" first.`:`${n}, so it cannot do that. Choose a different route for this channel first.`}function Z(i){return i==="internal"||i==="server"||i==="hosted_link"||i==="none"?i:"none"}function j(i,e,t){return`${i.toLocaleString()} ${i===1?e:t}`}function ye(i){let e=Math.max(0,i?.liveAccessLinks??0),t=Math.max(0,i?.activeSessions??0),n=Z(i?.from),s=Z(i?.to),o=`${[e?j(e,"buyer link is live","buyer links are live"):null,t?j(t,"buyer is in a checkout","buyers are in a checkout"):null].filter(Boolean).join(", and ")||"Buyers are inside this channel"} on "${q(n)}". Moving it to "${q(s)}" changes what happens to them.`,a=[];return e&&a.push(`${j(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&&a.push(`${j(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:o,consequences:a}}var te={maxRedemptions:100,maxQuantity:4};function ke(i){switch(i.status??i.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 ne(i){return i.state==="active"&&i.status==="active"}function Ue(i){return Number.isFinite(i)?new Date(i).toLocaleString(void 0,{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):"\u2014"}function se(i){return[{k:"Expires",v:Ue(i.expiresAt)},{k:"Redemptions",v:`${i.redemptions.toLocaleString()} of ${i.maxRedemptions.toLocaleString()} used`},{k:"Seats per buyer",v:`${i.maxQuantity.toLocaleString()} seat${i.maxQuantity===1?"":"s"} maximum`},{k:"Covers",v:i.includePublic?"This channel's allocation and Public sale seats":"This channel's allocation only"}]}function V(i){let e=i?.serverMessage?.trim();switch(i?.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 X(i?.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 i?.status===403?"Hosted access links need channel-management permission.":e||"That did not go through. Try again."}}function rt(i){return(i?.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?F({count:e.count,labels:e.labels,truncated:e.truncated??!1}):void 0}))}function we(i){return i==="builtin"?"Built-in":i==="active"?"Active":i==="paused"?"Paused":"Archived"}var g=class extends Error{constructor(e,t,n,s,r,o){super(t),this.name="ManageApiError",this.status=e,this.code=n,this.conflicts=s,this.details=r,this.serverMessage=o}};async function xe(i){let t=(i.headers.get("content-type")??"").includes("application/json")?await i.json().catch(()=>null):null;if(!i.ok){let n=t;throw new g(i.status,n?.error??`request_failed_${i.status}`,n?.code,n?.conflicts,n?.details,typeof n?.message=="string"?n.message:void 0)}return t}function C(i){return i&&typeof i=="object"?i:{}}function G(i,e,t=0){return typeof i=="number"&&Number.isFinite(i)?i:typeof e=="number"&&Number.isFinite(e)?e:t}function Se(i,e){return i===null?null:typeof i=="number"&&Number.isFinite(i)?i:i!==void 0?null:typeof e=="number"&&Number.isFinite(e)?e:null}function Le(i){let e=C(i),t=G(e.bookedValue,e.bookedRevenue);return{...e,bookedValue:t,bookedRevenue:t}}function Ne(i){let e=C(i),t=C(e.report),n=Array.isArray(t.byCategory)?t.byCategory.map(r=>{let o=C(r),a=G(o.bookedValue,o.bookedRevenue);return{...o,bookedValue:a,bookedRevenue:a}}):[],s=Array.isArray(t.bySection)?t.bySection.map(Le):void 0;return{...e,report:{...t,byCategory:n,...s?{bySection:s}:{}}}}function Ve(i){let e=C(i),t=C(e.bookedValue),n=C(e.revenue),s=Object.keys(t).length?t:n,r=Array.isArray(t.bySection)?t.bySection:Array.isArray(n.bySection)?n.bySection:[],o={...s,gross:G(t.gross,n.gross),bySection:r.map(Le)},a=C(e.velocity),l=Array.isArray(a.bySection)?a.bySection.map(h=>{let d=C(h),u=G(d.bookedValue,d.grossRevenue);return{...d,bookedValue:u,grossRevenue:u}}):[];return{...e,bookedValue:o,revenue:o,velocity:{...a,bySection:l}}}function je(i){let e=C(i),t=C(e.report),n=typeof t.includesBookedValue=="boolean"?t.includesBookedValue:t.includesRevenue===!0,s=Array.isArray(t.rows)?t.rows.map(a=>{let l=C(a),h=C(l.attribution),d=Se(h.bookedValue,h.revenue);return{...l,attribution:{...h,bookedValue:d,revenue:d}}}):[],r=C(t.totals),o=Se(r.bookedValue,r.revenue);return{...e,report:{...t,includesBookedValue:n,includesRevenue:n,rows:s,totals:{...r,bookedValue:o,revenue:o}}}}function ie(i){let e=C(i),t=typeof e.includesBookedValue=="boolean"?e.includesBookedValue:e.includesRevenue===!0;return{...e,includesBookedValue:t,includesRevenue:t}}var Ce=class{constructor(e,t){this.base=e.replace(/\/+$/,""),this.token=t}setToken(e){this.token=e}auth(e,t={}){let n=t.method??"GET",s={Authorization:`Bearer ${this.token}`},r;return t.body!==void 0&&(s["Content-Type"]="application/json",r=JSON.stringify(t.body)),fetch(`${this.base}${e}`,{method:n,headers:s,body:r,credentials:"omit"}).then(o=>xe(o))}async authBlob(e){let t=await fetch(`${this.base}${e}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});return t.ok||await xe(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 g(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,n={}){let s={labels:t};return typeof n.releaseAt=="number"&&(s.releaseAt=n.releaseAt),n.reason&&(s.reason=n.reason),this.auth(`/v1/events/${encodeURIComponent(e)}/block`,{method:"POST",body:s})}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,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/unbook`,{method:"POST",body:{labels:t,bookingRef:n}})}setHoldTtl(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/hold-ttl`,{method:"POST",body:{holdTtlMs:t}})}setCategory(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`,{method:"POST",body:{labels:t,categoryKey:n}})}setTableBooking(e,t,n,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/table-booking`,{method:"POST",body:{tableIds:t,mode:n,...s}})}bookings(e,t={}){let n=new URLSearchParams;t.q&&n.set("q",t.q),t.state&&n.set("state",t.state),t.cursor&&n.set("cursor",t.cursor),t.limit!=null&&n.set("limit",String(t.limit));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings${s?`?${s}`:""}`)}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 n=t.includeArchived?"?includeArchived=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels${n}`)}channelAllocation(e,t={}){let n=new URLSearchParams;t.afterLabel&&n.set("afterLabel",t.afterLabel),t.limit!=null&&n.set("limit",String(t.limit));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/allocation${s?`?${s}`:""}`)}channelAudit(e,t={}){let n=new URLSearchParams;t.limit!=null&&n.set("limit",String(t.limit)),t.before!=null&&n.set("before",String(t.before));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/audit${s?`?${s}`:""}`)}createChannel(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels`,{method:"POST",body:t})}renameChannel(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{name:n}})}updateChannelPricing(e,t,n,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{priceOverrides:n,expectedPricingVersion:s}})}setChannelPaused(e,t,n){let s=n?"pause":"unpause";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/${s}`,{method:"POST",body:{}})}archiveChannel(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/archive`,{method:"POST",body:{destination:n}})}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,n={}){let s=new URLSearchParams;t.length&&s.set("channelIds",t.join(",")),n.includePublic!=null&&s.set("includePublic",n.includePublic?"1":"0");let r=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/preview${r?`?${r}`:""}`)}setChannelAccessIntent(e,t,n,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{accessIntent:n,...s.acknowledgeLiveAccess?{acknowledgeLiveAccess:!0}:{},...s.reason?{reason:s.reason}:{}}})}createAccessLink(e,t,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`,{method:"POST",body:n})}accessLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`)}rotateAccessLink(e,t,n,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(n)}/rotate`,{method:"POST",body:{endActiveSessions:s}})}revokeAccessLink(e,t,n,s=!1){let r=s?"?endActiveSessions=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(n)}${r}`,{method:"DELETE"})}report(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/report`).then(Ne)}seatHistory(e,t,n,s){let r=new URLSearchParams({label:t});return n&&r.set("before",String(n)),s&&r.set("action",s),this.auth(`/v1/events/${encodeURIComponent(e)}/seat-history?${r}`)}controlRoom(e,t=15){return this.auth(`/v1/events/${encodeURIComponent(e)}/control-room?window=${t}`).then(Ve)}channelReport(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/report`).then(je)}createChannelReportLink(e,t,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`,{method:"POST",body:n}).then(s=>{let r=C(s);return{...r,link:ie(r.link)}})}channelReportLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`).then(n=>{let s=C(n);return{links:Array.isArray(s.links)?s.links.map(ie):[]}})}revokeChannelReportLink(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links/${encodeURIComponent(n)}`,{method:"DELETE"}).then(s=>{let r=C(s);return{...r,link:ie(r.link)}})}log(e,t={}){let n=new URLSearchParams;t.limit!=null&&n.set("limit",String(t.limit)),t.before!=null&&n.set("before",String(t.before));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/log${s?`?${s}`:""}`)}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 g(t.status,`request_failed_${t.status}`);return t.blob()}};function ae(i){return i.map((e,t)=>`
|
|
1
|
+
import{c as ne}from"./chunk-RZ2VKZ44.js";function ge(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dataset.themed="true";let t=document.createElement("details");t.className="slm-themed-picker";let n=document.createElement("summary"),s=document.createElement("div");s.className="slm-themed-options";let r=e.getAttribute("aria-label")||Array.from(e.labels??[]).map(a=>a.textContent).join(" ")||"Choose option";n.setAttribute("aria-label",r.trim()),t.append(n,s),e.after(t),e.hidden=!0;let o=()=>{n.textContent=e.selectedOptions[0]?.textContent??"Choose\u2026",n.setAttribute("aria-disabled",String(e.disabled)),s.replaceChildren(...Array.from(e.options).map(a=>{let l=document.createElement("button");return l.type="button",l.textContent=a.textContent,l.setAttribute("aria-label",a.textContent??""),l.disabled=e.disabled||a.disabled,l.setAttribute("aria-pressed",String(a.selected)),l.onclick=()=>{e.value=a.value,t.open=!1,o(),n.focus(),e.dispatchEvent(new Event("change",{bubbles:!0})),o()},l}))};o(),e.addEventListener("change",o),n.onclick=a=>{if(e.disabled){a.preventDefault();return}o(),i.querySelectorAll(".slm-themed-picker").forEach(l=>{l!==t&&(l.open=!1)})},t.addEventListener("focusout",a=>{t.contains(a.relatedTarget)||(t.open=!1)}),t.addEventListener("keydown",a=>{if(a.key==="Escape"&&(a.preventDefault(),a.stopPropagation(),t.open=!1,n.focus()),a.key==="ArrowDown"||a.key==="ArrowUp"){if(e.disabled)return;a.preventDefault(),t.open=!0;let l=Array.from(s.querySelectorAll("button:not(:disabled)")),c=l.indexOf(document.activeElement);l[(c+(a.key==="ArrowDown"?1:l.length-1)+l.length)%l.length]?.focus()}})})}function yt(i){i.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{}}))})}import{formatMoney as Ye}from"@seatlayer/core";function St(i){return i?i.mode:"open"}function Lt(i,e,t){switch(i){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 Ct(i){return new Date(i-new Date().getTimezoneOffset()*6e4).toISOString().slice(0,16)}function $t(i){if(typeof i=="string"){let e=document.querySelector(i);if(!e)throw new Error(`seatmanager: container "${i}" not found`);return e}if(!(i instanceof HTMLElement))throw new Error("seatmanager: container must be a CSS selector or an HTMLElement");return i}function Rt(i){if(!i.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 At(i){return i==="blocked"?"not_for_sale":i}var Ke=["free","booked","held","blocked"],V={free:"#6e7bff",booked:"#9ca3af",held:"#f4b740",blocked:"#475569"},Y={free:"Free",booked:"Sold",held:"Held",blocked:"Blocked"},Et=[`<span class="slm-legmark" style="background:${V.free}"></span> Free = category colour`,`<span class="slm-legmark" style="background:${V.booked}"></span> ${Y.booked}`,`<span class="slm-legmark" style="background:${V.held}"></span> ${Y.held}`,`<span class="slm-legcross" style="color:${V.blocked}">\u2715</span> ${Y.blocked}`].join(" \xB7 "),It=Ke.map(i=>({key:i,label:Y[i],color:V[i]}));function Tt(i,e){let t=i??{},n=e?ne[e]:null,s=e==="light";return{"--slm-bg":t.background??n?.background??"#0e1017","--slm-surface":n?.surface??"#181b24","--slm-text":n?.text??"#eef1f7","--slm-muted":n?.muted??"#8b93a7","--slm-line":n?.line??"rgba(255,255,255,.09)","--slm-tint":s?"rgba(23,32,51,.05)":"rgba(255,255,255,.035)","--slm-tint-strong":s?"rgba(23,32,51,.09)":"rgba(255,255,255,.07)","--slm-accent":t.accent??(s?"#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(i){return i?ne[i].map:null}function Mt(i,e){let t=Math.max(0,Math.round((e-i)/1e3));if(t<5)return"just now";if(t<60)return`${t}s ago`;let n=Math.round(t/60);return n<60?`${n}m ago`:`${Math.round(n/60)}h ago`}function Dt(i,e){return Ye(i,e,{maximumFractionDigits:0,fallback:(t,n)=>`${n} ${Math.round(t).toLocaleString()}`})}function w(i){return String(i??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var K=300,Ge=200;function Xe(i,e){if(!i.labels.length)return"Nothing found";let t=[];i.sections&&t.push(`${i.sections.toLocaleString()} section${i.sections===1?"":"s"}`),i.rows&&t.push(`${i.rows.toLocaleString()} row${i.rows===1?"":"s"}`);let n=`${i.labels.length.toLocaleString()} seat${i.labels.length===1?"":"s"} found`,s=t.length?`${t.join(" \xB7 ")} \xB7 ${n}`:n;return e?`${s} \xB7 Enter to ${e==="frame"?"show":"select"}`:s}function We(i={}){return`
|
|
2
|
+
<div class="slm-find${i.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"${i.compact?' aria-keyshortcuts="/"':""}>
|
|
4
|
+
<span class="slm-find-count" data-ch-find-count role="status"></span>
|
|
5
|
+
</div>`}function be(i,e){return i.toLocaleLowerCase().split(/\s+/).some(t=>e.length>=2?t.startsWith(e):t===e)}function Qe(i,e){let t=i.trim().toLocaleLowerCase();if(!t)return{labels:[],seats:0,rows:0,sections:0};let n=new Set,s=0,r=0;for(let h of e.sections)if(be(h.label,t)){s+=1;for(let m of h.labels)n.add(m)}let o=t.split(/\s+/),a=o[o.length-1],l=o.slice(0,-1).join(" ");for(let h of e.rows)if(h.label.toLocaleLowerCase()===a&&!(l&&!be(h.sectionLabel,l))){r+=1;for(let m of h.labels)n.add(m)}let c=0;for(let h of e.seatLabels){let m=h.toLocaleLowerCase();(m===t||m.startsWith(`${t}-`))&&(n.has(h)||(c+=1),n.add(h))}return{labels:[...n],seats:c,rows:r,sections:s}}function Ot(i){let e=i.clearAttr?`<button type="button" class="slm-linkbtn slm-selclear" ${i.clearAttr}${i.count?"":" disabled"}>Clear</button>`:"";return`<div class="slm-selbar" aria-live="polite">
|
|
6
|
+
<span class="slm-selnum${i.bump?" bump":""}">${i.count.toLocaleString()}</span>
|
|
7
|
+
<span class="slm-sellabel">${w(i.noun??"selected")}</span>
|
|
8
|
+
${i.breakdown??""}${e}
|
|
9
|
+
</div>`}var G=class{constructor(e){this.host=e;this.seatListLimit=K;this.rowsCache=null}rows(){return this.rowsCache||(this.rowsCache=this.host.rows()),this.rowsCache}reset(){this.rowsCache=null,this.seatListLimit=K}chipsHtml(e={}){let t=this.host.sections().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-sections">Section</button>':"",n=this.rows().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-rows">Rows\u2026</button>':"",s=this.host.categories().length?'<button type="button" class="slm-btn ghost" data-ch-act="pick-category">Category</button>':"",r=e.find===!1?"":We();return`
|
|
10
|
+
<div class="slm-chooser" data-ch-chooser>
|
|
11
|
+
<div class="slm-ch-row2">${e.intents??""}${t}${n}</div>
|
|
12
|
+
<div class="slm-ch-row2">${s}<button type="button" class="slm-btn ghost" data-ch-act="seatlist">Seat list \u2328</button></div>
|
|
13
|
+
${r}
|
|
14
|
+
</div>`}wire(e,t={}){this.wireChips(e),this.wireFind(e,t)}wireChips(e){e.querySelectorAll("[data-ch-act]").forEach(t=>{let n=t.dataset.chAct;n==="pick-sections"?t.addEventListener("click",()=>this.openSections()):n==="pick-rows"?t.addEventListener("click",()=>this.openRows()):n==="pick-category"?t.addEventListener("click",()=>this.openCategory()):n==="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 n=e.querySelector("[data-ch-find-input]"),s=e.querySelector("[data-ch-find-count]");if(!n||!s)return;let r={labels:[],seats:0,rows:0,sections:0},o=()=>{let a=n.value.trim();r=this.find(n.value),s.textContent=a?Xe(r,t.enter??"select"):"",this.host.highlight?.(a?r.labels:null),t.onFind?.(r)};n.addEventListener("input",o),n.addEventListener("keydown",a=>{if(a.key==="Escape"&&n.value){a.preventDefault(),a.stopPropagation(),n.value="",o();return}if(a.key!=="Enter"||(a.preventDefault(),!r.labels.length))return;if(t.enter==="frame"){this.host.frame?.(r.labels),s.textContent=`${r.labels.length.toLocaleString()} on the map`;return}let l=new Set([...this.host.selectionLabels(),...r.labels]);if(this.host.cap!=null&&l.size>this.host.cap){s.textContent=`That would make ${l.size.toLocaleString()} selected seats \u2014 the limit is ${this.host.cap.toLocaleString()}.`;return}this.host.selectByLabels(r.labels),s.textContent=`${r.labels.length.toLocaleString()} selected`}),n.addEventListener("search",o)}find(e){return Qe(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,n=e.map(c=>({key:c.key,label:c.label,color:c.color,labels:this.host.labelsInCategory(c.key)})),s=new Map(n.map(c=>[c.key,c])),r=new Set,o=new Set(this.host.selectionLabels()),a=()=>{let c=new Set(o);for(let h of r)for(let m of s.get(h)?.labels??[])c.add(m);return c},l=n.map(c=>{let h=c.labels.filter(p=>o.has(p)).length,m=c.labels.length===0,C=m?"not on this map":h?`${h.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="${w(c.key)}"${m?" disabled":""}>
|
|
16
|
+
<span class="box" aria-hidden="true">\u2713</span>
|
|
17
|
+
<span class="dot" style="background:${w(c.color??"#6e7bff")}" aria-hidden="true"></span>
|
|
18
|
+
<span>${w(c.label)}</span>
|
|
19
|
+
<span class="meta">${w(C)}</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">${l}</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 h=c.querySelector("[data-ch-add-scope]"),m=c.querySelector("[data-ch-error]"),C=()=>{let p=a(),g=p.size-o.size,v=p.size>t;h.disabled=g===0||v,h.textContent=v?`Maximum ${t.toLocaleString()} seats`:`Add ${g.toLocaleString()} seat${g===1?"":"s"}`,m.hidden=!v,m.textContent=v?`That would make ${p.size.toLocaleString()} selected seats. Choose fewer categories.`:""};c.querySelectorAll("[data-ch-category]").forEach(p=>{p.addEventListener("click",()=>{let g=p.dataset.chCategory;r.has(g)?r.delete(g):r.add(g),p.setAttribute("aria-checked",String(r.has(g))),C()})}),h.addEventListener("click",()=>{let p=[...a()];!r.size||p.length>t||(this.host.closeDialog(),this.host.selectByLabels(p))}),C()})}openSections(){this.openScope("sections")}openRows(){this.openScope("rows")}openScope(e){let t=this.host.cap??1/0,s=(e==="sections"?this.host.sections().map(p=>({id:p.id,label:p.label,group:"Sections",labels:this.host.labelsInSection(p.id)})):this.rows().map(p=>({id:p.id,label:p.label,group:p.sectionLabel,labels:p.labels}))).filter(p=>p.labels.length>0),r=new Map;for(let p of s){let g=r.get(p.group)??[];g.push(p),r.set(p.group,g)}let o=new Map(s.map(p=>[p.id,p])),a=new Set,l=new Set(this.host.selectionLabels()),c=()=>{let p=new Set(l);for(let g of a)for(let v of o.get(g)?.labels??[])p.add(v);return p},h=(p,g)=>{let v=c(),$=v.size-l.size,u=v.size>t;p.disabled=$===0||u,p.textContent=u?`Maximum ${t.toLocaleString()} seats`:`Add ${$.toLocaleString()} seat${$===1?"":"s"}`,g.hidden=!u,g.textContent=u?`That would make ${v.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:""},m=()=>{let p=[...c()];!a.size||p.length>t||(this.host.closeDialog(),this.host.selectByLabels(p))};if(e==="rows"){let p=[...r.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>`,g=>{let v=new Set,$=g.querySelector("[data-ch-add-scope]"),u=g.querySelector("[data-ch-error]"),x=g.querySelector("[data-ch-scope-list]"),f=g.querySelector("[data-ch-scope-search]"),y=g.querySelector("[data-ch-scope-summary]"),S=g.querySelector("[data-ch-scope-filter]"),b="",R=()=>{h($,u);let T=c().size-l.size;y.textContent=`${a.size.toLocaleString()} row${a.size===1?"":"s"} \xB7 ${T.toLocaleString()} seat${T===1?"":"s"} added`},k=()=>{let T=[],pe=0,te=0;p.forEach(([P,A],U)=>{let q=P.toLocaleLowerCase(),N=b?A.filter(M=>`${q} ${M.label.toLocaleLowerCase()}`.includes(b)):A;if(b&&!N.length)return;pe+=N.length;let me=A.every(M=>a.has(M.id)),ze=!me&&A.some(M=>a.has(M.id)),z=!!b||v.has(U),Fe=Math.max(0,Ge-te),F=z?N.slice(0,Fe):[];te+=F.length;let Ve=A.reduce((M,je)=>M+je.labels.length,0);T.push(`<div class="slm-ch-scopegroup">
|
|
42
|
+
<button type="button" class="slm-ch-groupcheck" role="checkbox" aria-checked="${me?"true":ze?"mixed":"false"}"
|
|
43
|
+
aria-label="Select all ${A.length.toLocaleString()} rows in ${w(P)}" data-ch-scope-group="${U}">
|
|
44
|
+
<span class="box" aria-hidden="true">\u2713</span><span>${w(P)}</span>
|
|
45
|
+
<span class="meta">${A.length.toLocaleString()} rows \xB7 ${Ve.toLocaleString()} seats</span>
|
|
46
|
+
</button>
|
|
47
|
+
<button type="button" class="slm-ch-grouptoggle" aria-expanded="${z}" aria-label="${z?"Hide":"Show"} rows in ${w(P)}"
|
|
48
|
+
data-ch-scope-toggle="${U}">${z?"Hide":"Show"}</button>
|
|
49
|
+
</div>`),T.push(...F.map(M=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
50
|
+
aria-checked="${a.has(M.id)}" data-ch-scope-id="${w(M.id)}">
|
|
51
|
+
<span class="box" aria-hidden="true">\u2713</span><span>${w(M.label)}</span>
|
|
52
|
+
<span class="meta">${M.labels.length.toLocaleString()} seat${M.labels.length===1?"":"s"}</span>
|
|
53
|
+
</button>`)),z&&N.length>F.length&&T.push(`<p class="slm-ch-scopehint">${(N.length-F.length).toLocaleString()} more row${N.length-F.length===1?"":"s"}. Search to narrow the list.</p>`)}),x.innerHTML=T.join("")||(b?`<div class="slm-ch-scope-empty" data-ch-state="scope-nomatch">No sections or rows match \u201C${w(b)}\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>`),S.textContent=b?`Showing ${te.toLocaleString()} of ${pe.toLocaleString()} matching rows. Section checkboxes still select every row in that section.`:"Showing section groups. Expand one or search to see rows.",x.querySelectorAll("[data-ch-scope-group]").forEach(P=>P.addEventListener("click",()=>{let A=p[Number(P.dataset.chScopeGroup)]?.[1]??[],U=A.every(q=>a.has(q.id));for(let q of A)U?a.delete(q.id):a.add(q.id);k(),R()})),x.querySelectorAll("[data-ch-scope-toggle]").forEach(P=>P.addEventListener("click",()=>{let A=Number(P.dataset.chScopeToggle);v.has(A)?v.delete(A):v.add(A),k()})),x.querySelectorAll("[data-ch-scope-id]").forEach(P=>P.addEventListener("click",()=>{let A=P.dataset.chScopeId;a.has(A)?a.delete(A):a.add(A),k(),R()}))};f.addEventListener("input",()=>{b=f.value.trim().toLocaleLowerCase(),k(),R()}),$.addEventListener("click",m),k(),R()});return}let C=[...r.entries()].map(([p,g])=>`
|
|
55
|
+
<div class="slm-ch-seatgroup"><span>${w(p)}</span></div>
|
|
56
|
+
${g.map(v=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
57
|
+
aria-checked="false" data-ch-scope-id="${w(v.id)}">
|
|
58
|
+
<span class="box" aria-hidden="true">\u2713</span>
|
|
59
|
+
<span>${w(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">${C||`<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>`,p=>{let g=p.querySelector("[data-ch-add-scope]"),v=p.querySelector("[data-ch-error]");p.querySelectorAll("[data-ch-scope-id]").forEach($=>{$.addEventListener("click",()=>{let u=$.dataset.chScopeId;a.has(u)?a.delete(u):a.add(u),$.setAttribute("aria-checked",String(a.has(u))),h(g,v)})}),g.addEventListener("click",m),h(g,v)})}openSeatList(e=""){let t=new Set(this.host.selectionLabels()),n=e.trim().toLocaleLowerCase(),s=u=>!n||u.toLocaleLowerCase().includes(n),r=this.rows(),o=new Map;for(let u of r)for(let x of u.labels)o.set(x,u);let a=new Map,l=new Map,c=0,h=0;for(let u of this.host.seats()){if(!s(u.label)||(c+=1,c>this.seatListLimit))continue;h+=1;let x=this.host.sectionOfLabel(u.label),f=x?.id??"",y=a.get(f)??{label:x?.label??"Other seats",lines:[],loose:[]};a.set(f,y);let S=o.get(u.label);if(!S){y.loose.push(u.label);continue}let b=l.get(S.id)??{id:S.id,label:S.label,seats:[]};l.has(S.id)||(l.set(S.id,b),y.lines.push(b)),b.seats.push(u.label)}let m=u=>this.host.seatMeta?.(u)??this.host.statusOf(u)??"free",C=(u,x)=>{let f=this.host.statusOf(u)??"free",y=x&&u.startsWith(`${x}-`)?u.slice(x.length+1):u;return`<button type="button" class="slm-ch-seatchip is-${w(f)}" role="checkbox"
|
|
71
|
+
aria-checked="${t.has(u)}" aria-label="${w(u)} \xB7 ${w(m(u))}" title="${w(u)} \xB7 ${w(m(u))}"
|
|
72
|
+
data-ch-seat="${w(u)}">${w(y)}</button>`},p=u=>{let x=u.seats.filter(f=>t.has(f)).length;return x===0?"false":x===u.seats.length?"true":"mixed"},g=[...a.entries()].map(([u,x])=>`
|
|
73
|
+
<div class="slm-ch-seatgroup">
|
|
74
|
+
<span>${w(x.label)}</span>
|
|
75
|
+
${u?`<button type="button" data-ch-section="${w(u)}">Select section</button>`:""}
|
|
76
|
+
</div>
|
|
77
|
+
${x.lines.map(f=>`
|
|
78
|
+
<div class="slm-ch-seatrow">
|
|
79
|
+
<button type="button" class="slm-ch-rowcheck" role="checkbox" aria-checked="${p(f)}" data-ch-row="${w(f.id)}"
|
|
80
|
+
aria-label="Row ${w(f.label)} \xB7 ${f.seats.length} seats">
|
|
81
|
+
<span class="box" aria-hidden="true">\u2713</span><span class="name">${w(f.label)}</span>
|
|
82
|
+
<span class="meta">${f.seats.length.toLocaleString()}</span>
|
|
83
|
+
</button>
|
|
84
|
+
<div class="slm-ch-seatchips">${f.seats.map(y=>C(y,f.label)).join("")}</div>
|
|
85
|
+
</div>`).join("")}
|
|
86
|
+
${x.loose.length?`<div class="slm-ch-seatrow loose"><div class="slm-ch-seatchips">${x.loose.map(f=>C(f,null)).join("")}</div></div>`:""}`).join(""),v=n?`<div class="slm-empty">Nothing matches \u201C${w(e.trim())}\u201D.</div>`:'<div class="slm-empty">No seats on this chart.</div>',$=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="${w(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">${h?g:v}</div>
|
|
96
|
+
${c>this.seatListLimit?`<div class="foot"><button type="button" class="slm-btn ghost" data-ch-more>Show ${Math.min(K,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">${$}</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>`,u=>{let x=y=>{this.host.clearSelection(),y.size&&this.host.selectByLabels([...y]),this.openSeatList(e)};u.querySelectorAll("[data-ch-seat]").forEach(y=>{y.addEventListener("click",()=>{let S=y.dataset.chSeat,b=new Set(this.host.selectionLabels());b.has(S)?b.delete(S):b.add(S),x(b)})}),u.querySelectorAll("[data-ch-row]").forEach(y=>{y.addEventListener("click",()=>{let S=l.get(y.dataset.chRow);if(!S)return;let b=new Set(this.host.selectionLabels()),R=S.seats.every(k=>b.has(k));for(let k of S.seats)R?b.delete(k):b.add(k);x(b)})}),u.querySelectorAll("[data-ch-section]").forEach(y=>{y.addEventListener("click",()=>{this.host.selectSection(y.dataset.chSection),this.openSeatList(e)})}),u.querySelector("[data-ch-clear-all]")?.addEventListener("click",()=>x(new Set)),u.querySelector("[data-ch-more]")?.addEventListener("click",()=>{this.seatListLimit+=K,this.openSeatList(e)});let f=u.querySelector("[data-ch-seatfilter-input]");if(f){let y=null;f.addEventListener("input",()=>{y&&clearTimeout(y),y=setTimeout(()=>{this.openSeatList(f.value);let S=this.lastDialogInput();S&&(S.focus(),S.setSelectionRange(S.value.length,S.value.length))},120)}),e&&(f.focus(),f.setSelectionRange(f.value.length,f.value.length))}})}lastDialogInput(){return document.querySelector(".slm-ch-dialog [data-ch-seatfilter-input]")}};var E="public",D="Public sale";function H(i){return i==null||i===""||i===E}var Q=["#a78bfa","#2dd4bf","#fb923c","#60a5fa","#f472b6","#a3e635","#f87171","#38bdf8","#c084fc","#facc15"],Ze="#f4b740",ve="ABCDEFGHJKLMNPQRSTUVWXYZ";function O(i,e){let t=(i??"").trim();return((/\p{L}/u.exec(t)?.[0]??t[0]??"")||e).toUpperCase().slice(0,1)}function oe(i,e){let t=new Set([...e].map(r=>O(r,"")).filter(Boolean)),n=O(i,"");return{letter:ve.includes(n)&&!t.has(n)?n:[...ve].find(r=>!t.has(r))??(n||"X"),color:Q[t.size%Q.length]}}function ye(i,e=0){return H(i.id)?{letter:O(i.marker,"P"),color:i.color||Ze}:{letter:O(i.marker||i.name,"?"),color:i.color||Q[e%Q.length]}}function ke(i,e,t){let n=new Map;for(let o of i){let a=ie(e.get(o));n.set(a,(n.get(a)??0)+1)}let s=[{id:E,name:t?.publicSale?.name??D},...(t?.channels??[]).map(o=>({id:o.id,name:o.name}))],r=[];for(let o of s){let a=n.get(o.id);a&&r.push({channelId:o.id,name:o.name,count:a}),n.delete(o.id)}for(let[o,a]of n)r.push({channelId:o,name:H(o)?D:"Another channel",count:a});return r}function ie(i){return H(i)?E:i}var fe=12;function se(i){return{count:i.length,labels:i.slice(0,fe),truncated:i.length>fe}}function we(i){let{labels:e,allocation:t,statusOf:n,nameOf:s}=i,r=ie(i.targetChannelId),o=new Set,a=0,l=0,c=new Map,h=[],m=[],C=[];for(let g of e){if(o.has(g))continue;o.add(g);let v=n(g);if(!v){C.push(g);continue}let $=ie(t.get(g));if($===r){l+=1;continue}if(v==="held"){h.push(g);continue}if(v==="booked"){m.push(g);continue}$===E?a+=1:c.set($,(c.get($)??0)+1)}let p=[...c.entries()].map(([g,v])=>({channelId:g,name:s(g),count:v}));return{changedFromPublic:{count:a},movedFromOtherChannel:{count:p.reduce((g,v)=>g+v.count,0),channels:p},alreadyInTarget:{count:l},skippedHeld:se(h),skippedBooked:se(m),notFound:se(C)}}function Z(i){return i.changedFromPublic.count+i.movedFromOtherChannel.count}function xe(i){return i.movedFromOtherChannel.count>0}function Se(i,e){let t=[];i.changedFromPublic.count&&t.push({kind:"add",icon:"+",count:i.changedFromPublic.count,text:`${i.changedFromPublic.count.toLocaleString()} from ${D}`});for(let n of i.movedFromOtherChannel.channels)t.push({kind:"move",icon:"\u21C4",count:n.count,text:`${n.count.toLocaleString()} moved out of ${n.name??"another channel"}`,why:"needs this confirmation"});return i.alreadyInTarget.count&&t.push({kind:"same",icon:"=",count:i.alreadyInTarget.count,text:`${i.alreadyInTarget.count.toLocaleString()} already in ${e}`,why:"unchanged"}),i.skippedHeld.count&&t.push({kind:"skip",icon:"\u23F8",count:i.skippedHeld.count,text:`${i.skippedHeld.count.toLocaleString()} in a buyer's checkout`,why:"can't move while held",peek:W(i.skippedHeld)}),i.skippedBooked.count&&t.push({kind:"skip",icon:"\u{1F512}",count:i.skippedBooked.count,text:`${i.skippedBooked.count.toLocaleString()} already sold`,why:"sales are never rewritten",peek:W(i.skippedBooked)}),i.notFound.count&&t.push({kind:"skip",icon:"?",count:i.notFound.count,text:`${i.notFound.count.toLocaleString()} not on this map`,why:"these seats are no longer part of the event",peek:W(i.notFound)}),t}function W(i){if(!i.labels.length)return;let e=i.labels.slice(0,4).join(", ");return i.truncated||i.labels.length>4?`${e}\u2026`:e}function Le(i){let e=i?.retryAfterMs??(i?.latestHoldExpiresAt?Math.max(0,i.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 Ce(i){if(!i||!i.intent)return"\u2014";let e=i.intent==="server"?"Website integration":i.intent==="hosted_link"?"Buyer link":i.intent==="internal"?"Your staff sell these":"Protected reserve",t=i.hasActiveGrants?"in use now":i.lastMintAt?`last used ${new Date(i.lastMintAt).toLocaleDateString()}`:null,n=i.detail??t;return n?`${e} \xB7 ${n}`:e}function _(i){return i==="internal"?"Sell through your own staff":i==="server"?"Integrate a website or app":i==="hosted_link"?"Sell with a buyer link":"Keep as protected reserve"}function $e(i){switch(i){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 Je(i){return i==="hosted_link"?"hosted_link":i==="server"?"server":i==="staff"?"internal":null}function J(i){let e=ae(i?.accessIntent),t=Je(i?.route),n=`This channel is set to "${_(e)}"`;return t?`${n}, so it cannot do that. Switch it to "${_(t)}" first.`:`${n}, so it cannot do that. Choose a different route for this channel first.`}function ae(i){return i==="internal"||i==="server"||i==="hosted_link"||i==="none"?i:"none"}function X(i,e,t){return`${i.toLocaleString()} ${i===1?e:t}`}function Re(i){let e=Math.max(0,i?.liveAccessLinks??0),t=Math.max(0,i?.activeSessions??0),n=ae(i?.from),s=ae(i?.to),o=`${[e?X(e,"buyer link is live","buyer links are live"):null,t?X(t,"buyer is in a checkout","buyers are in a checkout"):null].filter(Boolean).join(", and ")||"Buyers are inside this channel"} on "${_(n)}". Moving it to "${_(s)}" changes what happens to them.`,a=[];return e&&a.push(`${X(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&&a.push(`${X(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:o,consequences:a}}var re={maxRedemptions:100,maxQuantity:4};function Ae(i){switch(i.status??i.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 le(i){return i.state==="active"&&i.status==="active"}function et(i){return Number.isFinite(i)?new Date(i).toLocaleString(void 0,{day:"numeric",month:"short",year:"numeric",hour:"numeric",minute:"2-digit"}):"\u2014"}function ce(i){return[{k:"Expires",v:et(i.expiresAt)},{k:"Redemptions",v:`${i.redemptions.toLocaleString()} of ${i.maxRedemptions.toLocaleString()} used`},{k:"Seats per buyer",v:`${i.maxQuantity.toLocaleString()} seat${i.maxQuantity===1?"":"s"} maximum`},{k:"Covers",v:i.includePublic?"This channel's allocation and Public sale seats":"This channel's allocation only"}]}function j(i){let e=i?.serverMessage?.trim();switch(i?.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 J(i?.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 i?.status===403?"Hosted access links need channel-management permission.":e||"That did not go through. Try again."}}function qt(i){return(i?.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?W({count:e.count,labels:e.labels,truncated:e.truncated??!1}):void 0}))}function Ee(i){return i==="builtin"?"Built-in":i==="active"?"Active":i==="paused"?"Paused":"Archived"}var L=class extends Error{constructor(e,t,n,s,r,o){super(t),this.name="ManageApiError",this.status=e,this.code=n,this.conflicts=s,this.details=r,this.serverMessage=o}};async function Ie(i){let t=(i.headers.get("content-type")??"").includes("application/json")?await i.json().catch(()=>null):null;if(!i.ok){let n=t;throw new L(i.status,n?.error??`request_failed_${i.status}`,n?.code,n?.conflicts,n?.details,typeof n?.message=="string"?n.message:void 0)}return t}function I(i){return i&&typeof i=="object"?i:{}}function ee(i,e,t=0){return typeof i=="number"&&Number.isFinite(i)?i:typeof e=="number"&&Number.isFinite(e)?e:t}function Te(i,e){return i===null?null:typeof i=="number"&&Number.isFinite(i)?i:i!==void 0?null:typeof e=="number"&&Number.isFinite(e)?e:null}function Me(i){let e=I(i),t=ee(e.bookedValue,e.bookedRevenue);return{...e,bookedValue:t,bookedRevenue:t}}function tt(i){let e=I(i),t=I(e.report),n=Array.isArray(t.byCategory)?t.byCategory.map(r=>{let o=I(r),a=ee(o.bookedValue,o.bookedRevenue);return{...o,bookedValue:a,bookedRevenue:a}}):[],s=Array.isArray(t.bySection)?t.bySection.map(Me):void 0;return{...e,report:{...t,byCategory:n,...s?{bySection:s}:{}}}}function nt(i){let e=I(i),t=I(e.bookedValue),n=I(e.revenue),s=Object.keys(t).length?t:n,r=Array.isArray(t.bySection)?t.bySection:Array.isArray(n.bySection)?n.bySection:[],o={...s,gross:ee(t.gross,n.gross),bySection:r.map(Me)},a=I(e.velocity),l=Array.isArray(a.bySection)?a.bySection.map(c=>{let h=I(c),m=ee(h.bookedValue,h.grossRevenue);return{...h,bookedValue:m,grossRevenue:m}}):[];return{...e,bookedValue:o,revenue:o,velocity:{...a,bySection:l}}}function st(i){let e=I(i),t=I(e.report),n=typeof t.includesBookedValue=="boolean"?t.includesBookedValue:t.includesRevenue===!0,s=Array.isArray(t.rows)?t.rows.map(a=>{let l=I(a),c=I(l.attribution),h=Te(c.bookedValue,c.revenue);return{...l,attribution:{...c,bookedValue:h,revenue:h}}}):[],r=I(t.totals),o=Te(r.bookedValue,r.revenue);return{...e,report:{...t,includesBookedValue:n,includesRevenue:n,rows:s,totals:{...r,bookedValue:o,revenue:o}}}}function de(i){let e=I(i),t=typeof e.includesBookedValue=="boolean"?e.includesBookedValue:e.includesRevenue===!0;return{...e,includesBookedValue:t,includesRevenue:t}}var Pe=class{constructor(e,t){this.base=e.replace(/\/+$/,""),this.token=t}setToken(e){this.token=e}auth(e,t={}){let n=t.method??"GET",s={Authorization:`Bearer ${this.token}`},r;return t.body!==void 0&&(s["Content-Type"]="application/json",r=JSON.stringify(t.body)),fetch(`${this.base}${e}`,{method:n,headers:s,body:r,credentials:"omit"}).then(o=>Ie(o))}async authBlob(e){let t=await fetch(`${this.base}${e}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`},credentials:"omit"});return t.ok||await Ie(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 L(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,n={}){let s={labels:t};return typeof n.releaseAt=="number"&&(s.releaseAt=n.releaseAt),n.reason&&(s.reason=n.reason),this.auth(`/v1/events/${encodeURIComponent(e)}/block`,{method:"POST",body:s})}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,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/unbook`,{method:"POST",body:{labels:t,bookingRef:n}})}setHoldTtl(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/hold-ttl`,{method:"POST",body:{holdTtlMs:t}})}setCategory(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/category-assignments`,{method:"POST",body:{labels:t,categoryKey:n}})}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,n,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/table-booking`,{method:"POST",body:{tableIds:t,mode:n,...s}})}bookings(e,t={}){let n=new URLSearchParams;t.q&&n.set("q",t.q),t.state&&n.set("state",t.state),t.cursor&&n.set("cursor",t.cursor),t.limit!=null&&n.set("limit",String(t.limit));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/bookings${s?`?${s}`:""}`)}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 n=t.includeArchived?"?includeArchived=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels${n}`)}channelAllocation(e,t={}){let n=new URLSearchParams;t.afterLabel&&n.set("afterLabel",t.afterLabel),t.limit!=null&&n.set("limit",String(t.limit));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/allocation${s?`?${s}`:""}`)}channelAudit(e,t={}){let n=new URLSearchParams;t.limit!=null&&n.set("limit",String(t.limit)),t.before!=null&&n.set("before",String(t.before));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/audit${s?`?${s}`:""}`)}createChannel(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels`,{method:"POST",body:t})}renameChannel(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{name:n}})}updateChannelPricing(e,t,n,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{priceOverrides:n,expectedPricingVersion:s}})}setChannelPaused(e,t,n){let s=n?"pause":"unpause";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/${s}`,{method:"POST",body:{}})}archiveChannel(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/archive`,{method:"POST",body:{destination:n}})}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,n={}){let s=new URLSearchParams;t.length&&s.set("channelIds",t.join(",")),n.includePublic!=null&&s.set("includePublic",n.includePublic?"1":"0");let r=s.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/preview${r?`?${r}`:""}`)}setChannelAccessIntent(e,t,n,s={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}`,{method:"PATCH",body:{accessIntent:n,...s.acknowledgeLiveAccess?{acknowledgeLiveAccess:!0}:{},...s.reason?{reason:s.reason}:{}}})}createAccessLink(e,t,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`,{method:"POST",body:n})}accessLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links`)}rotateAccessLink(e,t,n,s){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(n)}/rotate`,{method:"POST",body:{endActiveSessions:s}})}revokeAccessLink(e,t,n,s=!1){let r=s?"?endActiveSessions=1":"";return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/access-links/${encodeURIComponent(n)}${r}`,{method:"DELETE"})}report(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/report`).then(tt)}seatHistory(e,t,n,s){let r=new URLSearchParams({label:t});return n&&r.set("before",String(n)),s&&r.set("action",s),this.auth(`/v1/events/${encodeURIComponent(e)}/seat-history?${r}`)}controlRoom(e,t=15){return this.auth(`/v1/events/${encodeURIComponent(e)}/control-room?window=${t}`).then(nt)}channelReport(e){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/report`).then(st)}createChannelReportLink(e,t,n={}){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`,{method:"POST",body:n}).then(s=>{let r=I(s);return{...r,link:de(r.link)}})}channelReportLinks(e,t){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links`).then(n=>{let s=I(n);return{links:Array.isArray(s.links)?s.links.map(de):[]}})}revokeChannelReportLink(e,t,n){return this.auth(`/v1/events/${encodeURIComponent(e)}/channels/${encodeURIComponent(t)}/report-links/${encodeURIComponent(n)}`,{method:"DELETE"}).then(s=>{let r=I(s);return{...r,link:de(r.link)}})}log(e,t={}){let n=new URLSearchParams;t.limit!=null&&n.set("limit",String(t.limit)),t.before!=null&&n.set("before",String(t.before));let s=n.toString();return this.auth(`/v1/events/${encodeURIComponent(e)}/log${s?`?${s}`:""}`)}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 L(t.status,`request_failed_${t.status}`);return t.blob()}};function he(i){return i.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("")}var
|
|
103
|
+
<span class="ico ${e.kind}" aria-hidden="true">${d(e.icon)}</span>
|
|
104
|
+
<span><b>${e.count.toLocaleString()}</b> ${d(e.text.replace(/^[\d,.\s]+/,""))}
|
|
105
|
+
${e.why?`<span class="why">\u2014 ${d(e.why)}</span>`:""}</span>
|
|
106
|
+
${e.peek?`<span class="peek">${d(e.peek)}</span>`:"<span></span>"}
|
|
107
|
+
</div>`).join("")}var He=`
|
|
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 d(i){return String(i??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Be(i){return new Date(i-new Date(i).getTimezoneOffset()*6e4).toISOString().slice(0,16)}function ue(i,e){let t=i.querySelector(e)?.value.trim()??"",n=Number(t);return t!==""&&Number.isInteger(n)?n:null}function Oe(i,e){let t=typeof navigator>"u"?null:navigator.clipboard;return t?.writeText?t.writeText(e).then(()=>!0,()=>De(i,e)):Promise.resolve(De(i,e))}function De(i,e){let t=i.querySelector("[data-ch-lk-sink]");if(t&&typeof document.execCommand=="function")try{t.value=e,t.select(),t.setSelectionRange(0,e.length);let n=document.execCommand("copy");if(t.value="",n)return!0}catch{t.value=""}return it(i),!1}function it(i){let e=i.querySelector("[data-ch-lk-url]");if(e)try{let t=document.createRange();t.selectNodeContents(e);let n=window.getSelection();n?.removeAllRanges(),n?.addRange(t)}catch{}}var at=8,ot="#6e7bff",rt="#b9c0ff",lt={unavailableFill:"#303846",unavailableStroke:"#4b5669",allocationStroke:"#101723",sectionPlate:"rgba(11,16,28,.88)",sectionPlateInk:"#f8fafc"},ct={unavailableFill:"rgba(156,163,175,.55)",unavailableStroke:"rgba(107,114,128,.65)",allocationStroke:"#ffffff",sectionPlate:"rgba(255,255,255,.9)",sectionPlateInk:"#172033"};function dt(i){return i?.dataset?.theme==="light"?ct:lt}function Ne(i){let e=i.canvas,t=i.layer;if(!e||!t)return;let n=i.host.mapLayer.getBoundingClientRect(),s=Math.max(1,Math.round(n.width)),r=Math.max(1,Math.round(n.height)),o=typeof devicePixelRatio=="number"?Math.min(3,Math.max(1,devicePixelRatio)):1;(e.width!==s*o||e.height!==r*o)&&(e.width=s*o,e.height=r*o);let a=i.resolveCtx();if(!a)return;a.setTransform(o,0,0,o,0,0),a.clearRect(0,0,s,r);let l=dt(i.host.root),c=i.host.isSeatDetail(),h=Math.max(3,i.host.seatPixelSize()),m=h/2,C=i.view==="preview"?i.previewProjection:null,p=C?new Set(C.available===!1?[]:C.eligible??[]):null,g=new Map,v=!c&&i.host.sections().length>1?new Map:null,$=i.view==="preview"&&c&&h<=15?new Map:null;for(let u of i.host.seats()){let x=i.host.statusOf(u.label)??"free",f=i.allocation.get(u.label)??E;if(f!==E){let R=g.get(f)??{x:0,y:0,n:0};R.x+=u.x,R.y+=u.y,R.n+=1,g.set(f,R)}if(!c){let R=i.host.sectionOfLabel(u.label),k=R?i.host.worldToScreen({x:u.x,y:u.y}):null;if(v&&R&&k){let T=v.get(R.id)??{label:R.label,minX:k.x,minY:k.y,maxX:k.x,maxY:k.y};T.minX=Math.min(T.minX,k.x),T.minY=Math.min(T.minY,k.y),T.maxX=Math.max(T.maxX,k.x),T.maxY=Math.max(T.maxY,k.y),v.set(R.id,T)}continue}if(x!=="free")continue;let y=null,S=null;if(i.view==="preview"?p?.has(u.label)?(y=ot,S=rt):(y=l.unavailableFill,S=l.unavailableStroke):f!==E&&(y=i.markerFor(f).color,S=l.allocationStroke),!y)continue;let b=i.host.worldToScreen({x:u.x,y:u.y});if(b&&!(b.x<-h||b.y<-h||b.x>s+h||b.y>r+h)){if($){let R=i.host.sectionOfLabel(u.label);if(R){let k=$.get(R.id)??{label:R.label,minX:b.x,minY:b.y,maxX:b.x,maxY:b.y};k.minX=Math.min(k.minX,b.x),k.minY=Math.min(k.minY,b.y),k.maxX=Math.max(k.maxX,b.x),k.maxY=Math.max(k.maxY,b.y),$.set(R.id,k)}}if(a.fillStyle=y,i.view==="preview"||f!==E){let R=Math.max(2,m+Math.min(1.5,m*.06));a.globalAlpha=1,a.beginPath(),a.arc(b.x,b.y,R,0,Math.PI*2),a.fill(),a.strokeStyle=S??y,a.lineWidth=i.view==="preview"?Math.max(1,Math.min(1.75,h*.13)):Math.max(1,Math.min(1.5,h*.1)),a.stroke(),i.view==="preview"&&p?.has(u.label)&&h>=22&&ht(a,u.label,b.x,b.y,R)}else a.globalAlpha=.85,a.fillRect(b.x-m,b.y-m,h,h)}}a.globalAlpha=1,$&>(a,$,l),ut(v,i),bt(g,i,a)}function ht(i,e,t,n,s){let r=s*1.55,o=Math.min(13,Math.max(7,s*.55)),a=6;for(;o>=a&&(i.font=`800 ${o}px var(--slm-font, system-ui, sans-serif)`,!(i.measureText(e).width<=r));)o-=.5;o<a||(i.fillStyle="#ffffff",i.textAlign="center",i.textBaseline="middle",i.fillText(e,t,n))}function ut(i,e){let t=e.layer;if(t&&(t.querySelectorAll(".slm-ch-section-target").forEach(n=>n.remove()),!!i))for(let[n,s]of i){let r=s.maxX-s.minX,o=s.maxY-s.minY;if(r<20||o<20)continue;let a=document.createElement("button");a.type="button",a.className="slm-ch-section-target",a.style.left=`${s.minX-8}px`,a.style.top=`${s.minY-8}px`,a.style.width=`${r+16}px`,a.style.height=`${o+16}px`,a.setAttribute("aria-label",`Open ${s.label} seats`),mt(a,e,()=>e.onSectionTargetClick(n)),t.appendChild(a)}}var _e=4;function pt(i,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:i.pointerId,pointerType:i.pointerType,isPrimary:!0}):new MouseEvent("pointerdown",t)}function qe(i){return i.host.mapLayer.querySelector(".slm-map-host")??i.host.mapLayer}function mt(i,e,t){i.addEventListener("wheel",l=>{let c=qe(e);c!==i&&(l.preventDefault(),c.dispatchEvent(new WheelEvent("wheel",{deltaX:l.deltaX,deltaY:l.deltaY,deltaZ:l.deltaZ,deltaMode:l.deltaMode,clientX:l.clientX,clientY:l.clientY,ctrlKey:l.ctrlKey,shiftKey:l.shiftKey,altKey:l.altKey,metaKey:l.metaKey,bubbles:!0,cancelable:!0,composed:!0})))},{passive:!1});let n=null,s=!1,r=()=>{n=null,e.layer?.classList.remove("panning"),window.removeEventListener("pointermove",o,!0),window.removeEventListener("pointerup",a,!0),window.removeEventListener("pointercancel",a,!0)};function o(l){if(!n||s||Math.abs(l.clientX-n.x)<_e&&Math.abs(l.clientY-n.y)<_e)return;s=!0;let c=n;e.layer?.classList.add("panning");let h=document.elementFromPoint?.(c.x,c.y)??null;(h&&h!==i?h:qe(e)).dispatchEvent(pt(l,c))}function a(){r()}i.addEventListener("pointerdown",l=>{s=!1,n={x:l.clientX,y:l.clientY},window.addEventListener("pointermove",o,!0),window.addEventListener("pointerup",a,!0),window.addEventListener("pointercancel",a,!0)}),i.addEventListener("click",l=>{if(s){s=!1,l.preventDefault(),l.stopPropagation();return}t()})}function gt(i,e,t){for(let n of e.values()){let s=n.maxX-n.minX,r=n.maxY-n.minY;if(s<52||r<26)continue;let o=(n.minX+n.maxX)/2,a=(n.minY+n.maxY)/2,l=Math.max(11,Math.min(15,r*.16));i.font=`800 ${l}px var(--slm-font, system-ui, sans-serif)`;let c=Math.min(s-8,i.measureText(n.label).width+18),h=l+10;i.fillStyle=t.sectionPlate,i.fillRect(o-c/2,a-h/2,c,h),i.fillStyle=t.sectionPlateInk,i.textAlign="center",i.textBaseline="middle",i.fillText(n.label,o,a)}}function bt(i,e,t){let n=e.layer;if(!n||(n.querySelectorAll(".slm-ch-flag").forEach(r=>r.remove()),e.view==="preview"))return;let s=[...i.entries()].sort((r,o)=>o[1].n-r[1].n).slice(0,at);for(let[r,o]of s){let a=e.list?.channels.find(m=>m.id===r);if(!a)continue;let l=e.host.worldToScreen({x:o.x/o.n,y:o.y/o.n});if(!l)continue;let c=e.markerFor(r),h=document.createElement("span");h.className="slm-ch-flag",h.style.left=`${l.x}px`,h.style.top=`${l.y}px`,h.innerHTML=`<span class="mk" style="background:${d(c.color)}">${d(c.letter)}</span>${d(a.name)}${a.state==="paused"?" \xB7 Paused":""}`,n.appendChild(h)}}var vt=`
|
|
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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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 ft=3e4,B=5e3,Ue=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 n={selectionLabels:()=>e.selectionLabels(),selectByLabels:s=>e.selectByLabels(s),clearSelection:()=>e.clearSelection(),selectSection:s=>e.selectSection(s),sections:()=>e.sections(),labelsInSection:s=>e.labelsInSection(s),rows:()=>e.rows(),categories:()=>e.categories(),labelsInCategory:s=>e.labelsInCategory(s),seats:()=>e.seats(),statusOf:s=>e.statusOf(s),sectionOfLabel:s=>e.sectionOfLabel(s),seatMeta:s=>{let r=this.allocation.get(s)??E;return`${this.nameOf(r)??D} \xB7 ${e.statusOf(s)??"free"}`},openDialog:(s,r)=>this.renderScrim(s,r),closeDialog:()=>this.closeDialog(),cap:B};this.chooser=new G(n)}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})},ft),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,n=()=>t!==this.listSeq;try{let s=await this.host.api.channels(this.host.eventKey,{includeArchived:this.showArchived});if(n())return;if(this.list=s,this.assignmentVersion=s.assignmentVersion,this.loadError=null,this.targetChannelId||(this.targetChannelId=s.channels.find(r=>r.state==="active")?.id??E),this.allocationVersion!==s.assignmentVersion){if(await this.loadAllocation(t),n())return;this.allocationVersion=s.assignmentVersion}if(this.detailChannelId&&await this.loadLinks(this.detailChannelId),n())return;this.loading=!1,this.active&&(this.paintRail(),this.paintOverlay())}catch(s){if(n())return;this.loading=!1,s instanceof L&&s.status===403&&(this.caps={view:!1,manage:!1}),this.loadError=s,e.quiet||this.host.onError(s),this.active&&this.paintRail()}}async loadAllocation(e){let t=new Map,n;for(let s=0;s<200;s+=1){if(e!==void 0&&e!==this.listSeq)return;let r=await this.host.api.channelAllocation(this.host.eventKey,{afterLabel:n,limit:1e3});for(let o of r.allocations)H(o.channelId)||t.set(o.label,o.channelId);if(this.assignmentVersion=r.assignmentVersion,!r.nextAfterLabel)break;n=r.nextAfterLabel}e!==void 0&&e!==this.listSeq||(this.allocation=t)}channelById(e){if(H(e))return{id:E,name:this.list?.publicSale?.name??D,marker:"P",color:null};let t=this.list?.channels.find(n=>n.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)??E):null}markerFor(e){let t=Math.max(0,this.list?.channels.findIndex(s=>s.id===e)??0),n=this.channelById(e);return ye(n??{id:e,name:"?",marker:null,color:null},t)}assignableChannels(){return[{id:E,name:this.list?.publicSale.name??D},...(this.list?.channels??[]).filter(e=>e.state!=="archived").map(e=>({id:e.id,name:e.name}))]}currentPlan(){let e=this.host.selectionLabels(),t=we({labels:e,targetChannelId:this.targetChannelId,allocation:this.allocation,statusOf:n=>this.host.statusOf(n),nameOf:n=>this.nameOf(n)});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||
|
|
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(n=>n.remove())}paintOverlay(){let e=this.canvas,t=this.layer;!e||!t||!this.overlayVisible||Ne({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:n=>this.markerFor(n),onSectionTargetClick:n=>{this.focusedSectionId=n,this.host.focusSection(n),this.paintRail()}})}setStaged(e,t=""){let n=this.stagedEl;if(n){if(!e){n.classList.remove("on","done","shake"),n.innerHTML="";return}n.innerHTML=e,n.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 n=this.nameOf(this.targetChannelId)??D,s=Z(t),r=e.length>B,o=t.skippedHeld.count+t.skippedBooked.count,a=[`<b>${e.length.toLocaleString()}</b> selected`,`<b>+${s.toLocaleString()}</b> to ${d(n)}`];t.alreadyInTarget.count&&a.push(`<b>${t.alreadyInTarget.count.toLocaleString()}</b> already in`),o&&a.push(`<b>${o.toLocaleString()}</b> can't move now`),this.setStaged(`
|
|
315
370
|
<span>${a.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"${r?" disabled":""}>
|
|
319
|
-
${r?`Maximum ${
|
|
320
|
-
</button>`),this.stagedEl?.querySelectorAll("[data-ch-act]").forEach(l=>{l.addEventListener("click",()=>{l.dataset.chAct==="discard"?this.host.clearSelection():this.openDialog({kind:"review"})})})}setBanner(e,t="",n){let s=this.bannerEl;if(!s)return;if(this.host.root.classList.toggle("ch-preview",e),!e){s.classList.remove("on"),s.innerHTML="";return}let r=this.previewAudience.length===1?this.markerFor(this.previewAudience[0]):{color:"var(--slm-accent)",letter:""},o=n==null?"":` \xB7 ${n.toLocaleString()} ${n===1?"seat":"seats"} available now`;s.innerHTML=`<span class="dot" style="background:${
|
|
321
|
-
Previewing buyer access \xB7 ${
|
|
322
|
-
<button type="button" data-ch-act="exit-preview">Exit preview</button>`,s.classList.add("on"),s.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(n=>n.state==="active");this.previewAudience=[t?t.id
|
|
374
|
+
${r?`Maximum ${B.toLocaleString()} seats`:"Review changes"}
|
|
375
|
+
</button>`),this.stagedEl?.querySelectorAll("[data-ch-act]").forEach(l=>{l.addEventListener("click",()=>{l.dataset.chAct==="discard"?this.host.clearSelection():this.openDialog({kind:"review"})})})}setBanner(e,t="",n){let s=this.bannerEl;if(!s)return;if(this.host.root.classList.toggle("ch-preview",e),!e){s.classList.remove("on"),s.innerHTML="";return}let r=this.previewAudience.length===1?this.markerFor(this.previewAudience[0]):{color:"var(--slm-accent)",letter:""},o=n==null?"":` \xB7 ${n.toLocaleString()} ${n===1?"seat":"seats"} available now`;s.innerHTML=`<span class="dot" style="background:${d(r.color)}"></span>
|
|
376
|
+
Previewing buyer access \xB7 ${d(t)}${o} \xB7 read-only
|
|
377
|
+
<button type="button" data-ch-act="exit-preview">Exit preview</button>`,s.classList.add("on"),s.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(n=>n.state==="active");this.previewAudience=[t?t.id:E]}this.loadPreview()}this.paintRail(),this.paintOverlay(),this.paintStagedBar(),this.onInteractionChange?.()}async loadPreview(){let e=[...this.previewAudience],t=e.map(n=>this.nameOf(n)??D).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(H)}),this.previewState="ready";let n=this.previewProjection.available===!1?void 0:this.previewProjection.counts?.eligible??this.previewProjection.eligible?.length;this.setBanner(!0,t,n)}catch(n){let s=n instanceof L?n.status:0;this.previewState=s===404||s===405||s===501?"unsupported":"error",this.previewProjection=null,this.previewState==="error"&&this.host.onError(n)}this.active&&(this.paintRail(),this.paintOverlay())}setRailHtml(e){if(e===this.railHtml)return!1;let t=this.host.rail,n=t.scrollTop;return t.innerHTML=e,this.railHtml=e,n&&(t.scrollTop=n),!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,24 +385,24 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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 n=(s,r,o,a="")=>{let l=this.lastCounts.get(`${t}:${s}`),
|
|
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>${d(e)}</span>
|
|
389
|
+
<button type="button" data-ch-act="sections">All sections</button></div>`:""}countsHtml(e,t){let n=(s,r,o,a="")=>{let l=this.lastCounts.get(`${t}:${s}`),c=l!=null&&l!==r?" bump":"";return this.lastCounts.set(`${t}:${s}`,r),`<span class="${a}"><b class="${c.trim()}">${r.toLocaleString()}</b> ${o}</span>`};return`<span class="slm-ch-counts">
|
|
335
390
|
${n("allocated",e.allocated,"allocated")}
|
|
336
391
|
${n("free",e.free,"free","free")}
|
|
337
392
|
${n("booked",e.booked,"sold")}
|
|
338
393
|
${e.held?n("held",e.held,"held"):""}
|
|
339
|
-
</span>`}channelRowHtml(e,t={}){let n=this.markerFor(e.id),s=t.builtin?"builtin":e.state,r=e.state==="paused"||e.state==="archived"?" dim":"",o=!t.builtin&&this.caps.manage&&this.detailChannelId!==e.id,a=`slm-ch-row${t.builtin?" public":""}${e.state==="archived"?" archived":""}${this.detailChannelId===e.id?" on":""}${o?" open":""}`,l=!t.builtin&&this.caps.manage?`<button type="button" class="slm-ch-more" data-ch-menu="${
|
|
340
|
-
aria-label="More actions for ${
|
|
341
|
-
aria-label="Open ${
|
|
394
|
+
</span>`}channelRowHtml(e,t={}){let n=this.markerFor(e.id),s=t.builtin?"builtin":e.state,r=e.state==="paused"||e.state==="archived"?" dim":"",o=!t.builtin&&this.caps.manage&&this.detailChannelId!==e.id,a=`slm-ch-row${t.builtin?" public":""}${e.state==="archived"?" archived":""}${this.detailChannelId===e.id?" on":""}${o?" open":""}`,l=!t.builtin&&this.caps.manage?`<button type="button" class="slm-ch-more" data-ch-menu="${d(e.id)}"
|
|
395
|
+
aria-label="More actions for ${d(e.name)}" aria-haspopup="dialog">\u22EF</button>`:"",c=o?` role="button" tabindex="0" data-ch-open="${d(e.id)}"
|
|
396
|
+
aria-label="Open ${d(e.name)}"`:"";return`<div class="${a}"${c}>
|
|
342
397
|
<span class="slm-ch-head">
|
|
343
|
-
<span class="slm-ch-mk${r}" style="background:${
|
|
344
|
-
<span class="slm-ch-name">${
|
|
345
|
-
<span class="slm-ch-badge ${s}">${
|
|
398
|
+
<span class="slm-ch-mk${r}" style="background:${d(n.color)}" aria-hidden="true">${d(n.letter)}</span>
|
|
399
|
+
<span class="slm-ch-name">${d(e.name)}</span>
|
|
400
|
+
<span class="slm-ch-badge ${s}">${d(Ee(t.builtin?"builtin":e.state))}</span>
|
|
346
401
|
${l}
|
|
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(l=>l.state==="archived").length,n=e.channels.filter(l=>this.showArchived||l.state!=="archived"),s=[this.channelRowHtml(e.publicSale,{builtin:!0}),...n.map((l,
|
|
404
|
+
${t.builtin?"":`<span class="slm-ch-access">${d(Ce(e.access))}</span>`}
|
|
405
|
+
</div>`}listRailHtml(){let e=this.list,t=e.channels.filter(l=>l.state==="archived").length,n=e.channels.filter(l=>this.showArchived||l.state!=="archived"),s=[this.channelRowHtml(e.publicSale,{builtin:!0}),...n.map((l,c)=>this.channelRowHtml(l,{index:c}))].join(""),r=n.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>`,o=this.caps.manage?'<button type="button" class="slm-btn slm-ch-new" data-ch-act="create">+ New channel</button>':"",a=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>${o}</div>
|
|
352
407
|
<div class="slm-ch-list">${s}</div>
|
|
353
408
|
${r}
|
|
@@ -358,36 +413,29 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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(r=>`<option value="${d(r.id)}"${r.id===this.targetChannelId?" selected":""}>${d(r.name)}</option>`).join(""),n=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
|
-
${n}${s}
|
|
371
|
-
<button type="button" class="${r}" 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="${n}" 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=ke(e,this.allocation,this.list),n=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>`:"",s=e.length!==this.lastSelectionCount?" bump":"";this.lastSelectionCount=e.length;let r=e.length>
|
|
382
|
-
<span class="mk" style="background:${
|
|
383
|
-
<b>${a.count.toLocaleString()}</b><span>${
|
|
429
|
+
<button type="button" data-ch-act="refresh-review">Refresh and review \u2192</button></span></div>`:"",s=e.length!==this.lastSelectionCount?" bump":"";this.lastSelectionCount=e.length;let r=e.length>B,o=t.map(a=>{let l=this.markerFor(a.channelId);return`<div class="slm-ch-selsrc-row">
|
|
430
|
+
<span class="mk" style="background:${d(l.color)}" aria-hidden="true">${d(l.letter)}</span>
|
|
431
|
+
<b>${a.count.toLocaleString()}</b><span>${d(a.name)}</span></div>`}).join("");return`
|
|
384
432
|
${n}
|
|
385
433
|
${this.assignmentToolsHtml()}
|
|
386
434
|
<div class="slm-selbar"><span class="slm-selnum slm-ch-selnum${s}">${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">${o}</div>
|
|
389
437
|
${r?`<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 ${B.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>
|
|
@@ -415,40 +463,40 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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 ${d(n.name)}</p>
|
|
419
467
|
<div class="slm-ch-list">${this.channelRowHtml(n)}</div>
|
|
420
468
|
${a}
|
|
421
469
|
${r}
|
|
422
|
-
${s}`}distributeHtml(e){let t=e.access?.intent??"none",n=e.access?.hasActiveGrants===!0,s=this.linksState!=="unsupported",r=this.links.some(
|
|
423
|
-
<b>${
|
|
424
|
-
<span class="why">${
|
|
425
|
-
${
|
|
426
|
-
data-ch-act="${c
|
|
470
|
+
${s}`}distributeHtml(e){let t=e.access?.intent??"none",n=e.access?.hasActiveGrants===!0,s=this.linksState!=="unsupported",r=this.links.some(le),o=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.":n?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.",a=(l,c,h,m)=>{let C=l===t;return`<div class="slm-ch-dist${C?" on":""}" data-ch-route="${d(l)}">
|
|
471
|
+
<b>${d(_(l))}${C?'<span class="cur">Current route</span>':""}</b>
|
|
472
|
+
<span class="why">${d($e(l))}</span>
|
|
473
|
+
${C&&!h?"":`<button type="button" class="slm-btn${m&&!C?"":" ghost"}"
|
|
474
|
+
data-ch-act="${d(c)}">${d(h)}</button>`}
|
|
427
475
|
</div>`};return`
|
|
428
476
|
<p class="slm-eyebrow" style="margin-top:14px">Distribute</p>
|
|
429
|
-
<p class="slm-hint">${
|
|
477
|
+
<p class="slm-hint">${d(o)}</p>
|
|
430
478
|
${s?a("hosted_link","link-create",r?"Create another buyer link":"Create buyer link",!0):""}
|
|
431
479
|
${a("server","embed-code",t==="server"?"Get embed code":"Use a website or app",!1)}
|
|
432
480
|
${a("internal","route-internal",t==="internal"?"":"Hand to your staff",!1)}
|
|
433
481
|
${a("none","route-none",t==="none"?"":"Keep as reserve",!1)}
|
|
434
482
|
${this.hostedLinksHtml()}
|
|
435
|
-
${t==="server"?
|
|
483
|
+
${t==="server"?He:""}`}async loadLinks(e){if(!this.caps.view)return;let t=++this.linksSeq,n=()=>t!==this.linksSeq||this.linksChannelId!==e;this.linksChannelId!==e&&(this.links=[],this.linksChannelId=e,this.linksState="loading");try{let s=await this.host.api.accessLinks(this.host.eventKey,e);if(n())return;this.links=s.links??[],this.linksState="ready"}catch(s){if(n())return;let r=s instanceof L?s.status:0;this.links=[],this.linksState=r===404||r===405||r===501?"unsupported":"error",this.linksState==="error"&&this.host.onError(s)}}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=Ae(e),n=e.maxRedemptions>0?Math.min(100,Math.round(e.redemptions/e.maxRedemptions*100)):0,s=ce(e).map(l=>`<div class="slm-ch-lkrow"><span class="k">${d(l.k)}</span>
|
|
491
|
+
<span class="v">${d(l.v)}</span></div>`).join(""),r=e.activeSessions?`<div class="slm-ch-lkrow"><span class="k">Buyers inside now</span>
|
|
444
492
|
<span class="v">${e.activeSessions.toLocaleString()}</span></div>`:"",o=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">${d(new Date(e.lastRedeemedAt).toLocaleString())}</span></div>`:"",a=this.caps.manage&&le(e)?`<div class="slm-ch-row2">
|
|
494
|
+
<button type="button" class="slm-btn ghost" data-ch-rotate="${d(e.id)}">Rotate</button>
|
|
495
|
+
<button type="button" class="slm-btn ghost" data-ch-revoke="${d(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">${d(e.label||"Buyer link")}</span>
|
|
499
|
+
<span class="slm-ch-badge ${t.kind}">${d(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">
|
|
@@ -457,15 +505,15 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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
507
|
${a}
|
|
460
|
-
</div>`}previewRailHtml(){let e=[{id
|
|
508
|
+
</div>`}previewRailHtml(){let e=[{id:E,name:this.list?.publicSale.name??D},...(this.list?.channels??[]).filter(m=>m.state!=="archived").map(m=>({id:m.id,name:m.name}))],t=this.previewAudience[0]??E,n=e.map(m=>`<option value="${d(m.id)}"${m.id===t?" selected":""}>${d(m.name)}</option>`).join(""),s=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>`:"",r=this.previewState==="loading"?'<div class="slm-ch-busy" role="status" data-ch-state="preview-loading">Asking the server what this audience sees\u2026</div>':"",o=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
513
|
<button type="button" data-ch-act="preview-retry">Try again</button></span></div>`:"",a=this.previewProjection?.available===!1?`<div class="slm-ch-alert warn" role="status"><span>\u23F8</span>
|
|
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>`:"",l=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>`:"",
|
|
514
|
+
<span><b>This private sale is not available.</b> ${d((this.previewProjection.unavailable??[]).map(m=>`${this.nameOf(m.channelId)??"This channel"} is ${m.state}`).join("; ")||"The audience cannot buy right now")}.
|
|
515
|
+
A buyer arriving with this access sees this message, not these seats.</span></div>`:"",l=this.previewProjection?.counts?.eligible??this.previewProjection?.eligible?.length,c=l!=null&&this.previewProjection?.available!==!1?`<div class="slm-ch-alert info"><span>\u2713</span><span><b>${l.toLocaleString()} ${l===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>`:"",h=H(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,7 +523,7 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
475
523
|
<label for="slm-ch-audience">Audience</label>
|
|
476
524
|
<select class="slm-select" id="slm-ch-audience" data-ch-audience>${n}</select>
|
|
477
525
|
</div>
|
|
478
|
-
${
|
|
526
|
+
${h}
|
|
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
529
|
${r}${o}${s}${a}
|
|
@@ -484,74 +532,21 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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(s=>`<option value="${c(s.value)}">${c(s.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>`,s=>{s.querySelector("[data-ch-confirm]")?.addEventListener("click",()=>{let o=s.querySelector("#slm-ch-choice")?.value;this.closeDialog(),o&&n(o)})})}renderScopeDialog(e){let t=e.scope==="rows"?"rows":"sections",s=(t==="sections"?this.host.sections().map(a=>({id:a.id,label:a.label,group:"Sections",labels:this.host.labelsInSection(a.id)})):this.assignmentRows().map(a=>({id:a.id,label:a.label,group:a.sectionLabel,labels:a.labels}))).filter(a=>a.labels.length>0),r=new Map;for(let a of s){let l=r.get(a.group)??[];l.push(a),r.set(a.group,l)}if(t==="rows"){let a=[...r.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>`,l=>{let h=new Map(s.map(p=>[p.id,p])),d=new Set,u=new Set,k=new Set(this.host.selectionLabels()),L=l.querySelector("[data-ch-add-scope]"),v=l.querySelector("[data-ch-error]"),m=l.querySelector("[data-ch-scope-list]"),b=l.querySelector("[data-ch-scope-search]"),w=l.querySelector("[data-ch-scope-summary]"),W=l.querySelector("[data-ch-scope-filter]"),M=200,R="",H=()=>{let p=new Set(k);for(let x of d)for(let T of h.get(x)?.labels??[])p.add(T);return p},f=()=>{let p=H(),x=p.size-k.size,T=p.size>A;L.disabled=x===0||T,L.textContent=T?`Maximum ${A.toLocaleString()} seats`:`Add ${x.toLocaleString()} seat${x===1?"":"s"}`,v.hidden=!T,v.textContent=T?`That would make ${p.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:"",w.textContent=`${d.size.toLocaleString()} row${d.size===1?"":"s"} \xB7 ${x.toLocaleString()} seat${x===1?"":"s"} added`},y=()=>{let p=[],x=0,T=0;a.forEach(([I,S],z)=>{let O=I.toLocaleLowerCase(),_=R?S.filter(E=>`${O} ${E.label.toLocaleLowerCase()}`.includes(R)):S;if(R&&!_.length)return;x+=_.length;let re=S.every(E=>d.has(E.id)),He=!re&&S.some(E=>d.has(E.id)),U=!!R||u.has(z),Be=Math.max(0,M-T),N=U?_.slice(0,Be):[];T+=N.length;let qe=S.reduce((E,Oe)=>E+Oe.labels.length,0);p.push(`<div class="slm-ch-scopegroup">
|
|
512
|
-
<button type="button" class="slm-ch-groupcheck" role="checkbox" aria-checked="${re?"true":He?"mixed":"false"}"
|
|
513
|
-
aria-label="Select all ${S.length.toLocaleString()} rows in ${c(I)}" data-ch-scope-group="${z}">
|
|
514
|
-
<span class="box" aria-hidden="true">\u2713</span><span>${c(I)}</span>
|
|
515
|
-
<span class="meta">${S.length.toLocaleString()} rows \xB7 ${qe.toLocaleString()} seats</span>
|
|
516
|
-
</button>
|
|
517
|
-
<button type="button" class="slm-ch-grouptoggle" aria-expanded="${U}" aria-label="${U?"Hide":"Show"} rows in ${c(I)}"
|
|
518
|
-
data-ch-scope-toggle="${z}">${U?"Hide":"Show"}</button>
|
|
519
|
-
</div>`),p.push(...N.map(E=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
520
|
-
aria-checked="${d.has(E.id)}" data-ch-scope-id="${c(E.id)}">
|
|
521
|
-
<span class="box" aria-hidden="true">\u2713</span><span>${c(E.label)}</span>
|
|
522
|
-
<span class="meta">${E.labels.length.toLocaleString()} seat${E.labels.length===1?"":"s"}</span>
|
|
523
|
-
</button>`)),U&&_.length>N.length&&p.push(`<p class="slm-ch-scopehint">${(_.length-N.length).toLocaleString()} more row${_.length-N.length===1?"":"s"}. Search to narrow the list.</p>`)}),m.innerHTML=p.join("")||(R?`<div class="slm-ch-scope-empty" data-ch-state="scope-nomatch">No sections or rows match \u201C${c(R)}\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>`),W.textContent=R?`Showing ${T.toLocaleString()} of ${x.toLocaleString()} matching rows. Section checkboxes still select every row in that section.`:"Showing section groups. Expand one or search to see rows.",m.querySelectorAll("[data-ch-scope-group]").forEach(I=>I.addEventListener("click",()=>{let S=a[Number(I.dataset.chScopeGroup)]?.[1]??[],z=S.every(O=>d.has(O.id));for(let O of S)z?d.delete(O.id):d.add(O.id);y(),f()})),m.querySelectorAll("[data-ch-scope-toggle]").forEach(I=>I.addEventListener("click",()=>{let S=Number(I.dataset.chScopeToggle);u.has(S)?u.delete(S):u.add(S),y()})),m.querySelectorAll("[data-ch-scope-id]").forEach(I=>I.addEventListener("click",()=>{let S=I.dataset.chScopeId;d.has(S)?d.delete(S):d.add(S),y(),f()}))};b.addEventListener("input",()=>{R=b.value.trim().toLocaleLowerCase(),y(),f()}),L.addEventListener("click",()=>{let p=[...H()];!d.size||p.length>A||(this.closeDialog(),this.host.selectByLabels(p))}),y(),f()});return}let o=[...r.entries()].map(([a,l])=>`
|
|
525
|
-
<div class="slm-ch-seatgroup"><span>${c(a)}</span></div>
|
|
526
|
-
${l.map(h=>`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
527
|
-
aria-checked="false" data-ch-scope-id="${c(h.id)}">
|
|
528
|
-
<span class="box" aria-hidden="true">\u2713</span>
|
|
529
|
-
<span>${c(h.label)}</span>
|
|
530
|
-
<span class="meta">${h.labels.length.toLocaleString()} seat${h.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">${o||`<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>`,a=>{let l=new Map(s.map(m=>[m.id,m])),h=new Set,d=new Set(this.host.selectionLabels()),u=a.querySelector("[data-ch-add-scope]"),k=a.querySelector("[data-ch-error]"),L=()=>{let m=new Set(d);for(let b of h)for(let w of l.get(b)?.labels??[])m.add(w);return m},v=()=>{let m=L(),b=m.size-d.size,w=m.size>A;u.disabled=b===0||w,u.textContent=w?`Maximum ${A.toLocaleString()} seats`:`Add ${b.toLocaleString()} seat${b===1?"":"s"}`,k.hidden=!w,k.textContent=w?`That would make ${m.size.toLocaleString()} selected seats. Choose fewer rows or sections.`:""};a.querySelectorAll("[data-ch-scope-id]").forEach(m=>{m.addEventListener("click",()=>{let b=m.dataset.chScopeId;h.has(b)?h.delete(b):h.add(b),m.setAttribute("aria-checked",String(h.has(b))),v()})}),u.addEventListener("click",()=>{let m=[...L()];!h.size||m.length>A||(this.closeDialog(),this.host.selectByLabels(m))}),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(o=>o.id===e.channelId),n=e.intentTo;if(!t||!n||!this.caps.manage){this.closeDialog();return}let{headline:s,consequences:r}=ye(e.switchBlocked);this.renderScrim(`
|
|
541
|
-
<h3 id="slm-ch-dlg-title">Change how ${c(t.name)} reaches buyers?</h3>
|
|
542
|
-
<p class="sub">${c(s)}</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(o=>{o.addEventListener("click",()=>this.setView(o.dataset.chView))}),e.querySelectorAll("[data-ch-map]").forEach(o=>{o.addEventListener("click",()=>{this.mapIntent=o.dataset.chMap==="assign"?"assign":"pan",this.mapIntent==="assign"&&(this.assignOpen=!0),this.paintRail(),this.onInteractionChange?.()})}),e.querySelectorAll("[data-ch-open]").forEach(o=>{let a=()=>this.openChannel(o.dataset.chOpen);o.addEventListener("click",a),o.addEventListener("keydown",l=>{l.key!=="Enter"&&l.key!==" "&&l.key!=="Spacebar"||(l.preventDefault(),a())})}),e.querySelectorAll("[data-ch-menu]").forEach(o=>{o.addEventListener("click",a=>{a.stopPropagation(),this.openDialog({kind:"menu",channelId:o.dataset.chMenu})}),o.addEventListener("keydown",a=>{a.stopPropagation()})}),e.querySelectorAll("[data-ch-rotate]").forEach(o=>{o.addEventListener("click",()=>this.openDialog({kind:"linkRotate",channelId:this.detailChannelId,linkId:o.dataset.chRotate}))}),e.querySelectorAll("[data-ch-revoke]").forEach(o=>{o.addEventListener("click",()=>this.openDialog({kind:"linkRevoke",channelId:this.detailChannelId,linkId:o.dataset.chRevoke}))});let t=e.querySelector("[data-ch-target]");t?.addEventListener("change",()=>{this.targetChannelId=t.value,this.conflict=!1,this.paintRail()});let n=e.querySelector("[data-ch-audience]");n?.addEventListener("change",()=>{this.previewAudience=[n.value],this.loadPreview()});let s=e.querySelector("[data-ch-includepublic]");s?.addEventListener("change",()=>{this.previewIncludePublic=s.checked,this.loadPreview()}),e.querySelector(".slm-ch-grab")?.addEventListener("click",()=>this.cycleDetent()),e.querySelectorAll("[data-ch-act]").forEach(o=>{o.addEventListener("click",()=>this.railAction(o.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(o=>o.id===e.channelId),n=e.intentTo;if(!t||!n||!this.caps.manage){this.closeDialog();return}let{headline:s,consequences:r}=Re(e.switchBlocked);this.renderScrim(`
|
|
536
|
+
<h3 id="slm-ch-dlg-title">Change how ${d(t.name)} reaches buyers?</h3>
|
|
537
|
+
<p class="sub">${d(s)}</p>
|
|
543
538
|
<div class="slm-ch-alert warn" role="alert"><span>\u26A0</span><span>
|
|
544
|
-
${r.map(o=>`<span style="display:block;margin-bottom:6px">${
|
|
539
|
+
${r.map(o=>`<span style="display:block;margin-bottom:6px">${d(o)}</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"}>${d(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 "${d(_(n))}"`}</button>
|
|
553
548
|
</div>`,o=>{o.querySelector("[data-ch-intent-ack]")?.addEventListener("click",()=>{this.acknowledgeIntentSwitch(n,e.pendingLink??null)})})}async acknowledgeIntentSwitch(e,t){let n=this.detailChannelId;if(!n){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(n,t)}renderScrim(e,t){let n=this.scrimEl;n||(this.lastFocus=document.activeElement??null),n?.remove();let s=document.createElement("div");s.className="slm-ch-scrim",s.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(s),this.scrimEl=s;let r=s.firstElementChild;r.querySelectorAll("[data-ch-close]").forEach(a=>{a.addEventListener("click",()=>this.closeDialog())}),s.addEventListener("keydown",a=>{if(a.key==="Escape"){a.stopPropagation(),this.closeDialog();return}if(a.key!=="Tab")return;let l=[...r.querySelectorAll('summary,button:not([disabled]),select:not([hidden]),input,textarea,a[href],[tabindex]:not([tabindex="-1"])')];if(!l.length)return;let
|
|
549
|
+
aria-labelledby="slm-ch-dlg-title" tabindex="-1">${e}</div>`,this.host.root.appendChild(s),this.scrimEl=s;let r=s.firstElementChild;r.querySelectorAll("[data-ch-close]").forEach(a=>{a.addEventListener("click",()=>this.closeDialog())}),s.addEventListener("keydown",a=>{if(a.key==="Escape"){a.stopPropagation(),this.closeDialog();return}if(a.key!=="Tab")return;let l=[...r.querySelectorAll('summary,button:not([disabled]),select:not([hidden]),input,textarea,a[href],[tabindex]:not([tabindex="-1"])')];if(!l.length)return;let c=l[0],h=l[l.length-1];a.shiftKey&&document.activeElement===c?(a.preventDefault(),h.focus()):!a.shiftKey&&document.activeElement===h&&(a.preventDefault(),c.focus())}),t(r),ge(r),(r.querySelector("input,summary,button")??r).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(s=>O(s.marker||s.name,"")),n=oe("",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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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:${d(n.color)};width:28px;height:28px;font-size:13px">${d(n.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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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"}>${d(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>`,s=>{let r=s.querySelector("#slm-ch-name"),o=s.querySelector("[data-ch-marker]");r.addEventListener("input",()=>{let a=
|
|
574
|
+
</div>`,s=>{let r=s.querySelector("#slm-ch-name"),o=s.querySelector("[data-ch-marker]");r.addEventListener("input",()=>{let a=oe(r.value,t);o.textContent=a.letter,o.style.background=a.color}),s.querySelectorAll("[data-ch-create]").forEach(a=>{a.addEventListener("click",()=>{let l=a.dataset.chCreate==="allocate";this.createChannel(r.value,o.textContent??"",o.style.background,s.querySelector("#slm-ch-ref")?.value??"",l)})})})}async createChannel(e,t,n,s,r){let o=e.trim();if(!o){this.showDialogError("Give the channel a name your team will recognise.");return}try{let a=await this.host.api.createChannel(this.host.eventKey,{name:o,marker:O(t,"")||null,color:n||null,externalRef:s.trim()||null});this.closeDialog(),await this.refresh(),this.targetChannelId=a.channel.id,this.detailChannelId=r?null:a.channel.id,this.announce(`Channel ${o} created with 0 seats allocated.`),this.host.toast(r?`${o} created. Select seats on the map to allocate them.`:`${o} created.`,"ok"),this.paintRail()}catch(a){let l=a instanceof L?a.code:void 0;this.showDialogError(l==="channel_name_taken"?"That name is already used on this event. Pick another.":"Couldn't create the channel. Try again."),this.host.onError(a)}}showDialogError(e){let t=this.scrimEl?.querySelector("[data-ch-error]");t&&(t.textContent=e,t.hidden=!1)}renderReviewDialog(e){let{labels:t,buckets:n}=this.currentPlan(),s=e.applied,r=s?s.buckets:n,o=this.nameOf(s?.targetChannelId??this.targetChannelId)??D,a=Se(r,o),l=s?s.applied:Z(n),c=!s&&t.length>0&&l===0,h=!s&&t.length>B,m=he(a),C=s?'<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 ${h||
|
|
576
|
+
<button type="button" class="slm-btn" data-ch-apply ${c||h||e.busy?"disabled":""}>
|
|
582
577
|
${e.busy?"Applying\u2026":`Apply ${l.toLocaleString()} change${l===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">${s?`Moved ${s.applied.toLocaleString()} seat${s.applied===1?"":"s"} to ${
|
|
579
|
+
</div>`,p=!s&&xe(n)?'<p class="slm-note">Applying moves inventory out of another private channel. That is the line marked above.</p>':"",g=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 ${d(o)}.</span></div>`:"",v=h?`<div class="slm-ch-alert warn" role="alert"><span>\u2139</span><span><b>Choose fewer seats.</b>
|
|
581
|
+
One Apply can cover at most ${B.toLocaleString()} seats.</span></div>`:"";this.renderScrim(`
|
|
582
|
+
<h3 id="slm-ch-dlg-title">${s?`Moved ${s.applied.toLocaleString()} seat${s.applied===1?"":"s"} to ${d(o)}`:`Move ${t.length.toLocaleString()} selected seat${t.length===1?"":"s"} to ${d(o)}`}</h3>
|
|
588
583
|
<p class="sub">${s?"These are the exact counts the server applied.":"Every selected seat is in exactly one line below."}</p>
|
|
584
|
+
${g}
|
|
589
585
|
${v}
|
|
590
|
-
${m}
|
|
591
|
-
${
|
|
592
|
-
${
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
<span>Assigned <b>${e.applied.toLocaleString()}</b> seat${e.applied===1?"":"s"} to ${c(t)}
|
|
586
|
+
${m||'<div class="slm-empty">Nothing selected.</div>'}
|
|
587
|
+
${p}
|
|
588
|
+
<p class="slm-ch-err" data-ch-error ${e.error?"":"hidden"}>${d(e.error??"")}</p>
|
|
589
|
+
${C}`,$=>{$.querySelector("[data-ch-apply]")?.addEventListener("click",()=>{this.apply()})}),s&&this.announce(`Applied ${s.applied} change${s.applied===1?"":"s"} to ${o}.`)}async apply(){if(!this.dialog||!this.caps.manage)return;let{labels:e}=this.currentPlan();if(e.length){if(e.length>B){this.showDialogError(`Choose at most ${B.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:H(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 L&&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 L&&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)??D,n=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 ${d(t)}
|
|
596
591
|
${n?` \xB7 ${n.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}${n?`; ${n} 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(s=>s.id===e.channelId);if(!t||!this.caps.manage){this.closeDialog();return}let n=t.state==="paused";this.renderScrim(`
|
|
599
|
-
<h3 id="slm-ch-dlg-title">${
|
|
594
|
+
<h3 id="slm-ch-dlg-title">${d(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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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>`,s=>{s.querySelectorAll("[data-ch-menu-act]").forEach(r=>{r.addEventListener("click",()=>{let o=r.dataset.chMenuAct;if(o==="open"){this.closeDialog(),this.openChannel(t.id);return}if(o==="rename"){this.openDialog({kind:"rename",channelId:t.id});return}if(o==="archive"){this.openDialog({kind:"archive",channelId:t.id});return}this.closeDialog(),this.togglePause(t.id)})})})}renderRenameDialog(e){let t=this.list?.channels.find(n=>n.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 ${d(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="${d(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"}>${d(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>`,n=>{n.querySelector("[data-ch-rename]")?.addEventListener("click",()=>{let s=n.querySelector("#slm-ch-newname")?.value??"";if(!s.trim()){this.showDialogError("A channel needs a name.");return}this.host.api.renameChannel(this.host.eventKey,t.id,s.trim()).then(()=>(this.closeDialog(),this.refresh())).catch(r=>{this.showDialogError(r instanceof
|
|
623
|
-
<span><b>${
|
|
617
|
+
</div>`,n=>{n.querySelector("[data-ch-rename]")?.addEventListener("click",()=>{let s=n.querySelector("#slm-ch-newname")?.value??"";if(!s.trim()){this.showDialogError("A channel needs a name.");return}this.host.api.renameChannel(this.host.eventKey,t.id,s.trim()).then(()=>(this.closeDialog(),this.refresh())).catch(r=>{this.showDialogError(r instanceof L&&r.code==="channel_name_taken"?"That name is already used on this event.":"Couldn't rename the channel."),this.host.onError(r)})})})}renderPricingDialog(e){let t=this.list?.channels.find(o=>o.id===e.channelId),n=this.host.api.updateChannelPricing;if(!t||!n||!this.caps.manage){this.closeDialog();return}let s=new Map((t.priceOverrides??[]).map(o=>[`${o.categoryKey}\0${o.tierId??""}`,o.price])),r=this.host.categories().flatMap(o=>(o.tiers?.length?o.tiers:[null]).map(l=>{let c=l?.id??null,h=`${o.key}\0${c??""}`,m=l?.price??o.price??0,C=s.get(h),p=l?`${o.label} \xB7 ${l.name}`:o.label;return`<label class="slm-ch-price-row">
|
|
618
|
+
<span><b>${d(p)}</b><small>Event price ${d(String(m))}</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 ${d(p)}"
|
|
621
|
+
data-ch-price-category="${d(o.key)}" data-ch-price-tier="${d(c??"")}"
|
|
622
|
+
placeholder="${d(String(m))}" value="${C===void 0?"":d(String(C))}"
|
|
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 ${d(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">${r||'<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"}>${d(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||!r?"disabled":""}>
|
|
637
632
|
${e.busy?"Saving\u2026":"Save prices"}
|
|
638
633
|
</button>
|
|
639
|
-
</div>`,o=>{o.querySelector("[data-ch-price-save]")?.addEventListener("click",()=>{let a=[];for(let l of o.querySelectorAll("[data-ch-price-category]")){let
|
|
634
|
+
</div>`,o=>{o.querySelector("[data-ch-price-save]")?.addEventListener("click",()=>{let a=[];for(let l of o.querySelectorAll("[data-ch-price-category]")){let c=l.value.trim();if(!c)continue;let h=Number(c);if(!Number.isFinite(h)||h<0||h>1e6){l.focus(),this.showDialogError("Enter a price from 0 to 1,000,000, or leave the field blank.");return}a.push({categoryKey:l.dataset.chPriceCategory,tierId:l.dataset.chPriceTier||null,price:h})}this.saveChannelPricing(t,a)})})}async saveChannelPricing(e,t){let n=this.host.api.updateChannelPricing;if(!(!n||!this.dialog||this.dialog.kind!=="pricing")){this.dialog={...this.dialog,busy:!0,error:null},this.renderDialog();try{await n.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(s){if(s instanceof L&&s.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:s instanceof L&&s.serverMessage?s.serverMessage:"Couldn't save these prices. Try again."},this.renderDialog(),this.host.onError(s)}}}async chooseWebsiteIntegration(){this.detailChannelId&&await this.setAccessIntent("server")}async setAccessIntent(e,t={}){let n=this.detailChannelId;if(!n||!this.caps.manage)return!1;try{let s=await this.host.api.setChannelAccessIntent(this.host.eventKey,n,e,t);return await this.refresh(),this.host.toast(this.intentSavedCopy(e,s?.intentSwitch),"ok"),!0}catch(s){return s instanceof L&&s.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:n,intentTo:e,switchBlocked:s.details}),!1):s instanceof L&&s.code==="channel_access_intent_forbids"?(this.host.toast(J(s.details),"err"),!1):(this.host.toast("Couldn't change how this channel reaches buyers.","err"),this.host.onError(s),!1)}}intentSavedCopy(e,t){let n=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 n;let s=t.closedLinks?` ${t.closedLinks.toLocaleString()} buyer link${t.closedLinks===1?"":"s"} closed.`:"",r=t.keptSessions?` ${t.keptSessions.toLocaleString()} buyer${t.keptSessions===1?"":"s"} already in a checkout can still finish.`:"";return`${n}${s}${r}`}async togglePause(e=this.detailChannelId){let t=this.list?.channels.find(s=>s.id===e);if(!t||!this.caps.manage)return;let n=t.state!=="paused";try{await this.host.api.setChannelPaused(this.host.eventKey,t.id,n),await this.refresh(),this.host.toast(n?`${t.name} paused. Existing checkouts can finish; no new buyer access is issued.`:`${t.name} resumed.`,"ok")}catch(s){this.host.toast("Couldn't change that channel.","err"),this.host.onError(s)}}renderArchiveDialog(e){let t=this.list?.channels.find(a=>a.id===e.channelId);if(!t){this.closeDialog();return}let n=e.archiveBlocked??null,s=!n&&t.counts.held>0,r=this.assignableChannels().filter(a=>a.id!==t.id),o=n?`<div class="slm-ch-alert warn" role="alert"><span>\u23F3</span>
|
|
640
635
|
<span><b>${(n.heldUnits??n.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 ${d(Le(n))}.</span></div>`:s?`<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 ${d(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
|
${o}
|
|
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
|
-
${r.map(a=>`<option value="${
|
|
646
|
+
${r.map(a=>`<option value="${d(a.id)}">${d(a.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 "${d(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"}>${d(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 ${n?"disabled":""}>Archive channel</button>
|
|
661
|
-
</div>`,a=>{a.querySelector("[data-ch-archive]")?.addEventListener("click",()=>{let l=a.querySelector("#slm-ch-dest")?.value??"";this.archive(t.id,l||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(n){if(n instanceof
|
|
662
|
-
<
|
|
663
|
-
<span>${c(o.label)}</span>
|
|
664
|
-
${r?`<button type="button" data-ch-section="${c(r)}">Select section</button>`:""}
|
|
665
|
-
</div>
|
|
666
|
-
${o.seats.map(a=>{let l=this.allocation.get(a.label)??$,h=this.nameOf(l)??P;return`<button type="button" class="slm-ch-seatitem" role="checkbox"
|
|
667
|
-
aria-checked="${e.has(a.label)}" data-ch-seat="${c(a.label)}">
|
|
668
|
-
<span class="box" aria-hidden="true">\u2713</span>
|
|
669
|
-
<span>${c(a.label)}</span>
|
|
670
|
-
<span class="meta">${c(h)} \xB7 ${c(a.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">${s||'<div class="slm-empty">No seats on this chart.</div>'}</div>
|
|
675
|
-
${n>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>`,r=>{r.querySelectorAll("[data-ch-seat]").forEach(o=>{o.addEventListener("click",()=>{let a=o.dataset.chSeat,l=new Set(this.host.selectionLabels());l.has(a)?l.delete(a):l.add(a),this.host.clearSelection(),l.size&&this.host.selectByLabels([...l]),this.renderSeatListDialog()})}),r.querySelectorAll("[data-ch-section]").forEach(o=>{o.addEventListener("click",()=>{this.host.selectSection(o.dataset.chSection),this.renderSeatListDialog()})}),r.querySelector("[data-ch-more]")?.addEventListener("click",()=>{this.seatListLimit+=De,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(n=>n.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 ${c(t.name)}</h3>
|
|
656
|
+
</div>`,a=>{a.querySelector("[data-ch-archive]")?.addEventListener("click",()=>{let l=a.querySelector("#slm-ch-dest")?.value??"";this.archive(t.id,l||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(n){if(n instanceof L&&n.status===409&&n.code==="channel_archive_blocked_by_holds"){this.dialog={kind:"archive",channelId:e,archiveBlocked:n.details??{}},this.renderDialog();return}this.showDialogError("Couldn't archive that channel. Try again."),this.host.onError(n)}}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(n=>n.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 ${d(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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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="${re.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="${re.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"}>${d(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>`,n=>{let s=n.querySelector("[data-ch-lk-expiry]"),r=n.querySelector("[data-ch-lk-when-field]"),o=n.querySelector("#slm-ch-lk-when");s.addEventListener("change",()=>{let a=s.value==="custom";r.hidden=!a,a&&!o.value&&(o.value=
|
|
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>`:"",r=
|
|
717
|
-
<span class="v">${
|
|
695
|
+
</div>`,n=>{let s=n.querySelector("[data-ch-lk-expiry]"),r=n.querySelector("[data-ch-lk-when-field]"),o=n.querySelector("#slm-ch-lk-when");s.addEventListener("change",()=>{let a=s.value==="custom";r.hidden=!a,a&&!o.value&&(o.value=Be(Date.now()+7*864e5))}),n.querySelector("[data-ch-lk-create]")?.addEventListener("click",()=>{let a=ue(n,"#slm-ch-lk-redemptions"),l=ue(n,"#slm-ch-lk-quantity");if(a==null||l==null){this.showDialogError("Those two settings need to be whole numbers.");return}let c;if(s.value==="custom"&&(c=Date.parse(o.value),!Number.isFinite(c))){this.showDialogError("Pick the date and time the link should stop working.");return}this.createLink(t.id,{label:n.querySelector("#slm-ch-lk-label")?.value.trim()||null,includePublic:n.querySelector("#slm-ch-lk-public")?.checked??!1,...c===void 0?{}:{expiresAt:c},maxRedemptions:a,maxQuantity:l})})})}async createLink(e,t){await this.ensureHostedLinkRoute(e,t)&&await this.mintLink(e,t)}async mintLink(e,t){try{let n=await this.host.api.createAccessLink(this.host.eventKey,e,t);this.revealLink(n,{channelId:e}),await this.reloadAfterLinkChange(e)}catch(n){this.showDialogError(j(n instanceof L?n:void 0)),n instanceof L||this.host.onError(n)}}async ensureHostedLinkRoute(e,t){if((this.list?.channels.find(s=>s.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(s){return s instanceof L&&s.code==="channel_intent_switch_blocked"?(this.openDialog({kind:"intentSwitch",channelId:e,intentTo:"hosted_link",switchBlocked:s.details,pendingLink:t}),!1):(this.showDialogError(s instanceof L&&s.code==="channel_access_intent_forbids"?J(s.details):"Couldn't set this channel up for buyer links. Try again."),s instanceof L||this.host.onError(s),!1)}}revealLink(e,t){let n=e.url;this.dialog=null;let s=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>`:"",r=ce(e.link).map(o=>`<div class="slm-ch-lkrow"><span class="k">${d(o.k)}</span>
|
|
697
|
+
<span class="v">${d(o.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
|
${s}
|
|
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="${d(n)}">${d(n)}</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 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
731
711
|
${r}
|
|
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>`,o=>{let a=o.querySelector("[data-ch-lk-copy]"),l=null;a?.addEventListener("click",()=>{
|
|
714
|
+
</div>`,o=>{let a=o.querySelector("[data-ch-lk-copy]"),l=null;a?.addEventListener("click",()=>{Oe(o,n).then(c=>{if(!c){a.textContent="Copy",a.classList.remove("copied"),this.announce("Copying was blocked. The link is selected \u2014 copy it by hand.");return}a.textContent="Copied",a.classList.add("copied"),this.announce("Buyer link copied."),l&&clearTimeout(l),l=setTimeout(()=>{a.textContent="Copy",a.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 n=t.activeSessions??0,s=n?`<div class="slm-ch-alert warn"><span>\u26A0</span>
|
|
735
715
|
<span><b>${n.toLocaleString()} buyer${n===1?"":"s"}</b> got in with the current link
|
|
736
716
|
and still ${n===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 ${d(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
|
${s}
|
|
@@ -749,12 +729,12 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
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"}>${d(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>`,r=>{let o=r.querySelector("[data-ch-lk-rotate]");r.querySelectorAll("[data-ch-rot]").forEach(a=>{a.addEventListener("change",()=>{o.disabled=!1})}),o.addEventListener("click",()=>{let a=[...r.querySelectorAll("[data-ch-rot]")].find(l=>l.checked);if(!a){this.showDialogError(
|
|
757
|
-
<h3 id="slm-ch-dlg-title">Revoke the ${
|
|
736
|
+
</div>`,r=>{let o=r.querySelector("[data-ch-lk-rotate]");r.querySelectorAll("[data-ch-rot]").forEach(a=>{a.addEventListener("change",()=>{o.disabled=!1})}),o.addEventListener("click",()=>{let a=[...r.querySelectorAll("[data-ch-rot]")].find(l=>l.checked);if(!a){this.showDialogError(j({code:"end_active_sessions_required"}));return}this.rotateLink(e.channelId,t.id,a.value==="end")})})}async rotateLink(e,t,n){try{let s=await this.host.api.rotateAccessLink(this.host.eventKey,e,t,n);this.revealLink(s,{channelId:e,rotated:!0}),await this.reloadAfterLinkChange(e)}catch(s){this.showDialogError(j(s instanceof L?s:void 0)),s instanceof L||this.host.onError(s)}}renderLinkRevokeDialog(e){let t=this.linkById(e.linkId);if(!t||!this.caps.manage){this.closeDialog();return}let n=t.activeSessions??0;this.renderScrim(`
|
|
737
|
+
<h3 id="slm-ch-dlg-title">Revoke the ${d(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
|
${n?`<label class="slm-ch-radio">
|
|
@@ -763,8 +743,8 @@ function le(i){i.querySelectorAll("select:not([data-themed])").forEach(e=>{e.dat
|
|
|
763
743
|
buyer${n===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"}>${d(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>`,s=>{s.querySelector("[data-ch-lk-revoke]")?.addEventListener("click",()=>{let r=s.querySelector("[data-ch-lk-endsessions]")?.checked??!1;this.revokeLink(e.channelId,t.id,r)})})}async revokeLink(e,t,n){try{let s=await this.host.api.revokeAccessLink(this.host.eventKey,e,t,n);this.closeDialog(),await this.reloadAfterLinkChange(e),this.host.toast(s.endedSessions?`Link revoked. ${s.endedSessions.toLocaleString()} buyer${s.endedSessions===1?"":"s"} lost access.`:"Link revoked. It no longer opens for anyone.","ok")}catch(s){this.showDialogError(
|
|
750
|
+
</div>`,s=>{s.querySelector("[data-ch-lk-revoke]")?.addEventListener("click",()=>{let r=s.querySelector("[data-ch-lk-endsessions]")?.checked??!1;this.revokeLink(e.channelId,t.id,r)})})}async revokeLink(e,t,n){try{let s=await this.host.api.revokeAccessLink(this.host.eventKey,e,t,n);this.closeDialog(),await this.reloadAfterLinkChange(e),this.host.toast(s.endedSessions?`Link revoked. ${s.endedSessions.toLocaleString()} buyer${s.endedSessions===1?"":"s"} lost access.`:"Link revoked. It no longer opens for anyone.","ok")}catch(s){this.showDialogError(j(s instanceof L?s:void 0)),s instanceof L||this.host.onError(s)}}applySheetClasses(){let e=this.host.root,t=this.host.isCompact();e.classList.toggle("ch-sheet",t&&this.active);for(let n of["collapsed","medium","full"])e.classList.toggle(`detent-${n}`,t&&this.active&&this.detent===n);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}};export{ge as a,yt as b,L as c,Pe as d,St as e,Lt as f,Ct as g,$t as h,Rt as i,At as j,V as k,Et as l,It as m,Tt as n,Pt as o,Mt as p,Dt as q,w as r,We as s,Ot as t,G as u,E as v,D as w,H as x,O as y,oe as z,ye as A,ke as B,we as C,Z as D,xe as E,Se as F,Le as G,Ce as H,_ as I,$e as J,J as K,Re as L,re as M,Ae as N,le as O,ce as P,j as Q,qt as R,Ee as S,he as T,vt as U,Ue as V};
|