2025-05-14 08:55:54 +00:00
|
|
|
import React, { useEffect, useState } from 'react'
|
|
|
|
import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
|
2025-05-15 12:30:07 +00:00
|
|
|
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
|
2025-05-29 06:30:16 +00:00
|
|
|
import { useProductContext } from '../../products/productContext';
|
2025-06-10 12:36:41 +00:00
|
|
|
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
2025-05-14 04:27:31 +00:00
|
|
|
|
|
|
|
export default function ROIData() {
|
2025-05-29 06:30:16 +00:00
|
|
|
const { selectedProductStore } = useProductContext();
|
2025-05-14 04:27:31 +00:00
|
|
|
const { inputValues } = useInputValues();
|
|
|
|
const { productionCapacityData } = useProductionCapacityData()
|
2025-05-29 06:30:16 +00:00
|
|
|
const { selectedProduct } = selectedProductStore();
|
2025-05-15 12:30:07 +00:00
|
|
|
const { isPlaying } = usePlayButtonStore();
|
2025-05-14 08:55:54 +00:00
|
|
|
const { setRoiSummaryData } = useROISummaryData();
|
2025-06-10 12:36:41 +00:00
|
|
|
const { products, getProductById } = useProductStore();
|
|
|
|
const [compareProducts, setCompareProducts] = useState<any[]>([]);
|
|
|
|
|
2025-05-14 04:27:31 +00:00
|
|
|
useEffect(() => {
|
2025-05-15 12:30:07 +00:00
|
|
|
if (!isPlaying) {
|
|
|
|
setRoiSummaryData({
|
|
|
|
productName: "",
|
|
|
|
roiPercentage: 0,
|
|
|
|
paybackPeriod: 0,
|
|
|
|
totalCost: 0,
|
|
|
|
revenueGenerated: 0,
|
|
|
|
netProfit: 0,
|
|
|
|
netLoss: 0,
|
|
|
|
})
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-05-14 04:27:31 +00:00
|
|
|
if (inputValues === undefined) 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 materialCost = parseFloat(inputValues["Material cost"]);
|
|
|
|
const productionPeriod = parseFloat(inputValues["Production period"]);
|
|
|
|
const salvageValue = parseFloat(inputValues["Salvage value"]);
|
|
|
|
const sellingPrice = parseFloat(inputValues["Selling price"]);
|
|
|
|
const initialInvestment = parseFloat(inputValues["Initial Investment"]);
|
|
|
|
const shiftLength = parseFloat(inputValues["Shift length"]);
|
|
|
|
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
|
|
|
|
const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
2025-05-15 12:30:07 +00:00
|
|
|
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;
|
2025-06-10 12:36:41 +00:00
|
|
|
|
2025-05-15 12:30:07 +00:00
|
|
|
// Net Profit over production period
|
|
|
|
const netProfit = annualProfit * productionPeriod;
|
|
|
|
// ROI
|
|
|
|
const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
|
2025-05-14 04:27:31 +00:00
|
|
|
// Payback Period
|
2025-05-15 12:30:07 +00:00
|
|
|
const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0
|
2025-06-10 12:36:41 +00:00
|
|
|
|
2025-05-14 12:51:49 +00:00
|
|
|
|
2025-06-10 12:36:41 +00:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2025-05-14 08:55:54 +00:00
|
|
|
|
|
|
|
setRoiSummaryData({
|
2025-05-14 12:51:49 +00:00
|
|
|
productName: selectedProduct.productName,
|
2025-05-15 12:30:07 +00:00
|
|
|
roiPercentage: parseFloat((roiPercentage / 100).toFixed(2)), // normalized to 0.x format
|
2025-05-14 12:51:49 +00:00
|
|
|
paybackPeriod: parseFloat(paybackPeriod.toFixed(2)),
|
2025-05-15 12:30:07 +00:00
|
|
|
totalCost: parseFloat(totalAnnualCost.toFixed(2)),
|
|
|
|
revenueGenerated: parseFloat(annualRevenue.toFixed(2)),
|
|
|
|
netProfit: netProfit > 0 ? parseFloat(netProfit.toFixed(2)) : 0,
|
|
|
|
netLoss: netProfit < 0 ? -netProfit : 0
|
2025-05-14 08:55:54 +00:00
|
|
|
});
|
2025-05-14 04:27:31 +00:00
|
|
|
|
2025-05-15 12:30:07 +00:00
|
|
|
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;
|
|
|
|
|
2025-06-10 12:36:41 +00:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
console.log('compareProducts: ', compareProducts);
|
|
|
|
|
2025-05-14 04:27:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}, [inputValues, productionCapacityData]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<></>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
|