update some stuff

This commit is contained in:
Jake Kasper
2025-08-21 17:46:56 -04:00
parent b114fb1d22
commit 79bff678f7

View File

@@ -8,7 +8,8 @@ import {
TrashIcon, TrashIcon,
ArrowLeftIcon, ArrowLeftIcon,
MapPinIcon, MapPinIcon,
SwatchIcon SwatchIcon,
PencilIcon
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import { propertiesAPI } from '../../services/api'; import { propertiesAPI } from '../../services/api';
import LoadingSpinner from '../../components/UI/LoadingSpinner'; import LoadingSpinner from '../../components/UI/LoadingSpinner';
@@ -54,10 +55,19 @@ function PolygonDrawer({ isDrawing, onPolygonComplete, currentColor }) {
if (!isDrawing) return; if (!isDrawing) return;
const newPoint = [e.latlng.lat, e.latlng.lng]; const newPoint = [e.latlng.lat, e.latlng.lng];
setCurrentPolygon(prev => [...prev, newPoint]); console.log('Adding point:', newPoint);
setCurrentPolygon(prev => {
const newPoly = [...prev, newPoint];
console.log('Current polygon has', newPoly.length, 'points');
return newPoly;
});
}, },
dblclick() { dblclick(e) {
console.log('Double click detected, drawing:', isDrawing, 'points:', currentPolygon.length);
if (isDrawing && currentPolygon.length >= 3) { if (isDrawing && currentPolygon.length >= 3) {
e.originalEvent.preventDefault();
e.originalEvent.stopPropagation();
console.log('Completing polygon with', currentPolygon.length, 'points');
onPolygonComplete(currentPolygon); onPolygonComplete(currentPolygon);
setCurrentPolygon([]); setCurrentPolygon([]);
} }
@@ -89,11 +99,30 @@ const PropertyDetail = () => {
const [showNameModal, setShowNameModal] = useState(false); const [showNameModal, setShowNameModal] = useState(false);
const [pendingSection, setPendingSection] = useState(null); const [pendingSection, setPendingSection] = useState(null);
const [sectionName, setSectionName] = useState(''); const [sectionName, setSectionName] = useState('');
const [editingSection, setEditingSection] = useState(null);
const [showEditModal, setShowEditModal] = useState(false);
useEffect(() => { useEffect(() => {
fetchPropertyDetails(); fetchPropertyDetails();
}, [id]); // eslint-disable-line react-hooks/exhaustive-deps }, [id]); // eslint-disable-line react-hooks/exhaustive-deps
// Handle keyboard shortcuts for polygon drawing
useEffect(() => {
const handleKeyPress = (e) => {
if (isDrawing && e.key === 'Enter') {
// Find the PolygonDrawer component and complete the polygon
console.log('Enter pressed during drawing mode');
}
if (e.key === 'Escape' && isDrawing) {
setIsDrawing(false);
toast.info('Drawing cancelled');
}
};
document.addEventListener('keydown', handleKeyPress);
return () => document.removeEventListener('keydown', handleKeyPress);
}, [isDrawing]);
const fetchPropertyDetails = async () => { const fetchPropertyDetails = async () => {
try { try {
setLoading(true); setLoading(true);
@@ -110,12 +139,14 @@ const PropertyDetail = () => {
}; };
const handlePolygonComplete = (coordinates) => { const handlePolygonComplete = (coordinates) => {
console.log('handlePolygonComplete called with', coordinates.length, 'coordinates');
if (coordinates.length < 3) { if (coordinates.length < 3) {
toast.error('Polygon needs at least 3 points'); toast.error('Polygon needs at least 3 points');
return; return;
} }
const area = calculateAreaInSqFt([...coordinates, coordinates[0]]); const area = calculateAreaInSqFt([...coordinates, coordinates[0]]);
console.log('Calculated area:', area);
setPendingSection({ coordinates, color: currentColor, area }); setPendingSection({ coordinates, color: currentColor, area });
setShowNameModal(true); setShowNameModal(true);
setIsDrawing(false); setIsDrawing(false);
@@ -153,6 +184,34 @@ const PropertyDetail = () => {
} }
}; };
const startEditSection = (section) => {
setEditingSection(section);
setSectionName(section.name);
setCurrentColor(section.color);
setShowEditModal(true);
};
const saveEditedSection = () => {
if (!sectionName.trim()) {
toast.error('Please enter a section name');
return;
}
const updatedSection = {
...editingSection,
name: sectionName,
color: currentColor
};
setLawnSections(prev => prev.map(s => s.id === editingSection.id ? updatedSection : s));
toast.success('Section updated!');
// Reset
setSectionName('');
setEditingSection(null);
setShowEditModal(false);
};
const getTotalArea = () => { const getTotalArea = () => {
return lawnSections.reduce((total, section) => total + section.area, 0); return lawnSections.reduce((total, section) => total + section.area, 0);
}; };
@@ -231,7 +290,8 @@ const PropertyDetail = () => {
<div style={{ height: '600px', width: '100%' }}> <div style={{ height: '600px', width: '100%' }}>
<MapContainer <MapContainer
center={mapCenter} center={mapCenter}
zoom={hasValidCoordinates ? 19 : 13} zoom={hasValidCoordinates ? 21 : 13}
maxZoom={23}
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
> >
<TileLayer <TileLayer
@@ -260,12 +320,20 @@ const PropertyDetail = () => {
<div className="text-center"> <div className="text-center">
<strong>{section.name}</strong><br /> <strong>{section.name}</strong><br />
{section.area.toLocaleString()} sq ft<br /> {section.area.toLocaleString()} sq ft<br />
<button <div className="flex gap-2 mt-2">
onClick={() => deleteLawnSection(section.id)} <button
className="text-red-600 text-sm mt-2" onClick={() => startEditSection(section)}
> className="text-blue-600 text-sm"
Delete >
</button> Edit
</button>
<button
onClick={() => deleteLawnSection(section.id)}
className="text-red-600 text-sm"
>
Delete
</button>
</div>
</div> </div>
</Popup> </Popup>
</Polygon> </Polygon>
@@ -282,9 +350,15 @@ const PropertyDetail = () => {
</div> </div>
{isDrawing && ( {isDrawing && (
<div className="p-4 bg-blue-50"> <div className="p-4 bg-blue-50 border-t">
<p className="text-sm text-blue-800"> <div className="flex items-center gap-2">
<strong>Drawing Mode:</strong> Click to add points. Double-click to complete polygon. <div className="w-3 h-3 bg-blue-600 rounded-full animate-pulse"></div>
<p className="text-sm text-blue-800">
<strong>Drawing Mode Active:</strong> Click to add points. Double-click to complete polygon.
</p>
</div>
<p className="text-xs text-blue-600 mt-1">
Need at least 3 points to create a section. Press ESC to cancel.
</p> </p>
</div> </div>
)} )}
@@ -350,12 +424,20 @@ const PropertyDetail = () => {
<p className="text-xs text-gray-600">{section.area.toLocaleString()} sq ft</p> <p className="text-xs text-gray-600">{section.area.toLocaleString()} sq ft</p>
</div> </div>
</div> </div>
<button <div className="flex gap-1">
onClick={() => deleteLawnSection(section.id)} <button
className="text-red-600 hover:text-red-800" onClick={() => startEditSection(section)}
> className="text-blue-600 hover:text-blue-800"
<TrashIcon className="h-4 w-4" /> >
</button> <PencilIcon className="h-4 w-4" />
</button>
<button
onClick={() => deleteLawnSection(section.id)}
className="text-red-600 hover:text-red-800"
>
<TrashIcon className="h-4 w-4" />
</button>
</div>
</div> </div>
))} ))}
</div> </div>
@@ -366,8 +448,8 @@ const PropertyDetail = () => {
{/* Name Modal */} {/* Name Modal */}
{showNameModal && ( {showNameModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center" style={{ zIndex: 9999 }}>
<div className="bg-white rounded-lg p-6 w-96"> <div className="bg-white rounded-lg p-6 w-96 shadow-2xl">
<h3 className="text-lg font-semibold mb-4">Name Your Lawn Section</h3> <h3 className="text-lg font-semibold mb-4">Name Your Lawn Section</h3>
<div className="space-y-4"> <div className="space-y-4">
<input <input
@@ -404,6 +486,68 @@ const PropertyDetail = () => {
</div> </div>
</div> </div>
)} )}
{/* Edit Modal */}
{showEditModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center" style={{ zIndex: 9999 }}>
<div className="bg-white rounded-lg p-6 w-96 shadow-2xl">
<h3 className="text-lg font-semibold mb-4">Edit Lawn Section</h3>
<div className="space-y-4">
<div>
<label className="label">Section Name</label>
<input
type="text"
className="input"
value={sectionName}
onChange={(e) => setSectionName(e.target.value)}
placeholder="e.g., Front Yard, Back Lawn"
autoFocus
/>
</div>
<div>
<label className="label">Color</label>
<div className="grid grid-cols-3 gap-2">
{SECTION_COLORS.map((color) => (
<button
key={color.value}
onClick={() => setCurrentColor(color)}
className={`w-10 h-10 rounded border-2 ${
currentColor.value === color.value ? 'border-gray-900' : 'border-gray-300'
}`}
style={{ backgroundColor: color.value }}
title={color.name}
/>
))}
</div>
</div>
<div className="flex items-center gap-2 text-sm text-gray-600">
<div
className="w-4 h-4 rounded"
style={{ backgroundColor: currentColor.value }}
/>
<span>{editingSection?.area.toLocaleString()} sq ft</span>
</div>
</div>
<div className="flex gap-3 mt-6">
<button onClick={saveEditedSection} className="btn-primary flex-1">
Save Changes
</button>
<button
onClick={() => {
setShowEditModal(false);
setEditingSection(null);
setSectionName('');
}}
className="btn-secondary flex-1"
>
Cancel
</button>
</div>
</div>
</div>
)}
</div> </div>
); );
}; };