v3 #100
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect } from "react";
|
||||
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 Project from "./pages/Project";
|
||||
import UserAuth from "./pages/UserAuth";
|
||||
|
@ -14,6 +14,7 @@ const App: React.FC = () => {
|
|||
Cache.enabled = true;
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<LoggerProvider>
|
||||
<Router>
|
||||
|
|
|
@ -116,7 +116,6 @@ const DashboardHome: React.FC = () => {
|
|||
const renderProjects = () => {
|
||||
const projectList = recentProjects[Object.keys(recentProjects)[0]];
|
||||
|
||||
console.log('projectList: ', projectList);
|
||||
if (!projectList?.length) {
|
||||
return <div className="empty-state">No recent projects found</div>;
|
||||
}
|
||||
|
|
|
@ -1292,8 +1292,8 @@ export const PerformanceIcon = () => {
|
|||
<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"
|
||||
stroke="url(#paint0_linear_1736_988)"
|
||||
stroke-width="1.80917"
|
||||
stroke-linecap="round"
|
||||
strokeWidth="1.80917"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
|
@ -1304,8 +1304,8 @@ export const PerformanceIcon = () => {
|
|||
y2="17.742"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="#6F42C1" />
|
||||
<stop offset="1" stop-color="#B392F0" />
|
||||
<stop stopColor="#6F42C1" />
|
||||
<stop offset="1" stopColor="#B392F0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
@ -1328,9 +1328,9 @@ export const GreenTickIcon = () => {
|
|||
<path
|
||||
d="M4.85742 7.20505L6.91318 9.25578L10.3394 5.83789"
|
||||
stroke="white"
|
||||
stroke-width="2.45534"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeWidth="2.45534"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { useProductContext } from '../../../modules/simulation/products/productContext'
|
||||
import RegularDropDown from '../../ui/inputs/RegularDropDown';
|
||||
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 CompareLayOut from '../../ui/compareVersion/CompareLayOut';
|
||||
import ComparisonResult from '../../ui/compareVersion/ComparisonResult';
|
||||
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() {
|
||||
const { isPlaying, setIsPlaying } = usePlayButtonStore();
|
||||
|
@ -17,16 +18,63 @@ function ComparisonScene() {
|
|||
const { selectedProduct } = selectedProductStore();
|
||||
const { comparisonProduct, setComparisonProduct } = useComparisonProduct();
|
||||
const { mainProduct } = useMainProduct();
|
||||
const { setIsPaused } = usePauseButtonStore();
|
||||
const { loadingProgress } = useLoadingProgress();
|
||||
const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
|
||||
const [shouldShowComparisonResult, setShouldShowComparisonResult] = useState(false);
|
||||
|
||||
const handleSelectLayout = (option: string) => {
|
||||
const product = products.find((product) => product.productName === option);
|
||||
if (product) {
|
||||
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 (
|
||||
<>
|
||||
{isVersionSaved && activeModule === "simulation" && selectedProduct && (
|
||||
|
@ -42,7 +90,8 @@ function ComparisonScene() {
|
|||
</div>
|
||||
}
|
||||
<CompareLayOut />
|
||||
{(comparisonProduct && mainProduct && !loadingProgress) && <ComparisonResult />}
|
||||
|
||||
{(shouldShowComparisonResult && !loadingProgress) && <ComparisonResult />}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import {
|
||||
useLoadingProgress,
|
||||
useRenameModeStore,
|
||||
|
@ -42,7 +42,7 @@ function MainScene() {
|
|||
const { setMainProduct } = useMainProduct();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { isVersionSaved } = useSaveVersion();
|
||||
const { isVersionSaved, setIsVersionSaved } = useSaveVersion();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { selectedUser } = useSelectedUserStore();
|
||||
const { loadingProgress } = useLoadingProgress();
|
||||
|
@ -52,11 +52,19 @@ function MainScene() {
|
|||
const { visualizationSocket } = useSocketStore();
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { setFloatingWidget } = useFloatingWidget();
|
||||
const { comparisonProduct } = useComparisonProduct();
|
||||
const { clearComparisonProduct } = useComparisonProduct();
|
||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||
const { setName } = useAssetsStore();
|
||||
const { projectId } = useParams()
|
||||
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (activeModule !== 'simulation') {
|
||||
clearComparisonProduct();
|
||||
setIsVersionSaved(false);
|
||||
}
|
||||
}, [activeModule])
|
||||
|
||||
const handleSelectLayout = (option: string) => {
|
||||
const product = products.find((product) => product.productName === option);
|
||||
if (product) {
|
||||
|
@ -64,6 +72,7 @@ function MainScene() {
|
|||
}
|
||||
};
|
||||
const handleObjectRename = async (newName: string) => {
|
||||
if (!projectId) return
|
||||
const email = localStorage.getItem("email") ?? "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
let response = await setFloorItemApi(
|
||||
|
@ -99,10 +108,10 @@ function MainScene() {
|
|||
{activeModule !== "market" && !isPlaying && !isVersionSaved && (
|
||||
<Tools />
|
||||
)}
|
||||
{(isPlaying || comparisonProduct !== null) &&
|
||||
{(isPlaying) &&
|
||||
activeModule === "simulation" &&
|
||||
loadingProgress == 0 && <SimulationPlayer />}
|
||||
{(isPlaying || comparisonProduct !== null) &&
|
||||
{(isPlaying) &&
|
||||
activeModule !== "simulation" && <ControlsPlayer />}
|
||||
|
||||
{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 RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
||||
import { AnalysisPresetsType } from "../../../../types/analysis";
|
||||
|
@ -19,55 +19,70 @@ const Analysis: React.FC = () => {
|
|||
// { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } },
|
||||
],
|
||||
"Production capacity": [
|
||||
{ type: "range", inputs: { label: "Shift length", activeOption: "hr" } },
|
||||
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } },
|
||||
{ type: "default", inputs: { label: "Working days / year", activeOption: "days" } },
|
||||
{ type: "default", inputs: { label: "Yield rate", activeOption: "%" } },
|
||||
{ type: "range", inputs: { label: "Shift length", activeOption: "hr", defaultValue: 1 } },
|
||||
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit", defaultValue: 3 } },
|
||||
{ type: "default", inputs: { label: "Working days / year", activeOption: "days", defaultValue: 300 } },
|
||||
{ type: "default", inputs: { label: "Yield rate", activeOption: "%", defaultValue: 98 } },
|
||||
],
|
||||
ROI: [
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Selling price", activeOption: "INR" },
|
||||
inputs: { label: "Selling price", activeOption: "INR", defaultValue: 500 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Material cost", activeOption: "INR" },
|
||||
inputs: { label: "Material cost", activeOption: "INR", defaultValue: 300 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Labor Cost", activeOption: "INR" },
|
||||
inputs: { label: "Labor Cost", activeOption: "INR", defaultValue: 150 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Maintenance cost", activeOption: "INR" },
|
||||
inputs: { label: "Labor Count", activeOption: "", defaultValue: 1 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Electricity cost", activeOption: "INR" },
|
||||
inputs: { label: "Maintenance cost", activeOption: "INR", defaultValue: 1200 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Fixed costs", activeOption: "INR" },
|
||||
inputs: { label: "Electricity cost", activeOption: "INR", defaultValue: 840 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Initial Investment", activeOption: "INR" },
|
||||
inputs: { label: "Fixed costs", activeOption: "INR", defaultValue: 1150 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Salvage value", activeOption: "Hrs" },
|
||||
inputs: { label: "Initial Investment", activeOption: "INR", defaultValue: 3500000 },
|
||||
},
|
||||
{
|
||||
type: "default",
|
||||
inputs: { label: "Production period", activeOption: "yrs" },
|
||||
inputs: { label: "Salvage value", activeOption: "Day", defaultValue: 565 },
|
||||
},
|
||||
{
|
||||
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();
|
||||
|
||||
return (
|
||||
|
|
|
@ -10,7 +10,8 @@ interface InputRendererProps {
|
|||
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 (
|
||||
<div key={`main-${keyName}`} className="analysis-inputs">
|
||||
{presets.map((preset, index) => {
|
||||
|
@ -19,7 +20,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
|
|||
<InputWithDropDown
|
||||
key={index}
|
||||
label={preset.inputs.label}
|
||||
value={inputValues[preset.inputs.label] || ""}
|
||||
value={preset.inputs.defaultValue?.toString() || inputValues[preset.inputs.label] || ""}
|
||||
activeOption={preset.inputs.activeOption}
|
||||
onChange={(newValue) => onInputChange(preset.inputs.label, newValue)}
|
||||
/>
|
||||
|
@ -32,7 +33,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
|
|||
label={preset.inputs.label}
|
||||
min={0}
|
||||
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 RenameInput from "../../../ui/inputs/RenameInput";
|
||||
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 { generateUUID } from "three/src/math/MathUtils";
|
||||
import RenderOverlay from "../../../templates/Overlay";
|
||||
|
@ -48,6 +48,7 @@ const Simulations: React.FC = () => {
|
|||
const [processes, setProcesses] = useState<Event[][]>();
|
||||
const { setToggleUI } = useToggleStore();
|
||||
const { projectId } = useParams();
|
||||
const { setMainProduct } = useMainProduct();
|
||||
|
||||
const { comparePopUp, setComparePopUp } = useCompareStore();
|
||||
const { setIsVersionSaved } = useSaveVersion();
|
||||
|
@ -85,8 +86,13 @@ const Simulations: React.FC = () => {
|
|||
updatedProducts[newSelectedIndex].productUuid,
|
||||
updatedProducts[newSelectedIndex].productName
|
||||
);
|
||||
setMainProduct(
|
||||
updatedProducts[newSelectedIndex].productUuid,
|
||||
updatedProducts[newSelectedIndex].productName
|
||||
);
|
||||
} else {
|
||||
setSelectedProduct("", "");
|
||||
setMainProduct("", "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,6 +108,7 @@ const Simulations: React.FC = () => {
|
|||
renameProductApi({ productName: newName, productUuid, projectId: projectId || '' });
|
||||
if (selectedProduct.productUuid === productUuid) {
|
||||
setSelectedProduct(productUuid, newName);
|
||||
setMainProduct(productUuid, newName);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -172,9 +179,10 @@ const Simulations: React.FC = () => {
|
|||
{/* eslint-disable-next-line */}
|
||||
<div
|
||||
className="value"
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
setSelectedProduct(product.productUuid, product.productName)
|
||||
}
|
||||
setMainProduct(product.productUuid, product.productName)
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
|
|
|
@ -26,6 +26,8 @@ const ThroughputSummary: React.FC = () => {
|
|||
unit: "KWH",
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Dynamic shift data
|
||||
const shiftUtilization = [
|
||||
{ shift: 1, percentage: 30, color: "#F3C64D" },
|
||||
|
@ -126,7 +128,7 @@ const ThroughputSummary: React.FC = () => {
|
|||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
<span className="value">{productionCapacityData}</span>{" "}
|
||||
Units/hour
|
||||
Units/Month
|
||||
</div>
|
||||
<div className="lineChart">
|
||||
<div className="assetUsage">
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
import SemiCircleProgress from "./SemiCircleProgress";
|
||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
import { useROISummaryData } from "../../../store/builder/store";
|
||||
import { useInputValues, useROISummaryData } from "../../../store/builder/store";
|
||||
|
||||
const ROISummary = ({
|
||||
roiSummaryData = {
|
||||
|
@ -67,6 +67,8 @@ const ROISummary = ({
|
|||
},
|
||||
}) => {
|
||||
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
|
||||
const toggleTable = () => {
|
||||
|
@ -95,6 +97,17 @@ const 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 (
|
||||
<>
|
||||
|
||||
|
@ -121,25 +134,30 @@ const ROISummary = ({
|
|||
<SonarCrownIcon />
|
||||
<div className="icon"></div>
|
||||
<div className="info">
|
||||
<span> {roiSummary.roiPercentage}%</span> ROI with payback
|
||||
in just <span>{roiSummary.paybackPeriod}</span> months
|
||||
<span>{roiSummary.roiPercentage.toFixed(2)}% </span>
|
||||
ROI in the period of {productionPeriod} years
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="roi-details">
|
||||
<div className="progress-wrapper">
|
||||
<SemiCircleProgress />
|
||||
<SemiCircleProgress
|
||||
progress={(parseFloat(roiSummary.paybackPeriod.toFixed(2)) / (productionPeriod)) * 100}
|
||||
years={parseFloat(roiSummary.paybackPeriod.toFixed(2))}
|
||||
/>
|
||||
<div className="content">
|
||||
you're on track to hit it by
|
||||
<div className="key">July 2029</div>
|
||||
<div className="key">{getPaybackDateFromYears(roiSummary.paybackPeriod)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="metrics">
|
||||
<div className="metric-wrapper">
|
||||
<div className="metric-item">
|
||||
<span className="metric-label">Total Cost Incurred</span>
|
||||
<span className="metric-value">
|
||||
<span>₹</span>
|
||||
{roiSummary.totalCost}
|
||||
{roiSummary.totalCost.toFixed(0)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="metric-item">
|
||||
|
@ -147,7 +165,7 @@ const ROISummary = ({
|
|||
<span className="metric-value">
|
||||
<span>₹</span>
|
||||
|
||||
{roiSummary.revenueGenerated}
|
||||
{roiSummary.revenueGenerated.toFixed(0)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -161,8 +179,8 @@ const ROISummary = ({
|
|||
<div className="metric-value">
|
||||
<span>₹</span>
|
||||
{roiSummary.netProfit > 0
|
||||
? roiSummary.netProfit
|
||||
: roiSummary.netLoss}
|
||||
? roiSummary.netProfit.toFixed(0)
|
||||
: roiSummary.netLoss.toFixed(0)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 {
|
||||
ThroughputSummaryIcon,
|
||||
} from "../../icons/analysis";
|
||||
|
@ -14,14 +14,15 @@ const ProductionCapacity = ({
|
|||
const { machineActiveTime } = useMachineUptime();
|
||||
const { materialCycleTime } = useMaterialCycle();
|
||||
const { throughputData } = useThroughPutData()
|
||||
const { inputValues } = useInputValues();
|
||||
|
||||
const progressPercent = machineActiveTime;
|
||||
|
||||
const shiftLength = parseFloat(inputValues["Shift length"]);
|
||||
|
||||
const totalBars = 6;
|
||||
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
|
||||
const partialFillPercent =
|
||||
((progressPercent / 100) * totalBars - barsToFill) * 100;
|
||||
const partialFillPercent = ((progressPercent / 1000) * totalBars - barsToFill) * 100;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
|
@ -29,13 +30,14 @@ const ProductionCapacity = ({
|
|||
if (throughputData > 0) {
|
||||
setIsLoading(false);
|
||||
} else {
|
||||
setIsLoading(true);
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [throughputData])
|
||||
|
||||
const Units_per_hour = ((shiftLength * 60) / (materialCycleTime / 60) / shiftLength)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
{!isLoading && <div className="throughtputSummary-container analysis-card">
|
||||
<div className="throughtputSummary-wrapper analysis-card-wrapper">
|
||||
<div className="card-header">
|
||||
|
@ -53,8 +55,7 @@ const ProductionCapacity = ({
|
|||
<>
|
||||
<div className="process-container">
|
||||
<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>
|
||||
|
||||
{/* Dynamic Progress Bar */}
|
||||
|
|
|
@ -118,7 +118,6 @@ const CompareLayOut = () => {
|
|||
if (product) {
|
||||
setComparisonProduct(product.productUuid, product.productName);
|
||||
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 EnergyUsage from "./result-card/EnergyUsage";
|
||||
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 { 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(
|
||||
() => ({
|
||||
responsive: true,
|
||||
|
@ -25,11 +57,11 @@ const ComparisonResult = () => {
|
|||
const purpleLight = "#b19cd9";
|
||||
|
||||
const throughputData = {
|
||||
labels: ["Layout 1", "Layout 2"],
|
||||
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||
datasets: [
|
||||
{
|
||||
label: "Throughput (units/hr)",
|
||||
data: [500, 550],
|
||||
data: [comparedProducts[0]?.simulationData.throughputData, comparedProducts[1]?.simulationData.throughputData],
|
||||
backgroundColor: [purpleDark, purpleLight],
|
||||
borderColor: [purpleDark, purpleLight],
|
||||
borderWidth: 1,
|
||||
|
@ -41,11 +73,11 @@ const ComparisonResult = () => {
|
|||
|
||||
|
||||
const cycleTimePieData = {
|
||||
labels: ["Layout 1", "Layout 2"],
|
||||
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||
datasets: [
|
||||
{
|
||||
label: "Cycle Time (sec)",
|
||||
data: [120, 110],
|
||||
data: [comparedProducts[0]?.simulationData.machineActiveTime, comparedProducts[1]?.simulationData.machineActiveTime],
|
||||
backgroundColor: [purpleDark, purpleLight],
|
||||
borderColor: "#fff",
|
||||
borderWidth: 2,
|
||||
|
@ -54,11 +86,24 @@ const ComparisonResult = () => {
|
|||
};
|
||||
|
||||
const downtimeData = {
|
||||
labels: ["Layout 1", "Layout 2"],
|
||||
labels: [comparedProducts[0]?.productName, comparedProducts[1]?.productName],
|
||||
datasets: [
|
||||
{
|
||||
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],
|
||||
borderColor: [purpleDark, purpleLight],
|
||||
borderWidth: 1,
|
||||
|
@ -68,20 +113,21 @@ const ComparisonResult = () => {
|
|||
],
|
||||
};
|
||||
|
||||
const scrapRateData = {
|
||||
labels: ["Layout 1", "Layout 2"],
|
||||
datasets: [
|
||||
{
|
||||
label: "Scrap Rate (tons)",
|
||||
data: [2.7, 1.9],
|
||||
backgroundColor: [purpleDark, purpleLight],
|
||||
borderColor: [purpleDark, purpleLight],
|
||||
borderWidth: 1,
|
||||
borderRadius: 10,
|
||||
borderSkipped: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
const highestProductivityProduct = (comparedProducts[0]?.simulationData?.productionCapacity ?? 0) > (comparedProducts[1]?.simulationData?.productionCapacity ?? 0) ? comparedProducts[0] : comparedProducts[1];
|
||||
|
||||
const product1CyclePercentage = (comparedProducts[0]?.simulationData?.machineActiveTime ?? 0) /
|
||||
((compareProductsData[0]?.simulationData?.machineActiveTime ?? 0) +
|
||||
(compareProductsData[0]?.simulationData?.machineIdleTime ?? 0)) * 100;
|
||||
const product2CyclePercentage = ((comparedProducts[1]?.simulationData?.machineActiveTime ?? 0) /
|
||||
((compareProductsData[1]?.simulationData?.machineActiveTime ?? 0) +
|
||||
(compareProductsData[1]?.simulationData?.machineIdleTime ?? 0))) * 100;
|
||||
|
||||
const product1IdlePercentage = (comparedProducts[0]?.simulationData?.machineIdleTime ?? 0) /
|
||||
((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 (
|
||||
<div className="compare-result-container">
|
||||
|
@ -92,12 +138,12 @@ const ComparisonResult = () => {
|
|||
<h4>Throughput (units/hr)</h4>
|
||||
<div className="layers-wrapper">
|
||||
<div className="layer-wrapper">
|
||||
<div className="key">Layout 1</div>
|
||||
<div className="value">500/ hr</div>
|
||||
<div className="key">{comparedProducts[0]?.productName}</div>
|
||||
<div className="value">{comparedProducts[0]?.simulationData.throughputData}/ hr</div>
|
||||
</div>
|
||||
<div className="layer-wrapper">
|
||||
<div className="key">Layout 2</div>
|
||||
<div className="value">550/ hr</div>
|
||||
<div className="key">{comparedProducts[1]?.productName}</div>
|
||||
<div className="value">{comparedProducts[1]?.simulationData.throughputData}/ hr</div>
|
||||
</div>
|
||||
<div className="chart">
|
||||
<Bar data={throughputData} options={options} />
|
||||
|
@ -110,17 +156,17 @@ const ComparisonResult = () => {
|
|||
<div className="cycle-header">Cycle Time</div>
|
||||
<div className="layers-wrapper">
|
||||
<div className="layers">
|
||||
<div className="layer-name">Layout 1</div>
|
||||
<div className="layer-time">120 Sec</div>
|
||||
<div className="layer-name">{comparedProducts[0]?.productName}</div>
|
||||
<div className="layer-time">{compareProductsData[0]?.simulationData.machineActiveTime} Sec</div>
|
||||
<div className="layer-profit">
|
||||
<span>↑</span>19.6%
|
||||
<span>↑</span>{(100 - product1CyclePercentage).toFixed(2)}%
|
||||
</div>
|
||||
</div>
|
||||
<div className="layers">
|
||||
<div className="layer-name">Layout 2</div>
|
||||
<div className="layer-time">110 Sec</div>
|
||||
<div className="layer-name">{comparedProducts[1]?.productName}</div>
|
||||
<div className="layer-time">{compareProductsData[1]?.simulationData.machineActiveTime} Sec</div>
|
||||
<div className="layer-profit">
|
||||
<span>↑</span>1.6%
|
||||
<span>↑</span>{(100 - product2CyclePercentage).toFixed(2)}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -130,6 +176,31 @@ const ComparisonResult = () => {
|
|||
</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-header">Overall Downtime</div>
|
||||
<div className="totalDownTime-wrapper">
|
||||
|
@ -147,23 +218,23 @@ const ComparisonResult = () => {
|
|||
<Bar data={downtimeData} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<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-value">
|
||||
<div className="overallScrapRate-label">Layout 1</div>
|
||||
<div className="overallScrapRate-key">Total scrap produced by</div>
|
||||
<div className="overallScrapRateKey-value">2.7 ton</div>
|
||||
<div className="overallScrapRate-label">{highestProductivityProduct?.productName}</div>
|
||||
<div className="overallScrapRate-key">Total product produced</div>
|
||||
<div className="overallScrapRateKey-value">{highestProductivityProduct?.simulationData.productionCapacity}</div>
|
||||
</div>
|
||||
<div className="chart">
|
||||
<Bar data={scrapRateData} options={options} />
|
||||
<Bar data={productionCapacityData} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<PerformanceResult />
|
||||
{ comparedProducts.length === 2 &&<PerformanceResult comparedProducts={comparedProducts}/>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -20,27 +20,32 @@ ChartJS.register(
|
|||
);
|
||||
|
||||
const EnergyUsage = () => {
|
||||
const data = {
|
||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
||||
datasets: [
|
||||
{
|
||||
label: "Simulation 1",
|
||||
data: [400, 600, 450, 1000, 1000],
|
||||
borderColor: "#6a0dad",
|
||||
fill: false,
|
||||
tension: 0.5, // More curved line
|
||||
pointRadius: 0, // Remove point indicators
|
||||
},
|
||||
{
|
||||
label: "Simulation 2",
|
||||
data: [300, 500, 700, 950, 1100],
|
||||
borderColor: "#b19cd9",
|
||||
fill: false,
|
||||
tension: 0.5,
|
||||
pointRadius: 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
const data = useMemo(() => {
|
||||
const randomizeData = () =>
|
||||
Array.from({ length: 5 }, () => Math.floor(Math.random() * (2000 - 300 + 1)) + 300);
|
||||
|
||||
return {
|
||||
labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
||||
datasets: [
|
||||
{
|
||||
label: "Simulation 1",
|
||||
data: randomizeData(),
|
||||
borderColor: "#6a0dad",
|
||||
fill: false,
|
||||
tension: 0.5, // More curved line
|
||||
pointRadius: 0, // Remove point indicators
|
||||
},
|
||||
{
|
||||
label: "Simulation 2",
|
||||
data: randomizeData(),
|
||||
borderColor: "#b19cd9",
|
||||
fill: false,
|
||||
tension: 0.5,
|
||||
pointRadius: 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
}, []);
|
||||
|
||||
const options = useMemo(
|
||||
() => ({
|
||||
|
|
|
@ -5,7 +5,8 @@ import {
|
|||
TickIcon,
|
||||
} from "../../../icons/ExportCommonIcons";
|
||||
|
||||
const PerformanceResult = () => {
|
||||
const PerformanceResult = ({ comparedProducts }: any) => {
|
||||
const ProfitProduct = comparedProducts[0].simulationData.netProfit > comparedProducts[1].simulationData.netProfit ? comparedProducts[0] : comparedProducts[1];
|
||||
return (
|
||||
<div className="performanceResult-wrapper comparisionCard">
|
||||
<div className="header">
|
||||
|
@ -26,30 +27,30 @@ const PerformanceResult = () => {
|
|||
</div>
|
||||
<div className="metric-value">98%</div>
|
||||
</div>
|
||||
<div className="label">Environmental impact</div>
|
||||
<div className="label">Net Profit</div>
|
||||
</div>
|
||||
|
||||
<div className="metrics-right">
|
||||
<div className="metric-wrapper">
|
||||
<div className="metric-label">Waste generation</div>
|
||||
<div className="metric-label">ROI Percentage</div>
|
||||
<div className="metric">
|
||||
<div className="metric-icon">I</div>
|
||||
<div className="metric-value">0.5%</div>
|
||||
<div className="metric-icon"></div>
|
||||
<div className="metric-value">{ProfitProduct.simulationData.roiPercentage.toFixed(2)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="metric-wrapper">
|
||||
<div className="metric-label">Risk
management</div>
|
||||
<div className="metric-label">Payback Period</div>
|
||||
<div className="metric">
|
||||
<div className="metric-icon">I</div>
|
||||
<div className="metric-value">0.1%</div>
|
||||
<div className="metric-icon"></div>
|
||||
<div className="metric-value">{ProfitProduct.simulationData.netProfit}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="metric-wrapper">
|
||||
<div className="metric">
|
||||
<div className="metric-icon">I</div>
|
||||
<div className="metric-value">0.5%</div>
|
||||
<div className="metric-icon"></div>
|
||||
<div className="metric-value">{parseFloat(ProfitProduct.simulationData.paybackPeriod.toFixed(2))}years</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -147,7 +147,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||
projectId
|
||||
);
|
||||
// console.log("response: ", response);
|
||||
console.log(' zoneAssetId.id,: ', zoneAssetId.id,);
|
||||
console.log(' zoneAssetId.id,: ', zoneAssetId.id,);
|
||||
|
||||
setName(zoneAssetId.id, response.modelName);
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ const SimulationPlayer: React.FC = () => {
|
|||
<div className="icon">
|
||||
<HourlySimulationIcon />
|
||||
</div>
|
||||
<div className="label">ThroughPut Data</div>
|
||||
<div className="label">ThroughPut</div>
|
||||
</div>
|
||||
<div className="progress-wrapper">
|
||||
<div
|
||||
|
@ -202,7 +202,7 @@ const SimulationPlayer: React.FC = () => {
|
|||
<div className="icon">
|
||||
<DailyProductionIcon />
|
||||
</div>
|
||||
<div className="label">Daily Production</div>
|
||||
<div className="label">Production Capacity</div>
|
||||
</div>
|
||||
<div className="progress-wrapper">
|
||||
<div
|
||||
|
@ -217,7 +217,7 @@ const SimulationPlayer: React.FC = () => {
|
|||
<div className="icon">
|
||||
<MonthlyROI />
|
||||
</div>
|
||||
<div className="label">Monthly ROI</div>
|
||||
<div className="label">ROI</div>
|
||||
</div>
|
||||
<div className="progress-wrapper">
|
||||
<div
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as THREE from 'three';
|
||||
|
||||
import * as Types from "../../../../types/world/worldTypes";
|
||||
|
||||
function hideWalls(
|
||||
|
@ -7,21 +6,24 @@ function hideWalls(
|
|||
scene: THREE.Scene,
|
||||
camera: THREE.Camera
|
||||
): void {
|
||||
|
||||
////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera //////////
|
||||
|
||||
const v = new THREE.Vector3();
|
||||
const u = new THREE.Vector3();
|
||||
const wallNormal = new THREE.Vector3();
|
||||
const cameraToWall = new THREE.Vector3();
|
||||
const cameraDirection = new THREE.Vector3();
|
||||
|
||||
if (visibility === true) {
|
||||
for (const children of scene.children) {
|
||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||
children.children[0].children.forEach((child: any) => {
|
||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
||||
child.children[0].getWorldDirection(v);
|
||||
camera.getWorldDirection(u);
|
||||
if (child.children[0].material) {
|
||||
child.children[0].material.visible = (2 * v.dot(u)) >= -0.5;
|
||||
const wallMesh = child.children[0];
|
||||
wallMesh.getWorldDirection(wallNormal);
|
||||
cameraToWall.copy(wallMesh.position).sub(camera.position).normalize();
|
||||
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) {
|
||||
if (children.name === "Walls" && children.children[0]?.children.length > 0) {
|
||||
children.children[0].children.forEach((child: any) => {
|
||||
if (child.children[0]?.userData.WallType === "RoomWall") {
|
||||
if (child.children[0].material) {
|
||||
child.children[0].material.visible = true;
|
||||
}
|
||||
if (child.children[0]?.userData.WallType === "RoomWall" && child.children[0].material) {
|
||||
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("SelectionGroup") &&
|
||||
!intersect.object.name.includes("selectionAssetGroup") &&
|
||||
!intersect.object.name.includes("commentHolder") &&
|
||||
!intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
|
||||
!intersect.object.name.includes("SelectionGroupBoundingBox") &&
|
||||
!intersect.object.name.includes("SelectionGroupBoundingLine") &&
|
||||
|
@ -76,11 +77,13 @@ function CommentsGroup() {
|
|||
!intersect.object.name.includes("zonePlane") &&
|
||||
!intersect.object.name.includes("SelectionGroup") &&
|
||||
!intersect.object.name.includes("selectionAssetGroup") &&
|
||||
!intersect.object.name.includes("commentHolder") &&
|
||||
!intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
|
||||
!intersect.object.name.includes("SelectionGroupBoundingBox") &&
|
||||
!intersect.object.name.includes("SelectionGroupBoundingLine") &&
|
||||
intersect.object.type !== "GridHelper"
|
||||
);
|
||||
console.log('intersects: ', intersects);
|
||||
if (intersects.length > 0) {
|
||||
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 { Color } from "three";
|
||||
import { KeyboardControls } from "@react-three/drei";
|
||||
import { SceneProvider } from "./sceneContext";
|
||||
|
||||
|
@ -9,6 +8,12 @@ import Visualization from "../visualization/visualization";
|
|||
import Setup from "./setup/setup";
|
||||
import Simulation from "../simulation/simulation";
|
||||
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' }) {
|
||||
const map = useMemo(() => [
|
||||
|
@ -17,19 +22,76 @@ export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Co
|
|||
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
||||
{ 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 (
|
||||
<SceneProvider layout={layout}>
|
||||
<KeyboardControls map={map}>
|
||||
<Canvas
|
||||
id="sceneCanvas"
|
||||
shadows
|
||||
color="#aaaa"
|
||||
eventPrefix="client"
|
||||
gl={{ powerPreference: "high-performance", antialias: true }}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
onCreated={(e) => {
|
||||
e.scene.background = new Color(0x19191d);
|
||||
e.scene.background = null;
|
||||
}}
|
||||
gl={{ powerPreference: "high-performance", antialias: true, preserveDrawingBuffer: true }}
|
||||
>
|
||||
<Setup />
|
||||
<Collaboration />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
|
||||
import React, { useEffect } from 'react'
|
||||
import { CompareProduct, useCompareProductDataStore, useInputValues, useMachineDowntime, useMachineUptime, useProductionCapacityData, useROISummaryData, useThroughPutData } from '../../../../store/builder/store';
|
||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||
import { useProductContext } from '../../products/productContext';
|
||||
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
||||
|
@ -12,28 +12,31 @@ export default function ROIData() {
|
|||
const { isPlaying } = usePlayButtonStore();
|
||||
const { setRoiSummaryData } = useROISummaryData();
|
||||
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(() => {
|
||||
if (!isPlaying) {
|
||||
setRoiSummaryData({
|
||||
productName: "",
|
||||
roiPercentage: 0,
|
||||
paybackPeriod: 0,
|
||||
totalCost: 0,
|
||||
revenueGenerated: 0,
|
||||
netProfit: 0,
|
||||
netLoss: 0,
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputValues === undefined) return;
|
||||
if (isPlaying) return;
|
||||
setRoiSummaryData({
|
||||
productName: "",
|
||||
roiPercentage: 0,
|
||||
paybackPeriod: 0,
|
||||
totalCost: 0,
|
||||
revenueGenerated: 0,
|
||||
netProfit: 0,
|
||||
netLoss: 0,
|
||||
});
|
||||
}, [isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
if (inputValues === undefined || !isPlaying) return;
|
||||
const electricityCost = parseFloat(inputValues["Electricity cost"]);
|
||||
const fixedCost = parseFloat(inputValues["Fixed costs"]);
|
||||
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 productionPeriod = parseFloat(inputValues["Production period"]);
|
||||
const salvageValue = parseFloat(inputValues["Salvage value"]);
|
||||
|
@ -46,109 +49,146 @@ export default function ROIData() {
|
|||
if (!isNaN(electricityCost) && !isNaN(fixedCost) && !isNaN(laborCost) && !isNaN(maintenanceCost) &&
|
||||
!isNaN(materialCost) && !isNaN(productionPeriod) && !isNaN(salvageValue) && !isNaN(sellingPrice) &&
|
||||
!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({
|
||||
productName: selectedProduct.productName,
|
||||
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)), // normalized to 0.x format
|
||||
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
|
||||
roiPercentage: ROI,
|
||||
paybackPeriod: Payback_period_years,
|
||||
totalCost: Total_cost,
|
||||
revenueGenerated: Total_revenue,
|
||||
netProfit: Net_profit > 0 ? Net_profit : 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);
|
||||
|
||||
|
||||
setCompareProducts(prev => {
|
||||
const newData = {
|
||||
productUuid: productData?.productUuid,
|
||||
productName: productData?.productName,
|
||||
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,
|
||||
netLoss: netProfit < 0 ? parseFloat((-netProfit).toFixed(2)) : 0
|
||||
};
|
||||
|
||||
const existingIndex = prev.findIndex(
|
||||
item => item.productUuid === productData?.productUuid
|
||||
);
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
// Replace the existing item
|
||||
const updated = [...prev];
|
||||
updated[existingIndex] = newData;
|
||||
return updated;
|
||||
} else {
|
||||
// Add as new item
|
||||
return [...prev, newData];
|
||||
const prev = useCompareProductDataStore.getState().compareProductsData;
|
||||
const newData: CompareProduct = {
|
||||
productUuid: productData?.productUuid ?? '',
|
||||
productName: productData?.productName ?? '',
|
||||
simulationData: {
|
||||
// costPerUnit: costPerUnit,
|
||||
// workingDaysPerYear: workingDaysPerYear,
|
||||
// shiftLength: shiftLength,
|
||||
// shiftsPerDay: shiftsPerDay,
|
||||
roiPercentage: ROI,
|
||||
paybackPeriod: Payback_period_years,
|
||||
// paybackPeriod: paybackPeriod,
|
||||
// totalCost: totalAnnualCost,
|
||||
// revenueGenerated: annualRevenue,
|
||||
netProfit: Net_profit > 0 ? Net_profit : 0,
|
||||
productionCapacity: productionCapacityData,
|
||||
// netLoss: netProfit < 0 ? (-netProfit) : 0,
|
||||
machineIdleTime: machineIdleTime,
|
||||
machineActiveTime: machineActiveTime,
|
||||
throughputData: throughputData,
|
||||
}
|
||||
});
|
||||
// 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 { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
|
||||
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
||||
import { useProductContext } from '../../products/productContext';
|
||||
|
||||
export default function ProductionCapacityData() {
|
||||
const { throughputData } = useThroughPutData()
|
||||
const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
|
||||
const { inputValues } = useInputValues();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPlaying) {
|
||||
|
||||
setProductionCapacityData(0);
|
||||
return;
|
||||
}
|
||||
if (!inputValues || throughputData === undefined) return;
|
||||
}, [isPlaying]);
|
||||
|
||||
const shiftLength = parseFloat(inputValues["Shift length"]);
|
||||
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
|
||||
useEffect(() => {
|
||||
if (!inputValues || throughputData === undefined || !isPlaying) return;
|
||||
const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
|
||||
const yieldRate = parseFloat(inputValues["Yield rate"]);
|
||||
|
||||
if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) &&
|
||||
!isNaN(yieldRate) && throughputData >= 0) {
|
||||
// Total units produced per day before yield
|
||||
const dailyProduction = throughputData * shiftLength * shiftsPerDay;
|
||||
|
||||
if (!isNaN(workingDaysPerYear) && throughputData > 0) {
|
||||
const Monthly_working_days = workingDaysPerYear / 12;
|
||||
const Production_capacity_per_month = throughputData * Monthly_working_days;
|
||||
|
||||
// Units after applying yield rate
|
||||
const goodUnitsPerDay = dailyProduction * (yieldRate / 100);
|
||||
|
||||
|
||||
// Annual output
|
||||
const annualProduction = goodUnitsPerDay * workingDaysPerYear;
|
||||
|
||||
|
||||
// Final production capacity per hour (after yield)
|
||||
const productionPerHour = throughputData * (yieldRate / 100);
|
||||
|
||||
|
||||
// Set the final capacity (units/hour)
|
||||
setProductionCapacityData(Number(productionPerHour.toFixed(2)));
|
||||
setProductionCapacityData(Number(Production_capacity_per_month.toFixed(2)));
|
||||
}
|
||||
}, [throughputData, inputValues]);
|
||||
}, [throughputData, inputValues, isPlaying]);
|
||||
|
||||
return (
|
||||
<></>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
||||
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 { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useProductContext } from '../../products/productContext';
|
||||
import { set } from 'immer/dist/internal';
|
||||
|
||||
export default function ThroughPutData() {
|
||||
const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext();
|
||||
|
@ -19,25 +20,34 @@ export default function ThroughPutData() {
|
|||
const { materialHistory, materials } = materialStore();
|
||||
const { machineCount, setMachineCount } = useMachineCount();
|
||||
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
|
||||
const { machineIdleTime, setMachineIdleTime } = useMachineDowntime();
|
||||
const { materialCycleTime, setMaterialCycleTime } = useMaterialCycle();
|
||||
const { setProcessBar } = useProcessBar();
|
||||
const { setThroughputData } = useThroughPutData()
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { inputValues } = useInputValues();
|
||||
|
||||
// Setting machine count
|
||||
let totalItems = 0;
|
||||
let totalActiveTime = 0;
|
||||
let totalIdleTime = 0
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPlaying) {
|
||||
totalActiveTime = 0;
|
||||
totalItems = 0;
|
||||
totalIdleTime = 0;
|
||||
setMachineCount(0);
|
||||
setMachineActiveTime(0);
|
||||
setMachineIdleTime(0);
|
||||
setMaterialCycleTime(0);
|
||||
setProcessBar([]);
|
||||
setThroughputData(0);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
}, [isPlaying])
|
||||
|
||||
useEffect(() => {
|
||||
if (isPlaying) {
|
||||
let process: any = [];
|
||||
const fetchProductSequenceData = async () => {
|
||||
const productData = getProductById(selectedProduct.productUuid);
|
||||
|
@ -53,6 +63,9 @@ export default function ThroughPutData() {
|
|||
process.push({ modelid: arm.modelUuid, modelName: arm.modelName, activeTime: arm?.activeTime })
|
||||
totalActiveTime += arm.activeTime;
|
||||
}
|
||||
if (arm.idleTime > 0) {
|
||||
totalIdleTime += arm.idleTime;
|
||||
}
|
||||
});
|
||||
} else if (item.type === "vehicle") {
|
||||
vehicles.filter(vehicle => vehicle.modelUuid === item.modelUuid)
|
||||
|
@ -62,6 +75,9 @@ export default function ThroughPutData() {
|
|||
|
||||
totalActiveTime += vehicle.activeTime;
|
||||
}
|
||||
if (vehicle.idleTime > 0) {
|
||||
totalIdleTime += vehicle.idleTime;
|
||||
}
|
||||
});
|
||||
} else if (item.type === "machine") {
|
||||
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 })
|
||||
totalActiveTime += machine.activeTime;
|
||||
}
|
||||
if (machine.idleTime > 0) {
|
||||
totalIdleTime += machine.idleTime;
|
||||
}
|
||||
});
|
||||
} else if (item.type === "transfer") {
|
||||
conveyors.filter(conveyor => conveyor.modelUuid === item.modelUuid)
|
||||
|
@ -83,7 +102,7 @@ export default function ThroughPutData() {
|
|||
.forEach(storage => {
|
||||
if (storage.activeTime > 0) {
|
||||
// totalActiveTime += storage.activeTime;
|
||||
//
|
||||
//
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -92,9 +111,10 @@ export default function ThroughPutData() {
|
|||
totalItems += sequence.length;
|
||||
});
|
||||
|
||||
|
||||
|
||||
setMachineCount(totalItems);
|
||||
setMachineActiveTime(totalActiveTime);
|
||||
setMachineIdleTime(totalIdleTime);
|
||||
let arr = process.map((item: any) => ({
|
||||
name: item.modelName,
|
||||
completed: Math.round((item.activeTime / totalActiveTime) * 100)
|
||||
|
@ -107,15 +127,15 @@ export default function ThroughPutData() {
|
|||
fetchProductSequenceData();
|
||||
}
|
||||
// if (materialCycleTime <= 0) return
|
||||
}, [products, selectedProduct, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
|
||||
}, [products, selectedProduct?.productUuid, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
|
||||
|
||||
useEffect(() => {
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
async function getMachineActive() {
|
||||
const productData = getProductById(selectedProduct.productUuid);
|
||||
let anyArmActive;
|
||||
let anyVehicleActive;
|
||||
let anyMachineActive;
|
||||
|
||||
if (productData) {
|
||||
const productSequenceData = await determineExecutionMachineSequences([productData]);
|
||||
if (productSequenceData?.length > 0) {
|
||||
|
@ -160,8 +180,8 @@ export default function ThroughPutData() {
|
|||
}
|
||||
|
||||
const allInactive = !anyArmActive && !anyVehicleActive && !anyMachineActive;
|
||||
if (allInactive && materials.length === 0 && materialHistory.length > 0) {
|
||||
|
||||
if (materials.length >= 0 && materialHistory.length > 0) {
|
||||
|
||||
let totalCycleTimeSum = 0;
|
||||
let cycleCount = 0;
|
||||
|
||||
|
@ -182,21 +202,28 @@ export default function ThroughPutData() {
|
|||
}
|
||||
}
|
||||
if (isPlaying) {
|
||||
setTimeout(() => {
|
||||
timeoutId = setTimeout(() => {
|
||||
getMachineActive();
|
||||
}, 500)
|
||||
}, 1500);
|
||||
}
|
||||
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct])
|
||||
|
||||
return () => {
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
};
|
||||
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct?.productUuid])
|
||||
|
||||
useEffect(() => {
|
||||
if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
|
||||
const utilization = machineActiveTime / 3600; // Active time per hour
|
||||
const unitsPerMachinePerHour = 3600 / materialCycleTime;
|
||||
const throughput = unitsPerMachinePerHour * machineCount * utilization;
|
||||
setThroughputData(Number(throughput.toFixed(2))); // Keep as number
|
||||
//
|
||||
const shiftLength = parseFloat(inputValues["Shift length"]);
|
||||
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
|
||||
const yieldRate = parseFloat(inputValues["Yield rate"]);
|
||||
|
||||
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 (
|
||||
<>
|
||||
|
|
|
@ -13,6 +13,7 @@ function Products() {
|
|||
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout } = useSceneContext();
|
||||
const { products, getProductById, addProduct, setProducts } = useProductStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { setMainProduct } = useMainProduct();
|
||||
const { selectedProduct, setSelectedProduct } = selectedProductStore();
|
||||
const { addVehicle, clearvehicles } = vehicleStore();
|
||||
const { addArmBot, clearArmBots } = armBotStore();
|
||||
|
@ -51,11 +52,13 @@ function Products() {
|
|||
})
|
||||
if (layout === 'Main Layout') {
|
||||
setSelectedProduct(id, name);
|
||||
setMainProduct(id, name);
|
||||
}
|
||||
} else {
|
||||
setProducts(data);
|
||||
if (layout === 'Main Layout') {
|
||||
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(
|
||||
(start: any, end: any) => {
|
||||
console.log('end: ', end);
|
||||
try {
|
||||
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||
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].z) == Math.round(end.z)
|
||||
) {
|
||||
console.log('if ', segmentPath);
|
||||
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
|
||||
} else {
|
||||
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];
|
||||
try {
|
||||
const res = await signInApi(email, password, organization, fingerprint);
|
||||
console.log('res: ', res);
|
||||
// console.log('res: ', res);
|
||||
if (res.message.message === "login successfull") {
|
||||
setError("");
|
||||
setOrganization(organization);
|
||||
|
@ -56,10 +56,10 @@ const UserAuth: React.FC = () => {
|
|||
localStorage.setItem("refreshToken", res.message.refreshToken);
|
||||
|
||||
try {
|
||||
console.log('res.message.userId: ', res.message.userId);
|
||||
console.log('organization: ', organization);
|
||||
// console.log('res.message.userId: ', res.message.userId);
|
||||
// console.log('organization: ', organization);
|
||||
const projects = await recentlyViewed(organization, res.message.userId);
|
||||
console.log('projects: ', projects);
|
||||
// console.log('projects: ', projects);
|
||||
|
||||
if (res.message.isShare) {
|
||||
if (Object.values(projects.RecentlyViewed).length > 0) {
|
||||
|
|
|
@ -3,26 +3,25 @@ export const setFloorItemApi = async (
|
|||
organization: string,
|
||||
modelUuid?: string,
|
||||
modelName?: string,
|
||||
assetId?: string,
|
||||
projectId?: string,
|
||||
assetId?: string,
|
||||
position?: Object,
|
||||
rotation?: Object,
|
||||
isLocked?: boolean,
|
||||
isVisible?: boolean
|
||||
isVisible?: boolean,
|
||||
) => {
|
||||
try {
|
||||
const body: any = {
|
||||
organization,
|
||||
modelUuid,
|
||||
modelName,
|
||||
projectId,
|
||||
position,
|
||||
rotation,
|
||||
assetId,
|
||||
isLocked,
|
||||
isVisible,
|
||||
projectId,
|
||||
};
|
||||
|
||||
const response = await fetch(`${url_Backend_dwinzo}/api/V1/setAsset`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
|
@ -26,7 +26,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
|
|||
auth: { token },
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
const dashBoardSocket = io(
|
||||
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`,
|
||||
|
@ -546,6 +546,10 @@ export const useMachineUptime = create<any>((set: any) => ({
|
|||
machineActiveTime: 0,
|
||||
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) => ({
|
||||
materialCycleTime: 0,
|
||||
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
|
||||
|
@ -709,3 +713,32 @@ function getInitialViewSceneLabels(): boolean {
|
|||
const saved = localStorage.getItem('viewSceneLabels');
|
||||
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: () => {
|
||||
set((state) => {
|
||||
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-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
|
|
|
@ -657,7 +657,7 @@
|
|||
|
||||
path {
|
||||
stroke: var(--text-button-color);
|
||||
stroke-width: 1.3;
|
||||
strokeWidth: 1.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1021,7 +1021,7 @@
|
|||
|
||||
path {
|
||||
stroke: var(--accent-color);
|
||||
stroke-width: 1.5px;
|
||||
strokeWidth: 1.5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
|
|
@ -5,6 +5,7 @@ type Preset = {
|
|||
activeOption: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
defaultValue?: string | number;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue