Enhance analysis components with new state management for production capacity and ROI data

This commit is contained in:
Gomathi 2025-05-14 14:25:54 +05:30
parent 3ccfc54922
commit e4be4505a9
8 changed files with 131 additions and 142 deletions

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect, useState } from "react";
import { Line } from "react-chartjs-2"; import { Line } from "react-chartjs-2";
import { import {
Chart as ChartJS, Chart as ChartJS,
@ -9,11 +9,11 @@ import {
} from "chart.js"; } from "chart.js";
import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis"; import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis";
import SkeletonUI from "../../templates/SkeletonUI"; import SkeletonUI from "../../templates/SkeletonUI";
import { useMachineUptime } from "../../../store/builder/store"; import { useMachineUptime, useProductionCapacityData } from "../../../store/builder/store";
ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement);
const ThroughputSummary:React.FC = () => { const ThroughputSummary: React.FC = () => {
// Define all data internally within the component // Define all data internally within the component
const timeRange = { const timeRange = {
startTime: "08:00 AM", startTime: "08:00 AM",
@ -33,6 +33,7 @@ const ThroughputSummary:React.FC = () => {
{ shift: 3, percentage: 30, color: "#7981F5" }, { shift: 3, percentage: 30, color: "#7981F5" },
]; ];
const { productionCapacityData } = useProductionCapacityData()
const chartOptions = { const chartOptions = {
@ -85,7 +86,16 @@ const ThroughputSummary:React.FC = () => {
}, },
], ],
}; };
const isLoading = false;
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
if (productionCapacityData >= 0) {
setIsLoading(true);
console.log('productionCapacityData: ', productionCapacityData);
}
}, [productionCapacityData])
return ( return (
<div className="production analysis-card"> <div className="production analysis-card">
@ -106,7 +116,7 @@ const ThroughputSummary:React.FC = () => {
<> <>
<div className="process-container"> <div className="process-container">
<div className="throughput-value"> <div className="throughput-value">
<span className="value">{throughputData.totalThroughput}</span>{" "} <span className="value">{productionCapacityData}</span>{" "}
Units/hour Units/hour
</div> </div>
<div className="lineChart"> <div className="lineChart">

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { import {
CostBreakDownIcon, CostBreakDownIcon,
LightBulpIcon, LightBulpIcon,
@ -9,6 +9,8 @@ import {
import SemiCircleProgress from "./SemiCircleProgress"; import SemiCircleProgress from "./SemiCircleProgress";
import { ArrowIcon } from "../../icons/ExportCommonIcons"; import { ArrowIcon } from "../../icons/ExportCommonIcons";
import SkeletonUI from "../../templates/SkeletonUI"; import SkeletonUI from "../../templates/SkeletonUI";
import { useROISummaryData } from "../../../store/builder/store";
import { set } from "immer/dist/internal";
const ROISummary = ({ const ROISummary = ({
roiSummaryData = { roiSummaryData = {
@ -79,8 +81,21 @@ const ROISummary = ({
const year = now.getFullYear(); const year = now.getFullYear();
return `${day} ${month}, ${year}`; return `${day} ${month}, ${year}`;
} }
const [isLoading, setIsLoading] = useState(false);
const { roiSummary } = useROISummaryData();
useEffect(() => {
if (roiSummary && typeof roiSummary === 'object') {
console.log('roiSummary: ', roiSummary);
setIsLoading(true)
}
}, [roiSummary])
const isLoading = false;
return ( return (
<div className="roiSummary-container analysis-card"> <div className="roiSummary-container analysis-card">
<div className="roiSummary-wrapper analysis-card-wrapper"> <div className="roiSummary-wrapper analysis-card-wrapper">
@ -104,8 +119,8 @@ const ROISummary = ({
<SonarCrownIcon /> <SonarCrownIcon />
<div className="icon"></div> <div className="icon"></div>
<div className="info"> <div className="info">
<span>+{roiSummaryData.roiPercentage}%</span> ROI with payback <span>+{roiSummary.roiPercentage}%</span> ROI with payback
in just <span>{roiSummaryData.paybackPeriod}</span> months in just <span>{roiSummary.paybackPeriod}</span> months
</div> </div>
</div> </div>
<div className="roi-details"> <div className="roi-details">
@ -122,7 +137,7 @@ const ROISummary = ({
<span className="metric-label">Total Cost Incurred</span> <span className="metric-label">Total Cost Incurred</span>
<span className="metric-value"> <span className="metric-value">
<span></span> <span></span>
{roiSummaryData.totalCost} {roiSummary.totalCost}
</span> </span>
</div> </div>
<div className="metric-item"> <div className="metric-item">
@ -130,13 +145,12 @@ const ROISummary = ({
<span className="metric-value"> <span className="metric-value">
<span></span> <span></span>
{roiSummaryData.revenueGenerated} {roiSummary.revenueGenerated}
</span> </span>
</div> </div>
</div> </div>
<div <div
className={`metric-item net-profit ${ className={`metric-item net-profit ${roiSummary.netProfit ?? "loss"
roiSummaryData.netProfit ?? "loss"
}`} }`}
> >
<div className="metric-label"> <div className="metric-label">
@ -145,9 +159,9 @@ const ROISummary = ({
</div> </div>
<div className="metric-value"> <div className="metric-value">
<span></span> <span></span>
{roiSummaryData.netProfit {roiSummary.netProfit
? roiSummaryData.netProfit ? roiSummary.netProfit
: roiSummaryData.netLoss} : roiSummary.netLoss}
</div> </div>
</div> </div>
</div> </div>
@ -164,8 +178,7 @@ const ROISummary = ({
</span> </span>
</div> </div>
<div <div
className={`breakdown-table-wrapper ${ className={`breakdown-table-wrapper ${isTableOpen ? "open" : "closed"
isTableOpen ? "open" : "closed"
}`} }`}
style={{ style={{
transition: "max-height 0.3s ease-in-out", transition: "max-height 0.3s ease-in-out",

View File

@ -1,5 +1,5 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useMachineCount, useMachineUptime, useMaterialCycle, useThroughPutData } from "../../../store/builder/store"; import { useMachineCount, useMachineUptime, useMaterialCycle, useProductionCapacityData, useThroughPutData } from "../../../store/builder/store";
import { import {
ThroughputSummaryIcon, ThroughputSummaryIcon,
} from "../../icons/analysis"; } from "../../icons/analysis";
@ -17,7 +17,7 @@ const ProductionCapacity = ({
const { machineActiveTime } = useMachineUptime(); const { machineActiveTime } = useMachineUptime();
const { materialCycleTime } = useMaterialCycle(); const { materialCycleTime } = useMaterialCycle();
const { throughputData } = useThroughPutData() const { throughputData } = useThroughPutData()
const { productionCapacityData } = useProductionCapacityData()
const progressPercent = machineActiveTime; const progressPercent = machineActiveTime;
@ -30,10 +30,12 @@ const ProductionCapacity = ({
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
useEffect(() => { useEffect(() => {
if (throughputData > 0) { if (throughputData >= 0) {
console.log('machineActiveTime: ', machineActiveTime); console.log('machineActiveTime: ', machineActiveTime);
console.log('materialCycleTime: ', materialCycleTime); console.log('materialCycleTime: ', materialCycleTime);
console.log('throughputData: ', throughputData); console.log('throughputData: ', throughputData);
console.log('productionCapacityData: ', productionCapacityData);
setIsLoading(true); setIsLoading(true);
} }
@ -59,6 +61,7 @@ const ProductionCapacity = ({
<div className="process-container"> <div className="process-container">
<div className="throughput-value"> <div className="throughput-value">
<span className="value">{throughputData}</span> Units/hour <span className="value">{throughputData}</span> Units/hour
</div> </div>
{/* Dynamic Progress Bar */} {/* Dynamic Progress Bar */}

View File

@ -1,10 +1,12 @@
import React, { useEffect } from 'react' import React, { useEffect, useState } from 'react'
import { useInputValues, useProductionCapacityData } from '../../../../store/builder/store'; import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
export default function ROIData() { export default function ROIData() {
const { inputValues } = useInputValues(); const { inputValues } = useInputValues();
const { productionCapacityData } = useProductionCapacityData() const { productionCapacityData } = useProductionCapacityData()
const { setRoiSummaryData } = useROISummaryData();
useEffect(() => { useEffect(() => {
if (inputValues === undefined) return; if (inputValues === undefined) return;
@ -53,6 +55,7 @@ export default function ROIData() {
let TotalAnnualCost = MaterialCost + LaborCost + EnergyCost + MaintenceCost; let TotalAnnualCost = MaterialCost + LaborCost + EnergyCost + MaintenceCost;
console.log('TotalAnnualCost: ', TotalAnnualCost); console.log('TotalAnnualCost: ', TotalAnnualCost);
//Profit for Year //Profit for Year
let ProfitforYear = RevenueForYear - TotalAnnualCost; let ProfitforYear = RevenueForYear - TotalAnnualCost;
console.log('ProfitforYear: ', ProfitforYear); console.log('ProfitforYear: ', ProfitforYear);
@ -72,6 +75,15 @@ export default function ROIData() {
console.log('paybackPeriod: ', paybackPeriod); console.log('paybackPeriod: ', paybackPeriod);
setRoiSummaryData({
roiPercentage: ROIData,
paybackPeriod,
totalCost: TotalAnnualCost,
revenueGenerated: RevenueForYear,
netProfit: NetProfit > 0 ? NetProfit : 0,
netLoss: NetProfit < 0 ? -NetProfit : 0
});
} }
}, [inputValues, productionCapacityData]); }, [inputValues, productionCapacityData]);

View File

@ -19,7 +19,7 @@ export default function ProductionCapacityData() {
// console.log('yieldRate: ', yieldRate); // console.log('yieldRate: ', yieldRate);
if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData > 0) { if (!isNaN(shiftLength) && !isNaN(shiftsPerDay) && !isNaN(workingDaysPerYear) && !isNaN(yieldRate) && throughputData >= 0) {
//Daily Output //Daily Output
const dailyProduction = throughputData * shiftLength * shiftsPerDay; const dailyProduction = throughputData * shiftLength * shiftsPerDay;
console.log("DailyProduction: ", dailyProduction.toFixed(2)); console.log("DailyProduction: ", dailyProduction.toFixed(2));

View File

@ -19,7 +19,7 @@ export default function ThroughPutData() {
const { machines } = useMachineStore(); const { machines } = useMachineStore();
const { conveyors } = useConveyorStore(); const { conveyors } = useConveyorStore();
const { storageUnits } = useStorageUnitStore(); const { storageUnits } = useStorageUnitStore();
const { materials } = useMaterialStore(); const { materialHistory } = useMaterialStore();
const { machineCount, setMachineCount } = useMachineCount(); const { machineCount, setMachineCount } = useMachineCount();
const { machineActiveTime, setMachineActiveTime } = useMachineUptime(); const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
@ -33,20 +33,14 @@ export default function ThroughPutData() {
// Setting machine count // Setting machine count
useEffect(() => { useEffect(() => {
if (materialCycleTime < 0) return if (materialCycleTime < 0) return
// console.log('materialCycleTime: ', materialCycleTime);
const fetchProductSequenceData = async () => { const fetchProductSequenceData = async () => {
const productData = getProductById(selectedProduct.productId); const productData = getProductById(selectedProduct.productId);
if (productData) { if (productData) {
const productSequenceData = await determineExecutionMachineSequences([productData]); const productSequenceData = await determineExecutionMachineSequences([productData])
// console.log('productSequenceData: ', productSequenceData);
if (productSequenceData?.length > 0) { if (productSequenceData?.length > 0) {
let totalItems = 0; let totalItems = 0;
let totalActiveTime = 0; let totalActiveTime = 0;
productSequenceData.forEach((sequence) => { productSequenceData.forEach((sequence) => {
// console.log('sequence: ', sequence);
sequence.forEach((item) => { sequence.forEach((item) => {
if (item.type === "roboticArm") { if (item.type === "roboticArm") {
armBots.filter(arm => arm.modelUuid === item.modelUuid) armBots.filter(arm => arm.modelUuid === item.modelUuid)
@ -62,7 +56,7 @@ export default function ThroughPutData() {
if (vehicle.activeTime >= 0) { if (vehicle.activeTime >= 0) {
// totalActiveTime += vehicle.activeTime; // totalActiveTime += vehicle.activeTime;
// totalActiveTime += 10; totalActiveTime += 34;
} }
}); });
} else if (item.type === "machine") { } else if (item.type === "machine") {
@ -70,7 +64,7 @@ export default function ThroughPutData() {
.forEach(machine => { .forEach(machine => {
if (machine.activeTime >= 0) { if (machine.activeTime >= 0) {
// totalActiveTime += machine.activeTime; // totalActiveTime += machine.activeTime;
// totalActiveTime += 12; totalActiveTime += 12;
} }
}); });
} else if (item.type === "transfer") { } else if (item.type === "transfer") {
@ -78,7 +72,7 @@ export default function ThroughPutData() {
.forEach(conveyor => { .forEach(conveyor => {
if (conveyor.activeTime >= 0) { if (conveyor.activeTime >= 0) {
// totalActiveTime += conveyor.activeTime; // totalActiveTime += conveyor.activeTime;
// totalActiveTime += 7; totalActiveTime += 89;
} }
}); });
} else if (item.type === "storageUnit") { } else if (item.type === "storageUnit") {
@ -86,12 +80,11 @@ export default function ThroughPutData() {
.forEach(storage => { .forEach(storage => {
if (storage.activeTime >= 0) { if (storage.activeTime >= 0) {
// totalActiveTime += storage.activeTime; // totalActiveTime += storage.activeTime;
// totalActiveTime += 9; totalActiveTime += 45;
} }
}); });
} }
}); });
totalItems += sequence.length; totalItems += sequence.length;
}); });
@ -107,16 +100,17 @@ export default function ThroughPutData() {
// Setting material cycle time // Setting material cycle time
useEffect(() => { useEffect(() => {
materials.map((material) => { materialHistory.forEach((material) => {
// console.log('material: ', material); const start = material.material.startTime ?? 0;
// const totalCycleTime = material.endTime - material.startTime;//dynamic const end = material.material.endTime ?? 0;
const staticStartTime = 50;
const staticEndTime = 100; if (start === 0 || end === 0) return;
const totalCycleTime = staticEndTime - staticStartTime;
setMaterialCycleTime(totalCycleTime) const totalCycleTime = end - start;
setMaterialCycleTime(totalCycleTime.toFixed(2)); // Set the material cycle time in the store
});
}, [materialHistory]);
})
}, [materials]);
useEffect(() => { useEffect(() => {
@ -125,12 +119,12 @@ export default function ThroughPutData() {
const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); // ✅ division by 100 const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); // ✅ division by 100
setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store
// console.log('---Throughput Results---'); console.log('---Throughput Results---');
// console.log('Total Active Time:', machineActiveTime); console.log('Total Active Time:', machineActiveTime);
// console.log('Material Cycle Time:', materialCycleTime); console.log('Material Cycle Time:', materialCycleTime);
// console.log('Machine Count:', machineCount); console.log('Machine Count:', machineCount);
// console.log('Average Process Time (%):', avgProcessTime); console.log('Average Process Time (%):', avgProcessTime);
// console.log('Calculated Throughput:', throughput); console.log('Calculated Throughput:', throughput);
} }
}, [machineActiveTime, materialCycleTime, machineCount]); }, [machineActiveTime, materialCycleTime, machineCount]);
@ -141,68 +135,3 @@ export default function ThroughPutData() {
</> </>
); );
} }
// useEffect(() => {
// if (!isPlaying) return;
// const intervalMs = 1000
// if (!armBot.isActive && armBot.state == "idle" && (currentPhase == "rest" || currentPhase == "init") && !isIdleRef.current) {
// isIdleRef.current = true
// // Stop the timer
// // 🚨 1. Clear Active Timer
// if (activeTimerId.current) {
// clearInterval(activeTimerId.current);
// activeTimerId.current = null;
// }
// incrementActiveTime(armBot.modelUuid, activeSecondsElapsed.current)
// console.log(`✅ Active Cycle completed in ${activeSecondsElapsed.current} seconds`);
// // 🚨 2. Reset active timer seconds after logging
// // activeSecondsElapsed.current = 0;
// // 🚨 3. Start Idle Timer (clean old idle timer first)
// if (idleTimerId.current) {
// clearInterval(idleTimerId.current);
// idleTimerId.current = null;
// }
// idleSecondsElapsed.current = 0;
// idleTimerId.current = setInterval(() => {
// if (!isPausedRef.current) {
// idleSecondsElapsed.current += 1;
// console.log(`🕒 Idle Timer: ${idleSecondsElapsed.current} seconds`);
// }
// }, intervalMs);
// }
// if (armBot.isActive && armBot.state != "idle" && currentPhase !== "rest" && armBot.currentAction && isIdleRef.current) {
// isIdleRef.current = false
// if (armBot.currentAction) {
// // 🚨 Clear Idle Timer
// if (idleTimerId.current) {
// clearInterval(idleTimerId.current);
// idleTimerId.current = null;
// }
// incrementIdleTime(armBot.modelUuid, idleSecondsElapsed.current)
// console.log(`🕒 Idle Cycle completed in: ${idleSecondsElapsed.current} seconds`);
// idleSecondsElapsed.current = 0;
// // 🚨 Start Active Timer
// if (activeTimerId.current) {
// clearInterval(activeTimerId.current);
// }
// // activeSecondsElapsed.current = 0;
// activeTimerId.current = setInterval(() => {
// if (!isPausedRef.current) {
// activeSecondsElapsed.current += 1
// console.log(`🕒 Active Timer: ${activeSecondsElapsed.current} seconds`);
// }
// }, intervalMs);
// }
// }
// }, [armBot, currentPhase, isPlaying])

View File

@ -234,7 +234,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
cancelAnimationFrame(animationFrameIdRef.current!); cancelAnimationFrame(animationFrameIdRef.current!);
animationFrameIdRef.current = null; animationFrameIdRef.current = null;
const roundedActiveTime = Math.round(activeSecondsElapsed.current); // Get the final rounded active time const roundedActiveTime = Math.round(activeSecondsElapsed.current); // Get the final rounded active time
console.log('Final Active Time:', roundedActiveTime, 'seconds'); // console.log('🚨Final Active Time:',armBot.modelUuid, roundedActiveTime, 'seconds');
incrementActiveTime(armBot.modelUuid, roundedActiveTime); incrementActiveTime(armBot.modelUuid, roundedActiveTime);
activeSecondsElapsed.current = 0; activeSecondsElapsed.current = 0;
@ -242,7 +242,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
cancelAnimationFrame(animationFrameIdRef.current!); cancelAnimationFrame(animationFrameIdRef.current!);
animationFrameIdRef.current = null; animationFrameIdRef.current = null;
const roundedIdleTime = Math.round(idleSecondsElapsed.current); // Get the final rounded idle time const roundedIdleTime = Math.round(idleSecondsElapsed.current); // Get the final rounded idle time
console.log('Final Idle Time:', roundedIdleTime, 'seconds'); // console.log('🕒 Final Idle Time:', armBot.modelUuid,roundedIdleTime, 'seconds');
incrementIdleTime(armBot.modelUuid, roundedIdleTime); incrementIdleTime(armBot.modelUuid, roundedIdleTime);
idleSecondsElapsed.current = 0; idleSecondsElapsed.current = 0;
@ -260,10 +260,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
}, [armBot.isActive, armBot.state, currentPhase]) }, [armBot.isActive, armBot.state, currentPhase])
useEffect(() => {
console.log('armBots: ', armBots);
}, [armBots])
useEffect(() => { useEffect(() => {
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid); const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);

View File

@ -493,3 +493,29 @@ export const useInputValues = create<InputValuesStore>((set) => ({
}, },
})), })),
})); }));
export interface ROISummaryData {
roiPercentage: number;
paybackPeriod: number;
totalCost: number;
revenueGenerated: number;
netProfit: number;
netLoss: number;
}
interface ROISummaryStore {
roiSummary: ROISummaryData;
setRoiSummaryData: (values: ROISummaryData) => void;
}
export const useROISummaryData = create<ROISummaryStore>((set) => ({
roiSummary: {
roiPercentage: 0,
paybackPeriod: 0,
totalCost: 0,
revenueGenerated: 0,
netProfit: 0,
netLoss: 0,
},
setRoiSummaryData: (values) => set({ roiSummary: values }),
}));