gpt-engineer-app[bot] 2 hafta önce
ebeveyn
işleme
ce2a770652

+ 11 - 2
src/hooks/useFeeds.tsx

@@ -26,6 +26,14 @@ export function useFeeds() {
         return;
       }
 
+      // Fetch subscriber counts (accessible to everyone via SECURITY DEFINER function)
+      const { data: subscriberCounts, error: subscriberError } = await supabase
+        .rpc('get_feed_subscriber_counts');
+
+      if (subscriberError) {
+        console.error('Error fetching subscriber counts:', subscriberError);
+      }
+
       // If user is authenticated, fetch their subscriptions
       let userFeedsData = null;
       if (user) {
@@ -41,7 +49,7 @@ export function useFeeds() {
         }
       }
 
-      // Combine feeds with user subscription status
+      // Combine feeds with user subscription status and subscriber counts
       const combinedFeeds = feedsData.map(feed => ({
         id: feed.id,
         name: feed.name,
@@ -52,7 +60,8 @@ export function useFeeds() {
         isFollowed: userFeedsData?.find(uf => uf.feed_id === feed.id)?.is_followed || false,
         lastUpdated: feed.last_updated || feed.created_at,
         articleCount: feed.article_count || 0,
-        status: feed.status as Feed['status']
+        status: feed.status as Feed['status'],
+        subscriberCount: Number(subscriberCounts?.find(sc => sc.feed_id === feed.id)?.subscriber_count) || 0
       }));
 
       setFeeds(combinedFeeds);

+ 7 - 0
src/integrations/supabase/types.ts

@@ -235,6 +235,13 @@ export type Database = {
       [_ in never]: never
     }
     Functions: {
+      get_feed_subscriber_counts: {
+        Args: never
+        Returns: {
+          feed_id: string
+          subscriber_count: number
+        }[]
+      }
       is_super_user: { Args: { user_email?: string }; Returns: boolean }
       purge_old_articles: {
         Args: never

+ 40 - 15
src/pages/FeedsManagement.tsx

@@ -32,7 +32,8 @@ import {
   User,
   RefreshCw,
   Edit,
-  Timer
+  Timer,
+  Users
 } from 'lucide-react';
 import { Link } from 'react-router-dom';
 import AddFeedModal from '@/components/AddFeedModal';
@@ -287,6 +288,7 @@ const FeedsManagement = () => {
   const followedCount = feeds.filter(f => f.isFollowed).length;
   const activeCount = feeds.filter(f => f.status === 'active').length;
   const errorCount = feeds.filter(f => f.status === 'error').length;
+  const totalSubscribers = feeds.reduce((sum, f) => sum + (f.subscriberCount || 0), 0);
 
   const feedTypes = [
     { value: 'website', label: 'Sites web', icon: Globe },
@@ -353,7 +355,7 @@ const FeedsManagement = () => {
         <div className="space-y-6">
 
           {/* Statistiques */}
-          <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
+          <div className="grid grid-cols-2 md:grid-cols-5 gap-4">
             <Card>
               <CardHeader className="pb-2">
                 <CardTitle className="text-sm font-medium">Total flux</CardTitle>
@@ -362,6 +364,17 @@ const FeedsManagement = () => {
                 <div className="text-2xl font-bold">{feeds.length}</div>
               </CardContent>
             </Card>
+            <Card>
+              <CardHeader className="pb-2">
+                <CardTitle className="text-sm font-medium flex items-center gap-1">
+                  <Users className="h-4 w-4" />
+                  Abonnements
+                </CardTitle>
+              </CardHeader>
+              <CardContent>
+                <div className="text-2xl font-bold text-purple-600">{totalSubscribers}</div>
+              </CardContent>
+            </Card>
             {user && (
               <Card>
                 <CardHeader className="pb-2">
@@ -509,6 +522,12 @@ const FeedsManagement = () => {
                       <TableHead>Type</TableHead>
                       <TableHead>Statut</TableHead>
                       <TableHead>Articles</TableHead>
+                      <TableHead className="text-center">
+                        <div className="flex items-center justify-center gap-1">
+                          <Users className="h-4 w-4" />
+                          Abonnés
+                        </div>
+                      </TableHead>
                       <TableHead>Dernière MAJ</TableHead>
                       {user && <TableHead>Suivi</TableHead>}
                       <TableHead>Actions</TableHead>
@@ -557,19 +576,25 @@ const FeedsManagement = () => {
                              </div>
                            </TableCell>
                            <TableCell>
-                             <Badge variant="secondary">{feed.articleCount}</Badge>
-                           </TableCell>
-                           <TableCell>
-                             <div className="text-sm">
-                               {new Date(feed.lastUpdated).toLocaleDateString('fr-FR', {
-                                 day: '2-digit',
-                                 month: '2-digit',
-                                 year: 'numeric',
-                                 hour: '2-digit',
-                                 minute: '2-digit'
-                               })}
-                             </div>
-                           </TableCell>
+                              <Badge variant="secondary">{feed.articleCount}</Badge>
+                            </TableCell>
+                            <TableCell className="text-center">
+                              <Badge variant="outline" className="bg-purple-50 text-purple-700 border-purple-200">
+                                <Users className="h-3 w-3 mr-1" />
+                                {feed.subscriberCount || 0}
+                              </Badge>
+                            </TableCell>
+                            <TableCell>
+                              <div className="text-sm">
+                                {new Date(feed.lastUpdated).toLocaleDateString('fr-FR', {
+                                  day: '2-digit',
+                                  month: '2-digit',
+                                  year: 'numeric',
+                                  hour: '2-digit',
+                                  minute: '2-digit'
+                                })}
+                              </div>
+                            </TableCell>
                            {user && (
                              <TableCell>
                                <Switch

+ 1 - 0
src/types/feed.ts

@@ -10,4 +10,5 @@ export interface Feed {
   lastUpdated: string;
   articleCount: number;
   status: 'active' | 'error' | 'pending';
+  subscriberCount?: number;
 }

+ 13 - 0
supabase/migrations/20260119114940_30db7093-a9b3-48a9-80f6-cac17e3b1083.sql

@@ -0,0 +1,13 @@
+-- Fonction pour récupérer le nombre d'abonnés par flux
+-- Utilise SECURITY DEFINER pour permettre l'accès public aux compteurs agrégés
+CREATE OR REPLACE FUNCTION public.get_feed_subscriber_counts()
+RETURNS TABLE(feed_id uuid, subscriber_count bigint)
+LANGUAGE sql
+STABLE SECURITY DEFINER
+SET search_path TO 'public'
+AS $$
+  SELECT feed_id, COUNT(*) as subscriber_count
+  FROM public.user_feeds
+  WHERE is_followed = true
+  GROUP BY feed_id;
+$$;