feat: add loading state with timeout for ThroughputSummary and ROISummary components
This commit is contained in:
parent
3d9f625e3d
commit
db8536100c
|
@ -91,8 +91,11 @@ const ThroughputSummary: React.FC = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (productionCapacityData >= 0) {
|
if (productionCapacityData >0) {
|
||||||
setIsLoading(false);
|
setTimeout(() => {
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
}, 3000);
|
||||||
console.log("productionCapacityData: ", productionCapacityData);
|
console.log("productionCapacityData: ", productionCapacityData);
|
||||||
} else {
|
} else {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
@ -100,7 +103,8 @@ const ThroughputSummary: React.FC = () => {
|
||||||
}, [productionCapacityData]);
|
}, [productionCapacityData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="production analysis-card">
|
<>
|
||||||
|
{!isLoading && <div className="production analysis-card">
|
||||||
<div className="production-wrapper analysis-card-wrapper">
|
<div className="production-wrapper analysis-card-wrapper">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
|
@ -184,7 +188,8 @@ const ThroughputSummary: React.FC = () => {
|
||||||
<SkeletonUI type={"default"} />
|
<SkeletonUI type={"default"} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -84,135 +84,142 @@ const ROISummary = ({
|
||||||
const { roiSummary } = useROISummaryData();
|
const { roiSummary } = useROISummaryData();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (roiSummary && typeof roiSummary === "object") {
|
if (roiSummary.productName) {
|
||||||
setIsLoading(false); // Data loaded
|
// If productName is set, assume data is loaded
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
setIsLoading(false);
|
||||||
|
}, 3000);
|
||||||
|
// setIsLoading(false);
|
||||||
} else {
|
} else {
|
||||||
setIsLoading(true); // Show skeleton while loading
|
// If productName is empty, assume still loading
|
||||||
|
setIsLoading(true);
|
||||||
}
|
}
|
||||||
}, [roiSummary]);
|
}, [roiSummary]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="roiSummary-container analysis-card">
|
<>
|
||||||
<div className="roiSummary-wrapper analysis-card-wrapper">
|
{!isLoading && <div className="roiSummary-container analysis-card">
|
||||||
<div className="card-header">
|
<div className="roiSummary-wrapper analysis-card-wrapper">
|
||||||
<div className="header">
|
<div className="card-header">
|
||||||
<div className="main-header">ROI Summary</div>
|
<div className="header">
|
||||||
<div className="sub-header">From {getCurrentDate()}</div>
|
<div className="main-header">ROI Summary</div>
|
||||||
</div>
|
<div className="sub-header">From {getCurrentDate()}</div>
|
||||||
<div className="icon-wrapper">
|
|
||||||
<ROISummaryIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{!isLoading ? (
|
|
||||||
<>
|
|
||||||
<div className="product-info">
|
|
||||||
<ROISummaryProductName />
|
|
||||||
<div className="product-label">Product :</div>
|
|
||||||
<div className="product-name">{roiSummary.productName}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="playBack">
|
<div className="icon-wrapper">
|
||||||
<SonarCrownIcon />
|
<ROISummaryIcon />
|
||||||
<div className="icon"></div>
|
</div>
|
||||||
<div className="info">
|
</div>
|
||||||
<span> {roiSummary.roiPercentage}%</span> ROI with payback
|
{!isLoading ? (
|
||||||
in just <span>{roiSummary.paybackPeriod}</span> months
|
<>
|
||||||
|
<div className="product-info">
|
||||||
|
<ROISummaryProductName />
|
||||||
|
<div className="product-label">Product :</div>
|
||||||
|
<div className="product-name">{roiSummary.productName}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="playBack">
|
||||||
<div className="roi-details">
|
<SonarCrownIcon />
|
||||||
<div className="progress-wrapper">
|
<div className="icon"></div>
|
||||||
<SemiCircleProgress />
|
<div className="info">
|
||||||
<div className="content">
|
<span> {roiSummary.roiPercentage}%</span> ROI with payback
|
||||||
you're on track to hit it by
|
in just <span>{roiSummary.paybackPeriod}</span> months
|
||||||
<div className="key">July 2029</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="metrics">
|
<div className="roi-details">
|
||||||
<div className="metric-wrapper">
|
<div className="progress-wrapper">
|
||||||
<div className="metric-item">
|
<SemiCircleProgress />
|
||||||
<span className="metric-label">Total Cost Incurred</span>
|
<div className="content">
|
||||||
<span className="metric-value">
|
you're on track to hit it by
|
||||||
<span>₹</span>
|
<div className="key">July 2029</div>
|
||||||
{roiSummary.totalCost}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="metric-item">
|
</div>
|
||||||
<span className="metric-label">Revenue Generated</span>
|
<div className="metrics">
|
||||||
<span className="metric-value">
|
<div className="metric-wrapper">
|
||||||
<span>₹</span>
|
<div className="metric-item">
|
||||||
|
<span className="metric-label">Total Cost Incurred</span>
|
||||||
|
<span className="metric-value">
|
||||||
|
<span>₹</span>
|
||||||
|
{roiSummary.totalCost}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="metric-item">
|
||||||
|
<span className="metric-label">Revenue Generated</span>
|
||||||
|
<span className="metric-value">
|
||||||
|
<span>₹</span>
|
||||||
|
|
||||||
{roiSummary.revenueGenerated}
|
{roiSummary.revenueGenerated}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className={`metric-item net-profit ${roiSummary.netProfit > 0 ? "profit" : "loss"}`}
|
||||||
|
>
|
||||||
|
<div className="metric-label">
|
||||||
|
<span>↑</span>
|
||||||
|
Net Profit
|
||||||
|
</div>
|
||||||
|
<div className="metric-value">
|
||||||
|
<span>₹</span>
|
||||||
|
{roiSummary.netProfit > 0
|
||||||
|
? roiSummary.netProfit
|
||||||
|
: roiSummary.netLoss}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="cost-breakdown">
|
||||||
|
<div className="breakdown-header" onClick={toggleTable}>
|
||||||
|
<div className="section-wrapper">
|
||||||
|
<CostBreakDownIcon />
|
||||||
|
<span className="section-title">Cost Breakdown</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span className={`expand-icon ${isTableOpen ? "open" : ""}`}>
|
||||||
|
<ArrowIcon />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`metric-item net-profit ${roiSummary.netProfit > 0 ? "profit" : "loss"}`}
|
className={`breakdown-table-wrapper ${isTableOpen ? "open" : "closed"
|
||||||
|
}`}
|
||||||
|
style={{
|
||||||
|
transition: "max-height 0.3s ease-in-out",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="metric-label">
|
<table className="breakdown-table">
|
||||||
<span>↑</span>
|
<thead>
|
||||||
Net Profit
|
<tr>
|
||||||
</div>
|
<th>Item</th>
|
||||||
<div className="metric-value">
|
<th>Unit Cost</th>
|
||||||
<span>₹</span>
|
<th>Labor Cost</th>
|
||||||
{roiSummary.netProfit > 0
|
<th>Total Cost</th>
|
||||||
? roiSummary.netProfit
|
<th>Selling Price</th>
|
||||||
: roiSummary.netLoss}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="cost-breakdown">
|
|
||||||
<div className="breakdown-header" onClick={toggleTable}>
|
|
||||||
<div className="section-wrapper">
|
|
||||||
<CostBreakDownIcon />
|
|
||||||
<span className="section-title">Cost Breakdown</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span className={`expand-icon ${isTableOpen ? "open" : ""}`}>
|
|
||||||
<ArrowIcon />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`breakdown-table-wrapper ${isTableOpen ? "open" : "closed"
|
|
||||||
}`}
|
|
||||||
style={{
|
|
||||||
transition: "max-height 0.3s ease-in-out",
|
|
||||||
overflow: "hidden",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<table className="breakdown-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Item</th>
|
|
||||||
<th>Unit Cost</th>
|
|
||||||
<th>Labor Cost</th>
|
|
||||||
<th>Total Cost</th>
|
|
||||||
<th>Selling Price</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{roiSummaryData.costBreakdown.map((row, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className={
|
|
||||||
row.item === "Total"
|
|
||||||
? "total-row"
|
|
||||||
: row.item === "Net Profit"
|
|
||||||
? "net-profit-row"
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<td>{row.item}</td>
|
|
||||||
<td>{row.unitCost}</td>
|
|
||||||
<td>{row.laborCost}</td>
|
|
||||||
<td>{row.totalCost}</td>
|
|
||||||
<td>{row.sellingPrice}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{roiSummaryData.costBreakdown.map((row, index) => (
|
||||||
|
<tr
|
||||||
|
key={index}
|
||||||
|
className={
|
||||||
|
row.item === "Total"
|
||||||
|
? "total-row"
|
||||||
|
: row.item === "Net Profit"
|
||||||
|
? "net-profit-row"
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<td>{row.item}</td>
|
||||||
|
<td>{row.unitCost}</td>
|
||||||
|
<td>{row.laborCost}</td>
|
||||||
|
<td>{row.totalCost}</td>
|
||||||
|
<td>{row.sellingPrice}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/* <div className="tips-section">
|
||||||
{/* <div className="tips-section">
|
|
||||||
<div className="tip-header">
|
<div className="tip-header">
|
||||||
<span className="lightbulb-icon">
|
<span className="lightbulb-icon">
|
||||||
<LightBulpIcon />
|
<LightBulpIcon />
|
||||||
|
@ -232,13 +239,14 @@ const ROISummary = ({
|
||||||
<div className="btn">Get ROI Boost Tips</div>
|
<div className="btn">Get ROI Boost Tips</div>
|
||||||
</button>
|
</button>
|
||||||
</div> */}
|
</div> */}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<SkeletonUI type={"default"} />
|
<SkeletonUI type={"default"} />
|
||||||
// <div> No Data</div>
|
// <div> No Data</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,72 +30,73 @@ const ProductionCapacity = ({
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (throughputData >= 0) {
|
console.log('throughputData: ', throughputData > 0);
|
||||||
// console.log('machineActiveTime: ', machineActiveTime);
|
if (throughputData > 0) {
|
||||||
// console.log('materialCycleTime: ', materialCycleTime);
|
setIsLoading(false);
|
||||||
// console.log('throughputData: ', throughputData);
|
} else {
|
||||||
// console.log('productionCapacityData: ', productionCapacityData);
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [throughputData])
|
}, [throughputData])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="throughtputSummary-container analysis-card">
|
<>
|
||||||
<div className="throughtputSummary-wrapper analysis-card-wrapper">
|
{!isLoading && <div className="throughtputSummary-container analysis-card">
|
||||||
<div className="card-header">
|
<div className="throughtputSummary-wrapper analysis-card-wrapper">
|
||||||
<div className="header">
|
<div className="card-header">
|
||||||
<div className="main-header">Throughput Summary</div>
|
<div className="header">
|
||||||
<div className="sub-header">
|
<div className="main-header">Throughput Summary</div>
|
||||||
{timeRange.startTime} - {timeRange.endTime}
|
<div className="sub-header">
|
||||||
|
{timeRange.startTime} - {timeRange.endTime}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="icon-wrapper">
|
||||||
|
<ThroughputSummaryIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="icon-wrapper">
|
{!isLoading ? (
|
||||||
<ThroughputSummaryIcon />
|
<>
|
||||||
</div>
|
<div className="process-container">
|
||||||
|
<div className="throughput-value">
|
||||||
|
<span className="value">{throughputData}</span> Units/hour
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Dynamic Progress Bar */}
|
||||||
|
<div className="progress-bar-wrapper">
|
||||||
|
{[...Array(totalBars)].map((_, i) => (
|
||||||
|
<div className="progress-bar" key={i}>
|
||||||
|
{i < barsToFill ? (
|
||||||
|
<div className="bar-fill full" />
|
||||||
|
) : i === barsToFill ? (
|
||||||
|
<div
|
||||||
|
className="bar-fill partial"
|
||||||
|
style={{ width: `${partialFillPercent}%` }}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="metrics-section">
|
||||||
|
<div className="metric">
|
||||||
|
<span className="label">Avg. Process Time</span>
|
||||||
|
<span className="value">{materialCycleTime} secs/unit </span>
|
||||||
|
</div>
|
||||||
|
<div className="metric">
|
||||||
|
<span className="label">Machine Utilization</span>
|
||||||
|
<span className="value">{machineActiveTime}</span>
|
||||||
|
{/* <span className="value">{machineActiveTime}</span> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<SkeletonUI type={"default"} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isLoading ? (
|
</div>}
|
||||||
<>
|
</>
|
||||||
<div className="process-container">
|
|
||||||
<div className="throughput-value">
|
|
||||||
<span className="value">{throughputData}</span> Units/hour
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Dynamic Progress Bar */}
|
|
||||||
<div className="progress-bar-wrapper">
|
|
||||||
{[...Array(totalBars)].map((_, i) => (
|
|
||||||
<div className="progress-bar" key={i}>
|
|
||||||
{i < barsToFill ? (
|
|
||||||
<div className="bar-fill full" />
|
|
||||||
) : i === barsToFill ? (
|
|
||||||
<div
|
|
||||||
className="bar-fill partial"
|
|
||||||
style={{ width: `${partialFillPercent}%` }}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="metrics-section">
|
|
||||||
<div className="metric">
|
|
||||||
<span className="label">Avg. Process Time</span>
|
|
||||||
<span className="value">{materialCycleTime} secs/unit </span>
|
|
||||||
</div>
|
|
||||||
<div className="metric">
|
|
||||||
<span className="label">Machine Utilization</span>
|
|
||||||
<span className="value">{machineActiveTime}</span>
|
|
||||||
{/* <span className="value">{machineActiveTime}</span> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<SkeletonUI type={"default"} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue