Refactor simulation styles and update API services

- Refactored SCSS styles for simulation player and dashboard components to improve readability and maintainability.
- Changed property names in Block and UIElement types for clarity.
- Implemented getDashBoardBlocksApi and upsertDashBoardBlocksApi services for fetching and updating dashboard blocks.
- Removed unnecessary transition property in simulation dashboard styles.
This commit is contained in:
2025-10-17 10:27:43 +05:30
parent 48c7007431
commit ba615cefed
16 changed files with 1016 additions and 956 deletions

View File

@@ -1,3 +1,4 @@
import { useParams } from "react-router-dom";
import React, { useState, useRef, useEffect } from "react";
import { dataModelManager } from "./data/dataModel";
import ControlPanel from "./ControlPanel";
@@ -5,16 +6,24 @@ import SwapModal from "./SwapModal";
import DataModelPanel from "./components/models/DataModelPanel";
import { useSceneContext } from "../../modules/scene/sceneContext";
import useModuleStore from "../../store/ui/useModuleStore";
import { calculateMinBlockSize } from "./functions/block/calculateMinBlockSize";
import { handleElementDragStart, handleElementResizeStart, handleBlockResizeStart, handleSwapStart, handleSwapTarget, handleBlockClick, handleElementClick } from "./functions/eventHandlers";
import BlockGrid from "./components/block/BlockGrid";
import ElementDropdown from "./components/element/ElementDropdown";
import BlockEditor from "./components/block/BlockEditor";
import ElementEditor from "./components/element/ElementEditor";
import useCallBackOnKey from "../../utils/hooks/useCallBackOnKey";
import { handleBlockDragStart } from "./functions/block/handleBlockDragStart";
import { getDashBoardBlocksApi } from "../../services/visulization/dashBoard/getDashBoardBlocks";
import { upsetDashBoardBlocksApi } from "../../services/visulization/dashBoard/upsertDashBoardBlocks";
const DashboardEditor: React.FC = () => {
const { simulationDashBoardStore } = useSceneContext();
const { simulationDashBoardStore, versionStore } = useSceneContext();
const { selectedVersion } = versionStore();
const { projectId } = useParams();
const { activeModule } = useModuleStore();
const {
blocks,
setBlocks,
@@ -33,7 +42,9 @@ const DashboardEditor: React.FC = () => {
updateElementData,
updateGraphData,
updateGraphTitle,
updateGraphType,
swapElements,
subscribe,
} = simulationDashBoardStore();
const [selectedBlock, setSelectedBlock] = useState<string | null>(null);
const [selectedElement, setSelectedElement] = useState<string | null>(null);
@@ -63,8 +74,40 @@ const DashboardEditor: React.FC = () => {
const dropdownRef = useRef<HTMLDivElement>(null);
const blockRef = useRef<HTMLDivElement>(null);
const currentBlock = blocks.find((b) => b.id === selectedBlock);
const currentElement = currentBlock?.elements.find((el) => el.id === selectedElement);
const currentBlock = blocks.find((b) => b.blockUuid === selectedBlock);
const currentElement = currentBlock?.elements.find((el) => el.elementUuid === selectedElement);
useEffect(() => {
if (!projectId || !selectedVersion) return;
// getDashBoardBlocksApi(projectId, selectedVersion.versionId).then((data) => {
// if (data.data && data.data.blocks) {
// console.log("data: ", data);
// setBlocks(data.data.blocks);
// }
// });
}, [projectId, selectedVersion]);
useEffect(() => {
const unsubscribe = subscribe(() => {
if (!projectId || !selectedVersion) return;
// upsetDashBoardBlocksApi({ projectId, versionId: selectedVersion.versionId, blocks }).then((data) => {
// console.log("data: ", data);
// });
});
return () => {
unsubscribe();
};
}, [blocks, projectId, selectedVersion]);
useCallBackOnKey(
() => {
console.log(blocks);
},
"Ctrl+S",
{ dependencies: [blocks], noRepeat: true, allowOnInput: true }
);
// Subscribe to data model changes
useEffect(() => {
@@ -140,86 +183,144 @@ const DashboardEditor: React.FC = () => {
}, [selectedBlock, selectedElement]);
// Drag and drop handler
useEffect(() => {
const handleMouseMove = (e: MouseEvent): void => {
// Element dragging - use elementDragOffset
if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
if (blockElement) {
const blockRect = blockElement.getBoundingClientRect();
const newX = e.clientX - blockRect.left - elementDragOffset.x; // Use elementDragOffset
const newY = e.clientY - blockRect.top - elementDragOffset.y; // Use elementDragOffset
useEffect(() => {
const handleMouseMove = (e: MouseEvent): void => {
// Element dragging - direct DOM manipulation
if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;
if (blockElement && elementToDrag) {
const blockRect = blockElement.getBoundingClientRect();
const newX = e.clientX - blockRect.left - elementDragOffset.x;
const newY = e.clientY - blockRect.top - elementDragOffset.y;
updateElementPosition(selectedBlock, draggingElement, {
x: Math.max(0, Math.min(blockRect.width - 50, newX)),
y: Math.max(0, Math.min(blockRect.height - 30, newY)),
});
}
// Direct DOM manipulation
elementToDrag.style.left = `${Math.max(0, Math.min(blockRect.width - 50, newX))}px`;
elementToDrag.style.top = `${Math.max(0, Math.min(blockRect.height - 30, newY))}px`;
}
}
// Block dragging - use blockDragOffset
if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
const editorElement = editorRef.current;
if (editorElement) {
const editorRect = editorElement.getBoundingClientRect();
const newX = e.clientX - editorRect.left - blockDragOffset.x; // Use blockDragOffset
const newY = e.clientY - editorRect.top - blockDragOffset.y; // Use blockDragOffset
// Block dragging - direct DOM manipulation
if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
const editorElement = editorRef.current;
const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;
if (editorElement && blockToDrag) {
const editorRect = editorElement.getBoundingClientRect();
const newX = e.clientX - editorRect.left - blockDragOffset.x;
const newY = e.clientY - editorRect.top - blockDragOffset.y;
updateBlockPosition(draggingBlock, {
x: Math.max(0, Math.min(editorRect.width - (currentBlock.size?.width || 400), newX)),
y: Math.max(0, Math.min(editorRect.height - (currentBlock.size?.height || 300), newY)),
});
}
// Direct DOM manipulation
blockToDrag.style.left = `${Math.max(0, Math.min(editorRect.width - (currentBlock.size?.width || 400), newX))}px`;
blockToDrag.style.top = `${Math.max(0, Math.min(editorRect.height - (currentBlock.size?.height || 300), newY))}px`;
}
}
if ((resizingElement || resizingBlock) && resizeStart) {
if (resizingElement && selectedBlock) {
// Resizing - direct DOM manipulation
if ((resizingElement || resizingBlock) && resizeStart) {
if (resizingElement && selectedBlock) {
const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
if (elementToResize) {
const deltaX = e.clientX - resizeStart.x;
const deltaY = e.clientY - resizeStart.y;
const newWidth = Math.max(100, resizeStart.width + deltaX);
const newHeight = Math.max(50, resizeStart.height + deltaY);
updateElementSize(selectedBlock, resizingElement, {
width: newWidth,
height: newHeight,
});
} else if (resizingBlock) {
// Direct DOM manipulation
elementToResize.style.width = `${newWidth}px`;
elementToResize.style.height = `${newHeight}px`;
}
} else if (resizingBlock) {
const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
if (blockToResize) {
const deltaX = e.clientX - resizeStart.x;
const deltaY = e.clientY - resizeStart.y;
const currentBlock = blocks.find((b) => b.id === resizingBlock);
const currentBlock = blocks.find((b) => b.blockUuid === resizingBlock);
const minSize = currentBlock ? calculateMinBlockSize(currentBlock) : { width: 300, height: 200 };
const newWidth = Math.max(minSize.width, resizeStart.width + deltaX);
const newHeight = Math.max(minSize.height, resizeStart.height + deltaY);
updateBlockSize(resizingBlock, {
width: newWidth,
height: newHeight,
});
// Direct DOM manipulation
blockToResize.style.width = `${newWidth}px`;
blockToResize.style.height = `${newHeight}px`;
}
}
};
}
};
const handleMouseUp = (): void => {
setDraggingElement(null);
setResizingElement(null);
setDraggingBlock(null);
setResizingBlock(null);
setResizeStart(null);
};
if (draggingElement || draggingBlock || resizingElement || resizingBlock) {
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
const handleMouseUp = (): void => {
// Update state only on mouse up for elements
if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;
if (blockElement && elementToDrag) {
const computedStyle = window.getComputedStyle(elementToDrag);
const x = parseFloat(computedStyle.left);
const y = parseFloat(computedStyle.top);
updateElementPosition(selectedBlock, draggingElement, { x, y });
}
}
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
}, [draggingElement, resizingElement, draggingBlock, resizingBlock, elementDragOffset, blockDragOffset, selectedBlock, currentElement, resizeStart, currentBlock, blocks]);
// Update state only on mouse up for blocks
if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;
if (blockToDrag) {
const computedStyle = window.getComputedStyle(blockToDrag);
const x = parseFloat(computedStyle.left);
const y = parseFloat(computedStyle.top);
updateBlockPosition(draggingBlock, { x, y });
}
}
// Update state only on mouse up for resizing
if (resizingElement && selectedBlock) {
const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
if (elementToResize) {
const computedStyle = window.getComputedStyle(elementToResize);
const width = parseFloat(computedStyle.width);
const height = parseFloat(computedStyle.height);
updateElementSize(selectedBlock, resizingElement, { width, height });
}
}
if (resizingBlock) {
const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
if (blockToResize) {
const computedStyle = window.getComputedStyle(blockToResize);
const width = parseFloat(computedStyle.width);
const height = parseFloat(computedStyle.height);
updateBlockSize(resizingBlock, { width, height });
}
}
// Reset all dragging states
setDraggingElement(null);
setResizingElement(null);
setDraggingBlock(null);
setResizingBlock(null);
setResizeStart(null);
};
if (draggingElement || draggingBlock || resizingElement || resizingBlock) {
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
}
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
};
}, [draggingElement, resizingElement, draggingBlock, resizingBlock, elementDragOffset, blockDragOffset, selectedBlock, currentElement, resizeStart, currentBlock, blocks]);
// Update dropdown position when showElementDropdown changes
useEffect(() => {
@@ -234,7 +335,9 @@ const DashboardEditor: React.FC = () => {
return (
<div ref={editorRef} className="dashboard-editor">
<ControlPanel editMode={editMode} setEditMode={setEditMode} addBlock={() => addBlock()} showDataModelPanel={showDataModelPanel} setShowDataModelPanel={setShowDataModelPanel} />
{activeModule === "visualization" && (
<ControlPanel editMode={editMode} setEditMode={setEditMode} addBlock={() => addBlock()} showDataModelPanel={showDataModelPanel} setShowDataModelPanel={setShowDataModelPanel} />
)}
<BlockGrid
blocks={blocks}
@@ -285,8 +388,6 @@ const DashboardEditor: React.FC = () => {
currentElement={currentElement}
selectedBlock={selectedBlock}
selectedElement={selectedElement}
blocks={blocks}
setBlocks={setBlocks}
updateElementStyle={(blockId, elementId, style) => updateElementStyle(blockId, elementId, style)}
updateElementSize={(blockId, elementId, size) => updateElementSize(blockId, elementId, size)}
updateElementPosition={(blockId, elementId, position) => updateElementPosition(blockId, elementId, position)}
@@ -295,6 +396,7 @@ const DashboardEditor: React.FC = () => {
updateElementData={(blockId, elementId, updates) => updateElementData(blockId, elementId, updates)}
updateGraphData={(blockId, elementId, newData) => updateGraphData(blockId, elementId, newData)}
updateGraphTitle={(blockId, elementId, title) => updateGraphTitle(blockId, elementId, title)}
updateGraphType={(blockId, elementId, type) => updateGraphType(blockId, elementId, type)}
setSwapSource={setSwapSource}
setShowSwapUI={setShowSwapUI}
dataModelManager={dataModelManager}

View File

@@ -44,36 +44,27 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
handleBlockDragStart,
}) => {
const minSize = calculateMinBlockSize(block);
const isSelected = selectedBlock === block.id;
const isDraggable =
editMode && (block.positionType === "absolute" || block.positionType === "fixed");
const isSelected = selectedBlock === block.blockUuid;
const isDraggable = editMode && (block.positionType === "absolute" || block.positionType === "fixed");
const handleMouseDown = (event: React.MouseEvent) => {
if (isDraggable) {
handleBlockDragStart(block.id, event);
handleBlockDragStart(block.blockUuid, event);
}
handleBlockClick(block.id, event);
handleBlockClick(block.blockUuid, event);
};
return (
<div
key={block.id}
data-block-id={block.id}
key={block.blockUuid}
data-block-id={block.blockUuid}
ref={isSelected ? blockRef : null}
className={`block ${isSelected ? "selected" : ""} ${editMode ? "edit-mode" : ""} ${
isDraggable ? "draggable" : ""
}`}
className={`block ${isSelected ? "selected" : ""} ${editMode ? "edit-mode" : ""} ${isDraggable ? "draggable" : ""}`}
style={{
...block.style,
position: block.positionType || "relative",
left:
block.positionType === "absolute" || block.positionType === "fixed"
? `${block.position?.x || 0}px`
: "auto",
top:
block.positionType === "absolute" || block.positionType === "fixed"
? `${block.position?.y || 0}px`
: "auto",
left: block.positionType === "absolute" || block.positionType === "fixed" ? `${block.position?.x || 0}px` : "auto",
top: block.positionType === "absolute" || block.positionType === "fixed" ? `${block.position?.y || 0}px` : "auto",
width: block.size?.width || 400,
height: block.size?.height || 300,
minWidth: minSize.width,
@@ -88,7 +79,7 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
<button
onClick={(e) => {
e.stopPropagation();
setShowElementDropdown(showElementDropdown === block.id ? null : block.id);
setShowElementDropdown(showElementDropdown === block.blockUuid ? null : block.blockUuid);
}}
className="add-element-button"
>
@@ -99,9 +90,9 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
{/* Elements */}
{block.elements.map((el) => (
<ElementComponent
key={el.id}
key={el.elementUuid}
element={el}
blockId={block.id}
blockId={block.blockUuid}
editMode={editMode}
selectedElement={selectedElement}
showSwapUI={showSwapUI}
@@ -115,12 +106,7 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
))}
{/* Block resize handle */}
{editMode && isSelected && (
<div
className="resize-handle"
onMouseDown={(e) => handleBlockResizeStart(block.id, e)}
/>
)}
{editMode && isSelected && <div className="resize-handle" onMouseDown={(e) => handleBlockResizeStart(block.blockUuid, e)} />}
{/* Drag handle indicator for absolute/fixed blocks */}
{isDraggable && editMode && (

View File

@@ -50,7 +50,7 @@ const BlockGrid: React.FC<BlockGridProps> = ({
<div className="block-grid">
{blocks.map((block) => (
<BlockComponent
key={block.id}
key={block.blockUuid}
block={block}
editMode={editMode}
selectedBlock={selectedBlock}
@@ -68,7 +68,7 @@ const BlockGrid: React.FC<BlockGridProps> = ({
handleBlockDragStart={handleBlockDragStart}
setShowElementDropdown={setShowElementDropdown}
showElementDropdown={showElementDropdown}
blockRef={selectedBlock === block.id ? blockRef : noopRef}
blockRef={selectedBlock === block.blockUuid ? blockRef : noopRef}
/>
))}
</div>

View File

@@ -30,8 +30,8 @@ const ElementComponent: React.FC<ElementComponentProps> = ({
handleSwapStart,
handleSwapTarget,
}) => {
const isSelected = selectedElement === element.id;
const isSwapSource = swapSource === element.id;
const isSelected = selectedElement === element.elementUuid;
const isSwapSource = swapSource === element.elementUuid;
const elementClasses = [
"element",
@@ -47,14 +47,13 @@ const ElementComponent: React.FC<ElementComponentProps> = ({
return (
<div
key={element.id}
data-element-id={element.id}
key={element.elementUuid}
data-element-id={element.elementUuid}
className={elementClasses}
style={{
...element.style,
position: element.positionType || "relative",
left:
element.positionType === "absolute" ? `${element.position?.x || 0}px` : "auto",
left: element.positionType === "absolute" ? `${element.position?.x || 0}px` : "auto",
top: element.positionType === "absolute" ? `${element.position?.y || 0}px` : "auto",
width: element.size?.width || "auto",
height: element.size?.height || "auto",
@@ -63,30 +62,24 @@ const ElementComponent: React.FC<ElementComponentProps> = ({
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
if (showSwapUI && swapSource !== element.id) {
handleSwapTarget(element.id, e);
if (showSwapUI && swapSource !== element.elementUuid) {
handleSwapTarget(element.elementUuid, e);
} else {
handleElementClick(blockId, element.id, e);
handleElementClick(blockId, element.elementUuid, e);
}
}}
onMouseDown={(e) => handleElementDragStart(element.id, e)}
onMouseDown={(e) => handleElementDragStart(element.elementUuid, e)}
>
<ElementContent element={element} resolvedData={resolveElementValue(element)} />
{editMode && (
<>
{element.positionType === "relative" && (
<button
onClick={(e) => handleSwapStart(element.id, e)}
className="swap-button"
>
<button onClick={(e) => handleSwapStart(element.elementUuid, e)} className="swap-button">
Swap
</button>
)}
<div
className="resize-handle"
onMouseDown={(e) => handleElementResizeStart(element.id, e)}
/>
<div className="resize-handle" onMouseDown={(e) => handleElementResizeStart(element.elementUuid, e)} />
</>
)}
</div>

View File

@@ -1,5 +1,5 @@
import type { RefObject } from "react";
import { ExtendedCSSProperties, UIElement, Block } from "../../../../types/exportedTypes";
import { ExtendedCSSProperties, UIElement } from "../../../../types/exportedTypes";
import { getCurrentElementStyleValue } from "../../functions/helpers/getCurrentElementStyleValue";
import type { DataModelManager } from "../../data/dataModel";
@@ -8,8 +8,6 @@ interface ElementEditorProps {
currentElement: UIElement;
selectedBlock: string;
selectedElement: string;
blocks: Block[];
setBlocks: (blocks: Block[]) => void;
updateElementStyle: (blockId: string, elementId: string, style: ExtendedCSSProperties) => void;
updateElementSize: (blockId: string, elementId: string, size: { width: number; height: number }) => void;
updateElementPosition: (blockId: string, elementId: string, position: { x: number; y: number }) => void;
@@ -18,6 +16,7 @@ interface ElementEditorProps {
updateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => void;
updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void;
updateGraphTitle: (blockId: string, elementId: string, title: string) => void;
updateGraphType: (blockId: string, elementId: string, type: GraphTypes) => void;
setSwapSource: (source: string | null) => void;
setShowSwapUI: (show: boolean) => void;
dataModelManager: DataModelManager;
@@ -28,8 +27,6 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
currentElement,
selectedBlock,
selectedElement,
blocks,
setBlocks,
updateElementStyle,
updateElementSize,
updateElementPosition,
@@ -38,6 +35,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
updateElementData,
updateGraphData,
updateGraphTitle,
updateGraphType,
setSwapSource,
setShowSwapUI,
dataModelManager,
@@ -352,26 +350,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
<label className="form-label">Chart Type: </label>
<select
value={currentElement.graphType || "line"}
onChange={(e) => {
const newGraphType = e.target.value as "line" | "bar" | "area" | "pie" | "radar";
setBlocks(
blocks.map((b) =>
b.id === selectedBlock
? {
...b,
elements: b.elements.map((el) =>
el.id === selectedElement
? {
...el,
graphType: newGraphType,
}
: el
),
}
: b
)
);
}}
onChange={(e) => updateGraphType(selectedBlock, selectedElement, e.target.value as GraphTypes)}
className="form-select"
>
<option value="line">Line Chart</option>

View File

@@ -27,13 +27,13 @@ import RenameTooltip from "../../ui/features/RenameTooltip";
import VersionSaved from "../sidebarRight/versionHisory/VersionSaved";
import Footer from "../../footer/Footer";
import ThreadChat from "../../ui/collaboration/threads/ThreadChat";
import DashboardEditor from "../../SimulationDashboard/DashboardEditor";
import Scene from "../../../modules/scene/scene";
import { recentlyViewedApi } from "../../../services/dashboard/recentlyViewedApi";
import { setAssetsApi } from "../../../services/builder/asset/floorAsset/setAssetsApi";
import { getVersionHistoryApi } from "../../../services/builder/versionControl/getVersionHistoryApi";
import { getUserData } from "../../../functions/getUserData";
import DashboardEditor from "../../SimulationDashboard/DashboardEditor";
function MainScene() {
const { setMainState, clearComparisonState } = useSimulationState();
@@ -205,7 +205,7 @@ function MainScene() {
{activeModule !== "market" && !isPlaying && !isComparing && <Tools />}
{isPlaying && activeModule === "simulation" && loadingProgress === 0 && <SimulationPlayer />}
{isPlaying && activeModule !== "simulation" && <ControlsPlayer />}
{activeModule === "visualization" && <DashboardEditor />}
{(activeModule === "visualization" || (isPlaying && activeModule === "simulation")) && <DashboardEditor />}
{isRenameMode && selectedAssets.length === 1 && <RenameTooltip name={selectedAssets[0].userData.modelName} onSubmit={handleObjectRename} />}

View File

@@ -1,31 +1,12 @@
import React, { useEffect, useRef, useState } from "react";
import {
AsileIcon,
CommentIcon,
CursorIcon,
DeleteIcon,
FloorIcon,
FreeMoveIcon,
MeasureToolIcon,
PenIcon,
PlayIcon,
SaveTemplateIcon,
WallIcon,
ZoneIcon,
} from "../icons/ExportToolsIcons";
import { AsileIcon, CommentIcon, CursorIcon, DeleteIcon, FloorIcon, FreeMoveIcon, MeasureToolIcon, PenIcon, PlayIcon, SaveTemplateIcon, WallIcon, ZoneIcon } from "../icons/ExportToolsIcons";
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
import useModuleStore from "../../store/ui/useModuleStore";
import { handleSaveTemplate } from "../../modules/visualization/functions/handleSaveTemplate";
import { usePlayButtonStore } from "../../store/ui/usePlayButtonStore";
import useTemplateStore from "../../store/ui/useTemplateStore";
import { useSelectedZoneStore } from "../../store/visualization/old/useZoneStore";
import {
useActiveTool,
useToggleView,
useToolMode,
useActiveSubTool,
useShortcutStore,
} from "../../store/builder/store";
import { useActiveTool, useToggleView, useToolMode, useActiveSubTool, useShortcutStore } from "../../store/builder/store";
import { useSocketStore } from "../../store/socket/useSocketStore";
import { useToggleStore } from "../../store/ui/useUIToggleStore";
import { use3DWidget, useFloatingWidget } from "../../store/visualization/old/useDroppedObjectsStore";
@@ -66,7 +47,8 @@ const Tools: React.FC = () => {
const { widgets3D } = use3DWidget();
const { visualizationSocket } = useSocketStore();
const { versionStore } = useSceneContext();
const { versionStore, simulationDashBoardStore } = useSceneContext();
const { saveBlocks } = simulationDashBoardStore();
const { selectedVersion } = versionStore();
const { projectId } = useParams();
@@ -75,10 +57,7 @@ const Tools: React.FC = () => {
// 1. Set UI toggles on initial render
useEffect(() => {
setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
setToggleUI(localStorage.getItem("navBarUiLeft") !== "false", localStorage.getItem("navBarUiRight") !== "false");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -172,67 +151,28 @@ const Tools: React.FC = () => {
}
setActiveTool("cursor");
setActiveSubTool("cursor");
setToggleUI(
localStorage.getItem("navBarUiLeft") !== "false",
localStorage.getItem("navBarUiRight") !== "false"
);
setToggleUI(localStorage.getItem("navBarUiLeft") !== "false", localStorage.getItem("navBarUiRight") !== "false");
};
const renderBuilderTools = () => (
<>
{toggleView && (
<div className="draw-tools">
<ToolButton
toolId="drawWall"
icon={WallIcon}
tooltip="draw wall (q)"
active={activeTool === "draw-wall"}
onClick={() => setActiveTool("draw-wall")}
/>
<ToolButton
toolId="drawZone"
icon={ZoneIcon}
tooltip="draw zone (e)"
active={activeTool === "draw-zone"}
onClick={() => setActiveTool("draw-zone")}
/>
<ToolButton
toolId="drawAisle"
icon={AsileIcon}
tooltip="draw aisle (r)"
active={activeTool === "draw-aisle"}
onClick={() => setActiveTool("draw-aisle")}
/>
<ToolButton
toolId="drawFloor"
icon={FloorIcon}
tooltip="draw floor (t)"
active={activeTool === "draw-floor"}
onClick={() => setActiveTool("draw-floor")}
/>
<ToolButton toolId="drawWall" icon={WallIcon} tooltip="draw wall (q)" active={activeTool === "draw-wall"} onClick={() => setActiveTool("draw-wall")} />
<ToolButton toolId="drawZone" icon={ZoneIcon} tooltip="draw zone (e)" active={activeTool === "draw-zone"} onClick={() => setActiveTool("draw-zone")} />
<ToolButton toolId="drawAisle" icon={AsileIcon} tooltip="draw aisle (r)" active={activeTool === "draw-aisle"} onClick={() => setActiveTool("draw-aisle")} />
<ToolButton toolId="drawFloor" icon={FloorIcon} tooltip="draw floor (t)" active={activeTool === "draw-floor"} onClick={() => setActiveTool("draw-floor")} />
</div>
)}
<div className="draw-tools">
<ToolButton
toolId="measureScale"
icon={MeasureToolIcon}
tooltip="measure scale (m)"
active={activeTool === "measure"}
onClick={() => setActiveTool("measure")}
/>
<ToolButton toolId="measureScale" icon={MeasureToolIcon} tooltip="measure scale (m)" active={activeTool === "measure"} onClick={() => setActiveTool("measure")} />
</div>
</>
);
const renderSimulationTools = () => (
<div className="draw-tools">
<ToolButton
toolId="pen"
icon={PenIcon}
tooltip="pen"
active={activeTool === "pen"}
onClick={() => setActiveTool("pen")}
/>
<ToolButton toolId="pen" icon={PenIcon} tooltip="pen" active={activeTool === "pen"} onClick={() => setActiveTool("pen")} />
</div>
);
@@ -243,7 +183,8 @@ const Tools: React.FC = () => {
icon={SaveTemplateIcon}
tooltip="save template"
active={false}
onClick={() =>
onClick={() => {
saveBlocks();
handleSaveTemplate({
addTemplate,
floatingWidget,
@@ -253,18 +194,14 @@ const Tools: React.FC = () => {
visualizationSocket,
projectId,
versionId: selectedVersion?.versionId || "",
})
}
});
}}
/>
</div>
);
const renderModeSwitcher = () => (
<button
id="toggle-threed-button"
className={`toggle-threed-button${!toggleView ? " toggled" : ""}`}
onClick={toggle2D3D}
>
<button id="toggle-threed-button" className={`toggle-threed-button${!toggleView ? " toggled" : ""}`} onClick={toggle2D3D}>
<div className="tooltip">toggle view (tab)</div>
<div className={`toggle-option${toggleView ? " active" : ""}`}>2d</div>
<div className={`toggle-option${!toggleView ? " active" : ""}`}>3d</div>
@@ -337,13 +274,7 @@ const Tools: React.FC = () => {
)}
{/* Dropdown Menu */}
{activeModule !== "visualization" && (
<button
id="drop-down-button"
title="drop-down"
className="drop-down-option-button"
ref={dropdownRef}
onClick={() => setOpenDrop(!openDrop)}
>
<button id="drop-down-button" title="drop-down" className="drop-down-option-button" ref={dropdownRef} onClick={() => setOpenDrop(!openDrop)}>
<ArrowIcon />
{openDrop && (
<div className="drop-down-container">
@@ -358,9 +289,7 @@ const Tools: React.FC = () => {
setOpenDrop(false);
}}
>
<div className="active-option">
{activeSubTool === option && <TickIcon />}
</div>
<div className="active-option">{activeSubTool === option && <TickIcon />}</div>
{getIconComponent(option)}
<div className="option">{option}</div>
</button>
@@ -376,14 +305,7 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="transform-tools">
{["move", "rotate"].map((tool) => (
<ToolButton
key={tool}
toolId={tool}
icon={getIconByTool(tool)}
tooltip={`${tool}`}
active={activeTool === tool}
onClick={() => setActiveTool(tool)}
/>
<ToolButton key={tool} toolId={tool} icon={getIconByTool(tool)} tooltip={`${tool}`} active={activeTool === tool} onClick={() => setActiveTool(tool)} />
))}
</div>
</>
@@ -396,13 +318,7 @@ const Tools: React.FC = () => {
<div className="split"></div>
<div className="general-options">
<ToolButton
toolId="comment"
icon={CommentIcon}
tooltip="comment"
active={activeTool === "comment"}
onClick={() => setActiveTool("comment")}
/>
<ToolButton toolId="comment" icon={CommentIcon} tooltip="comment" active={activeTool === "comment"} onClick={() => setActiveTool("comment")} />
{!toggleView && (
<ToolButton
toolId="play"

View File

@@ -142,11 +142,9 @@ const TreeNode = ({
<button className="control-button" title={isVisible ? "Visible" : "Hidden"} onClick={(e) => handleOptionClick(e, "visibility")}>
<EyeIcon isClosed={!isVisible} />
</button>
{isGroupNode && item.children && item.children.length > 0 && (
<button className="control-button" title="Focus" onClick={(e) => handleOptionClick(e, "focus")}>
<FocusIcon />
</button>
)}
<button className="control-button" title="Focus" onClick={(e) => handleOptionClick(e, "focus")}>
<FocusIcon />
</button>
<button className="control-button" title={isLocked ? "Locked" : "Unlocked"} onClick={(e) => handleOptionClick(e, "lock")}>
<LockIcon isLocked={isLocked} />
</button>

View File

@@ -1,4 +1,4 @@
import { Box3, Object3D, Vector3, PerspectiveCamera } from "three";
import { Box3, Object3D, Vector3, PerspectiveCamera, Sphere } from "three";
import { useCallback } from "react";
import { useSceneContext } from "../../scene/sceneContext";
@@ -15,9 +15,10 @@ export function useZoomMesh() {
if (models.length === 0) return;
const box = new Box3();
models.forEach((model) => {
for (const model of models) {
box.expandByObject(model);
});
}
const cam = camera.current;
if (!(cam instanceof PerspectiveCamera)) {
@@ -25,50 +26,29 @@ export function useZoomMesh() {
return;
}
const camPos = new Vector3();
cam.getWorldPosition(camPos);
const camDir = new Vector3(0, 0, -1).transformDirection(cam.matrixWorld);
const boxCenter = box.getCenter(new Vector3());
const boxSize = box.getSize(new Vector3());
const boundingSphere = new Sphere();
box.getBoundingSphere(boundingSphere);
const radius = boundingSphere.radius;
const fov = (cam.fov * Math.PI) / 180;
const aspect = cam.aspect;
const halfFovY = fov / 2;
const halfFovX = Math.atan(Math.tan(halfFovY) * aspect);
const camRight = new Vector3(1, 0, 0).transformDirection(cam.matrixWorld);
const camUp = new Vector3(0, 1, 0).transformDirection(cam.matrixWorld);
const distance = radius / Math.sin(fov / 2);
const distanceWithMargin = distance * 0.75;
const camDirection = new Vector3();
cam.getWorldDirection(camDirection);
const corners = [];
for (let i = 0; i < 8; i++) {
const corner = new Vector3();
corner.x = i & 1 ? box.max.x : box.min.x;
corner.y = i & 2 ? box.max.y : box.min.y;
corner.z = i & 4 ? box.max.z : box.min.z;
corners.push(corner);
const newCameraPosition = new Vector3().copy(boxCenter).sub(camDirection.multiplyScalar(distanceWithMargin));
const minDistance = Math.max(radius * 0.5, boxSize.length() * 0.1);
const currentDistance = newCameraPosition.distanceTo(boxCenter);
if (currentDistance < minDistance) {
const direction = new Vector3().subVectors(newCameraPosition, boxCenter).normalize();
newCameraPosition.copy(boxCenter).add(direction.multiplyScalar(minDistance));
}
let maxRight = 0;
let maxUp = 0;
for (const corner of corners) {
const toCorner = corner.clone().sub(boxCenter);
const projRight = Math.abs(toCorner.dot(camRight));
const projUp = Math.abs(toCorner.dot(camUp));
maxRight = Math.max(maxRight, projRight);
maxUp = Math.max(maxUp, projUp);
}
const distX = maxRight / Math.sin(halfFovX);
const distY = maxUp / Math.sin(halfFovY);
const requiredDist = Math.max(distX, distY);
const toBox = boxCenter.clone().sub(camPos);
const currentDistAlongView = toBox.dot(camDir);
if (currentDistAlongView <= 0) {
const newPos = boxCenter.clone().add(camDir.clone().multiplyScalar(requiredDist));
controls.current.setLookAt(newPos.x, newPos.y, newPos.z, boxCenter.x, boxCenter.y, boxCenter.z, true);
return;
}
const targetCamPos = boxCenter.clone().sub(camDir.clone().multiplyScalar(requiredDist));
controls.current.setLookAt(targetCamPos.x, targetCamPos.y, targetCamPos.z, boxCenter.x, boxCenter.y, boxCenter.z, true);
controls.current.setLookAt(newCameraPosition.x, newCameraPosition.y, newCameraPosition.z, boxCenter.x, boxCenter.y, boxCenter.z, true);
},
[scene, camera, controls]
);

View File

@@ -54,3 +54,13 @@ export function getAvatarColor(index: number, userId?: string): string {
// Fallback: Assign a color using the index if no userId or local storage is unavailable
return avatarColors[index % avatarColors.length];
}
export function getAvatarColorUsingUserID(userId: string): string {
// Simple deterministic color based on userId hash
let hash = 0;
for (let i = 0; i < userId.length; i++) {
hash = userId.charCodeAt(i) + ((hash << 5) - hash);
}
hash = Math.abs(hash);
return avatarColors[hash % avatarColors.length];
}

View File

@@ -0,0 +1,27 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getDashBoardBlocksApi = async (projectId: string, versionId: string) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/V1/simulation/blocks/${projectId}/${versionId}`, {
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
});
const newAccessToken = response.headers.get("x-access-token");
if (newAccessToken) {
localStorage.setItem("token", newAccessToken);
}
if (!response.ok) {
echo.error("Failed to fetch dashBoardBlocks");
}
return await response.json();
} catch {
echo.error("Failed to fetch dashBoardBlocks");
}
};

View File

@@ -0,0 +1,30 @@
import { Block } from "../../../types/exportedTypes";
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const upsetDashBoardBlocksApi = async ({ projectId, versionId, blocks }: { projectId: string; versionId: string; blocks: Block[] }) => {
try {
const response = await fetch(`${url_Backend_dwinzo}/api/V1/simulation/blocks/upsert`, {
method: "POST",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
body: JSON.stringify({ projectId, versionId, blocks }),
});
const newAccessToken = response.headers.get("x-access-token");
if (newAccessToken) {
localStorage.setItem("token", newAccessToken);
}
if (!response.ok) {
echo.error("Failed to upsert dashBoardBlocks");
}
return await response.json();
} catch {
echo.error("Failed to upsert dashBoardBlocks");
}
};

View File

@@ -9,6 +9,11 @@ interface SimulationDashboardStore {
selectedBlockId: string | null;
selectedElementId: string | null;
// Subscription management
subscribe: (callback: () => void) => () => void;
_notifySubscribers: () => void;
saveBlocks: () => void;
// Block operations
addBlock: () => void;
removeBlock: (blockId: string) => void;
@@ -39,6 +44,7 @@ interface SimulationDashboardStore {
updateElementData: (blockId: string, elementId: string, updates: Partial<DataBinding>) => void;
updateGraphData: (blockId: string, elementId: string, newData: GraphDataPoint[]) => void;
updateGraphTitle: (blockId: string, elementId: string, title: string) => void;
updateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => void;
// Selection and hover management
setSelectedBlock: (blockId: string | null) => void;
@@ -56,6 +62,8 @@ interface SimulationDashboardStore {
hasElement: (blockId: string, elementId: string) => boolean;
}
const subscribers = new Set<() => void>();
export const createSimulationDashboardStore = () => {
return create<SimulationDashboardStore>()(
immer((set, get) => ({
@@ -63,11 +71,32 @@ export const createSimulationDashboardStore = () => {
selectedBlockId: null,
selectedElementId: null,
subscribe: (callback: () => void) => {
subscribers.add(callback);
return () => {
subscribers.delete(callback);
};
},
_notifySubscribers: () => {
subscribers.forEach((callback) => {
try {
callback();
} catch (error) {
console.error("Error in store subscriber:", error);
}
});
},
saveBlocks: () => {
get()._notifySubscribers();
},
// Block operations
addBlock: () => {
set((state) => {
const newBlock: Block = {
id: MathUtils.generateUUID(),
blockUuid: MathUtils.generateUUID(),
style: {
backgroundColor: "rgba(50, 50, 50, 0.8)",
backdropFilter: "blur(10px)",
@@ -90,7 +119,7 @@ export const createSimulationDashboardStore = () => {
removeBlock: (blockId) => {
set((state) => {
state.blocks = state.blocks.filter((block) => block.id !== blockId);
state.blocks = state.blocks.filter((block) => block.blockUuid !== blockId);
if (state.selectedBlockId === blockId) {
state.selectedBlockId = null;
}
@@ -99,7 +128,7 @@ export const createSimulationDashboardStore = () => {
updateBlock: (blockId, updates) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
Object.assign(block, updates);
}
@@ -123,7 +152,7 @@ export const createSimulationDashboardStore = () => {
// Block styling and positioning
updateBlockStyle: (blockId, newStyle) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
block.style = { ...block.style, ...newStyle };
}
@@ -132,7 +161,7 @@ export const createSimulationDashboardStore = () => {
updateBlockSize: (blockId, size) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
block.size = size;
}
@@ -141,7 +170,7 @@ export const createSimulationDashboardStore = () => {
updateBlockPosition: (blockId, position) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
block.position = position;
}
@@ -150,7 +179,7 @@ export const createSimulationDashboardStore = () => {
updateBlockPositionType: (blockId, positionType) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
block.positionType = positionType;
}
@@ -159,7 +188,7 @@ export const createSimulationDashboardStore = () => {
updateBlockZIndex: (blockId, zIndex) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
block.zIndex = zIndex;
}
@@ -169,10 +198,10 @@ export const createSimulationDashboardStore = () => {
// Element operations
addElement: (blockId, type, graphType) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const newElement: UIElement = {
id: MathUtils.generateUUID(),
elementUuid: MathUtils.generateUUID(),
type: type,
graphType,
graphTitle: graphType ? `${graphType.charAt(0).toUpperCase() + graphType.slice(1)} Chart` : undefined,
@@ -226,9 +255,9 @@ export const createSimulationDashboardStore = () => {
removeElement: (blockId, elementId) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
block.elements = block.elements.filter((el) => el.id !== elementId);
block.elements = block.elements.filter((el) => el.elementUuid !== elementId);
if (state.selectedElementId === elementId) {
state.selectedElementId = null;
}
@@ -238,9 +267,9 @@ export const createSimulationDashboardStore = () => {
updateElement: (blockId, elementId, updates) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
Object.assign(element, updates);
}
@@ -251,9 +280,9 @@ export const createSimulationDashboardStore = () => {
// Element styling and positioning
updateElementStyle: (blockId, elementId, newStyle) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
element.style = { ...element.style, ...newStyle };
}
@@ -263,9 +292,9 @@ export const createSimulationDashboardStore = () => {
updateElementSize: (blockId, elementId, size) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
element.size = size;
}
@@ -275,9 +304,9 @@ export const createSimulationDashboardStore = () => {
updateElementPosition: (blockId, elementId, position) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
element.position = position;
}
@@ -287,9 +316,9 @@ export const createSimulationDashboardStore = () => {
updateElementPositionType: (blockId, elementId, positionType) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
element.positionType = positionType;
}
@@ -299,9 +328,9 @@ export const createSimulationDashboardStore = () => {
updateElementZIndex: (blockId, elementId, zIndex) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
element.zIndex = zIndex;
}
@@ -312,9 +341,9 @@ export const createSimulationDashboardStore = () => {
// Element data operations
updateElementData: (blockId, elementId, updates) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element?.data) {
element.data = { ...element.data, ...updates };
}
@@ -324,9 +353,9 @@ export const createSimulationDashboardStore = () => {
updateGraphData: (blockId, elementId, newData) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
element.graphData = newData;
}
@@ -336,9 +365,9 @@ export const createSimulationDashboardStore = () => {
updateGraphTitle: (blockId, elementId, title) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.id === elementId);
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element) {
element.graphTitle = title;
}
@@ -346,6 +375,21 @@ export const createSimulationDashboardStore = () => {
});
},
updateGraphType: (blockId, elementId, graphType) => {
set((state) => {
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
const element = block.elements.find((el) => el.elementUuid === elementId);
if (element && element.type === "graph") {
element.graphType = graphType;
element.graphTitle = `${graphType.charAt(0).toUpperCase() + graphType.slice(1)} Chart`;
element.graphData = defaultGraphData;
}
}
});
},
// Selection and hover management
setSelectedBlock: (blockId) => {
set((state) => {
@@ -366,16 +410,16 @@ export const createSimulationDashboardStore = () => {
// Element swapping
swapElements: (blockId, elementId1, elementId2) => {
set((state) => {
const block = state.blocks.find((b) => b.id === blockId);
const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) {
block.elements = block.elements.map((el) => {
if (el.id === elementId1) {
const targetElement = block.elements.find((e) => e.id === elementId2);
return targetElement ? { ...targetElement, id: elementId1 } : el;
if (el.elementUuid === elementId1) {
const targetElement = block.elements.find((e) => e.elementUuid === elementId2);
return targetElement ? { ...targetElement, elementUuid: elementId1 } : el;
}
if (el.id === elementId2) {
const sourceElement = block.elements.find((e) => e.id === elementId1);
return sourceElement ? { ...sourceElement, id: elementId2 } : el;
if (el.elementUuid === elementId2) {
const sourceElement = block.elements.find((e) => e.elementUuid === elementId1);
return sourceElement ? { ...sourceElement, elementUuid: elementId2 } : el;
}
return el;
});
@@ -385,37 +429,37 @@ export const createSimulationDashboardStore = () => {
// Helper functions
getBlockById: (blockId) => {
return get().blocks.find((b) => b.id === blockId);
return get().blocks.find((b) => b.blockUuid === blockId);
},
getElementById: (blockId, elementId) => {
const block = get().blocks.find((b) => b.id === blockId);
return block?.elements.find((el) => el.id === elementId);
const block = get().blocks.find((b) => b.blockUuid === blockId);
return block?.elements.find((el) => el.elementUuid === elementId);
},
getSelectedBlock: () => {
const { selectedBlockId, blocks } = get();
return selectedBlockId ? blocks.find((b) => b.id === selectedBlockId) : undefined;
return selectedBlockId ? blocks.find((b) => b.blockUuid === selectedBlockId) : undefined;
},
getSelectedElement: () => {
const { selectedElementId, selectedBlockId, blocks } = get();
if (!selectedElementId || !selectedBlockId) return undefined;
const block = blocks.find((b) => b.id === selectedBlockId);
return block?.elements.find((el) => el.id === selectedElementId);
const block = blocks.find((b) => b.blockUuid === selectedBlockId);
return block?.elements.find((el) => el.elementUuid === selectedElementId);
},
hasBlock: (blockId) => {
return get().blocks.some((b) => b.id === blockId);
return get().blocks.some((b) => b.blockUuid === blockId);
},
hasElement: (blockId, elementId) => {
const block = get().blocks.find((b) => b.id === blockId);
return block?.elements.some((el) => el.id === elementId) || false;
const block = get().blocks.find((b) => b.blockUuid === blockId);
return block?.elements.some((el) => el.elementUuid === elementId) || false;
},
}))
);
};
export type SimulationDashboardStoreType = ReturnType<typeof createSimulationDashboardStore>;
export type SimulationDashboardStoreType = ReturnType<typeof createSimulationDashboardStore>;

File diff suppressed because it is too large Load Diff

View File

@@ -62,7 +62,7 @@
cursor: pointer;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
// transition: all 0.3s ease;
z-index: 1;
resize: none;
overflow: hidden;

View File

@@ -6,7 +6,7 @@ export interface ExtendedCSSProperties extends CSSProperties {
}
export type Block = {
id: string;
blockUuid: string;
style: CSSProperties;
elements: UIElement[];
zIndex?: number;
@@ -16,7 +16,7 @@ export type Block = {
};
export type UIElement = {
id: string;
elementUuid: string;
type: UIType;
graphType?: GraphTypes;
graphTitle?: string;