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 && (
)}
);
}