Files
Dwinzo_Demo/app/src/components/layout/sidebarRight/simulation/Simulations.tsx
2025-09-09 18:07:51 +05:30

275 lines
13 KiB
TypeScript

import { AddIcon, ArrowIcon, RemoveIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons";
import React, { useEffect, useRef, useState } from "react";
import RenameInput from "../../../ui/inputs/RenameInput";
import { handleResize } from "../../../../functions/handleResizePannel";
import { useSimulationState, useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
import { generateUUID } from "three/src/math/MathUtils";
import RenderOverlay from "../../../templates/Overlay";
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
import { deleteEventDataApi } from "../../../../services/simulation/products/deleteEventDataApi";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { deleteProductApi } from "../../../../services/simulation/products/deleteProductApi";
import { renameProductApi } from "../../../../services/simulation/products/renameProductApi";
import { determineExecutionMachineSequences } from "../../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
import ComparePopUp from "../../../ui/compareVersion/Compare";
import { useCompareStore, useIsComparing } from "../../../../store/builder/store";
import { useToggleStore } from "../../../../store/ui/useUIToggleStore";
import { useParams } from "react-router-dom";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
import { validateSimulationDataApi } from "../../../../services/simulation/comparison/validateSimulationDataApi";
interface Event {
modelName: string;
modelId: string;
}
const Simulations: React.FC = () => {
const productsContainerRef = useRef<HTMLDivElement>(null);
const { eventStore, productStore, versionStore } = useSceneContext();
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, getProductById, selectedProduct, setSelectedProduct } = productStore();
const { getEventByModelUuid } = eventStore();
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
const [openObjects, setOpenObjects] = useState(true);
const [processes, setProcesses] = useState<Event[][]>();
const { setToggleUI } = useToggleStore();
const { projectId } = useParams();
const { setMainState, clearMainState } = useSimulationState();
const { selectedVersion } = versionStore();
const { comparePopUp, setComparePopUp } = useCompareStore();
const { setIsComparing } = useIsComparing();
const handleSaveVersion = () => {
// setIsComparing(true);
setComparePopUp(false);
setToggleUI(false, false);
const singleData = {
projectId: projectId,
versionId: selectedVersion?.versionId || "",
productUuid: selectedProduct?.productUuid || "",
};
validateSimulationDataApi(singleData).then((getData) => {
echo.log(getData?.message);
const getSimulate = getData?.data?.existingSimulatedData;
if (!selectedVersion?.versionId || !projectId || getSimulate === undefined || !selectedProduct.productUuid) {
echo.warn("No prebacked Data found");
alert("Please run the simulation before comparing.");
return;
} else if (getSimulate) {
setToggleUI(true, true);
setIsComparing(true);
}
});
};
const handleAddProduct = () => {
const id = generateUUID();
const name = `Product ${products.length + 1}`;
addProduct(name, id);
upsertProductOrEventApi({
productName: name,
productUuid: id,
projectId: projectId,
versionId: selectedVersion?.versionId || "",
});
};
const handleRemoveProduct = (productUuid: string) => {
const currentIndex = products.findIndex((p) => p.productUuid === productUuid);
const isSelected = selectedProduct.productUuid === productUuid;
const updatedProducts = products.filter((p) => p.productUuid !== productUuid);
if (isSelected && selectedVersion) {
if (updatedProducts.length > 0) {
let newSelectedIndex = currentIndex;
if (currentIndex >= updatedProducts.length) {
newSelectedIndex = updatedProducts.length - 1;
}
setSelectedProduct(updatedProducts[newSelectedIndex].productUuid, updatedProducts[newSelectedIndex].productName);
const data = {
productUuid: updatedProducts[newSelectedIndex].productUuid,
productName: updatedProducts[newSelectedIndex].productName,
versionUuid: selectedVersion.versionId,
versionName: selectedVersion.versionName,
};
setMainState(data);
} else {
setSelectedProduct("", "");
clearMainState();
}
}
removeProduct(productUuid);
deleteProductApi({
productUuid,
versionId: selectedVersion?.versionId || "",
projectId,
});
};
const handleRenameProduct = (productUuid: string, newName: string) => {
renameProduct(productUuid, newName);
renameProductApi({ productName: newName, productUuid, projectId: projectId || "", versionId: selectedVersion?.versionId || "" });
if (selectedProduct.productUuid === productUuid && selectedVersion) {
setSelectedProduct(productUuid, newName);
const data = {
productUuid: productUuid,
productName: newName,
versionUuid: selectedVersion.versionId,
versionName: selectedVersion.versionName,
};
setMainState(data);
}
};
const handleRemoveEventFromProduct = () => {
if (selectedAsset) {
deleteEventDataApi({
productUuid: selectedProduct.productUuid,
modelUuid: selectedAsset.modelUuid,
versionId: selectedVersion?.versionId || "",
projectId: projectId,
});
removeEvent(selectedProduct.productUuid, selectedAsset.modelUuid);
clearSelectedAsset();
}
};
useEffect(() => {
const processes: Event[][] = [];
const selectedProductData = getProductById(selectedProduct.productUuid);
if (selectedProductData) {
determineExecutionMachineSequences([selectedProductData]).then((sequences) => {
sequences.forEach((sequence) => {
const events: Event[] =
sequence.map((event) => ({
modelName: event.modelName,
modelId: event.modelUuid,
})) || [];
processes.push(events);
});
setProcesses(processes);
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedProduct.productUuid, products]);
useEffect(() => {
if (comparePopUp || selectedProduct.productUuid) {
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [comparePopUp]);
return (
<div className="simulations-container">
<div className="header">Simulations</div>
<div className="add-product-container">
<div className="actions section">
<div className="header">
<div className="header-value">Products</div>
<button id="add-simulation" className="add-button" onClick={handleAddProduct}>
<AddIcon /> Add
</button>
</div>
<div className="lists-main-container" ref={productsContainerRef} style={{ height: "120px" }}>
<div className="list-container">
{products.map((product, index) => (
<div key={product.productUuid} className={`list-item ${selectedProduct.productUuid === product.productUuid ? "active" : ""}`}>
{/* eslint-disable-next-line */}
<div
className="value"
onClick={() => {
if (selectedVersion) {
setSelectedProduct(product.productUuid, product.productName);
const data = {
productUuid: product.productUuid,
productName: product.productName,
versionUuid: selectedVersion.versionId,
versionName: selectedVersion.versionName,
};
setMainState(data);
}
}}
>
<input type="radio" name="products" checked={selectedProduct.productUuid === product.productUuid} readOnly />
<RenameInput value={product.productName} onRename={(newName) => handleRenameProduct(product.productUuid, newName)} />
</div>
{products.length > 1 && (
<button id="remove-product-button" className="remove-button" onClick={() => handleRemoveProduct(product.productUuid)}>
<RemoveIcon />
</button>
)}
</div>
))}
</div>
<button className="resize-icon" id="action-resize" onMouseDown={(e: any) => handleResize(e, productsContainerRef)}>
<ResizeHeightIcon />
</button>
</div>
</div>
<div className="simulation-process section">
<button id="collapse-header" className="collapse-header-container" onClick={() => setOpenObjects(!openObjects)}>
<div className="header">Process Flow</div>
<div className="arrow-container">
<ArrowIcon />
</div>
</button>
{openObjects &&
processes?.map((process, index) => (
<section key={index}>
{process.map((event, index) => (
<div className="process-container" key={index}>
<div className="value">{event.modelName}</div>
</div>
))}
</section>
))}
</div>
<div className="compare-simulations-container">
<div className="compare-simulations-header">Need to Compare Layout?</div>
<div className="content">
Click '<span>Compare</span>' to review and analyze the layout differences between them.
</div>
<button className="input" onClick={() => setComparePopUp(true)}>
<input type="button" value={"Compare"} className="submit" />
</button>
</div>
</div>
{selectedAsset && (
<RenderOverlay>
<EditWidgetOption
options={["Add to Product", "Remove from Product"]}
onClick={(option) => {
if (option === "Add to Product") {
handleAddEventToProduct({
event: getEventByModelUuid(selectedAsset.modelUuid),
addEvent,
selectedProduct,
clearSelectedAsset,
projectId: projectId || "",
versionId: selectedVersion?.versionId || "",
});
} else {
handleRemoveEventFromProduct();
}
}}
/>
</RenderOverlay>
)}
{comparePopUp && (
<RenderOverlay>
<ComparePopUp onClose={handleSaveVersion} />
</RenderOverlay>
)}
</div>
);
};
export default Simulations;