@zonetrix/viewer 2.10.3 → 2.10.5

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),w=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(()=>{w()},[n]),{config:s,loading:r,error:u,refetch:w}}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(w=>{const g=w[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(),w=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),v=me(f,p);if(a.current!==null&&r.current!==null){const R=b/a.current,E=Math.min(Math.max(s.currentScale*R,s.minScale),s.maxScale),F=o.getBoundingClientRect(),M=v.x-F.left,j=v.y-F.top,z=s.currentScale,L={x:(M-s.currentPosition.x)/z,y:(j-s.currentPosition.y)/z},D=v.x-r.current.x,N=v.y-r.current.y,Q={x:M-L.x*E+D,y:j-L.y*E+N};s.onScaleChange(E,Q),a.current=b,r.current=v}},l=c=>{c.touches.length<2&&(a.current=null,r.current=null)};return o.addEventListener("touchstart",w,{passive:!1}),o.addEventListener("touchmove",g,{passive:!1}),o.addEventListener("touchend",l),()=>{o.removeEventListener("touchstart",w),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(v=>{h(n,v);const R=v.target.getStage();R&&l&&(R.container().style.cursor="pointer")},[n,h,l]),p=t.useCallback(v=>{u();const R=v.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 w=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}),w.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"),w={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:w,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:w=[],onSeatSelect:g,onSeatDeselect:l,onSelectionChange:c,colorOverrides:f,showTooltip:p=!0,zoomEnabled:b=!0,className:v="",onConfigLoad:R,onError:E,showFloorSelector:F,floorSelectorPosition:M="top-left",floorSelectorClassName:j,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=F!==void 0?F: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,m=-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),m=Math.max(m,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)),m=Math.max(m,C.position.y+(C.config?.height||100))}),{minX:d,minY:S,maxX:y,maxY:m,width:y-d,height:m-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,m=k.height,C=y-N*2,Z=m-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=m/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(w);return{reserved:e,unavailable:d,myReserved:S}},[h,u,w]),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(()=>{_&&E&&E(_)},[_,E]),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 m=new Set(y);return S?m.delete(e.id):m.add(e.id),m}),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,m=S/2,C={x:(y-T.x)/I,y:(m-T.y)/I};H(e),B({x:y-C.x*e,y:m-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,m=S/2,C={x:(y-T.x)/I,y:(m-T.y)/I};H(e),B({x:y-C.x*e,y:m-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 m=1.1,C=e.evt.deltaY>0?S/m:S*m,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 m=S.container().getBoundingClientRect();ye({visible:!0,x:m.left+y.x,y:m.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 ${v}`,children:i.jsx("p",{children:"Loading seat map..."})});if(_)return i.jsx("div",{className:`flex items-center justify-center h-full ${v}`,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 ${v}`,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 ${v}`,style:{width:"100%",height:"100%"},children:[Ue&&de.length>0&&i.jsx(Fe,{floors:de,currentFloorId:A,onFloorChange:$e,showAllOption:z,allLabel:L,position:M,className:j}),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}),w=t.useRef(h),g=t.useRef(u),l=t.useRef(a);w.current=h,g.current=u,l.current=a;const c=t.useCallback(v=>{if(!r||!s)return(o.current.loading!==!1||o.current.states!==null)&&(o.current={...ae,loading:!1},v()),()=>{};if(!ce()){const j="Firebase not initialized. Call initializeFirebaseForViewer first.";return o.current.error?.message!==j&&(o.current={...ae,loading:!1,error:new Error(j)},v()),()=>{}}const R=pe(),E=W.ref(R,`seatmaps/${s}/seat_states`),F=j=>{const L=j.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},w.current?.(L),v())},M=j=>{o.current={...o.current,loading:!1,error:j},g.current?.(j),v()};return W.onValue(E,F,M),()=>{W.off(E)}},[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,w]=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 v=t.useCallback(async()=>{if(!s)return;if(!ce()){f(new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")),l(!1);return}const R=pe(),E=W.ref(R,`seatmaps/${s}`);try{l(!0),f(null);const M=(await W.get(E)).val();if(M){const j=ot.fromFirebaseSeatMap(M);w(j),p.current?.(j)}else f(new Error(`Seat map ${s} not found in Firebase`))}catch(F){const M=F instanceof Error?F:new Error("Unknown error");f(M),b.current?.(M)}finally{l(!1)}},[s]);return t.useEffect(()=>{if(!a||!s){l(!1);return}if(v(),r&&ce()){const R=pe(),E=W.ref(R,`seatmaps/${s}/meta/updated_at`);let F=!0,M=null;const j=z=>{if(F){F=!1,M=z.val();return}const L=z.val();z.exists()&&L!==M&&(M=L,v())};return W.onValue(E,j),()=>{W.off(E)}}},[s,a,r]),{config:o,loading:g,error:c,refetch:v}}function ut(n){const{seatMapId:s,userId:a,enabled:r=!0,subscribeToDesignChanges:h=!1,onConfigLoad:u,onStateChange:o,onError:w}=n,{config:g,loading:l,error:c,refetch:f}=Te({seatMapId:s,enabled:r,subscribeToChanges:h,onConfigLoad:u,onError:w}),{states:p,loading:b,error:v,lastUpdated:R,myReservedSeats:E,otherReservedSeats:F,unavailableSeats:M,reservedSeats:j}=Le({seatMapId:s,currentUserId:a,enabled:r,onStateChange:o,onError:w});return{config:g,loading:l||b,error:c||v,myReservedSeats:E,otherReservedSeats:F,unavailableSeats:M,reservedSeats:j,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
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 () => {
2
+ import { useState as T, useEffect as W, useRef as A, useCallback as F, useMemo as U, memo as ne, useSyncExternalStore as lt } from "react";
3
+ import { Stage as dt, Layer as Me, Group as ut, Rect as Le, Text as Ee, Circle as ht } from "react-konva";
4
+ import { ref as ve, onValue as De, off as Ne, get as ft } from "firebase/database";
5
+ import { fromFirebaseSeatMap as gt } from "@zonetrix/shared";
6
+ function pt(t) {
7
+ const [n, i] = T(null), [r, d] = T(!1), [c, o] = T(null), x = 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);
@@ -31,16 +31,16 @@ function vt(t) {
31
31
  };
32
32
  }
33
33
  function bt(t) {
34
- const [n, i] = N({ width: 0, height: 0 });
34
+ const [n, i] = T({ width: 0, height: 0 });
35
35
  return W(() => {
36
36
  const r = t.current;
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
40
  const o = new ResizeObserver((x) => {
41
- const f = x[0];
42
- if (!f) return;
43
- const { width: a, height: s } = f.contentRect;
41
+ const h = x[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), () => {
@@ -65,35 +65,35 @@ function yt(t, n) {
65
65
  const o = c.container(), x = (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), m = 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, M = 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 = {
80
- x: (M - n.currentPosition.x) / Y,
81
- y: (k - n.currentPosition.y) / Y
82
- }, X = p.x - r.current.x, j = p.y - r.current.y, oe = {
83
- x: M - T.x * R + X,
84
- y: k - T.y * R + j
79
+ ), L = o.getBoundingClientRect(), E = m.x - L.left, R = m.y - L.top, Y = n.currentScale, k = {
80
+ x: (E - n.currentPosition.x) / Y,
81
+ y: (R - n.currentPosition.y) / Y
82
+ }, X = m.x - r.current.x, j = m.y - r.current.y, re = {
83
+ x: E - k.x * M + X,
84
+ y: R - k.y * M + j
85
85
  };
86
- n.onScaleChange(R, oe), i.current = h, r.current = p;
86
+ n.onScaleChange(M, re), i.current = g, r.current = m;
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", x, { passive: !1 }), o.addEventListener("touchmove", h, { passive: !1 }), o.addEventListener("touchend", a), () => {
92
+ o.removeEventListener("touchstart", x), 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,45 +103,45 @@ 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
+ }, Te = 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,
111
111
  unavailable: i.seatUnavailable,
112
112
  hidden: i.seatHidden
113
113
  // Hidden seats are filtered out, but included for type safety
114
- }[n], a = n === "available" || n === "selected", s = I(() => {
114
+ }[n], a = n === "available" || n === "selected", s = F(() => {
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 = F((m) => {
117
+ d(t, m);
118
+ const C = m.target.getStage();
119
+ C && a && (C.container().style.cursor = "pointer");
120
+ }, [t, d, a]), f = F((m) => {
121
121
  c();
122
- const w = p.target.getStage();
123
- w && (w.container().style.cursor = "grab");
124
- }, [c]), h = {
122
+ const C = m.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
+ Le,
143
143
  {
144
- ...h,
144
+ ...g,
145
145
  width: 24,
146
146
  height: 24,
147
147
  offsetX: 12,
@@ -151,7 +151,7 @@ const St = {
151
151
  );
152
152
  });
153
153
  Te.displayName = "ViewerSeat";
154
- const ze = re(({ stage: t, stageColor: n }) => {
154
+ const ke = 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__ */ D(ut, { x: t.position.x, y: t.position.y, rotation: t.config.rotation || 0, children: [
166
166
  /* @__PURE__ */ y(
167
- De,
167
+ Le,
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
+ ke.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 x = U(
219
+ () => [...t].sort((f, g) => f.order - g.order),
220
220
  [t]
221
221
  ), a = {
222
222
  position: "absolute",
@@ -261,20 +261,20 @@ const Ae = re(({
261
261
  children: d
262
262
  }
263
263
  ),
264
- x.map((g) => /* @__PURE__ */ y(
264
+ x.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__ */ D("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,
@@ -362,7 +362,7 @@ const Ye = re(({
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,13 +379,13 @@ 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: [
388
+ return /* @__PURE__ */ y("div", { style: x, children: /* @__PURE__ */ D("div", { style: h, children: [
389
389
  r.sectionName && /* @__PURE__ */ D("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 })
@@ -402,13 +402,13 @@ const Ye = re(({
402
402
  r.price.toFixed(2)
403
403
  ] })
404
404
  ] }),
405
- /* @__PURE__ */ D("div", { style: g, children: [
405
+ /* @__PURE__ */ D("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,
@@ -418,144 +418,144 @@ const It = ({
418
418
  unavailableSeats: c = [],
419
419
  selectedSeats: o,
420
420
  myReservedSeats: x = [],
421
- onSeatSelect: f,
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,
429
- onError: R,
425
+ showTooltip: f = !0,
426
+ zoomEnabled: g = !0,
427
+ className: m = "",
428
+ onConfigLoad: C,
429
+ onError: M,
430
430
  // Floor selector props
431
- showFloorSelector: F,
432
- floorSelectorPosition: M = "top-left",
433
- floorSelectorClassName: k,
431
+ showFloorSelector: L,
432
+ floorSelectorPosition: E = "top-left",
433
+ floorSelectorClassName: R,
434
434
  showAllFloorsOption: Y = !0,
435
- allFloorsLabel: T = "All",
435
+ allFloorsLabel: k = "All",
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), I = bt(we), [O, Ce] = T(/* @__PURE__ */ new Set()), [N, G] = T(1), [z, H] = T({ x: 0, y: 0 }), [We, Be] = T(null), [$e, Ue] = T(1), ie = A({ width: 0, height: 0 }), [Z, Re] = T({ 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 = F((e) => {
449
+ fe || Be(e), r?.(e);
450
+ }, [fe, r]), ge = p?.floors || [], _e = L !== void 0 ? L : 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, S = -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), S = Math.max(S, 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)), S = Math.max(S, w.position.y + (w.config?.height || 100));
470
+ }), { minX: l, minY: b, maxX: v, maxY: S, width: v - l, height: S - 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 = $(() => {
473
+ if (!X || !p || !$ || I.width === 0 || I.height === 0) return;
474
+ const e = Math.abs(I.width - ie.current.width), l = Math.abs(I.height - ie.current.height);
475
+ if (!(ie.current.width === 0) && e < 10 && l < 10) return;
476
+ ie.current = I;
477
+ const v = I.width, S = I.height, w = v - j * 2, ee = S - 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 = S / 2, at = it - rt * de, ct = st - ot * de;
478
+ G(de), H({ x: at, y: ct }), Ue(de);
479
+ }, [X, p, $, j, B, I, P]);
480
+ const V = U(() => {
481
481
  const e = new Set(d), l = new Set(c), b = new Set(x);
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, x]), pe = U(() => o ? new Set(o) : null, [o]), J = F((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(() => {
490
- K && R && R(K);
491
- }, [K, R]), W(() => {
492
- ae && ve && Ce(ve);
493
- }, [ae, ve]);
494
- const Ge = I((e) => {
488
+ p && C && C(p);
489
+ }, [p, C]), W(() => {
490
+ K && M && M(K);
491
+ }, [K, M]), W(() => {
492
+ se && pe && Ce(pe);
493
+ }, [se, pe]);
494
+ const qe = F((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);
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]);
499
+ se || Ce((v) => {
500
+ const S = new Set(v);
501
+ return b ? S.delete(e.id) : S.add(e.id), S;
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 = F(() => {
508
+ if (!g) return;
509
+ const e = Math.min(N + oe, B);
510
+ if (e !== N) {
511
+ const l = I.width || p?.canvas.width || 800, b = I.height || p?.canvas.height || 600, v = l / 2, S = b / 2, w = {
512
+ x: (v - z.x) / N,
513
+ y: (S - z.y) / N
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: S - 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, N, oe, B, I, p, z]), Ze = F(() => {
521
+ if (!g) return;
522
+ const e = Math.max(N - oe, q);
523
+ if (e !== N) {
524
+ const l = I.width || p?.canvas.width || 800, b = I.height || p?.canvas.height || 600, v = l / 2, S = b / 2, w = {
525
+ x: (v - z.x) / N,
526
+ y: (S - z.y) / N
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: S - w.y * e
531
531
  });
532
532
  }
533
- }, [h, L, ie, q, E, v, z]), Je = I((e) => {
533
+ }, [g, N, oe, q, I, p, z]), Ke = F((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 = F((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 S = 1.1, w = e.evt.deltaY > 0 ? b / S : b * S, 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: N,
559
559
  currentPosition: z,
560
560
  onScaleChange: (e, l) => {
561
561
  G(e), H(l);
@@ -564,72 +564,72 @@ const It = ({
564
564
  H(e);
565
565
  }
566
566
  });
567
- const et = I((e, l) => {
568
- if (!g) return;
567
+ const Qe = F((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;
573
- const m = b.container().getBoundingClientRect();
571
+ const v = b.getPointerPosition();
572
+ if (!v) return;
573
+ const S = b.container().getBoundingClientRect();
574
574
  Re({
575
575
  visible: !0,
576
- x: m.left + S.x,
577
- y: m.top + S.y,
576
+ x: S.left + v.x,
577
+ y: S.top + v.y,
578
578
  seat: e,
579
579
  state: J(e)
580
580
  });
581
- }, [g, J]), tt = I(() => {
581
+ }, [f, J]), et = F(() => {
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 ${m}`, 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 ${m}`, children: /* @__PURE__ */ D("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;
591
+ if (!p)
592
+ return /* @__PURE__ */ y("div", { className: `flex items-center justify-center h-full ${m}`, children: /* @__PURE__ */ y("p", { children: "No configuration provided" }) });
593
+ const tt = I.width || p.canvas.width, nt = I.height || p.canvas.height;
594
594
  return /* @__PURE__ */ D(
595
595
  "div",
596
596
  {
597
597
  ref: we,
598
- className: `relative ${p}`,
598
+ className: `relative ${m}`,
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
- allLabel: T,
609
- position: M,
610
- className: k
608
+ allLabel: k,
609
+ position: E,
610
+ className: R
611
611
  }
612
612
  ),
613
613
  /* @__PURE__ */ D(
614
- ut,
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: N,
620
+ scaleY: N,
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
+ ke,
630
630
  {
631
631
  stage: e,
632
- stageColor: ce.stageColor
632
+ stageColor: ae.stageColor
633
633
  },
634
634
  e.id
635
635
  )) }),
@@ -638,37 +638,37 @@ const It = ({
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: N,
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
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: [
@@ -679,36 +679,36 @@ const It = ({
679
679
  ] }),
680
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: [
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
- function kt() {
704
- ne = null;
703
+ function Lt() {
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,66 +727,58 @@ 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;
733
- const s = I(
734
- (p) => {
730
+ function St(t) {
731
+ const { seatMapId: n, currentUserId: i, enabled: r = !0, onStateChange: d, onError: c } = t, o = A({ ...ue }), x = A(d), h = A(c), a = A(i);
732
+ x.current = d, h.current = c, a.current = i;
733
+ const s = F(
734
+ (m) => {
735
735
  if (!r || !n)
736
- return o.current = { ...he, loading: !1 }, () => {
736
+ return (o.current.loading !== !1 || o.current.states !== null) && (o.current = { ...ue, loading: !1 }, m()), () => {
737
737
  };
738
- if (!me())
739
- return o.current = {
740
- ...he,
738
+ if (!Se()) {
739
+ const R = "Firebase not initialized. Call initializeFirebaseForViewer first.";
740
+ return o.current.error?.message !== R && (o.current = {
741
+ ...ue,
741
742
  loading: !1,
742
- error: new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")
743
- }, () => {
743
+ error: new Error(R)
744
+ }, m()), () => {
744
745
  };
745
- const w = Se(), R = ye(w, `seat_states/${n}`);
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 = {
749
- states: T,
746
+ }
747
+ const C = me(), M = ve(C, `seatmaps/${n}/seat_states`);
748
+ return De(M, (R) => {
749
+ const k = R.val() || {}, X = mt(k, a.current), j = o.current;
750
+ (j.loading || !ye(j.myReservedSeats, X.myReserved) || !ye(j.otherReservedSeats, X.otherReserved) || !ye(j.unavailableSeats, X.unavailable)) && (o.current = {
751
+ states: k,
750
752
  loading: !1,
751
753
  error: null,
752
754
  lastUpdated: Date.now(),
753
755
  myReservedSeats: X.myReserved,
754
756
  otherReservedSeats: X.otherReserved,
755
757
  unavailableSeats: X.unavailable
756
- }, x.current?.(T), p());
757
- }, (k) => {
758
+ }, x.current?.(k), m());
759
+ }, (R) => {
758
760
  o.current = {
759
761
  ...o.current,
760
762
  loading: !1,
761
- error: k
762
- }, f.current?.(k), p();
763
+ error: R
764
+ }, h.current?.(R), m();
763
765
  }), () => {
764
- Ne(R);
766
+ Ne(M);
765
767
  };
766
768
  },
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,
769
+ [n, r, i]
770
+ // Include currentUserId to re-derive on user change
771
+ ), u = F(() => o.current, []), f = F(() => ue, []), g = lt(s, u, f);
772
+ return {
773
+ states: g.states,
774
+ loading: g.loading,
775
+ error: g.error,
776
+ lastUpdated: g.lastUpdated,
777
+ myReservedSeats: g.myReservedSeats,
778
+ otherReservedSeats: g.otherReservedSeats,
779
+ unavailableSeats: g.unavailableSeats,
788
780
  // Legacy alias
789
- reservedSeats: h.otherReservedSeats
781
+ reservedSeats: g.otherReservedSeats
790
782
  };
791
783
  }
792
784
  function xt(t) {
@@ -796,26 +788,26 @@ function xt(t) {
796
788
  subscribeToChanges: r = !1,
797
789
  onConfigLoad: d,
798
790
  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 () => {
791
+ } = t, [o, x] = T(null), [h, a] = T(!0), [s, u] = T(null), f = A(d), g = A(c);
792
+ f.current = d, g.current = c;
793
+ const m = F(async () => {
802
794
  if (!n) return;
803
- if (!me()) {
795
+ if (!Se()) {
804
796
  u(new Error("Firebase not initialized. Call initializeFirebaseForViewer first.")), a(!1);
805
797
  return;
806
798
  }
807
- const w = Se(), R = ye(w, `seatmaps/${n}`);
799
+ const C = me(), M = ve(C, `seatmaps/${n}`);
808
800
  try {
809
801
  a(!0), u(null);
810
- const M = (await gt(R)).val();
811
- if (M) {
812
- const k = pt(M);
813
- x(k), g.current?.(k);
802
+ const E = (await ft(M)).val();
803
+ if (E) {
804
+ const R = gt(E);
805
+ x(R), f.current?.(R);
814
806
  } else
815
807
  u(new Error(`Seat map ${n} not found in Firebase`));
816
- } catch (F) {
817
- const M = F instanceof Error ? F : new Error("Unknown error");
818
- u(M), h.current?.(M);
808
+ } catch (L) {
809
+ const E = L instanceof Error ? L : new Error("Unknown error");
810
+ u(E), g.current?.(E);
819
811
  } finally {
820
812
  a(!1);
821
813
  }
@@ -825,25 +817,25 @@ function xt(t) {
825
817
  a(!1);
826
818
  return;
827
819
  }
828
- if (p(), r && me()) {
829
- const w = Se(), R = ye(w, `seatmaps/${n}/meta/updated_at`);
830
- let F = !0, M = null;
831
- return Le(R, (Y) => {
832
- if (F) {
833
- F = !1, M = Y.val();
820
+ if (m(), r && Se()) {
821
+ const C = me(), M = ve(C, `seatmaps/${n}/meta/updated_at`);
822
+ let L = !0, E = null;
823
+ return De(M, (Y) => {
824
+ if (L) {
825
+ L = !1, E = Y.val();
834
826
  return;
835
827
  }
836
- const T = Y.val();
837
- Y.exists() && T !== M && (M = T, p());
828
+ const k = Y.val();
829
+ Y.exists() && k !== E && (E = k, m());
838
830
  }), () => {
839
- Ne(R);
831
+ Ne(M);
840
832
  };
841
833
  }
842
834
  }, [n, i, r]), {
843
835
  config: o,
844
- loading: f,
836
+ loading: h,
845
837
  error: s,
846
- refetch: p
838
+ refetch: m
847
839
  };
848
840
  }
849
841
  function Dt(t) {
@@ -856,7 +848,7 @@ function Dt(t) {
856
848
  onStateChange: o,
857
849
  onError: x
858
850
  } = t, {
859
- config: f,
851
+ config: h,
860
852
  loading: a,
861
853
  error: s,
862
854
  refetch: u
@@ -867,15 +859,15 @@ function Dt(t) {
867
859
  onConfigLoad: c,
868
860
  onError: x
869
861
  }), {
870
- states: g,
871
- loading: h,
872
- error: p,
873
- lastUpdated: w,
874
- myReservedSeats: R,
875
- otherReservedSeats: F,
876
- unavailableSeats: M,
877
- reservedSeats: k
878
- } = mt({
862
+ states: f,
863
+ loading: g,
864
+ error: m,
865
+ lastUpdated: C,
866
+ myReservedSeats: M,
867
+ otherReservedSeats: L,
868
+ unavailableSeats: E,
869
+ reservedSeats: R
870
+ } = St({
879
871
  seatMapId: n,
880
872
  currentUserId: i,
881
873
  enabled: r,
@@ -883,28 +875,28 @@ function Dt(t) {
883
875
  onError: x
884
876
  });
885
877
  return {
886
- config: f,
887
- loading: a || h,
888
- error: s || p,
889
- myReservedSeats: R,
890
- otherReservedSeats: F,
891
- unavailableSeats: M,
892
- reservedSeats: k,
893
- seatStates: g,
894
- lastUpdated: w,
878
+ config: h,
879
+ loading: a || g,
880
+ error: s || m,
881
+ myReservedSeats: M,
882
+ otherReservedSeats: L,
883
+ unavailableSeats: E,
884
+ reservedSeats: R,
885
+ seatStates: f,
886
+ lastUpdated: C,
895
887
  refetch: u
896
888
  };
897
889
  }
898
890
  export {
899
- St as DEFAULT_COLORS,
891
+ vt as DEFAULT_COLORS,
900
892
  It as SeatMapViewer,
901
- kt as clearFirebaseInstance,
893
+ Lt as clearFirebaseInstance,
902
894
  Ft as initializeFirebaseForViewer,
903
- me as isFirebaseInitialized,
904
- vt as useConfigFetcher,
895
+ Se as isFirebaseInitialized,
896
+ pt as useConfigFetcher,
905
897
  bt as useContainerSize,
906
898
  xt as useFirebaseConfig,
907
- mt as useFirebaseSeatStates,
899
+ St as useFirebaseSeatStates,
908
900
  Dt as useRealtimeSeatMap,
909
901
  yt as useTouchGestures
910
902
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zonetrix/viewer",
3
- "version": "2.10.3",
3
+ "version": "2.10.5",
4
4
  "type": "module",
5
5
  "description": "Lightweight React component for rendering interactive seat maps",
6
6
  "main": "./dist/index.js",