Skip to main content
Glama

MCP-RSS-Crawler

by mshk
FeedItemList.tsx5.73 kB
import { useEffect, useState } from 'react'; import { FeedItem } from '@/lib/db'; import FeedItemCard from './FeedItemCard'; import Image from 'next/image'; import { useRouter } from 'next/navigation'; interface FeedItemListProps { feedId?: string; category?: string; searchQuery?: string; } export default function FeedItemList({ feedId, category, searchQuery }: FeedItemListProps) { const router = useRouter(); const [items, setItems] = useState<FeedItem[]>([]); const [loading, setLoading] = useState(true); const [error, setError] = useState<string | null>(null); const [hasArticles, setHasArticles] = useState(false); const [fetchingFeeds, setFetchingFeeds] = useState(false); const fetchFeeds = async () => { try { setFetchingFeeds(true); const response = await fetch('/api/feeds/fetch', { method: 'POST', }); if (!response.ok) { throw new Error('Failed to fetch feeds'); } const data = await response.json(); console.log('Fetch feeds response:', data); // Refresh the page to show the new feeds router.refresh(); // Reload the items fetchItems(); } catch (err) { console.error('Error fetching feeds:', err); setError(err instanceof Error ? err.message : 'Failed to fetch feeds'); } finally { setFetchingFeeds(false); } }; const fetchItems = async () => { try { setLoading(true); // Build the query URL based on the props let url = '/api/items'; const params = new URLSearchParams(); if (feedId) { params.append('feedId', feedId); } else if (category) { params.append('category', category); } else if (searchQuery) { params.append('query', searchQuery); } if (params.toString()) { url += `?${params.toString()}`; } const response = await fetch(url); if (!response.ok) { throw new Error('Failed to fetch items'); } const data = await response.json(); setItems(data); // Check if articles are available in the database try { const articleCheckResponse = await fetch('/api/articles/check'); if (articleCheckResponse.ok) { const checkData = await articleCheckResponse.json(); setHasArticles(checkData.hasArticles); } } catch (err) { console.error('Error checking for articles:', err); setHasArticles(false); } setLoading(false); } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred'); setLoading(false); } }; useEffect(() => { fetchItems(); }, [feedId, category, searchQuery]); if (loading) { return ( <div className="p-4"> <div className="animate-pulse space-y-4"> {[...Array(5)].map((_, i) => ( <div key={i} className="border rounded-lg p-4"> <div className="h-5 bg-gray-300 rounded w-3/4 mb-2"></div> <div className="h-4 bg-gray-300 rounded w-1/4 mb-3"></div> <div className="h-4 bg-gray-300 rounded w-full mb-2"></div> <div className="h-4 bg-gray-300 rounded w-full mb-2"></div> <div className="h-4 bg-gray-300 rounded w-2/3"></div> </div> ))} </div> </div> ); } if (error) { return ( <div className="p-4"> <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded"> <p>Error: {error}</p> </div> </div> ); } if (items.length === 0) { return ( <div className="p-4"> <div className="flex justify-between items-center mb-4"> <h2 className="text-xl font-bold flex items-center"> {feedId ? 'Feed Items' : category ? `Items in ${category}` : searchQuery ? `Search Results for "${searchQuery}"` : 'Recent Items'} </h2> <button onClick={fetchFeeds} disabled={fetchingFeeds} className={`px-4 py-2 rounded text-white ${fetchingFeeds ? 'bg-gray-400' : 'bg-blue-500 hover:bg-blue-600'}`} > {fetchingFeeds ? 'Fetching...' : 'Fetch Feeds'} </button> </div> <div className="bg-yellow-100 border border-yellow-400 text-yellow-700 px-4 py-3 rounded"> <p>No items found. Click the "Fetch Feeds" button to retrieve RSS feeds.</p> </div> </div> ); } return ( <div className="p-4"> <div className="mb-4"> <div className="flex justify-between items-center"> <h2 className="text-xl font-bold flex items-center"> {feedId ? 'Feed Items' : category ? `Items in ${category}` : searchQuery ? `Search Results for "${searchQuery}"` : 'Recent Items'} {hasArticles && ( <Image src="/file.svg" alt="Articles available" width={16} height={16} className="ml-2" title="Articles available" /> )} </h2> <button onClick={fetchFeeds} disabled={fetchingFeeds} className={`px-4 py-2 rounded text-white ${fetchingFeeds ? 'bg-gray-400' : 'bg-blue-500 hover:bg-blue-600'}`} > {fetchingFeeds ? 'Fetching...' : 'Fetch Feeds'} </button> </div> <p className="text-gray-600">{items.length} items found</p> </div> <div> {items.map(item => ( <FeedItemCard key={item.id} item={item} /> ))} </div> </div> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mshk/mcp-rss-crawler'

If you have feedback or need assistance with the MCP directory API, please join our Discord server