institutional-trader/frontend/src/components/dashboard/NewsFeedPanel.jsx

67 lines
2.6 KiB
JavaScript

import { useState, useEffect } from 'react';
const API_BASE = import.meta.env.VITE_API_URL || '';
function SentimentDot({ sentiment }) {
if (sentiment === 'BULLISH') return <span className="inline-block w-2 h-2 rounded-full bg-emerald-400 mr-2 flex-shrink-0" />;
if (sentiment === 'BEARISH') return <span className="inline-block w-2 h-2 rounded-full bg-red-400 mr-2 flex-shrink-0" />;
return <span className="inline-block w-2 h-2 rounded-full bg-slate-500 mr-2 flex-shrink-0" />;
}
export default function NewsFeedPanel() {
const [news, setNews] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchNews = () => {
fetch(`${API_BASE}/api/market/news`)
.then(r => r.json())
.then(d => { if (d.success) setNews(d.data || []); })
.catch(console.error)
.finally(() => setLoading(false));
};
fetchNews();
const interval = setInterval(fetchNews, 300000); // 5min
return () => clearInterval(interval);
}, []);
return (
<div className="bg-slate-900 border border-slate-700/50 rounded-xl overflow-hidden">
<div className="flex items-center justify-between px-3 py-2.5 border-b border-slate-700/50">
<h3 className="text-sm font-semibold text-white">📰 Market News</h3>
{loading && <span className="text-xs text-blue-400 animate-pulse">Loading...</span>}
</div>
<div className="divide-y divide-slate-800/30 max-h-[400px] overflow-y-auto">
{loading ? (
Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="p-3 animate-pulse">
<div className="h-3 bg-slate-800 rounded mb-1.5" />
<div className="h-3 bg-slate-800 rounded w-2/3" />
</div>
))
) : news.length === 0 ? (
<div className="p-4 text-slate-500 text-xs text-center">No news available</div>
) : (
news.map((item, i) => (
<a
key={i}
href={item.url}
target="_blank"
rel="noopener noreferrer"
className="flex items-start gap-2 p-3 hover:bg-slate-800/40 transition-colors group"
>
<SentimentDot sentiment={item.sentiment} />
<div className="flex-1 min-w-0">
<div className="text-xs text-slate-300 group-hover:text-white transition-colors line-clamp-2 leading-snug">
{item.title}
</div>
<div className="text-xs text-slate-600 mt-1">{item.source}</div>
</div>
</a>
))
)}
</div>
</div>
);
}