|
|
@@ -1,25 +1,29 @@
|
|
|
|
|
|
import { useState, useMemo } from 'react';
|
|
|
-import { newsItems, categories } from '@/data/mockNews';
|
|
|
-import { NewsItem } from '@/types/news';
|
|
|
+import { categories } from '@/data/mockNews';
|
|
|
+import { useArticles } from '@/hooks/useArticles';
|
|
|
+import { useAuth } from '@/hooks/useAuth';
|
|
|
import Header from '@/components/Header';
|
|
|
import CategoryFilter from '@/components/CategoryFilter';
|
|
|
import NewsCard from '@/components/NewsCard';
|
|
|
import AddFeedModal from '@/components/AddFeedModal';
|
|
|
import { Badge } from '@/components/ui/badge';
|
|
|
import { Button } from '@/components/ui/button';
|
|
|
-import { RefreshCw, Filter } from 'lucide-react';
|
|
|
+import { Card, CardContent } from '@/components/ui/card';
|
|
|
+import { RefreshCw, Filter, User, Rss } from 'lucide-react';
|
|
|
import { toast } from 'sonner';
|
|
|
+import { Link } from 'react-router-dom';
|
|
|
|
|
|
const Index = () => {
|
|
|
- const [news, setNews] = useState<NewsItem[]>(newsItems);
|
|
|
+ const { user } = useAuth();
|
|
|
+ const { articles, loading, togglePin, markAsRead, deleteArticle, refetch } = useArticles();
|
|
|
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
|
const [showFilters, setShowFilters] = useState(true);
|
|
|
const [isAddFeedModalOpen, setIsAddFeedModalOpen] = useState(false);
|
|
|
|
|
|
const filteredNews = useMemo(() => {
|
|
|
- let filtered = news;
|
|
|
+ let filtered = articles;
|
|
|
|
|
|
if (selectedCategory) {
|
|
|
const category = categories.find(c => c.id === selectedCategory);
|
|
|
@@ -41,42 +45,32 @@ const Index = () => {
|
|
|
if (!a.isPinned && b.isPinned) return 1;
|
|
|
return new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime();
|
|
|
});
|
|
|
- }, [news, selectedCategory, searchQuery]);
|
|
|
+ }, [articles, selectedCategory, searchQuery]);
|
|
|
|
|
|
- const pinnedCount = news.filter(item => item.isPinned).length;
|
|
|
- const unreadCount = news.filter(item => !item.isRead).length;
|
|
|
-
|
|
|
- const handleTogglePin = (id: string) => {
|
|
|
- setNews(prev => prev.map(item =>
|
|
|
- item.id === id ? { ...item, isPinned: !item.isPinned } : item
|
|
|
- ));
|
|
|
- toast.success("Article épinglé mis à jour");
|
|
|
- };
|
|
|
-
|
|
|
- const handleMarkAsRead = (id: string) => {
|
|
|
- setNews(prev => prev.map(item =>
|
|
|
- item.id === id ? { ...item, isRead: true } : item
|
|
|
- ));
|
|
|
- toast.success("Article marqué comme lu");
|
|
|
- };
|
|
|
-
|
|
|
- const handleDelete = (id: string) => {
|
|
|
- setNews(prev => prev.filter(item => item.id !== id));
|
|
|
- toast.success("Article supprimé");
|
|
|
- };
|
|
|
+ const pinnedCount = articles.filter(item => item.isPinned).length;
|
|
|
+ const unreadCount = articles.filter(item => !item.isRead).length;
|
|
|
|
|
|
const handleRefresh = () => {
|
|
|
+ refetch();
|
|
|
toast.success("Flux actualisés");
|
|
|
};
|
|
|
|
|
|
const handleAddFeed = (feedData: any) => {
|
|
|
console.log('Nouveau flux ajouté:', feedData);
|
|
|
toast.success(`Flux "${feedData.name}" ajouté avec succès!`);
|
|
|
-
|
|
|
- // Ici vous pourrez ajouter la logique pour envoyer les données à votre backend MySQL
|
|
|
- // Par exemple: await api.addFeed(feedData);
|
|
|
};
|
|
|
|
|
|
+ if (loading) {
|
|
|
+ return (
|
|
|
+ <div className="min-h-screen bg-background flex items-center justify-center">
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <Rss className="h-6 w-6 animate-spin text-primary" />
|
|
|
+ <p>Chargement des articles...</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
return (
|
|
|
<div className="min-h-screen bg-background">
|
|
|
<Header
|
|
|
@@ -87,6 +81,50 @@ const Index = () => {
|
|
|
/>
|
|
|
|
|
|
<main className="container mx-auto px-4 py-6">
|
|
|
+ {/* Message pour les utilisateurs non connectés */}
|
|
|
+ {!user && (
|
|
|
+ <Card className="mb-6 border-blue-200 bg-blue-50">
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <div className="flex items-center gap-3">
|
|
|
+ <User className="h-5 w-5 text-blue-600" />
|
|
|
+ <div className="flex-1">
|
|
|
+ <p className="font-medium text-blue-900">Vous consultez les derniers articles publics</p>
|
|
|
+ <p className="text-sm text-blue-700">
|
|
|
+ Connectez-vous pour voir uniquement les articles de vos flux suivis et personnaliser votre expérience.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <Link to="/auth">
|
|
|
+ <Button size="sm">
|
|
|
+ Se connecter
|
|
|
+ </Button>
|
|
|
+ </Link>
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* Message pour les utilisateurs connectés sans articles */}
|
|
|
+ {user && articles.length === 0 && (
|
|
|
+ <Card className="mb-6 border-yellow-200 bg-yellow-50">
|
|
|
+ <CardContent className="pt-6">
|
|
|
+ <div className="flex items-center gap-3">
|
|
|
+ <Rss className="h-5 w-5 text-yellow-600" />
|
|
|
+ <div className="flex-1">
|
|
|
+ <p className="font-medium text-yellow-900">Aucun article trouvé</p>
|
|
|
+ <p className="text-sm text-yellow-700">
|
|
|
+ Vous ne suivez aucun flux pour le moment. Visitez la page de gestion des flux pour commencer à suivre des sources d'actualités.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <Link to="/feeds">
|
|
|
+ <Button size="sm">
|
|
|
+ Gérer les flux
|
|
|
+ </Button>
|
|
|
+ </Link>
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ )}
|
|
|
+
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
|
|
|
{/* Sidebar */}
|
|
|
<div className={`lg:col-span-1 space-y-6 ${!showFilters && 'hidden lg:block'}`}>
|
|
|
@@ -94,7 +132,7 @@ const Index = () => {
|
|
|
categories={categories}
|
|
|
selectedCategory={selectedCategory}
|
|
|
onCategoryChange={setSelectedCategory}
|
|
|
- newsCount={news.length}
|
|
|
+ newsCount={articles.length}
|
|
|
/>
|
|
|
|
|
|
<div className="bg-card border rounded-lg p-4 space-y-3">
|
|
|
@@ -102,7 +140,7 @@ const Index = () => {
|
|
|
<div className="space-y-2 text-sm">
|
|
|
<div className="flex justify-between">
|
|
|
<span className="text-muted-foreground">Total articles</span>
|
|
|
- <Badge variant="outline">{news.length}</Badge>
|
|
|
+ <Badge variant="outline">{articles.length}</Badge>
|
|
|
</div>
|
|
|
<div className="flex justify-between">
|
|
|
<span className="text-muted-foreground">Non lus</span>
|
|
|
@@ -121,10 +159,7 @@ const Index = () => {
|
|
|
<div className="flex items-center justify-between">
|
|
|
<div className="flex items-center gap-4">
|
|
|
<h2 className="text-2xl font-bold">
|
|
|
- {selectedCategory ?
|
|
|
- categories.find(c => c.id === selectedCategory)?.name :
|
|
|
- 'Tous les flux'
|
|
|
- }
|
|
|
+ {user ? 'Vos flux suivis' : 'Derniers articles'}
|
|
|
</h2>
|
|
|
<Badge variant="outline">
|
|
|
{filteredNews.length} article{filteredNews.length !== 1 ? 's' : ''}
|
|
|
@@ -167,9 +202,9 @@ const Index = () => {
|
|
|
<NewsCard
|
|
|
key={item.id}
|
|
|
news={item}
|
|
|
- onTogglePin={handleTogglePin}
|
|
|
- onMarkAsRead={handleMarkAsRead}
|
|
|
- onDelete={handleDelete}
|
|
|
+ onTogglePin={togglePin}
|
|
|
+ onMarkAsRead={markAsRead}
|
|
|
+ onDelete={deleteArticle}
|
|
|
/>
|
|
|
))}
|
|
|
</div>
|
|
|
@@ -178,12 +213,14 @@ const Index = () => {
|
|
|
</div>
|
|
|
</main>
|
|
|
|
|
|
- <AddFeedModal
|
|
|
- isOpen={isAddFeedModalOpen}
|
|
|
- onClose={() => setIsAddFeedModalOpen(false)}
|
|
|
- onAddFeed={handleAddFeed}
|
|
|
- categories={categories}
|
|
|
- />
|
|
|
+ {user && (
|
|
|
+ <AddFeedModal
|
|
|
+ isOpen={isAddFeedModalOpen}
|
|
|
+ onClose={() => setIsAddFeedModalOpen(false)}
|
|
|
+ onAddFeed={handleAddFeed}
|
|
|
+ categories={categories}
|
|
|
+ />
|
|
|
+ )}
|
|
|
</div>
|
|
|
);
|
|
|
};
|