import { useState, useEffect, useRef } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { MetricsCard } from './MetricsCard'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Button } from '@/components/ui/button'; import { RefreshCw, Users, BarChart3, Eye, Heart } from 'lucide-react'; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import { format } from 'date-fns'; import { apiRequest } from '@/lib/queryClient'; import { useToast } from '@/hooks/use-toast'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; /** Maximum staleness before triggering an auto-refresh (12 hours in ms). */ const STALE_THRESHOLD_MS = 12 * 60 * 60 * 1000; export function AnalyticsDashboard() { const [selectedPageId, setSelectedPageId] = useState(null); const queryClient = useQueryClient(); const { toast } = useToast(); const autoRefreshDone = useRef(false); // Fetch Pages const { data: pages = [], isLoading: isLoadingPages } = useQuery({ queryKey: ['/api/pages'], }); // Set default selection useEffect(() => { if (pages.length > 0 && !selectedPageId) { setSelectedPageId(pages[0].id); } }, [pages, selectedPageId]); // Reset auto-refresh flag when switching pages useEffect(() => { autoRefreshDone.current = false; }, [selectedPageId]); // Fetch History for selected page (with polling every 30s) const { data: history = [], isLoading: isLoadingHistory } = useQuery({ queryKey: [`/api/analytics/pages/${selectedPageId}/history`], enabled: !!selectedPageId, }); // Refresh Mutation const refreshMutation = useMutation({ mutationFn: async () => { if (!selectedPageId) return; await apiRequest('POST', `/api/analytics/pages/${selectedPageId}/refresh`); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [`/api/analytics/pages/${selectedPageId}/history`] }); queryClient.invalidateQueries({ queryKey: ['/api/pages'] }); toast({ title: "Analyses actualisées", description: "Les dernières données ont été récupérées depuis Facebook.", }); }, onError: () => { toast({ title: "Échec de l'actualisation", description: "Impossible de récupérer les dernières données.", variant: "destructive" }); } }); // Auto-refresh on first load if data is stale or empty useEffect(() => { if (!selectedPageId || autoRefreshDone.current || refreshMutation.isPending) return; const isStale = history.length === 0 || (history[0]?.date && (Date.now() - new Date(history[0].date).getTime()) > STALE_THRESHOLD_MS); if (isStale) { autoRefreshDone.current = true; refreshMutation.mutate(); } }, [selectedPageId, history, refreshMutation]); const selectedPage = pages.find((p: any) => p.id === selectedPageId); // Prepare chart data (reverse to show chronological order) const chartData = [...history].reverse().map((entry: any) => ({ date: format(new Date(entry.date), 'dd/MM'), followers: entry.followersCount, reach: entry.pageReach, engagement: entry.pageEngagement || 0, views: entry.pageViews || 0, })); // Calculate trends (comparison between latest and previous entry) const latest = history[0]; const previous = history[1]; const getTrend = (current: number, prev: number): number => { if (!prev) return 0; return Math.round(((current - prev) / prev) * 100); }; if (isLoadingPages) return
Chargement des pages...
; if (!pages.length) return
Aucune page connectée. Veuillez connecter une page Facebook dans les Paramètres.
; return (
{selectedPage && ( Token : {selectedPage.tokenStatus || 'Inconnu'} )}
{selectedPageId && ( <>
} trend={latest && previous ? getTrend(latest.followersCount, previous.followersCount) : undefined} description="depuis la dernière mise à jour" /> } trend={latest && previous ? getTrend(latest.pageReach, previous.pageReach) : undefined} description="impressions uniques (jour)" /> } trend={latest && previous ? getTrend(latest.pageEngagement || 0, previous.pageEngagement || 0) : undefined} description="interactions totales (jour)" /> } trend={latest && previous ? getTrend(latest.pageViews || 0, previous.pageViews || 0) : undefined} description="vues totales (jour)" />
Historique de Croissance & Portée
)}
); }