import React, { useState, useEffect } from 'react'; import { Plus, Filter, Calendar, Scissors, AlertTriangle, Square, CheckCircle, Clock, Map, History } from './Icons'; import { Zone, MowingFormData, BulkMowingFormData } from '../types/zone'; import { api } from '../services/api'; import ZoneCard from './ZoneCard'; import ZoneForm from './ZoneForm'; import SitePlan from './SitePlan'; import HistoryView from './HistoryView'; import MowingModal from './MowingModal'; import BulkMowingModal from "./BulkMowingModal"; type FilterType = 'all' | 'due' | 'overdue' | 'new'; type ViewType = 'dashboard' | 'sitePlan' | 'history'; const Dashboard: React.FC = () => { const [zones, setZones] = useState([]); const [filteredZones, setFilteredZones] = useState([]); const [filter, setFilter] = useState('all'); const [view, setView] = useState('dashboard'); const [showForm, setShowForm] = useState(false); const [editingZone, setEditingZone] = useState(null); const [selectedZoneId, setSelectedZoneId] = useState(); const [showMowingModal, setShowMowingModal] = useState(false); const [showBulkMowingModal, setShowBulkMowingModal] = useState(false); const [mowingZone, setMowingZone] = useState(null); const [loading, setLoading] = useState(true); const [mowingLoading, setMowingLoading] = useState(false); useEffect(() => { loadZones(); }, []); useEffect(() => { applyFilter(); }, [zones, filter]); const loadZones = async () => { try { const data = await api.getZones(); setZones(data); } catch (error) { console.error('Failed to load zones:', error); } finally { setLoading(false); } }; const applyFilter = () => { let filtered = zones; switch (filter) { case 'due': filtered = zones.filter(zone => zone.isDueToday); break; case 'overdue': filtered = zones.filter(zone => zone.isOverdue); break; case 'new': filtered = zones.filter(zone => zone.isNew); break; default: filtered = zones; } setFilteredZones(filtered); }; const handleMarkAsMowed = (zone: Zone) => { setMowingZone(zone); setShowMowingModal(true); }; const handleMowingSubmit = async (data: MowingFormData) => { if (!mowingZone) return; setMowingLoading(true); try { await api.markAsMowed(mowingZone.id, data); setShowMowingModal(false); setMowingZone(null); loadZones(); } catch (error) { console.error('Failed to mark as mowed:', error); } finally { setMowingLoading(false); } }; const handleBulkMowingSubmit = async (data: BulkMowingFormData) => { setMowingLoading(true); try { await api.bulkMarkAsMowed(data); setShowBulkMowingModal(false); loadZones(); } catch (error) { console.error('Failed to record bulk mowing session:', error); } finally { setMowingLoading(false); } }; const handleDeleteZone = async (id: number) => { if (window.confirm('Are you sure you want to delete this zone?')) { try { await api.deleteZone(id); loadZones(); if (selectedZoneId === id) { setSelectedZoneId(undefined); } } catch (error) { console.error('Failed to delete zone:', error); } } }; const handleFormSubmit = async () => { setShowForm(false); setEditingZone(null); loadZones(); }; const handleZoneSelect = (zone: Zone) => { setSelectedZoneId(zone.id); setView('dashboard'); // Scroll to the zone card setTimeout(() => { const element = document.getElementById(`zone-card-${zone.id}`); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }, 100); }; // Calculate area statistics const overdueCount = zones.filter(zone => zone.isOverdue).length; const dueCount = zones.filter(zone => zone.isDueToday).length; const newCount = zones.filter(zone => zone.isNew).length; const okCount = zones.filter(zone => zone.status === 'ok').length; const totalArea = zones.reduce((sum, zone) => sum + zone.area, 0); // Calculate mowed vs remaining area based on status const mowedArea = zones .filter(zone => zone.status === 'ok') .reduce((sum, zone) => sum + zone.area, 0); const mowedPercentage = totalArea > 0 ? (mowedArea / totalArea) * 100 : 0; // Check if there are zones that need mowing for bulk action const zonesNeedingMowing = zones.filter(zone => zone.status === 'due' || zone.status === 'overdue' || zone.status === 'new' ); if (loading) { return (
); } return (
{/* Header */}

Менеджер по уходу за газоном

Следите за своим графиком стрижки газона

{/* View Toggle */}
{view === 'history' ? ( ) : view === 'sitePlan' ? ( ) : ( <> {/* Stats Cards */}

Кол-во зон

{zones.length}

Площадь, вся

{totalArea.toLocaleString()}

м2

Актуально

{okCount}

обслужено зон

{/*

Новые зоны

{newCount}

еще не косились

*/}

Внимание!

{dueCount + overdueCount}

зон для покоса

Срок - сегодня

{dueCount}

Срок прошел

{overdueCount}

{/* Progress Bar */} {totalArea > 0 && (

Ход скашивания

{mowedArea.toLocaleString()} / {totalArea.toLocaleString()} м2
{mowedPercentage.toFixed(1)}% Завершено ({okCount} зон) {(100 - mowedPercentage).toFixed(1)}% Осталось ({dueCount + overdueCount} зон)
)} {/* Bulk Mowing Notice */} {zonesNeedingMowing.length > 1 && (

Необходимо скосить несколько зон

Используйте массовое скашивание для записи нескольких зон, скошенных за один сеанс, с пропорциональным распределением времени

)} {/* Filter Buttons */}
Фильтр:
{[ { key: 'all' as FilterType, label: 'Все зоны', count: zones.length }, { key: 'new' as FilterType, label: 'Новые зоны', count: newCount }, { key: 'due' as FilterType, label: 'Срок - сегодня', count: dueCount }, { key: 'overdue' as FilterType, label: 'Срок прошел', count: overdueCount }, ].map(({ key, label, count }) => ( ))}
{/* Zones Grid */} {filteredZones.length === 0 ? (

Не найдено ни одной зоны

{filter === 'all' ? 'Get started by adding your first lawn zone.' : `Нет подходящих зон для "${filter}" фильтра.`}

) : (
{filteredZones.map(zone => (
{ setEditingZone(zone); setShowForm(true); }} onDelete={handleDeleteZone} />
))}
)} )} {/* Zone Form Modal */} {showForm && ( { setShowForm(false); setEditingZone(null); }} /> )} {/* Single Zone Mowing Modal */} {showMowingModal && mowingZone && ( { setShowMowingModal(false); setMowingZone(null); }} loading={mowingLoading} /> )} {/* Bulk Mowing Modal */} {showBulkMowingModal && ( setShowBulkMowingModal(false)} loading={mowingLoading} /> )}
); }; export default Dashboard;