Selaa lähdekoodia

Fix article visibility logic

Refactored article filtering to unify behavior between "all articles" and "followed feeds" views. Added an option to toggle the visibility of read articles and adjusted the automatic read marking logic to prevent accidental marking. Improved visual indicators for read/unread articles.
gpt-engineer-app[bot] 3 kuukautta sitten
vanhempi
sitoutus
0a7734f89e

+ 28 - 2
src/components/CategoryFilter.tsx

@@ -12,7 +12,8 @@ import {
   Pin,
   Calendar,
   Clock,
-  Heart
+  Heart,
+  Eye
 } from 'lucide-react';
 import { useAuth } from '@/hooks/useAuth';
 
@@ -27,6 +28,8 @@ interface CategoryFilterProps {
   onDateFilterChange?: (filter: 'today' | 'yesterday' | null) => void;
   showFollowedOnly?: boolean;
   onShowFollowedOnlyChange?: (showFollowedOnly: boolean) => void;
+  showReadArticles?: boolean;
+  onShowReadArticlesChange?: (showReadArticles: boolean) => void;
 }
 
 const iconMap = {
@@ -46,7 +49,9 @@ const CategoryFilter = ({
   dateFilter,
   onDateFilterChange,
   showFollowedOnly,
-  onShowFollowedOnlyChange
+  onShowFollowedOnlyChange,
+  showReadArticles,
+  onShowReadArticlesChange
 }: CategoryFilterProps) => {
   const { user } = useAuth();
 
@@ -129,6 +134,27 @@ const CategoryFilter = ({
               </div>
             )}
 
+            {/* Section 1b: Articles lus */}
+            {user && onShowReadArticlesChange && (
+              <div className="flex flex-col gap-2 min-w-fit">
+                <div className="flex items-center gap-2 mb-1">
+                  <Eye className="h-4 w-4 text-muted-foreground" />
+                  <span className="text-sm font-medium text-muted-foreground">Articles lus</span>
+                </div>
+                <div className="flex flex-wrap gap-2">
+                  <Button
+                    variant={showReadArticles ? "default" : "outline"}
+                    size="sm"
+                    className="justify-start gap-2 whitespace-nowrap"
+                    onClick={() => onShowReadArticlesChange(!showReadArticles)}
+                  >
+                    <Eye className="h-3 w-3" />
+                    {showReadArticles ? 'Masquer les lus' : 'Afficher les lus'}
+                  </Button>
+                </div>
+              </div>
+            )}
+
             {/* Section 2: Filtres de date */}
             {onDateFilterChange && (
               <div className="flex flex-col gap-2 min-w-fit">

+ 1 - 3
src/components/NewsCard.tsx

@@ -59,9 +59,7 @@ const NewsCard = ({
 
   const handleCardClick = () => {
     onOpenArticle(news);
-    if (!news.isRead) {
-      onMarkAsRead(news.id);
-    }
+    // Don't automatically mark as read on card click - user can use the "Mark as read" button
   };
 
   return (

+ 10 - 8
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, showFollowedOnly?: boolean) {
+export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null, showFollowedOnly?: boolean, showReadArticles?: boolean) {
   const [articles, setArticles] = useState<NewsItem[]>([]);
   const [loading, setLoading] = useState(true);
   const { user } = useAuth();
@@ -115,9 +115,9 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null, showF
           unique: uniqueArticles.length
         });
 
-        // Transform to NewsItem format and filter out read articles
+        // Transform to NewsItem format and conditionally filter read articles
         const transformedArticles: NewsItem[] = uniqueArticles
-          ?.filter(article => !article.user_articles[0]?.is_read) // Filter out read articles
+          ?.filter(article => showReadArticles || !article.user_articles[0]?.is_read)
           ?.map(article => ({
             id: article.id,
             title: article.title,
@@ -202,9 +202,9 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null, showF
           unique: uniqueArticles.length
         });
 
-        // Transform to NewsItem format
+        // Transform to NewsItem format and conditionally filter read articles
         const transformedArticles: NewsItem[] = uniqueArticles
-          ?.filter(article => article.feeds) // Only keep articles with valid feeds
+          ?.filter(article => article.feeds && (showReadArticles || !article.user_articles[0]?.is_read))
           ?.map(article => ({
             id: article.id,
             title: article.title,
@@ -291,11 +291,13 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null, showF
         return;
       }
 
-      // Update local state based on mode: remove in followed-only, keep in "all"
-      if (showFollowedOnly) {
+      // Update local state: remove if not showing read articles, otherwise mark as read
+      if (!showReadArticles) {
         setArticles(prev => prev.filter(item => item.id !== articleId));
+        toast.success("Article marqué comme lu");
       } else {
         setArticles(prev => prev.map(item => item.id === articleId ? { ...item, isRead: true } : item));
+        toast.success("Article marqué comme lu");
       }
     } catch (error) {
       console.error('Error marking as read:', error);
@@ -355,7 +357,7 @@ export function useRealArticles(dateFilter?: 'today' | 'yesterday' | null, showF
 
   useEffect(() => {
     fetchArticles();
-  }, [user, dateFilter, showFollowedOnly]);
+  }, [user, dateFilter, showFollowedOnly, showReadArticles]);
 
   return {
     articles,

+ 24 - 11
src/pages/Index.tsx

@@ -22,6 +22,7 @@ const Index = () => {
   } = useAuth();
   const [dateFilter, setDateFilter] = useState<'today' | 'yesterday' | null>(null);
   const [showFollowedOnly, setShowFollowedOnly] = useState(false);
+  const [showReadArticles, setShowReadArticles] = useState(false);
   const {
     articles,
     loading,
@@ -29,7 +30,7 @@ const Index = () => {
     markAsRead,
     deleteArticle,
     refetch
-  } = useRealArticles(dateFilter, showFollowedOnly);
+  } = useRealArticles(dateFilter, showFollowedOnly, showReadArticles);
   const isMobile = useIsMobile();
   const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
   const [searchQuery, setSearchQuery] = useState('');
@@ -56,7 +57,7 @@ const Index = () => {
     });
   }, [articles, selectedCategory, searchQuery]);
   const pinnedCount = articles.filter(item => item.isPinned).length;
-  const unreadCount = articles.length; // All displayed articles are unread now
+  const unreadCount = articles.filter(item => !item.isRead).length;
 
   // Update document title with unread count
   useEffect(() => {
@@ -130,19 +131,25 @@ const Index = () => {
                 newsCount={articles.length} 
                 pinnedCount={pinnedCount} 
                 articles={articles}
-                dateFilter={dateFilter}
-                onDateFilterChange={setDateFilter}
-                showFollowedOnly={showFollowedOnly}
-                onShowFollowedOnlyChange={setShowFollowedOnly}
+                          dateFilter={dateFilter}
+                          onDateFilterChange={setDateFilter}
+                          showFollowedOnly={showFollowedOnly}
+                          onShowFollowedOnlyChange={setShowFollowedOnly}
+                          showReadArticles={showReadArticles}
+                          onShowReadArticlesChange={setShowReadArticles}
               />
               
               <div className="bg-card border rounded-lg p-4 space-y-3">
                 <h3 className="font-semibold text-sm">Statistiques</h3>
                 <div className="space-y-2 text-sm">
-                  <div className="flex justify-between">
-                    <span className="text-muted-foreground">Articles non lus</span>
-                    <Badge variant="outline">{articles.length}</Badge>
-                  </div>
+                            <div className="flex justify-between">
+                              <span className="text-muted-foreground">Articles non lus</span>
+                              <Badge variant="outline">{unreadCount}</Badge>
+                            </div>
+                            <div className="flex justify-between">
+                              <span className="text-muted-foreground">Articles totaux</span>
+                              <Badge variant="outline">{articles.length}</Badge>
+                            </div>
                   {user && <div className="flex justify-between">
                       <span className="text-muted-foreground">Épinglés</span>
                       <Badge variant="secondary">{pinnedCount}</Badge>
@@ -157,7 +164,7 @@ const Index = () => {
             <div className="flex items-center justify-between">
               <div className="flex items-center gap-4">
                 <h2 className="text-2xl font-bold">
-                  {user ? 'Articles non lus' : 'Derniers articles'}
+                  {showReadArticles ? 'Tous les articles' : (user ? 'Articles non lus' : 'Derniers articles')}
                 </h2>
                 
               </div>
@@ -185,6 +192,8 @@ const Index = () => {
                           onDateFilterChange={setDateFilter}
                           showFollowedOnly={showFollowedOnly}
                           onShowFollowedOnlyChange={setShowFollowedOnly}
+                          showReadArticles={showReadArticles}
+                          onShowReadArticlesChange={setShowReadArticles}
                         />
                         
                         <div className="bg-card border rounded-lg p-4 space-y-3">
@@ -192,6 +201,10 @@ const Index = () => {
                           <div className="space-y-2 text-sm">
                             <div className="flex justify-between">
                               <span className="text-muted-foreground">Articles non lus</span>
+                              <Badge variant="outline">{unreadCount}</Badge>
+                            </div>
+                            <div className="flex justify-between">
+                              <span className="text-muted-foreground">Articles totaux</span>
                               <Badge variant="outline">{articles.length}</Badge>
                             </div>
                             {user && <div className="flex justify-between">