([]);
+ const { compareProductsData, setCompareProductsData } = useCompareProductDataStore();
+ const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
+ const { machineIdleTime, setMachineIdleTime } = useMachineDowntime();
+ const { throughputData } = useThroughPutData()
useEffect(() => {
- if (!isPlaying) {
- console.log("running ROIData effect");
- setRoiSummaryData({
- productName: "",
- roiPercentage: 0,
- paybackPeriod: 0,
- totalCost: 0,
- revenueGenerated: 0,
- netProfit: 0,
- netLoss: 0,
- })
+ if (isPlaying) return;
+ setRoiSummaryData({
+ productName: "",
+ roiPercentage: 0,
+ paybackPeriod: 0,
+ totalCost: 0,
+ revenueGenerated: 0,
+ netProfit: 0,
+ netLoss: 0,
+ });
+ }, [isPlaying]);
- return;
- }
- if (inputValues === undefined) return;
+ 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 maintenanceCost = parseFloat(inputValues["Maintenance cost"]);
const materialCost = parseFloat(inputValues["Material cost"]);
const productionPeriod = parseFloat(inputValues["Production period"]);
const salvageValue = parseFloat(inputValues["Salvage value"]);
@@ -46,32 +49,26 @@ 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) {
+ console.log('productionCapacityData: ', productionCapacityData);
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 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)), // normalized to 0.x format
+ roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)),
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
@@ -80,77 +77,54 @@ export default function ROIData() {
});
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)),
+ 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)),
+ // 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];
+ // 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]);
+ }
}
- }, [inputValues, productionCapacityData, selectedProduct?.productUuid]);
+ }, [inputValues, productionCapacityData, selectedProduct?.productUuid, isPlaying]);
+
useEffect(() => {
+ console.log('compareProductsData: ', compareProductsData);
+ }, [compareProductsData])
- console.log('compareProducts: ', compareProducts);
- }, [compareProducts]);
- useEffect(() => {
- // Clear ROI summary data when product changes
- setRoiSummaryData({
- productName: "",
- roiPercentage: 0,
- paybackPeriod: 0,
- totalCost: 0,
- revenueGenerated: 0,
- netProfit: 0,
- netLoss: 0,
- });
-
- // Optionally clear comparison data for this product only
- setCompareProducts(prev => prev.filter(p => p.productUuid !== selectedProduct.productUuid));
- }, [selectedProduct?.productUuid]);
-
- return (
- <>>
- )
+ return null;
}
-
-
diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx
index a9966ef..ced9ddc 100644
--- a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx
+++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx
@@ -13,10 +13,14 @@ export default function ProductionCapacityData() {
useEffect(() => {
if (!isPlaying) {
+ console.log('isPlaying: ', isPlaying);
setProductionCapacityData(0);
- return;
}
- if (!inputValues || throughputData === undefined) return;
+ }, [isPlaying]);
+
+ useEffect(() => {
+ if (!inputValues || throughputData === undefined || !isPlaying) return;
+ console.log('throughputData: ', throughputData);
const shiftLength = parseFloat(inputValues["Shift length"]);
console.log('shiftLength: ', shiftLength);
@@ -49,12 +53,7 @@ export default function ProductionCapacityData() {
// Set the final capacity (units/hour)
setProductionCapacityData(Number(productionPerHour.toFixed(2)));
}
- }, [throughputData, inputValues]);
- useEffect(() => {
-
- setProductionCapacityData(0);
-
- }, [selectedProduct?.productUuid]);
+ }, [throughputData, inputValues, isPlaying]);
return (
<>>
diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx
index fa43e0b..72189e0 100644
--- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx
+++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx
@@ -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 { 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,6 +20,7 @@ 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()
@@ -27,17 +29,24 @@ export default function ThroughPutData() {
// 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 +62,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 +74,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 +85,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)
@@ -95,6 +113,7 @@ export default function ThroughPutData() {
setMachineCount(totalItems);
setMachineActiveTime(totalActiveTime);
+ setMachineIdleTime(totalIdleTime);
let arr = process.map((item: any) => ({
name: item.modelName,
completed: Math.round((item.activeTime / totalActiveTime) * 100)
@@ -193,23 +212,13 @@ export default function ThroughPutData() {
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct?.productUuid])
useEffect(() => {
- if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
+ if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0 && isPlaying) {
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
- //
}
- }, [machineActiveTime, materialCycleTime, machineCount, selectedProduct?.productUuid]);
- useEffect(() => {
- totalActiveTime = 0;
- totalItems = 0;
- setMachineCount(0);
- setMachineActiveTime(0);
- setMaterialCycleTime(0);
- setProcessBar([]);
- setThroughputData(0);
- }, [selectedProduct?.productUuid]);
+ }, [machineActiveTime, materialCycleTime, machineCount, selectedProduct?.productUuid, isPlaying]);
return (
<>
diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx
index 0b26902..a242f5b 100644
--- a/app/src/modules/simulation/products/products.tsx
+++ b/app/src/modules/simulation/products/products.tsx
@@ -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);
}
}
})
diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts
index 4502c71..eba4c47 100644
--- a/app/src/store/builder/store.ts
+++ b/app/src/store/builder/store.ts
@@ -26,7 +26,7 @@ export const useSocketStore = create
((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((set: any) => ({
machineActiveTime: 0,
setMachineActiveTime: (x: any) => set({ machineActiveTime: x }),
}));
+export const useMachineDowntime = create((set: any) => ({
+ machineIdleTime: 0,
+ setMachineIdleTime: (x: any) => set({ machineIdleTime: x }),
+}));
export const useMaterialCycle = create((set: any) => ({
materialCycleTime: 0,
setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }),
@@ -709,3 +713,30 @@ 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;
+ // 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 }),
+}));
\ No newline at end of file
diff --git a/app/src/store/useCompareProductStore.ts b/app/src/store/useCompareProductStore.ts
new file mode 100644
index 0000000..d5972f8
--- /dev/null
+++ b/app/src/store/useCompareProductStore.ts
@@ -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;
+}
+
diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss
index b043e29..d5e1a6c 100644
--- a/app/src/styles/layout/sidebar.scss
+++ b/app/src/styles/layout/sidebar.scss
@@ -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 {