From 2c54a60d84a70f7b2de990ef82f09bacab34bfee Mon Sep 17 00:00:00 2001 From: Jake Kasper Date: Thu, 21 Aug 2025 17:50:33 -0400 Subject: [PATCH] polygons --- .../src/pages/Properties/PropertyDetail.js | 185 ++++++++++++++---- 1 file changed, 152 insertions(+), 33 deletions(-) diff --git a/frontend/src/pages/Properties/PropertyDetail.js b/frontend/src/pages/Properties/PropertyDetail.js index b52cae3..c7e2b47 100644 --- a/frontend/src/pages/Properties/PropertyDetail.js +++ b/frontend/src/pages/Properties/PropertyDetail.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import { MapContainer, TileLayer, Marker, Popup, Polygon, useMapEvents } from 'react-leaflet'; +import { MapContainer, TileLayer, Marker, Popup, Polygon, useMapEvents, useMap } from 'react-leaflet'; import { Icon } from 'leaflet'; import * as turf from '@turf/turf'; import { @@ -88,6 +88,141 @@ function PolygonDrawer({ isDrawing, onPolygonComplete, currentColor }) { ) : null; } +// Component for editable polygons +function EditablePolygon({ section, onUpdate, onEdit, onDelete }) { + // Import toast function from the module scope + const [isEditing, setIsEditing] = useState(false); + const [editedCoordinates, setEditedCoordinates] = useState(section.coordinates); + const map = useMap(); + + const handleMarkerDrag = (index, newLatLng) => { + const newCoords = [...editedCoordinates]; + newCoords[index] = [newLatLng.lat, newLatLng.lng]; + setEditedCoordinates(newCoords); + + // Recalculate area + const area = calculateAreaInSqFt([...newCoords, newCoords[0]]); + onUpdate(section.id, { ...section, coordinates: newCoords, area }); + }; + + const addPointAtIndex = (index, e) => { + e.originalEvent.stopPropagation(); + const newCoords = [...editedCoordinates]; + const newPoint = [e.latlng.lat, e.latlng.lng]; + newCoords.splice(index + 1, 0, newPoint); + setEditedCoordinates(newCoords); + + const area = calculateAreaInSqFt([...newCoords, newCoords[0]]); + onUpdate(section.id, { ...section, coordinates: newCoords, area }); + }; + + const removePoint = (index) => { + if (editedCoordinates.length <= 3) { + toast.error('Polygon must have at least 3 points'); + return; + } + const newCoords = editedCoordinates.filter((_, i) => i !== index); + setEditedCoordinates(newCoords); + + const area = calculateAreaInSqFt([...newCoords, newCoords[0]]); + onUpdate(section.id, { ...section, coordinates: newCoords, area }); + }; + + return ( + <> + { + if (!isEditing) { + setIsEditing(true); + toast.info('Edit mode: Drag points to move, right-click to add/remove points'); + } + } + }} + > + +
+ {section.name}
+ {section.area.toLocaleString()} sq ft
+
+ + + +
+
+
+
+ + {/* Editable markers for each point */} + {isEditing && editedCoordinates.map((coord, index) => ( + { + handleMarkerDrag(index, e.target.getLatLng()); + }, + contextmenu: (e) => { + e.originalEvent.preventDefault(); + if (editedCoordinates.length > 3) { + removePoint(index); + } + } + }} + icon={new Icon({ + iconUrl: 'data:image/svg+xml;base64,' + btoa(` + + + + `), + iconSize: [12, 12], + iconAnchor: [6, 6] + })} + > + +
+

Point {index + 1}

+ +
+
+
+ ))} + + ); +} + const PropertyDetail = () => { const { id } = useParams(); const navigate = useNavigate(); @@ -212,6 +347,10 @@ const PropertyDetail = () => { setShowEditModal(false); }; + const updateSection = (sectionId, updatedSection) => { + setLawnSections(prev => prev.map(s => s.id === sectionId ? updatedSection : s)); + }; + const getTotalArea = () => { return lawnSections.reduce((total, section) => total + section.area, 0); }; @@ -290,13 +429,14 @@ const PropertyDetail = () => {
{hasValidCoordinates && ( @@ -306,37 +446,13 @@ const PropertyDetail = () => { )} {lawnSections.map((section) => ( - - -
- {section.name}
- {section.area.toLocaleString()} sq ft
-
- - -
-
-
-
+ section={section} + onUpdate={updateSection} + onEdit={startEditSection} + onDelete={deleteLawnSection} + /> ))} {isDrawing && ( @@ -360,6 +476,9 @@ const PropertyDetail = () => {

Need at least 3 points to create a section. Press ESC to cancel.

+

+ 💡 After creating: Click any polygon to edit its points by dragging +

)}