import React, { useState, useEffect } from 'react'; import { History, BarChart, Calendar, Timer, Cloud, FileText, Square, ChevronDown, ChevronUp, Scissors, Users, Zap } from './Icons'; import { MowingHistory, MowingHistoryResponse, MowingStats, Zone } from '../types/zone'; import { api } from '../services/api'; import Pagination from './Pagination'; interface HistoryViewProps { zones: Zone[]; } interface SessionGroup { sessionId: string; entries: MowingHistory[]; totalDuration: number; totalArea: number; mowedDate: string; weather?: string; notes?: string; mowerName?: string; mowerType?: string; } const HistoryView: React.FC = ({ zones }) => { const [historyResponse, setHistoryResponse] = useState(null); const [stats, setStats] = useState(null); const [selectedZone, setSelectedZone] = useState(); const [period, setPeriod] = useState(30); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); const [loading, setLoading] = useState(true); const [expandedEntry, setExpandedEntry] = useState(null); const [expandedSession, setExpandedSession] = useState(null); useEffect(() => { loadData(); }, [selectedZone, period, currentPage, pageSize]); const loadData = async () => { setLoading(true); try { const offset = (currentPage - 1) * pageSize; const [historyData, statsData] = await Promise.all([ api.getMowingHistory(selectedZone, pageSize, offset), api.getMowingStats(period) ]); setHistoryResponse(historyData); setStats(statsData); } catch (error) { console.error('Failed to load history data:', error); } finally { setLoading(false); } }; const handlePageChange = (page: number) => { setCurrentPage(page); }; const handleZoneChange = (zoneId: number | undefined) => { setSelectedZone(zoneId); setCurrentPage(1); // Reset to first page when changing filters }; const handlePeriodChange = (newPeriod: number) => { setPeriod(newPeriod); setCurrentPage(1); // Reset to first page when changing filters }; const handlePageSizeChange = (newPageSize: number) => { setPageSize(newPageSize); setCurrentPage(1); // Reset to first page when changing page size }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('ru-RU', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', }); }; const formatTime = (dateString: string) => { return new Date(dateString).toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit', }); }; const formatDuration = (minutes: number) => { if (minutes < 60) return `${minutes}м`; const hours = Math.floor(minutes / 60); const mins = minutes % 60; return mins > 0 ? `${hours}ч ${mins}м` : `${hours}ч`; }; const getZoneName = (zoneId: number) => { const zone = zones.find(z => z.id === zoneId); return zone?.name || 'Неизвестная зона'; }; const getMowerIcon = (type?: string) => { if (!type) return '🚜'; switch (type.toLowerCase()) { case 'battery': return '🔋'; case 'electric': return '⚡'; case 'gas': case 'petrol': return '⛽'; default: return '🚜'; } }; const getActivityIcon = (activityType?: string) => { return activityType === 'trimming' ? ( ) : ( ); }; const getActivityLabel = (activityType?: string) => { return activityType === 'trimming' ? 'Trimming' : 'Mowing'; }; // Group history entries by session const groupBySession = (entries: MowingHistory[]): (SessionGroup | MowingHistory)[] => { const sessionMap = new Map(); const singleEntries: MowingHistory[] = []; entries.forEach(entry => { if (entry.sessionId) { if (!sessionMap.has(entry.sessionId)) { sessionMap.set(entry.sessionId, []); } sessionMap.get(entry.sessionId)!.push(entry); } else { singleEntries.push(entry); } }); const result: (SessionGroup | MowingHistory)[] = []; // Add session groups sessionMap.forEach((sessionEntries, sessionId) => { if (sessionEntries.length > 1) { // This is a bulk session const totalDuration = sessionEntries.reduce((sum, entry) => sum + (entry.duration || 0), 0); const totalArea = sessionEntries.reduce((sum, entry) => sum + entry.zoneArea, 0); const firstEntry = sessionEntries[0]; result.push({ sessionId, entries: sessionEntries.sort((a, b) => a.zoneName.localeCompare(b.zoneName)), totalDuration, totalArea, mowedDate: firstEntry.mowedDate, weather: firstEntry.weather, notes: firstEntry.notes, mowerName: firstEntry.mowerName, mowerType: firstEntry.mowerType, }); } else { // Single entry that happens to have a session ID result.push(sessionEntries[0]); } }); // Add single entries singleEntries.forEach(entry => result.push(entry)); // Sort by date (most recent first) return result.sort((a, b) => { const dateA = a.mowedDate; const dateB = b.mowedDate; return new Date(dateB).getTime() - new Date(dateA).getTime(); }); }; if (loading) { return (
); } const groupedHistory = historyResponse ? groupBySession(historyResponse.data) : []; return (
{/* Header and Filters */}

История покосов

Следите за своими мероприятиями по уходу за газоном и прогрессом в их выполнении

{/* Zone Filter */} {/* Period Filter */} {/* Page Size Filter */}
{/* Statistics Cards */} {stats && (

Всего сессий

{stats.totalSessions}

Всего времени

{formatDuration(stats.totalMinutes)}

Всего площадь

{stats.totalArea.toLocaleString()}

м2

Наибольшая активность

{stats.mostActiveZone?.name || 'НЕТ'}

{stats.mostActiveZone && (

{stats.mostActiveZone.sessions} сессии

)}

Часто используется

{stats.mostUsedMower?.name || 'НЕТ'}

{stats.mostUsedMower && (

{getMowerIcon(stats.mostUsedMower.type)} {stats.mostUsedMower.sessions} сессии

)}
)} {/* History List */}

Недавняя активность

{selectedZone ? `История для ${getZoneName(selectedZone)}` : 'Все зоны'}

{!historyResponse || historyResponse.data.length === 0 ? (

Пока нет истории

{selectedZone ? 'В этой зоне еще нет выходов на скашивание.' : 'Начните скашивать зоны, чтобы просмотреть свою историю здесь.' }

) : ( <>
{groupedHistory.map((item, index) => { // Check if this is a session group or single entry if ('entries' in item && item.entries.length > 1) { // This is a bulk session const session = item as SessionGroup; const isExpanded = expandedSession === session.sessionId; return (
{/* Session Header */}
{session.entries[0]?.activityType === 'trimming' ? (
) : (
)}

Массовая {getActivityLabel(session.entries[0]?.activityType)} сессия

{session.entries.length} зоны
{formatDate(session.mowedDate)} at {formatTime(session.mowedDate)}
{session.mowerName && (
{getMowerIcon(session.mowerType)} {session.mowerName}
)} {session.totalDuration > 0 && (
{formatDuration(session.totalDuration)} всего
)}
{session.totalArea.toLocaleString()} м2 всего
{session.weather && (
{session.weather}
)}
{/* Zone Summary */}

Зон {session.entries[0]?.activityType === 'trimming' ? 'подровнено' : 'скошено'}: {session.entries.map(e => e.zoneName).join(', ')}

{session.notes && (
{expandedEntry === -index && (

{session.notes}

)}
)}
{/* Expanded Session Details */} {isExpanded && (
Детализация по зонам
{session.entries.map(entry => (
{getActivityIcon(entry.activityType)}

{entry.zoneName}

{entry.zoneArea.toLocaleString()} м2

{entry.duration && (
{formatDuration(entry.duration)}
)}
))}
)}
); } else { // This is a single entry const entry = item as MowingHistory; return (
{getActivityIcon(entry.activityType)}

{entry.zoneName}

{entry.activityType === 'trimming' && ( Trimming )} {entry.zoneArea > 0 && `${entry.zoneArea.toLocaleString()} м2`}
{formatDate(entry.mowedDate)} at {formatTime(entry.mowedDate)}
{entry.mowerName && (
{getMowerIcon(entry.mowerType)} {entry.mowerName}
)} {entry.duration && (
{formatDuration(entry.duration)}
)} {entry.weather && (
{entry.weather}
)}
{entry.notes && (
{expandedEntry === entry.id && (

{entry.notes}

)}
)}
); } })}
{/* Pagination */} )}
); }; export default HistoryView;