seat-editor 3.3.13 → 3.3.14
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/app/constant.d.ts +1 -0
- package/dist/app/constant.js +1 -0
- package/dist/app/layout.d.ts +6 -0
- package/dist/app/layout.jsx +27 -0
- package/dist/app/new-board/page.jsx +55 -0
- package/dist/app/old-board/page.d.ts +3 -0
- package/dist/app/old-board/page.jsx +510 -0
- package/dist/app/only-view/chair.d.ts +1 -0
- package/dist/app/only-view/chair.js +12 -0
- package/dist/app/only-view/constant.d.ts +60 -0
- package/dist/app/only-view/constant.js +1336 -0
- package/dist/app/only-view/page.jsx +248 -0
- package/dist/app/only-view/user.d.ts +1 -0
- package/dist/app/only-view/user.js +12 -0
- package/dist/app/page.d.ts +2 -0
- package/dist/app/page.jsx +13 -0
- package/dist/app/test/page.d.ts +2 -0
- package/dist/app/test/page.jsx +45 -0
- package/dist/app/v2/page.d.ts +2 -0
- package/dist/app/v2/page.jsx +13 -0
- package/dist/components/button-tools/index.d.ts +11 -0
- package/dist/components/button-tools/index.jsx +17 -0
- package/dist/components/form-tools/label.d.ts +2 -0
- package/dist/components/form-tools/label.jsx +63 -0
- package/dist/components/form-tools/shape.d.ts +8 -0
- package/dist/components/form-tools/shape.jsx +113 -0
- package/dist/components/input/number-indicator.d.ts +7 -0
- package/dist/components/input/number-indicator.jsx +36 -0
- package/dist/components/joystick/index.d.ts +12 -0
- package/dist/components/joystick/index.jsx +49 -0
- package/dist/components/layer/index.d.ts +19 -0
- package/dist/components/layer/index.jsx +383 -0
- package/dist/components/layer-v2/index.d.ts +19 -0
- package/dist/components/layer-v2/index.jsx +370 -0
- package/dist/components/layer-v3/index.d.ts +13 -0
- package/dist/components/layer-v3/index.jsx +631 -0
- package/dist/components/layer-v3/utils.d.ts +19 -0
- package/dist/components/layer-v3/utils.js +72 -0
- package/dist/components/layer-v4/constant.d.ts +60 -0
- package/dist/components/layer-v4/constant.js +93 -0
- package/dist/components/layer-v4/index.d.ts +24 -0
- package/dist/components/layer-v4/index.jsx +1046 -0
- package/dist/components/lib/index.d.ts +8 -0
- package/dist/components/lib/index.jsx +33 -0
- package/dist/components/modal-preview/index.d.ts +4 -0
- package/dist/components/modal-preview/index.jsx +11 -0
- package/dist/dto/event-handler.d.ts +1 -0
- package/dist/dto/event-handler.js +1 -0
- package/dist/dto/table.d.ts +79 -0
- package/dist/dto/table.js +1 -0
- package/dist/features/board/board-slice.d.ts +14 -0
- package/dist/features/board/board-slice.js +52 -0
- package/dist/features/board/index.d.ts +6 -0
- package/dist/features/board/index.jsx +725 -0
- package/dist/features/board-v2/board-slice.d.ts +14 -0
- package/dist/features/board-v2/board-slice.js +52 -0
- package/dist/features/board-v2/index.d.ts +8 -0
- package/dist/features/board-v2/index.jsx +869 -0
- package/dist/features/board-v3/board-slice.d.ts +19 -0
- package/dist/features/board-v3/board-slice.js +274 -0
- package/dist/features/board-v3/constant.d.ts +5 -0
- package/dist/features/board-v3/constant.js +5 -0
- package/dist/features/board-v3/history-slice.d.ts +27 -0
- package/dist/features/board-v3/history-slice.js +27 -0
- package/dist/features/board-v3/icons.d.ts +4 -0
- package/dist/features/board-v3/icons.jsx +100 -0
- package/dist/features/board-v3/index.d.ts +16 -0
- package/dist/features/board-v3/index.jsx +1678 -0
- package/dist/features/board-v3/polygon.d.ts +28 -0
- package/dist/features/board-v3/polygon.js +109 -0
- package/dist/features/board-v3/rect.d.ts +9 -0
- package/dist/features/board-v3/rect.js +152 -0
- package/dist/features/board-v3/resize-element.d.ts +12 -0
- package/dist/features/board-v3/resize-element.js +43 -0
- package/dist/features/board-v3/utils.d.ts +180 -0
- package/dist/features/board-v3/utils.js +1235 -0
- package/dist/features/navbar/index.d.ts +2 -0
- package/dist/features/navbar/index.jsx +5 -0
- package/dist/features/panel/index.d.ts +6 -0
- package/dist/features/panel/index.jsx +251 -0
- package/dist/features/panel/panel-slice.d.ts +23 -0
- package/dist/features/panel/panel-slice.js +46 -0
- package/dist/features/panel/select-tool.d.ts +6 -0
- package/dist/features/panel/select-tool.jsx +70 -0
- package/dist/features/panel/selected-group.d.ts +2 -0
- package/dist/features/panel/selected-group.jsx +93 -0
- package/dist/features/panel/square-circle-tool.d.ts +2 -0
- package/dist/features/panel/square-circle-tool.jsx +10 -0
- package/dist/features/panel/table-seat-circle.d.ts +2 -0
- package/dist/features/panel/table-seat-circle.jsx +36 -0
- package/dist/features/panel/table-seat-square.d.ts +2 -0
- package/dist/features/panel/table-seat-square.jsx +51 -0
- package/dist/features/panel/text-tool.d.ts +2 -0
- package/dist/features/panel/text-tool.jsx +57 -0
- package/dist/features/panel/upload-tool.d.ts +10 -0
- package/dist/features/panel/upload-tool.jsx +176 -0
- package/dist/features/panel/utils.d.ts +5 -0
- package/dist/features/panel/utils.js +47 -0
- package/dist/features/side-tool/index.d.ts +8 -0
- package/dist/features/side-tool/index.jsx +390 -0
- package/dist/features/side-tool/side-tool-slice.d.ts +16 -0
- package/dist/features/side-tool/side-tool-slice.js +28 -0
- package/dist/features/theme/theme-slice.d.ts +12 -0
- package/dist/features/theme/theme-slice.js +15 -0
- package/dist/features/view-only/index.d.ts +19 -0
- package/dist/features/view-only/index.jsx +205 -0
- package/dist/features/view-only-2/index.d.ts +19 -0
- package/dist/features/view-only-2/index.jsx +190 -0
- package/dist/features/view-only-3/index.d.ts +89 -0
- package/dist/features/view-only-3/index.jsx +590 -0
- package/dist/features/view-only-3/utils.d.ts +1 -0
- package/dist/features/view-only-3/utils.js +3 -0
- package/dist/hooks/use-redux.d.ts +4 -0
- package/dist/hooks/use-redux.js +3 -0
- package/dist/index.js +10 -0
- package/dist/libs/middleware.d.ts +2 -0
- package/dist/libs/middleware.js +5 -0
- package/dist/libs/rootReducer.d.ts +12 -0
- package/dist/libs/rootReducer.js +14 -0
- package/dist/libs/store.d.ts +18 -0
- package/dist/libs/store.js +19 -0
- package/dist/provider/antd-provider.d.ts +4 -0
- package/dist/provider/antd-provider.jsx +46 -0
- package/dist/provider/redux-provider.d.ts +3 -0
- package/dist/provider/redux-provider.jsx +6 -0
- package/dist/provider/store-provider.d.ts +4 -0
- package/dist/provider/store-provider.jsx +10 -0
- package/dist/utils/constant.d.ts +3 -0
- package/dist/utils/constant.js +13 -0
- package/dist/utils/format.d.ts +2 -0
- package/dist/utils/format.js +29 -0
- package/dist/utils/injectCss.d.ts +1 -0
- package/dist/utils/injectCss.js +13 -0
- package/dist/utils/regex.d.ts +3 -0
- package/dist/utils/regex.js +3 -0
- package/package.json +1 -1
package/dist/app/constant.d.ts
CHANGED
package/dist/app/constant.js
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import localFont from "next/font/local";
|
|
2
|
+
import "./globals.css";
|
|
3
|
+
import { Layout } from "antd";
|
|
4
|
+
import { StoreProvider } from "../provider/store-provider";
|
|
5
|
+
const geistSans = localFont({
|
|
6
|
+
src: "./fonts/GeistVF.woff",
|
|
7
|
+
variable: "--font-geist-sans",
|
|
8
|
+
weight: "100 900",
|
|
9
|
+
});
|
|
10
|
+
const geistMono = localFont({
|
|
11
|
+
src: "./fonts/GeistMonoVF.woff",
|
|
12
|
+
variable: "--font-geist-mono",
|
|
13
|
+
weight: "100 900",
|
|
14
|
+
});
|
|
15
|
+
export const metadata = {
|
|
16
|
+
title: "Create Next App",
|
|
17
|
+
description: "Generated by create next app",
|
|
18
|
+
};
|
|
19
|
+
export default function RootLayout({ children, }) {
|
|
20
|
+
return (<html lang="en">
|
|
21
|
+
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
|
22
|
+
<StoreProvider>
|
|
23
|
+
<Layout>{children}</Layout>
|
|
24
|
+
</StoreProvider>
|
|
25
|
+
</body>
|
|
26
|
+
</html>);
|
|
27
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import SeatEditor from "../../features/package";
|
|
4
|
+
import { dummyExtra6 } from "../constant";
|
|
5
|
+
export default function NewBoard() {
|
|
6
|
+
const [initialValue, setInitialValue] = useState([]);
|
|
7
|
+
const [extraComponents, setExtraComponents] = useState([]);
|
|
8
|
+
const [backgroundColor, setBackgroundColor] = useState("#000000");
|
|
9
|
+
const [viewOnly, setViewOnly] = useState(false);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setInitialValue([]);
|
|
12
|
+
setExtraComponents(dummyExtra6);
|
|
13
|
+
}, []);
|
|
14
|
+
const handleUploadImage = (file) => {
|
|
15
|
+
const test = new Promise((resolve, reject) => {
|
|
16
|
+
const reader = new FileReader();
|
|
17
|
+
reader.onload = () => resolve(reader.result);
|
|
18
|
+
reader.onerror = reject;
|
|
19
|
+
reader.readAsDataURL(file);
|
|
20
|
+
});
|
|
21
|
+
return test;
|
|
22
|
+
};
|
|
23
|
+
return (<>
|
|
24
|
+
<div className="w-full h-screen flex flex-col relative justify-center">
|
|
25
|
+
<div className="w-full h-[1000px] bg-white border-r border-gray-200">
|
|
26
|
+
|
|
27
|
+
</div>
|
|
28
|
+
{/* <button className="bg-blue-500 text-white px-4 py-2 rounded"
|
|
29
|
+
onClick={() => setViewOnly(!viewOnly)}
|
|
30
|
+
>
|
|
31
|
+
{viewOnly ? "Edit Mode ddd" : "View Mode"}
|
|
32
|
+
</button> */}
|
|
33
|
+
<div className="flex-1 h-full">
|
|
34
|
+
<SeatEditor componentProps={initialValue} viewOnly={viewOnly} dragOnly={true} deleteAutorized={{
|
|
35
|
+
component: true,
|
|
36
|
+
extraComponent: true,
|
|
37
|
+
}} action={handleUploadImage} mappingKey="properties" onCurrentStateChange={(setState) => {
|
|
38
|
+
var _a, _b, _c, _d;
|
|
39
|
+
if (((_a = setState === null || setState === void 0 ? void 0 : setState.components) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
40
|
+
setInitialValue((_b = setState === null || setState === void 0 ? void 0 : setState.components) !== null && _b !== void 0 ? _b : []);
|
|
41
|
+
}
|
|
42
|
+
if (setState === null || setState === void 0 ? void 0 : setState.backgroundColor) {
|
|
43
|
+
setBackgroundColor(setState === null || setState === void 0 ? void 0 : setState.backgroundColor);
|
|
44
|
+
}
|
|
45
|
+
if (((_c = setState === null || setState === void 0 ? void 0 : setState.extraComponents) === null || _c === void 0 ? void 0 : _c.length) > 0) {
|
|
46
|
+
setExtraComponents((_d = setState === null || setState === void 0 ? void 0 : setState.extraComponents) !== null && _d !== void 0 ? _d : []);
|
|
47
|
+
}
|
|
48
|
+
}} extraComponentProps={dummyExtra6} defaultBackground={backgroundColor}
|
|
49
|
+
// dragOnly={true}
|
|
50
|
+
statusKey="status"/>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
</>);
|
|
55
|
+
}
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import { Button, Input, Modal } from "antd"; //tes commit
|
|
4
|
+
// aduhuhhusd
|
|
5
|
+
import { Square, MousePointer2, Move3D, Trash, CopyPlusIcon, ZoomInIcon, ZoomOutIcon, DownloadIcon, UploadIcon, Circle, PenIcon, Pencil, } from "lucide-react";
|
|
6
|
+
import { SketchPicker } from "react-color";
|
|
7
|
+
const SeatEditor = () => {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
const [activeTool, setActiveTool] = useState(null);
|
|
10
|
+
const [rectangles, setRectangles] = useState([]);
|
|
11
|
+
const [selectedRectangle, setSelectedRectangle] = useState(null);
|
|
12
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
13
|
+
const [startPoint, setStartPoint] = useState(null);
|
|
14
|
+
const [shadowRect, setShadowRect] = useState(null);
|
|
15
|
+
const [showModal, setShowModal] = useState(false);
|
|
16
|
+
const [dragOffset, setDragOffset] = useState(null);
|
|
17
|
+
const [zoom, setZoom] = useState(1);
|
|
18
|
+
const [resizeDirection, setResizeDirection] = useState(null);
|
|
19
|
+
const [images, setImages] = useState([]);
|
|
20
|
+
const [penPaths, setPenPaths] = useState([]);
|
|
21
|
+
const [currentPath, setCurrentPath] = useState(null);
|
|
22
|
+
const [isDrawing, setIsDrawing] = useState(false);
|
|
23
|
+
// upload image
|
|
24
|
+
const widthWorkspace = ((_a = document.getElementById("workspace")) === null || _a === void 0 ? void 0 : _a.clientWidth) || 0;
|
|
25
|
+
const heightWorkspace = ((_b = document.getElementById("workspace")) === null || _b === void 0 ? void 0 : _b.clientHeight) || 0;
|
|
26
|
+
const handleImageUploadBackground = (e) => {
|
|
27
|
+
var _a;
|
|
28
|
+
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
29
|
+
if (!file)
|
|
30
|
+
return;
|
|
31
|
+
const reader = new FileReader();
|
|
32
|
+
reader.onload = () => {
|
|
33
|
+
const img = document.createElement("img");
|
|
34
|
+
img.src = reader.result;
|
|
35
|
+
let width = img.width > widthWorkspace ? img.width / 2 : img.width;
|
|
36
|
+
let height = img.height > heightWorkspace ? img.height / 2 : img.height;
|
|
37
|
+
img.onload = () => {
|
|
38
|
+
setRectangles((prev) => [
|
|
39
|
+
...prev,
|
|
40
|
+
{
|
|
41
|
+
id: rectangles.length + 1,
|
|
42
|
+
x: 100,
|
|
43
|
+
y: 100,
|
|
44
|
+
width: width < 1 ? 100 : width,
|
|
45
|
+
height: height < 1 ? 100 : height,
|
|
46
|
+
rotation: 0,
|
|
47
|
+
shape: "image",
|
|
48
|
+
src: img.src,
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
reader.readAsDataURL(file);
|
|
54
|
+
};
|
|
55
|
+
const handleImageUpload = (e) => {
|
|
56
|
+
var _a;
|
|
57
|
+
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
58
|
+
if (!file)
|
|
59
|
+
return;
|
|
60
|
+
const reader = new FileReader();
|
|
61
|
+
reader.onload = () => {
|
|
62
|
+
const img = document.createElement("img");
|
|
63
|
+
img.src = reader.result;
|
|
64
|
+
let width = img.width > widthWorkspace ? img.width / 2 : img.width;
|
|
65
|
+
let height = img.height > heightWorkspace ? img.height / 2 : img.height;
|
|
66
|
+
img.onload = () => {
|
|
67
|
+
setRectangles((prev) => [
|
|
68
|
+
...prev,
|
|
69
|
+
{
|
|
70
|
+
id: rectangles.length + 1,
|
|
71
|
+
x: 100,
|
|
72
|
+
y: 100,
|
|
73
|
+
width: width < 1 ? 100 : width,
|
|
74
|
+
height: height < 1 ? 100 : height,
|
|
75
|
+
rotation: 0,
|
|
76
|
+
shape: "image-table",
|
|
77
|
+
src: img.src,
|
|
78
|
+
pax: "4 Pax",
|
|
79
|
+
highlightColor: "#C1443D",
|
|
80
|
+
status: "SOLD",
|
|
81
|
+
table: `V${rectangles.length + 1}`,
|
|
82
|
+
},
|
|
83
|
+
]);
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
reader.readAsDataURL(file);
|
|
87
|
+
};
|
|
88
|
+
// zoom in out
|
|
89
|
+
const zoomIn = () => setZoom((prev) => prev + 0.1);
|
|
90
|
+
const zoomOut = () => setZoom((prev) => Math.max(0.1, prev - 0.1));
|
|
91
|
+
const handleToolClick = (tool) => {
|
|
92
|
+
setActiveTool(tool);
|
|
93
|
+
setSelectedRectangle(null); // Deselect any rectangle when switching tools
|
|
94
|
+
};
|
|
95
|
+
// === Drawing Rectangle ===
|
|
96
|
+
const handleMouseDown = (e) => {
|
|
97
|
+
if (activeTool === "rectangle" ||
|
|
98
|
+
activeTool === "circle" ||
|
|
99
|
+
activeTool === "vip-seat") {
|
|
100
|
+
const rect = e.target.getBoundingClientRect();
|
|
101
|
+
setStartPoint({ x: e.clientX - rect.left, y: e.clientY - rect.top });
|
|
102
|
+
setIsDragging(true);
|
|
103
|
+
}
|
|
104
|
+
if (activeTool === "pen") {
|
|
105
|
+
const rect = e.target.getBoundingClientRect();
|
|
106
|
+
const newPoint = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
107
|
+
setCurrentPath({
|
|
108
|
+
id: penPaths.length + 1,
|
|
109
|
+
points: [newPoint],
|
|
110
|
+
color: "#fff", // Default white stroke
|
|
111
|
+
strokeWidth: 2, // Default stroke width
|
|
112
|
+
});
|
|
113
|
+
setIsDrawing(true);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
// rotate logic
|
|
117
|
+
const rotateRectangle = (direction) => {
|
|
118
|
+
if (selectedRectangle) {
|
|
119
|
+
const rotationChange = direction === "left" ? -5 : 5; // Rotate 5 degrees
|
|
120
|
+
const newRotation = (selectedRectangle.rotation + rotationChange) % 360;
|
|
121
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id
|
|
122
|
+
? Object.assign(Object.assign({}, rect), { rotation: newRotation }) : rect));
|
|
123
|
+
setSelectedRectangle((prev) => prev ? Object.assign(Object.assign({}, prev), { rotation: newRotation }) : null);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const handleMouseMove = (e) => {
|
|
127
|
+
// Resize logic for node tool
|
|
128
|
+
if (activeTool === "node" &&
|
|
129
|
+
isDragging &&
|
|
130
|
+
resizeDirection &&
|
|
131
|
+
selectedRectangle) {
|
|
132
|
+
const workspaceRect = e.currentTarget.getBoundingClientRect();
|
|
133
|
+
const currentX = e.clientX - workspaceRect.left;
|
|
134
|
+
const currentY = e.clientY - workspaceRect.top;
|
|
135
|
+
let newRect = Object.assign({}, selectedRectangle);
|
|
136
|
+
switch (resizeDirection) {
|
|
137
|
+
case "top-left":
|
|
138
|
+
newRect.width += newRect.x - currentX;
|
|
139
|
+
newRect.height =
|
|
140
|
+
selectedRectangle.shape === "circle"
|
|
141
|
+
? newRect.width
|
|
142
|
+
: newRect.height + (newRect.y - currentY);
|
|
143
|
+
newRect.x = currentX;
|
|
144
|
+
newRect.y =
|
|
145
|
+
selectedRectangle.shape === "circle" ? newRect.y : currentY;
|
|
146
|
+
break;
|
|
147
|
+
case "top-right":
|
|
148
|
+
newRect.width = currentX - newRect.x;
|
|
149
|
+
newRect.height =
|
|
150
|
+
selectedRectangle.shape === "circle"
|
|
151
|
+
? newRect.width
|
|
152
|
+
: newRect.height + (newRect.y - currentY);
|
|
153
|
+
newRect.y =
|
|
154
|
+
selectedRectangle.shape === "circle" ? newRect.y : currentY;
|
|
155
|
+
break;
|
|
156
|
+
case "bottom-left":
|
|
157
|
+
newRect.width += newRect.x - currentX;
|
|
158
|
+
newRect.height =
|
|
159
|
+
selectedRectangle.shape === "circle"
|
|
160
|
+
? newRect.width
|
|
161
|
+
: currentY - newRect.y;
|
|
162
|
+
newRect.x = currentX;
|
|
163
|
+
break;
|
|
164
|
+
case "bottom-right":
|
|
165
|
+
newRect.width = currentX - newRect.x;
|
|
166
|
+
newRect.height =
|
|
167
|
+
selectedRectangle.shape === "circle"
|
|
168
|
+
? newRect.width
|
|
169
|
+
: currentY - newRect.y;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
// Ensure width and height are always positive
|
|
173
|
+
newRect.width = Math.max(10, newRect.width);
|
|
174
|
+
newRect.height = Math.max(10, newRect.height);
|
|
175
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id ? Object.assign({}, newRect) : rect));
|
|
176
|
+
setSelectedRectangle(newRect);
|
|
177
|
+
}
|
|
178
|
+
if ((activeTool === "rectangle" ||
|
|
179
|
+
activeTool === "circle" ||
|
|
180
|
+
activeTool === "vip-seat") &&
|
|
181
|
+
isDragging &&
|
|
182
|
+
startPoint) {
|
|
183
|
+
const rect = e.target.getBoundingClientRect();
|
|
184
|
+
const currentX = e.clientX - rect.left;
|
|
185
|
+
const currentY = e.clientY - rect.top;
|
|
186
|
+
// Update shadow rectangle dimensions dynamically
|
|
187
|
+
const newShadowRect = {
|
|
188
|
+
id: -1, // Temporary ID for preview
|
|
189
|
+
x: Math.min(startPoint.x, currentX),
|
|
190
|
+
y: Math.min(startPoint.y, currentY),
|
|
191
|
+
width: Math.abs(currentX - startPoint.x),
|
|
192
|
+
height: Math.abs(currentY - startPoint.y),
|
|
193
|
+
color: activeTool === "vip-seat" ? "#2D2D36" : "rgba(74, 144, 226, 0.4)", // Light blue with transparency
|
|
194
|
+
pax: "",
|
|
195
|
+
rotation: 0,
|
|
196
|
+
shape: activeTool === "vip-seat" ? "vip-seat" : activeTool, // Define shape type
|
|
197
|
+
highlightColor: activeTool === "vip-seat" ? "#C1443D" : undefined, // Red section in VIP
|
|
198
|
+
status: activeTool === "vip-seat" ? "SOLD" : undefined,
|
|
199
|
+
table: activeTool === "vip-seat" ? `V${rectangles.length + 1}` : undefined, // Table number for VIP
|
|
200
|
+
};
|
|
201
|
+
setShadowRect(newShadowRect);
|
|
202
|
+
}
|
|
203
|
+
// Dragging for select tool
|
|
204
|
+
if (activeTool === "select" &&
|
|
205
|
+
isDragging &&
|
|
206
|
+
selectedRectangle &&
|
|
207
|
+
dragOffset) {
|
|
208
|
+
const workspaceRect = e.currentTarget.getBoundingClientRect();
|
|
209
|
+
const newX = e.clientX - workspaceRect.left - dragOffset.x;
|
|
210
|
+
const newY = e.clientY - workspaceRect.top - dragOffset.y;
|
|
211
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id
|
|
212
|
+
? Object.assign(Object.assign({}, rect), { x: newX, y: newY }) : rect));
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const handleMouseUp = () => {
|
|
216
|
+
setIsDragging(false);
|
|
217
|
+
setResizeDirection(null);
|
|
218
|
+
if ((activeTool === "rectangle" ||
|
|
219
|
+
activeTool === "circle" ||
|
|
220
|
+
activeTool === "vip-seat") &&
|
|
221
|
+
isDragging &&
|
|
222
|
+
shadowRect) {
|
|
223
|
+
// Finalize the rectangle on mouse release
|
|
224
|
+
const newRectangle = Object.assign(Object.assign({}, shadowRect), { id: rectangles.length + 1, color: "#4A90E2", pax: activeTool === "vip-seat" ? "4 Pax" : "Seat", highlightColor: activeTool === "vip-seat" ? "#C1443D" : undefined, status: activeTool === "vip-seat" ? "SOLD" : undefined, table: activeTool === "vip-seat" ? "V1" : undefined });
|
|
225
|
+
setRectangles([...rectangles, newRectangle]);
|
|
226
|
+
setImages((prev) => prev.map((img) => img.id === (selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id)
|
|
227
|
+
? Object.assign(Object.assign({}, img), { x: newRectangle.x, y: newRectangle.y }) : img));
|
|
228
|
+
setShadowRect(null); // Clear shadow preview
|
|
229
|
+
setIsDragging(false);
|
|
230
|
+
setStartPoint(null);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const handleRectangleMouseDown = (e, rect) => {
|
|
234
|
+
if (activeTool === "select" || activeTool === "node") {
|
|
235
|
+
setSelectedRectangle(rect);
|
|
236
|
+
const rectBox = e.target.getBoundingClientRect();
|
|
237
|
+
setDragOffset({
|
|
238
|
+
x: e.clientX - rectBox.left,
|
|
239
|
+
y: e.clientY - rectBox.top,
|
|
240
|
+
});
|
|
241
|
+
setIsDragging(true);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
const handleRectangleDoubleClick = (rect) => {
|
|
245
|
+
if (activeTool === "select" || activeTool === "node") {
|
|
246
|
+
setSelectedRectangle(rect);
|
|
247
|
+
setShowModal(true);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
const updateRectangle = (updates) => {
|
|
251
|
+
if (selectedRectangle) {
|
|
252
|
+
setRectangles((prev) => prev.map((rect) => rect.id === selectedRectangle.id ? Object.assign(Object.assign({}, rect), updates) : rect));
|
|
253
|
+
setSelectedRectangle((prev) => (prev ? Object.assign(Object.assign({}, prev), updates) : null));
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
const startResizing = (direction) => {
|
|
257
|
+
setResizeDirection(direction);
|
|
258
|
+
setIsDragging(true);
|
|
259
|
+
};
|
|
260
|
+
// Set the cursor style based on the active tool
|
|
261
|
+
const getCursorStyle = () => {
|
|
262
|
+
if (activeTool === "rectangle" ||
|
|
263
|
+
activeTool === "circle" ||
|
|
264
|
+
activeTool === "vip-seat")
|
|
265
|
+
return "cursor-crosshair";
|
|
266
|
+
if (activeTool === "select")
|
|
267
|
+
return "cursor-default";
|
|
268
|
+
if (activeTool === "node")
|
|
269
|
+
return "cursor-pointer";
|
|
270
|
+
return "cursor-default";
|
|
271
|
+
};
|
|
272
|
+
const deleteSelectedRectangle = () => {
|
|
273
|
+
if (selectedRectangle) {
|
|
274
|
+
setRectangles((prev) => prev.filter((rect) => rect.id !== selectedRectangle.id));
|
|
275
|
+
setSelectedRectangle(null);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
// duplicate
|
|
279
|
+
const duplicateRectangle = () => {
|
|
280
|
+
if (selectedRectangle) {
|
|
281
|
+
const newRectangle = Object.assign(Object.assign({}, selectedRectangle), { id: rectangles.length + 1, x: selectedRectangle.x + 20, y: selectedRectangle.y + 20 });
|
|
282
|
+
setRectangles([...rectangles, newRectangle]);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
const exportJSON = () => {
|
|
286
|
+
// const json = JSON.stringify(rectangles, null, 2);
|
|
287
|
+
// const blob = new Blob([json], { type: "application/json" });
|
|
288
|
+
// const link = document.createElement("a");
|
|
289
|
+
// link.href = URL.createObjectURL(blob);
|
|
290
|
+
// link.download = "seat_layout.json";
|
|
291
|
+
// document.body.appendChild(link);
|
|
292
|
+
// link.click();
|
|
293
|
+
// document.body.removeChild(link);
|
|
294
|
+
};
|
|
295
|
+
return (<div className="flex h-screen w-full">
|
|
296
|
+
{/* Toolbar */}
|
|
297
|
+
<div className="w-16 bg-gray-800 text-white flex flex-col items-center py-4 space-y-4">
|
|
298
|
+
{/* Select Tool */}
|
|
299
|
+
<Button type={activeTool === "select" ? "primary" : "default"} shape="circle" icon={<MousePointer2 />} onClick={() => handleToolClick("select")}/>
|
|
300
|
+
<Button type={activeTool === "circle" ? "primary" : "default"} shape="circle" icon={<Circle />} onClick={() => handleToolClick("circle")}/>
|
|
301
|
+
<Button type={activeTool === "vip-seat" ? "primary" : "default"} shape="circle" icon={<PenIcon />} // Use any icon you prefer
|
|
302
|
+
onClick={() => handleToolClick("vip-seat")}/>
|
|
303
|
+
{/* Rectangle Tool */}
|
|
304
|
+
<Button type={activeTool === "rectangle" ? "primary" : "default"} shape="circle" icon={<Square />} onClick={() => handleToolClick("rectangle")}/>
|
|
305
|
+
{/* Node Tool */}
|
|
306
|
+
<Button type={activeTool === "node" ? "primary" : "default"} shape="circle" icon={<Move3D />} onClick={() => handleToolClick("node")}/>
|
|
307
|
+
<Button type={activeTool === "pen" ? "primary" : "default"} shape="circle" icon={<Pencil />} onClick={() => handleToolClick("pen")}/>
|
|
308
|
+
|
|
309
|
+
{/* delete */}
|
|
310
|
+
<Button type="default" shape="circle" icon={<Trash />} onClick={deleteSelectedRectangle}/>
|
|
311
|
+
{/* duplicate */}
|
|
312
|
+
<Button type="default" shape="circle" icon={<CopyPlusIcon />} // You can use a copy icon
|
|
313
|
+
onClick={duplicateRectangle}/>
|
|
314
|
+
{/* zoomIn/out */}
|
|
315
|
+
<Button type="default" shape="circle" onClick={zoomIn} icon={<ZoomInIcon />}/>
|
|
316
|
+
<Button type="default" shape="circle" onClick={zoomOut} icon={<ZoomOutIcon />}/>
|
|
317
|
+
{/* {activeTool === "image" && ( */}
|
|
318
|
+
<UploadIcon />
|
|
319
|
+
<span>Image Seat</span>
|
|
320
|
+
<input type="file" accept="image/*" onChange={handleImageUpload}/>
|
|
321
|
+
<span>Background Image</span>
|
|
322
|
+
<input type="file" accept="image/*" onChange={handleImageUploadBackground}/>
|
|
323
|
+
{/* )} */}
|
|
324
|
+
<Button shape="circle" icon={<DownloadIcon />} onClick={exportJSON}/>
|
|
325
|
+
</div>
|
|
326
|
+
|
|
327
|
+
{/* Workspace */}
|
|
328
|
+
<div className="w-full flex items-center justify-center" id={"workspace"}>
|
|
329
|
+
<div className={`bg-gray-900 relative ${getCursorStyle()} w-full h-screen `} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} style={{
|
|
330
|
+
transform: `scale(${zoom})`,
|
|
331
|
+
transformOrigin: "0 0",
|
|
332
|
+
}}>
|
|
333
|
+
|
|
334
|
+
{shadowRect && (<div className="absolute border-dashed border-2 border-blue-400" style={{
|
|
335
|
+
left: shadowRect.x,
|
|
336
|
+
top: shadowRect.y,
|
|
337
|
+
width: shadowRect.width,
|
|
338
|
+
height: shadowRect.height,
|
|
339
|
+
backgroundColor: shadowRect.color,
|
|
340
|
+
}}/>)}
|
|
341
|
+
{/* Render rectangles */}
|
|
342
|
+
{rectangles.map((rect) => (<div key={rect.id} onMouseDown={(e) => handleRectangleMouseDown(e, rect)} onDoubleClick={() => handleRectangleDoubleClick(rect)} className={`absolute cursor-move border transition-transform ${(selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id) === rect.id
|
|
343
|
+
? "border-black"
|
|
344
|
+
: "border-gray-300"}`} style={{
|
|
345
|
+
left: rect.x,
|
|
346
|
+
top: rect.y,
|
|
347
|
+
width: rect.width,
|
|
348
|
+
height: rect.height,
|
|
349
|
+
backgroundColor: rect.color,
|
|
350
|
+
transform: `rotate(${rect.rotation}deg)`,
|
|
351
|
+
transformOrigin: "center",
|
|
352
|
+
borderRadius: rect.shape === "circle" ? "100%" : "0%",
|
|
353
|
+
}}>
|
|
354
|
+
{rect.shape === "image-table" && (<div className="w-full h-full relative">
|
|
355
|
+
<img src={rect.src} alt="custom" className="w-full h-full object-cover" draggable={false}/>
|
|
356
|
+
<div className="absolute left-0 right-0 flex items-center justify-center" style={{
|
|
357
|
+
top: "10%",
|
|
358
|
+
height: "20%",
|
|
359
|
+
backgroundColor: rect.highlightColor || "transparent",
|
|
360
|
+
}}>
|
|
361
|
+
<span className="text-white font-bold text-xs absolute" style={{
|
|
362
|
+
top: "10%",
|
|
363
|
+
left: "50%",
|
|
364
|
+
}}>
|
|
365
|
+
{rect.table}
|
|
366
|
+
</span>
|
|
367
|
+
</div>
|
|
368
|
+
<span className="text-xs text-white flex items-center justify-center absolute w-full" style={{
|
|
369
|
+
top: "85%",
|
|
370
|
+
left: "50%",
|
|
371
|
+
transform: "translate(-50%, -50%)",
|
|
372
|
+
backgroundColor: rect.highlightColor || "transparent"
|
|
373
|
+
}}>
|
|
374
|
+
{rect.pax}
|
|
375
|
+
</span>
|
|
376
|
+
<div className="absolute left-0 right-0 flex items-center justify-center" style={{
|
|
377
|
+
top: "40%",
|
|
378
|
+
height: "20%",
|
|
379
|
+
backgroundColor: rect.highlightColor || "transparent",
|
|
380
|
+
}}>
|
|
381
|
+
<span className="text-white font-bold text-xs">
|
|
382
|
+
{rect.status}
|
|
383
|
+
</span>
|
|
384
|
+
</div>
|
|
385
|
+
</div>)}
|
|
386
|
+
{rect.shape === "image" && (<img src={rect.src} alt="custom" className="w-full h-full object-cover" draggable={false}/>)}
|
|
387
|
+
{rect.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
|
|
388
|
+
top: "10%",
|
|
389
|
+
height: "20%",
|
|
390
|
+
}}>
|
|
391
|
+
<span className="text-white font-bold text-xs">
|
|
392
|
+
{rect.table}
|
|
393
|
+
</span>
|
|
394
|
+
</div>)}
|
|
395
|
+
{rect.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
|
|
396
|
+
top: "40%",
|
|
397
|
+
height: "20%",
|
|
398
|
+
backgroundColor: rect.highlightColor || "transparent",
|
|
399
|
+
}}>
|
|
400
|
+
<span className="text-white font-bold text-xs">
|
|
401
|
+
{rect.status}
|
|
402
|
+
</span>
|
|
403
|
+
</div>)}
|
|
404
|
+
|
|
405
|
+
{/* Bottom Text */}
|
|
406
|
+
<div className="absolute bottom-2 left-0 right-0 text-center text-white text-sm">
|
|
407
|
+
{rect.shape === "vip-seat" ? "8 Pax" : ""}
|
|
408
|
+
</div>
|
|
409
|
+
|
|
410
|
+
{/* Resize Nodes */}
|
|
411
|
+
{/* Resize Nodes (Only Show When in Node Mode and Item is Selected) */}
|
|
412
|
+
{activeTool === "node" && (selectedRectangle === null || selectedRectangle === void 0 ? void 0 : selectedRectangle.id) === rect.id && (<>
|
|
413
|
+
{/* Top Left */}
|
|
414
|
+
<div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
|
|
415
|
+
top: -6,
|
|
416
|
+
left: -6,
|
|
417
|
+
cursor: "nwse-resize",
|
|
418
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
419
|
+
}} onMouseDown={() => startResizing("top-left")}/>
|
|
420
|
+
{/* Top Right */}
|
|
421
|
+
<div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
|
|
422
|
+
top: -6,
|
|
423
|
+
right: -6,
|
|
424
|
+
cursor: "nesw-resize",
|
|
425
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
426
|
+
}} onMouseDown={() => startResizing("top-right")}/>
|
|
427
|
+
{/* Bottom Left */}
|
|
428
|
+
<div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
|
|
429
|
+
bottom: -6,
|
|
430
|
+
left: -6,
|
|
431
|
+
cursor: "nesw-resize",
|
|
432
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
433
|
+
}} onMouseDown={() => startResizing("bottom-left")}/>
|
|
434
|
+
{/* Bottom Right */}
|
|
435
|
+
<div className="absolute w-3 h-3 bg-white border border-gray-800" style={{
|
|
436
|
+
bottom: -6,
|
|
437
|
+
right: -6,
|
|
438
|
+
cursor: "nwse-resize",
|
|
439
|
+
borderRadius: rect.shape === "circle" ? "50%" : "0%",
|
|
440
|
+
}} onMouseDown={() => startResizing("bottom-right")}/>
|
|
441
|
+
</>)}
|
|
442
|
+
</div>))}
|
|
443
|
+
</div>
|
|
444
|
+
</div>
|
|
445
|
+
|
|
446
|
+
{/* Rectangle Customization Modal */}
|
|
447
|
+
<Modal open={showModal} onCancel={() => setShowModal(false)} onOk={() => setShowModal(false)} title="Edit Rectangle">
|
|
448
|
+
{selectedRectangle && (<>
|
|
449
|
+
<div className="flex gap-4 items-center">
|
|
450
|
+
<div className="flex flex-col">
|
|
451
|
+
<p className="mb-2 font-semibold">Change Color:</p>
|
|
452
|
+
<SketchPicker color={selectedRectangle.color} onChangeComplete={(color) => updateRectangle({ color: color.hex })}/>
|
|
453
|
+
</div>
|
|
454
|
+
<div className="flex flex-col">
|
|
455
|
+
<p className="mt-4 mb-2 font-semibold">Live Preview:</p>
|
|
456
|
+
<div className="relative borderflex items-center justify-center" style={{
|
|
457
|
+
width: selectedRectangle.width,
|
|
458
|
+
height: selectedRectangle.height,
|
|
459
|
+
margin: "0 auto",
|
|
460
|
+
transform: `rotate(${selectedRectangle.rotation}deg)`,
|
|
461
|
+
backgroundColor: selectedRectangle.color,
|
|
462
|
+
transition: "all 0.3s ease",
|
|
463
|
+
scale: "0.5",
|
|
464
|
+
borderRadius: selectedRectangle.shape === "circle" ? "100%" : "0%",
|
|
465
|
+
}}>
|
|
466
|
+
{selectedRectangle.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
|
|
467
|
+
top: "10%",
|
|
468
|
+
height: "20%",
|
|
469
|
+
}}>
|
|
470
|
+
<span className="text-white font-bold text-xs">
|
|
471
|
+
{selectedRectangle.status}sfsdf
|
|
472
|
+
</span>
|
|
473
|
+
</div>)}
|
|
474
|
+
{selectedRectangle.shape === "vip-seat" && (<div className="absolute left-0 right-0 flex items-center justify-center" style={{
|
|
475
|
+
top: "40%",
|
|
476
|
+
height: "20%",
|
|
477
|
+
backgroundColor: selectedRectangle.highlightColor || "transparent",
|
|
478
|
+
}}>
|
|
479
|
+
<span className="text-white font-bold text-xs">
|
|
480
|
+
{selectedRectangle.status} dsdsd
|
|
481
|
+
</span>
|
|
482
|
+
</div>)}
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
</div>
|
|
486
|
+
|
|
487
|
+
{/* Preview Section */}
|
|
488
|
+
|
|
489
|
+
<p className="mt-4 mb-2 font-semibold">Edit Text:</p>
|
|
490
|
+
<Input value={selectedRectangle.pax} onChange={(e) => updateRectangle({ pax: e.target.value })}/>
|
|
491
|
+
<p className="mt-4 mb-2 font-semibold">Edit Label:</p>
|
|
492
|
+
<Input value={selectedRectangle.table} onChange={(e) => updateRectangle({ table: e.target.value })}/>
|
|
493
|
+
<p className="mt-4 mb-2 font-semibold">Edit Highlight:</p>
|
|
494
|
+
<Input value={selectedRectangle.status} onChange={(e) => updateRectangle({ status: e.target.value })}/>
|
|
495
|
+
{/* Rotation Controls */}
|
|
496
|
+
<p className="mt-4 mb-2 font-semibold">Rotate:</p>
|
|
497
|
+
<div className="flex gap-4 items-center">
|
|
498
|
+
<Button onClick={() => rotateRectangle("left")}>
|
|
499
|
+
⟲ Rotate Left
|
|
500
|
+
</Button>
|
|
501
|
+
<span>{selectedRectangle.rotation}°</span>
|
|
502
|
+
<Button onClick={() => rotateRectangle("right")}>
|
|
503
|
+
⟳ Rotate Right
|
|
504
|
+
</Button>
|
|
505
|
+
</div>
|
|
506
|
+
</>)}
|
|
507
|
+
</Modal>
|
|
508
|
+
</div>);
|
|
509
|
+
};
|
|
510
|
+
export default SeatEditor;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function ChairIcon(): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const ChairIcon = () => {
|
|
2
|
+
return (<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<g clip-path="url(#clip0_3019_14165)">
|
|
4
|
+
<path d="M15.9717 7.5339V4.70339C15.9717 3.07627 14.7076 2.5 13.5189 2.5H6.46226C5.27359 2.5 4.00943 3.07627 4.00943 4.70339V7.5339C3.14151 7.73729 2.5 8.4322 2.5 9.27966V13.822C2.5 15.161 3.5 15.6864 4.48113 15.7373V16.8898C4.48113 17.2288 4.78302 17.5 5.16038 17.5H5.85849C6.23585 17.5 6.53774 17.2288 6.53774 16.8898V15.7373H13.4623V16.8898C13.4623 17.2288 13.7642 17.5 14.1415 17.5H14.8396C15.217 17.5 15.5189 17.2288 15.5189 16.8898V15.7373C16.9717 15.6695 17.5 14.7203 17.5 13.822V9.26271C17.4623 8.4322 16.8208 7.72034 15.9717 7.5339ZM4.68868 4.70339C4.68868 3.31356 5.80189 3.09322 6.46226 3.09322H13.5189C14.1792 3.09322 15.2925 3.29661 15.2925 4.68644V7.4661C14.2736 7.55085 13.4623 8.31356 13.4623 9.26271V9.68644H6.51887V9.26271C6.51887 8.31356 5.70755 7.55085 4.68868 7.4661V4.70339ZM13.4434 10.2966V12.3983H6.51887V10.2966H13.4434ZM5.85849 16.8898H5.16038V15.7373H5.85849V16.8898ZM14.8208 16.8898H14.1226V15.7373H14.8208V16.8898ZM16.8208 13.822H16.8019C16.8019 14.4153 16.5566 15.1441 15.3302 15.1441H14.8208H14.1226H5.85849H5.16038H4.65094C3.99057 15.1441 3.17925 14.9237 3.17925 13.822V9.26271C3.17925 8.6017 3.78302 8.05932 4.51887 8.05932C5.25472 8.05932 5.85849 8.6017 5.85849 9.26271V12.7034C5.85849 12.8729 6.00943 13.0085 6.19811 13.0085H13.8019C13.9906 13.0085 14.1415 12.8729 14.1415 12.7034V9.26271C14.1415 8.6017 14.7453 8.05932 15.4811 8.05932C16.217 8.05932 16.8208 8.6017 16.8208 9.26271V13.822Z" fill="#347ADB" stroke="#347ADB" stroke-width="0.8"/>
|
|
5
|
+
</g>
|
|
6
|
+
<defs>
|
|
7
|
+
<clipPath id="clip0_3019_14165">
|
|
8
|
+
<rect width="16.6667" height="16.6667" fill="white" transform="translate(1.66675 1.6665)"/>
|
|
9
|
+
</clipPath>
|
|
10
|
+
</defs>
|
|
11
|
+
</svg>);
|
|
12
|
+
};
|