288 lines
13 KiB
TypeScript
288 lines
13 KiB
TypeScript
import React, { useEffect, useRef, useState } from "react";
|
|
import { AddIcon, ArrowIcon, RemoveIcon, ResizeHeightIcon, } from "../../../icons/ExportCommonIcons";
|
|
import RenameInput from "../../../ui/inputs/RenameInput";
|
|
import { handleResize } from "../../../../functions/handleResizePannel";
|
|
import { useMainProduct, useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
|
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
|
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 { useEventsStore } from "../../../../store/simulation/useEventsStore";
|
|
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, useSaveVersion, } from "../../../../store/builder/store";
|
|
import { useToggleStore } from "../../../../store/useUIToggleStore";
|
|
import { useProductContext } from "../../../../modules/simulation/products/productContext";
|
|
import { useParams } from "react-router-dom";
|
|
|
|
interface Event {
|
|
modelName: string;
|
|
modelId: string;
|
|
}
|
|
|
|
interface ListProps {
|
|
val: Event;
|
|
}
|
|
|
|
const List: React.FC<ListProps> = ({ val }) => {
|
|
return (
|
|
<div className="process-container">
|
|
<div className="value">{val.modelName}</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const Simulations: React.FC = () => {
|
|
const productsContainerRef = useRef<HTMLDivElement>(null);
|
|
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent, getProductById, } = useProductStore();
|
|
const { selectedProductStore } = useProductContext();
|
|
const { selectedProduct, setSelectedProduct } = selectedProductStore();
|
|
const { getEventByModelUuid } = useEventsStore();
|
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
|
const [openObjects, setOpenObjects] = useState(true);
|
|
const [processes, setProcesses] = useState<Event[][]>();
|
|
const { setToggleUI } = useToggleStore();
|
|
const { projectId } = useParams();
|
|
const { setMainProduct } = useMainProduct();
|
|
|
|
const { comparePopUp, setComparePopUp } = useCompareStore();
|
|
const { setIsVersionSaved } = useSaveVersion();
|
|
|
|
const handleSaveVersion = () => {
|
|
setIsVersionSaved(true);
|
|
setComparePopUp(false);
|
|
setToggleUI(false, false);
|
|
};
|
|
|
|
const handleAddProduct = () => {
|
|
const id = generateUUID();
|
|
const name = `Product ${products.length + 1}`;
|
|
addProduct(name, id);
|
|
upsertProductOrEventApi({
|
|
productName: name,
|
|
productUuid: id,
|
|
projectId: projectId,
|
|
});
|
|
};
|
|
|
|
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) {
|
|
if (updatedProducts.length > 0) {
|
|
let newSelectedIndex = currentIndex;
|
|
if (currentIndex >= updatedProducts.length) {
|
|
newSelectedIndex = updatedProducts.length - 1;
|
|
}
|
|
setSelectedProduct(
|
|
updatedProducts[newSelectedIndex].productUuid,
|
|
updatedProducts[newSelectedIndex].productName
|
|
);
|
|
setMainProduct(
|
|
updatedProducts[newSelectedIndex].productUuid,
|
|
updatedProducts[newSelectedIndex].productName
|
|
);
|
|
} else {
|
|
setSelectedProduct("", "");
|
|
setMainProduct("", "");
|
|
}
|
|
}
|
|
|
|
removeProduct(productUuid);
|
|
deleteProductApi({
|
|
productUuid,
|
|
projectId
|
|
});
|
|
};
|
|
|
|
const handleRenameProduct = (productUuid: string, newName: string) => {
|
|
renameProduct(productUuid, newName);
|
|
renameProductApi({ productName: newName, productUuid, projectId: projectId || '' });
|
|
if (selectedProduct.productUuid === productUuid) {
|
|
setSelectedProduct(productUuid, newName);
|
|
setMainProduct(productUuid, newName);
|
|
}
|
|
};
|
|
|
|
const handleRemoveEventFromProduct = () => {
|
|
if (selectedAsset) {
|
|
|
|
deleteEventDataApi({
|
|
productUuid: selectedProduct.productUuid,
|
|
modelUuid: selectedAsset.modelUuid,
|
|
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);
|
|
}
|
|
);
|
|
}
|
|
|
|
}, [selectedProduct.productUuid, products]);
|
|
|
|
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={() => {
|
|
setSelectedProduct(product.productUuid, product.productName)
|
|
setMainProduct(product.productUuid, product.productName)
|
|
}}
|
|
>
|
|
<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) => (
|
|
<List key={`${index}-${event.modelName}`} val={event} />
|
|
))}
|
|
</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 || ''
|
|
});
|
|
} else {
|
|
handleRemoveEventFromProduct();
|
|
}
|
|
}}
|
|
/>
|
|
</RenderOverlay>
|
|
)}
|
|
|
|
{comparePopUp && (
|
|
<RenderOverlay>
|
|
<ComparePopUp onClose={handleSaveVersion} />
|
|
</RenderOverlay>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Simulations;
|