Pinned.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { useState } from "react";
  2. import { useNavigate } from "react-router-dom";
  3. import { Pin, ArrowLeft } from "lucide-react";
  4. import { useRealArticles } from "@/hooks/useRealArticles";
  5. import { useAuth } from "@/hooks/useAuth";
  6. import NewsCard from "@/components/NewsCard";
  7. import ArticleModal from "@/components/ArticleModal";
  8. import { NewsItem } from "@/types/news";
  9. import { Button } from "@/components/ui/button";
  10. const Pinned = () => {
  11. const navigate = useNavigate();
  12. const { user } = useAuth();
  13. const { articles, loading, togglePin, markAsRead, deleteArticle } = useRealArticles();
  14. const [selectedArticle, setSelectedArticle] = useState<NewsItem | null>(null);
  15. // Redirect if not authenticated
  16. if (!user) {
  17. navigate("/auth");
  18. return null;
  19. }
  20. // Filter only pinned articles
  21. const pinnedArticles = articles.filter(article => article.isPinned);
  22. if (loading) {
  23. return (
  24. <div className="min-h-screen bg-background flex items-center justify-center">
  25. <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
  26. </div>
  27. );
  28. }
  29. return (
  30. <div className="min-h-screen bg-background">
  31. {/* Header */}
  32. <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
  33. <div className="container flex h-16 items-center justify-between px-4">
  34. <div className="flex items-center gap-4">
  35. <Button
  36. variant="ghost"
  37. size="icon"
  38. onClick={() => navigate("/")}
  39. aria-label="Retour à l'accueil"
  40. >
  41. <ArrowLeft className="h-5 w-5" />
  42. </Button>
  43. <div className="flex items-center gap-2">
  44. <Pin className="h-6 w-6 text-primary" />
  45. <h1 className="text-2xl font-bold">Articles épinglés</h1>
  46. {pinnedArticles.length > 0 && (
  47. <span className="ml-2 rounded-full bg-primary/10 px-3 py-1 text-sm font-medium text-primary">
  48. {pinnedArticles.length}
  49. </span>
  50. )}
  51. </div>
  52. </div>
  53. </div>
  54. </header>
  55. {/* Content */}
  56. <main className="container mx-auto px-4 py-8">
  57. {pinnedArticles.length === 0 ? (
  58. <div className="flex flex-col items-center justify-center py-16 text-center">
  59. <Pin className="h-16 w-16 text-muted-foreground mb-4" />
  60. <h2 className="text-2xl font-semibold mb-2">Aucun article épinglé</h2>
  61. <p className="text-muted-foreground mb-6 max-w-md">
  62. Vous n'avez pas encore épinglé d'articles. Épinglez vos articles préférés depuis la page principale pour les retrouver facilement ici.
  63. </p>
  64. <Button onClick={() => navigate("/")} variant="default">
  65. Retour à l'accueil
  66. </Button>
  67. </div>
  68. ) : (
  69. <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  70. {pinnedArticles.map((article) => (
  71. <NewsCard
  72. key={article.id}
  73. news={article}
  74. onTogglePin={togglePin}
  75. onMarkAsRead={markAsRead}
  76. onDelete={deleteArticle}
  77. onOpenArticle={setSelectedArticle}
  78. />
  79. ))}
  80. </div>
  81. )}
  82. </main>
  83. {/* Article Modal */}
  84. {selectedArticle && (
  85. <ArticleModal
  86. article={selectedArticle}
  87. isOpen={!!selectedArticle}
  88. onClose={() => setSelectedArticle(null)}
  89. />
  90. )}
  91. </div>
  92. );
  93. };
  94. export default Pinned;