import { useState, useEffect } from 'react'; import { DateRangeSelector, StatCard, TimeSeriesChart, LitterTypeChart, QuantityChart } from '@/components/analytics'; import { analyticsService } from '@/services'; import type { DateRange, AnalyticsSummary, TimeSeriesDataPoint, LitterTypeDistribution, QuantityAggregation } from '@/types'; /** * Analytics Dashboard Page * Displays summary statistics, date range filtering, and CSV export functionality */ export function AnalyticsPage() { const [dateRange, setDateRange] = useState(() => { const end = new Date(); const start = new Date(); start.setMonth(end.getMonth() - 1); // Default to last month return { start, end }; }); const [summary, setSummary] = useState(null); const [timeSeriesData, setTimeSeriesData] = useState([]); const [litterTypeData, setLitterTypeData] = useState([]); const [quantityData, setQuantityData] = useState([]); const [loading, setLoading] = useState(true); const [chartsLoading, setChartsLoading] = useState(true); const [error, setError] = useState(null); const [exporting, setExporting] = useState(false); useEffect(() => { loadSummary(); loadChartData(); }, [dateRange]); const loadSummary = async () => { try { setLoading(true); setError(null); const data = await analyticsService.getSummary({ start: dateRange.start.toISOString(), end: dateRange.end.toISOString(), }); setSummary(data); } catch (err) { // If API is not available yet, show mock data for development console.warn('Analytics API not available, using mock data:', err); setSummary({ totalReports: 0, totalEvents: 0, totalUsers: 0, totalLitterCollected: 0, }); setError('Analytics API not yet implemented. Showing placeholder data.'); } finally { setLoading(false); } }; const loadChartData = async () => { try { setChartsLoading(true); const dateRangeParam = { start: dateRange.start.toISOString(), end: dateRange.end.toISOString(), }; // Load all chart data in parallel const [timeSeries, litterTypes, quantities] = await Promise.all([ analyticsService.getTimeSeries(dateRangeParam), analyticsService.getLitterTypeDistribution(dateRangeParam), analyticsService.getQuantityAggregation(dateRangeParam), ]); setTimeSeriesData(timeSeries); setLitterTypeData(litterTypes); setQuantityData(quantities); } catch (err) { // If API is not available yet, show mock data for development console.warn('Chart data API not available, using mock data:', err); // Generate mock time series data const mockTimeSeries: TimeSeriesDataPoint[] = []; const daysDiff = Math.ceil((dateRange.end.getTime() - dateRange.start.getTime()) / (1000 * 60 * 60 * 24)); const dataPoints = Math.min(daysDiff, 30); // Max 30 data points for (let i = 0; i < dataPoints; i++) { const date = new Date(dateRange.start); date.setDate(date.getDate() + Math.floor(i * daysDiff / dataPoints)); mockTimeSeries.push({ date: date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }), reports: Math.floor(Math.random() * 20) + 5, events: Math.floor(Math.random() * 5), }); } setTimeSeriesData(mockTimeSeries); // Generate mock litter type distribution const mockLitterTypes: LitterTypeDistribution[] = [ { type: 'plastic', count: 45, percentage: 45 }, { type: 'metal', count: 15, percentage: 15 }, { type: 'glass', count: 12, percentage: 12 }, { type: 'organic', count: 10, percentage: 10 }, { type: 'hazardous', count: 8, percentage: 8 }, { type: 'other', count: 10, percentage: 10 }, ]; setLitterTypeData(mockLitterTypes); // Generate mock quantity aggregation const mockQuantities: QuantityAggregation[] = [ { quantity: 'minimal', count: 30, percentage: 30 }, { quantity: 'moderate', count: 40, percentage: 40 }, { quantity: 'significant', count: 20, percentage: 20 }, { quantity: 'severe', count: 10, percentage: 10 }, ]; setQuantityData(mockQuantities); } finally { setChartsLoading(false); } }; const handleExportCSV = async () => { try { setExporting(true); const blob = await analyticsService.exportToCSV({ start: dateRange.start.toISOString(), end: dateRange.end.toISOString(), }); // Create download link const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `beach-litter-analytics-${dateRange.start.toISOString().split('T')[0]}-to-${dateRange.end.toISOString().split('T')[0]}.csv`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } catch (err) { console.error('Failed to export CSV:', err); alert('Export feature not yet available. The analytics API endpoints will be implemented in task 27.'); } finally { setExporting(false); } }; return (
{/* Header */}

Analytics Dashboard

{/* Date Range Selector */}
{/* Info/Warning State */} {error && (

{error}

)} {/* Loading State */} {loading && (
{[1, 2, 3, 4].map((i) => (
))}
)} {/* Summary Statistics */} {!loading && summary && (
} trend={ summary.periodComparison ? { value: summary.periodComparison.reports, isPositive: summary.periodComparison.reports > 0, } : undefined } subtitle="Litter reports submitted" /> } trend={ summary.periodComparison ? { value: summary.periodComparison.events, isPositive: summary.periodComparison.events > 0, } : undefined } subtitle="Cleanup events organized" /> } trend={ summary.periodComparison ? { value: summary.periodComparison.users, isPositive: summary.periodComparison.users > 0, } : undefined } subtitle="Contributing to the platform" /> } subtitle="From cleanup events" />
)} {/* Data Visualizations */}
{/* Time Series Chart */} {/* Litter Type and Quantity Charts - Side by Side on Desktop */}
); }