Enhance analysis components with new state management for production capacity and ROI data
This commit is contained in:
parent
3ccfc54922
commit
e4be4505a9
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Line } from "react-chartjs-2";
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
|
@ -9,11 +9,11 @@ import {
|
|||
} from "chart.js";
|
||||
import { PowerIcon, ProductionCapacityIcon } from "../../icons/analysis";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
import { useMachineUptime } from "../../../store/builder/store";
|
||||
import { useMachineUptime, useProductionCapacityData } from "../../../store/builder/store";
|
||||
|
||||
ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement);
|
||||
|
||||
const ThroughputSummary:React.FC = () => {
|
||||
const ThroughputSummary: React.FC = () => {
|
||||
// Define all data internally within the component
|
||||
const timeRange = {
|
||||
startTime: "08:00 AM",
|
||||
|
@ -33,6 +33,7 @@ const ThroughputSummary:React.FC = () => {
|
|||
{ shift: 3, percentage: 30, color: "#7981F5" },
|
||||
];
|
||||
|
||||
const { productionCapacityData } = useProductionCapacityData()
|
||||
|
||||
|
||||
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 (
|
||||
<div className="production analysis-card">
|
||||
|
@ -106,7 +116,7 @@ const ThroughputSummary:React.FC = () => {
|
|||
<>
|
||||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
<span className="value">{throughputData.totalThroughput}</span>{" "}
|
||||
<span className="value">{productionCapacityData}</span>{" "}
|
||||
Units/hour
|
||||
</div>
|
||||
<div className="lineChart">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
CostBreakDownIcon,
|
||||
LightBulpIcon,
|
||||
|
@ -9,6 +9,8 @@ import {
|
|||
import SemiCircleProgress from "./SemiCircleProgress";
|
||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||
import SkeletonUI from "../../templates/SkeletonUI";
|
||||
import { useROISummaryData } from "../../../store/builder/store";
|
||||
import { set } from "immer/dist/internal";
|
||||
|
||||
const ROISummary = ({
|
||||
roiSummaryData = {
|
||||
|
@ -79,8 +81,21 @@ const ROISummary = ({
|
|||
const year = now.getFullYear();
|
||||
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 (
|
||||
<div className="roiSummary-container analysis-card">
|
||||
<div className="roiSummary-wrapper analysis-card-wrapper">
|
||||
|
@ -104,8 +119,8 @@ const ROISummary = ({
|
|||
<SonarCrownIcon />
|
||||
<div className="icon"></div>
|
||||
<div className="info">
|
||||
<span>+{roiSummaryData.roiPercentage}%</span> ROI with payback
|
||||
in just <span>{roiSummaryData.paybackPeriod}</span> months
|
||||
<span>+{roiSummary.roiPercentage}%</span> ROI with payback
|
||||
in just <span>{roiSummary.paybackPeriod}</span> months
|
||||
</div>
|
||||
</div>
|
||||
<div className="roi-details">
|
||||
|
@ -122,7 +137,7 @@ const ROISummary = ({
|
|||
<span className="metric-label">Total Cost Incurred</span>
|
||||
<span className="metric-value">
|
||||
<span>₹</span>
|
||||
{roiSummaryData.totalCost}
|
||||
{roiSummary.totalCost}
|
||||
</span>
|
||||
</div>
|
||||
<div className="metric-item">
|
||||
|
@ -130,14 +145,13 @@ const ROISummary = ({
|
|||
<span className="metric-value">
|
||||
<span>₹</span>
|
||||
|
||||
{roiSummaryData.revenueGenerated}
|
||||
{roiSummary.revenueGenerated}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`metric-item net-profit ${
|
||||
roiSummaryData.netProfit ?? "loss"
|
||||
}`}
|
||||
className={`metric-item net-profit ${roiSummary.netProfit ?? "loss"
|
||||
}`}
|
||||
>
|
||||
<div className="metric-label">
|
||||
<span>↑</span>
|
||||
|
@ -145,9 +159,9 @@ const ROISummary = ({
|
|||
</div>
|
||||
<div className="metric-value">
|
||||
<span>₹</span>
|
||||
{roiSummaryData.netProfit
|
||||
? roiSummaryData.netProfit
|
||||
: roiSummaryData.netLoss}
|
||||
{roiSummary.netProfit
|
||||
? roiSummary.netProfit
|
||||
: roiSummary.netLoss}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -164,9 +178,8 @@ const ROISummary = ({
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={`breakdown-table-wrapper ${
|
||||
isTableOpen ? "open" : "closed"
|
||||
}`}
|
||||
className={`breakdown-table-wrapper ${isTableOpen ? "open" : "closed"
|
||||
}`}
|
||||
style={{
|
||||
transition: "max-height 0.3s ease-in-out",
|
||||
overflow: "hidden",
|
||||
|
@ -190,8 +203,8 @@ const ROISummary = ({
|
|||
row.item === "Total"
|
||||
? "total-row"
|
||||
: row.item === "Net Profit"
|
||||
? "net-profit-row"
|
||||
: ""
|
||||
? "net-profit-row"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<td>{row.item}</td>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 {
|
||||
ThroughputSummaryIcon,
|
||||
} from "../../icons/analysis";
|
||||
|
@ -17,23 +17,25 @@ const ProductionCapacity = ({
|
|||
const { machineActiveTime } = useMachineUptime();
|
||||
const { materialCycleTime } = useMaterialCycle();
|
||||
const { throughputData } = useThroughPutData()
|
||||
|
||||
|
||||
const progressPercent = machineActiveTime;
|
||||
|
||||
|
||||
const totalBars = 6;
|
||||
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
|
||||
const partialFillPercent =
|
||||
((progressPercent / 100) * totalBars - barsToFill) * 100;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (throughputData > 0) {
|
||||
console.log('machineActiveTime: ', machineActiveTime);
|
||||
console.log('materialCycleTime: ', materialCycleTime);
|
||||
console.log('throughputData: ', throughputData);
|
||||
const { productionCapacityData } = useProductionCapacityData()
|
||||
|
||||
const progressPercent = machineActiveTime;
|
||||
|
||||
|
||||
const totalBars = 6;
|
||||
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
|
||||
const partialFillPercent =
|
||||
((progressPercent / 100) * totalBars - barsToFill) * 100;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (throughputData >= 0) {
|
||||
console.log('machineActiveTime: ', machineActiveTime);
|
||||
console.log('materialCycleTime: ', materialCycleTime);
|
||||
console.log('throughputData: ', throughputData);
|
||||
console.log('productionCapacityData: ', productionCapacityData);
|
||||
|
||||
|
||||
setIsLoading(true);
|
||||
}
|
||||
|
@ -59,6 +61,7 @@ const ProductionCapacity = ({
|
|||
<div className="process-container">
|
||||
<div className="throughput-value">
|
||||
<span className="value">{throughputData}</span> Units/hour
|
||||
|
||||
</div>
|
||||
|
||||
{/* Dynamic Progress Bar */}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import { useInputValues, useProductionCapacityData } from '../../../../store/builder/store';
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store';
|
||||
|
||||
export default function ROIData() {
|
||||
const { inputValues } = useInputValues();
|
||||
const { productionCapacityData } = useProductionCapacityData()
|
||||
|
||||
|
||||
const { setRoiSummaryData } = useROISummaryData();
|
||||
useEffect(() => {
|
||||
if (inputValues === undefined) return;
|
||||
|
||||
|
@ -53,6 +55,7 @@ export default function ROIData() {
|
|||
let TotalAnnualCost = MaterialCost + LaborCost + EnergyCost + MaintenceCost;
|
||||
console.log('TotalAnnualCost: ', TotalAnnualCost);
|
||||
|
||||
|
||||
//Profit for Year
|
||||
let ProfitforYear = RevenueForYear - TotalAnnualCost;
|
||||
console.log('ProfitforYear: ', ProfitforYear);
|
||||
|
@ -70,7 +73,16 @@ export default function ROIData() {
|
|||
// Payback Period
|
||||
const paybackPeriod = initialInvestment / ProfitforYear;
|
||||
console.log('paybackPeriod: ', paybackPeriod);
|
||||
|
||||
|
||||
setRoiSummaryData({
|
||||
roiPercentage: ROIData,
|
||||
paybackPeriod,
|
||||
totalCost: TotalAnnualCost,
|
||||
revenueGenerated: RevenueForYear,
|
||||
netProfit: NetProfit > 0 ? NetProfit : 0,
|
||||
netLoss: NetProfit < 0 ? -NetProfit : 0
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ export default function ProductionCapacityData() {
|
|||
// 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
|
||||
const dailyProduction = throughputData * shiftLength * shiftsPerDay;
|
||||
console.log("DailyProduction: ", dailyProduction.toFixed(2));
|
||||
|
|
|
@ -19,7 +19,7 @@ export default function ThroughPutData() {
|
|||
const { machines } = useMachineStore();
|
||||
const { conveyors } = useConveyorStore();
|
||||
const { storageUnits } = useStorageUnitStore();
|
||||
const { materials } = useMaterialStore();
|
||||
const { materialHistory } = useMaterialStore();
|
||||
|
||||
const { machineCount, setMachineCount } = useMachineCount();
|
||||
const { machineActiveTime, setMachineActiveTime } = useMachineUptime();
|
||||
|
@ -33,20 +33,14 @@ export default function ThroughPutData() {
|
|||
// Setting machine count
|
||||
useEffect(() => {
|
||||
if (materialCycleTime < 0) return
|
||||
// console.log('materialCycleTime: ', materialCycleTime);
|
||||
const fetchProductSequenceData = async () => {
|
||||
const productData = getProductById(selectedProduct.productId);
|
||||
if (productData) {
|
||||
const productSequenceData = await determineExecutionMachineSequences([productData]);
|
||||
// console.log('productSequenceData: ', productSequenceData);
|
||||
|
||||
const productSequenceData = await determineExecutionMachineSequences([productData])
|
||||
if (productSequenceData?.length > 0) {
|
||||
let totalItems = 0;
|
||||
let totalActiveTime = 0;
|
||||
|
||||
productSequenceData.forEach((sequence) => {
|
||||
// console.log('sequence: ', sequence);
|
||||
|
||||
sequence.forEach((item) => {
|
||||
if (item.type === "roboticArm") {
|
||||
armBots.filter(arm => arm.modelUuid === item.modelUuid)
|
||||
|
@ -62,7 +56,7 @@ export default function ThroughPutData() {
|
|||
|
||||
if (vehicle.activeTime >= 0) {
|
||||
// totalActiveTime += vehicle.activeTime;
|
||||
// totalActiveTime += 10;
|
||||
totalActiveTime += 34;
|
||||
}
|
||||
});
|
||||
} else if (item.type === "machine") {
|
||||
|
@ -70,7 +64,7 @@ export default function ThroughPutData() {
|
|||
.forEach(machine => {
|
||||
if (machine.activeTime >= 0) {
|
||||
// totalActiveTime += machine.activeTime;
|
||||
// totalActiveTime += 12;
|
||||
totalActiveTime += 12;
|
||||
}
|
||||
});
|
||||
} else if (item.type === "transfer") {
|
||||
|
@ -78,7 +72,7 @@ export default function ThroughPutData() {
|
|||
.forEach(conveyor => {
|
||||
if (conveyor.activeTime >= 0) {
|
||||
// totalActiveTime += conveyor.activeTime;
|
||||
// totalActiveTime += 7;
|
||||
totalActiveTime += 89;
|
||||
}
|
||||
});
|
||||
} else if (item.type === "storageUnit") {
|
||||
|
@ -86,12 +80,11 @@ export default function ThroughPutData() {
|
|||
.forEach(storage => {
|
||||
if (storage.activeTime >= 0) {
|
||||
// totalActiveTime += storage.activeTime;
|
||||
// totalActiveTime += 9;
|
||||
totalActiveTime += 45;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
totalItems += sequence.length;
|
||||
});
|
||||
|
||||
|
@ -107,16 +100,17 @@ export default function ThroughPutData() {
|
|||
|
||||
// Setting material cycle time
|
||||
useEffect(() => {
|
||||
materials.map((material) => {
|
||||
// console.log('material: ', material);
|
||||
// const totalCycleTime = material.endTime - material.startTime;//dynamic
|
||||
const staticStartTime = 50;
|
||||
const staticEndTime = 100;
|
||||
const totalCycleTime = staticEndTime - staticStartTime;
|
||||
setMaterialCycleTime(totalCycleTime)
|
||||
materialHistory.forEach((material) => {
|
||||
const start = material.material.startTime ?? 0;
|
||||
const end = material.material.endTime ?? 0;
|
||||
|
||||
if (start === 0 || end === 0) return;
|
||||
|
||||
const totalCycleTime = end - start;
|
||||
setMaterialCycleTime(totalCycleTime.toFixed(2)); // Set the material cycle time in the store
|
||||
});
|
||||
}, [materialHistory]);
|
||||
|
||||
})
|
||||
}, [materials]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -125,12 +119,12 @@ export default function ThroughPutData() {
|
|||
const throughput = (3600 / materialCycleTime) * machineCount * (avgProcessTime / 100); // ✅ division by 100
|
||||
setThroughputData(throughput.toFixed(2)); // Set the throughput data in the store
|
||||
|
||||
// console.log('---Throughput Results---');
|
||||
// console.log('Total Active Time:', machineActiveTime);
|
||||
// console.log('Material Cycle Time:', materialCycleTime);
|
||||
// console.log('Machine Count:', machineCount);
|
||||
// console.log('Average Process Time (%):', avgProcessTime);
|
||||
// console.log('Calculated Throughput:', throughput);
|
||||
console.log('---Throughput Results---');
|
||||
console.log('Total Active Time:', machineActiveTime);
|
||||
console.log('Material Cycle Time:', materialCycleTime);
|
||||
console.log('Machine Count:', machineCount);
|
||||
console.log('Average Process Time (%):', avgProcessTime);
|
||||
console.log('Calculated Throughput:', throughput);
|
||||
}
|
||||
}, [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])
|
|
@ -234,7 +234,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
|||
cancelAnimationFrame(animationFrameIdRef.current!);
|
||||
animationFrameIdRef.current = null;
|
||||
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);
|
||||
activeSecondsElapsed.current = 0;
|
||||
|
||||
|
@ -242,7 +242,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
|||
cancelAnimationFrame(animationFrameIdRef.current!);
|
||||
animationFrameIdRef.current = null;
|
||||
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);
|
||||
idleSecondsElapsed.current = 0;
|
||||
|
||||
|
@ -260,10 +260,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
|||
|
||||
}, [armBot.isActive, armBot.state, currentPhase])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
console.log('armBots: ', armBots);
|
||||
}, [armBots])
|
||||
|
||||
useEffect(() => {
|
||||
const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
|
||||
|
|
|
@ -492,4 +492,30 @@ export const useInputValues = create<InputValuesStore>((set) => ({
|
|||
[label]: value,
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
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 }),
|
||||
}));
|
Loading…
Reference in New Issue