import { useMemo } from 'react'; import { ArrowUp, BarChart3, Clock, Target, TrendingUp, Users, Building2 } from 'lucide-react'; import { MainLayout } from '@/components/layout/MainLayout.tsx'; import PageHeader from '@/components/layout/PageHeader.tsx'; import Badge from '@/components/ui/Badge.tsx'; import Button from '@/components/ui/Button.tsx'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card.tsx'; import MetricItem from '@/components/ui/MetricItem.tsx'; import Spinner from '@/components/ui/Spinner.tsx'; import { Container, Flex, Grid, Stack } from '@/components/ui/layout'; import { useConnectionStatistics, useImpactMetrics, useMatchingStatistics, usePlatformStatistics, useResourceFlowStatistics, useSupplyDemandAnalysis, } from '@/hooks/api/useAnalyticsAPI.ts'; import { useTranslation } from '@/hooks/useI18n.tsx'; import { useNavigation } from '@/hooks/useNavigation.tsx'; const AnalyticsDashboard = () => { const { t } = useTranslation(); const { handleBackNavigation, handleFooterNavigate } = useNavigation(); // Analytics data const { data: platformStats, isLoading: isLoadingPlatform } = usePlatformStatistics(); const { data: matchingStats, isLoading: isLoadingMatching } = useMatchingStatistics(); const { data: resourceFlowStats, isLoading: isLoadingResourceFlow } = useResourceFlowStatistics(); const { data: impactMetrics, isLoading: isLoadingImpact } = useImpactMetrics(); const { data: connectionStats, isLoading: isLoadingConnections } = useConnectionStatistics(); const { data: supplyDemand, isLoading: isLoadingSupplyDemand } = useSupplyDemandAnalysis(); const isLoading = isLoadingPlatform || isLoadingMatching || isLoadingResourceFlow || isLoadingImpact || isLoadingConnections || isLoadingSupplyDemand; // Calculate derived metrics const analytics = useMemo(() => { const platform = platformStats || {}; const matching = matchingStats || {}; const resourceFlow = resourceFlowStats || {}; const impact = impactMetrics || {}; const connections = connectionStats || {}; const supplyDemandData = supplyDemand || {}; return { // Platform overview totalOrganizations: platform.total_organizations || 0, totalSites: platform.total_sites || 0, totalResourceFlows: platform.total_resource_flows || 0, totalMatches: platform.total_matches || 0, // Matching performance matchSuccessRate: matching.match_success_rate || 0, avgMatchTime: matching.avg_match_time_days || 0, totalMatchValue: matching.total_match_value || 0, topResourceTypes: matching.top_resource_types || [], matchTrends: matching.match_trends || [], // Resource flow analytics flowsByType: resourceFlow.flows_by_type || {}, flowsBySector: resourceFlow.flows_by_sector || {}, avgFlowValue: resourceFlow.avg_flow_value || 0, totalFlowVolume: resourceFlow.total_flow_volume || 0, // Impact metrics totalCo2Saved: impact.total_co2_saved_tonnes || 0, totalEconomicValue: impact.total_economic_value || 0, activeMatchesCount: impact.active_matches_count || 0, environmentalBreakdown: impact.environmental_breakdown || {}, // Connection analytics totalConnections: connections.total_connections || 0, activeConnections: connections.active_connections || 0, potentialConnections: connections.potential_connections || 0, connectionRate: connections.connection_rate || 0, // Supply/demand topNeeds: supplyDemandData.top_needs || [], topOffers: supplyDemandData.top_offers || [], marketGaps: supplyDemandData.market_gaps || [], }; }, [platformStats, matchingStats, resourceFlowStats, impactMetrics, connectionStats, supplyDemand]); const formatCurrency = (value: number) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'EUR', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(value); }; const formatNumber = (value: number) => { return new Intl.NumberFormat('en-US').format(value); }; const formatPercentage = (value: number) => { return `${(value * 100).toFixed(1)}%`; }; // Simple bar chart component using CSS const SimpleBarChart = ({ data, title }: { data: Array<{ label: string; value: number; color?: string }>; title: string }) => { const maxValue = Math.max(...data.map(d => d.value)); return (
{t('analyticsDashboard.successRate', 'Success Rate')}
{t('analyticsDashboard.avgDays', 'Avg Days')}
{t('analyticsDashboard.total', 'Total')}
{t('analyticsDashboard.active', 'Active')}
{t('analyticsDashboard.potential', 'Potential')}
{t('analyticsDashboard.tonnesCo2Saved', 'Tonnes CO₂ Saved')}
{t('analyticsDashboard.economicValueCreated', 'Economic Value Created')}
{t('analyticsDashboard.activeMatches', 'Active Matches')}
{t('analyticsDashboard.impactCategories', 'Impact Categories')}
{need.item}
{need.sector}
{t('analyticsDashboard.noNeedsData', 'No needs data available')}
{offer.item}
{offer.sector}
{t('analyticsDashboard.noOffersData', 'No offers data available')}
{gap.description}