Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/llms-txt-hub / apps/web/components/latest-news.tsx |
| Date | Not specified in source |
| Repository | Janady13/llms-txt-hub |
| Revision | e0f4bf978d4df168369c7601d9c5f5ea89e84377 |
| Branch | main |
| Path or archive member | apps/web/components/latest-news.tsx |
| Original SHA-256 | d1bb18863ba1ebd4327904b76ce25ec879212b17b5c09f377d2073aa620a4c9c |
| Git blob SHA | 77c254ef6c3786f57c80abc3a8b2e0c616042dc2 |
| Reading-copy SHA-256 | d1bb18863ba1ebd4327904b76ce25ec879212b17b5c09f377d2073aa620a4c9c |
Recovered source transcript
Download complete source text ↓138 lines · 4.4 KB
'use client'
import { Skeleton } from '@thedaviddias/design-system/skeleton'
import { logger } from '@thedaviddias/logging'
import { ArrowRight, ExternalLink, Rss } from 'lucide-react'
import Link from 'next/link'
import { useEffect, useState } from 'react'
import { RSS_FEED_URL } from '@/app/api/rss-feed/route'
import { Card } from '@/components/ui/card'
import { getRoute } from '@/lib/routes'
interface NewsItem {
title: string
link: string
pubDate: string
}
const NUMBER_OF_NEWS_ITEMS = 4
/**
* Displays a list of the latest news items fetched from the RSS feed
*/
export function LatestNews() {
const [news, setNews] = useState<NewsItem[]>([])
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
/**
* Fetches news items from the RSS feed API
*/
async function fetchNews() {
try {
setIsLoading(true)
const response = await fetch('/api/rss-feed')
if (!response.ok) {
throw new Error('Failed to fetch news')
}
const data = await response.json()
setNews(data.items.slice(0, NUMBER_OF_NEWS_ITEMS))
} catch (error) {
logger.error('Failed to fetch news:', { data: error, tags: { type: 'component' } })
setError('Failed to load latest news. Please try again later.')
} finally {
setIsLoading(false)
}
}
fetchNews()
}, [])
if (isLoading) {
return (
<section className="space-y-4">
<div className="flex justify-between items-center">
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold">Latest News</h2>
<Link
href={RSS_FEED_URL}
className="text-sm text-muted-foreground hover:text-foreground"
>
<Rss className="size-4" />
<span className="sr-only">RSS Feed for latest news</span>
</Link>
</div>
<div className="flex items-center gap-2">
<Link href={getRoute('news')} className="flex items-center">
All news <ArrowRight className="ml-2 size-4" />
</Link>
</div>
</div>
<div className="grid gap-4">
{Array.from({ length: NUMBER_OF_NEWS_ITEMS }).map((_, index) => (
<Card key={index} className="p-4">
<Skeleton className="h-4 w-3/4 mb-2" />
<Skeleton className="h-4 w-1/2" />
</Card>
))}
</div>
</section>
)
}
if (error) {
return <div className="text-red-500">{error}</div>
}
return (
<section className="space-y-4">
<div className="flex justify-between items-center">
<div className="flex items-center gap-2">
<h2 className="text-2xl font-bold">Latest News</h2>
<Link href={RSS_FEED_URL} className="text-sm text-muted-foreground hover:text-foreground">
<Rss className="size-4" />
<span className="sr-only">RSS Feed for latest news</span>
</Link>
</div>
<div className="flex items-center gap-2">
<Link href={getRoute('news')} className="flex items-center">
All news <ArrowRight className="ml-2 size-4" />
</Link>
</div>
</div>
<div className="grid gap-4">
{isLoading ? (
Array.from({ length: NUMBER_OF_NEWS_ITEMS }).map((_, index) => (
<Card key={index} className="p-4">
<Skeleton className="h-4 w-3/4 mb-2" />
<Skeleton className="h-4 w-1/2" />
</Card>
))
) : news.length > 0 ? (
news.map((item, index) => (
<Card key={index} className="p-4">
<h3 className="font-semibold">
<Link
href={item.link}
className="hover:underline"
target="_blank"
rel="noopener noreferrer"
>
{item.title}
<ExternalLink className="inline-block ml-2 size-4" />
</Link>
</h3>
<p className="text-sm text-muted-foreground">
{new Date(item.pubDate).toLocaleDateString()}
</p>
</Card>
))
) : (
<p className="text-muted-foreground">No news items available at the moment.</p>
)}
</div>
</section>
)
}