updated comparision
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user