Add CraftingPanel component for crafting functionality
This commit is contained in:
71
web/client/src/components/CraftingPanel.jsx
Normal file
71
web/client/src/components/CraftingPanel.jsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useInventoryStore } from '../store/inventoryStore';
|
||||||
|
import { formatItemName } from '../utils/itemUtils';
|
||||||
|
import ItemIcon from './ItemIcon';
|
||||||
|
import './CraftingPanel.css';
|
||||||
|
|
||||||
|
function CraftingPanel() {
|
||||||
|
const craftable = useInventoryStore((state) => state.craftable);
|
||||||
|
const craftTurtleOk = useInventoryStore((state) => state.craftTurtleOk);
|
||||||
|
const craftItem = useInventoryStore((state) => state.craftItem);
|
||||||
|
const [craftingIdx, setCraftingIdx] = useState(null);
|
||||||
|
|
||||||
|
const handleCraft = async (idx) => {
|
||||||
|
setCraftingIdx(idx);
|
||||||
|
await craftItem(idx);
|
||||||
|
setCraftingIdx(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="crafting-panel">
|
||||||
|
<div className="crafting-header">
|
||||||
|
<h2>🔨 Crafting</h2>
|
||||||
|
<div className={`turtle-status ${craftTurtleOk ? 'online' : 'offline'}`}>
|
||||||
|
🐢 {craftTurtleOk ? 'Turtle Online' : 'Turtle Offline'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!craftTurtleOk && (
|
||||||
|
<div className="turtle-warning">
|
||||||
|
⚠️ Crafting turtle is not connected. Crafting commands will fail.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="craft-list">
|
||||||
|
{(craftable || []).map((recipe, idx) => (
|
||||||
|
<div key={idx} className="craft-card">
|
||||||
|
<div className="craft-output">
|
||||||
|
<ItemIcon itemName={recipe.output} size={32} />
|
||||||
|
<div className="craft-info">
|
||||||
|
<span className="craft-name">{formatItemName(recipe.output)}</span>
|
||||||
|
<span className="craft-count">Produces {recipe.count || 1}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="craft-ingredients">
|
||||||
|
{recipe.slots && Object.entries(recipe.slots).map(([slot, item]) => (
|
||||||
|
<div key={slot} className="craft-ingredient">
|
||||||
|
<ItemIcon itemName={item} size={16} />
|
||||||
|
<span>{formatItemName(item)}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className={`mc-btn green craft-btn ${craftingIdx === idx ? 'crafting' : ''}`}
|
||||||
|
onClick={() => handleCraft(idx + 1)}
|
||||||
|
disabled={craftingIdx !== null || !craftTurtleOk}
|
||||||
|
>
|
||||||
|
{craftingIdx === idx + 1 ? '⏳ Crafting...' : '🔨 Craft'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{(!craftable || craftable.length === 0) && (
|
||||||
|
<div className="no-data">No crafting recipes configured</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CraftingPanel;
|
||||||
Reference in New Issue
Block a user