feat: Refactor TurtleCard and TurtleDetails to implement active state management and enhance command handling
This commit is contained in:
@@ -3,7 +3,7 @@ import { useTurtleStore } from '../store/turtleStore';
|
|||||||
import './ControlPanel.css';
|
import './ControlPanel.css';
|
||||||
|
|
||||||
function TurtleCard({ turtle, isSelected, onSelect }) {
|
function TurtleCard({ turtle, isSelected, onSelect }) {
|
||||||
const mode = turtle.mode || 'unknown';
|
const activeState = turtle.state || turtle.mode || 'idle';
|
||||||
const fuel = turtle.fuel === 'unlimited' ? '∞' : (turtle.fuel || '?');
|
const fuel = turtle.fuel === 'unlimited' ? '∞' : (turtle.fuel || '?');
|
||||||
const inventoryCount = turtle.inventory?.length || 0;
|
const inventoryCount = turtle.inventory?.length || 0;
|
||||||
|
|
||||||
@@ -11,8 +11,14 @@ function TurtleCard({ turtle, isSelected, onSelect }) {
|
|||||||
mining: '#4ade80',
|
mining: '#4ade80',
|
||||||
exploring: '#60a5fa',
|
exploring: '#60a5fa',
|
||||||
returning: '#f59e0b',
|
returning: '#f59e0b',
|
||||||
|
goHome: '#f59e0b',
|
||||||
idle: '#9ca3af',
|
idle: '#9ca3af',
|
||||||
manual: '#a78bfa',
|
manual: '#a78bfa',
|
||||||
|
refueling: '#ef4444',
|
||||||
|
farming: '#22c55e',
|
||||||
|
dumpInventory: '#a855f7',
|
||||||
|
dumping: '#a855f7',
|
||||||
|
moving: '#06b6d4',
|
||||||
unknown: '#6b7280'
|
unknown: '#6b7280'
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,12 +26,12 @@ function TurtleCard({ turtle, isSelected, onSelect }) {
|
|||||||
<div
|
<div
|
||||||
className={`turtle-card ${isSelected ? 'selected' : ''}`}
|
className={`turtle-card ${isSelected ? 'selected' : ''}`}
|
||||||
onClick={onSelect}
|
onClick={onSelect}
|
||||||
style={{ borderColor: modeColors[mode] }}
|
style={{ borderColor: modeColors[activeState] || modeColors.unknown }}
|
||||||
>
|
>
|
||||||
<div className="turtle-header">
|
<div className="turtle-header">
|
||||||
<h3>Turtle {turtle.turtleID}</h3>
|
<h3>Turtle {turtle.turtleID}</h3>
|
||||||
<span className="mode-badge" style={{ background: modeColors[mode] }}>
|
<span className="mode-badge" style={{ background: modeColors[activeState] || modeColors.unknown }}>
|
||||||
{mode}
|
{activeState}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -67,6 +73,7 @@ function TurtleCard({ turtle, isSelected, onSelect }) {
|
|||||||
|
|
||||||
function TurtleDetails({ turtle }) {
|
function TurtleDetails({ turtle }) {
|
||||||
const sendCommand = useTurtleStore((state) => state.sendCommand);
|
const sendCommand = useTurtleStore((state) => state.sendCommand);
|
||||||
|
const setTurtleState = useTurtleStore((state) => state.setTurtleState);
|
||||||
|
|
||||||
if (!turtle) {
|
if (!turtle) {
|
||||||
return (
|
return (
|
||||||
@@ -80,6 +87,12 @@ function TurtleDetails({ turtle }) {
|
|||||||
sendCommand(turtle.turtleID, command, param);
|
sendCommand(turtle.turtleID, command, param);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleStateChange = (stateName, data = {}) => {
|
||||||
|
setTurtleState(turtle.turtleID, stateName, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeState = turtle.state || turtle.mode || 'idle';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="turtle-details">
|
<div className="turtle-details">
|
||||||
<h2>Turtle {turtle.turtleID} Control</h2>
|
<h2>Turtle {turtle.turtleID} Control</h2>
|
||||||
@@ -88,9 +101,15 @@ function TurtleDetails({ turtle }) {
|
|||||||
<h3>Status</h3>
|
<h3>Status</h3>
|
||||||
<div className="status-grid">
|
<div className="status-grid">
|
||||||
<div className="status-item">
|
<div className="status-item">
|
||||||
<span className="label">Mode:</span>
|
<span className="label">State:</span>
|
||||||
<span className="value">{turtle.mode || 'unknown'}</span>
|
<span className="value">{activeState}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{turtle.stateDescription && (
|
||||||
|
<div className="status-item">
|
||||||
|
<span className="label">Activity:</span>
|
||||||
|
<span className="value">{turtle.stateDescription}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="status-item">
|
<div className="status-item">
|
||||||
<span className="label">Fuel:</span>
|
<span className="label">Fuel:</span>
|
||||||
<span className="value">
|
<span className="value">
|
||||||
@@ -119,7 +138,77 @@ function TurtleDetails({ turtle }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="detail-section">
|
<div className="detail-section">
|
||||||
<h3>Commands</h3>
|
<h3>State Machine</h3>
|
||||||
|
<div className="command-grid">
|
||||||
|
<button
|
||||||
|
className={`command-btn ${activeState === 'idle' ? 'active' : ''}`}
|
||||||
|
onClick={() => { handleStateChange('idle'); handleCommand('stop'); }}
|
||||||
|
title="Stop and go idle"
|
||||||
|
style={activeState === 'idle' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
⏸️ Idle
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`command-btn explore ${activeState === 'exploring' ? 'active' : ''}`}
|
||||||
|
onClick={() => { handleStateChange('exploring'); handleCommand('explore'); }}
|
||||||
|
title="Autonomous exploration"
|
||||||
|
style={activeState === 'exploring' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
🔍 Explore
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`command-btn mine ${activeState === 'mining' ? 'active' : ''}`}
|
||||||
|
onClick={() => { handleStateChange('mining'); handleCommand('explore'); }}
|
||||||
|
title="Mining with ore priority"
|
||||||
|
style={activeState === 'mining' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
⛏️ Mine
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`command-btn ${activeState === 'farming' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleStateChange('farming')}
|
||||||
|
title="Automated farming"
|
||||||
|
style={activeState === 'farming' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
🌾 Farm
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`command-btn return ${activeState === 'goHome' || activeState === 'returning' ? 'active' : ''}`}
|
||||||
|
onClick={() => { handleStateChange('goHome'); handleCommand('returnHome'); }}
|
||||||
|
title="Navigate home"
|
||||||
|
style={activeState === 'goHome' || activeState === 'returning' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
🏠 Go Home
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`command-btn refuel ${activeState === 'refueling' ? 'active' : ''}`}
|
||||||
|
onClick={() => { handleStateChange('refueling'); handleCommand('refuel'); }}
|
||||||
|
title="Auto-refuel from inventory"
|
||||||
|
style={activeState === 'refueling' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
⛽ Refuel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`command-btn ${activeState === 'dumpInventory' || activeState === 'dumping' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleStateChange('dumpInventory')}
|
||||||
|
title="Dump inventory into nearby container"
|
||||||
|
style={activeState === 'dumpInventory' || activeState === 'dumping' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
📦 Dump
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`command-btn ${activeState === 'moving' ? 'active' : ''}`}
|
||||||
|
onClick={() => handleStateChange('moving')}
|
||||||
|
title="Navigate to target"
|
||||||
|
style={activeState === 'moving' ? { outline: '2px solid #fff' } : {}}
|
||||||
|
>
|
||||||
|
🧭 Move To
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="detail-section">
|
||||||
|
<h3>Legacy Commands</h3>
|
||||||
<div className="command-grid">
|
<div className="command-grid">
|
||||||
<button
|
<button
|
||||||
className="command-btn explore"
|
className="command-btn explore"
|
||||||
|
|||||||
Reference in New Issue
Block a user