Prechádzať zdrojové kódy

Add feed following and date filtering

Added functionality to display articles from followed feeds and updated date filters (today, yesterday) to work without requiring a subscription.
gpt-engineer-app[bot] 5 mesiacov pred
rodič
commit
c18a1e62eb

+ 37 - 2
src/components/CategoryFilter.tsx

@@ -11,7 +11,8 @@ import {
   Filter,
   Pin,
   Calendar,
-  Clock
+  Clock,
+  Heart
 } from 'lucide-react';
 import { useAuth } from '@/hooks/useAuth';
 
@@ -24,6 +25,8 @@ interface CategoryFilterProps {
   articles: any[]; // Add articles to calculate counts per category
   dateFilter?: 'today' | 'yesterday' | null;
   onDateFilterChange?: (filter: 'today' | 'yesterday' | null) => void;
+  showFollowedOnly?: boolean;
+  onShowFollowedOnlyChange?: (showFollowedOnly: boolean) => void;
 }
 
 const iconMap = {
@@ -41,7 +44,9 @@ const CategoryFilter = ({
   pinnedCount = 0,
   articles,
   dateFilter,
-  onDateFilterChange
+  onDateFilterChange,
+  showFollowedOnly,
+  onShowFollowedOnlyChange
 }: CategoryFilterProps) => {
   const { user } = useAuth();
 
@@ -90,6 +95,36 @@ const CategoryFilter = ({
           );
         })}
       </div>
+      
+      {user && onShowFollowedOnlyChange && (
+        <div className="pt-4 border-t space-y-2">
+          <div className="flex items-center gap-2">
+            <Heart className="h-4 w-4 text-muted-foreground" />
+            <span className="text-sm font-medium">Affichage</span>
+          </div>
+          
+          <div className="space-y-1">
+            <Button
+              variant={!showFollowedOnly ? "default" : "outline"}
+              size="sm"
+              className="w-full justify-start gap-2"
+              onClick={() => onShowFollowedOnlyChange(false)}
+            >
+              <span>Tous les flux</span>
+            </Button>
+            
+            <Button
+              variant={showFollowedOnly ? "default" : "outline"}
+              size="sm"
+              className="w-full justify-start gap-2"
+              onClick={() => onShowFollowedOnlyChange(true)}
+            >
+              <Heart className="h-3 w-3" />
+              <span>Flux suivis uniquement</span>
+            </Button>
+          </div>
+        </div>
+      )}
 
       {onDateFilterChange && (
         <div className="pt-4 border-t space-y-2">

+ 76 - 7
src/hooks/useRealArticles.tsx

@@ -5,7 +5,7 @@ import { useAuth } from './useAuth';
 import { NewsItem } from '@/types/news';
 import { toast } from 'sonner';
 
-export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null) {
+export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null, showFollowedOnly?: boolean) {
   const [articles, setArticles] = useState<NewsItem[]>([]);
   const [loading, setLoading] = useState(true);
   const { user } = useAuth();
@@ -13,7 +13,7 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null) {
   const fetchArticles = async () => {
     try {
       setLoading(true);
-      console.log('🔄 Fetching articles...', { user: !!user, dateFilter });
+      console.log('🔄 Fetching articles...', { user: !!user, dateFilter, showFollowedOnly });
       
       // Calculate date ranges for filtering
       let dateStart = null;
@@ -34,7 +34,76 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null) {
         dateEnd = yesterday.toISOString();
       }
       
-      if (user) {
+      if (user && showFollowedOnly) {
+        // For authenticated users wanting only followed feeds
+        const { data: userFeeds, error: userFeedsError } = await supabase
+          .from('user_feeds')
+          .select('feed_id')
+          .eq('user_id', user.id)
+          .eq('is_followed', true);
+
+        if (userFeedsError) {
+          console.error('❌ Error fetching user feeds:', userFeedsError);
+          toast.error('Erreur lors du chargement de vos flux');
+          return;
+        }
+
+        console.log('📋 User followed feeds:', userFeeds);
+        const followedFeedIds = userFeeds?.map(uf => uf.feed_id) || [];
+        
+        if (followedFeedIds.length === 0) {
+          console.log('⚠️ No followed feeds found for user');
+          setArticles([]);
+          return;
+        }
+
+        // Fetch articles from followed feeds with user interactions, excluding read articles
+        let query = supabase
+          .from('articles')
+          .select(`
+            *,
+            feeds!inner(name, category),
+            user_articles(is_read, is_pinned)
+          `)
+          .in('feed_id', followedFeedIds);
+        
+        // Apply date filter if specified
+        if (dateStart && dateEnd) {
+          query = query.gte('published_at', dateStart).lte('published_at', dateEnd);
+        }
+        
+        const { data: articlesData, error: articlesError } = await query
+          .order('published_at', { ascending: false })
+          .limit(100);
+
+        if (articlesError) {
+          console.error('❌ Error fetching articles:', articlesError);
+          toast.error('Erreur lors du chargement des articles');
+          return;
+        }
+
+        console.log('📰 Articles found for followed feeds:', articlesData?.length);
+
+        // Transform to NewsItem format and filter out read articles
+        const transformedArticles: NewsItem[] = articlesData
+          ?.filter(article => !article.user_articles[0]?.is_read) // Filter out read articles
+          ?.map(article => ({
+            id: article.id,
+            title: article.title,
+            description: article.description || '',
+            content: article.content || '',
+            source: article.feeds.name,
+            category: article.feeds.category as NewsItem['category'],
+            publishedAt: article.published_at,
+            readTime: article.read_time || 5,
+            isPinned: article.user_articles[0]?.is_pinned || false,
+            isRead: article.user_articles[0]?.is_read || false,
+            url: article.url || undefined,
+            imageUrl: article.image_url || undefined
+          })) || [];
+
+        setArticles(transformedArticles);
+      } else if (user) {
         // For authenticated users, fetch articles from their followed feeds
         const { data: userFeeds, error: userFeedsError } = await supabase
           .from('user_feeds')
@@ -148,8 +217,8 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null) {
 
         setArticles(transformedArticles);
       } else {
-        // For visitors, show recent articles from all feeds
-        console.log('👤 Loading articles for visitor');
+        // For visitors or users wanting all articles, show recent articles from all feeds
+        console.log('👤 Loading articles for visitor or all articles');
         let query = supabase
           .from('articles')
           .select(`
@@ -164,7 +233,7 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null) {
         
         const { data: articlesData, error: articlesError } = await query
           .order('published_at', { ascending: false })
-          .limit(20);
+          .limit(50);
 
         if (articlesError) {
           console.error('❌ Error fetching public articles:', articlesError);
@@ -323,7 +392,7 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null) {
 
   useEffect(() => {
     fetchArticles();
-  }, [user, dateFilter]);
+  }, [user, dateFilter, showFollowedOnly]);
 
   return {
     articles,

+ 6 - 1
src/pages/Index.tsx

@@ -21,6 +21,7 @@ const Index = () => {
     user
   } = useAuth();
   const [dateFilter, setDateFilter] = useState<'today' | 'yesterday' | null>(null);
+  const [showFollowedOnly, setShowFollowedOnly] = useState(false);
   const {
     articles,
     loading,
@@ -28,7 +29,7 @@ const Index = () => {
     markAsRead,
     deleteArticle,
     refetch
-  } = useRealArticles(dateFilter);
+  } = useRealArticles(dateFilter, showFollowedOnly);
   const isMobile = useIsMobile();
   const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
   const [searchQuery, setSearchQuery] = useState('');
@@ -131,6 +132,8 @@ const Index = () => {
                 articles={articles}
                 dateFilter={dateFilter}
                 onDateFilterChange={setDateFilter}
+                showFollowedOnly={showFollowedOnly}
+                onShowFollowedOnlyChange={setShowFollowedOnly}
               />
               
               <div className="bg-card border rounded-lg p-4 space-y-3">
@@ -180,6 +183,8 @@ const Index = () => {
                           articles={articles}
                           dateFilter={dateFilter}
                           onDateFilterChange={setDateFilter}
+                          showFollowedOnly={showFollowedOnly}
+                          onShowFollowedOnlyChange={setShowFollowedOnly}
                         />
                         
                         <div className="bg-card border rounded-lg p-4 space-y-3">