import { createFileRoute } from '@tanstack/react-router' import { useInfiniteQuery } from '@tanstack/react-query' import { fetchArticles } from '@/api/articles' import { Button } from '@/components/ui/button' import { addArticleToCollection, createCollection, fetchCollections } from '@/api/collections'; import { useUser } from '@/store/user'; import { useNavigate } from '@tanstack/react-router'; import { Article } from '@/types'; import { useEffect, useRef, useCallback } from 'react'; export const Route = createFileRoute('/articles')({ component: ArticlesPage }) async function handleAddToCollection( article: Article, userId: string | undefined, navigate: ReturnType ) { if (!userId) { alert('Please login to add articles to collections'); navigate({ to: '/login' }); return; } const collectionName = prompt('Enter Collection Name:'); if (!collectionName) return; try { // Fetch existing collections const collections = await fetchCollections(); let collection = collections.find((col) => col.name === collectionName); // If collection does not exist, create it if (!collection) { collection = await createCollection({ name: collectionName, userId }); alert(`Collection '${collectionName}' created successfully!`); } // Add article to the collection await addArticleToCollection(collection.id, { title: article.title, content: article.content, source: article.source, url: article.url, publishedAt: new Date(article.publishedAt) }); alert(`Article added to collection '${collectionName}' successfully!`); } catch (error: unknown) { console.error('Failed to add article to collection:', error); alert('Failed to add article to collection. Please try again.'); } } function ArticlesPage() { const { data, isLoading, isError, error, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ queryKey: ['articles'], queryFn: async ({ pageParam = undefined }) => { const response = await fetchArticles(pageParam); return response; }, getNextPageParam: (lastPage) => lastPage.nextCursor, initialPageParam: undefined as string | undefined, staleTime: 1000 * 60 // Cache for 1 minute }); const user = useUser(); const navigate = useNavigate(); const loadMoreRef = useRef(null); const handleObserver = useCallback((entries: IntersectionObserverEntry[]) => { const [target] = entries; if (target.isIntersecting && hasNextPage && !isFetchingNextPage) { void fetchNextPage(); } }, [fetchNextPage, hasNextPage, isFetchingNextPage]); useEffect(() => { const element = loadMoreRef.current; const observer = new IntersectionObserver(handleObserver, { root: null, rootMargin: '0px', threshold: 0.1, }); if (element) { observer.observe(element); } return () => { if (element) { observer.unobserve(element); } }; }, [handleObserver]); // Show initial loading state if (isLoading && !data?.pages?.length) { return (
); } if (isError) { return (

Error

Failed to load articles: {error?.message || 'Unknown error'}

); } const allArticles = data?.pages.flatMap(page => page.articles) ?? []; return (

News Articles

Browse the latest news from various sources

{allArticles.length > 0 ? ( <>
{allArticles.map(article => (

{article.title}

{article.content?.substring(0, 120)}...

{article.source} {new Date(article.publishedAt).toLocaleDateString()}
))}
{/* Loading more trigger and indicator */}
{isFetchingNextPage ? (
) : hasNextPage ? ( Scroll to load more ) : ( No more articles to load )}
) : (

No articles found

Check back later for new content

)}
); }