@zonetrix/viewer 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -8
- package/dist/components/SeatMapViewer.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +214 -194
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,7 +49,8 @@ import type {
|
|
|
49
49
|
SeatShape,
|
|
50
50
|
SeatData,
|
|
51
51
|
SeatMapConfig,
|
|
52
|
-
ColorSettings
|
|
52
|
+
ColorSettings,
|
|
53
|
+
FloorConfig
|
|
53
54
|
} from '@zonetrix/viewer';
|
|
54
55
|
|
|
55
56
|
// Hooks
|
|
@@ -103,7 +104,7 @@ function BookingApp() {
|
|
|
103
104
|
|------|------|----------|-------------|
|
|
104
105
|
| `config` | `SeatMapConfig` | No* | Seat map configuration object |
|
|
105
106
|
| `configUrl` | `string` | No* | URL to fetch configuration from |
|
|
106
|
-
| `floorId` | `string` | No | Filter seats/stages by floor ID |
|
|
107
|
+
| `floorId` | `string` | No | Filter seats/stages by floor ID (controlled mode) |
|
|
107
108
|
| `onFloorChange` | `(floorId: string) => void` | No | Callback when floor changes |
|
|
108
109
|
| `reservedSeats` | `string[]` | No | Array of seat IDs/numbers to mark as reserved |
|
|
109
110
|
| `unavailableSeats` | `string[]` | No | Array of seat IDs/numbers to mark as unavailable |
|
|
@@ -116,6 +117,11 @@ function BookingApp() {
|
|
|
116
117
|
| `className` | `string` | No | Custom CSS class for the container |
|
|
117
118
|
| `onConfigLoad` | `(config: SeatMapConfig) => void` | No | Callback when config is loaded |
|
|
118
119
|
| `onError` | `(error: Error) => void` | No | Callback when an error occurs |
|
|
120
|
+
| `showFloorSelector` | `boolean` | No | Show/hide built-in floor selector (default: true when floors > 1) |
|
|
121
|
+
| `floorSelectorPosition` | `string` | No | Position: 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' |
|
|
122
|
+
| `floorSelectorClassName` | `string` | No | Custom CSS class for floor selector |
|
|
123
|
+
| `showAllFloorsOption` | `boolean` | No | Show "All" button in floor selector (default: true) |
|
|
124
|
+
| `allFloorsLabel` | `string` | No | Custom label for "All" button (default: 'All') |
|
|
119
125
|
|
|
120
126
|
*Note: Either `config` or `configUrl` must be provided.
|
|
121
127
|
|
|
@@ -257,19 +263,43 @@ function MobileOptimized() {
|
|
|
257
263
|
}
|
|
258
264
|
```
|
|
259
265
|
|
|
260
|
-
### 6. Multi-floor Venue
|
|
266
|
+
### 6. Multi-floor Venue (Built-in Floor Selector)
|
|
267
|
+
|
|
268
|
+
The viewer includes a built-in floor selector that automatically appears when your config has multiple floors.
|
|
261
269
|
|
|
262
270
|
```tsx
|
|
263
|
-
import { useState } from 'react';
|
|
264
271
|
import { SeatMapViewer } from '@zonetrix/viewer';
|
|
265
272
|
|
|
266
273
|
function MultiFloorVenue() {
|
|
267
|
-
|
|
274
|
+
return (
|
|
275
|
+
<SeatMapViewer
|
|
276
|
+
config={venueConfig}
|
|
277
|
+
onSeatSelect={(seat) => handleSelection(seat)}
|
|
278
|
+
// Floor selector auto-shows when config.floors.length > 1
|
|
279
|
+
// Customize position and labels:
|
|
280
|
+
floorSelectorPosition="top-right"
|
|
281
|
+
allFloorsLabel="All Floors"
|
|
282
|
+
/>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
#### Custom Floor Selector (Controlled Mode)
|
|
288
|
+
|
|
289
|
+
For full control over the floor selector UI, use controlled mode:
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
import { useState } from 'react';
|
|
293
|
+
import { SeatMapViewer } from '@zonetrix/viewer';
|
|
294
|
+
|
|
295
|
+
function CustomFloorSelector() {
|
|
296
|
+
const [currentFloor, setCurrentFloor] = useState<string | null>(null);
|
|
268
297
|
|
|
269
298
|
return (
|
|
270
299
|
<div>
|
|
271
|
-
{/*
|
|
300
|
+
{/* Your custom floor selector */}
|
|
272
301
|
<div className="floor-tabs">
|
|
302
|
+
<button onClick={() => setCurrentFloor(null)}>All</button>
|
|
273
303
|
{venueConfig.floors?.map((floor) => (
|
|
274
304
|
<button
|
|
275
305
|
key={floor.id}
|
|
@@ -283,7 +313,8 @@ function MultiFloorVenue() {
|
|
|
283
313
|
|
|
284
314
|
<SeatMapViewer
|
|
285
315
|
config={venueConfig}
|
|
286
|
-
|
|
316
|
+
showFloorSelector={false} // Hide built-in selector
|
|
317
|
+
floorId={currentFloor || undefined}
|
|
287
318
|
onFloorChange={setCurrentFloor}
|
|
288
319
|
onSeatSelect={(seat) => handleSelection(seat)}
|
|
289
320
|
/>
|
|
@@ -364,7 +395,11 @@ The viewer accepts a `SeatMapConfig` object. You can create these configurations
|
|
|
364
395
|
}
|
|
365
396
|
],
|
|
366
397
|
"sections": [],
|
|
367
|
-
"stages": []
|
|
398
|
+
"stages": [],
|
|
399
|
+
"floors": [
|
|
400
|
+
{ "id": "floor_1", "name": "Ground Floor", "order": 0 },
|
|
401
|
+
{ "id": "floor_2", "name": "First Floor", "order": 1 }
|
|
402
|
+
]
|
|
368
403
|
}
|
|
369
404
|
```
|
|
370
405
|
|
|
@@ -416,6 +451,17 @@ interface ColorSettings {
|
|
|
416
451
|
}
|
|
417
452
|
```
|
|
418
453
|
|
|
454
|
+
### FloorConfig
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
interface FloorConfig {
|
|
458
|
+
id: string; // Unique identifier (e.g., "floor_1")
|
|
459
|
+
name: string; // Display name (e.g., "Ground Floor")
|
|
460
|
+
order: number; // Sort order (0 = first)
|
|
461
|
+
color?: string; // Optional floor color
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
419
465
|
## Seat States Explained
|
|
420
466
|
|
|
421
467
|
| State | Description | User Can Select? | Visual |
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),t=require("react"),v=require("react-konva");function K(i){const[h,d]=t.useState(null),[S,y]=t.useState(!1),[w,x]=t.useState(null),g=async()=>{if(i){y(!0),x(null);try{const f=await fetch(i);if(!f.ok)throw new Error(`Failed to fetch config: ${f.statusText}`);const u=await f.json();d(u)}catch(f){const u=f instanceof Error?f:new Error("Unknown error occurred");x(u),console.error("Failed to fetch seat map config:",u)}finally{y(!1)}}};return t.useEffect(()=>{g()},[i]),{config:h,loading:S,error:w,refetch:g}}const G={canvasBackground:"#1a1a1a",stageColor:"#808080",seatAvailable:"#2C2B30",seatReserved:"#FCEA00",seatSelected:"#3A7DE5",seatUnavailable:"#6b7280",seatHidden:"#4a4a4a",gridLines:"#404040",currency:"KD"},J=t.memo(({seat:i,state:h,colors:d,onClick:S})=>{const x={available:d.seatAvailable,reserved:d.seatReserved,selected:d.seatSelected,unavailable:d.seatUnavailable,hidden:d.seatHidden}[h],g=h==="available"||h==="selected",f=t.useCallback(()=>{g&&S(i)},[i,S,g]),u={x:i.position.x,y:i.position.y,fill:x,stroke:"#ffffff",strokeWidth:1,onClick:f,onTap:f};return i.shape==="circle"?o.jsx(v.Circle,{...u,radius:12}):o.jsx(v.Rect,{...u,width:24,height:24,offsetX:12,offsetY:12,cornerRadius:i.shape==="square"?0:4})});J.displayName="ViewerSeat";const Q=t.memo(({stage:i,stageColor:h})=>o.jsxs(v.Group,{x:i.position.x,y:i.position.y,children:[o.jsx(v.Rect,{width:i.config.width,height:i.config.height,fill:h+"80",stroke:"#ffffff",strokeWidth:2,cornerRadius:10}),o.jsx(v.Text,{text:i.config.label,x:0,y:0,width:i.config.width,height:i.config.height,fontSize:24,fontStyle:"bold",fill:"#ffffff",align:"center",verticalAlign:"middle"})]}));Q.displayName="ViewerStage";const Z=t.memo(({floors:i,currentFloorId:h,onFloorChange:d,showAllOption:S,allLabel:y,position:w,className:x})=>{const g=t.useMemo(()=>[...i].sort((p,I)=>p.order-I.order),[i]),u={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}}[w]},Y={padding:"6px 14px",fontSize:"14px",fontWeight:500,border:"1px solid #444",borderRadius:"6px",backgroundColor:"transparent",color:"#fff",cursor:"pointer",transition:"all 0.2s ease"},E={...Y,backgroundColor:"#3A7DE5",borderColor:"#3A7DE5"};return o.jsxs("div",{className:x,style:u,children:[S&&o.jsx("button",{type:"button",onClick:()=>d(null),style:h===null?E:Y,children:y}),g.map(p=>o.jsx("button",{type:"button",onClick:()=>d(p.id),style:h===p.id?E:Y,children:p.name},p.id))]})});Z.displayName="FloorSelectorBar";const Se=({config:i,configUrl:h,floorId:d,onFloorChange:S,reservedSeats:y=[],unavailableSeats:w=[],onSeatSelect:x,onSeatDeselect:g,onSelectionChange:f,colorOverrides:u,showTooltip:Y=!0,zoomEnabled:E=!0,className:p="",onConfigLoad:I,onError:T,showFloorSelector:O,floorSelectorPosition:ee="top-left",floorSelectorClassName:te,showAllFloorsOption:ne=!0,allFloorsLabel:se="All",fitToView:z=!0,fitPadding:W=40})=>{const P=t.useRef(null),[j,oe]=t.useState(new Set),[X,V]=t.useState(1),[F,_]=t.useState({x:0,y:0}),[ie,re]=t.useState(null),[q,U]=t.useState(!1),{config:ae,loading:le,error:N}=K(h),s=i||ae,$=d!==void 0,m=$?d||null:ie,ce=t.useCallback(e=>{$||re(e),S?.(e)},[$,S]),B=s?.floors||[],de=O!==void 0?O:B.length>1,D=t.useMemo(()=>s?{...s.colors,...u}:{...G,...u},[s,u]),k=t.useMemo(()=>{if(!s)return[];let e=s.seats.filter(n=>n.state!=="hidden");return m&&(e=e.filter(n=>n.floorId===m||!n.floorId&&m==="floor_default")),e},[s,m]),L=t.useMemo(()=>s?.stages?m?s.stages.filter(e=>e.floorId===m||!e.floorId&&m==="floor_default"):s.stages:[],[s,m]),b=t.useMemo(()=>{if(!s||k.length===0&&L.length===0)return null;const e=12;let n=1/0,r=1/0,a=-1/0,l=-1/0;return k.forEach(c=>{n=Math.min(n,c.position.x-e),r=Math.min(r,c.position.y-e),a=Math.max(a,c.position.x+e),l=Math.max(l,c.position.y+e)}),L.forEach(c=>{n=Math.min(n,c.position.x),r=Math.min(r,c.position.y),a=Math.max(a,c.position.x+(c.config?.width||200)),l=Math.max(l,c.position.y+(c.config?.height||100))}),{minX:n,minY:r,maxX:a,maxY:l,width:a-n,height:l-r}},[s,k,L]);t.useEffect(()=>{if(!z||q||!s||!b)return;const e=s.canvas.width,n=s.canvas.height,r=e-W*2,a=n-W*2,l=r/b.width,c=a/b.height,M=Math.min(l,c,2),C=b.minX+b.width/2,he=b.minY+b.height/2,pe=e/2,xe=n/2,ge=pe-C*M,me=xe-he*M;V(M),_({x:ge,y:me}),U(!0)},[z,q,s,b,W]),t.useEffect(()=>{z&&U(!1)},[m,z]);const R=t.useMemo(()=>{const e=new Set(y),n=new Set(w);return{reserved:e,unavailable:n}},[y,w]),H=t.useCallback(e=>{const n=e.id,r=e.seatNumber||"";return R.unavailable.has(n)||R.unavailable.has(r)?"unavailable":R.reserved.has(n)||R.reserved.has(r)?"reserved":j.has(n)?"selected":e.state},[R,j]);t.useEffect(()=>{s&&I&&I(s)},[s,I]),t.useEffect(()=>{N&&T&&T(N)},[N,T]);const fe=t.useCallback(e=>{const n=H(e);if(n!=="available"&&n!=="selected")return;const r=j.has(e.id);oe(a=>{const l=new Set(a);return r?l.delete(e.id):l.add(e.id),l}),r?g?.(e):(x?.(e),x||console.log("Seat selected:",e))},[H,j,x,g]),A=t.useMemo(()=>s?k.filter(e=>j.has(e.id)):[],[k,j]);t.useEffect(()=>{f?.(A)},[A,f]);const ue=t.useCallback(e=>{if(!E)return;e.evt.preventDefault();const n=P.current;if(!n)return;const r=X,a=n.getPointerPosition();if(!a)return;const l={x:(a.x-F.x)/r,y:(a.y-F.y)/r},c=e.evt.deltaY>0?-1:1,M=1.05;let C=c>0?r*M:r/M;C=Math.max(.5,Math.min(5,C)),V(C),_({x:a.x-l.x*C,y:a.y-l.y*C})},[E,X,F]);return le?o.jsx("div",{className:`flex items-center justify-center h-full ${p}`,children:o.jsx("p",{children:"Loading seat map..."})}):N?o.jsx("div",{className:`flex items-center justify-center h-full ${p}`,children:o.jsxs("p",{className:"text-red-500",children:["Error loading seat map: ",N.message]})}):s?o.jsxs("div",{className:`relative ${p}`,children:[de&&B.length>0&&o.jsx(Z,{floors:B,currentFloorId:m,onFloorChange:ce,showAllOption:ne,allLabel:se,position:ee,className:te}),o.jsxs(v.Stage,{ref:P,width:s.canvas.width,height:s.canvas.height,scaleX:X,scaleY:X,x:F.x,y:F.y,onWheel:ue,style:{backgroundColor:s.canvas.backgroundColor},children:[o.jsx(v.Layer,{listening:!1,children:L.map(e=>o.jsx(Q,{stage:e,stageColor:D.stageColor},e.id))}),o.jsx(v.Layer,{children:k.map(e=>o.jsx(J,{seat:e,state:H(e),colors:D,onClick:fe},e.id))})]}),A.length>0&&o.jsxs("div",{className:"absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg",children:[o.jsxs("h3",{className:"font-semibold mb-2",children:["Selected Seats (",A.length,")"]}),o.jsx("div",{className:"max-h-48 overflow-y-auto space-y-1",children:A.map(e=>o.jsxs("div",{className:"text-sm",children:[e.seatNumber,e.price&&` - ${D.currency} ${e.price.toFixed(2)}`]},e.id))})]})]}):o.jsx("div",{className:`flex items-center justify-center h-full ${p}`,children:o.jsx("p",{children:"No configuration provided"})})};exports.DEFAULT_COLORS=G;exports.SeatMapViewer=Se;exports.useConfigFetcher=K;
|
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import { jsx as r, jsxs as
|
|
2
|
-
import { useState as
|
|
3
|
-
import { Stage as
|
|
4
|
-
function
|
|
5
|
-
const [
|
|
6
|
-
if (
|
|
7
|
-
|
|
1
|
+
import { jsx as r, jsxs as v } from "react/jsx-runtime";
|
|
2
|
+
import { useState as S, useEffect as F, useRef as we, useCallback as W, useMemo as k, memo as O } from "react";
|
|
3
|
+
import { Stage as Ce, Layer as Z, Group as ke, Rect as ee, Text as Ie, Circle as Me } from "react-konva";
|
|
4
|
+
function Ne(i) {
|
|
5
|
+
const [h, c] = S(null), [y, x] = S(!1), [w, p] = S(null), g = async () => {
|
|
6
|
+
if (i) {
|
|
7
|
+
x(!0), p(null);
|
|
8
8
|
try {
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
11
|
-
throw new Error(`Failed to fetch config: ${
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
} catch (
|
|
15
|
-
const
|
|
16
|
-
|
|
9
|
+
const d = await fetch(i);
|
|
10
|
+
if (!d.ok)
|
|
11
|
+
throw new Error(`Failed to fetch config: ${d.statusText}`);
|
|
12
|
+
const f = await d.json();
|
|
13
|
+
c(f);
|
|
14
|
+
} catch (d) {
|
|
15
|
+
const f = d instanceof Error ? d : new Error("Unknown error occurred");
|
|
16
|
+
p(f), console.error("Failed to fetch seat map config:", f);
|
|
17
17
|
} finally {
|
|
18
|
-
|
|
18
|
+
x(!1);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
}, [
|
|
25
|
-
config:
|
|
26
|
-
loading:
|
|
27
|
-
error:
|
|
28
|
-
refetch:
|
|
22
|
+
return F(() => {
|
|
23
|
+
g();
|
|
24
|
+
}, [i]), {
|
|
25
|
+
config: h,
|
|
26
|
+
loading: y,
|
|
27
|
+
error: w,
|
|
28
|
+
refetch: g
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
const
|
|
31
|
+
const Fe = {
|
|
32
32
|
canvasBackground: "#1a1a1a",
|
|
33
33
|
stageColor: "#808080",
|
|
34
34
|
seatAvailable: "#2C2B30",
|
|
@@ -38,64 +38,64 @@ const Se = {
|
|
|
38
38
|
seatHidden: "#4a4a4a",
|
|
39
39
|
gridLines: "#404040",
|
|
40
40
|
currency: "KD"
|
|
41
|
-
},
|
|
42
|
-
const
|
|
43
|
-
available:
|
|
44
|
-
reserved:
|
|
45
|
-
selected:
|
|
46
|
-
unavailable:
|
|
47
|
-
hidden:
|
|
41
|
+
}, te = O(({ seat: i, state: h, colors: c, onClick: y }) => {
|
|
42
|
+
const p = {
|
|
43
|
+
available: c.seatAvailable,
|
|
44
|
+
reserved: c.seatReserved,
|
|
45
|
+
selected: c.seatSelected,
|
|
46
|
+
unavailable: c.seatUnavailable,
|
|
47
|
+
hidden: c.seatHidden
|
|
48
48
|
// Hidden seats are filtered out, but included for type safety
|
|
49
|
-
}[
|
|
50
|
-
|
|
51
|
-
}, [
|
|
52
|
-
x:
|
|
53
|
-
y:
|
|
54
|
-
fill:
|
|
49
|
+
}[h], g = h === "available" || h === "selected", d = W(() => {
|
|
50
|
+
g && y(i);
|
|
51
|
+
}, [i, y, g]), f = {
|
|
52
|
+
x: i.position.x,
|
|
53
|
+
y: i.position.y,
|
|
54
|
+
fill: p,
|
|
55
55
|
stroke: "#ffffff",
|
|
56
56
|
strokeWidth: 1,
|
|
57
|
-
onClick:
|
|
58
|
-
onTap:
|
|
57
|
+
onClick: d,
|
|
58
|
+
onTap: d
|
|
59
59
|
};
|
|
60
|
-
return
|
|
61
|
-
|
|
60
|
+
return i.shape === "circle" ? /* @__PURE__ */ r(
|
|
61
|
+
Me,
|
|
62
62
|
{
|
|
63
|
-
...
|
|
63
|
+
...f,
|
|
64
64
|
radius: 12
|
|
65
65
|
}
|
|
66
66
|
) : /* @__PURE__ */ r(
|
|
67
|
-
|
|
67
|
+
ee,
|
|
68
68
|
{
|
|
69
|
-
...
|
|
69
|
+
...f,
|
|
70
70
|
width: 24,
|
|
71
71
|
height: 24,
|
|
72
72
|
offsetX: 12,
|
|
73
73
|
offsetY: 12,
|
|
74
|
-
cornerRadius:
|
|
74
|
+
cornerRadius: i.shape === "square" ? 0 : 4
|
|
75
75
|
}
|
|
76
76
|
);
|
|
77
77
|
});
|
|
78
|
-
|
|
79
|
-
const
|
|
78
|
+
te.displayName = "ViewerSeat";
|
|
79
|
+
const ne = O(({ stage: i, stageColor: h }) => /* @__PURE__ */ v(ke, { x: i.position.x, y: i.position.y, children: [
|
|
80
80
|
/* @__PURE__ */ r(
|
|
81
|
-
|
|
81
|
+
ee,
|
|
82
82
|
{
|
|
83
|
-
width:
|
|
84
|
-
height:
|
|
85
|
-
fill:
|
|
83
|
+
width: i.config.width,
|
|
84
|
+
height: i.config.height,
|
|
85
|
+
fill: h + "80",
|
|
86
86
|
stroke: "#ffffff",
|
|
87
87
|
strokeWidth: 2,
|
|
88
88
|
cornerRadius: 10
|
|
89
89
|
}
|
|
90
90
|
),
|
|
91
91
|
/* @__PURE__ */ r(
|
|
92
|
-
|
|
92
|
+
Ie,
|
|
93
93
|
{
|
|
94
|
-
text:
|
|
94
|
+
text: i.config.label,
|
|
95
95
|
x: 0,
|
|
96
96
|
y: 0,
|
|
97
|
-
width:
|
|
98
|
-
height:
|
|
97
|
+
width: i.config.width,
|
|
98
|
+
height: i.config.height,
|
|
99
99
|
fontSize: 24,
|
|
100
100
|
fontStyle: "bold",
|
|
101
101
|
fill: "#ffffff",
|
|
@@ -104,20 +104,20 @@ const X = V(({ stage: t, stageColor: a }) => /* @__PURE__ */ m(pe, { x: t.positi
|
|
|
104
104
|
}
|
|
105
105
|
)
|
|
106
106
|
] }));
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
floors:
|
|
110
|
-
currentFloorId:
|
|
111
|
-
onFloorChange:
|
|
112
|
-
showAllOption:
|
|
113
|
-
allLabel:
|
|
114
|
-
position:
|
|
115
|
-
className:
|
|
107
|
+
ne.displayName = "ViewerStage";
|
|
108
|
+
const ie = O(({
|
|
109
|
+
floors: i,
|
|
110
|
+
currentFloorId: h,
|
|
111
|
+
onFloorChange: c,
|
|
112
|
+
showAllOption: y,
|
|
113
|
+
allLabel: x,
|
|
114
|
+
position: w,
|
|
115
|
+
className: p
|
|
116
116
|
}) => {
|
|
117
|
-
const
|
|
118
|
-
() => [...
|
|
119
|
-
[
|
|
120
|
-
),
|
|
117
|
+
const g = k(
|
|
118
|
+
() => [...i].sort((u, E) => u.order - E.order),
|
|
119
|
+
[i]
|
|
120
|
+
), f = {
|
|
121
121
|
position: "absolute",
|
|
122
122
|
display: "flex",
|
|
123
123
|
alignItems: "center",
|
|
@@ -132,8 +132,8 @@ const q = V(({
|
|
|
132
132
|
"top-right": { top: 0, right: 0 },
|
|
133
133
|
"bottom-left": { bottom: 0, left: 0 },
|
|
134
134
|
"bottom-right": { bottom: 0, right: 0 }
|
|
135
|
-
}[
|
|
136
|
-
},
|
|
135
|
+
}[w]
|
|
136
|
+
}, $ = {
|
|
137
137
|
padding: "6px 14px",
|
|
138
138
|
fontSize: "14px",
|
|
139
139
|
fontWeight: 500,
|
|
@@ -143,177 +143,197 @@ const q = V(({
|
|
|
143
143
|
color: "#fff",
|
|
144
144
|
cursor: "pointer",
|
|
145
145
|
transition: "all 0.2s ease"
|
|
146
|
-
},
|
|
147
|
-
|
|
146
|
+
}, A = {
|
|
147
|
+
...$,
|
|
148
148
|
backgroundColor: "#3A7DE5",
|
|
149
149
|
borderColor: "#3A7DE5"
|
|
150
150
|
};
|
|
151
|
-
return /* @__PURE__ */
|
|
152
|
-
|
|
151
|
+
return /* @__PURE__ */ v("div", { className: p, style: f, children: [
|
|
152
|
+
y && /* @__PURE__ */ r(
|
|
153
153
|
"button",
|
|
154
154
|
{
|
|
155
155
|
type: "button",
|
|
156
|
-
onClick: () =>
|
|
157
|
-
style:
|
|
158
|
-
children:
|
|
156
|
+
onClick: () => c(null),
|
|
157
|
+
style: h === null ? A : $,
|
|
158
|
+
children: x
|
|
159
159
|
}
|
|
160
160
|
),
|
|
161
|
-
|
|
161
|
+
g.map((u) => /* @__PURE__ */ r(
|
|
162
162
|
"button",
|
|
163
163
|
{
|
|
164
164
|
type: "button",
|
|
165
|
-
onClick: () =>
|
|
166
|
-
style:
|
|
167
|
-
children:
|
|
165
|
+
onClick: () => c(u.id),
|
|
166
|
+
style: h === u.id ? A : $,
|
|
167
|
+
children: u.name
|
|
168
168
|
},
|
|
169
|
-
|
|
169
|
+
u.id
|
|
170
170
|
))
|
|
171
171
|
] });
|
|
172
172
|
});
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
config:
|
|
176
|
-
configUrl:
|
|
177
|
-
floorId:
|
|
178
|
-
onFloorChange:
|
|
179
|
-
reservedSeats:
|
|
180
|
-
unavailableSeats:
|
|
181
|
-
onSeatSelect:
|
|
182
|
-
onSeatDeselect:
|
|
183
|
-
onSelectionChange:
|
|
184
|
-
colorOverrides:
|
|
185
|
-
showTooltip:
|
|
186
|
-
zoomEnabled:
|
|
187
|
-
className:
|
|
188
|
-
onConfigLoad:
|
|
189
|
-
onError:
|
|
173
|
+
ie.displayName = "FloorSelectorBar";
|
|
174
|
+
const Ye = ({
|
|
175
|
+
config: i,
|
|
176
|
+
configUrl: h,
|
|
177
|
+
floorId: c,
|
|
178
|
+
onFloorChange: y,
|
|
179
|
+
reservedSeats: x = [],
|
|
180
|
+
unavailableSeats: w = [],
|
|
181
|
+
onSeatSelect: p,
|
|
182
|
+
onSeatDeselect: g,
|
|
183
|
+
onSelectionChange: d,
|
|
184
|
+
colorOverrides: f,
|
|
185
|
+
showTooltip: $ = !0,
|
|
186
|
+
zoomEnabled: A = !0,
|
|
187
|
+
className: u = "",
|
|
188
|
+
onConfigLoad: E,
|
|
189
|
+
onError: D,
|
|
190
190
|
// Floor selector props
|
|
191
|
-
showFloorSelector:
|
|
192
|
-
floorSelectorPosition:
|
|
193
|
-
floorSelectorClassName:
|
|
194
|
-
showAllFloorsOption:
|
|
195
|
-
allFloorsLabel:
|
|
191
|
+
showFloorSelector: U,
|
|
192
|
+
floorSelectorPosition: oe = "top-left",
|
|
193
|
+
floorSelectorClassName: re,
|
|
194
|
+
showAllFloorsOption: se = !0,
|
|
195
|
+
allFloorsLabel: ae = "All",
|
|
196
|
+
fitToView: j = !0,
|
|
197
|
+
fitPadding: H = 40
|
|
196
198
|
}) => {
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
}, [
|
|
200
|
-
() =>
|
|
201
|
-
[
|
|
202
|
-
),
|
|
203
|
-
if (!
|
|
204
|
-
let e =
|
|
205
|
-
return
|
|
206
|
-
(
|
|
199
|
+
const q = we(null), [I, le] = S(/* @__PURE__ */ new Set()), [B, G] = S(1), [R, K] = S({ x: 0, y: 0 }), [ce, de] = S(null), [J, Q] = S(!1), { config: fe, loading: he, error: Y } = Ne(h), n = i || fe, L = c !== void 0, m = L ? c || null : ce, ue = W((e) => {
|
|
200
|
+
L || de(e), y?.(e);
|
|
201
|
+
}, [L, y]), P = n?.floors || [], pe = U !== void 0 ? U : P.length > 1, V = k(
|
|
202
|
+
() => n ? { ...n.colors, ...f } : { ...Fe, ...f },
|
|
203
|
+
[n, f]
|
|
204
|
+
), M = k(() => {
|
|
205
|
+
if (!n) return [];
|
|
206
|
+
let e = n.seats.filter((t) => t.state !== "hidden");
|
|
207
|
+
return m && (e = e.filter(
|
|
208
|
+
(t) => t.floorId === m || !t.floorId && m === "floor_default"
|
|
207
209
|
)), e;
|
|
208
|
-
}, [
|
|
209
|
-
(e) => e.floorId ===
|
|
210
|
-
) :
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const n =
|
|
224
|
-
|
|
210
|
+
}, [n, m]), T = k(() => n?.stages ? m ? n.stages.filter(
|
|
211
|
+
(e) => e.floorId === m || !e.floorId && m === "floor_default"
|
|
212
|
+
) : n.stages : [], [n, m]), b = k(() => {
|
|
213
|
+
if (!n || M.length === 0 && T.length === 0)
|
|
214
|
+
return null;
|
|
215
|
+
const e = 12;
|
|
216
|
+
let t = 1 / 0, o = 1 / 0, s = -1 / 0, a = -1 / 0;
|
|
217
|
+
return M.forEach((l) => {
|
|
218
|
+
t = Math.min(t, l.position.x - e), o = Math.min(o, l.position.y - e), s = Math.max(s, l.position.x + e), a = Math.max(a, l.position.y + e);
|
|
219
|
+
}), T.forEach((l) => {
|
|
220
|
+
t = Math.min(t, l.position.x), o = Math.min(o, l.position.y), s = Math.max(s, l.position.x + (l.config?.width || 200)), a = Math.max(a, l.position.y + (l.config?.height || 100));
|
|
221
|
+
}), { minX: t, minY: o, maxX: s, maxY: a, width: s - t, height: a - o };
|
|
222
|
+
}, [n, M, T]);
|
|
223
|
+
F(() => {
|
|
224
|
+
if (!j || J || !n || !b) return;
|
|
225
|
+
const e = n.canvas.width, t = n.canvas.height, o = e - H * 2, s = t - H * 2, a = o / b.width, l = s / b.height, N = Math.min(a, l, 2), C = b.minX + b.width / 2, ye = b.minY + b.height / 2, xe = e / 2, be = t / 2, ve = xe - C * N, Se = be - ye * N;
|
|
226
|
+
G(N), K({ x: ve, y: Se }), Q(!0);
|
|
227
|
+
}, [j, J, n, b, H]), F(() => {
|
|
228
|
+
j && Q(!1);
|
|
229
|
+
}, [m, j]);
|
|
230
|
+
const z = k(() => {
|
|
231
|
+
const e = new Set(x), t = new Set(w);
|
|
232
|
+
return { reserved: e, unavailable: t };
|
|
233
|
+
}, [x, w]), _ = W((e) => {
|
|
234
|
+
const t = e.id, o = e.seatNumber || "";
|
|
235
|
+
return z.unavailable.has(t) || z.unavailable.has(o) ? "unavailable" : z.reserved.has(t) || z.reserved.has(o) ? "reserved" : I.has(t) ? "selected" : e.state;
|
|
236
|
+
}, [z, I]);
|
|
237
|
+
F(() => {
|
|
238
|
+
n && E && E(n);
|
|
239
|
+
}, [n, E]), F(() => {
|
|
240
|
+
Y && D && D(Y);
|
|
241
|
+
}, [Y, D]);
|
|
242
|
+
const ge = W((e) => {
|
|
243
|
+
const t = _(e);
|
|
244
|
+
if (t !== "available" && t !== "selected")
|
|
225
245
|
return;
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
return
|
|
230
|
-
}),
|
|
231
|
-
}, [
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}, [
|
|
235
|
-
const
|
|
236
|
-
if (!
|
|
246
|
+
const o = I.has(e.id);
|
|
247
|
+
le((s) => {
|
|
248
|
+
const a = new Set(s);
|
|
249
|
+
return o ? a.delete(e.id) : a.add(e.id), a;
|
|
250
|
+
}), o ? g?.(e) : (p?.(e), p || console.log("Seat selected:", e));
|
|
251
|
+
}, [_, I, p, g]), X = k(() => n ? M.filter((e) => I.has(e.id)) : [], [M, I]);
|
|
252
|
+
F(() => {
|
|
253
|
+
d?.(X);
|
|
254
|
+
}, [X, d]);
|
|
255
|
+
const me = W((e) => {
|
|
256
|
+
if (!A) return;
|
|
237
257
|
e.evt.preventDefault();
|
|
238
|
-
const
|
|
239
|
-
if (!
|
|
240
|
-
const
|
|
241
|
-
if (!
|
|
242
|
-
const
|
|
243
|
-
x: (
|
|
244
|
-
y: (
|
|
245
|
-
},
|
|
246
|
-
let
|
|
247
|
-
|
|
248
|
-
x:
|
|
249
|
-
y:
|
|
258
|
+
const t = q.current;
|
|
259
|
+
if (!t) return;
|
|
260
|
+
const o = B, s = t.getPointerPosition();
|
|
261
|
+
if (!s) return;
|
|
262
|
+
const a = {
|
|
263
|
+
x: (s.x - R.x) / o,
|
|
264
|
+
y: (s.y - R.y) / o
|
|
265
|
+
}, l = e.evt.deltaY > 0 ? -1 : 1, N = 1.05;
|
|
266
|
+
let C = l > 0 ? o * N : o / N;
|
|
267
|
+
C = Math.max(0.5, Math.min(5, C)), G(C), K({
|
|
268
|
+
x: s.x - a.x * C,
|
|
269
|
+
y: s.y - a.y * C
|
|
250
270
|
});
|
|
251
|
-
}, [
|
|
252
|
-
return
|
|
271
|
+
}, [A, B, R]);
|
|
272
|
+
return he ? /* @__PURE__ */ r("div", { className: `flex items-center justify-center h-full ${u}`, children: /* @__PURE__ */ r("p", { children: "Loading seat map..." }) }) : Y ? /* @__PURE__ */ r("div", { className: `flex items-center justify-center h-full ${u}`, children: /* @__PURE__ */ v("p", { className: "text-red-500", children: [
|
|
253
273
|
"Error loading seat map: ",
|
|
254
|
-
|
|
255
|
-
] }) }) :
|
|
256
|
-
|
|
257
|
-
|
|
274
|
+
Y.message
|
|
275
|
+
] }) }) : n ? /* @__PURE__ */ v("div", { className: `relative ${u}`, children: [
|
|
276
|
+
pe && P.length > 0 && /* @__PURE__ */ r(
|
|
277
|
+
ie,
|
|
258
278
|
{
|
|
259
279
|
floors: P,
|
|
260
|
-
currentFloorId:
|
|
261
|
-
onFloorChange:
|
|
262
|
-
showAllOption:
|
|
263
|
-
allLabel:
|
|
264
|
-
position:
|
|
265
|
-
className:
|
|
280
|
+
currentFloorId: m,
|
|
281
|
+
onFloorChange: ue,
|
|
282
|
+
showAllOption: se,
|
|
283
|
+
allLabel: ae,
|
|
284
|
+
position: oe,
|
|
285
|
+
className: re
|
|
266
286
|
}
|
|
267
287
|
),
|
|
268
|
-
/* @__PURE__ */
|
|
269
|
-
|
|
288
|
+
/* @__PURE__ */ v(
|
|
289
|
+
Ce,
|
|
270
290
|
{
|
|
271
|
-
ref:
|
|
272
|
-
width:
|
|
273
|
-
height:
|
|
274
|
-
scaleX:
|
|
275
|
-
scaleY:
|
|
276
|
-
x:
|
|
277
|
-
y:
|
|
278
|
-
onWheel:
|
|
279
|
-
style: { backgroundColor:
|
|
291
|
+
ref: q,
|
|
292
|
+
width: n.canvas.width,
|
|
293
|
+
height: n.canvas.height,
|
|
294
|
+
scaleX: B,
|
|
295
|
+
scaleY: B,
|
|
296
|
+
x: R.x,
|
|
297
|
+
y: R.y,
|
|
298
|
+
onWheel: me,
|
|
299
|
+
style: { backgroundColor: n.canvas.backgroundColor },
|
|
280
300
|
children: [
|
|
281
|
-
/* @__PURE__ */ r(
|
|
282
|
-
|
|
301
|
+
/* @__PURE__ */ r(Z, { listening: !1, children: T.map((e) => /* @__PURE__ */ r(
|
|
302
|
+
ne,
|
|
283
303
|
{
|
|
284
304
|
stage: e,
|
|
285
|
-
stageColor:
|
|
305
|
+
stageColor: V.stageColor
|
|
286
306
|
},
|
|
287
307
|
e.id
|
|
288
308
|
)) }),
|
|
289
|
-
/* @__PURE__ */ r(
|
|
290
|
-
|
|
309
|
+
/* @__PURE__ */ r(Z, { children: M.map((e) => /* @__PURE__ */ r(
|
|
310
|
+
te,
|
|
291
311
|
{
|
|
292
312
|
seat: e,
|
|
293
|
-
state:
|
|
294
|
-
colors:
|
|
295
|
-
onClick:
|
|
313
|
+
state: _(e),
|
|
314
|
+
colors: V,
|
|
315
|
+
onClick: ge
|
|
296
316
|
},
|
|
297
317
|
e.id
|
|
298
318
|
)) })
|
|
299
319
|
]
|
|
300
320
|
}
|
|
301
321
|
),
|
|
302
|
-
|
|
303
|
-
/* @__PURE__ */
|
|
322
|
+
X.length > 0 && /* @__PURE__ */ v("div", { className: "absolute top-4 right-4 bg-white dark:bg-gray-800 p-4 rounded shadow-lg", children: [
|
|
323
|
+
/* @__PURE__ */ v("h3", { className: "font-semibold mb-2", children: [
|
|
304
324
|
"Selected Seats (",
|
|
305
|
-
|
|
325
|
+
X.length,
|
|
306
326
|
")"
|
|
307
327
|
] }),
|
|
308
|
-
/* @__PURE__ */ r("div", { className: "max-h-48 overflow-y-auto space-y-1", children:
|
|
328
|
+
/* @__PURE__ */ r("div", { className: "max-h-48 overflow-y-auto space-y-1", children: X.map((e) => /* @__PURE__ */ v("div", { className: "text-sm", children: [
|
|
309
329
|
e.seatNumber,
|
|
310
|
-
e.price && ` - ${
|
|
330
|
+
e.price && ` - ${V.currency} ${e.price.toFixed(2)}`
|
|
311
331
|
] }, e.id)) })
|
|
312
332
|
] })
|
|
313
|
-
] }) : /* @__PURE__ */ r("div", { className: `flex items-center justify-center h-full ${
|
|
333
|
+
] }) : /* @__PURE__ */ r("div", { className: `flex items-center justify-center h-full ${u}`, children: /* @__PURE__ */ r("p", { children: "No configuration provided" }) });
|
|
314
334
|
};
|
|
315
335
|
export {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
336
|
+
Fe as DEFAULT_COLORS,
|
|
337
|
+
Ye as SeatMapViewer,
|
|
338
|
+
Ne as useConfigFetcher
|
|
319
339
|
};
|