feat: Add default values to analysis presets and enhance input handling in components

This commit is contained in:
Gomathi 2025-06-11 16:33:21 +05:30
parent 5d03a2bc61
commit 7e85cf4e53
10 changed files with 108 additions and 63 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { AIIcon } from "../../../icons/ExportCommonIcons"; import { AIIcon } from "../../../icons/ExportCommonIcons";
import RegularDropDown from "../../../ui/inputs/RegularDropDown"; import RegularDropDown from "../../../ui/inputs/RegularDropDown";
import { AnalysisPresetsType } from "../../../../types/analysis"; import { AnalysisPresetsType } from "../../../../types/analysis";
@ -19,55 +19,66 @@ const Analysis: React.FC = () => {
// { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } }, // { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } },
], ],
"Production capacity": [ "Production capacity": [
{ type: "range", inputs: { label: "Shift length", activeOption: "hr" } }, { type: "range", inputs: { label: "Shift length", activeOption: "hr", defaultValue: 8 } },
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } }, { type: "default", inputs: { label: "Shifts / day", activeOption: "unit", defaultValue: 2 } },
{ type: "default", inputs: { label: "Working days / year", activeOption: "days" } }, { type: "default", inputs: { label: "Working days / year", activeOption: "days", defaultValue: 300 } },
{ type: "default", inputs: { label: "Yield rate", activeOption: "%" } }, { type: "default", inputs: { label: "Yield rate", activeOption: "%", defaultValue: 90 } },
], ],
ROI: [ ROI: [
{ {
type: "default", type: "default",
inputs: { label: "Selling price", activeOption: "INR" }, inputs: { label: "Selling price", activeOption: "INR", defaultValue: 1500 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Material cost", activeOption: "INR" }, inputs: { label: "Material cost", activeOption: "INR", defaultValue: 300 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Labor Cost", activeOption: "INR" }, inputs: { label: "Labor Cost", activeOption: "INR", defaultValue: 200 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Maintenance cost", activeOption: "INR" }, inputs: { label: "Maintenance cost", activeOption: "INR", defaultValue: 1200 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Electricity cost", activeOption: "INR" }, inputs: { label: "Electricity cost", activeOption: "INR", defaultValue: 1000 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Fixed costs", activeOption: "INR" }, inputs: { label: "Fixed costs", activeOption: "INR", defaultValue: 5000 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Initial Investment", activeOption: "INR" }, inputs: { label: "Initial Investment", activeOption: "INR", defaultValue: 100000 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Salvage value", activeOption: "Hrs" }, inputs: { label: "Salvage value", activeOption: "Hrs", defaultValue: 5000 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Production period", activeOption: "yrs" }, inputs: { label: "Production period", activeOption: "yrs", defaultValue: 5 },
}, },
{ {
type: "default", type: "default",
inputs: { label: "Tax rate", activeOption: "%" }, inputs: { label: "Tax rate", activeOption: "%", defaultValue: 30 },
}, },
], ],
}; };
useEffect(() => {
Object.values(AnalysisPresets).forEach((category) => {
category.forEach((item) => {
const { label, defaultValue } = item.inputs;
if (defaultValue !== undefined) {
updateInputValue(label, defaultValue.toString());
}
});
});
}, []);
const { inputValues, setInputValues, updateInputValue } = useInputValues(); const { inputValues, setInputValues, updateInputValue } = useInputValues();
return ( return (

View File

@ -10,7 +10,8 @@ interface InputRendererProps {
onInputChange: (label: string, value: string) => void; onInputChange: (label: string, value: string) => void;
} }
const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,inputValues, onInputChange }) => { const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets, inputValues, onInputChange }) => {
return ( return (
<div key={`main-${keyName}`} className="analysis-inputs"> <div key={`main-${keyName}`} className="analysis-inputs">
{presets.map((preset, index) => { {presets.map((preset, index) => {
@ -19,7 +20,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
<InputWithDropDown <InputWithDropDown
key={index} key={index}
label={preset.inputs.label} label={preset.inputs.label}
value={inputValues[preset.inputs.label] || ""} value={preset.inputs.defaultValue?.toString() || inputValues[preset.inputs.label] || ""}
activeOption={preset.inputs.activeOption} activeOption={preset.inputs.activeOption}
onChange={(newValue) => onInputChange(preset.inputs.label, newValue)} onChange={(newValue) => onInputChange(preset.inputs.label, newValue)}
/> />
@ -32,7 +33,7 @@ const RenderAnalysisInputs: React.FC<InputRendererProps> = ({ keyName, presets,i
label={preset.inputs.label} label={preset.inputs.label}
min={0} min={0}
max={8} max={8}
value={5} value={Number(preset.inputs.defaultValue) || Number(inputValues[preset.inputs.label]) || 5}
/> />
); );
} }

View File

@ -26,6 +26,7 @@ const ProductionCapacity = ({
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
useEffect(() => { useEffect(() => {
console.log('throughputData: ', throughputData);
if (throughputData > 0) { if (throughputData > 0) {
setIsLoading(false); setIsLoading(false);
} else { } else {

View File

@ -122,7 +122,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
zoneUuid: selectedZone.zoneUuid, zoneUuid: selectedZone.zoneUuid,
zoneName: newName, zoneName: newName,
}; };
const response = await zoneCameraUpdate(zonesdata, organization,projectId); const response = await zoneCameraUpdate(zonesdata, organization, projectId);
if (response.message === "zone updated") { if (response.message === "zone updated") {
setSelectedZone((prev) => ({ ...prev, zoneName: newName })); setSelectedZone((prev) => ({ ...prev, zoneName: newName }));
setZones((prevZones: any[]) => setZones((prevZones: any[]) =>
@ -143,9 +143,10 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
let response = await setFloorItemApi( let response = await setFloorItemApi(
organization, organization,
zoneAssetId.id, zoneAssetId.id,
newName newName,
projectId
); );
// console.log("response: ", response); console.log("response: ", response);
setName(zoneAssetId.id, response.modelName); setName(zoneAssetId.id, response.modelName);
} }

View File

@ -16,6 +16,7 @@ export default function ROIData() {
useEffect(() => { useEffect(() => {
if (!isPlaying) { if (!isPlaying) {
console.log("running ROIData effect");
setRoiSummaryData({ setRoiSummaryData({
productName: "", productName: "",
roiPercentage: 0, roiPercentage: 0,
@ -25,11 +26,10 @@ export default function ROIData() {
netProfit: 0, netProfit: 0,
netLoss: 0, netLoss: 0,
}) })
return; return;
} }
if (inputValues === undefined) return; if (inputValues === undefined) return;
const electricityCost = parseFloat(inputValues["Electricity cost"]); const electricityCost = parseFloat(inputValues["Electricity cost"]);
const fixedCost = parseFloat(inputValues["Fixed costs"]); const fixedCost = parseFloat(inputValues["Fixed costs"]);
const laborCost = parseFloat(inputValues["Labor Cost"]); const laborCost = parseFloat(inputValues["Labor Cost"]);
@ -60,23 +60,14 @@ export default function ROIData() {
const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost; const totalAnnualCost = totalMaterialCost + totalLaborCost + totalEnergyCost + totalMaintenanceCost;
// Annual Profit // Annual Profit
const annualProfit = annualRevenue - totalAnnualCost; const annualProfit = annualRevenue - totalAnnualCost;
// Net Profit over production period // Net Profit over production period
const netProfit = annualProfit * productionPeriod; const netProfit = annualProfit * productionPeriod;
// ROI // ROI
const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100; const roiPercentage = ((netProfit + salvageValue - initialInvestment) / initialInvestment) * 100;
// Payback Period // Payback Period
const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0 const paybackPeriod = initialInvestment / (annualProfit || 1); // Avoid division by 0
//
//
//
//
//
//
//
//
setRoiSummaryData({ setRoiSummaryData({
productName: selectedProduct.productName, productName: selectedProduct.productName,
@ -99,17 +90,9 @@ export default function ROIData() {
const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0; const netProfitForTarget = profitForTargetUnits > 0 ? profitForTargetUnits : 0;
const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0; const netLossForTarget = profitForTargetUnits < 0 ? -profitForTargetUnits : 0;
//
//
//
//
//
//
const productData = getProductById(selectedProduct.productUuid); const productData = getProductById(selectedProduct.productUuid);
setCompareProducts(prev => { setCompareProducts(prev => {
const newData = { const newData = {
productUuid: productData?.productUuid, productUuid: productData?.productUuid,
@ -140,11 +123,30 @@ export default function ROIData() {
return [...prev, newData]; return [...prev, newData];
} }
}); });
// console.log('compareProducts: ', compareProducts);
} }
}, [inputValues, productionCapacityData]); }, [inputValues, productionCapacityData, selectedProduct?.productUuid]);
useEffect(() => {
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 (
<></> <></>

View File

@ -1,12 +1,15 @@
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store' import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store'
import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore';
import { useProductContext } from '../../products/productContext';
export default function ProductionCapacityData() { export default function ProductionCapacityData() {
const { throughputData } = useThroughPutData() const { throughputData } = useThroughPutData()
const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData() const { productionCapacityData, setProductionCapacityData } = useProductionCapacityData()
const { inputValues } = useInputValues(); const { inputValues } = useInputValues();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
useEffect(() => { useEffect(() => {
if (!isPlaying) { if (!isPlaying) {
@ -16,32 +19,42 @@ export default function ProductionCapacityData() {
if (!inputValues || throughputData === undefined) return; if (!inputValues || throughputData === undefined) return;
const shiftLength = parseFloat(inputValues["Shift length"]); const shiftLength = parseFloat(inputValues["Shift length"]);
console.log('shiftLength: ', shiftLength);
const shiftsPerDay = parseFloat(inputValues["Shifts / day"]); const shiftsPerDay = parseFloat(inputValues["Shifts / day"]);
const workingDaysPerYear = parseFloat(inputValues["Working days / year"]); const workingDaysPerYear = parseFloat(inputValues["Working days / year"]);
const yieldRate = parseFloat(inputValues["Yield rate"]); const yieldRate = parseFloat(inputValues["Yield rate"]);
if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) &&
!isNaN(yieldRate) && throughputData >= 0) { !isNaN(yieldRate) && throughputData > 0) {
// Total units produced per day before yield // Total units produced per day before yield
const dailyProduction = throughputData * shiftLength * shiftsPerDay; const dailyProduction = throughputData * shiftLength * shiftsPerDay;
// Units after applying yield rate // Units after applying yield rate
const goodUnitsPerDay = dailyProduction * (yieldRate / 100); const goodUnitsPerDay = dailyProduction * (yieldRate / 100);
// Annual output // Annual output
const annualProduction = goodUnitsPerDay * workingDaysPerYear; const annualProduction = goodUnitsPerDay * workingDaysPerYear;
// Final production capacity per hour (after yield) // Final production capacity per hour (after yield)
const productionPerHour = throughputData * (yieldRate / 100); const productionPerHour = throughputData * (yieldRate / 100);
// Set the final capacity (units/hour) // Set the final capacity (units/hour)
setProductionCapacityData(Number(productionPerHour.toFixed(2))); setProductionCapacityData(Number(productionPerHour.toFixed(2)));
} }
}, [throughputData, inputValues]); }, [throughputData, inputValues]);
useEffect(() => {
setProductionCapacityData(0);
}, [selectedProduct?.productUuid]);
return ( return (
<></> <></>

View File

@ -36,7 +36,7 @@ export default function ThroughPutData() {
setMaterialCycleTime(0); setMaterialCycleTime(0);
setProcessBar([]); setProcessBar([]);
setThroughputData(0); setThroughputData(0);
return; return;
} else { } else {
let process: any = []; let process: any = [];
const fetchProductSequenceData = async () => { const fetchProductSequenceData = async () => {
@ -83,7 +83,7 @@ export default function ThroughPutData() {
.forEach(storage => { .forEach(storage => {
if (storage.activeTime > 0) { if (storage.activeTime > 0) {
// totalActiveTime += storage.activeTime; // totalActiveTime += storage.activeTime;
// //
} }
}); });
} }
@ -92,7 +92,7 @@ export default function ThroughPutData() {
totalItems += sequence.length; totalItems += sequence.length;
}); });
setMachineCount(totalItems); setMachineCount(totalItems);
setMachineActiveTime(totalActiveTime); setMachineActiveTime(totalActiveTime);
let arr = process.map((item: any) => ({ let arr = process.map((item: any) => ({
@ -107,15 +107,15 @@ export default function ThroughPutData() {
fetchProductSequenceData(); fetchProductSequenceData();
} }
// if (materialCycleTime <= 0) return // if (materialCycleTime <= 0) return
}, [products, selectedProduct, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]); }, [products, selectedProduct?.productUuid, getProductById, setMachineCount, materialCycleTime, armBots, vehicles, machines]);
useEffect(() => { useEffect(() => {
let timeoutId: ReturnType<typeof setTimeout>;
async function getMachineActive() { async function getMachineActive() {
const productData = getProductById(selectedProduct.productUuid); const productData = getProductById(selectedProduct.productUuid);
let anyArmActive; let anyArmActive;
let anyVehicleActive; let anyVehicleActive;
let anyMachineActive; let anyMachineActive;
if (productData) { if (productData) {
const productSequenceData = await determineExecutionMachineSequences([productData]); const productSequenceData = await determineExecutionMachineSequences([productData]);
if (productSequenceData?.length > 0) { if (productSequenceData?.length > 0) {
@ -161,7 +161,7 @@ export default function ThroughPutData() {
const allInactive = !anyArmActive && !anyVehicleActive && !anyMachineActive; const allInactive = !anyArmActive && !anyVehicleActive && !anyMachineActive;
if (allInactive && materials.length === 0 && materialHistory.length > 0) { if (allInactive && materials.length === 0 && materialHistory.length > 0) {
let totalCycleTimeSum = 0; let totalCycleTimeSum = 0;
let cycleCount = 0; let cycleCount = 0;
@ -182,11 +182,15 @@ export default function ThroughPutData() {
} }
} }
if (isPlaying) { if (isPlaying) {
setTimeout(() => { timeoutId = setTimeout(() => {
getMachineActive(); getMachineActive();
}, 500) }, 1500);
} }
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct])
return () => {
if (timeoutId) clearTimeout(timeoutId);
};
}, [armBots, materials, materialHistory, machines, vehicles, selectedProduct?.productUuid])
useEffect(() => { useEffect(() => {
if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) { if (machineActiveTime > 0 && materialCycleTime > 0 && machineCount > 0) {
@ -196,7 +200,16 @@ export default function ThroughPutData() {
setThroughputData(Number(throughput.toFixed(2))); // Keep as number setThroughputData(Number(throughput.toFixed(2))); // Keep as number
// //
} }
}, [machineActiveTime, materialCycleTime, machineCount]); }, [machineActiveTime, materialCycleTime, machineCount, selectedProduct?.productUuid]);
useEffect(() => {
totalActiveTime = 0;
totalItems = 0;
setMachineCount(0);
setMachineActiveTime(0);
setMaterialCycleTime(0);
setProcessBar([]);
setThroughputData(0);
}, [selectedProduct?.productUuid]);
return ( return (
<> <>

View File

@ -3,24 +3,25 @@ export const setFloorItemApi = async (
organization: string, organization: string,
modelUuid?: string, modelUuid?: string,
modelName?: string, modelName?: string,
projectId?: string,
modelfileID?: string, modelfileID?: string,
position?: Object, position?: Object,
rotation?: Object, rotation?: Object,
isLocked?: boolean, isLocked?: boolean,
isVisible?: boolean isVisible?: boolean,
) => { ) => {
try { try {
const body: any = { const body: any = {
organization, organization,
modelUuid, modelUuid,
modelName, modelName,
projectId,
position, position,
rotation, rotation,
modelfileID, modelfileID,
isLocked, isLocked,
isVisible, isVisible,
}; };
const response = await fetch(`${url_Backend_dwinzo}/api/V1/setAsset`, { const response = await fetch(`${url_Backend_dwinzo}/api/V1/setAsset`, {
method: "POST", method: "POST",
headers: { headers: {

View File

@ -88,6 +88,7 @@ export const createMaterialStore = () => {
clearMaterials: () => { clearMaterials: () => {
set((state) => { set((state) => {
state.materials = []; state.materials = [];
state.materialHistory = [];
}); });
}, },

View File

@ -5,6 +5,7 @@ type Preset = {
activeOption: string; activeOption: string;
min?: number; min?: number;
max?: number; max?: number;
defaultValue?: string | number;
}; };
}; };