@zonetrix/viewer 2.10.3 → 2.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),t=require("react"),X=require("react-konva"),W=require("firebase/database"),it=require("@zonetrix/shared");function Ce(n){const[s,i]=t.useState(null),[r,h]=t.useState(!1),[u,o]=t.useState(null),w=async()=>{if(n){h(!0),o(null);try{const p=await fetch(n);if(!p.ok)throw new Error(`Failed to fetch config: ${p.statusText}`);const l=await p.json();i(l)}catch(p){const l=p instanceof Error?p:new Error("Unknown error occurred");o(l),console.error("Failed to fetch seat map config:",l)}finally{h(!1)}}};return t.useEffect(()=>{w()},[n]),{config:s,loading:r,error:u,refetch:w}}function Re(n){const[s,i]=t.useState({width:0,height:0});return t.useEffect(()=>{const r=n.current;if(!r)return;const{width:h,height:u}=r.getBoundingClientRect();h>0&&u>0&&i({width:h,height:u});const o=new ResizeObserver(w=>{const p=w[0];if(!p)return;const{width:l,height:c}=p.contentRect;l>0&&c>0&&i(f=>f.width===l&&f.height===c?f:{width:l,height:c})});return o.observe(r),()=>{o.disconnect()}},[n]),s}function ye(n,s){return Math.sqrt(Math.pow(s.x-n.x,2)+Math.pow(s.y-n.y,2))}function me(n,s){return{x:(n.x+s.x)/2,y:(n.y+s.y)/2}}function je(n,s){const i=t.useRef(null),r=t.useRef(null),h=t.useRef(1);t.useEffect(()=>{const u=n.current;if(!u||!s.enabled)return;const o=u.container(),w=c=>{if(c.touches.length===2){c.preventDefault();const f={x:c.touches[0].clientX,y:c.touches[0].clientY},b={x:c.touches[1].clientX,y:c.touches[1].clientY};i.current=ye(f,b),r.current=me(f,b),h.current=s.currentScale}},p=c=>{if(c.touches.length!==2)return;c.preventDefault();const f={x:c.touches[0].clientX,y:c.touches[0].clientY},b={x:c.touches[1].clientX,y:c.touches[1].clientY},g=ye(f,b),x=me(f,b);if(i.current!==null&&r.current!==null){const C=g/i.current,j=Math.min(Math.max(s.currentScale*C,s.minScale),s.maxScale),E=o.getBoundingClientRect(),M=x.x-E.left,F=x.y-E.top,z=s.currentScale,L={x:(M-s.currentPosition.x)/z,y:(F-s.currentPosition.y)/z},D=x.x-r.current.x,N=x.y-r.current.y,ee={x:M-L.x*j+D,y:F-L.y*j+N};s.onScaleChange(j,ee),i.current=g,r.current=x}},l=c=>{c.touches.length<2&&(i.current=null,r.current=null)};return o.addEventListener("touchstart",w,{passive:!1}),o.addEventListener("touchmove",p,{passive:!1}),o.addEventListener("touchend",l),()=>{o.removeEventListener("touchstart",w),o.removeEventListener("touchmove",p),o.removeEventListener("touchend",l)}},[n,s])}const Me={canvasBackground:"#1a1a1a",stageColor:"#808080",seatAvailable:"#2C2B30",seatReserved:"#FCEA00",seatSelected:"#3A7DE5",seatUnavailable:"#6b7280",seatHidden:"#4a4a4a",gridLines:"#404040",currency:"KD"},Ee=t.memo(({seat:n,state:s,colors:i,onClick:r,onMouseEnter:h,onMouseLeave:u})=>{const p={available:i.seatAvailable,reserved:i.seatReserved,selected:i.seatSelected,unavailable:i.seatUnavailable,hidden:i.seatHidden}[s],l=s==="available"||s==="selected",c=t.useCallback(()=>{l&&r(n)},[n,r,l]),f=t.useCallback(x=>{h(n,x);const C=x.target.getStage();C&&l&&(C.container().style.cursor="pointer")},[n,h,l]),b=t.useCallback(x=>{u();const C=x.target.getStage();C&&(C.container().style.cursor="grab")},[u]),g={x:n.position.x,y:n.position.y,fill:p,stroke:"#ffffff",strokeWidth:1,onClick:c,onTap:c,onMouseEnter:f,onMouseLeave:b};return n.shape==="circle"?a.jsx(X.Circle,{...g,radius:12}):a.jsx(X.Rect,{...g,width:24,height:24,offsetX:12,offsetY:12,cornerRadius:n.shape==="square"?0:4})});Ee.displayName="ViewerSeat";const Fe=t.memo(({stage:n,stageColor:s})=>{const i=u=>({stage:"🎭",table:"⬜",wall:"▬",barrier:"🛡️","dj-booth":"🎵",bar:"🍷","entry-exit":"🚪",custom:"➕"})[u||"stage"]||"🎭",r=n.config.color||s,h=i(n.config.objectType);return a.jsxs(X.Group,{x:n.position.x,y:n.position.y,rotation:n.config.rotation||0,children:[a.jsx(X.Rect,{width:n.config.width,height:n.config.height,fill:r+"80",stroke:"#ffffff",strokeWidth:2,cornerRadius:10}),a.jsx(X.Text,{text:h,x:0,y:0,width:n.config.width,height:n.config.height*.4,fontSize:32,fill:"#ffffff",align:"center",verticalAlign:"middle"}),a.jsx(X.Text,{text:n.config.label,x:0,y:n.config.height*.4,width:n.config.width,height:n.config.height*.6,fontSize:20,fontStyle:"bold",fill:"#ffffff",align:"center",verticalAlign:"middle"})]})});Fe.displayName="ViewerStage";const ke=t.memo(({floors:n,currentFloorId:s,onFloorChange:i,showAllOption:r,allLabel:h,position:u,className:o})=>{const w=t.useMemo(()=>[...n].sort((b,g)=>b.order-g.order),[n]),l={position:"absolute",display:"flex",alignItems:"center",gap:"8px",padding:"8px 12px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[u]},c={padding:"10px 16px",fontSize:"14px",fontWeight:500,border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",transition:"all 0.2s ease",minHeight:"44px",touchAction:"manipulation"},f={...c,backgroundColor:"#3A7DE5",borderColor:"#3A7DE5"};return a.jsxs("div",{className:o,style:l,children:[r&&a.jsx("button",{type:"button",onClick:()=>i(null),style:s===null?f:c,children:h}),w.map(b=>a.jsx("button",{type:"button",onClick:()=>i(b.id),style:s===b.id?f:c,children:b.name},b.id))]})});ke.displayName="FloorSelectorBar";const Ie=t.memo(({scale:n,minScale:s,maxScale:i,onZoomIn:r,onZoomOut:h,position:u,className:o})=>{const p={position:"absolute",display:"flex",flexDirection:"column",gap:"4px",padding:"8px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[u]},l={width:"44px",height:"44px",minWidth:"44px",minHeight:"44px",fontSize:"22px",fontWeight:"bold",border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s ease",touchAction:"manipulation"},c={...l,opacity:.4,cursor:"not-allowed"},f=n<i,b=n>s;return a.jsxs("div",{className:o,style:p,children:[a.jsx("button",{type:"button",onClick:r,disabled:!f,style:f?l:c,title:"Zoom In",children:"+"}),a.jsx("button",{type:"button",onClick:h,disabled:!b,style:b?l:c,title:"Zoom Out",children:"−"})]})});Ie.displayName="ZoomControls";const Le=t.memo(({visible:n,x:s,y:i,seat:r,currency:h,state:u})=>{if(!n||!r)return null;const o=r.seatNumber||(r.rowLabel&&r.columnLabel?`${r.rowLabel}-${r.columnLabel}`:"N/A"),w={position:"fixed",left:`${s+15}px`,top:`${i+15}px`,zIndex:1e3,pointerEvents:"none"},p={backgroundColor:"rgba(26, 26, 26, 0.95)",color:"#fff",border:"1px solid #444",borderRadius:"8px",padding:"8px 12px",fontSize:"13px",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.3)",minWidth:"140px"},l={color:"#9ca3af",marginRight:"4px"},c={fontWeight:600},f={color:"#4ade80",fontWeight:600},b={fontSize:"11px",color:"#6b7280",textTransform:"capitalize",marginTop:"4px"};return a.jsx("div",{style:w,children:a.jsxs("div",{style:p,children:[r.sectionName&&a.jsxs("div",{style:{marginBottom:"4px"},children:[a.jsx("span",{style:l,children:"Section:"}),a.jsx("span",{style:{...c,color:"#3b82f6"},children:r.sectionName})]}),a.jsxs("div",{style:{marginBottom:"4px"},children:[a.jsx("span",{style:l,children:"Seat:"}),a.jsx("span",{style:c,children:o})]}),r.price!==void 0&&r.price>0&&u==="available"&&a.jsxs("div",{style:{marginBottom:"4px"},children:[a.jsx("span",{style:l,children:"Price:"}),a.jsxs("span",{style:f,children:[h," ",r.price.toFixed(2)]})]}),a.jsxs("div",{style:b,children:["Status: ",u]})]})})});Le.displayName="SeatTooltip";const at=({config:n,configUrl:s,floorId:i,onFloorChange:r,reservedSeats:h=[],unavailableSeats:u=[],selectedSeats:o,myReservedSeats:w=[],onSeatSelect:p,onSeatDeselect:l,onSelectionChange:c,colorOverrides:f,showTooltip:b=!0,zoomEnabled:g=!0,className:x="",onConfigLoad:C,onError:j,showFloorSelector:E,floorSelectorPosition:M="top-left",floorSelectorClassName:F,showAllFloorsOption:z=!0,allFloorsLabel:L="All",fitToView:D=!0,fitPadding:N=40,showZoomControls:ee=!0,zoomControlsPosition:ze="bottom-right",zoomControlsClassName:Ne,minZoom:be,maxZoom:Y=3,zoomStep:te=.25,touchEnabled:Ae=!0})=>{const ue=t.useRef(null),xe=t.useRef(null),k=Re(xe),[$,Se]=t.useState(new Set),[I,H]=t.useState(1),[T,B]=t.useState({x:0,y:0}),[Xe,Ye]=t.useState(null),[Pe,We]=t.useState(1),ne=t.useRef({width:0,height:0}),[q,ve]=t.useState({visible:!1,x:0,y:0,seat:null,state:"available"}),{config:Be,loading:Ue,error:_}=Ce(s),S=n||Be,de=i!==void 0,A=de?i||null:Xe,se=o!==void 0,$e=t.useCallback(e=>{de||Ye(e),r?.(e)},[de,r]),he=S?.floors||[],Oe=E!==void 0?E:he.length>1,re=t.useMemo(()=>S?{...S.colors,...f}:{...Me,...f},[S,f]),O=t.useMemo(()=>{if(!S)return[];let e=S.seats.filter(d=>d.state!=="hidden");return A&&(e=e.filter(d=>d.floorId===A||!d.floorId&&A==="floor_default")),e},[S,A]),oe=t.useMemo(()=>S?.stages?A?S.stages.filter(e=>e.floorId===A||!e.floorId&&A==="floor_default"):S.stages:[],[S,A]),P=t.useMemo(()=>{if(!S||O.length===0&&oe.length===0)return null;const e=12;let d=1/0,v=1/0,y=-1/0,m=-1/0;return O.forEach(R=>{d=Math.min(d,R.position.x-e),v=Math.min(v,R.position.y-e),y=Math.max(y,R.position.x+e),m=Math.max(m,R.position.y+e)}),oe.forEach(R=>{d=Math.min(d,R.position.x),v=Math.min(v,R.position.y),y=Math.max(y,R.position.x+(R.config?.width||200)),m=Math.max(m,R.position.y+(R.config?.height||100))}),{minX:d,minY:v,maxX:y,maxY:m,width:y-d,height:m-v}},[S,O,oe]);t.useEffect(()=>{if(!D||!S||!P||k.width===0||k.height===0)return;const e=Math.abs(k.width-ne.current.width),d=Math.abs(k.height-ne.current.height);if(!(ne.current.width===0)&&e<10&&d<10)return;ne.current=k;const y=k.width,m=k.height,R=y-N*2,Z=m-N*2,ie=R/P.width,ge=Z/P.height,ae=Math.min(ie,ge,Y),et=P.minX+P.width/2,tt=P.minY+P.height/2,nt=y/2,st=m/2,rt=nt-et*ae,ot=st-tt*ae;H(ae),B({x:rt,y:ot}),We(ae)},[D,S,P,N,Y,k,A]);const U=t.useMemo(()=>{const e=new Set(h),d=new Set(u),v=new Set(w);return{reserved:e,unavailable:d,myReserved:v}},[h,u,w]),fe=t.useMemo(()=>o?new Set(o):null,[o]),G=t.useCallback(e=>{const d=e.id,v=e.seatNumber||"";return U.unavailable.has(d)||U.unavailable.has(v)?"unavailable":U.reserved.has(d)||U.reserved.has(v)?"reserved":U.myReserved.has(d)||U.myReserved.has(v)||$.has(d)?"selected":e.state},[U,$]);t.useEffect(()=>{S&&C&&C(S)},[S,C]),t.useEffect(()=>{_&&j&&j(_)},[_,j]),t.useEffect(()=>{se&&fe&&Se(fe)},[se,fe]);const Ve=t.useCallback(e=>{const d=G(e);if(d!=="available"&&d!=="selected")return;const v=$.has(e.id);se||Se(y=>{const m=new Set(y);return v?m.delete(e.id):m.add(e.id),m}),v?l?.(e):(p?.(e),p||console.log("Seat selected:",e))},[G,$,se,p,l]),K=t.useMemo(()=>S?O.filter(e=>$.has(e.id)):[],[O,$]);t.useEffect(()=>{c?.(K)},[K,c]);const V=be!==void 0?be:Pe,He=t.useCallback(()=>{if(!g)return;const e=Math.min(I+te,Y);if(e!==I){const d=k.width||S?.canvas.width||800,v=k.height||S?.canvas.height||600,y=d/2,m=v/2,R={x:(y-T.x)/I,y:(m-T.y)/I};H(e),B({x:y-R.x*e,y:m-R.y*e})}},[g,I,te,Y,k,S,T]),qe=t.useCallback(()=>{if(!g)return;const e=Math.max(I-te,V);if(e!==I){const d=k.width||S?.canvas.width||800,v=k.height||S?.canvas.height||600,y=d/2,m=v/2,R={x:(y-T.x)/I,y:(m-T.y)/I};H(e),B({x:y-R.x*e,y:m-R.y*e})}},[g,I,te,V,k,S,T]),_e=t.useCallback(e=>{B({x:e.target.x(),y:e.target.y()})},[]),Ge=t.useCallback(e=>{if(!g)return;e.evt.preventDefault();const d=ue.current;if(!d)return;const v=d.scaleX(),y=d.getPointerPosition();if(!y)return;const m=1.1,R=e.evt.deltaY>0?v/m:v*m,Z=Math.min(Math.max(R,V),Y),ie={x:(y.x-T.x)/v,y:(y.y-T.y)/v},ge={x:y.x-ie.x*Z,y:y.y-ie.y*Z};H(Z),B(ge)},[g,T,V,Y]);je(ue,{enabled:Ae&&g,minScale:V,maxScale:Y,currentScale:I,currentPosition:T,onScaleChange:(e,d)=>{H(e),B(d)},onPositionChange:e=>{B(e)}});const Ke=t.useCallback((e,d)=>{if(!b)return;const v=d.target.getStage();if(!v)return;const y=v.getPointerPosition();if(!y)return;const m=v.container().getBoundingClientRect();ve({visible:!0,x:m.left+y.x,y:m.top+y.y,seat:e,state:G(e)})},[b,G]),Ze=t.useCallback(()=>{ve(e=>({...e,visible:!1}))},[]);if(Ue)return a.jsx("div",{className:`flex items-center justify-center h-full ${x}`,children:a.jsx("p",{children:"Loading seat map..."})});if(_)return a.jsx("div",{className:`flex items-center justify-center h-full ${x}`,children:a.jsxs("p",{className:"text-red-500",children:["Error loading seat map: ",_.message]})});if(!S)return a.jsx("div",{className:`flex items-center justify-center h-full ${x}`,children:a.jsx("p",{children:"No configuration provided"})});const Je=k.width||S.canvas.width,Qe=k.height||S.canvas.height;return a.jsxs("div",{ref:xe,className:`relative ${x}`,style:{width:"100%",height:"100%"},children:[Oe&&he.length>0&&a.jsx(ke,{floors:he,currentFloorId:A,onFloorChange:$e,showAllOption:z,allLabel:L,position:M,className:F}),a.jsxs(X.Stage,{ref:ue,width:Je,height:Qe,scaleX:I,scaleY:I,x:T.x,y:T.y,draggable:!0,onDragEnd:_e,onWheel:Ge,style:{backgroundColor:S.canvas.backgroundColor,cursor:"grab"},children:[a.jsx(X.Layer,{listening:!1,children:oe.map(e=>a.jsx(Fe,{stage:e,stageColor:re.stageColor},e.id))}),a.jsx(X.Layer,{children:O.map(e=>a.jsx(Ee,{seat:e,state:G(e),colors:re,onClick:Ve,onMouseEnter:Ke,onMouseLeave:Ze},e.id))})]}),b&&a.jsx(Le,{visible:q.visible,x:q.x,y:q.y,seat:q.seat,currency:re.currency,state:q.state}),ee&&g&&a.jsx(Ie,{scale:I,minScale:V,maxScale:Y,onZoomIn:He,onZoomOut:qe,position:ze,className:Ne}),K.length>0&&a.jsxs("div",{className:"absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg",children:[a.jsxs("h3",{className:"font-semibold mb-2",children:["Selected Seats (",K.length,")"]}),a.jsx("div",{className:"max-h-48 overflow-y-auto space-y-1",children:K.map(e=>a.jsxs("div",{className:"text-sm",children:[e.seatNumber,e.price&&` - ${re.currency} ${e.price.toFixed(2)}`]},e.id))})]})]})};let Q=null;function ct(n){Q=n}function pe(){if(!Q)throw new Error("Firebase database not initialized. Call initializeFirebaseForViewer(db) first.");return Q}function le(){return Q!==null}function lt(){Q=null}function J(n,s){if(n.length!==s.length)return!1;const i=[...n].sort(),r=[...s].sort();return i.every((h,u)=>h===r[u])}function we(n,s){const i=[],r=[],h=[];return Object.entries(n).forEach(([u,o])=>{o&&typeof o=="object"&&o.state&&(o.state==="unavailable"?h.push(u):o.state==="reserved"&&(s&&o.userId===s?i.push(u):r.push(u)))}),{myReserved:i.sort(),otherReserved:r.sort(),unavailable:h.sort()}}const ce={states:null,loading:!0,error:null,lastUpdated:null,myReservedSeats:[],otherReservedSeats:[],unavailableSeats:[]};function Te(n){const{seatMapId:s,currentUserId:i,enabled:r=!0,onStateChange:h,onError:u}=n,o=t.useRef({...ce}),w=t.useRef(h),p=t.useRef(u),l=t.useRef(i);w.current=h,p.current=u,l.current=i;const c=t.useCallback(x=>{if(!r||!s)return o.current={...ce,loading:!1},()=>{};if(!le())return o.current={...ce,loading:!1,error:new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")},()=>{};const C=pe(),j=W.ref(C,`seat_states/${s}`),E=F=>{const L=F.val()||{},D=we(L,l.current),N=o.current;(N.loading||!J(N.myReservedSeats,D.myReserved)||!J(N.otherReservedSeats,D.otherReserved)||!J(N.unavailableSeats,D.unavailable))&&(o.current={states:L,loading:!1,error:null,lastUpdated:Date.now(),myReservedSeats:D.myReserved,otherReservedSeats:D.otherReserved,unavailableSeats:D.unavailable},w.current?.(L),x())},M=F=>{o.current={...o.current,loading:!1,error:F},p.current?.(F),x()};return W.onValue(j,E,M),()=>{W.off(j)}},[s,r]),f=t.useCallback(()=>o.current,[]),b=t.useCallback(()=>ce,[]),g=t.useSyncExternalStore(c,f,b);return t.useEffect(()=>{if(g.states&&i!==void 0){const x=we(g.states,i),C=o.current;(!J(C.myReservedSeats,x.myReserved)||!J(C.otherReservedSeats,x.otherReserved))&&(o.current={...C,myReservedSeats:x.myReserved,otherReservedSeats:x.otherReserved,unavailableSeats:x.unavailable,lastUpdated:Date.now()})}},[i]),{states:g.states,loading:g.loading,error:g.error,lastUpdated:g.lastUpdated,myReservedSeats:g.myReservedSeats,otherReservedSeats:g.otherReservedSeats,unavailableSeats:g.unavailableSeats,reservedSeats:g.otherReservedSeats}}function De(n){const{seatMapId:s,enabled:i=!0,subscribeToChanges:r=!1,onConfigLoad:h,onError:u}=n,[o,w]=t.useState(null),[p,l]=t.useState(!0),[c,f]=t.useState(null),b=t.useRef(h),g=t.useRef(u);b.current=h,g.current=u;const x=t.useCallback(async()=>{if(!s)return;if(!le()){f(new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")),l(!1);return}const C=pe(),j=W.ref(C,`seatmaps/${s}`);try{l(!0),f(null);const M=(await W.get(j)).val();if(M){const F=it.fromFirebaseSeatMap(M);w(F),b.current?.(F)}else f(new Error(`Seat map ${s} not found in Firebase`))}catch(E){const M=E instanceof Error?E:new Error("Unknown error");f(M),g.current?.(M)}finally{l(!1)}},[s]);return t.useEffect(()=>{if(!i||!s){l(!1);return}if(x(),r&&le()){const C=pe(),j=W.ref(C,`seatmaps/${s}/meta/updated_at`);let E=!0,M=null;const F=z=>{if(E){E=!1,M=z.val();return}const L=z.val();z.exists()&&L!==M&&(M=L,x())};return W.onValue(j,F),()=>{W.off(j)}}},[s,i,r]),{config:o,loading:p,error:c,refetch:x}}function ut(n){const{seatMapId:s,userId:i,enabled:r=!0,subscribeToDesignChanges:h=!1,onConfigLoad:u,onStateChange:o,onError:w}=n,{config:p,loading:l,error:c,refetch:f}=De({seatMapId:s,enabled:r,subscribeToChanges:h,onConfigLoad:u,onError:w}),{states:b,loading:g,error:x,lastUpdated:C,myReservedSeats:j,otherReservedSeats:E,unavailableSeats:M,reservedSeats:F}=Te({seatMapId:s,currentUserId:i,enabled:r,onStateChange:o,onError:w});return{config:p,loading:l||g,error:c||x,myReservedSeats:j,otherReservedSeats:E,unavailableSeats:M,reservedSeats:F,seatStates:b,lastUpdated:C,refetch:f}}exports.DEFAULT_COLORS=Me;exports.SeatMapViewer=at;exports.clearFirebaseInstance=lt;exports.initializeFirebaseForViewer=ct;exports.isFirebaseInitialized=le;exports.useConfigFetcher=Ce;exports.useContainerSize=Re;exports.useFirebaseConfig=De;exports.useFirebaseSeatStates=Te;exports.useRealtimeSeatMap=ut;exports.useTouchGestures=je;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react/jsx-runtime"),t=require("react"),X=require("react-konva"),W=require("firebase/database"),ot=require("@zonetrix/shared");function we(n){const[s,a]=t.useState(null),[r,h]=t.useState(!1),[u,o]=t.useState(null),m=async()=>{if(n){h(!0),o(null);try{const g=await fetch(n);if(!g.ok)throw new Error(`Failed to fetch config: ${g.statusText}`);const l=await g.json();a(l)}catch(g){const l=g instanceof Error?g:new Error("Unknown error occurred");o(l),console.error("Failed to fetch seat map config:",l)}finally{h(!1)}}};return t.useEffect(()=>{m()},[n]),{config:s,loading:r,error:u,refetch:m}}function Ce(n){const[s,a]=t.useState({width:0,height:0});return t.useEffect(()=>{const r=n.current;if(!r)return;const{width:h,height:u}=r.getBoundingClientRect();h>0&&u>0&&a({width:h,height:u});const o=new ResizeObserver(m=>{const g=m[0];if(!g)return;const{width:l,height:c}=g.contentRect;l>0&&c>0&&a(f=>f.width===l&&f.height===c?f:{width:l,height:c})});return o.observe(r),()=>{o.disconnect()}},[n]),s}function ve(n,s){return Math.sqrt(Math.pow(s.x-n.x,2)+Math.pow(s.y-n.y,2))}function me(n,s){return{x:(n.x+s.x)/2,y:(n.y+s.y)/2}}function Re(n,s){const a=t.useRef(null),r=t.useRef(null),h=t.useRef(1);t.useEffect(()=>{const u=n.current;if(!u||!s.enabled)return;const o=u.container(),m=c=>{if(c.touches.length===2){c.preventDefault();const f={x:c.touches[0].clientX,y:c.touches[0].clientY},p={x:c.touches[1].clientX,y:c.touches[1].clientY};a.current=ve(f,p),r.current=me(f,p),h.current=s.currentScale}},g=c=>{if(c.touches.length!==2)return;c.preventDefault();const f={x:c.touches[0].clientX,y:c.touches[0].clientY},p={x:c.touches[1].clientX,y:c.touches[1].clientY},b=ve(f,p),w=me(f,p);if(a.current!==null&&r.current!==null){const R=b/a.current,M=Math.min(Math.max(s.currentScale*R,s.minScale),s.maxScale),E=o.getBoundingClientRect(),j=w.x-E.left,F=w.y-E.top,z=s.currentScale,L={x:(j-s.currentPosition.x)/z,y:(F-s.currentPosition.y)/z},D=w.x-r.current.x,N=w.y-r.current.y,Q={x:j-L.x*M+D,y:F-L.y*M+N};s.onScaleChange(M,Q),a.current=b,r.current=w}},l=c=>{c.touches.length<2&&(a.current=null,r.current=null)};return o.addEventListener("touchstart",m,{passive:!1}),o.addEventListener("touchmove",g,{passive:!1}),o.addEventListener("touchend",l),()=>{o.removeEventListener("touchstart",m),o.removeEventListener("touchmove",g),o.removeEventListener("touchend",l)}},[n,s])}const je={canvasBackground:"#1a1a1a",stageColor:"#808080",seatAvailable:"#2C2B30",seatReserved:"#FCEA00",seatSelected:"#3A7DE5",seatUnavailable:"#6b7280",seatHidden:"#4a4a4a",gridLines:"#404040",currency:"KD"},Me=t.memo(({seat:n,state:s,colors:a,onClick:r,onMouseEnter:h,onMouseLeave:u})=>{const g={available:a.seatAvailable,reserved:a.seatReserved,selected:a.seatSelected,unavailable:a.seatUnavailable,hidden:a.seatHidden}[s],l=s==="available"||s==="selected",c=t.useCallback(()=>{l&&r(n)},[n,r,l]),f=t.useCallback(w=>{h(n,w);const R=w.target.getStage();R&&l&&(R.container().style.cursor="pointer")},[n,h,l]),p=t.useCallback(w=>{u();const R=w.target.getStage();R&&(R.container().style.cursor="grab")},[u]),b={x:n.position.x,y:n.position.y,fill:g,stroke:"#ffffff",strokeWidth:1,onClick:c,onTap:c,onMouseEnter:f,onMouseLeave:p};return n.shape==="circle"?i.jsx(X.Circle,{...b,radius:12}):i.jsx(X.Rect,{...b,width:24,height:24,offsetX:12,offsetY:12,cornerRadius:n.shape==="square"?0:4})});Me.displayName="ViewerSeat";const Ee=t.memo(({stage:n,stageColor:s})=>{const a=u=>({stage:"🎭",table:"⬜",wall:"▬",barrier:"🛡️","dj-booth":"🎵",bar:"🍷","entry-exit":"🚪",custom:"➕"})[u||"stage"]||"🎭",r=n.config.color||s,h=a(n.config.objectType);return i.jsxs(X.Group,{x:n.position.x,y:n.position.y,rotation:n.config.rotation||0,children:[i.jsx(X.Rect,{width:n.config.width,height:n.config.height,fill:r+"80",stroke:"#ffffff",strokeWidth:2,cornerRadius:10}),i.jsx(X.Text,{text:h,x:0,y:0,width:n.config.width,height:n.config.height*.4,fontSize:32,fill:"#ffffff",align:"center",verticalAlign:"middle"}),i.jsx(X.Text,{text:n.config.label,x:0,y:n.config.height*.4,width:n.config.width,height:n.config.height*.6,fontSize:20,fontStyle:"bold",fill:"#ffffff",align:"center",verticalAlign:"middle"})]})});Ee.displayName="ViewerStage";const Fe=t.memo(({floors:n,currentFloorId:s,onFloorChange:a,showAllOption:r,allLabel:h,position:u,className:o})=>{const m=t.useMemo(()=>[...n].sort((p,b)=>p.order-b.order),[n]),l={position:"absolute",display:"flex",alignItems:"center",gap:"8px",padding:"8px 12px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[u]},c={padding:"10px 16px",fontSize:"14px",fontWeight:500,border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",transition:"all 0.2s ease",minHeight:"44px",touchAction:"manipulation"},f={...c,backgroundColor:"#3A7DE5",borderColor:"#3A7DE5"};return i.jsxs("div",{className:o,style:l,children:[r&&i.jsx("button",{type:"button",onClick:()=>a(null),style:s===null?f:c,children:h}),m.map(p=>i.jsx("button",{type:"button",onClick:()=>a(p.id),style:s===p.id?f:c,children:p.name},p.id))]})});Fe.displayName="FloorSelectorBar";const ke=t.memo(({scale:n,minScale:s,maxScale:a,onZoomIn:r,onZoomOut:h,position:u,className:o})=>{const g={position:"absolute",display:"flex",flexDirection:"column",gap:"4px",padding:"8px",backgroundColor:"rgba(26, 26, 26, 0.95)",borderRadius:"8px",margin:"12px",zIndex:10,...{"top-left":{top:0,left:0},"top-right":{top:0,right:0},"bottom-left":{bottom:0,left:0},"bottom-right":{bottom:0,right:0}}[u]},l={width:"44px",height:"44px",minWidth:"44px",minHeight:"44px",fontSize:"22px",fontWeight:"bold",border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",transition:"all 0.2s ease",touchAction:"manipulation"},c={...l,opacity:.4,cursor:"not-allowed"},f=n<a,p=n>s;return i.jsxs("div",{className:o,style:g,children:[i.jsx("button",{type:"button",onClick:r,disabled:!f,style:f?l:c,title:"Zoom In",children:"+"}),i.jsx("button",{type:"button",onClick:h,disabled:!p,style:p?l:c,title:"Zoom Out",children:"−"})]})});ke.displayName="ZoomControls";const Ie=t.memo(({visible:n,x:s,y:a,seat:r,currency:h,state:u})=>{if(!n||!r)return null;const o=r.seatNumber||(r.rowLabel&&r.columnLabel?`${r.rowLabel}-${r.columnLabel}`:"N/A"),m={position:"fixed",left:`${s+15}px`,top:`${a+15}px`,zIndex:1e3,pointerEvents:"none"},g={backgroundColor:"rgba(26, 26, 26, 0.95)",color:"#fff",border:"1px solid #444",borderRadius:"8px",padding:"8px 12px",fontSize:"13px",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.3)",minWidth:"140px"},l={color:"#9ca3af",marginRight:"4px"},c={fontWeight:600},f={color:"#4ade80",fontWeight:600},p={fontSize:"11px",color:"#6b7280",textTransform:"capitalize",marginTop:"4px"};return i.jsx("div",{style:m,children:i.jsxs("div",{style:g,children:[r.sectionName&&i.jsxs("div",{style:{marginBottom:"4px"},children:[i.jsx("span",{style:l,children:"Section:"}),i.jsx("span",{style:{...c,color:"#3b82f6"},children:r.sectionName})]}),i.jsxs("div",{style:{marginBottom:"4px"},children:[i.jsx("span",{style:l,children:"Seat:"}),i.jsx("span",{style:c,children:o})]}),r.price!==void 0&&r.price>0&&u==="available"&&i.jsxs("div",{style:{marginBottom:"4px"},children:[i.jsx("span",{style:l,children:"Price:"}),i.jsxs("span",{style:f,children:[h," ",r.price.toFixed(2)]})]}),i.jsxs("div",{style:p,children:["Status: ",u]})]})})});Ie.displayName="SeatTooltip";const it=({config:n,configUrl:s,floorId:a,onFloorChange:r,reservedSeats:h=[],unavailableSeats:u=[],selectedSeats:o,myReservedSeats:m=[],onSeatSelect:g,onSeatDeselect:l,onSelectionChange:c,colorOverrides:f,showTooltip:p=!0,zoomEnabled:b=!0,className:w="",onConfigLoad:R,onError:M,showFloorSelector:E,floorSelectorPosition:j="top-left",floorSelectorClassName:F,showAllFloorsOption:z=!0,allFloorsLabel:L="All",fitToView:D=!0,fitPadding:N=40,showZoomControls:Q=!0,zoomControlsPosition:De="bottom-right",zoomControlsClassName:ze,minZoom:be,maxZoom:Y=3,zoomStep:ee=.25,touchEnabled:Ne=!0})=>{const le=t.useRef(null),xe=t.useRef(null),k=Ce(xe),[U,Se]=t.useState(new Set),[I,H]=t.useState(1),[T,B]=t.useState({x:0,y:0}),[Ae,Xe]=t.useState(null),[Ye,Pe]=t.useState(1),te=t.useRef({width:0,height:0}),[q,ye]=t.useState({visible:!1,x:0,y:0,seat:null,state:"available"}),{config:We,loading:Be,error:_}=we(s),x=n||We,ue=a!==void 0,A=ue?a||null:Ae,ne=o!==void 0,$e=t.useCallback(e=>{ue||Xe(e),r?.(e)},[ue,r]),de=x?.floors||[],Ue=E!==void 0?E:de.length>1,se=t.useMemo(()=>x?{...x.colors,...f}:{...je,...f},[x,f]),O=t.useMemo(()=>{if(!x)return[];let e=x.seats.filter(d=>d.state!=="hidden");return A&&(e=e.filter(d=>d.floorId===A||!d.floorId&&A==="floor_default")),e},[x,A]),re=t.useMemo(()=>x?.stages?A?x.stages.filter(e=>e.floorId===A||!e.floorId&&A==="floor_default"):x.stages:[],[x,A]),P=t.useMemo(()=>{if(!x||O.length===0&&re.length===0)return null;const e=12;let d=1/0,S=1/0,y=-1/0,v=-1/0;return O.forEach(C=>{d=Math.min(d,C.position.x-e),S=Math.min(S,C.position.y-e),y=Math.max(y,C.position.x+e),v=Math.max(v,C.position.y+e)}),re.forEach(C=>{d=Math.min(d,C.position.x),S=Math.min(S,C.position.y),y=Math.max(y,C.position.x+(C.config?.width||200)),v=Math.max(v,C.position.y+(C.config?.height||100))}),{minX:d,minY:S,maxX:y,maxY:v,width:y-d,height:v-S}},[x,O,re]);t.useEffect(()=>{if(!D||!x||!P||k.width===0||k.height===0)return;const e=Math.abs(k.width-te.current.width),d=Math.abs(k.height-te.current.height);if(!(te.current.width===0)&&e<10&&d<10)return;te.current=k;const y=k.width,v=k.height,C=y-N*2,Z=v-N*2,oe=C/P.width,fe=Z/P.height,ie=Math.min(oe,fe,Y),Qe=P.minX+P.width/2,et=P.minY+P.height/2,tt=y/2,nt=v/2,st=tt-Qe*ie,rt=nt-et*ie;H(ie),B({x:st,y:rt}),Pe(ie)},[D,x,P,N,Y,k,A]);const $=t.useMemo(()=>{const e=new Set(h),d=new Set(u),S=new Set(m);return{reserved:e,unavailable:d,myReserved:S}},[h,u,m]),he=t.useMemo(()=>o?new Set(o):null,[o]),G=t.useCallback(e=>{const d=e.id,S=e.seatNumber||"";return $.unavailable.has(d)||$.unavailable.has(S)?"unavailable":$.reserved.has(d)||$.reserved.has(S)?"reserved":$.myReserved.has(d)||$.myReserved.has(S)||U.has(d)?"selected":e.state},[$,U]);t.useEffect(()=>{x&&R&&R(x)},[x,R]),t.useEffect(()=>{_&&M&&M(_)},[_,M]),t.useEffect(()=>{ne&&he&&Se(he)},[ne,he]);const Oe=t.useCallback(e=>{const d=G(e);if(d!=="available"&&d!=="selected")return;const S=U.has(e.id);ne||Se(y=>{const v=new Set(y);return S?v.delete(e.id):v.add(e.id),v}),S?l?.(e):(g?.(e),g||console.log("Seat selected:",e))},[G,U,ne,g,l]),K=t.useMemo(()=>x?O.filter(e=>U.has(e.id)):[],[O,U]);t.useEffect(()=>{c?.(K)},[K,c]);const V=be!==void 0?be:Ye,Ve=t.useCallback(()=>{if(!b)return;const e=Math.min(I+ee,Y);if(e!==I){const d=k.width||x?.canvas.width||800,S=k.height||x?.canvas.height||600,y=d/2,v=S/2,C={x:(y-T.x)/I,y:(v-T.y)/I};H(e),B({x:y-C.x*e,y:v-C.y*e})}},[b,I,ee,Y,k,x,T]),He=t.useCallback(()=>{if(!b)return;const e=Math.max(I-ee,V);if(e!==I){const d=k.width||x?.canvas.width||800,S=k.height||x?.canvas.height||600,y=d/2,v=S/2,C={x:(y-T.x)/I,y:(v-T.y)/I};H(e),B({x:y-C.x*e,y:v-C.y*e})}},[b,I,ee,V,k,x,T]),qe=t.useCallback(e=>{B({x:e.target.x(),y:e.target.y()})},[]),_e=t.useCallback(e=>{if(!b)return;e.evt.preventDefault();const d=le.current;if(!d)return;const S=d.scaleX(),y=d.getPointerPosition();if(!y)return;const v=1.1,C=e.evt.deltaY>0?S/v:S*v,Z=Math.min(Math.max(C,V),Y),oe={x:(y.x-T.x)/S,y:(y.y-T.y)/S},fe={x:y.x-oe.x*Z,y:y.y-oe.y*Z};H(Z),B(fe)},[b,T,V,Y]);Re(le,{enabled:Ne&&b,minScale:V,maxScale:Y,currentScale:I,currentPosition:T,onScaleChange:(e,d)=>{H(e),B(d)},onPositionChange:e=>{B(e)}});const Ge=t.useCallback((e,d)=>{if(!p)return;const S=d.target.getStage();if(!S)return;const y=S.getPointerPosition();if(!y)return;const v=S.container().getBoundingClientRect();ye({visible:!0,x:v.left+y.x,y:v.top+y.y,seat:e,state:G(e)})},[p,G]),Ke=t.useCallback(()=>{ye(e=>({...e,visible:!1}))},[]);if(Be)return i.jsx("div",{className:`flex items-center justify-center h-full ${w}`,children:i.jsx("p",{children:"Loading seat map..."})});if(_)return i.jsx("div",{className:`flex items-center justify-center h-full ${w}`,children:i.jsxs("p",{className:"text-red-500",children:["Error loading seat map: ",_.message]})});if(!x)return i.jsx("div",{className:`flex items-center justify-center h-full ${w}`,children:i.jsx("p",{children:"No configuration provided"})});const Ze=k.width||x.canvas.width,Je=k.height||x.canvas.height;return i.jsxs("div",{ref:xe,className:`relative ${w}`,style:{width:"100%",height:"100%"},children:[Ue&&de.length>0&&i.jsx(Fe,{floors:de,currentFloorId:A,onFloorChange:$e,showAllOption:z,allLabel:L,position:j,className:F}),i.jsxs(X.Stage,{ref:le,width:Ze,height:Je,scaleX:I,scaleY:I,x:T.x,y:T.y,draggable:!0,onDragEnd:qe,onWheel:_e,style:{backgroundColor:x.canvas.backgroundColor,cursor:"grab"},children:[i.jsx(X.Layer,{listening:!1,children:re.map(e=>i.jsx(Ee,{stage:e,stageColor:se.stageColor},e.id))}),i.jsx(X.Layer,{children:O.map(e=>i.jsx(Me,{seat:e,state:G(e),colors:se,onClick:Oe,onMouseEnter:Ge,onMouseLeave:Ke},e.id))})]}),p&&i.jsx(Ie,{visible:q.visible,x:q.x,y:q.y,seat:q.seat,currency:se.currency,state:q.state}),Q&&b&&i.jsx(ke,{scale:I,minScale:V,maxScale:Y,onZoomIn:Ve,onZoomOut:He,position:De,className:ze}),K.length>0&&i.jsxs("div",{className:"absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg",children:[i.jsxs("h3",{className:"font-semibold mb-2",children:["Selected Seats (",K.length,")"]}),i.jsx("div",{className:"max-h-48 overflow-y-auto space-y-1",children:K.map(e=>i.jsxs("div",{className:"text-sm",children:[e.seatNumber,e.price&&` - ${se.currency} ${e.price.toFixed(2)}`]},e.id))})]})]})};let J=null;function at(n){J=n}function pe(){if(!J)throw new Error("Firebase database not initialized. Call initializeFirebaseForViewer(db) first.");return J}function ce(){return J!==null}function ct(){J=null}function ge(n,s){if(n.length!==s.length)return!1;const a=[...n].sort(),r=[...s].sort();return a.every((h,u)=>h===r[u])}function lt(n,s){const a=[],r=[],h=[];return Object.entries(n).forEach(([u,o])=>{o&&typeof o=="object"&&o.state&&(o.state==="unavailable"?h.push(u):o.state==="reserved"&&(s&&o.userId===s?a.push(u):r.push(u)))}),{myReserved:a.sort(),otherReserved:r.sort(),unavailable:h.sort()}}const ae={states:null,loading:!0,error:null,lastUpdated:null,myReservedSeats:[],otherReservedSeats:[],unavailableSeats:[]};function Le(n){const{seatMapId:s,currentUserId:a,enabled:r=!0,onStateChange:h,onError:u}=n,o=t.useRef({...ae}),m=t.useRef(h),g=t.useRef(u),l=t.useRef(a);m.current=h,g.current=u,l.current=a;const c=t.useCallback(w=>{if(!r||!s)return o.current={...ae,loading:!1},()=>{};if(!ce())return o.current={...ae,loading:!1,error:new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")},()=>{};const R=pe(),M=W.ref(R,`seatmaps/${s}/seat_states`),E=F=>{const L=F.val()||{},D=lt(L,l.current),N=o.current;(N.loading||!ge(N.myReservedSeats,D.myReserved)||!ge(N.otherReservedSeats,D.otherReserved)||!ge(N.unavailableSeats,D.unavailable))&&(o.current={states:L,loading:!1,error:null,lastUpdated:Date.now(),myReservedSeats:D.myReserved,otherReservedSeats:D.otherReserved,unavailableSeats:D.unavailable},m.current?.(L),w())},j=F=>{o.current={...o.current,loading:!1,error:F},g.current?.(F),w()};return W.onValue(M,E,j),()=>{W.off(M)}},[s,r,a]),f=t.useCallback(()=>o.current,[]),p=t.useCallback(()=>ae,[]),b=t.useSyncExternalStore(c,f,p);return{states:b.states,loading:b.loading,error:b.error,lastUpdated:b.lastUpdated,myReservedSeats:b.myReservedSeats,otherReservedSeats:b.otherReservedSeats,unavailableSeats:b.unavailableSeats,reservedSeats:b.otherReservedSeats}}function Te(n){const{seatMapId:s,enabled:a=!0,subscribeToChanges:r=!1,onConfigLoad:h,onError:u}=n,[o,m]=t.useState(null),[g,l]=t.useState(!0),[c,f]=t.useState(null),p=t.useRef(h),b=t.useRef(u);p.current=h,b.current=u;const w=t.useCallback(async()=>{if(!s)return;if(!ce()){f(new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")),l(!1);return}const R=pe(),M=W.ref(R,`seatmaps/${s}`);try{l(!0),f(null);const j=(await W.get(M)).val();if(j){const F=ot.fromFirebaseSeatMap(j);m(F),p.current?.(F)}else f(new Error(`Seat map ${s} not found in Firebase`))}catch(E){const j=E instanceof Error?E:new Error("Unknown error");f(j),b.current?.(j)}finally{l(!1)}},[s]);return t.useEffect(()=>{if(!a||!s){l(!1);return}if(w(),r&&ce()){const R=pe(),M=W.ref(R,`seatmaps/${s}/meta/updated_at`);let E=!0,j=null;const F=z=>{if(E){E=!1,j=z.val();return}const L=z.val();z.exists()&&L!==j&&(j=L,w())};return W.onValue(M,F),()=>{W.off(M)}}},[s,a,r]),{config:o,loading:g,error:c,refetch:w}}function ut(n){const{seatMapId:s,userId:a,enabled:r=!0,subscribeToDesignChanges:h=!1,onConfigLoad:u,onStateChange:o,onError:m}=n,{config:g,loading:l,error:c,refetch:f}=Te({seatMapId:s,enabled:r,subscribeToChanges:h,onConfigLoad:u,onError:m}),{states:p,loading:b,error:w,lastUpdated:R,myReservedSeats:M,otherReservedSeats:E,unavailableSeats:j,reservedSeats:F}=Le({seatMapId:s,currentUserId:a,enabled:r,onStateChange:o,onError:m});return{config:g,loading:l||b,error:c||w,myReservedSeats:M,otherReservedSeats:E,unavailableSeats:j,reservedSeats:F,seatStates:p,lastUpdated:R,refetch:f}}exports.DEFAULT_COLORS=je;exports.SeatMapViewer=it;exports.clearFirebaseInstance=ct;exports.initializeFirebaseForViewer=at;exports.isFirebaseInitialized=ce;exports.useConfigFetcher=we;exports.useContainerSize=Ce;exports.useFirebaseConfig=Te;exports.useFirebaseSeatStates=Le;exports.useRealtimeSeatMap=ut;exports.useTouchGestures=Re;
package/dist/index.mjs CHANGED
@@ -1,20 +1,20 @@
1
- import { jsx as y, jsxs as D } from "react/jsx-runtime";
2
- import { useState as N, useEffect as W, useRef as A, useCallback as I, useMemo as $, memo as re, useSyncExternalStore as dt } from "react";
3
- import { Stage as ut, Layer as Me, Group as ht, Rect as De, Text as Ee, Circle as ft } from "react-konva";
4
- import { ref as ye, onValue as Le, off as Ne, get as gt } from "firebase/database";
5
- import { fromFirebaseSeatMap as pt } from "@zonetrix/shared";
6
- function vt(t) {
7
- const [n, i] = N(null), [r, d] = N(!1), [c, o] = N(null), x = async () => {
1
+ import { jsx as y, jsxs as L } from "react/jsx-runtime";
2
+ import { useState as N, useEffect as W, useRef as A, useCallback as I, useMemo as U, memo as ne, useSyncExternalStore as lt } from "react";
3
+ import { Stage as dt, Layer as Me, Group as ut, Rect as ke, Text as Ee, Circle as ht } from "react-konva";
4
+ import { ref as ve, onValue as Le, off as De, get as ft } from "firebase/database";
5
+ import { fromFirebaseSeatMap as gt } from "@zonetrix/shared";
6
+ function pt(t) {
7
+ const [n, i] = N(null), [r, d] = N(!1), [c, o] = N(null), S = async () => {
8
8
  if (t) {
9
9
  d(!0), o(null);
10
10
  try {
11
- const f = await fetch(t);
12
- if (!f.ok)
13
- throw new Error(`Failed to fetch config: ${f.statusText}`);
14
- const a = await f.json();
11
+ const h = await fetch(t);
12
+ if (!h.ok)
13
+ throw new Error(`Failed to fetch config: ${h.statusText}`);
14
+ const a = await h.json();
15
15
  i(a);
16
- } catch (f) {
17
- const a = f instanceof Error ? f : new Error("Unknown error occurred");
16
+ } catch (h) {
17
+ const a = h instanceof Error ? h : new Error("Unknown error occurred");
18
18
  o(a), console.error("Failed to fetch seat map config:", a);
19
19
  } finally {
20
20
  d(!1);
@@ -22,12 +22,12 @@ function vt(t) {
22
22
  }
23
23
  };
24
24
  return W(() => {
25
- x();
25
+ S();
26
26
  }, [t]), {
27
27
  config: n,
28
28
  loading: r,
29
29
  error: c,
30
- refetch: x
30
+ refetch: S
31
31
  };
32
32
  }
33
33
  function bt(t) {
@@ -37,10 +37,10 @@ function bt(t) {
37
37
  if (!r) return;
38
38
  const { width: d, height: c } = r.getBoundingClientRect();
39
39
  d > 0 && c > 0 && i({ width: d, height: c });
40
- const o = new ResizeObserver((x) => {
41
- const f = x[0];
42
- if (!f) return;
43
- const { width: a, height: s } = f.contentRect;
40
+ const o = new ResizeObserver((S) => {
41
+ const h = S[0];
42
+ if (!h) return;
43
+ const { width: a, height: s } = h.contentRect;
44
44
  a > 0 && s > 0 && i((u) => u.width === a && u.height === s ? u : { width: a, height: s });
45
45
  });
46
46
  return o.observe(r), () => {
@@ -62,38 +62,38 @@ function yt(t, n) {
62
62
  W(() => {
63
63
  const c = t.current;
64
64
  if (!c || !n.enabled) return;
65
- const o = c.container(), x = (s) => {
65
+ const o = c.container(), S = (s) => {
66
66
  if (s.touches.length === 2) {
67
67
  s.preventDefault();
68
- const u = { x: s.touches[0].clientX, y: s.touches[0].clientY }, g = { x: s.touches[1].clientX, y: s.touches[1].clientY };
69
- i.current = Ie(u, g), r.current = Fe(u, g), d.current = n.currentScale;
68
+ const u = { x: s.touches[0].clientX, y: s.touches[0].clientY }, f = { x: s.touches[1].clientX, y: s.touches[1].clientY };
69
+ i.current = Ie(u, f), r.current = Fe(u, f), d.current = n.currentScale;
70
70
  }
71
- }, f = (s) => {
71
+ }, h = (s) => {
72
72
  if (s.touches.length !== 2) return;
73
73
  s.preventDefault();
74
- const u = { x: s.touches[0].clientX, y: s.touches[0].clientY }, g = { x: s.touches[1].clientX, y: s.touches[1].clientY }, h = Ie(u, g), p = Fe(u, g);
74
+ const u = { x: s.touches[0].clientX, y: s.touches[0].clientY }, f = { x: s.touches[1].clientX, y: s.touches[1].clientY }, g = Ie(u, f), x = Fe(u, f);
75
75
  if (i.current !== null && r.current !== null) {
76
- const w = h / i.current, R = Math.min(
77
- Math.max(n.currentScale * w, n.minScale),
76
+ const C = g / i.current, R = Math.min(
77
+ Math.max(n.currentScale * C, n.minScale),
78
78
  n.maxScale
79
- ), F = o.getBoundingClientRect(), M = p.x - F.left, k = p.y - F.top, Y = n.currentScale, T = {
79
+ ), F = o.getBoundingClientRect(), M = x.x - F.left, k = x.y - F.top, Y = n.currentScale, T = {
80
80
  x: (M - n.currentPosition.x) / Y,
81
81
  y: (k - n.currentPosition.y) / Y
82
- }, X = p.x - r.current.x, j = p.y - r.current.y, oe = {
82
+ }, X = x.x - r.current.x, j = x.y - r.current.y, re = {
83
83
  x: M - T.x * R + X,
84
84
  y: k - T.y * R + j
85
85
  };
86
- n.onScaleChange(R, oe), i.current = h, r.current = p;
86
+ n.onScaleChange(R, re), i.current = g, r.current = x;
87
87
  }
88
88
  }, a = (s) => {
89
89
  s.touches.length < 2 && (i.current = null, r.current = null);
90
90
  };
91
- return o.addEventListener("touchstart", x, { passive: !1 }), o.addEventListener("touchmove", f, { passive: !1 }), o.addEventListener("touchend", a), () => {
92
- o.removeEventListener("touchstart", x), o.removeEventListener("touchmove", f), o.removeEventListener("touchend", a);
91
+ return o.addEventListener("touchstart", S, { passive: !1 }), o.addEventListener("touchmove", h, { passive: !1 }), o.addEventListener("touchend", a), () => {
92
+ o.removeEventListener("touchstart", S), o.removeEventListener("touchmove", h), o.removeEventListener("touchend", a);
93
93
  };
94
94
  }, [t, n]);
95
95
  }
96
- const St = {
96
+ const vt = {
97
97
  canvasBackground: "#1a1a1a",
98
98
  stageColor: "#808080",
99
99
  seatAvailable: "#2C2B30",
@@ -103,8 +103,8 @@ const St = {
103
103
  seatHidden: "#4a4a4a",
104
104
  gridLines: "#404040",
105
105
  currency: "KD"
106
- }, Te = re(({ seat: t, state: n, colors: i, onClick: r, onMouseEnter: d, onMouseLeave: c }) => {
107
- const f = {
106
+ }, Ne = ne(({ seat: t, state: n, colors: i, onClick: r, onMouseEnter: d, onMouseLeave: c }) => {
107
+ const h = {
108
108
  available: i.seatAvailable,
109
109
  reserved: i.seatReserved,
110
110
  selected: i.seatSelected,
@@ -113,35 +113,35 @@ const St = {
113
113
  // Hidden seats are filtered out, but included for type safety
114
114
  }[n], a = n === "available" || n === "selected", s = I(() => {
115
115
  a && r(t);
116
- }, [t, r, a]), u = I((p) => {
117
- d(t, p);
118
- const w = p.target.getStage();
119
- w && a && (w.container().style.cursor = "pointer");
120
- }, [t, d, a]), g = I((p) => {
116
+ }, [t, r, a]), u = I((x) => {
117
+ d(t, x);
118
+ const C = x.target.getStage();
119
+ C && a && (C.container().style.cursor = "pointer");
120
+ }, [t, d, a]), f = I((x) => {
121
121
  c();
122
- const w = p.target.getStage();
123
- w && (w.container().style.cursor = "grab");
124
- }, [c]), h = {
122
+ const C = x.target.getStage();
123
+ C && (C.container().style.cursor = "grab");
124
+ }, [c]), g = {
125
125
  x: t.position.x,
126
126
  y: t.position.y,
127
- fill: f,
127
+ fill: h,
128
128
  stroke: "#ffffff",
129
129
  strokeWidth: 1,
130
130
  onClick: s,
131
131
  onTap: s,
132
132
  onMouseEnter: u,
133
- onMouseLeave: g
133
+ onMouseLeave: f
134
134
  };
135
135
  return t.shape === "circle" ? /* @__PURE__ */ y(
136
- ft,
136
+ ht,
137
137
  {
138
- ...h,
138
+ ...g,
139
139
  radius: 12
140
140
  }
141
141
  ) : /* @__PURE__ */ y(
142
- De,
142
+ ke,
143
143
  {
144
- ...h,
144
+ ...g,
145
145
  width: 24,
146
146
  height: 24,
147
147
  offsetX: 12,
@@ -150,8 +150,8 @@ const St = {
150
150
  }
151
151
  );
152
152
  });
153
- Te.displayName = "ViewerSeat";
154
- const ze = re(({ stage: t, stageColor: n }) => {
153
+ Ne.displayName = "ViewerSeat";
154
+ const Te = ne(({ stage: t, stageColor: n }) => {
155
155
  const i = (c) => ({
156
156
  stage: "🎭",
157
157
  table: "⬜",
@@ -162,9 +162,9 @@ const ze = re(({ stage: t, stageColor: n }) => {
162
162
  "entry-exit": "🚪",
163
163
  custom: "➕"
164
164
  })[c || "stage"] || "🎭", r = t.config.color || n, d = i(t.config.objectType);
165
- return /* @__PURE__ */ D(ht, { x: t.position.x, y: t.position.y, rotation: t.config.rotation || 0, children: [
165
+ return /* @__PURE__ */ L(ut, { x: t.position.x, y: t.position.y, rotation: t.config.rotation || 0, children: [
166
166
  /* @__PURE__ */ y(
167
- De,
167
+ ke,
168
168
  {
169
169
  width: t.config.width,
170
170
  height: t.config.height,
@@ -205,8 +205,8 @@ const ze = re(({ stage: t, stageColor: n }) => {
205
205
  )
206
206
  ] });
207
207
  });
208
- ze.displayName = "ViewerStage";
209
- const Ae = re(({
208
+ Te.displayName = "ViewerStage";
209
+ const ze = ne(({
210
210
  floors: t,
211
211
  currentFloorId: n,
212
212
  onFloorChange: i,
@@ -215,8 +215,8 @@ const Ae = re(({
215
215
  position: c,
216
216
  className: o
217
217
  }) => {
218
- const x = $(
219
- () => [...t].sort((g, h) => g.order - h.order),
218
+ const S = U(
219
+ () => [...t].sort((f, g) => f.order - g.order),
220
220
  [t]
221
221
  ), a = {
222
222
  position: "absolute",
@@ -251,7 +251,7 @@ const Ae = re(({
251
251
  backgroundColor: "#3A7DE5",
252
252
  borderColor: "#3A7DE5"
253
253
  };
254
- return /* @__PURE__ */ D("div", { className: o, style: a, children: [
254
+ return /* @__PURE__ */ L("div", { className: o, style: a, children: [
255
255
  r && /* @__PURE__ */ y(
256
256
  "button",
257
257
  {
@@ -261,20 +261,20 @@ const Ae = re(({
261
261
  children: d
262
262
  }
263
263
  ),
264
- x.map((g) => /* @__PURE__ */ y(
264
+ S.map((f) => /* @__PURE__ */ y(
265
265
  "button",
266
266
  {
267
267
  type: "button",
268
- onClick: () => i(g.id),
269
- style: n === g.id ? u : s,
270
- children: g.name
268
+ onClick: () => i(f.id),
269
+ style: n === f.id ? u : s,
270
+ children: f.name
271
271
  },
272
- g.id
272
+ f.id
273
273
  ))
274
274
  ] });
275
275
  });
276
- Ae.displayName = "FloorSelectorBar";
277
- const Xe = re(({
276
+ ze.displayName = "FloorSelectorBar";
277
+ const Ae = ne(({
278
278
  scale: t,
279
279
  minScale: n,
280
280
  maxScale: i,
@@ -283,7 +283,7 @@ const Xe = re(({
283
283
  position: c,
284
284
  className: o
285
285
  }) => {
286
- const f = {
286
+ const h = {
287
287
  position: "absolute",
288
288
  display: "flex",
289
289
  flexDirection: "column",
@@ -320,8 +320,8 @@ const Xe = re(({
320
320
  ...a,
321
321
  opacity: 0.4,
322
322
  cursor: "not-allowed"
323
- }, u = t < i, g = t > n;
324
- return /* @__PURE__ */ D("div", { className: o, style: f, children: [
323
+ }, u = t < i, f = t > n;
324
+ return /* @__PURE__ */ L("div", { className: o, style: h, children: [
325
325
  /* @__PURE__ */ y(
326
326
  "button",
327
327
  {
@@ -338,16 +338,16 @@ const Xe = re(({
338
338
  {
339
339
  type: "button",
340
340
  onClick: d,
341
- disabled: !g,
342
- style: g ? a : s,
341
+ disabled: !f,
342
+ style: f ? a : s,
343
343
  title: "Zoom Out",
344
344
  children: "−"
345
345
  }
346
346
  )
347
347
  ] });
348
348
  });
349
- Xe.displayName = "ZoomControls";
350
- const Ye = re(({
349
+ Ae.displayName = "ZoomControls";
350
+ const Xe = ne(({
351
351
  visible: t,
352
352
  x: n,
353
353
  y: i,
@@ -356,13 +356,13 @@ const Ye = re(({
356
356
  state: c
357
357
  }) => {
358
358
  if (!t || !r) return null;
359
- const o = r.seatNumber || (r.rowLabel && r.columnLabel ? `${r.rowLabel}-${r.columnLabel}` : "N/A"), x = {
359
+ const o = r.seatNumber || (r.rowLabel && r.columnLabel ? `${r.rowLabel}-${r.columnLabel}` : "N/A"), S = {
360
360
  position: "fixed",
361
361
  left: `${n + 15}px`,
362
362
  top: `${i + 15}px`,
363
363
  zIndex: 1e3,
364
364
  pointerEvents: "none"
365
- }, f = {
365
+ }, h = {
366
366
  backgroundColor: "rgba(26, 26, 26, 0.95)",
367
367
  color: "#fff",
368
368
  border: "1px solid #444",
@@ -379,36 +379,36 @@ const Ye = re(({
379
379
  }, u = {
380
380
  color: "#4ade80",
381
381
  fontWeight: 600
382
- }, g = {
382
+ }, f = {
383
383
  fontSize: "11px",
384
384
  color: "#6b7280",
385
385
  textTransform: "capitalize",
386
386
  marginTop: "4px"
387
387
  };
388
- return /* @__PURE__ */ y("div", { style: x, children: /* @__PURE__ */ D("div", { style: f, children: [
389
- r.sectionName && /* @__PURE__ */ D("div", { style: { marginBottom: "4px" }, children: [
388
+ return /* @__PURE__ */ y("div", { style: S, children: /* @__PURE__ */ L("div", { style: h, children: [
389
+ r.sectionName && /* @__PURE__ */ L("div", { style: { marginBottom: "4px" }, children: [
390
390
  /* @__PURE__ */ y("span", { style: a, children: "Section:" }),
391
391
  /* @__PURE__ */ y("span", { style: { ...s, color: "#3b82f6" }, children: r.sectionName })
392
392
  ] }),
393
- /* @__PURE__ */ D("div", { style: { marginBottom: "4px" }, children: [
393
+ /* @__PURE__ */ L("div", { style: { marginBottom: "4px" }, children: [
394
394
  /* @__PURE__ */ y("span", { style: a, children: "Seat:" }),
395
395
  /* @__PURE__ */ y("span", { style: s, children: o })
396
396
  ] }),
397
- r.price !== void 0 && r.price > 0 && c === "available" && /* @__PURE__ */ D("div", { style: { marginBottom: "4px" }, children: [
397
+ r.price !== void 0 && r.price > 0 && c === "available" && /* @__PURE__ */ L("div", { style: { marginBottom: "4px" }, children: [
398
398
  /* @__PURE__ */ y("span", { style: a, children: "Price:" }),
399
- /* @__PURE__ */ D("span", { style: u, children: [
399
+ /* @__PURE__ */ L("span", { style: u, children: [
400
400
  d,
401
401
  " ",
402
402
  r.price.toFixed(2)
403
403
  ] })
404
404
  ] }),
405
- /* @__PURE__ */ D("div", { style: g, children: [
405
+ /* @__PURE__ */ L("div", { style: f, children: [
406
406
  "Status: ",
407
407
  c
408
408
  ] })
409
409
  ] }) });
410
410
  });
411
- Ye.displayName = "SeatTooltip";
411
+ Xe.displayName = "SeatTooltip";
412
412
  const It = ({
413
413
  config: t,
414
414
  configUrl: n,
@@ -417,15 +417,15 @@ const It = ({
417
417
  reservedSeats: d = [],
418
418
  unavailableSeats: c = [],
419
419
  selectedSeats: o,
420
- myReservedSeats: x = [],
421
- onSeatSelect: f,
420
+ myReservedSeats: S = [],
421
+ onSeatSelect: h,
422
422
  onSeatDeselect: a,
423
423
  onSelectionChange: s,
424
424
  colorOverrides: u,
425
- showTooltip: g = !0,
426
- zoomEnabled: h = !0,
427
- className: p = "",
428
- onConfigLoad: w,
425
+ showTooltip: f = !0,
426
+ zoomEnabled: g = !0,
427
+ className: x = "",
428
+ onConfigLoad: C,
429
429
  onError: R,
430
430
  // Floor selector props
431
431
  showFloorSelector: F,
@@ -436,126 +436,126 @@ const It = ({
436
436
  fitToView: X = !0,
437
437
  fitPadding: j = 40,
438
438
  // Zoom controls
439
- showZoomControls: oe = !0,
440
- zoomControlsPosition: je = "bottom-right",
441
- zoomControlsClassName: Pe,
439
+ showZoomControls: re = !0,
440
+ zoomControlsPosition: Ye = "bottom-right",
441
+ zoomControlsClassName: je,
442
442
  minZoom: xe,
443
443
  maxZoom: B = 3,
444
- zoomStep: ie = 0.25,
444
+ zoomStep: oe = 0.25,
445
445
  // Touch gestures
446
- touchEnabled: We = !0
446
+ touchEnabled: Pe = !0
447
447
  }) => {
448
- const fe = A(null), we = A(null), E = bt(we), [O, Ce] = N(/* @__PURE__ */ new Set()), [L, G] = N(1), [z, H] = N({ x: 0, y: 0 }), [Be, Ue] = N(null), [$e, He] = N(1), se = A({ width: 0, height: 0 }), [Z, Re] = N({ visible: !1, x: 0, y: 0, seat: null, state: "available" }), { config: Ve, loading: Oe, error: K } = vt(n), v = t || Ve, ge = i !== void 0, P = ge ? i || null : Be, ae = o !== void 0, _e = I((e) => {
449
- ge || Ue(e), r?.(e);
450
- }, [ge, r]), pe = v?.floors || [], qe = F !== void 0 ? F : pe.length > 1, ce = $(
451
- () => v ? { ...v.colors, ...u } : { ...St, ...u },
452
- [v, u]
453
- ), _ = $(() => {
454
- if (!v) return [];
455
- let e = v.seats.filter((l) => l.state !== "hidden");
448
+ const he = A(null), we = A(null), E = bt(we), [O, Ce] = N(/* @__PURE__ */ new Set()), [D, G] = N(1), [z, H] = N({ x: 0, y: 0 }), [We, Be] = N(null), [$e, Ue] = N(1), ie = A({ width: 0, height: 0 }), [Z, Re] = N({ visible: !1, x: 0, y: 0, seat: null, state: "available" }), { config: He, loading: Ve, error: K } = pt(n), p = t || He, fe = i !== void 0, P = fe ? i || null : We, se = o !== void 0, Oe = I((e) => {
449
+ fe || Be(e), r?.(e);
450
+ }, [fe, r]), ge = p?.floors || [], _e = F !== void 0 ? F : ge.length > 1, ae = U(
451
+ () => p ? { ...p.colors, ...u } : { ...vt, ...u },
452
+ [p, u]
453
+ ), _ = U(() => {
454
+ if (!p) return [];
455
+ let e = p.seats.filter((l) => l.state !== "hidden");
456
456
  return P && (e = e.filter(
457
457
  (l) => l.floorId === P || !l.floorId && P === "floor_default"
458
458
  )), e;
459
- }, [v, P]), le = $(() => v?.stages ? P ? v.stages.filter(
459
+ }, [p, P]), ce = U(() => p?.stages ? P ? p.stages.filter(
460
460
  (e) => e.floorId === P || !e.floorId && P === "floor_default"
461
- ) : v.stages : [], [v, P]), U = $(() => {
462
- if (!v || _.length === 0 && le.length === 0)
461
+ ) : p.stages : [], [p, P]), $ = U(() => {
462
+ if (!p || _.length === 0 && ce.length === 0)
463
463
  return null;
464
464
  const e = 12;
465
- let l = 1 / 0, b = 1 / 0, S = -1 / 0, m = -1 / 0;
466
- return _.forEach((C) => {
467
- l = Math.min(l, C.position.x - e), b = Math.min(b, C.position.y - e), S = Math.max(S, C.position.x + e), m = Math.max(m, C.position.y + e);
468
- }), le.forEach((C) => {
469
- l = Math.min(l, C.position.x), b = Math.min(b, C.position.y), S = Math.max(S, C.position.x + (C.config?.width || 200)), m = Math.max(m, C.position.y + (C.config?.height || 100));
470
- }), { minX: l, minY: b, maxX: S, maxY: m, width: S - l, height: m - b };
471
- }, [v, _, le]);
465
+ let l = 1 / 0, b = 1 / 0, v = -1 / 0, m = -1 / 0;
466
+ return _.forEach((w) => {
467
+ l = Math.min(l, w.position.x - e), b = Math.min(b, w.position.y - e), v = Math.max(v, w.position.x + e), m = Math.max(m, w.position.y + e);
468
+ }), ce.forEach((w) => {
469
+ l = Math.min(l, w.position.x), b = Math.min(b, w.position.y), v = Math.max(v, w.position.x + (w.config?.width || 200)), m = Math.max(m, w.position.y + (w.config?.height || 100));
470
+ }), { minX: l, minY: b, maxX: v, maxY: m, width: v - l, height: m - b };
471
+ }, [p, _, ce]);
472
472
  W(() => {
473
- if (!X || !v || !U || E.width === 0 || E.height === 0) return;
474
- const e = Math.abs(E.width - se.current.width), l = Math.abs(E.height - se.current.height);
475
- if (!(se.current.width === 0) && e < 10 && l < 10) return;
476
- se.current = E;
477
- const S = E.width, m = E.height, C = S - j * 2, ee = m - j * 2, de = C / U.width, be = ee / U.height, ue = Math.min(de, be, B), ot = U.minX + U.width / 2, it = U.minY + U.height / 2, st = S / 2, at = m / 2, ct = st - ot * ue, lt = at - it * ue;
478
- G(ue), H({ x: ct, y: lt }), He(ue);
479
- }, [X, v, U, j, B, E, P]);
480
- const V = $(() => {
481
- const e = new Set(d), l = new Set(c), b = new Set(x);
473
+ if (!X || !p || !$ || E.width === 0 || E.height === 0) return;
474
+ const e = Math.abs(E.width - ie.current.width), l = Math.abs(E.height - ie.current.height);
475
+ if (!(ie.current.width === 0) && e < 10 && l < 10) return;
476
+ ie.current = E;
477
+ const v = E.width, m = E.height, w = v - j * 2, ee = m - j * 2, le = w / $.width, be = ee / $.height, de = Math.min(le, be, B), rt = $.minX + $.width / 2, ot = $.minY + $.height / 2, it = v / 2, st = m / 2, at = it - rt * de, ct = st - ot * de;
478
+ G(de), H({ x: at, y: ct }), Ue(de);
479
+ }, [X, p, $, j, B, E, P]);
480
+ const V = U(() => {
481
+ const e = new Set(d), l = new Set(c), b = new Set(S);
482
482
  return { reserved: e, unavailable: l, myReserved: b };
483
- }, [d, c, x]), ve = $(() => o ? new Set(o) : null, [o]), J = I((e) => {
483
+ }, [d, c, S]), pe = U(() => o ? new Set(o) : null, [o]), J = I((e) => {
484
484
  const l = e.id, b = e.seatNumber || "";
485
485
  return V.unavailable.has(l) || V.unavailable.has(b) ? "unavailable" : V.reserved.has(l) || V.reserved.has(b) ? "reserved" : V.myReserved.has(l) || V.myReserved.has(b) || O.has(l) ? "selected" : e.state;
486
486
  }, [V, O]);
487
487
  W(() => {
488
- v && w && w(v);
489
- }, [v, w]), W(() => {
488
+ p && C && C(p);
489
+ }, [p, C]), W(() => {
490
490
  K && R && R(K);
491
491
  }, [K, R]), W(() => {
492
- ae && ve && Ce(ve);
493
- }, [ae, ve]);
494
- const Ge = I((e) => {
492
+ se && pe && Ce(pe);
493
+ }, [se, pe]);
494
+ const qe = I((e) => {
495
495
  const l = J(e);
496
496
  if (l !== "available" && l !== "selected")
497
497
  return;
498
498
  const b = O.has(e.id);
499
- ae || Ce((S) => {
500
- const m = new Set(S);
499
+ se || Ce((v) => {
500
+ const m = new Set(v);
501
501
  return b ? m.delete(e.id) : m.add(e.id), m;
502
- }), b ? a?.(e) : (f?.(e), f || console.log("Seat selected:", e));
503
- }, [J, O, ae, f, a]), Q = $(() => v ? _.filter((e) => O.has(e.id)) : [], [_, O]);
502
+ }), b ? a?.(e) : (h?.(e), h || console.log("Seat selected:", e));
503
+ }, [J, O, se, h, a]), Q = U(() => p ? _.filter((e) => O.has(e.id)) : [], [_, O]);
504
504
  W(() => {
505
505
  s?.(Q);
506
506
  }, [Q, s]);
507
- const q = xe !== void 0 ? xe : $e, Ze = I(() => {
508
- if (!h) return;
509
- const e = Math.min(L + ie, B);
510
- if (e !== L) {
511
- const l = E.width || v?.canvas.width || 800, b = E.height || v?.canvas.height || 600, S = l / 2, m = b / 2, C = {
512
- x: (S - z.x) / L,
513
- y: (m - z.y) / L
507
+ const q = xe !== void 0 ? xe : $e, Ge = I(() => {
508
+ if (!g) return;
509
+ const e = Math.min(D + oe, B);
510
+ if (e !== D) {
511
+ const l = E.width || p?.canvas.width || 800, b = E.height || p?.canvas.height || 600, v = l / 2, m = b / 2, w = {
512
+ x: (v - z.x) / D,
513
+ y: (m - z.y) / D
514
514
  };
515
515
  G(e), H({
516
- x: S - C.x * e,
517
- y: m - C.y * e
516
+ x: v - w.x * e,
517
+ y: m - w.y * e
518
518
  });
519
519
  }
520
- }, [h, L, ie, B, E, v, z]), Ke = I(() => {
521
- if (!h) return;
522
- const e = Math.max(L - ie, q);
523
- if (e !== L) {
524
- const l = E.width || v?.canvas.width || 800, b = E.height || v?.canvas.height || 600, S = l / 2, m = b / 2, C = {
525
- x: (S - z.x) / L,
526
- y: (m - z.y) / L
520
+ }, [g, D, oe, B, E, p, z]), Ze = I(() => {
521
+ if (!g) return;
522
+ const e = Math.max(D - oe, q);
523
+ if (e !== D) {
524
+ const l = E.width || p?.canvas.width || 800, b = E.height || p?.canvas.height || 600, v = l / 2, m = b / 2, w = {
525
+ x: (v - z.x) / D,
526
+ y: (m - z.y) / D
527
527
  };
528
528
  G(e), H({
529
- x: S - C.x * e,
530
- y: m - C.y * e
529
+ x: v - w.x * e,
530
+ y: m - w.y * e
531
531
  });
532
532
  }
533
- }, [h, L, ie, q, E, v, z]), Je = I((e) => {
533
+ }, [g, D, oe, q, E, p, z]), Ke = I((e) => {
534
534
  H({
535
535
  x: e.target.x(),
536
536
  y: e.target.y()
537
537
  });
538
- }, []), Qe = I((e) => {
539
- if (!h) return;
538
+ }, []), Je = I((e) => {
539
+ if (!g) return;
540
540
  e.evt.preventDefault();
541
- const l = fe.current;
541
+ const l = he.current;
542
542
  if (!l) return;
543
- const b = l.scaleX(), S = l.getPointerPosition();
544
- if (!S) return;
545
- const m = 1.1, C = e.evt.deltaY > 0 ? b / m : b * m, ee = Math.min(Math.max(C, q), B), de = {
546
- x: (S.x - z.x) / b,
547
- y: (S.y - z.y) / b
543
+ const b = l.scaleX(), v = l.getPointerPosition();
544
+ if (!v) return;
545
+ const m = 1.1, w = e.evt.deltaY > 0 ? b / m : b * m, ee = Math.min(Math.max(w, q), B), le = {
546
+ x: (v.x - z.x) / b,
547
+ y: (v.y - z.y) / b
548
548
  }, be = {
549
- x: S.x - de.x * ee,
550
- y: S.y - de.y * ee
549
+ x: v.x - le.x * ee,
550
+ y: v.y - le.y * ee
551
551
  };
552
552
  G(ee), H(be);
553
- }, [h, z, q, B]);
554
- yt(fe, {
555
- enabled: We && h,
553
+ }, [g, z, q, B]);
554
+ yt(he, {
555
+ enabled: Pe && g,
556
556
  minScale: q,
557
557
  maxScale: B,
558
- currentScale: L,
558
+ currentScale: D,
559
559
  currentPosition: z,
560
560
  onScaleChange: (e, l) => {
561
561
  G(e), H(l);
@@ -564,151 +564,151 @@ const It = ({
564
564
  H(e);
565
565
  }
566
566
  });
567
- const et = I((e, l) => {
568
- if (!g) return;
567
+ const Qe = I((e, l) => {
568
+ if (!f) return;
569
569
  const b = l.target.getStage();
570
570
  if (!b) return;
571
- const S = b.getPointerPosition();
572
- if (!S) return;
571
+ const v = b.getPointerPosition();
572
+ if (!v) return;
573
573
  const m = b.container().getBoundingClientRect();
574
574
  Re({
575
575
  visible: !0,
576
- x: m.left + S.x,
577
- y: m.top + S.y,
576
+ x: m.left + v.x,
577
+ y: m.top + v.y,
578
578
  seat: e,
579
579
  state: J(e)
580
580
  });
581
- }, [g, J]), tt = I(() => {
581
+ }, [f, J]), et = I(() => {
582
582
  Re((e) => ({ ...e, visible: !1 }));
583
583
  }, []);
584
- if (Oe)
585
- return /* @__PURE__ */ y("div", { className: `flex items-center justify-center h-full ${p}`, children: /* @__PURE__ */ y("p", { children: "Loading seat map..." }) });
584
+ if (Ve)
585
+ return /* @__PURE__ */ y("div", { className: `flex items-center justify-center h-full ${x}`, children: /* @__PURE__ */ y("p", { children: "Loading seat map..." }) });
586
586
  if (K)
587
- return /* @__PURE__ */ y("div", { className: `flex items-center justify-center h-full ${p}`, children: /* @__PURE__ */ D("p", { className: "text-red-500", children: [
587
+ return /* @__PURE__ */ y("div", { className: `flex items-center justify-center h-full ${x}`, children: /* @__PURE__ */ L("p", { className: "text-red-500", children: [
588
588
  "Error loading seat map: ",
589
589
  K.message
590
590
  ] }) });
591
- if (!v)
592
- return /* @__PURE__ */ y("div", { className: `flex items-center justify-center h-full ${p}`, children: /* @__PURE__ */ y("p", { children: "No configuration provided" }) });
593
- const nt = E.width || v.canvas.width, rt = E.height || v.canvas.height;
594
- return /* @__PURE__ */ D(
591
+ if (!p)
592
+ return /* @__PURE__ */ y("div", { className: `flex items-center justify-center h-full ${x}`, children: /* @__PURE__ */ y("p", { children: "No configuration provided" }) });
593
+ const tt = E.width || p.canvas.width, nt = E.height || p.canvas.height;
594
+ return /* @__PURE__ */ L(
595
595
  "div",
596
596
  {
597
597
  ref: we,
598
- className: `relative ${p}`,
598
+ className: `relative ${x}`,
599
599
  style: { width: "100%", height: "100%" },
600
600
  children: [
601
- qe && pe.length > 0 && /* @__PURE__ */ y(
602
- Ae,
601
+ _e && ge.length > 0 && /* @__PURE__ */ y(
602
+ ze,
603
603
  {
604
- floors: pe,
604
+ floors: ge,
605
605
  currentFloorId: P,
606
- onFloorChange: _e,
606
+ onFloorChange: Oe,
607
607
  showAllOption: Y,
608
608
  allLabel: T,
609
609
  position: M,
610
610
  className: k
611
611
  }
612
612
  ),
613
- /* @__PURE__ */ D(
614
- ut,
613
+ /* @__PURE__ */ L(
614
+ dt,
615
615
  {
616
- ref: fe,
617
- width: nt,
618
- height: rt,
619
- scaleX: L,
620
- scaleY: L,
616
+ ref: he,
617
+ width: tt,
618
+ height: nt,
619
+ scaleX: D,
620
+ scaleY: D,
621
621
  x: z.x,
622
622
  y: z.y,
623
623
  draggable: !0,
624
- onDragEnd: Je,
625
- onWheel: Qe,
626
- style: { backgroundColor: v.canvas.backgroundColor, cursor: "grab" },
624
+ onDragEnd: Ke,
625
+ onWheel: Je,
626
+ style: { backgroundColor: p.canvas.backgroundColor, cursor: "grab" },
627
627
  children: [
628
- /* @__PURE__ */ y(Me, { listening: !1, children: le.map((e) => /* @__PURE__ */ y(
629
- ze,
628
+ /* @__PURE__ */ y(Me, { listening: !1, children: ce.map((e) => /* @__PURE__ */ y(
629
+ Te,
630
630
  {
631
631
  stage: e,
632
- stageColor: ce.stageColor
632
+ stageColor: ae.stageColor
633
633
  },
634
634
  e.id
635
635
  )) }),
636
636
  /* @__PURE__ */ y(Me, { children: _.map((e) => /* @__PURE__ */ y(
637
- Te,
637
+ Ne,
638
638
  {
639
639
  seat: e,
640
640
  state: J(e),
641
- colors: ce,
642
- onClick: Ge,
643
- onMouseEnter: et,
644
- onMouseLeave: tt
641
+ colors: ae,
642
+ onClick: qe,
643
+ onMouseEnter: Qe,
644
+ onMouseLeave: et
645
645
  },
646
646
  e.id
647
647
  )) })
648
648
  ]
649
649
  }
650
650
  ),
651
- g && /* @__PURE__ */ y(
652
- Ye,
651
+ f && /* @__PURE__ */ y(
652
+ Xe,
653
653
  {
654
654
  visible: Z.visible,
655
655
  x: Z.x,
656
656
  y: Z.y,
657
657
  seat: Z.seat,
658
- currency: ce.currency,
658
+ currency: ae.currency,
659
659
  state: Z.state
660
660
  }
661
661
  ),
662
- oe && h && /* @__PURE__ */ y(
663
- Xe,
662
+ re && g && /* @__PURE__ */ y(
663
+ Ae,
664
664
  {
665
- scale: L,
665
+ scale: D,
666
666
  minScale: q,
667
667
  maxScale: B,
668
- onZoomIn: Ze,
669
- onZoomOut: Ke,
670
- position: je,
671
- className: Pe
668
+ onZoomIn: Ge,
669
+ onZoomOut: Ze,
670
+ position: Ye,
671
+ className: je
672
672
  }
673
673
  ),
674
- Q.length > 0 && /* @__PURE__ */ D("div", { className: "absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg", children: [
675
- /* @__PURE__ */ D("h3", { className: "font-semibold mb-2", children: [
674
+ Q.length > 0 && /* @__PURE__ */ L("div", { className: "absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg", children: [
675
+ /* @__PURE__ */ L("h3", { className: "font-semibold mb-2", children: [
676
676
  "Selected Seats (",
677
677
  Q.length,
678
678
  ")"
679
679
  ] }),
680
- /* @__PURE__ */ y("div", { className: "max-h-48 overflow-y-auto space-y-1", children: Q.map((e) => /* @__PURE__ */ D("div", { className: "text-sm", children: [
680
+ /* @__PURE__ */ y("div", { className: "max-h-48 overflow-y-auto space-y-1", children: Q.map((e) => /* @__PURE__ */ L("div", { className: "text-sm", children: [
681
681
  e.seatNumber,
682
- e.price && ` - ${ce.currency} ${e.price.toFixed(2)}`
682
+ e.price && ` - ${ae.currency} ${e.price.toFixed(2)}`
683
683
  ] }, e.id)) })
684
684
  ] })
685
685
  ]
686
686
  }
687
687
  );
688
688
  };
689
- let ne = null;
689
+ let te = null;
690
690
  function Ft(t) {
691
- ne = t;
691
+ te = t;
692
692
  }
693
- function Se() {
694
- if (!ne)
693
+ function me() {
694
+ if (!te)
695
695
  throw new Error(
696
696
  "Firebase database not initialized. Call initializeFirebaseForViewer(db) first."
697
697
  );
698
- return ne;
698
+ return te;
699
699
  }
700
- function me() {
701
- return ne !== null;
700
+ function Se() {
701
+ return te !== null;
702
702
  }
703
703
  function kt() {
704
- ne = null;
704
+ te = null;
705
705
  }
706
- function te(t, n) {
706
+ function ye(t, n) {
707
707
  if (t.length !== n.length) return !1;
708
708
  const i = [...t].sort(), r = [...n].sort();
709
709
  return i.every((d, c) => d === r[c]);
710
710
  }
711
- function ke(t, n) {
711
+ function mt(t, n) {
712
712
  const i = [], r = [], d = [];
713
713
  return Object.entries(t).forEach(([c, o]) => {
714
714
  o && typeof o == "object" && o.state && (o.state === "unavailable" ? d.push(c) : o.state === "reserved" && (n && o.userId === n ? i.push(c) : r.push(c)));
@@ -718,7 +718,7 @@ function ke(t, n) {
718
718
  unavailable: d.sort()
719
719
  };
720
720
  }
721
- const he = {
721
+ const ue = {
722
722
  states: null,
723
723
  loading: !0,
724
724
  error: null,
@@ -727,25 +727,25 @@ const he = {
727
727
  otherReservedSeats: [],
728
728
  unavailableSeats: []
729
729
  };
730
- function mt(t) {
731
- const { seatMapId: n, currentUserId: i, enabled: r = !0, onStateChange: d, onError: c } = t, o = A({ ...he }), x = A(d), f = A(c), a = A(i);
732
- x.current = d, f.current = c, a.current = i;
730
+ function St(t) {
731
+ const { seatMapId: n, currentUserId: i, enabled: r = !0, onStateChange: d, onError: c } = t, o = A({ ...ue }), S = A(d), h = A(c), a = A(i);
732
+ S.current = d, h.current = c, a.current = i;
733
733
  const s = I(
734
- (p) => {
734
+ (x) => {
735
735
  if (!r || !n)
736
- return o.current = { ...he, loading: !1 }, () => {
736
+ return o.current = { ...ue, loading: !1 }, () => {
737
737
  };
738
- if (!me())
738
+ if (!Se())
739
739
  return o.current = {
740
- ...he,
740
+ ...ue,
741
741
  loading: !1,
742
742
  error: new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")
743
743
  }, () => {
744
744
  };
745
- const w = Se(), R = ye(w, `seat_states/${n}`);
745
+ const C = me(), R = ve(C, `seatmaps/${n}/seat_states`);
746
746
  return Le(R, (k) => {
747
- const T = k.val() || {}, X = ke(T, a.current), j = o.current;
748
- (j.loading || !te(j.myReservedSeats, X.myReserved) || !te(j.otherReservedSeats, X.otherReserved) || !te(j.unavailableSeats, X.unavailable)) && (o.current = {
747
+ const T = k.val() || {}, X = mt(T, a.current), j = o.current;
748
+ (j.loading || !ye(j.myReservedSeats, X.myReserved) || !ye(j.otherReservedSeats, X.otherReserved) || !ye(j.unavailableSeats, X.unavailable)) && (o.current = {
749
749
  states: T,
750
750
  loading: !1,
751
751
  error: null,
@@ -753,40 +753,30 @@ function mt(t) {
753
753
  myReservedSeats: X.myReserved,
754
754
  otherReservedSeats: X.otherReserved,
755
755
  unavailableSeats: X.unavailable
756
- }, x.current?.(T), p());
756
+ }, S.current?.(T), x());
757
757
  }, (k) => {
758
758
  o.current = {
759
759
  ...o.current,
760
760
  loading: !1,
761
761
  error: k
762
- }, f.current?.(k), p();
762
+ }, h.current?.(k), x();
763
763
  }), () => {
764
- Ne(R);
764
+ De(R);
765
765
  };
766
766
  },
767
- [n, r]
768
- ), u = I(() => o.current, []), g = I(() => he, []), h = dt(s, u, g);
769
- return W(() => {
770
- if (h.states && i !== void 0) {
771
- const p = ke(h.states, i), w = o.current;
772
- (!te(w.myReservedSeats, p.myReserved) || !te(w.otherReservedSeats, p.otherReserved)) && (o.current = {
773
- ...w,
774
- myReservedSeats: p.myReserved,
775
- otherReservedSeats: p.otherReserved,
776
- unavailableSeats: p.unavailable,
777
- lastUpdated: Date.now()
778
- });
779
- }
780
- }, [i]), {
781
- states: h.states,
782
- loading: h.loading,
783
- error: h.error,
784
- lastUpdated: h.lastUpdated,
785
- myReservedSeats: h.myReservedSeats,
786
- otherReservedSeats: h.otherReservedSeats,
787
- unavailableSeats: h.unavailableSeats,
767
+ [n, r, i]
768
+ // Include currentUserId to re-derive on user change
769
+ ), u = I(() => o.current, []), f = I(() => ue, []), g = lt(s, u, f);
770
+ return {
771
+ states: g.states,
772
+ loading: g.loading,
773
+ error: g.error,
774
+ lastUpdated: g.lastUpdated,
775
+ myReservedSeats: g.myReservedSeats,
776
+ otherReservedSeats: g.otherReservedSeats,
777
+ unavailableSeats: g.unavailableSeats,
788
778
  // Legacy alias
789
- reservedSeats: h.otherReservedSeats
779
+ reservedSeats: g.otherReservedSeats
790
780
  };
791
781
  }
792
782
  function xt(t) {
@@ -796,26 +786,26 @@ function xt(t) {
796
786
  subscribeToChanges: r = !1,
797
787
  onConfigLoad: d,
798
788
  onError: c
799
- } = t, [o, x] = N(null), [f, a] = N(!0), [s, u] = N(null), g = A(d), h = A(c);
800
- g.current = d, h.current = c;
801
- const p = I(async () => {
789
+ } = t, [o, S] = N(null), [h, a] = N(!0), [s, u] = N(null), f = A(d), g = A(c);
790
+ f.current = d, g.current = c;
791
+ const x = I(async () => {
802
792
  if (!n) return;
803
- if (!me()) {
793
+ if (!Se()) {
804
794
  u(new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")), a(!1);
805
795
  return;
806
796
  }
807
- const w = Se(), R = ye(w, `seatmaps/${n}`);
797
+ const C = me(), R = ve(C, `seatmaps/${n}`);
808
798
  try {
809
799
  a(!0), u(null);
810
- const M = (await gt(R)).val();
800
+ const M = (await ft(R)).val();
811
801
  if (M) {
812
- const k = pt(M);
813
- x(k), g.current?.(k);
802
+ const k = gt(M);
803
+ S(k), f.current?.(k);
814
804
  } else
815
805
  u(new Error(`Seat map ${n} not found in Firebase`));
816
806
  } catch (F) {
817
807
  const M = F instanceof Error ? F : new Error("Unknown error");
818
- u(M), h.current?.(M);
808
+ u(M), g.current?.(M);
819
809
  } finally {
820
810
  a(!1);
821
811
  }
@@ -825,8 +815,8 @@ function xt(t) {
825
815
  a(!1);
826
816
  return;
827
817
  }
828
- if (p(), r && me()) {
829
- const w = Se(), R = ye(w, `seatmaps/${n}/meta/updated_at`);
818
+ if (x(), r && Se()) {
819
+ const C = me(), R = ve(C, `seatmaps/${n}/meta/updated_at`);
830
820
  let F = !0, M = null;
831
821
  return Le(R, (Y) => {
832
822
  if (F) {
@@ -834,19 +824,19 @@ function xt(t) {
834
824
  return;
835
825
  }
836
826
  const T = Y.val();
837
- Y.exists() && T !== M && (M = T, p());
827
+ Y.exists() && T !== M && (M = T, x());
838
828
  }), () => {
839
- Ne(R);
829
+ De(R);
840
830
  };
841
831
  }
842
832
  }, [n, i, r]), {
843
833
  config: o,
844
- loading: f,
834
+ loading: h,
845
835
  error: s,
846
- refetch: p
836
+ refetch: x
847
837
  };
848
838
  }
849
- function Dt(t) {
839
+ function Lt(t) {
850
840
  const {
851
841
  seatMapId: n,
852
842
  userId: i,
@@ -854,9 +844,9 @@ function Dt(t) {
854
844
  subscribeToDesignChanges: d = !1,
855
845
  onConfigLoad: c,
856
846
  onStateChange: o,
857
- onError: x
847
+ onError: S
858
848
  } = t, {
859
- config: f,
849
+ config: h,
860
850
  loading: a,
861
851
  error: s,
862
852
  refetch: u
@@ -865,46 +855,46 @@ function Dt(t) {
865
855
  enabled: r,
866
856
  subscribeToChanges: d,
867
857
  onConfigLoad: c,
868
- onError: x
858
+ onError: S
869
859
  }), {
870
- states: g,
871
- loading: h,
872
- error: p,
873
- lastUpdated: w,
860
+ states: f,
861
+ loading: g,
862
+ error: x,
863
+ lastUpdated: C,
874
864
  myReservedSeats: R,
875
865
  otherReservedSeats: F,
876
866
  unavailableSeats: M,
877
867
  reservedSeats: k
878
- } = mt({
868
+ } = St({
879
869
  seatMapId: n,
880
870
  currentUserId: i,
881
871
  enabled: r,
882
872
  onStateChange: o,
883
- onError: x
873
+ onError: S
884
874
  });
885
875
  return {
886
- config: f,
887
- loading: a || h,
888
- error: s || p,
876
+ config: h,
877
+ loading: a || g,
878
+ error: s || x,
889
879
  myReservedSeats: R,
890
880
  otherReservedSeats: F,
891
881
  unavailableSeats: M,
892
882
  reservedSeats: k,
893
- seatStates: g,
894
- lastUpdated: w,
883
+ seatStates: f,
884
+ lastUpdated: C,
895
885
  refetch: u
896
886
  };
897
887
  }
898
888
  export {
899
- St as DEFAULT_COLORS,
889
+ vt as DEFAULT_COLORS,
900
890
  It as SeatMapViewer,
901
891
  kt as clearFirebaseInstance,
902
892
  Ft as initializeFirebaseForViewer,
903
- me as isFirebaseInitialized,
904
- vt as useConfigFetcher,
893
+ Se as isFirebaseInitialized,
894
+ pt as useConfigFetcher,
905
895
  bt as useContainerSize,
906
896
  xt as useFirebaseConfig,
907
- mt as useFirebaseSeatStates,
908
- Dt as useRealtimeSeatMap,
897
+ St as useFirebaseSeatStates,
898
+ Lt as useRealtimeSeatMap,
909
899
  yt as useTouchGestures
910
900
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zonetrix/viewer",
3
- "version": "2.10.3",
3
+ "version": "2.10.4",
4
4
  "type": "module",
5
5
  "description": "Lightweight React component for rendering interactive seat maps",
6
6
  "main": "./dist/index.js",