import React, { useState, useEffect } from 'react'; import './MiningAreasPanel.css'; export default function MiningAreasPanel({ turtles, selectedTurtle, apiUrl }) { const [areas, setAreas] = useState([]); const [showCreateForm, setShowCreateForm] = useState(false); const [newArea, setNewArea] = useState({ areaName: '', color: '#4a8c2a', startX: '', startY: '', startZ: '', endX: '', endY: '', endZ: '', turtleID: '' }); const [filterStatus, setFilterStatus] = useState('all'); // all, planned, mining, completed // Load mining areas useEffect(() => { loadAreas(); const interval = setInterval(loadAreas, 5000); return () => clearInterval(interval); }, [apiUrl]); const loadAreas = async () => { try { const response = await fetch(`${apiUrl}/api/mining-areas`); if (response.ok) { const data = await response.json(); // Server returns a flat array of formatted areas setAreas(Array.isArray(data) ? data : (data.areas || [])); } } catch (error) { console.error('Failed to load mining areas:', error); } }; // Create new mining area const handleCreateArea = async (e) => { e.preventDefault(); if (!newArea.areaName || !newArea.turtleID) { alert('Please provide area name and assign a turtle'); return; } // Validate coordinates const coords = ['startX', 'startY', 'startZ', 'endX', 'endY', 'endZ']; for (const coord of coords) { if (newArea[coord] === '' || isNaN(Number(newArea[coord]))) { alert(`Please provide valid ${coord} coordinate`); return; } } try { const response = await fetch(`${apiUrl}/api/mining-areas`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...newArea, startX: Number(newArea.startX), startY: Number(newArea.startY), startZ: Number(newArea.startZ), endX: Number(newArea.endX), endY: Number(newArea.endY), endZ: Number(newArea.endZ), color: newArea.color, status: 'planned' }) }); if (response.ok) { setShowCreateForm(false); setNewArea({ areaName: '', startX: '', startY: '', startZ: '', endX: '', endY: '', endZ: '', turtleID: '' }); loadAreas(); } else { const error = await response.json(); alert(`Failed to create area: ${error.error || 'Unknown error'}`); } } catch (error) { console.error('Failed to create mining area:', error); alert('Failed to create mining area'); } }; // Delete mining area const handleDeleteArea = async (areaID) => { if (!confirm('Are you sure you want to delete this mining area?')) return; try { const response = await fetch(`${apiUrl}/api/mining-areas/${areaID}`, { method: 'DELETE' }); if (response.ok) { loadAreas(); } else { alert('Failed to delete area'); } } catch (error) { console.error('Failed to delete area:', error); alert('Failed to delete area'); } }; // Update area status const handleUpdateStatus = async (areaID, newStatus) => { try { const response = await fetch(`${apiUrl}/api/mining-areas/${areaID}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: newStatus }) }); if (response.ok) { loadAreas(); } else { alert('Failed to update status'); } } catch (error) { console.error('Failed to update status:', error); alert('Failed to update status'); } }; // Auto-fill from selected turtle position const handleUseCurrentPosition = () => { if (!selectedTurtle || !selectedTurtle.position) { alert('No turtle selected or turtle has no position'); return; } const pos = selectedTurtle.position; setNewArea(prev => ({ ...prev, startX: pos.x.toString(), startY: pos.y.toString(), startZ: pos.z.toString(), turtleID: selectedTurtle.turtleID.toString() })); }; // Calculate volume const calculateVolume = (area) => { const width = Math.abs(area.endX - area.startX) + 1; const height = Math.abs(area.endY - area.startY) + 1; const depth = Math.abs(area.endZ - area.startZ) + 1; return width * height * depth; }; // Check for overlapping areas const checkOverlap = (area1, area2) => { const overlapX = Math.max( Math.min(area1.endX, area2.endX) - Math.max(area1.startX, area2.startX) + 1, 0 ); const overlapY = Math.max( Math.min(area1.endY, area2.endY) - Math.max(area1.startY, area2.startY) + 1, 0 ); const overlapZ = Math.max( Math.min(area1.endZ, area2.endZ) - Math.max(area1.startZ, area2.startZ) + 1, 0 ); return overlapX > 0 && overlapY > 0 && overlapZ > 0; }; // Find conflicts const findConflicts = (area) => { return areas.filter(other => other.areaID !== area.areaID && checkOverlap(area, other) ); }; // Filter areas const filteredAreas = areas.filter(area => { if (filterStatus === 'all') return true; return area.status === filterStatus; }); // Status badge component const StatusBadge = ({ status }) => { const colors = { planned: '#345ec3', mining: '#ffaa00', completed: '#4a8c2a' }; return ( {status} ); }; return (
No mining areas {filterStatus !== 'all' ? `with status "${filterStatus}"` : ''}
{filterStatus === 'all' && (Create a new area to get started
)}