From 48138c216684fc1d71d00d6e941192575b5a0889 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Wed, 8 Oct 2025 15:35:49 +0000 Subject: [PATCH] Update dashboard to show accurate statistics and improve sidebar functionality Refactor the API endpoint for statistics to accurately calculate and display scheduled posts, AI text generations, and media stored, including percentage changes and trending indicators. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/ycYcQjF --- client/src/components/stats-cards.tsx | 29 ++++++++++++------ server/routes.ts | 42 ++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/client/src/components/stats-cards.tsx b/client/src/components/stats-cards.tsx index 0051ce6..ad7fbee 100644 --- a/client/src/components/stats-cards.tsx +++ b/client/src/components/stats-cards.tsx @@ -1,8 +1,19 @@ import { CalendarCheck, Users, Bot, Images, TrendingUp, TrendingDown } from "lucide-react"; import { useQuery } from "@tanstack/react-query"; +interface StatsResponse { + scheduledPosts: number; + scheduledPostsChange?: string; + scheduledPostsTrending?: "up" | "down"; + connectedPages: number; + aiTextsGenerated: number; + aiTextsChange?: string; + aiTextsTrending?: "up" | "down"; + mediaStored: number; +} + export default function StatsCards() { - const { data: stats, isLoading } = useQuery({ + const { data: stats, isLoading } = useQuery({ queryKey: ["/api/stats"], }); @@ -10,32 +21,32 @@ export default function StatsCards() { { icon: CalendarCheck, iconColor: "from-blue-500 to-blue-600", - title: (stats as any)?.scheduledPosts ?? 0, + title: stats?.scheduledPosts ?? 0, subtitle: "Publications planifiées", - change: "+12%", - trending: "up", + change: stats?.scheduledPostsChange, + trending: stats?.scheduledPostsTrending, changeLabel: "vs mois dernier", }, { icon: Users, iconColor: "from-purple-500 to-purple-600", - title: (stats as any)?.connectedPages ?? 0, + title: stats?.connectedPages ?? 0, subtitle: "Pages connectées", info: "Facebook • Instagram", }, { icon: Bot, iconColor: "from-green-500 to-green-600", - title: (stats as any)?.aiTextsGenerated ?? 0, + title: stats?.aiTextsGenerated ?? 0, subtitle: "Textes générés par IA", - change: "+8%", - trending: "up", + change: stats?.aiTextsChange, + trending: stats?.aiTextsTrending, changeLabel: "vs hier", }, { icon: Images, iconColor: "from-cyan-500 to-cyan-600", - title: (stats as any)?.mediaStored ?? 0, + title: stats?.mediaStored ?? 0, subtitle: "Médias stockés", info: "Images • Vidéos", }, diff --git a/server/routes.ts b/server/routes.ts index 1e18e45..f92ba5a 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -369,12 +369,52 @@ export async function registerRoutes(app: Express): Promise { const media = await storage.getMedia(userId); const aiGenerations = await storage.getAiGenerations(userId); + // Statistiques actuelles const scheduledPosts = posts.filter(p => p.status === "scheduled").length; + const currentAiTexts = aiGenerations.length; + const currentMedia = media.length; + + // Calculer les statistiques de la période précédente (hier pour les textes IA, mois dernier pour les posts) + const now = new Date(); + const yesterday = new Date(now); + yesterday.setDate(yesterday.getDate() - 1); + yesterday.setHours(0, 0, 0, 0); + + const lastMonth = new Date(now); + lastMonth.setMonth(lastMonth.getMonth() - 1); + + // Textes IA générés hier + const aiTextsYesterday = aiGenerations.filter(gen => { + if (!gen.createdAt) return false; + const genDate = new Date(gen.createdAt); + genDate.setHours(0, 0, 0, 0); + return genDate.getTime() === yesterday.getTime(); + }).length; + + // Posts planifiés le mois dernier + const scheduledPostsLastMonth = posts.filter(p => { + if (!p.createdAt) return false; + const createdDate = new Date(p.createdAt); + return p.status === "scheduled" && createdDate < lastMonth; + }).length; + + // Calculer les variations en pourcentage + const aiTextChange = aiTextsYesterday > 0 + ? Math.round(((currentAiTexts - aiTextsYesterday) / aiTextsYesterday) * 100) + : currentAiTexts > 0 ? 100 : 0; + + const scheduledPostsChange = scheduledPostsLastMonth > 0 + ? Math.round(((scheduledPosts - scheduledPostsLastMonth) / scheduledPostsLastMonth) * 100) + : scheduledPosts > 0 ? 100 : 0; res.json({ scheduledPosts, + scheduledPostsChange: scheduledPostsChange > 0 ? `+${scheduledPostsChange}%` : `${scheduledPostsChange}%`, + scheduledPostsTrending: scheduledPostsChange >= 0 ? "up" : "down", connectedPages: pages.length, - aiTextsGenerated: aiGenerations.length, + aiTextsGenerated: currentAiTexts, + aiTextsChange: aiTextChange > 0 ? `+${aiTextChange}%` : `${aiTextChange}%`, + aiTextsTrending: aiTextChange >= 0 ? "up" : "down", mediaStored: media.length, }); } catch (error) {