147 lines
5.2 KiB
TypeScript
147 lines
5.2 KiB
TypeScript
import { useParams, Link } from 'react-router-dom'
|
|
import { useQuery } from '@tanstack/react-query'
|
|
import { formatDistanceToNow } from 'date-fns'
|
|
import { es } from 'date-fns/locale'
|
|
import { apiService } from '../services/api'
|
|
import { Globe, ArrowLeft, ExternalLink, Newspaper, Heart } from 'lucide-react'
|
|
import { useState, useEffect } from 'react'
|
|
import { WikiTooltip } from '../components/ui/WikiTooltip'
|
|
|
|
export function News() {
|
|
const { id } = useParams<{ id: string }>()
|
|
const [isFavorite, setIsFavorite] = useState(false)
|
|
|
|
const { data: news, isLoading, error } = useQuery({
|
|
queryKey: ['news', id],
|
|
queryFn: () => apiService.getNewsById(id!),
|
|
enabled: !!id,
|
|
})
|
|
|
|
useEffect(() => {
|
|
const stored = localStorage.getItem('favorites')
|
|
if (stored && id) {
|
|
const favorites = JSON.parse(stored)
|
|
setIsFavorite(favorites.some((n: any) => n.id === id))
|
|
}
|
|
}, [id])
|
|
|
|
const toggleFavorite = () => {
|
|
const stored = localStorage.getItem('favorites')
|
|
let favorites = stored ? JSON.parse(stored) : []
|
|
|
|
if (isFavorite) {
|
|
favorites = favorites.filter((n: any) => n.id !== id)
|
|
} else if (news) {
|
|
favorites.push(news)
|
|
}
|
|
|
|
localStorage.setItem('favorites', JSON.stringify(favorites))
|
|
setIsFavorite(!isFavorite)
|
|
}
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex justify-center py-12">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600"></div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (error || !news) {
|
|
return (
|
|
<div className="text-center py-12">
|
|
<p className="text-red-600">Error al cargar la noticia</p>
|
|
<Link to="/" className="text-primary-600 hover:underline mt-4 inline-block">
|
|
Volver al inicio
|
|
</Link>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<Link to="/" className="inline-flex items-center gap-2 text-gray-600 hover:text-primary-600 mb-6">
|
|
<ArrowLeft className="h-4 w-4" />
|
|
Volver
|
|
</Link>
|
|
|
|
<article className="card p-8">
|
|
{news.imagen_url && news.imagen_url.trim() && (
|
|
<img src={news.imagen_url} alt={news.titulo} className="w-full h-96 object-cover rounded-xl mb-8" />
|
|
)}
|
|
|
|
<div className="flex items-center gap-4 text-sm text-gray-500 mb-4">
|
|
{news.fuente_nombre && (
|
|
<span className="flex items-center gap-1">
|
|
<Newspaper className="h-4 w-4" />
|
|
{news.fuente_nombre}
|
|
</span>
|
|
)}
|
|
<span>•</span>
|
|
<span>
|
|
{news.fecha && formatDistanceToNow(new Date(news.fecha), { addSuffix: true, locale: es })}
|
|
</span>
|
|
</div>
|
|
|
|
<h1 className="text-3xl font-bold text-gray-900 mb-4">
|
|
{news.title_translated || news.titulo}
|
|
</h1>
|
|
|
|
<p className="text-lg text-gray-600 mb-6">
|
|
{news.summary_translated || news.resumen}
|
|
</p>
|
|
|
|
<div className="flex gap-4">
|
|
<a
|
|
href={news.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-2 text-primary-600 hover:underline"
|
|
>
|
|
<ExternalLink className="h-4 w-4" />
|
|
View Original
|
|
</a>
|
|
<button
|
|
onClick={toggleFavorite}
|
|
className={`inline-flex items-center gap-2 ${isFavorite ? 'text-red-500' : 'text-gray-500 hover:text-red-500'}`}
|
|
>
|
|
<Heart className={`h-4 w-4 ${isFavorite ? 'fill-current' : ''}`} />
|
|
{isFavorite ? 'Saved' : 'Save'}
|
|
</button>
|
|
</div>
|
|
|
|
{news.entities && news.entities.length > 0 && (
|
|
<div className="mt-8 pt-8 border-t border-gray-100">
|
|
<h3 className="text-xl font-bold tracking-tight text-gray-900 mb-4">Entidades Mencionadas</h3>
|
|
<div className="flex flex-wrap gap-2">
|
|
{news.entities.map((ent: any) => (
|
|
<WikiTooltip
|
|
key={ent.valor + ent.tipo}
|
|
name={ent.valor}
|
|
summary={ent.wiki_summary}
|
|
imagePath={ent.image_path}
|
|
wikiUrl={ent.wiki_url}
|
|
>
|
|
<span className="inline-flex items-center gap-4 px-3 py-2 rounded-xl text-base bg-gray-50 border border-gray-200 hover:border-primary-300 hover:bg-primary-50 transition-colors cursor-pointer group-hover:border-primary-300 group-hover:bg-primary-50">
|
|
{ent.image_path && (
|
|
<img
|
|
src={ent.image_path}
|
|
alt=""
|
|
className="w-20 h-20 rounded-full object-cover border-2 border-white shadow-md"
|
|
onError={(e) => (e.currentTarget.style.display = 'none')}
|
|
/>
|
|
)}
|
|
<span className="font-semibold text-gray-800 ml-1">{ent.valor}</span>
|
|
<span className="text-[10px] text-gray-500 font-medium uppercase tracking-wider bg-white px-1.5 py-0.5 rounded-md border border-gray-200">
|
|
{ent.tipo}
|
|
</span>
|
|
</span>
|
|
</WikiTooltip>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</article>
|
|
</div>
|
|
)
|
|
}
|