turash/bugulma/frontend/hooks/pages/useAnalyticsDashboard.ts
2025-12-15 10:06:41 +01:00

139 lines
5.0 KiB
TypeScript

import {
useConnectionStatistics,
useImpactMetrics,
useMatchingStatistics,
usePlatformStatistics,
useResourceFlowStatistics,
useSupplyDemandAnalysis,
} from '@/hooks/api/useAnalyticsAPI.ts';
import type {
ConnectionStatistics,
ImpactMetrics,
MatchingStatistics,
PlatformStatistics,
ResourceFlowStatistics,
SupplyDemandAnalysis,
} from '@/services/analytics-api.ts';
import { useMemo } from 'react';
export type AnalyticsDashboardData = {
totalOrganizations: number;
totalSites: number;
totalResourceFlows: number;
totalMatches: number;
matchSuccessRate: number;
avgMatchTime: number;
totalMatchValue: number;
topResourceTypes: Array<{ type: string; count: number }>;
flowsByType: Record<string, number>;
flowsBySector: Record<string, number>;
avgFlowValue: number;
totalFlowVolume: number;
totalConnections: number;
activeConnections: number;
potentialConnections: number;
connectionRate: number;
totalCo2Saved: number;
totalEconomicValue: number;
activeMatchesCount: number;
environmentalBreakdown: Record<string, unknown>;
topNeeds: Array<{ item: string; count: number }>;
topOffers: Array<{ item: string; count: number }>;
};
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}
export function useAnalyticsDashboard() {
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;
const analytics: AnalyticsDashboardData = useMemo(() => {
const platform: Partial<PlatformStatistics> = platformStats ?? {};
const matching: Partial<MatchingStatistics> = matchingStats ?? {};
const resourceFlow: Partial<ResourceFlowStatistics> = resourceFlowStats ?? {};
const impact: Partial<ImpactMetrics> = impactMetrics ?? {};
const connections: Partial<ConnectionStatistics> = connectionStats ?? {};
const supplyDemandData: Partial<SupplyDemandAnalysis> = supplyDemand ?? {};
const totalConnections = Number(connections.total_connections || 0);
const activeConnections = Number(connections.active_connections || 0);
const potentialConnections = Number(connections.potential_connections || 0);
const connectionRate = totalConnections > 0 ? activeConnections / totalConnections : 0;
const topResourceTypesRaw = matching.top_resource_types ?? [];
const topResourceTypes = Array.isArray(topResourceTypesRaw)
? topResourceTypesRaw
.map((it: unknown) => {
if (typeof it === 'string') return { type: it, count: 1 };
if (isRecord(it)) {
const type = typeof it.type === 'string' ? it.type : '';
const count = typeof it.count === 'number' ? it.count : 1;
return { type, count };
}
return { type: '', count: 1 };
})
.filter((x) => x.type)
: [];
return {
totalOrganizations: Number(platform.total_organizations || 0),
totalSites: Number(platform.total_sites || 0),
totalResourceFlows: Number(platform.total_resource_flows || 0),
totalMatches: Number(platform.total_matches || 0),
matchSuccessRate: Number(matching.match_success_rate || 0),
avgMatchTime: Number(matching.avg_match_time_days || 0),
totalMatchValue: Number(matching.total_match_value || 0),
topResourceTypes,
flowsByType: (resourceFlow.flows_by_type || {}) as Record<string, number>,
flowsBySector: (resourceFlow.flows_by_sector || {}) as Record<string, number>,
avgFlowValue: Number(resourceFlow.avg_flow_value || 0),
totalFlowVolume: Number(resourceFlow.total_flow_volume || 0),
totalConnections,
activeConnections,
potentialConnections,
connectionRate,
totalCo2Saved: Number(impact.total_co2_savings_tonnes || 0),
totalEconomicValue: Number(impact.total_economic_value_eur || 0),
activeMatchesCount: Number(impact.active_matches_count || 0),
environmentalBreakdown: isRecord(impact.environmental_breakdown)
? impact.environmental_breakdown
: {},
topNeeds: (supplyDemandData.top_needs || []) as Array<{ item: string; count: number }>,
topOffers: (supplyDemandData.top_offers || []) as Array<{ item: string; count: number }>,
};
}, [
platformStats,
matchingStats,
resourceFlowStats,
impactMetrics,
connectionStats,
supplyDemand,
]);
return { isLoading, analytics };
}