import { ActiveProposalsSection, ImpactMetricsSection, MyOrganizationsSection, PlatformHealthSection, PlatformOverviewSection, QuickActionsSection, RecentActivitySection, YourContributionSection, } from '@/components/dashboard'; import { MainLayout } from '@/components/layout/MainLayout.tsx'; import PageHeader from '@/components/layout/PageHeader.tsx'; import DateRangePicker, { type DateRange } from '@/components/ui/DateRangePicker.tsx'; import { Container, Flex, Grid, Stack } from '@/components/ui/layout'; import { useAuth } from '@/contexts/AuthContext.tsx'; import { useDashboardStatistics, useImpactMetrics, useMatchingStatistics, usePlatformStatistics, } from '@/hooks/api/useAnalyticsAPI.ts'; import { useUserOrganizations } from '@/hooks/api/useOrganizationsAPI.ts'; import { useProposals } from '@/hooks/api/useProposalsAPI.ts'; import { useTranslation } from '@/hooks/useI18n.tsx'; import { useNavigation } from '@/hooks/useNavigation.tsx'; import { useOrganizations } from '@/hooks/useOrganizations.ts'; import type { Proposal } from '@/types.ts'; import { useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; type ActivityFilter = 'all' | 'match' | 'proposal' | 'organization'; const DashboardPage = () => { const { t } = useTranslation(); const navigate = useNavigate(); const { handleBackNavigation, handleFooterNavigate } = useNavigation(); const { user } = useAuth(); const [activityFilter, setActivityFilter] = useState('all'); const [dateRange, setDateRange] = useState({ startDate: null, endDate: null, preset: '30d', }); // Analytics data - Zod validates these, so if data exists, it's guaranteed to be valid const { data: dashboardStats, isLoading: isLoadingDashboard, error: dashboardError, } = useDashboardStatistics(); const { data: platformStats, isLoading: isLoadingPlatform, error: platformError, } = usePlatformStatistics(); const { data: matchingStats, isLoading: isLoadingMatching, error: matchingError, } = useMatchingStatistics(); const { data: impactMetrics, isLoading: isLoadingImpact, error: impactError, } = useImpactMetrics(); // User-specific data const { data: proposalsData } = useProposals(); const { organizations } = useOrganizations(); const { data: userOrganizations } = useUserOrganizations(); // Proposals data - validated by API const proposals: Proposal[] = proposalsData?.proposals ?? []; const pendingProposals = proposals.filter((p: Proposal) => p.status === 'pending'); // Calculate derived statistics - data is validated by Zod, so we can trust it const stats = useMemo(() => { // If data exists, it's validated by Zod - use it directly const dashboard = dashboardStats; const platform = platformStats; const matching = matchingStats; const impact = impactMetrics; // User-specific metrics const myOrganizationsCount = Array.isArray(userOrganizations) ? userOrganizations.length : 0; const myProposalsCount = proposals.length; const myPendingProposalsCount = pendingProposals.length; return { // Platform-wide metrics - prefer dashboard stats, fallback to platform stats totalOrganizations: dashboard?.total_organizations ?? platform?.total_organizations ?? 0, totalSites: dashboard?.total_sites ?? platform?.total_sites ?? 0, totalResourceFlows: dashboard?.total_resource_flows ?? platform?.total_resource_flows ?? 0, totalMatches: dashboard?.total_matches ?? platform?.total_matches ?? 0, activeProposals: pendingProposals.length, recentActivity: dashboard?.recent_activity ?? [], // User-specific metrics myOrganizations: myOrganizationsCount, myProposals: myProposalsCount, myPendingProposals: myPendingProposalsCount, // Matching statistics - optional fields use nullish coalescing matchSuccessRate: matching?.match_success_rate ?? 0, avgMatchTime: matching?.avg_match_time_days ?? 0, topResourceTypes: matching?.top_resource_types ?? [], // Impact metrics totalCo2Saved: impact?.total_co2_saved_tonnes ?? impact?.total_co2_savings_tonnes ?? 0, totalEconomicValue: impact?.total_economic_value ?? impact?.total_economic_value_eur ?? 0, activeMatches: impact?.active_matches_count ?? 0, }; }, [ dashboardStats, platformStats, matchingStats, impactMetrics, proposalsData, userOrganizations, pendingProposals, ]); // Filter activities based on selected filter // Activity type is validated by Zod, so it's guaranteed to be a string const filteredActivities = useMemo(() => { if (activityFilter === 'all') { return stats.recentActivity; } return stats.recentActivity.filter((activity) => { const activityType = activity.type.toLowerCase(); switch (activityFilter) { case 'match': return activityType.includes('match'); case 'proposal': return activityType.includes('proposal'); case 'organization': return activityType.includes('organization') || activityType.includes('org'); default: return true; } }); }, [stats.recentActivity, activityFilter]); // Number formatting handled by shared utilities inside components const isLoading = isLoadingDashboard || isLoadingPlatform || isLoadingMatching || isLoadingImpact; const hasError = dashboardError || platformError || matchingError || impactError; return ( navigate(path)} t={t} /> {/* Recent Activity & Proposals */} navigate(path)} t={t} /> navigate(path)} t={t} /> ); }; export default DashboardPage;