Add StorageOverview component for inventory management display
This commit is contained in:
123
web/client/src/components/StorageOverview.jsx
Normal file
123
web/client/src/components/StorageOverview.jsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import React from 'react';
|
||||
import { useInventoryStore } from '../store/inventoryStore';
|
||||
import './StorageOverview.css';
|
||||
|
||||
function StorageOverview() {
|
||||
const inventory = useInventoryStore((state) => state.inventory);
|
||||
const activity = useInventoryStore((state) => state.activity);
|
||||
const connected = useInventoryStore((state) => state.connected);
|
||||
const lastUpdate = useInventoryStore((state) => state.lastUpdate);
|
||||
const craftTurtleOk = useInventoryStore((state) => state.craftTurtleOk);
|
||||
const requestScan = useInventoryStore((state) => state.requestScan);
|
||||
|
||||
const usedPercent = inventory.totalSlots > 0
|
||||
? Math.round((inventory.usedSlots / inventory.totalSlots) * 100)
|
||||
: 0;
|
||||
|
||||
const getUsageColor = () => {
|
||||
if (usedPercent >= 90) return 'critical';
|
||||
if (usedPercent >= 75) return 'warning';
|
||||
return 'normal';
|
||||
};
|
||||
|
||||
const timeSinceUpdate = lastUpdate
|
||||
? Math.floor((Date.now() - lastUpdate) / 1000)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="storage-overview">
|
||||
<div className="overview-header">
|
||||
<h2>📊 Storage</h2>
|
||||
<button className="mc-btn blue" onClick={requestScan} title="Refresh inventory scan">
|
||||
🔍 Scan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Storage capacity bar */}
|
||||
<div className="capacity-section">
|
||||
<div className="capacity-label">
|
||||
<span>Capacity</span>
|
||||
<span className={`capacity-percent ${getUsageColor()}`}>{usedPercent}%</span>
|
||||
</div>
|
||||
<div className="capacity-bar">
|
||||
<div
|
||||
className={`capacity-fill ${getUsageColor()}`}
|
||||
style={{ width: `${usedPercent}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<div className="capacity-detail">
|
||||
{inventory.usedSlots} / {inventory.totalSlots} slots
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats grid */}
|
||||
<div className="stats-grid">
|
||||
<div className="stat-item">
|
||||
<span className="stat-label">Total Items</span>
|
||||
<span className="stat-value">{(inventory.grandTotal || 0).toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="stat-item">
|
||||
<span className="stat-label">Item Types</span>
|
||||
<span className="stat-value">{(inventory.itemList || []).length}</span>
|
||||
</div>
|
||||
<div className="stat-item">
|
||||
<span className="stat-label">Chests</span>
|
||||
<span className="stat-value">{inventory.chestCount || 0}</span>
|
||||
</div>
|
||||
<div className="stat-item">
|
||||
<span className="stat-label">Free Slots</span>
|
||||
<span className="stat-value">{inventory.freeSlots || 0}</span>
|
||||
</div>
|
||||
<div className="stat-item">
|
||||
<span className="stat-label">Furnaces</span>
|
||||
<span className="stat-value">{inventory.furnaceCount || 0}</span>
|
||||
</div>
|
||||
<div className="stat-item">
|
||||
<span className="stat-label">Craft Turtle</span>
|
||||
<span className={`stat-value ${craftTurtleOk ? 'ok' : 'offline'}`}>
|
||||
{craftTurtleOk ? '✅ Online' : '❌ Offline'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Peripherals */}
|
||||
<div className="peripherals-section">
|
||||
<h3>Peripherals</h3>
|
||||
<div className="peripheral-list">
|
||||
<div className={`peripheral-item ${inventory.dropperOk ? 'ok' : 'error'}`}>
|
||||
<span>{inventory.dropperOk ? '✅' : '❌'} Dropper</span>
|
||||
</div>
|
||||
<div className={`peripheral-item ${inventory.barrelOk ? 'ok' : 'error'}`}>
|
||||
<span>{inventory.barrelOk ? '✅' : '❌'} Barrel</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Activity indicators */}
|
||||
<div className="activity-section">
|
||||
<h3>Activity</h3>
|
||||
<div className="activity-list">
|
||||
{activity.sorting && <div className="activity-item active">📦 Sorting</div>}
|
||||
{activity.smelting && <div className="activity-item active">🔥 Smelting</div>}
|
||||
{activity.dispensing && <div className="activity-item active">📤 Dispensing</div>}
|
||||
{activity.composting && <div className="activity-item active">🌱 Composting</div>}
|
||||
{activity.defragging && <div className="activity-item active">🔧 Defragging</div>}
|
||||
{activity.crafting && <div className="activity-item active">🔨 Crafting</div>}
|
||||
{!activity.sorting && !activity.smelting && !activity.dispensing &&
|
||||
!activity.composting && !activity.defragging && !activity.crafting && (
|
||||
<div className="activity-item idle">💤 Idle</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Last update */}
|
||||
{lastUpdate > 0 && (
|
||||
<div className="last-update">
|
||||
Last update: {timeSinceUpdate !== null ? `${timeSinceUpdate}s ago` : 'Never'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default StorageOverview;
|
||||
Reference in New Issue
Block a user