v3 #100
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Cache } from "three";
|
import { Cache } from "three";
|
||||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
import { BrowserRouter as Router, Routes, Route, useParams } from "react-router-dom";
|
||||||
import Dashboard from "./pages/Dashboard";
|
import Dashboard from "./pages/Dashboard";
|
||||||
import Project from "./pages/Project";
|
import Project from "./pages/Project";
|
||||||
import UserAuth from "./pages/UserAuth";
|
import UserAuth from "./pages/UserAuth";
|
||||||
|
@ -14,6 +14,7 @@ const App: React.FC = () => {
|
||||||
Cache.enabled = true;
|
Cache.enabled = true;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoggerProvider>
|
<LoggerProvider>
|
||||||
<Router>
|
<Router>
|
||||||
|
|
|
@ -116,7 +116,6 @@ const DashboardHome: React.FC = () => {
|
||||||
const renderProjects = () => {
|
const renderProjects = () => {
|
||||||
const projectList = recentProjects[Object.keys(recentProjects)[0]];
|
const projectList = recentProjects[Object.keys(recentProjects)[0]];
|
||||||
|
|
||||||
console.log('projectList: ', projectList);
|
|
||||||
if (!projectList?.length) {
|
if (!projectList?.length) {
|
||||||
return <div className="empty-state">No recent projects found</div>;
|
return <div className="empty-state">No recent projects found</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1292,8 +1292,8 @@ export const PerformanceIcon = () => {
|
||||||
<path
|
<path
|
||||||
d="M11.1484 1.16797C16.2895 1.16797 20.4921 5.3714 20.4922 10.5117C20.4922 12.7821 19.6669 14.8349 18.3467 16.4316L18.1807 16.2656C19.3378 14.8012 20.1179 12.9631 20.2236 10.9746L20.2354 10.5107C20.2364 9.46665 20.0573 8.43143 19.707 7.4502L19.5469 7.03223C19.1476 6.06682 18.5848 5.17876 17.8848 4.40625L17.5771 4.08301C16.733 3.23884 15.7302 2.56951 14.627 2.11328C13.524 1.65716 12.342 1.42257 11.1484 1.42383C10.1041 1.42277 9.06837 1.60175 8.08691 1.95215L7.66992 2.11328C6.70451 2.51257 5.81644 3.07536 5.04395 3.77539L4.71973 4.08398C3.98113 4.8228 3.37584 5.68237 2.93066 6.625L2.75 7.03418C2.3509 7.99977 2.12214 9.02598 2.07227 10.0674L2.06152 10.5127C2.06152 12.7338 2.80096 14.7019 4.10059 16.2803L3.93652 16.4443C2.58335 14.8587 1.80469 12.8058 1.80469 10.5117C1.80479 5.37146 6.00742 1.16807 11.1484 1.16797ZM10.8008 11.2383L10.3887 10.8076L13.8027 7.81543L10.8008 11.2383Z"
|
d="M11.1484 1.16797C16.2895 1.16797 20.4921 5.3714 20.4922 10.5117C20.4922 12.7821 19.6669 14.8349 18.3467 16.4316L18.1807 16.2656C19.3378 14.8012 20.1179 12.9631 20.2236 10.9746L20.2354 10.5107C20.2364 9.46665 20.0573 8.43143 19.707 7.4502L19.5469 7.03223C19.1476 6.06682 18.5848 5.17876 17.8848 4.40625L17.5771 4.08301C16.733 3.23884 15.7302 2.56951 14.627 2.11328C13.524 1.65716 12.342 1.42257 11.1484 1.42383C10.1041 1.42277 9.06837 1.60175 8.08691 1.95215L7.66992 2.11328C6.70451 2.51257 5.81644 3.07536 5.04395 3.77539L4.71973 4.08398C3.98113 4.8228 3.37584 5.68237 2.93066 6.625L2.75 7.03418C2.3509 7.99977 2.12214 9.02598 2.07227 10.0674L2.06152 10.5127C2.06152 12.7338 2.80096 14.7019 4.10059 16.2803L3.93652 16.4443C2.58335 14.8587 1.80469 12.8058 1.80469 10.5117C1.80479 5.37146 6.00742 1.16807 11.1484 1.16797ZM10.8008 11.2383L10.3887 10.8076L13.8027 7.81543L10.8008 11.2383Z"
|
||||||
stroke="url(#paint0_linear_1736_988)"
|
stroke="url(#paint0_linear_1736_988)"
|
||||||
stroke-width="1.80917"
|
strokeWidth="1.80917"
|
||||||
stroke-linecap="round"
|
strokeLinecap="round"
|
||||||
/>
|
/>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
|
@ -1304,8 +1304,8 @@ export const PerformanceIcon = () => {
|
||||||
y2="17.742"
|
y2="17.742"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="#6F42C1" />
|
<stop stopColor="#6F42C1" />
|
||||||
<stop offset="1" stop-color="#B392F0" />
|
<stop offset="1" stopColor="#B392F0" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -1328,9 +1328,9 @@ export const GreenTickIcon = () => {
|
||||||
<path
|
<path
|
||||||
d="M4.85742 7.20505L6.91318 9.25578L10.3394 5.83789"
|
d="M4.85742 7.20505L6.91318 9.25578L10.3394 5.83789"
|
||||||
stroke="white"
|
stroke="white"
|
||||||
stroke-width="2.45534"
|
strokeWidth="2.45534"
|
||||||
stroke-linecap="round"
|
strokeLinecap="round"
|
||||||
stroke-linejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { useProductContext } from '../../../modules/simulation/products/productContext'
|
import { useProductContext } from '../../../modules/simulation/products/productContext'
|
||||||
import RegularDropDown from '../../ui/inputs/RegularDropDown';
|
import RegularDropDown from '../../ui/inputs/RegularDropDown';
|
||||||
import { useProductStore } from '../../../store/simulation/useProductStore';
|
import { useProductStore } from '../../../store/simulation/useProductStore';
|
||||||
import { useLoadingProgress, useSaveVersion } from '../../../store/builder/store';
|
import { useCompareProductDataStore, useLoadingProgress, useSaveVersion } from '../../../store/builder/store';
|
||||||
import useModuleStore from '../../../store/useModuleStore';
|
import useModuleStore from '../../../store/useModuleStore';
|
||||||
import CompareLayOut from '../../ui/compareVersion/CompareLayOut';
|
import CompareLayOut from '../../ui/compareVersion/CompareLayOut';
|
||||||
import ComparisonResult from '../../ui/compareVersion/ComparisonResult';
|
import ComparisonResult from '../../ui/compareVersion/ComparisonResult';
|
||||||
import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore';
|
import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore';
|
||||||
import { usePauseButtonStore, usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
function ComparisonScene() {
|
function ComparisonScene() {
|
||||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||||
|
@ -17,16 +18,63 @@ function ComparisonScene() {
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
|
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
|
||||||
const { mainProduct } = useMainProduct();
|
const { mainProduct } = useMainProduct();
|
||||||
const { setIsPaused } = usePauseButtonStore();
|
|
||||||
const { loadingProgress } = useLoadingProgress();
|
const { loadingProgress } = useLoadingProgress();
|
||||||
|
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
|
||||||
|
const [shouldShowComparisonResult, setShouldShowComparisonResult] = useState(false);
|
||||||
|
|
||||||
const handleSelectLayout = (option: string) => {
|
const handleSelectLayout = (option: string) => {
|
||||||
const product = products.find((product) => product.productName === option);
|
const product = products.find((product) => product.productName === option);
|
||||||
if (product) {
|
if (product) {
|
||||||
setComparisonProduct(product.productUuid, product.productName);
|
setComparisonProduct(product.productUuid, product.productName);
|
||||||
setIsPaused(true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// useEffect(() => {
|
||||||
|
// setCompareProductsData([
|
||||||
|
// {
|
||||||
|
// "productUuid": "15193386-ec58-4ec6-8a92-e665a39eebf1",
|
||||||
|
// "productName": "Product 1",
|
||||||
|
// "simulationData": {
|
||||||
|
// "roiPercentage": 273.9428571428571,
|
||||||
|
// "paybackPeriod": 1.8251981643721318,
|
||||||
|
// "netProfit": 9588000,
|
||||||
|
// "productionCapacity": 4508.5,
|
||||||
|
// "machineIdleTime": 1450,
|
||||||
|
// "machineActiveTime": 430,
|
||||||
|
// "throughputData": 180.34
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "productUuid": "f614bf50-f61d-41c5-acc0-3783fb4da6b8",
|
||||||
|
// "productName": "Product 2",
|
||||||
|
// "simulationData": {
|
||||||
|
// "roiPercentage": 281.7214285714286,
|
||||||
|
// "paybackPeriod": 1.7748028701097842,
|
||||||
|
// "netProfit": 9860250,
|
||||||
|
// "productionCapacity": 4599.25,
|
||||||
|
// "machineIdleTime": 1885,
|
||||||
|
// "machineActiveTime": 646,
|
||||||
|
// "throughputData": 183.97
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ])
|
||||||
|
// }, []); // ✅ Runs only once on mount
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (mainProduct && comparisonProduct && compareProductsData.length > 1) {
|
||||||
|
// console.log('compareProductsData: ', compareProductsData);
|
||||||
|
const hasMain = compareProductsData.some(val => val.productUuid === mainProduct.productUuid);
|
||||||
|
const hasComparison = compareProductsData.some(val => val.productUuid === comparisonProduct.productUuid);
|
||||||
|
if (hasMain && hasComparison && mainProduct.productUuid !== comparisonProduct.productUuid) {
|
||||||
|
setShouldShowComparisonResult(true);
|
||||||
|
} else {
|
||||||
|
setShouldShowComparisonResult(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setShouldShowComparisonResult(false);
|
||||||
|
}
|
||||||
|
}, [compareProductsData, mainProduct, comparisonProduct]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isVersionSaved && activeModule === "simulation" && selectedProduct && (
|
{isVersionSaved && activeModule === "simulation" && selectedProduct && (
|
||||||
|
@ -42,7 +90,8 @@ function ComparisonScene() {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<CompareLayOut />
|
<CompareLayOut />
|
||||||
{(comparisonProduct && mainProduct && !loadingProgress) && <ComparisonResult />}
|
|
||||||
|
{(shouldShowComparisonResult && !loadingProgress) && <ComparisonResult />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
useLoadingProgress,
|
useLoadingProgress,
|
||||||
useRenameModeStore,
|
useRenameModeStore,
|
||||||
|
@ -42,7 +42,7 @@ function MainScene() {
|
||||||
const { setMainProduct } = useMainProduct();
|
const { setMainProduct } = useMainProduct();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
const { selectedProduct } = selectedProductStore();
|
const { selectedProduct } = selectedProductStore();
|
||||||
const { isVersionSaved } = useSaveVersion();
|
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { selectedUser } = useSelectedUserStore();
|
const { selectedUser } = useSelectedUserStore();
|
||||||
const { loadingProgress } = useLoadingProgress();
|
const { loadingProgress } = useLoadingProgress();
|
||||||
|
@ -52,11 +52,19 @@ function MainScene() {
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
const { selectedZone } = useSelectedZoneStore();
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
const { setFloatingWidget } = useFloatingWidget();
|
const { setFloatingWidget } = useFloatingWidget();
|
||||||
const { comparisonProduct } = useComparisonProduct();
|
const { clearComparisonProduct } = useComparisonProduct();
|
||||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
const { setName } = useAssetsStore();
|
const { setName } = useAssetsStore();
|
||||||
const { projectId } = useParams()
|
const { projectId } = useParams()
|
||||||
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeModule !== 'simulation') {
|
||||||
|
clearComparisonProduct();
|
||||||
|
setIsVersionSaved(false);
|
||||||
|
}
|
||||||
|
}, [activeModule])
|
||||||
|
|
||||||
const handleSelectLayout = (option: string) => {
|
const handleSelectLayout = (option: string) => {
|
||||||
const product = products.find((product) => product.productName === option);
|
const product = products.find((product) => product.productName === option);
|
||||||
if (product) {
|
if (product) {
|
||||||
|
@ -64,6 +72,7 @@ function MainScene() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleObjectRename = async (newName: string) => {
|
const handleObjectRename = async (newName: string) => {
|
||||||
|
if (!projectId) return
|
||||||
const email = localStorage.getItem("email") ?? "";
|
const email = localStorage.getItem("email") ?? "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
let response = await setFloorItemApi(
|
let response = await setFloorItemApi(
|
||||||
|
@ -99,10 +108,10 @@ function MainScene() {
|
||||||
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
|
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
|
||||||
<Tools />
|
<Tools />
|
||||||
)}
|
)}
|
||||||
{(isPlaying || comparisonProduct !== null) &&
|
{(isPlaying) &&
|
||||||
activeModule === "simulation" &&
|
activeModule === "simulation" &&
|
||||||
loadingProgress == 0 && <SimulationPlayer />}
|
loadingProgress == 0 && <SimulationPlayer />}
|
||||||
{(isPlaying || comparisonProduct !== null) &&
|
{(isPlaying) &&
|
||||||
activeModule !== "simulation" && <ControlsPlayer />}
|
activeModule !== "simulation" && <ControlsPlayer />}
|
||||||
|
|
||||||
{isRenameMode && selectedFloorItem?.userData.modelName && <RenameTooltip name={selectedFloorItem?.userData.modelName} onSubmit={handleObjectRename} />}
|
{isRenameMode && selectedFloorItem?.userData.modelName && <RenameTooltip name={selectedFloorItem?.userData.modelName} onSubmit={handleObjectRename} />}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { AIIcon } from "../../../icons/ExportCommonIcons";
|
import { AIIcon } from "../../../icons/ExportCommonIcons";
|
||||||
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
||||||
import { AnalysisPresetsType } from "../../../../types/analysis";
|
import { AnalysisPresetsType } from "../../../../types/analysis";
|
||||||
|
@ -19,55 +19,70 @@ const Analysis: React.FC = () => {
|
||||||
// { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } },
|
// { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } },
|
||||||
],
|
],
|
||||||
"Production capacity": [
|
"Production capacity": [
|
||||||
{ type: "range", inputs: { label: "Shift length", activeOption: "hr" } },
|
{ type: "range", inputs: { label: "Shift length", activeOption: "hr", defaultValue: 1 } },
|
||||||
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } },
|
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit", defaultValue: 3 } },
|
||||||
{ type: "default", inputs: { label: "Working days / year", activeOption: "days" } },
|
{ type: "default", inputs: { label: "Working days / year", activeOption: "days", defaultValue: 300 } },
|
||||||
{ type: "default", inputs: { label: "Yield rate", activeOption: "%" } },
|
{ type: "default", inputs: { label: "Yield rate", activeOption: "%", defaultValue: 98 } },
|
||||||
],
|
],
|
||||||
ROI: [
|
ROI: [
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Selling price", activeOption: "INR" },
|
inputs: { label: "Selling price", activeOption: "INR", defaultValue: 500 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Material cost", activeOption: "INR" },
|
inputs: { label: "Material cost", activeOption: "INR", defaultValue: 300 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Labor Cost", activeOption: "INR" },
|
inputs: { label: "Labor Cost", activeOption: "INR", defaultValue: 150 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Maintenance cost", activeOption: "INR" },
|
inputs: { label: "Labor Count", activeOption: "", defaultValue: 1 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Electricity cost", activeOption: "INR" },
|
inputs: { label: "Maintenance cost", activeOption: "INR", defaultValue: 1200 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Fixed costs", activeOption: "INR" },
|
inputs: { label: "Electricity cost", activeOption: "INR", defaultValue: 840 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Initial Investment", activeOption: "INR" },
|
inputs: { label: "Fixed costs", activeOption: "INR", defaultValue: 1150 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Salvage value", activeOption: "Hrs" },
|
inputs: { label: "Initial Investment", activeOption: "INR", defaultValue: 3500000 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Production period", activeOption: "yrs" },
|
inputs: { label: "Salvage value", activeOption: "Day", defaultValue: 565 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Tax rate", activeOption: "%" },
|
inputs: { label: "Production period", activeOption: "yrs", defaultValue: 5 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "default",
|
||||||
|
inputs: { label: "Tax rate", activeOption: "%", defaultValue: 30 },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Object.values(AnalysisPresets).forEach((category) => {
|
||||||
|
category.forEach((item) => {
|
||||||
|
const { label, defaultValue } = item.inputs;
|
||||||
|
if (defaultValue !== undefined) {
|
||||||
|
updateInputValue(label, defaultValue.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const { inputValues, setInputValues, updateInputValue } = useInputValues();
|
const { inputValues, setInputValues, updateInputValue } = useInputValues();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -10,7 +10,8 @@ interface InputRendererProps {
|
||||||
onInputChange: (label: string, value: string) => void;
|
onInputChange: (label: string, value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,inputValues, onInputChange }) => {
|
const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets, inputValues, onInputChange }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`main-${keyName}`} className="analysis-inputs">
|
<div key={`main-${keyName}`} className="analysis-inputs">
|
||||||
{presets.map((preset, index) => {
|
{presets.map((preset, index) => {
|
||||||
|
@ -19,7 +20,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
key={index}
|
key={index}
|
||||||
label={preset.inputs.label}
|
label={preset.inputs.label}
|
||||||
value={inputValues[preset.inputs.label] || ""}
|
value={preset.inputs.defaultValue?.toString() || inputValues[preset.inputs.label] || ""}
|
||||||
activeOption={preset.inputs.activeOption}
|
activeOption={preset.inputs.activeOption}
|
||||||
onChange={(newValue) => onInputChange(preset.inputs.label, newValue)}
|
onChange={(newValue) => onInputChange(preset.inputs.label, newValue)}
|
||||||
/>
|
/>
|
||||||
|
@ -32,7 +33,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
|
||||||
label={preset.inputs.label}
|
label={preset.inputs.label}
|
||||||
min={0}
|
min={0}
|
||||||
max={8}
|
max={8}
|
||||||
value={5}
|
value={Number(preset.inputs.defaultValue) || Number(inputValues[preset.inputs.label]) || 5}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from "react";
|
||||||
import { AddIcon, ArrowIcon, RemoveIcon, ResizeHeightIcon, } from "../../../icons/ExportCommonIcons";
|
import { AddIcon, ArrowIcon, RemoveIcon, ResizeHeightIcon, } from "../../../icons/ExportCommonIcons";
|
||||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||||
import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
|
import { useMainProduct, useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||||
import { generateUUID } from "three/src/math/MathUtils";
|
import { generateUUID } from "three/src/math/MathUtils";
|
||||||
import RenderOverlay from "../../../templates/Overlay";
|
import RenderOverlay from "../../../templates/Overlay";
|
||||||
|
@ -48,6 +48,7 @@ const Simulations: React.FC = () => {
|
||||||
const [processes, setProcesses] = useState<Event[][]>();
|
const [processes, setProcesses] = useState<Event[][]>();
|
||||||
const { setToggleUI } = useToggleStore();
|
const { setToggleUI } = useToggleStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
|
const { setMainProduct } = useMainProduct();
|
||||||
|
|
||||||
const { comparePopUp, setComparePopUp } = useCompareStore();
|
const { comparePopUp, setComparePopUp } = useCompareStore();
|
||||||
const { setIsVersionSaved } = useSaveVersion();
|
const { setIsVersionSaved } = useSaveVersion();
|
||||||
|
@ -85,8 +86,13 @@ const Simulations: React.FC = () => {
|
||||||
updatedProducts[newSelectedIndex].productUuid,
|
updatedProducts[newSelectedIndex].productUuid,
|
||||||
updatedProducts[newSelectedIndex].productName
|
updatedProducts[newSelectedIndex].productName
|
||||||
);
|
);
|
||||||
|
setMainProduct(
|
||||||
|
updatedProducts[newSelectedIndex].productUuid,
|
||||||
|
updatedProducts[newSelectedIndex].productName
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
setSelectedProduct("", "");
|
setSelectedProduct("", "");
|
||||||
|
setMainProduct("", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +108,7 @@ const Simulations: React.FC = () => {
|
||||||
renameProductApi({ productName: newName, productUuid, projectId: projectId || '' });
|
renameProductApi({ productName: newName, productUuid, projectId: projectId || '' });
|
||||||
if (selectedProduct.productUuid === productUuid) {
|
if (selectedProduct.productUuid === productUuid) {
|
||||||
setSelectedProduct(productUuid, newName);
|
setSelectedProduct(productUuid, newName);
|
||||||
|
setMainProduct(productUuid, newName);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,9 +179,10 @@ const Simulations: React.FC = () => {
|
||||||
{/* eslint-disable-next-line */}
|
{/* eslint-disable-next-line */}
|
||||||
<div
|
<div
|
||||||
className="value"
|
className="value"
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
setSelectedProduct(product.productUuid, product.productName)
|
setSelectedProduct(product.productUuid, product.productName)
|
||||||
}
|
setMainProduct(product.productUuid, product.productName)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
|
|
|
@ -26,6 +26,8 @@ const ThroughputSummary: React.FC = () => {
|
||||||
unit: "KWH",
|
unit: "KWH",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Dynamic shift data
|
// Dynamic shift data
|
||||||
const shiftUtilization = [
|
const shiftUtilization = [
|
||||||
{ shift: 1, percentage: 30, color: "#F3C64D" },
|
{ shift: 1, percentage: 30, color: "#F3C64D" },
|
||||||
|
@ -126,7 +128,7 @@ const ThroughputSummary: React.FC = () => {
|
||||||
<div className="process-container">
|
<div className="process-container">
|
||||||
<div className="throughput-value">
|
<div className="throughput-value">
|
||||||
<span className="value">{productionCapacityData}</span>{" "}
|
<span className="value">{productionCapacityData}</span>{" "}
|
||||||
Units/hour
|
Units/Month
|
||||||
</div>
|
</div>
|
||||||
<div className="lineChart">
|
<div className="lineChart">
|
||||||
<div className="assetUsage">
|
<div className="assetUsage">
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
import SemiCircleProgress from "./SemiCircleProgress";
|
import SemiCircleProgress from "./SemiCircleProgress";
|
||||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||||
import SkeletonUI from "../../templates/SkeletonUI";
|
import SkeletonUI from "../../templates/SkeletonUI";
|
||||||
import { useROISummaryData } from "../../../store/builder/store";
|
import { useInputValues, useROISummaryData } from "../../../store/builder/store";
|
||||||
|
|
||||||
const ROISummary = ({
|
const ROISummary = ({
|
||||||
roiSummaryData = {
|
roiSummaryData = {
|
||||||
|
@ -67,6 +67,8 @@ const ROISummary = ({
|
||||||
},
|
},
|
||||||
}) => {
|
}) => {
|
||||||
const [isTableOpen, setIsTableOpen] = useState(false); // State to handle the table open/close
|
const [isTableOpen, setIsTableOpen] = useState(false); // State to handle the table open/close
|
||||||
|
const { inputValues } = useInputValues();
|
||||||
|
const productionPeriod = parseFloat(inputValues["Production period"]);
|
||||||
|
|
||||||
// Function to toggle the breakdown table visibility
|
// Function to toggle the breakdown table visibility
|
||||||
const toggleTable = () => {
|
const toggleTable = () => {
|
||||||
|
@ -95,6 +97,17 @@ const ROISummary = ({
|
||||||
}
|
}
|
||||||
}, [roiSummary]);
|
}, [roiSummary]);
|
||||||
|
|
||||||
|
function getPaybackDateFromYears(yearsToAdd: number) {
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
const totalMonths = Math.round(yearsToAdd * 12);
|
||||||
|
|
||||||
|
const paybackDate = new Date(now.getFullYear(), now.getMonth() + totalMonths, now.getDate());
|
||||||
|
const month = paybackDate.toLocaleString("en-GB", { month: "long" });
|
||||||
|
const year = paybackDate.getFullYear();
|
||||||
|
return `${month} ${year}`;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
@ -121,25 +134,30 @@ const ROISummary = ({
|
||||||
<SonarCrownIcon />
|
<SonarCrownIcon />
|
||||||
<div className="icon"></div>
|
<div className="icon"></div>
|
||||||
<div className="info">
|
<div className="info">
|
||||||
<span> {roiSummary.roiPercentage}%</span> ROI with payback
|
<span>{roiSummary.roiPercentage.toFixed(2)}% </span>
|
||||||
in just <span>{roiSummary.paybackPeriod}</span> months
|
ROI in the period of {productionPeriod} years
|
||||||
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="roi-details">
|
<div className="roi-details">
|
||||||
<div className="progress-wrapper">
|
<div className="progress-wrapper">
|
||||||
<SemiCircleProgress />
|
<SemiCircleProgress
|
||||||
|
progress={(parseFloat(roiSummary.paybackPeriod.toFixed(2)) / (productionPeriod)) * 100}
|
||||||
|
years={parseFloat(roiSummary.paybackPeriod.toFixed(2))}
|
||||||
|
/>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
you're on track to hit it by
|
you're on track to hit it by
|
||||||
<div className="key">July 2029</div>
|
<div className="key">{getPaybackDateFromYears(roiSummary.paybackPeriod)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="metrics">
|
<div className="metrics">
|
||||||
<div className="metric-wrapper">
|
<div className="metric-wrapper">
|
||||||
<div className="metric-item">
|
<div className="metric-item">
|
||||||
<span className="metric-label">Total Cost Incurred</span>
|
<span className="metric-label">Total Cost Incurred</span>
|
||||||
<span className="metric-value">
|
<span className="metric-value">
|
||||||
<span>₹</span>
|
<span>₹</span>
|
||||||
{roiSummary.totalCost}
|
{roiSummary.totalCost.toFixed(0)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="metric-item">
|
<div className="metric-item">
|
||||||
|
@ -147,7 +165,7 @@ const ROISummary = ({
|
||||||
<span className="metric-value">
|
<span className="metric-value">
|
||||||
<span>₹</span>
|
<span>₹</span>
|
||||||
|
|
||||||
{roiSummary.revenueGenerated}
|
{roiSummary.revenueGenerated.toFixed(0)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -161,8 +179,8 @@ const ROISummary = ({
|
||||||
<div className="metric-value">
|
<div className="metric-value">
|
||||||
<span>₹</span>
|
<span>₹</span>
|
||||||
{roiSummary.netProfit > 0
|
{roiSummary.netProfit > 0
|
||||||
? roiSummary.netProfit
|
? roiSummary.netProfit.toFixed(0)
|
||||||
: roiSummary.netLoss}
|
: roiSummary.netLoss.toFixed(0)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useMachineCount, useMachineUptime, useMaterialCycle, useProductionCapacityData, useThroughPutData } from "../../../store/builder/store";
|
import { useInputValues, useMachineCount, useMachineUptime, useMaterialCycle, useProductionCapacityData, useThroughPutData } from "../../../store/builder/store";
|
||||||
import {
|
import {
|
||||||
ThroughputSummaryIcon,
|
ThroughputSummaryIcon,
|
||||||
} from "../../icons/analysis";
|
} from "../../icons/analysis";
|
||||||
|
@ -14,14 +14,15 @@ const ProductionCapacity = ({
|
||||||
const { machineActiveTime } = useMachineUptime();
|
const { machineActiveTime } = useMachineUptime();
|
||||||
const { materialCycleTime } = useMaterialCycle();
|
const { materialCycleTime } = useMaterialCycle();
|
||||||
const { throughputData } = useThroughPutData()
|
const { throughputData } = useThroughPutData()
|
||||||
|
const { inputValues } = useInputValues();
|
||||||
|
|
||||||
const progressPercent = machineActiveTime;
|
const progressPercent = machineActiveTime;
|
||||||
|
|
||||||
|
const shiftLength = parseFloat(inputValues["Shift length"]);
|
||||||
|
|
||||||
const totalBars = 6;
|
const totalBars = 6;
|
||||||
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
|
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
|
||||||
const partialFillPercent =
|
const partialFillPercent = ((progressPercent / 1000) * totalBars - barsToFill) * 100;
|
||||||
((progressPercent / 100) * totalBars - barsToFill) * 100;
|
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
@ -29,13 +30,14 @@ const ProductionCapacity = ({
|
||||||
if (throughputData > 0) {
|
if (throughputData > 0) {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} else {
|
} else {
|
||||||
setIsLoading(true);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [throughputData])
|
}, [throughputData])
|
||||||
|
|
||||||
|
const Units_per_hour = ((shiftLength * 60) / (materialCycleTime / 60) / shiftLength)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
{!isLoading && <div className="throughtputSummary-container analysis-card">
|
{!isLoading && <div className="throughtputSummary-container analysis-card">
|
||||||
<div className="throughtputSummary-wrapper analysis-card-wrapper">
|
<div className="throughtputSummary-wrapper analysis-card-wrapper">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
|
@ -53,8 +55,7 @@ const ProductionCapacity = ({
|
||||||
<>
|
<>
|
||||||
<div className="process-container">
|
<div className="process-container">
|
||||||
<div className="throughput-value">
|
<div className="throughput-value">
|
||||||
<span className="value">{throughputData}</span> Units/hour
|
<span className="value">{(Units_per_hour).toFixed(2) === "Infinity"? 0 : (Units_per_hour).toFixed(2) }</span> Units/hour
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Dynamic Progress Bar */}
|
{/* Dynamic Progress Bar */}
|
||||||
|
|
|
@ -118,7 +118,6 @@ const CompareLayOut = () => {
|
||||||
if (product) {
|
if (product) {
|
||||||
setComparisonProduct(product.productUuid, product.productName);
|
setComparisonProduct(product.productUuid, product.productName);
|
||||||
setLoadingProgress(1);
|
setLoadingProgress(1);
|
||||||
setIsPaused(true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,41 @@
|
||||||
import React, { useMemo } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import PerformanceResult from "./result-card/PerformanceResult";
|
import PerformanceResult from "./result-card/PerformanceResult";
|
||||||
import EnergyUsage from "./result-card/EnergyUsage";
|
import EnergyUsage from "./result-card/EnergyUsage";
|
||||||
import { Bar, Line, Pie } from "react-chartjs-2";
|
import { Bar, Line, Pie } from "react-chartjs-2";
|
||||||
|
import { CompareProduct, useCompareProductDataStore } from "../../../store/builder/store";
|
||||||
|
import { useComparisonProduct, useMainProduct } from "../../../store/simulation/useSimulationStore";
|
||||||
|
|
||||||
const ComparisonResult = () => {
|
const ComparisonResult = () => {
|
||||||
|
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
|
||||||
|
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
|
||||||
|
const { mainProduct } = useMainProduct();
|
||||||
|
const [comparedProducts, setComparedProducts] = useState<[CompareProduct, CompareProduct] | []>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (compareProductsData.length > 0 && mainProduct && comparisonProduct) {
|
||||||
|
const mainProductData = compareProductsData.find(
|
||||||
|
(product) => product.productUuid === mainProduct.productUuid
|
||||||
|
);
|
||||||
|
const comparisonProductData = compareProductsData.find(
|
||||||
|
(product) => product.productUuid === comparisonProduct.productUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mainProductData && comparisonProductData) {
|
||||||
|
setComparedProducts([mainProductData, comparisonProductData]);
|
||||||
|
} else {
|
||||||
|
setComparedProducts([]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setComparedProducts([]);
|
||||||
|
}
|
||||||
|
}, [compareProductsData, mainProduct, comparisonProduct]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (comparedProducts.length === 2) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [comparedProducts]);
|
||||||
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
responsive: true,
|
responsive: true,
|
||||||
|
@ -25,11 +57,11 @@ const ComparisonResult = () => {
|
||||||
const purpleLight = "#b19cd9";
|
const purpleLight = "#b19cd9";
|
||||||
|
|
||||||
const throughputData = {
|
const throughputData = {
|
||||||
labels: ["Layout 1", "Layout 2"],
|
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Throughput (units/hr)",
|
label: "Throughput (units/hr)",
|
||||||
data: [500, 550],
|
data: [comparedProducts[0]?.simulationData.throughputData, comparedProducts[1]?.simulationData.throughputData],
|
||||||
backgroundColor: [purpleDark, purpleLight],
|
backgroundColor: [purpleDark, purpleLight],
|
||||||
borderColor: [purpleDark, purpleLight],
|
borderColor: [purpleDark, purpleLight],
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
|
@ -41,11 +73,11 @@ const ComparisonResult = () => {
|
||||||
|
|
||||||
|
|
||||||
const cycleTimePieData = {
|
const cycleTimePieData = {
|
||||||
labels: ["Layout 1", "Layout 2"],
|
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Cycle Time (sec)",
|
label: "Cycle Time (sec)",
|
||||||
data: [120, 110],
|
data: [comparedProducts[0]?.simulationData.machineActiveTime, comparedProducts[1]?.simulationData.machineActiveTime],
|
||||||
backgroundColor: [purpleDark, purpleLight],
|
backgroundColor: [purpleDark, purpleLight],
|
||||||
borderColor: "#fff",
|
borderColor: "#fff",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
|
@ -54,11 +86,24 @@ const ComparisonResult = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const downtimeData = {
|
const downtimeData = {
|
||||||
labels: ["Layout 1", "Layout 2"],
|
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Downtime (mins)",
|
label: "Downtime (mins)",
|
||||||
data: [17, 12],
|
data: [comparedProducts[0]?.simulationData.machineIdleTime, comparedProducts[1]?.simulationData.machineIdleTime],
|
||||||
|
backgroundColor: [purpleDark, purpleLight],
|
||||||
|
borderColor: "#fff",
|
||||||
|
borderWidth: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const productionCapacityData = {
|
||||||
|
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "Production Capacity (units)",
|
||||||
|
data: [comparedProducts[0]?.simulationData.productionCapacity, comparedProducts[1]?.simulationData.productionCapacity],
|
||||||
backgroundColor: [purpleDark, purpleLight],
|
backgroundColor: [purpleDark, purpleLight],
|
||||||
borderColor: [purpleDark, purpleLight],
|
borderColor: [purpleDark, purpleLight],
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
|
@ -68,20 +113,21 @@ const ComparisonResult = () => {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const scrapRateData = {
|
const highestProductivityProduct = (comparedProducts[0]?.simulationData?.productionCapacity ?? 0) > (comparedProducts[1]?.simulationData?.productionCapacity ?? 0) ? comparedProducts[0] : comparedProducts[1];
|
||||||
labels: ["Layout 1", "Layout 2"],
|
|
||||||
datasets: [
|
const product1CyclePercentage = (comparedProducts[0]?.simulationData?.machineActiveTime ?? 0) /
|
||||||
{
|
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) +
|
||||||
label: "Scrap Rate (tons)",
|
(compareProductsData[0]?.simulationData?.machineIdleTime ?? 0)) * 100;
|
||||||
data: [2.7, 1.9],
|
const product2CyclePercentage = ((comparedProducts[1]?.simulationData?.machineActiveTime ?? 0) /
|
||||||
backgroundColor: [purpleDark, purpleLight],
|
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) +
|
||||||
borderColor: [purpleDark, purpleLight],
|
(compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
||||||
borderWidth: 1,
|
|
||||||
borderRadius: 10,
|
const product1IdlePercentage = (comparedProducts[0]?.simulationData?.machineIdleTime ?? 0) /
|
||||||
borderSkipped: false,
|
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) +
|
||||||
},
|
(compareProductsData[0]?.simulationData?.machineIdleTime ?? 0)) * 100;
|
||||||
],
|
const product2IdlePercentage = ((comparedProducts[1]?.simulationData?.machineIdleTime ?? 0) /
|
||||||
};
|
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) +
|
||||||
|
(compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="compare-result-container">
|
<div className="compare-result-container">
|
||||||
|
@ -92,12 +138,12 @@ const ComparisonResult = () => {
|
||||||
<h4>Throughput (units/hr)</h4>
|
<h4>Throughput (units/hr)</h4>
|
||||||
<div className="layers-wrapper">
|
<div className="layers-wrapper">
|
||||||
<div className="layer-wrapper">
|
<div className="layer-wrapper">
|
||||||
<div className="key">Layout 1</div>
|
<div className="key">{comparedProducts[0]?.productName}</div>
|
||||||
<div className="value">500/ hr</div>
|
<div className="value">{comparedProducts[0]?.simulationData.throughputData}/ hr</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="layer-wrapper">
|
<div className="layer-wrapper">
|
||||||
<div className="key">Layout 2</div>
|
<div className="key">{comparedProducts[1]?.productName}</div>
|
||||||
<div className="value">550/ hr</div>
|
<div className="value">{comparedProducts[1]?.simulationData.throughputData}/ hr</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="chart">
|
<div className="chart">
|
||||||
<Bar data={throughputData} options={options} />
|
<Bar data={throughputData} options={options} />
|
||||||
|
@ -110,17 +156,17 @@ const ComparisonResult = () => {
|
||||||
<div className="cycle-header">Cycle Time</div>
|
<div className="cycle-header">Cycle Time</div>
|
||||||
<div className="layers-wrapper">
|
<div className="layers-wrapper">
|
||||||
<div className="layers">
|
<div className="layers">
|
||||||
<div className="layer-name">Layout 1</div>
|
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
||||||
<div className="layer-time">120 Sec</div>
|
<div className="layer-time">{compareProductsData[0]?.simulationData.machineActiveTime} Sec</div>
|
||||||
<div className="layer-profit">
|
<div className="layer-profit">
|
||||||
<span>↑</span>19.6%
|
<span>↑</span>{(100 - product1CyclePercentage).toFixed(2)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="layers">
|
<div className="layers">
|
||||||
<div className="layer-name">Layout 2</div>
|
<div className="layer-name">{comparedProducts[1]?.productName}</div>
|
||||||
<div className="layer-time">110 Sec</div>
|
<div className="layer-time">{compareProductsData[1]?.simulationData.machineActiveTime} Sec</div>
|
||||||
<div className="layer-profit">
|
<div className="layer-profit">
|
||||||
<span>↑</span>1.6%
|
<span>↑</span>{(100 - product2CyclePercentage).toFixed(2)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -130,6 +176,31 @@ const ComparisonResult = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="cycle-time-container comparisionCard">
|
||||||
|
<div className="cycle-main">
|
||||||
|
<div className="cycle-header">Overall Downtime</div>
|
||||||
|
<div className="layers-wrapper">
|
||||||
|
<div className="layers">
|
||||||
|
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
||||||
|
<div className="layer-time">{compareProductsData[0]?.simulationData.machineIdleTime} Sec</div>
|
||||||
|
<div className="layer-profit">
|
||||||
|
<span>↑</span>{(100 - product1IdlePercentage).toFixed(2)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="layers">
|
||||||
|
<div className="layer-name">{comparedProducts[1]?.productName}</div>
|
||||||
|
<div className="layer-time">{compareProductsData[1]?.simulationData.machineIdleTime} Sec</div>
|
||||||
|
<div className="layer-profit">
|
||||||
|
<span>↑</span>{(100 - product2IdlePercentage).toFixed(2)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="chart">
|
||||||
|
<Pie data={downtimeData} options={options} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/*
|
||||||
<div className="overallDowntime-container comparisionCard">
|
<div className="overallDowntime-container comparisionCard">
|
||||||
<div className="overallDowntime-header">Overall Downtime</div>
|
<div className="overallDowntime-header">Overall Downtime</div>
|
||||||
<div className="totalDownTime-wrapper">
|
<div className="totalDownTime-wrapper">
|
||||||
|
@ -147,23 +218,23 @@ const ComparisonResult = () => {
|
||||||
<Bar data={downtimeData} options={options} />
|
<Bar data={downtimeData} options={options} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className="overallScrapRate comparisionCard">
|
<div className="overallScrapRate comparisionCard">
|
||||||
<div className="overallScrapRate-header">Overall Scrap Rate</div>
|
<div className="overallScrapRate-header">Production Capacity</div>
|
||||||
<div className="overallScrapRate-wrapper">
|
<div className="overallScrapRate-wrapper">
|
||||||
<div className="overallScrapRate-value">
|
<div className="overallScrapRate-value">
|
||||||
<div className="overallScrapRate-label">Layout 1</div>
|
<div className="overallScrapRate-label">{highestProductivityProduct?.productName}</div>
|
||||||
<div className="overallScrapRate-key">Total scrap produced by</div>
|
<div className="overallScrapRate-key">Total product produced</div>
|
||||||
<div className="overallScrapRateKey-value">2.7 ton</div>
|
<div className="overallScrapRateKey-value">{highestProductivityProduct?.simulationData.productionCapacity}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="chart">
|
<div className="chart">
|
||||||
<Bar data={scrapRateData} options={options} />
|
<Bar data={productionCapacityData} options={options} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PerformanceResult />
|
{ comparedProducts.length === 2 &&<PerformanceResult comparedProducts={comparedProducts}/>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,27 +20,32 @@ ChartJS.register(
|
||||||
);
|
);
|
||||||
|
|
||||||
const EnergyUsage = () => {
|
const EnergyUsage = () => {
|
||||||
const data = {
|
const data = useMemo(() => {
|
||||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
const randomizeData = () =>
|
||||||
datasets: [
|
Array.from({ length: 5 }, () => Math.floor(Math.random() * (2000 - 300 + 1)) + 300);
|
||||||
{
|
|
||||||
label: "Simulation 1",
|
return {
|
||||||
data: [400, 600, 450, 1000, 1000],
|
labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
||||||
borderColor: "#6a0dad",
|
datasets: [
|
||||||
fill: false,
|
{
|
||||||
tension: 0.5, // More curved line
|
label: "Simulation 1",
|
||||||
pointRadius: 0, // Remove point indicators
|
data: randomizeData(),
|
||||||
},
|
borderColor: "#6a0dad",
|
||||||
{
|
fill: false,
|
||||||
label: "Simulation 2",
|
tension: 0.5, // More curved line
|
||||||
data: [300, 500, 700, 950, 1100],
|
pointRadius: 0, // Remove point indicators
|
||||||
borderColor: "#b19cd9",
|
},
|
||||||
fill: false,
|
{
|
||||||
tension: 0.5,
|
label: "Simulation 2",
|
||||||
pointRadius: 0,
|
data: randomizeData(),
|
||||||
},
|
borderColor: "#b19cd9",
|
||||||
],
|
fill: false,
|
||||||
};
|
tension: 0.5,
|
||||||
|
pointRadius: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const options = useMemo(
|
const options = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
|
|
@ -5,7 +5,8 @@ import {
|
||||||
TickIcon,
|
TickIcon,
|
||||||
} from "../../../icons/ExportCommonIcons";
|
} from "../../../icons/ExportCommonIcons";
|
||||||
|
|
||||||
const PerformanceResult = () => {
|
const PerformanceResult = ({ comparedProducts }: any) => {
|
||||||
|
const ProfitProduct = comparedProducts[0].simulationData.netProfit > comparedProducts[1].simulationData.netProfit ? comparedProducts[0] : comparedProducts[1];
|
||||||
return (
|
return (
|
||||||
<div className="performanceResult-wrapper comparisionCard">
|
<div className="performanceResult-wrapper comparisionCard">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
|
@ -26,30 +27,30 @@ const PerformanceResult = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="metric-value">98%</div>
|
<div className="metric-value">98%</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="label">Environmental impact</div>
|
<div className="label">Net Profit</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="metrics-right">
|
<div className="metrics-right">
|
||||||
<div className="metric-wrapper">
|
<div className="metric-wrapper">
|
||||||
<div className="metric-label">Waste generation</div>
|
<div className="metric-label">ROI Percentage</div>
|
||||||
<div className="metric">
|
<div className="metric">
|
||||||
<div className="metric-icon">I</div>
|
<div className="metric-icon"></div>
|
||||||
<div className="metric-value">0.5%</div>
|
<div className="metric-value">{ProfitProduct.simulationData.roiPercentage.toFixed(2)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="metric-wrapper">
|
<div className="metric-wrapper">
|
||||||
<div className="metric-label">Risk
management</div>
|
<div className="metric-label">Payback Period</div>
|
||||||
<div className="metric">
|
<div className="metric">
|
||||||
<div className="metric-icon">I</div>
|
<div className="metric-icon"></div>
|
||||||
<div className="metric-value">0.1%</div>
|
<div className="metric-value">{ProfitProduct.simulationData.netProfit}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="metric-wrapper">
|
<div className="metric-wrapper">
|
||||||
<div className="metric">
|
<div className="metric">
|
||||||
<div className="metric-icon">I</div>
|
<div className="metric-icon"></div>
|
||||||
<div className="metric-value">0.5%</div>
|
<div className="metric-value">{parseFloat(ProfitProduct.simulationData.paybackPeriod.toFixed(2))}years</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -147,7 +147,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
||||||
projectId
|
projectId
|
||||||
);
|
);
|
||||||
// console.log("response: ", response);
|
// console.log("response: ", response);
|
||||||
console.log(' zoneAssetId.id,: ', zoneAssetId.id,);
|
console.log(' zoneAssetId.id,: ', zoneAssetId.id,);
|
||||||
|
|
||||||
setName(zoneAssetId.id, response.modelName);
|
setName(zoneAssetId.id, response.modelName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
<HourlySimulationIcon />
|
<HourlySimulationIcon />
|
||||||
</div>
|
</div>
|
||||||
<div className="label">ThroughPut Data</div>
|
<div className="label">ThroughPut</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="progress-wrapper">
|
<div className="progress-wrapper">
|
||||||
<div
|
<div
|
||||||
|
@ -202,7 +202,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
<DailyProductionIcon />
|
<DailyProductionIcon />
|
||||||
</div>
|
</div>
|
||||||
<div className="label">Daily Production</div>
|
<div className="label">Production Capacity</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="progress-wrapper">
|
<div className="progress-wrapper">
|
||||||
<div
|
<div
|
||||||
|
@ -217,7 +217,7 @@ const SimulationPlayer: React.FC = () => {
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
<MonthlyROI />
|
<MonthlyROI />
|
||||||
</div>
|
</div>
|
||||||
<div className="label">Monthly ROI</div>
|
<div className="label">ROI</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="progress-wrapper">
|
<div className="progress-wrapper">
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
|
|
||||||
import * as Types from "../../../../types/world/worldTypes";
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
|
|
||||||
function hideWalls(
|
function hideWalls(
|
||||||
|
@ -7,21 +6,24 @@ function hideWalls(
|
||||||
scene: THREE.Scene,
|
scene: THREE.Scene,
|
||||||
camera: THREE.Camera
|
camera: THREE.Camera
|
||||||
): void {
|
): void {
|
||||||
|
const wallNormal = new THREE.Vector3();
|
||||||
////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera //////////
|
const cameraToWall = new THREE.Vector3();
|
||||||
|
const cameraDirection = new THREE.Vector3();
|
||||||
const v = new THREE.Vector3();
|
|
||||||
const u = new THREE.Vector3();
|
|
||||||
|
|
||||||
if (visibility === true) {
|
if (visibility === true) {
|
||||||
for (const children of scene.children) {
|
for (const children of scene.children) {
|
||||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||||
children.children[0].children.forEach((child: any) => {
|
children.children[0].children.forEach((child: any) => {
|
||||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
if (child.children[0]?.userData.WallType === "RoomWall") {
|
||||||
child.children[0].getWorldDirection(v);
|
const wallMesh = child.children[0];
|
||||||
camera.getWorldDirection(u);
|
wallMesh.getWorldDirection(wallNormal);
|
||||||
if (child.children[0].material) {
|
cameraToWall.copy(wallMesh.position).sub(camera.position).normalize();
|
||||||
child.children[0].material.visible = (2 * v.dot(u)) >= -0.5;
|
camera.getWorldDirection(cameraDirection);
|
||||||
|
const isFacingCamera = wallNormal.dot(cameraToWall) > 0;
|
||||||
|
const isInFrontOfCamera = cameraDirection.dot(cameraToWall) > -0.3;
|
||||||
|
|
||||||
|
if (wallMesh.material) {
|
||||||
|
wallMesh.material.visible = isFacingCamera && isInFrontOfCamera;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -31,10 +33,8 @@ function hideWalls(
|
||||||
for (const children of scene.children) {
|
for (const children of scene.children) {
|
||||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||||
children.children[0].children.forEach((child: any) => {
|
children.children[0].children.forEach((child: any) => {
|
||||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
if (child.children[0]?.userData.WallType === "RoomWall" && child.children[0].material) {
|
||||||
if (child.children[0].material) {
|
child.children[0].material.visible = true;
|
||||||
child.children[0].material.visible = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,4 @@ function hideWalls(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default hideWalls;
|
export default hideWalls;
|
|
@ -49,6 +49,7 @@ function CommentsGroup() {
|
||||||
!intersect.object.name.includes("zonePlane") &&
|
!intersect.object.name.includes("zonePlane") &&
|
||||||
!intersect.object.name.includes("SelectionGroup") &&
|
!intersect.object.name.includes("SelectionGroup") &&
|
||||||
!intersect.object.name.includes("selectionAssetGroup") &&
|
!intersect.object.name.includes("selectionAssetGroup") &&
|
||||||
|
!intersect.object.name.includes("commentHolder") &&
|
||||||
!intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
|
!intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
|
||||||
!intersect.object.name.includes("SelectionGroupBoundingBox") &&
|
!intersect.object.name.includes("SelectionGroupBoundingBox") &&
|
||||||
!intersect.object.name.includes("SelectionGroupBoundingLine") &&
|
!intersect.object.name.includes("SelectionGroupBoundingLine") &&
|
||||||
|
@ -76,11 +77,13 @@ function CommentsGroup() {
|
||||||
!intersect.object.name.includes("zonePlane") &&
|
!intersect.object.name.includes("zonePlane") &&
|
||||||
!intersect.object.name.includes("SelectionGroup") &&
|
!intersect.object.name.includes("SelectionGroup") &&
|
||||||
!intersect.object.name.includes("selectionAssetGroup") &&
|
!intersect.object.name.includes("selectionAssetGroup") &&
|
||||||
|
!intersect.object.name.includes("commentHolder") &&
|
||||||
!intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
|
!intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
|
||||||
!intersect.object.name.includes("SelectionGroupBoundingBox") &&
|
!intersect.object.name.includes("SelectionGroupBoundingBox") &&
|
||||||
!intersect.object.name.includes("SelectionGroupBoundingLine") &&
|
!intersect.object.name.includes("SelectionGroupBoundingLine") &&
|
||||||
intersect.object.type !== "GridHelper"
|
intersect.object.type !== "GridHelper"
|
||||||
);
|
);
|
||||||
|
console.log('intersects: ', intersects);
|
||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
const position = new Vector3(intersects[0].point.x, Math.max(intersects[0].point.y, 0), intersects[0].point.z);
|
const position = new Vector3(intersects[0].point.x, Math.max(intersects[0].point.y, 0), intersects[0].point.z);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { Canvas } from "@react-three/fiber";
|
import { Canvas } from "@react-three/fiber";
|
||||||
import { Color } from "three";
|
|
||||||
import { KeyboardControls } from "@react-three/drei";
|
import { KeyboardControls } from "@react-three/drei";
|
||||||
import { SceneProvider } from "./sceneContext";
|
import { SceneProvider } from "./sceneContext";
|
||||||
|
|
||||||
|
@ -9,6 +8,12 @@ import Visualization from "../visualization/visualization";
|
||||||
import Setup from "./setup/setup";
|
import Setup from "./setup/setup";
|
||||||
import Simulation from "../simulation/simulation";
|
import Simulation from "../simulation/simulation";
|
||||||
import Collaboration from "../collaboration/collaboration";
|
import Collaboration from "../collaboration/collaboration";
|
||||||
|
import useModuleStore from "../../store/useModuleStore";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { getAllProjects } from "../../services/dashboard/getAllProjects";
|
||||||
|
import { getUserData } from "../../components/Dashboard/functions/getUserData";
|
||||||
|
import { useLoadingProgress, useSocketStore } from "../../store/builder/store";
|
||||||
|
import { useAssetsStore } from "../../store/builder/useAssetStore";
|
||||||
|
|
||||||
export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Comparison Layout' }) {
|
export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Comparison Layout' }) {
|
||||||
const map = useMemo(() => [
|
const map = useMemo(() => [
|
||||||
|
@ -17,19 +22,76 @@ export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Co
|
||||||
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
||||||
{ name: "right", keys: ["ArrowRight", "d", "D"] },
|
{ name: "right", keys: ["ArrowRight", "d", "D"] },
|
||||||
], []);
|
], []);
|
||||||
|
const { assets } = useAssetsStore();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
const { projectSocket } = useSocketStore();
|
||||||
|
const { loadingProgress } = useLoadingProgress();
|
||||||
|
const handleUpdatingProject = async () => {
|
||||||
|
if (!projectId) return;
|
||||||
|
try {
|
||||||
|
const projects = await getAllProjects(userId, organization);
|
||||||
|
let projectUuid = projects.Projects.find(
|
||||||
|
(val: any) => val.projectUuid === projectId || val._id === projectId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (activeModule === "builder" && loadingProgress !== 1) {
|
||||||
|
const canvas =
|
||||||
|
document.getElementById("sceneCanvas")?.children[0]?.children[0];
|
||||||
|
const screenshotDataUrl = (canvas as HTMLCanvasElement)?.toDataURL("image/png");
|
||||||
|
setTimeout(() => {
|
||||||
|
const updateProjects = {
|
||||||
|
projectId: projectUuid,
|
||||||
|
organization,
|
||||||
|
userId,
|
||||||
|
projectName: projectUuid.projectName,
|
||||||
|
thumbnail: screenshotDataUrl,
|
||||||
|
};
|
||||||
|
if (projectSocket) {
|
||||||
|
projectSocket.emit("v1:project:update", updateProjects);
|
||||||
|
}
|
||||||
|
}, 8000);
|
||||||
|
} else {
|
||||||
|
const canvas =
|
||||||
|
document.getElementById("sceneCanvas")?.children[0]?.children[0];
|
||||||
|
const screenshotDataUrl = (canvas as HTMLCanvasElement)?.toDataURL("image/png");
|
||||||
|
const updateProjects = {
|
||||||
|
projectId: projectUuid,
|
||||||
|
organization,
|
||||||
|
userId,
|
||||||
|
projectName: projectUuid.projectName,
|
||||||
|
thumbnail: screenshotDataUrl,
|
||||||
|
};
|
||||||
|
// console.log('screenshotDataUrl: ', screenshotDataUrl);
|
||||||
|
// console.log('updateProjects: ', updateProjects);
|
||||||
|
if (projectSocket) {
|
||||||
|
projectSocket.emit("v1:project:update", updateProjects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) { }
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
handleUpdatingProject()
|
||||||
|
}, [activeModule, assets, loadingProgress])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SceneProvider layout={layout}>
|
<SceneProvider layout={layout}>
|
||||||
<KeyboardControls map={map}>
|
<KeyboardControls map={map}>
|
||||||
<Canvas
|
<Canvas
|
||||||
|
id="sceneCanvas"
|
||||||
|
shadows
|
||||||
|
color="#aaaa"
|
||||||
eventPrefix="client"
|
eventPrefix="client"
|
||||||
gl={{ powerPreference: "high-performance", antialias: true }}
|
|
||||||
onContextMenu={(e) => {
|
onContextMenu={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}}
|
}}
|
||||||
onCreated={(e) => {
|
onCreated={(e) => {
|
||||||
e.scene.background = new Color(0x19191d);
|
e.scene.background = null;
|
||||||
}}
|
}}
|
||||||
|
gl={{ powerPreference: "high-performance", antialias: true, preserveDrawingBuffer: true }}
|
||||||
>
|
>
|
||||||
<Setup />
|
<Setup />
|
||||||
<Collaboration />
|
<Collaboration />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
|
import { CompareProduct, useCompareProductDataStore, useInputValues, useMachineDowntime, useMachineUptime, useProductionCapacityData, useROISummaryData, useThroughPutData } from '../../../../store/builder/store';
|
||||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||||
import { useProductContext } from '../../products/productContext';
|
import { useProductContext } from '../../products/productContext';
|
||||||
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
||||||
|
@ -12,28 +12,31 @@ export default function ROIData() {
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { setRoiSummaryData } = useROISummaryData();
|
const { setRoiSummaryData } = useROISummaryData();
|
||||||
const { products, getProductById } = useProductStore();
|
const { products, getProductById } = useProductStore();
|
||||||
const [compareProducts, setCompareProducts] = useState<any[]>([]);
|
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
|
||||||
|
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
|
||||||
|
const { machineIdleTime, setMachineIdleTime } = useMachineDowntime();
|
||||||
|
const { throughputData } = useThroughPutData()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPlaying) {
|
if (isPlaying) return;
|
||||||
setRoiSummaryData({
|
setRoiSummaryData({
|
||||||
productName: "",
|
productName: "",
|
||||||
roiPercentage: 0,
|
roiPercentage: 0,
|
||||||
paybackPeriod: 0,
|
paybackPeriod: 0,
|
||||||
totalCost: 0,
|
totalCost: 0,
|
||||||
revenueGenerated: 0,
|
revenueGenerated: 0,
|
||||||
netProfit: 0,
|
netProfit: 0,
|
||||||
netLoss: 0,
|
netLoss: 0,
|
||||||
})
|
});
|
||||||
return;
|
}, [isPlaying]);
|
||||||
}
|
|
||||||
|
|
||||||
if (inputValues === undefined) return;
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputValues === undefined || !isPlaying) return;
|
||||||
const electricityCost = parseFloat(inputValues["Electricity cost"]);
|
const electricityCost = parseFloat(inputValues["Electricity cost"]);
|
||||||
const fixedCost = parseFloat(inputValues["Fixed costs"]);
|
const fixedCost = parseFloat(inputValues["Fixed costs"]);
|
||||||
const laborCost = parseFloat(inputValues["Labor Cost"]);
|
const laborCost = parseFloat(inputValues["Labor Cost"]);
|
||||||
const maintenanceCost = parseFloat(inputValues["Maintenance cost"]); // Remove space typ
|
const laborCount = parseFloat(inputValues["Labor Count"]);
|
||||||
|
const maintenanceCost = parseFloat(inputValues["Maintenance cost"]);
|
||||||
const materialCost = parseFloat(inputValues["Material cost"]);
|
const materialCost = parseFloat(inputValues["Material cost"]);
|
||||||
const productionPeriod = parseFloat(inputValues["Production period"]);
|
const productionPeriod = parseFloat(inputValues["Production period"]);
|
||||||
const salvageValue = parseFloat(inputValues["Salvage value"]);
|
const salvageValue = parseFloat(inputValues["Salvage value"]);
|
||||||
|
@ -46,109 +49,146 @@ export default function ROIData() {
|
||||||
if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) &&
|
if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) &&
|
||||||
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
|
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
|
||||||
!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
|
!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && productionCapacityData > 0) {
|
||||||
|
|
||||||
const totalHoursPerYear = shiftLength * shiftsPerDay * workingDaysPerYear;
|
|
||||||
// Total good units produced per year
|
|
||||||
const annualProductionUnits = productionCapacityData * totalHoursPerYear;
|
|
||||||
// Revenue for a year
|
|
||||||
const annualRevenue = annualProductionUnits * sellingPrice;
|
|
||||||
// Costs
|
|
||||||
const totalMaterialCost = annualProductionUnits * materialCost;
|
|
||||||
const totalLaborCost = laborCost * totalHoursPerYear;
|
|
||||||
const totalEnergyCost = electricityCost * totalHoursPerYear;
|
|
||||||
const totalMaintenanceCost = maintenanceCost + fixedCost;
|
|
||||||
const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost;
|
|
||||||
// Annual Profit
|
|
||||||
const annualProfit = annualRevenue - totalAnnualCost;
|
|
||||||
|
|
||||||
// Net Profit over production period
|
|
||||||
const netProfit = annualProfit * productionPeriod;
|
|
||||||
// ROI
|
|
||||||
const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
|
|
||||||
// Payback Period
|
|
||||||
const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0
|
|
||||||
|
|
||||||
|
|
||||||
//
|
// const totalHoursPerYear = shiftLength * shiftsPerDay * workingDaysPerYear;
|
||||||
//
|
// const annualProductionUnits = productionCapacityData * totalHoursPerYear;
|
||||||
//
|
// const annualRevenue = annualProductionUnits * sellingPrice;
|
||||||
//
|
|
||||||
//
|
// const totalMaterialCost = annualProductionUnits * materialCost;
|
||||||
//
|
// const totalLaborCost = laborCost * totalHoursPerYear;
|
||||||
//
|
// const totalEnergyCost = electricityCost * totalHoursPerYear;
|
||||||
//
|
// const totalMaintenanceCost = maintenanceCost + fixedCost;
|
||||||
|
// const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost;
|
||||||
|
// const annualProfit = annualRevenue - totalAnnualCost;
|
||||||
|
|
||||||
|
// const netProfit = annualProfit * productionPeriod;
|
||||||
|
// const roiPercentage = ((annualProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
|
||||||
|
// const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0
|
||||||
|
|
||||||
|
// setRoiSummaryData({
|
||||||
|
// productName: selectedProduct.productName,
|
||||||
|
// roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)),
|
||||||
|
// paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
|
||||||
|
// totalCost: parseFloat(totalAnnualCost.toFixed(2)),
|
||||||
|
// revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
|
||||||
|
// netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
|
||||||
|
// netLoss: netProfit < 0 ? -netProfit : 0
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const productCount = 1000;
|
||||||
|
// const costPerUnit = totalAnnualCost / annualProductionUnits;
|
||||||
|
// const costForTargetUnits = productCount * costPerUnit;
|
||||||
|
// const revenueForTargetUnits = productCount * sellingPrice;
|
||||||
|
// const profitForTargetUnits = revenueForTargetUnits - costForTargetUnits;
|
||||||
|
|
||||||
|
// const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0;
|
||||||
|
// const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0;
|
||||||
|
|
||||||
|
// const productData = getProductById(selectedProduct.productUuid);
|
||||||
|
// const prev = useCompareProductDataStore.getState().compareProductsData;
|
||||||
|
// const newData: CompareProduct = {
|
||||||
|
// productUuid: productData?.productUuid ?? '',
|
||||||
|
// productName: productData?.productName ?? '',
|
||||||
|
// simulationData: {
|
||||||
|
// // costPerUnit: parseFloat(costPerUnit.toFixed(2)),
|
||||||
|
// // workingDaysPerYear: parseFloat(workingDaysPerYear.toFixed(2)),
|
||||||
|
// // shiftLength: parseFloat(shiftLength.toFixed(2)),
|
||||||
|
// // shiftsPerDay: parseFloat(shiftsPerDay.toFixed(2)),
|
||||||
|
// roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)),
|
||||||
|
// // paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
|
||||||
|
// // totalCost: parseFloat(totalAnnualCost.toFixed(2)),
|
||||||
|
// // revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
|
||||||
|
// netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
|
||||||
|
// productionCapacity: parseFloat(productionCapacityData.toFixed(2)),
|
||||||
|
// // netLoss: netProfit < 0 ? parseFloat((-netProfit).toFixed(2)) : 0,
|
||||||
|
// machineIdleTime: parseFloat(machineIdleTime.toFixed(2)),
|
||||||
|
// machineActiveTime: parseFloat(machineActiveTime.toFixed(2)),
|
||||||
|
// throughputData: throughputData,
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const existingIndex = prev.findIndex((item: CompareProduct) =>
|
||||||
|
// item.productUuid === productData?.productUuid
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (existingIndex !== -1) {
|
||||||
|
// const updated = [...prev];
|
||||||
|
// updated[existingIndex] = newData;
|
||||||
|
// setCompareProductsData(updated);
|
||||||
|
// } else {
|
||||||
|
// setCompareProductsData([...prev, newData]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const Annual_units = throughputData * workingDaysPerYear
|
||||||
|
const Total_units = Annual_units * productionPeriod
|
||||||
|
|
||||||
|
const Total_revenue = Total_units * sellingPrice
|
||||||
|
const Total_variable_cost = Total_units * (materialCost + (laborCost))
|
||||||
|
|
||||||
|
const Total_fixed_cost = (maintenanceCost + electricityCost + fixedCost) * workingDaysPerYear * productionPeriod
|
||||||
|
const Total_cost = Total_variable_cost + Total_fixed_cost
|
||||||
|
|
||||||
|
const Net_profit = Total_revenue - Total_cost + (salvageValue * workingDaysPerYear * productionPeriod)
|
||||||
|
|
||||||
|
const ROI = (Net_profit / initialInvestment) * 100
|
||||||
|
|
||||||
|
const Annual_net_profit = (Annual_units * (sellingPrice - materialCost - laborCost)) - (maintenanceCost + electricityCost + fixedCost) * workingDaysPerYear + (salvageValue * workingDaysPerYear)
|
||||||
|
const Payback_period_years = initialInvestment / Annual_net_profit;
|
||||||
|
|
||||||
setRoiSummaryData({
|
setRoiSummaryData({
|
||||||
productName: selectedProduct.productName,
|
productName: selectedProduct.productName,
|
||||||
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)), // normalized to 0.x format
|
roiPercentage: ROI,
|
||||||
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
|
paybackPeriod: Payback_period_years,
|
||||||
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
|
totalCost: Total_cost,
|
||||||
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
|
revenueGenerated: Total_revenue,
|
||||||
netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
|
netProfit: Net_profit > 0 ? Net_profit : 0,
|
||||||
netLoss: netProfit < 0 ? -netProfit : 0
|
netLoss: Net_profit < 0 ? -Net_profit : 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const productCount = 1000;
|
|
||||||
|
|
||||||
// Cost per unit (based on full annual cost)
|
|
||||||
const costPerUnit = totalAnnualCost / annualProductionUnits;
|
|
||||||
|
|
||||||
const costForTargetUnits = productCount * costPerUnit;
|
|
||||||
const revenueForTargetUnits = productCount * sellingPrice;
|
|
||||||
const profitForTargetUnits = revenueForTargetUnits - costForTargetUnits;
|
|
||||||
|
|
||||||
const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0;
|
|
||||||
const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0;
|
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
const productData = getProductById(selectedProduct.productUuid);
|
const productData = getProductById(selectedProduct.productUuid);
|
||||||
|
const prev = useCompareProductDataStore.getState().compareProductsData;
|
||||||
|
const newData: CompareProduct = {
|
||||||
setCompareProducts(prev => {
|
productUuid: productData?.productUuid ?? '',
|
||||||
const newData = {
|
productName: productData?.productName ?? '',
|
||||||
productUuid: productData?.productUuid,
|
simulationData: {
|
||||||
productName: productData?.productName,
|
// costPerUnit: costPerUnit,
|
||||||
costPerUnit: parseFloat(costPerUnit.toFixed(2)),
|
// workingDaysPerYear: workingDaysPerYear,
|
||||||
workingDaysPerYear: parseFloat(workingDaysPerYear.toFixed(2)),
|
// shiftLength: shiftLength,
|
||||||
shiftLength: parseFloat(shiftLength.toFixed(2)),
|
// shiftsPerDay: shiftsPerDay,
|
||||||
shiftsPerDay: parseFloat(shiftsPerDay.toFixed(2)),
|
roiPercentage: ROI,
|
||||||
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)),
|
paybackPeriod: Payback_period_years,
|
||||||
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
|
// paybackPeriod: paybackPeriod,
|
||||||
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
|
// totalCost: totalAnnualCost,
|
||||||
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
|
// revenueGenerated: annualRevenue,
|
||||||
netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
|
netProfit: Net_profit > 0 ? Net_profit : 0,
|
||||||
netLoss: netProfit < 0 ? parseFloat((-netProfit).toFixed(2)) : 0
|
productionCapacity: productionCapacityData,
|
||||||
};
|
// netLoss: netProfit < 0 ? (-netProfit) : 0,
|
||||||
|
machineIdleTime: machineIdleTime,
|
||||||
const existingIndex = prev.findIndex(
|
machineActiveTime: machineActiveTime,
|
||||||
item => item.productUuid === productData?.productUuid
|
throughputData: throughputData,
|
||||||
);
|
|
||||||
|
|
||||||
if (existingIndex !== -1) {
|
|
||||||
// Replace the existing item
|
|
||||||
const updated = [...prev];
|
|
||||||
updated[existingIndex] = newData;
|
|
||||||
return updated;
|
|
||||||
} else {
|
|
||||||
// Add as new item
|
|
||||||
return [...prev, newData];
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
// console.log('compareProducts: ', compareProducts);
|
|
||||||
|
const existingIndex = prev.findIndex((item: CompareProduct) =>
|
||||||
|
item.productUuid === productData?.productUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingIndex !== -1) {
|
||||||
|
const updated = [...prev];
|
||||||
|
updated[existingIndex] = newData;
|
||||||
|
setCompareProductsData(updated);
|
||||||
|
} else {
|
||||||
|
setCompareProductsData([...prev, newData]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [inputValues, productionCapacityData]);
|
}, [inputValues, productionCapacityData, throughputData, isPlaying]);
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<></>
|
|
||||||
)
|
}, [compareProductsData])
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,36 @@
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
|
import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
|
||||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||||
|
import { useProductContext } from '../../products/productContext';
|
||||||
|
|
||||||
export default function ProductionCapacityData() {
|
export default function ProductionCapacityData() {
|
||||||
const { throughputData } = useThroughPutData()
|
const { throughputData } = useThroughPutData()
|
||||||
const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
|
const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
|
||||||
const { inputValues } = useInputValues();
|
const { inputValues } = useInputValues();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { selectedProduct } = selectedProductStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPlaying) {
|
if (!isPlaying) {
|
||||||
|
|
||||||
setProductionCapacityData(0);
|
setProductionCapacityData(0);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!inputValues || throughputData === undefined) return;
|
}, [isPlaying]);
|
||||||
|
|
||||||
const shiftLength = parseFloat(inputValues["Shift length"]);
|
useEffect(() => {
|
||||||
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
|
if (!inputValues || throughputData === undefined || !isPlaying) return;
|
||||||
const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
|
const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
|
||||||
const yieldRate = parseFloat(inputValues["Yield rate"]);
|
|
||||||
|
|
||||||
if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) &&
|
if (!isNaN(workingDaysPerYear) && throughputData > 0) {
|
||||||
!isNaN(yieldRate) && throughputData >= 0) {
|
const Monthly_working_days = workingDaysPerYear / 12;
|
||||||
// Total units produced per day before yield
|
const Production_capacity_per_month = throughputData * Monthly_working_days;
|
||||||
const dailyProduction = throughputData * shiftLength * shiftsPerDay;
|
|
||||||
|
|
||||||
|
|
||||||
// Units after applying yield rate
|
|
||||||
const goodUnitsPerDay = dailyProduction * (yieldRate / 100);
|
|
||||||
|
|
||||||
|
|
||||||
// Annual output
|
|
||||||
const annualProduction = goodUnitsPerDay * workingDaysPerYear;
|
|
||||||
|
|
||||||
|
|
||||||
// Final production capacity per hour (after yield)
|
setProductionCapacityData(Number(Production_capacity_per_month.toFixed(2)));
|
||||||
const productionPerHour = throughputData * (yieldRate / 100);
|
|
||||||
|
|
||||||
|
|
||||||
// Set the final capacity (units/hour)
|
|
||||||
setProductionCapacityData(Number(productionPerHour.toFixed(2)));
|
|
||||||
}
|
}
|
||||||
}, [throughputData, inputValues]);
|
}, [throughputData, inputValues, isPlaying]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<></>
|
<></>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
||||||
import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
|
import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences';
|
||||||
import { useMachineCount, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store';
|
import { useInputValues, useMachineCount, useMachineDowntime, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store';
|
||||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||||
import { useSceneContext } from '../../../scene/sceneContext';
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
import { useProductContext } from '../../products/productContext';
|
import { useProductContext } from '../../products/productContext';
|
||||||
|
import { set } from 'immer/dist/internal';
|
||||||
|
|
||||||
export default function ThroughPutData() {
|
export default function ThroughPutData() {
|
||||||
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext();
|
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext();
|
||||||
|
@ -19,25 +20,34 @@ export default function ThroughPutData() {
|
||||||
const { materialHistory, materials } = materialStore();
|
const { materialHistory, materials } = materialStore();
|
||||||
const { machineCount, setMachineCount } = useMachineCount();
|
const { machineCount, setMachineCount } = useMachineCount();
|
||||||
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
|
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
|
||||||
|
const { machineIdleTime, setMachineIdleTime } = useMachineDowntime();
|
||||||
const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
|
const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
|
||||||
const { setProcessBar } = useProcessBar();
|
const { setProcessBar } = useProcessBar();
|
||||||
const { setThroughputData } = useThroughPutData()
|
const { setThroughputData } = useThroughPutData()
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const { inputValues } = useInputValues();
|
||||||
|
|
||||||
// Setting machine count
|
// Setting machine count
|
||||||
let totalItems = 0;
|
let totalItems = 0;
|
||||||
let totalActiveTime = 0;
|
let totalActiveTime = 0;
|
||||||
|
let totalIdleTime = 0
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPlaying) {
|
if (!isPlaying) {
|
||||||
totalActiveTime = 0;
|
totalActiveTime = 0;
|
||||||
totalItems = 0;
|
totalItems = 0;
|
||||||
|
totalIdleTime = 0;
|
||||||
setMachineCount(0);
|
setMachineCount(0);
|
||||||
setMachineActiveTime(0);
|
setMachineActiveTime(0);
|
||||||
|
setMachineIdleTime(0);
|
||||||
setMaterialCycleTime(0);
|
setMaterialCycleTime(0);
|
||||||
setProcessBar([]);
|
setProcessBar([]);
|
||||||
setThroughputData(0);
|
setThroughputData(0);
|
||||||
return;
|
}
|
||||||
} else {
|
}, [isPlaying])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isPlaying) {
|
||||||
let process: any = [];
|
let process: any = [];
|
||||||
const fetchProductSequenceData = async () => {
|
const fetchProductSequenceData = async () => {
|
||||||
const productData = getProductById(selectedProduct.productUuid);
|
const productData = getProductById(selectedProduct.productUuid);
|
||||||
|
@ -53,6 +63,9 @@ export default function ThroughPutData() {
|
||||||
process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime })
|
process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime })
|
||||||
totalActiveTime += arm.activeTime;
|
totalActiveTime += arm.activeTime;
|
||||||
}
|
}
|
||||||
|
if (arm.idleTime > 0) {
|
||||||
|
totalIdleTime += arm.idleTime;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else if (item.type === "vehicle") {
|
} else if (item.type === "vehicle") {
|
||||||
vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid)
|
vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid)
|
||||||
|
@ -62,6 +75,9 @@ export default function ThroughPutData() {
|
||||||
|
|
||||||
totalActiveTime += vehicle.activeTime;
|
totalActiveTime += vehicle.activeTime;
|
||||||
}
|
}
|
||||||
|
if (vehicle.idleTime > 0) {
|
||||||
|
totalIdleTime += vehicle.idleTime;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else if (item.type === "machine") {
|
} else if (item.type === "machine") {
|
||||||
machines.filter(machine => machine.modelUuid === item.modelUuid)
|
machines.filter(machine => machine.modelUuid === item.modelUuid)
|
||||||
|
@ -70,6 +86,9 @@ export default function ThroughPutData() {
|
||||||
process.push({ modelid: machine.modelUuid, modelName: machine.modelName, activeTime: machine?.activeTime })
|
process.push({ modelid: machine.modelUuid, modelName: machine.modelName, activeTime: machine?.activeTime })
|
||||||
totalActiveTime += machine.activeTime;
|
totalActiveTime += machine.activeTime;
|
||||||
}
|
}
|
||||||
|
if (machine.idleTime > 0) {
|
||||||
|
totalIdleTime += machine.idleTime;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else if (item.type === "transfer") {
|
} else if (item.type === "transfer") {
|
||||||
conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid)
|
conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid)
|
||||||
|
@ -83,7 +102,7 @@ export default function ThroughPutData() {
|
||||||
.forEach(storage => {
|
.forEach(storage => {
|
||||||
if (storage.activeTime > 0) {
|
if (storage.activeTime > 0) {
|
||||||
// totalActiveTime += storage.activeTime;
|
// totalActiveTime += storage.activeTime;
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -92,9 +111,10 @@ export default function ThroughPutData() {
|
||||||
totalItems += sequence.length;
|
totalItems += sequence.length;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
setMachineCount(totalItems);
|
setMachineCount(totalItems);
|
||||||
setMachineActiveTime(totalActiveTime);
|
setMachineActiveTime(totalActiveTime);
|
||||||
|
setMachineIdleTime(totalIdleTime);
|
||||||
let arr = process.map((item: any) => ({
|
let arr = process.map((item: any) => ({
|
||||||
name: item.modelName,
|
name: item.modelName,
|
||||||
completed: Math.round((item.activeTime / totalActiveTime) * 100)
|
completed: Math.round((item.activeTime / totalActiveTime) * 100)
|
||||||
|
@ -107,15 +127,15 @@ export default function ThroughPutData() {
|
||||||
fetchProductSequenceData();
|
fetchProductSequenceData();
|
||||||
}
|
}
|
||||||
// if (materialCycleTime <= 0) return
|
// if (materialCycleTime <= 0) return
|
||||||
}, [products, selectedProduct, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
|
}, [products, selectedProduct?.productUuid, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
let timeoutId: ReturnType<typeof setTimeout>;
|
||||||
async function getMachineActive() {
|
async function getMachineActive() {
|
||||||
const productData = getProductById(selectedProduct.productUuid);
|
const productData = getProductById(selectedProduct.productUuid);
|
||||||
let anyArmActive;
|
let anyArmActive;
|
||||||
let anyVehicleActive;
|
let anyVehicleActive;
|
||||||
let anyMachineActive;
|
let anyMachineActive;
|
||||||
|
|
||||||
if (productData) {
|
if (productData) {
|
||||||
const productSequenceData = await determineExecutionMachineSequences([productData]);
|
const productSequenceData = await determineExecutionMachineSequences([productData]);
|
||||||
if (productSequenceData?.length > 0) {
|
if (productSequenceData?.length > 0) {
|
||||||
|
@ -160,8 +180,8 @@ export default function ThroughPutData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const allInactive = !anyArmActive && !anyVehicleActive && !anyMachineActive;
|
const allInactive = !anyArmActive && !anyVehicleActive && !anyMachineActive;
|
||||||
if (allInactive && materials.length === 0 && materialHistory.length > 0) {
|
if (materials.length >= 0 && materialHistory.length > 0) {
|
||||||
|
|
||||||
let totalCycleTimeSum = 0;
|
let totalCycleTimeSum = 0;
|
||||||
let cycleCount = 0;
|
let cycleCount = 0;
|
||||||
|
|
||||||
|
@ -182,21 +202,28 @@ export default function ThroughPutData() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
getMachineActive();
|
getMachineActive();
|
||||||
}, 500)
|
}, 1500);
|
||||||
}
|
}
|
||||||
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct])
|
|
||||||
|
return () => {
|
||||||
|
if (timeoutId) clearTimeout(timeoutId);
|
||||||
|
};
|
||||||
|
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct?.productUuid])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
|
const shiftLength = parseFloat(inputValues["Shift length"]);
|
||||||
const utilization = machineActiveTime / 3600; // Active time per hour
|
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
|
||||||
const unitsPerMachinePerHour = 3600 / materialCycleTime;
|
const yieldRate = parseFloat(inputValues["Yield rate"]);
|
||||||
const throughput = unitsPerMachinePerHour * machineCount * utilization;
|
|
||||||
setThroughputData(Number(throughput.toFixed(2))); // Keep as number
|
if (shiftLength > 0 && materialCycleTime > 0 && machineCount > 0 && isPlaying) {
|
||||||
//
|
const Units_per_shift = (shiftLength * 60) / (materialCycleTime / 60);
|
||||||
|
|
||||||
|
const Throughput_per_day = Units_per_shift * shiftsPerDay * (yieldRate / 100);
|
||||||
|
setThroughputData(Number(Throughput_per_day.toFixed(2))); // Keep as number
|
||||||
}
|
}
|
||||||
}, [machineActiveTime, materialCycleTime, machineCount]);
|
}, [materialCycleTime, machineCount, isPlaying, inputValues]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -13,6 +13,7 @@ function Products() {
|
||||||
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout } = useSceneContext();
|
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout } = useSceneContext();
|
||||||
const { products, getProductById, addProduct, setProducts } = useProductStore();
|
const { products, getProductById, addProduct, setProducts } = useProductStore();
|
||||||
const { selectedProductStore } = useProductContext();
|
const { selectedProductStore } = useProductContext();
|
||||||
|
const { setMainProduct } = useMainProduct();
|
||||||
const { selectedProduct, setSelectedProduct } = selectedProductStore();
|
const { selectedProduct, setSelectedProduct } = selectedProductStore();
|
||||||
const { addVehicle, clearvehicles } = vehicleStore();
|
const { addVehicle, clearvehicles } = vehicleStore();
|
||||||
const { addArmBot, clearArmBots } = armBotStore();
|
const { addArmBot, clearArmBots } = armBotStore();
|
||||||
|
@ -51,11 +52,13 @@ function Products() {
|
||||||
})
|
})
|
||||||
if (layout === 'Main Layout') {
|
if (layout === 'Main Layout') {
|
||||||
setSelectedProduct(id, name);
|
setSelectedProduct(id, name);
|
||||||
|
setMainProduct(id, name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setProducts(data);
|
setProducts(data);
|
||||||
if (layout === 'Main Layout') {
|
if (layout === 'Main Layout') {
|
||||||
setSelectedProduct(data[0].productUuid, data[0].productName);
|
setSelectedProduct(data[0].productUuid, data[0].productName);
|
||||||
|
setMainProduct(data[0].productUuid, data[0].productName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -48,7 +48,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||||
|
|
||||||
const computePath = useCallback(
|
const computePath = useCallback(
|
||||||
(start: any, end: any) => {
|
(start: any, end: any) => {
|
||||||
console.log('end: ', end);
|
|
||||||
try {
|
try {
|
||||||
const navMeshQuery = new NavMeshQuery(navMesh);
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
||||||
|
@ -57,7 +56,6 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
|
||||||
Math.round(segmentPath[segmentPath.length - 1].x) == Math.round(end.x) &&
|
Math.round(segmentPath[segmentPath.length - 1].x) == Math.round(end.x) &&
|
||||||
Math.round(segmentPath[segmentPath.length - 1].z) == Math.round(end.z)
|
Math.round(segmentPath[segmentPath.length - 1].z) == Math.round(end.z)
|
||||||
) {
|
) {
|
||||||
console.log('if ', segmentPath);
|
|
||||||
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
|
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
|
||||||
} else {
|
} else {
|
||||||
console.log("There is no path here...Choose valid path")
|
console.log("There is no path here...Choose valid path")
|
||||||
|
|
|
@ -43,7 +43,7 @@ const UserAuth: React.FC = () => {
|
||||||
const organization = email.split("@")[1].split(".")[0];
|
const organization = email.split("@")[1].split(".")[0];
|
||||||
try {
|
try {
|
||||||
const res = await signInApi(email, password, organization, fingerprint);
|
const res = await signInApi(email, password, organization, fingerprint);
|
||||||
console.log('res: ', res);
|
// console.log('res: ', res);
|
||||||
if (res.message.message === "login successfull") {
|
if (res.message.message === "login successfull") {
|
||||||
setError("");
|
setError("");
|
||||||
setOrganization(organization);
|
setOrganization(organization);
|
||||||
|
@ -56,10 +56,10 @@ const UserAuth: React.FC = () => {
|
||||||
localStorage.setItem("refreshToken", res.message.refreshToken);
|
localStorage.setItem("refreshToken", res.message.refreshToken);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('res.message.userId: ', res.message.userId);
|
// console.log('res.message.userId: ', res.message.userId);
|
||||||
console.log('organization: ', organization);
|
// console.log('organization: ', organization);
|
||||||
const projects = await recentlyViewed(organization, res.message.userId);
|
const projects = await recentlyViewed(organization, res.message.userId);
|
||||||
console.log('projects: ', projects);
|
// console.log('projects: ', projects);
|
||||||
|
|
||||||
if (res.message.isShare) {
|
if (res.message.isShare) {
|
||||||
if (Object.values(projects.RecentlyViewed).length > 0) {
|
if (Object.values(projects.RecentlyViewed).length > 0) {
|
||||||
|
|
|
@ -3,26 +3,25 @@ export const setFloorItemApi = async (
|
||||||
organization: string,
|
organization: string,
|
||||||
modelUuid?: string,
|
modelUuid?: string,
|
||||||
modelName?: string,
|
modelName?: string,
|
||||||
assetId?: string,
|
|
||||||
projectId?: string,
|
projectId?: string,
|
||||||
|
assetId?: string,
|
||||||
position?: Object,
|
position?: Object,
|
||||||
rotation?: Object,
|
rotation?: Object,
|
||||||
isLocked?: boolean,
|
isLocked?: boolean,
|
||||||
isVisible?: boolean
|
isVisible?: boolean,
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const body: any = {
|
const body: any = {
|
||||||
organization,
|
organization,
|
||||||
modelUuid,
|
modelUuid,
|
||||||
modelName,
|
modelName,
|
||||||
projectId,
|
|
||||||
position,
|
position,
|
||||||
rotation,
|
rotation,
|
||||||
assetId,
|
assetId,
|
||||||
isLocked,
|
isLocked,
|
||||||
isVisible,
|
isVisible,
|
||||||
|
projectId,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/setAsset`, {
|
const response = await fetch(`${url_Backend_dwinzo}/api/V1/setAsset`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -26,7 +26,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
|
||||||
auth: { token },
|
auth: { token },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const dashBoardSocket = io(
|
const dashBoardSocket = io(
|
||||||
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`,
|
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`,
|
||||||
|
@ -546,6 +546,10 @@ export const useMachineUptime = create<any>((set: any) => ({
|
||||||
machineActiveTime: 0,
|
machineActiveTime: 0,
|
||||||
setMachineActiveTime: (x: any) => set({ machineActiveTime: x }),
|
setMachineActiveTime: (x: any) => set({ machineActiveTime: x }),
|
||||||
}));
|
}));
|
||||||
|
export const useMachineDowntime = create<any>((set: any) => ({
|
||||||
|
machineIdleTime: 0,
|
||||||
|
setMachineIdleTime: (x: any) => set({ machineIdleTime: x }),
|
||||||
|
}));
|
||||||
export const useMaterialCycle = create<any>((set: any) => ({
|
export const useMaterialCycle = create<any>((set: any) => ({
|
||||||
materialCycleTime: 0,
|
materialCycleTime: 0,
|
||||||
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
|
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
|
||||||
|
@ -709,3 +713,32 @@ function getInitialViewSceneLabels(): boolean {
|
||||||
const saved = localStorage.getItem('viewSceneLabels');
|
const saved = localStorage.getItem('viewSceneLabels');
|
||||||
return saved ? JSON.parse(saved) : false;
|
return saved ? JSON.parse(saved) : false;
|
||||||
}
|
}
|
||||||
|
export interface CompareProduct {
|
||||||
|
productUuid: string;
|
||||||
|
productName: string;
|
||||||
|
simulationData: {
|
||||||
|
// costPerUnit: number;
|
||||||
|
// workingDaysPerYear: number;
|
||||||
|
// shiftLength: number;
|
||||||
|
// shiftsPerDay: number;
|
||||||
|
roiPercentage: number;
|
||||||
|
// paybackPeriod: number;
|
||||||
|
// totalCost: number;
|
||||||
|
// revenueGenerated: number;
|
||||||
|
netProfit: number;
|
||||||
|
productionCapacity: number;
|
||||||
|
paybackPeriod: number;
|
||||||
|
// netLoss: number;
|
||||||
|
machineIdleTime: number;
|
||||||
|
machineActiveTime: number;
|
||||||
|
throughputData: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCompareProductDataStore = create<{
|
||||||
|
compareProductsData: CompareProduct[];
|
||||||
|
setCompareProductsData: (x: CompareProduct[]) => void;
|
||||||
|
}>((set) => ({
|
||||||
|
compareProductsData: [],
|
||||||
|
setCompareProductsData: (x) => set({ compareProductsData: x }),
|
||||||
|
}));
|
|
@ -88,6 +88,7 @@ export const createMaterialStore = () => {
|
||||||
clearMaterials: () => {
|
clearMaterials: () => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.materials = [];
|
state.materials = [];
|
||||||
|
state.materialHistory = [];
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// store/simulation/useCompareProductDataStore.ts
|
||||||
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
interface CompareProduct {
|
||||||
|
productUuid: string;
|
||||||
|
productName: string;
|
||||||
|
costPerUnit: number;
|
||||||
|
workingDaysPerYear: number;
|
||||||
|
shiftLength: number;
|
||||||
|
shiftsPerDay: number;
|
||||||
|
roiPercentage: number;
|
||||||
|
paybackPeriod: number;
|
||||||
|
totalCost: number;
|
||||||
|
revenueGenerated: number;
|
||||||
|
netProfit: number;
|
||||||
|
netLoss: number;
|
||||||
|
}
|
||||||
|
|
|
@ -64,13 +64,14 @@
|
||||||
.production-details {
|
.production-details {
|
||||||
.production-wrapper {
|
.production-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
// align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
justify-content: start;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -657,7 +657,7 @@
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: var(--text-button-color);
|
stroke: var(--text-button-color);
|
||||||
stroke-width: 1.3;
|
strokeWidth: 1.3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1021,7 +1021,7 @@
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: var(--accent-color);
|
stroke: var(--accent-color);
|
||||||
stroke-width: 1.5px;
|
strokeWidth: 1.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -5,6 +5,7 @@ type Preset = {
|
||||||
activeOption: string;
|
activeOption: string;
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
|
defaultValue?: string | number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue