| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- import { useState, useEffect } from 'react';
- import { supabase } from '@/integrations/supabase/client';
- import { useAuth } from './useAuth';
- import { NewsItem } from '@/types/news';
- import { toast } from 'sonner';
- const ARTICLES_PER_PAGE = 20;
- interface FeedInfo {
- name: string;
- description: string | null;
- category: string;
- type: string;
- }
- export function useFeedArticles(feedId: string, page: number = 1) {
- const [articles, setArticles] = useState<NewsItem[]>([]);
- const [feedInfo, setFeedInfo] = useState<FeedInfo | null>(null);
- const [loading, setLoading] = useState(true);
- const [totalCount, setTotalCount] = useState(0);
- const { user } = useAuth();
- const fetchFeedArticles = async () => {
- try {
- setLoading(true);
- console.log('🔄 Fetching articles for feed:', feedId, 'page:', page);
- // Fetch feed info
- const { data: feed, error: feedError } = await supabase
- .from('feeds')
- .select('name, description, category, type')
- .eq('id', feedId)
- .single();
- if (feedError) {
- console.error('❌ Error fetching feed info:', feedError);
- toast.error('Flux introuvable');
- return;
- }
- setFeedInfo(feed);
- // Get total count for pagination
- const { count } = await supabase
- .from('articles')
- .select('*', { count: 'exact', head: true })
- .eq('feed_id', feedId);
- setTotalCount(count || 0);
- // Calculate pagination
- const from = (page - 1) * ARTICLES_PER_PAGE;
- const to = from + ARTICLES_PER_PAGE - 1;
- // Fetch articles with pagination
- let query = supabase
- .from('articles')
- .select(`
- *,
- feeds!inner(name, category),
- user_articles(is_read, is_pinned)
- `)
- .eq('feed_id', feedId)
- .order('published_at', { ascending: false })
- .range(from, to);
- const { data: articlesData, error: articlesError } = await query;
- if (articlesError) {
- console.error('❌ Error fetching articles:', articlesError);
- toast.error('Erreur lors du chargement des articles');
- return;
- }
- console.log('📰 Articles found:', articlesData?.length || 0);
- // Transform to NewsItem format
- const transformedArticles: NewsItem[] = articlesData
- ?.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: user ? (article.user_articles[0]?.is_pinned || false) : false,
- isRead: user ? (article.user_articles[0]?.is_read || false) : false,
- url: article.url || undefined,
- imageUrl: article.image_url || undefined,
- feedId: article.feed_id
- })) || [];
- setArticles(transformedArticles);
- } catch (error) {
- console.error('💥 Error in fetchFeedArticles:', error);
- toast.error('Erreur lors du chargement des articles');
- } finally {
- setLoading(false);
- }
- };
- const togglePin = async (articleId: string) => {
- if (!user) {
- toast.error('Vous devez être connecté pour épingler un article');
- return;
- }
- try {
- const article = articles.find(a => a.id === articleId);
- if (!article) return;
- const { error } = await supabase
- .from('user_articles')
- .upsert({
- user_id: user.id,
- article_id: articleId,
- is_pinned: !article.isPinned,
- is_read: article.isRead
- }, {
- onConflict: 'user_id,article_id'
- });
- if (error) {
- toast.error('Erreur lors de la mise à jour');
- return;
- }
- setArticles(prev => prev.map(item =>
- item.id === articleId ? { ...item, isPinned: !item.isPinned } : item
- ));
-
- toast.success(article.isPinned ? "Article retiré des épinglés" : "Article épinglé");
- } catch (error) {
- console.error('Error toggling pin:', error);
- toast.error('Erreur lors de la mise à jour');
- }
- };
- const markAsRead = async (articleId: string) => {
- if (!user) return;
- try {
- const article = articles.find(a => a.id === articleId);
- if (!article || article.isRead) return;
- const { error } = await supabase
- .from('user_articles')
- .upsert({
- user_id: user.id,
- article_id: articleId,
- is_read: true,
- is_pinned: article.isPinned,
- read_at: new Date().toISOString()
- }, {
- onConflict: 'user_id,article_id'
- });
- if (error) {
- console.error('Error marking as read:', error);
- return;
- }
- 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);
- }
- };
- const deleteArticle = async (articleId: string) => {
- if (!user) {
- toast.error('Vous devez être connecté pour supprimer un article');
- return;
- }
- try {
- const { error } = await supabase
- .from('user_articles')
- .delete()
- .eq('user_id', user.id)
- .eq('article_id', articleId);
- if (error) {
- toast.error('Erreur lors de la suppression');
- return;
- }
- setArticles(prev => prev.filter(item => item.id !== articleId));
- toast.success("Article supprimé de votre vue");
- } catch (error) {
- console.error('Error deleting article:', error);
- toast.error('Erreur lors de la suppression');
- }
- };
- useEffect(() => {
- if (feedId) {
- fetchFeedArticles();
- }
- }, [feedId, page, user]);
- const totalPages = Math.ceil(totalCount / ARTICLES_PER_PAGE);
- return {
- articles,
- feedInfo,
- loading,
- totalCount,
- totalPages,
- currentPage: page,
- togglePin,
- markAsRead,
- deleteArticle,
- refetch: fetchFeedArticles
- };
- }
|