|
import React from 'react'; |
|
import { Bot, Newspaper, LineChart, Share2, TrendingUp, TrendingDown, ChevronsUp, ChevronsDown, Landmark, Building2, User, ArrowUp, ArrowDown, Minus } from 'lucide-react'; |
|
import ReactMarkdown from 'react-markdown'; |
|
import HistoricalChart from './HistoricalChart'; |
|
|
|
const SectionTitle = ({ icon, title, subtitle }) => ( |
|
<div className="mb-8"> |
|
<div className="flex items-center space-x-4 mb-2"> |
|
<div className="p-2 bg-gradient-to-r from-green-500/20 to-emerald-500/20 rounded-lg border border-green-500/30"> |
|
{icon} |
|
</div> |
|
<h2 className="text-3xl font-bold bg-gradient-to-r from-green-400 to-emerald-400 bg-clip-text text-transparent tracking-wide"> |
|
{title} |
|
</h2> |
|
</div> |
|
{subtitle && ( |
|
<p className="text-gray-400 ml-16 text-sm leading-relaxed">{subtitle}</p> |
|
)} |
|
</div> |
|
); |
|
|
|
const MetricCard = ({ title, value, subtitle, trend }) => { |
|
const getTrendIcon = () => { |
|
if (trend > 0) return <ArrowUp className="w-4 h-4 text-green-400" />; |
|
if (trend < 0) return <ArrowDown className="w-4 h-4 text-red-400" />; |
|
return <Minus className="w-4 h-4 text-gray-400" />; |
|
}; |
|
|
|
const getTrendColor = () => { |
|
if (trend > 0) return 'text-green-400'; |
|
if (trend < 0) return 'text-red-400'; |
|
return 'text-gray-400'; |
|
}; |
|
|
|
return ( |
|
<div className="group relative overflow-hidden"> |
|
<div className="absolute inset-0 bg-gradient-to-br from-green-500/5 to-emerald-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300 rounded-xl"></div> |
|
<div className="relative bg-gray-800/60 backdrop-blur-sm p-6 rounded-xl border border-gray-700/50 hover:border-green-500/30 transition-all duration-300 hover:shadow-lg hover:shadow-green-500/10 hover:-translate-y-1"> |
|
<div className="flex items-center justify-between mb-2"> |
|
<p className="text-sm font-medium text-gray-400 uppercase tracking-wide">{title}</p> |
|
{trend !== undefined && getTrendIcon()} |
|
</div> |
|
<p className="text-2xl font-bold text-white mb-1 leading-tight">{value}</p> |
|
{subtitle && ( |
|
<p className={`text-xs font-medium ${getTrendColor()} flex items-center space-x-1`}> |
|
<span>{subtitle}</span> |
|
</p> |
|
)} |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
const NewsCard = ({ item, index }) => ( |
|
<a |
|
href={item.url} |
|
target="_blank" |
|
rel="noopener noreferrer" |
|
className="group block relative overflow-hidden bg-gradient-to-br from-gray-800/80 to-gray-900/80 backdrop-blur-sm rounded-xl border border-gray-700/50 hover:border-green-500/30 transition-all duration-300 hover:shadow-xl hover:shadow-green-500/10 hover:-translate-y-2" |
|
> |
|
<div className="absolute inset-0 bg-gradient-to-br from-green-500/5 to-emerald-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div> |
|
<div className="relative p-6"> |
|
<div className="flex items-start justify-between mb-4"> |
|
<span className={`inline-flex items-center px-3 py-1 rounded-full text-xs font-bold ${ |
|
item.sentiment === 'Positive' |
|
? 'bg-green-900/60 text-green-300 border border-green-500/30' |
|
: item.sentiment === 'Negative' |
|
? 'bg-red-900/60 text-red-300 border border-red-500/30' |
|
: 'bg-yellow-900/60 text-yellow-300 border border-yellow-500/30' |
|
}`}> |
|
{item.sentiment} |
|
</span> |
|
<div className="flex items-center space-x-1"> |
|
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div> |
|
<span className="text-xs text-gray-500">Live</span> |
|
</div> |
|
</div> |
|
|
|
<h3 className="font-bold text-gray-100 mb-3 line-clamp-3 leading-snug text-base group-hover:text-green-300 transition-colors"> |
|
{item.title} |
|
</h3> |
|
|
|
<div className="flex justify-between items-center text-xs text-gray-400 pt-4 border-t border-gray-700/50"> |
|
<span className="font-semibold bg-gray-700/50 px-2 py-1 rounded-md">{item.source}</span> |
|
<span className="opacity-70">Click to read</span> |
|
</div> |
|
</div> |
|
</a> |
|
); |
|
|
|
function ResultsDisplay({ result }) { |
|
if (!result) return null; |
|
|
|
const { |
|
company_name, |
|
current_price, |
|
previous_close, |
|
day_high, |
|
day_low, |
|
fifty_two_week_high, |
|
fifty_two_week_low, |
|
market_cap, |
|
pe_ratio, |
|
sector, |
|
industry, |
|
ceo, |
|
intelligence_briefing, |
|
llm_analysis |
|
} = result; |
|
|
|
const price_change = current_price - previous_close; |
|
const price_change_percent = ((price_change / previous_close) * 100); |
|
const advisorReportText = llm_analysis?.llm_report; |
|
|
|
const handleShare = () => { |
|
if (navigator.share) { |
|
navigator.share({ |
|
title: `${company_name} Analysis`, |
|
text: `Check out this comprehensive analysis of ${company_name}`, |
|
url: window.location.href, |
|
}); |
|
} else { |
|
navigator.clipboard.writeText(window.location.href); |
|
alert('Analysis link copied to clipboard!'); |
|
} |
|
}; |
|
|
|
return ( |
|
<div className="mt-12 animate-fade-in"> |
|
|
|
<div className="relative overflow-hidden bg-gradient-to-br from-gray-800/60 to-gray-900/60 backdrop-blur-sm p-8 rounded-2xl border border-gray-700/50 mb-12"> |
|
<div className="absolute inset-0 bg-gradient-to-br from-green-500/5 to-emerald-500/5"></div> |
|
<div className="relative flex flex-col lg:flex-row justify-between items-start"> |
|
<div className="flex-1"> |
|
<div className="flex items-center space-x-4 mb-4"> |
|
<div className="w-3 h-3 bg-green-400 rounded-full animate-pulse"></div> |
|
<span className="text-sm font-medium text-green-400 uppercase tracking-wider">Live Analysis</span> |
|
</div> |
|
|
|
<h1 className="text-5xl lg:text-6xl font-extrabold bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent mb-4 leading-tight"> |
|
{company_name} |
|
</h1> |
|
|
|
<div className="flex flex-wrap items-center gap-6 text-gray-400"> |
|
<span className="flex items-center space-x-2 bg-gray-700/50 px-3 py-2 rounded-lg"> |
|
<Building2 className="w-4 h-4 text-green-400" /> |
|
<span className="font-medium">{sector}</span> |
|
</span> |
|
<span className="flex items-center space-x-2 bg-gray-700/50 px-3 py-2 rounded-lg"> |
|
<Landmark className="w-4 h-4 text-green-400" /> |
|
<span className="font-medium">{industry}</span> |
|
</span> |
|
<span className="flex items-center space-x-2 bg-gray-700/50 px-3 py-2 rounded-lg"> |
|
<User className="w-4 h-4 text-green-400" /> |
|
<span className="font-medium">CEO: {ceo}</span> |
|
</span> |
|
</div> |
|
</div> |
|
|
|
<button |
|
onClick={handleShare} |
|
className="mt-6 lg:mt-0 flex-shrink-0 group relative overflow-hidden bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-500 hover:to-emerald-500 text-white font-semibold py-3 px-6 rounded-xl transition-all duration-300 hover:shadow-lg hover:shadow-green-500/25 hover:-translate-y-1" |
|
> |
|
<div className="absolute inset-0 bg-white/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div> |
|
<div className="relative flex items-center space-x-2"> |
|
<Share2 className="w-5 h-5" /> |
|
<span>Share Analysis</span> |
|
</div> |
|
</button> |
|
</div> |
|
</div> |
|
|
|
<div className="mb-16"> |
|
<SectionTitle |
|
icon={<TrendingUp className="w-8 h-8 text-green-400" />} |
|
title="Key Metrics" |
|
subtitle="Real-time financial indicators and performance metrics" |
|
/> |
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 gap-6"> |
|
<MetricCard |
|
title="Current Price" |
|
value={`₹${current_price?.toFixed(2)}`} |
|
subtitle={`${price_change >= 0 ? '+' : ''}₹${price_change.toFixed(2)} (${price_change_percent >= 0 ? '+' : ''}${price_change_percent.toFixed(2)}%)`} |
|
trend={price_change} |
|
/> |
|
<MetricCard |
|
title="Market Cap" |
|
value={`₹${(market_cap / 10000000).toFixed(2)} Cr`} |
|
/> |
|
<MetricCard |
|
title="P/E Ratio" |
|
value={pe_ratio?.toFixed(2)} |
|
subtitle="Price to Earnings" |
|
/> |
|
<MetricCard |
|
title="Today's Range" |
|
value={`₹${day_low?.toFixed(2)}`} |
|
subtitle={`High: ₹${day_high?.toFixed(2)}`} |
|
/> |
|
<MetricCard |
|
title="52W Range" |
|
value={`₹${fifty_two_week_low?.toFixed(2)}`} |
|
subtitle={`High: ₹${fifty_two_week_high?.toFixed(2)}`} |
|
/> |
|
</div> |
|
</div> |
|
|
|
<div className="mb-16"> |
|
<SectionTitle |
|
icon={<LineChart className="w-8 h-8 text-green-400" />} |
|
title="Price Movement" |
|
subtitle="Historical price action over the last 100 trading days" |
|
/> |
|
|
|
<div className="relative overflow-hidden bg-gradient-to-br from-gray-800/40 to-gray-900/40 backdrop-blur-sm p-8 rounded-2xl border border-gray-700/50"> |
|
<div className="absolute inset-0 bg-gradient-to-br from-green-500/3 to-emerald-500/3"></div> |
|
<div className="relative"> |
|
<HistoricalChart ticker={result.ticker} /> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
{advisorReportText && ( |
|
<div className="mb-16"> |
|
<SectionTitle |
|
icon={<Bot className="w-8 h-8 text-green-400" />} |
|
title="AI Analyst Report" |
|
subtitle="Comprehensive analysis powered by advanced AI models and real-time market data" |
|
/> |
|
|
|
<div className="relative overflow-hidden bg-gradient-to-br from-gray-800/40 to-gray-900/40 backdrop-blur-sm rounded-2xl border border-gray-700/50"> |
|
<div className="absolute inset-0 bg-gradient-to-br from-green-500/3 to-emerald-500/3"></div> |
|
<div className="relative p-8"> |
|
<div className="flex items-center space-x-3 mb-6 pb-4 border-b border-gray-700/50"> |
|
<div className="w-3 h-3 bg-green-400 rounded-full animate-pulse"></div> |
|
<span className="text-sm font-medium text-green-400 uppercase tracking-wider">AI Generated</span> |
|
<span className="text-xs text-gray-500">•</span> |
|
<span className="text-xs text-gray-500">Powered by AI</span> |
|
</div> |
|
|
|
<div className="prose prose-invert prose-lg max-w-none text-gray-300 prose-headings:text-green-400 prose-strong:text-white prose-p:leading-relaxed prose-li:leading-relaxed"> |
|
<ReactMarkdown |
|
components={{ |
|
h1: ({node, ...props}) => <h2 className="text-2xl font-bold mt-8 mb-4 text-green-400" {...props} />, |
|
h2: ({node, ...props}) => <h3 className="text-xl font-bold mt-6 mb-3 text-green-300" {...props} />, |
|
h3: ({node, ...props}) => <h4 className="text-lg font-semibold mt-4 mb-2 text-green-200" {...props} />, |
|
ul: ({node, ...props}) => <ul className="list-disc pl-6 space-y-2 my-4" {...props} />, |
|
ol: ({node, ...props}) => <ol className="list-decimal pl-6 space-y-2 my-4" {...props} />, |
|
li: ({node, ...props}) => <li className="leading-relaxed text-gray-300" {...props} />, |
|
p: ({node, ...props}) => <p className="mb-4 leading-relaxed text-gray-300" {...props} />, |
|
strong: ({node, ...props}) => <strong className="font-semibold text-white" {...props} />, |
|
blockquote: ({node, ...props}) => ( |
|
<blockquote className="border-l-4 border-green-500/50 pl-4 italic text-gray-400 my-4" {...props} /> |
|
), |
|
}} |
|
> |
|
{advisorReportText} |
|
</ReactMarkdown> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
)} |
|
|
|
<div className="mb-16"> |
|
<SectionTitle |
|
icon={<Newspaper className="w-8 h-8 text-green-400" />} |
|
title="Market Intelligence" |
|
subtitle="Latest news and sentiment analysis from multiple sources" |
|
/> |
|
|
|
{intelligence_briefing?.articles?.length > 0 ? ( |
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-8"> |
|
{intelligence_briefing.articles.slice(0, 9).map((item, index) => ( |
|
<NewsCard key={index} item={item} index={index} /> |
|
))} |
|
</div> |
|
) : ( |
|
<div className="text-center py-16 bg-gray-800/30 rounded-2xl border border-gray-700/50"> |
|
<Newspaper className="w-16 h-16 text-gray-600 mx-auto mb-4" /> |
|
<p className="text-gray-400 text-lg">No news articles found for this symbol.</p> |
|
<p className="text-gray-500 text-sm mt-2">Try checking back later or verify the ticker symbol.</p> |
|
</div> |
|
)} |
|
</div> |
|
</div> |
|
); |
|
} |
|
|
|
export default ResultsDisplay; |