import React, { useState, useRef, useEffect } from 'react'; import { MapPin, Upload, X, Eye, EyeOff } from './Icons'; import { Zone } from '../types/zone'; interface ZoneMarker { id: number; x: number; // Percentage from left y: number; // Percentage from top } interface SitePlanProps { zones: Zone[]; onZoneSelect: (zone: Zone) => void; selectedZoneId?: number; } const SitePlan: React.FC = ({ zones, onZoneSelect, selectedZoneId }) => { const [sitePlanImage, setSitePlanImage] = useState( localStorage.getItem('sitePlanImage') ); const [zoneMarkers, setZoneMarkers] = useState(() => { const saved = localStorage.getItem('zoneMarkers'); return saved ? JSON.parse(saved) : []; }); const [isEditMode, setIsEditMode] = useState(false); const [showMarkers, setShowMarkers] = useState(true); const fileInputRef = useRef(null); const imageRef = useRef(null); // Save markers to localStorage whenever they change useEffect(() => { localStorage.setItem('zoneMarkers', JSON.stringify(zoneMarkers)); }, [zoneMarkers]); const handleImageUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { const imageUrl = e.target?.result as string; setSitePlanImage(imageUrl); localStorage.setItem('sitePlanImage', imageUrl); }; reader.readAsDataURL(file); } }; const handleImageClick = (e: React.MouseEvent) => { if (!isEditMode || !imageRef.current) return; const rect = imageRef.current.getBoundingClientRect(); const x = ((e.clientX - rect.left) / rect.width) * 100; const y = ((e.clientY - rect.top) / rect.height) * 100; // Find a zone that doesn't have a marker yet const unmarkedZone = zones.find(zone => !zoneMarkers.some(marker => marker.id === zone.id) ); if (unmarkedZone) { const newMarker: ZoneMarker = { id: unmarkedZone.id, x, y }; setZoneMarkers(prev => [...prev, newMarker]); } }; const removeMarker = (zoneId: number) => { setZoneMarkers(prev => prev.filter(marker => marker.id !== zoneId)); }; const clearSitePlan = () => { if (window.confirm('Are you sure you want to remove the site plan and all markers?')) { setSitePlanImage(null); setZoneMarkers([]); localStorage.removeItem('sitePlanImage'); localStorage.removeItem('zoneMarkers'); setIsEditMode(false); } }; const getZoneById = (id: number) => zones.find(zone => zone.id === id); const getMarkerColor = (zone: Zone) => { switch (zone.status) { case 'overdue': return 'bg-red-500 border-red-600 shadow-red-200'; case 'due': return 'bg-orange-500 border-orange-600 shadow-orange-200'; default: return 'bg-green-500 border-green-600 shadow-green-200'; } }; if (!sitePlanImage) { return (

План участка

Загрузите изображение участка, чтобы визуализировать расположение зон

Поддерживаемые форматы: JPG, PNG, GIF (максимально 10MB)

); } return (
{/* Header */}

План участка

({zoneMarkers.length} of {zones.length} zones marked)
{isEditMode && (

Edit Mode: Click on the image to place markers for zones. Zones without markers: {zones.filter(zone => !zoneMarkers.some(marker => marker.id === zone.id)).map(zone => zone.name).join(', ') || 'None'}

)}
{/* Site Plan Image */}
План участка {/* Zone Markers */} {showMarkers && zoneMarkers.map(marker => { const zone = getZoneById(marker.id); if (!zone) return null; return (
{/* Marker */} {/* Tooltip */}
{zone.name}
{zone.isOverdue ? 'Срок прошел' : zone.isDueToday ? 'Срок - сегодня' : `${zone.daysUntilNext} дней`}
{/* Remove button in edit mode */} {isEditMode && ( )}
); })}
{/* Legend */} {showMarkers && zoneMarkers.length > 0 && (

Zone Status Legend

Up to date
Срок - сегодня
Overdue
)}
); }; export default SitePlan;