import React, { useMemo } from 'react'; import { Card, CardContent, CardActions, Button, Typography, List, ListItem, ListItemText, ListItemSecondaryAction, IconButton, Divider, Box, ListItemButton, ListItemIcon } from '@mui/material'; import DeleteIcon from '@mui/icons-material/Delete'; import DragIndicatorIcon from '@mui/icons-material/DragIndicator'; import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core'; import { SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable, } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; // A new component for the sortable list item, using dnd-kit hooks function SortablePointItem({ point, index, onPreviewPoint, onPointSelect }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: String(point.id) }); const style = { transform: CSS.Transform.toString(transform), transition, zIndex: isDragging ? 100 : 'auto', // Ensure dragging item is on top }; return ( onPreviewPoint(point.id || 0)} onMouseLeave={() => onPreviewPoint(0)} sx={{ cursor: 'grab', touchAction: 'none', bgcolor: isDragging ? 'action.hover' : 'transparent', }} > onPointSelect(point)}> ); } export default function GeometryCreatorPanel({ isOpen, drawingState, onCancel, onFinish, onPointSelect, // To remove a point from the list onPreviewPoint, // For the available points list availablePoints, multiSelectPoints, onAvailablePointClick, onAddMultiSelectedPoints, onClearPoints, onReorderPoints, }) { if (!isOpen) { return null; } const { mode, points: selectedPoints } = drawingState; const title = mode === 'polyline' ? 'Create Polyline' : 'Create Polygon'; const finishText = mode === 'polyline' ? 'Finish Polyline' : 'Finish Polygon'; const minPoints = mode === 'polyline' ? 2 : 3; const availablePointsToShow = useMemo(() => { const selectedIds = new Set(selectedPoints.map(p => p.id)); return availablePoints.filter(p => !selectedIds.has(p.id)); }, [availablePoints, selectedPoints]); const sensors = useSensors( useSensor(PointerSensor, { // Require the mouse to move by a few pixels before activating activationConstraint: { distance: 5, }, }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates, }) ); function handleDragEnd(event) { const { active, over } = event; if (over && active.id !== over.id) { const oldIndex = selectedPoints.findIndex(p => String(p.id) === active.id); const newIndex = selectedPoints.findIndex(p => String(p.id) === over.id); if (oldIndex !== -1 && newIndex !== -1) { onReorderPoints(oldIndex, newIndex); } } } return ( {title} Select existing measured points from the 3D view or the list below. Selected Points ({selectedPoints.length}) {selectedPoints.length > 0 && ( )} {selectedPoints.length === 0 ? ( No points selected yet. ) : ( String(p.id))} strategy={verticalListSortingStrategy}> {selectedPoints.map((point, index) => ( ))} )} Available Measured Points {availablePointsToShow.map((point) => ( onAvailablePointClick(event, point.id)} selected={multiSelectPoints.includes(point.id)} onMouseEnter={() => onPreviewPoint(point.id)} onMouseLeave={() => onPreviewPoint(0)} sx={{ borderRadius: 1, "&.Mui-selected": { bgcolor: "primary.light", color: "primary.contrastText", "&:hover": { bgcolor: "primary.main" }, }, }} > ))} {availablePointsToShow.length === 0 && ( )} ); }