import { useState, useEffect, useRef } from 'react' import anime from 'animejs' import RecommendationHero from './components/RecommendationHero' import SignalCards from './components/SignalCards' import AgentStream from './components/AgentStream' import RiskFlags from './components/RiskFlags' import PortfolioView from './components/PortfolioView' import PriceChart from './components/PriceChart' const POPULAR = ['AAPL', 'NVDA', 'TSLA', 'MSFT', 'AMZN', 'GOOGL', 'META', 'SPY'] // ── Portfolio page ─────────────────────────────────────────────────────────── function PortfolioPage({ onAnalyse, onBack }) { return (
My Portfolio
) } // ── Landing ────────────────────────────────────────────────────────────────── function Landing({ onSearch, onPortfolio }) { const [input, setInput] = useState('') const cardRef = useRef(null) useEffect(() => { // Animate each letter of the title anime({ targets: '.hero-letter', translateY: [40, 0], opacity: [0, 1], delay: anime.stagger(45), easing: 'easeOutExpo', duration: 750, }) // Animate the search card up anime({ targets: cardRef.current, translateY: [30, 0], opacity: [0, 1], delay: 500, easing: 'easeOutExpo', duration: 800, }) }, []) const go = (ticker) => { const t = ticker.trim().toUpperCase() if (t) onSearch(t) } return (
🤖 Powered by AI Agents

{'Should you buy it?'.split('').map((ch, i) => ( {ch === ' ' ? '\u00a0' : ch} ))}

Type any stock ticker and get a plain-English verdict powered by machine learning, technical analysis, and real-time news.

setInput(e.target.value.toUpperCase())} onKeyDown={(e) => e.key === 'Enter' && go(input)} maxLength={10} autoFocus />
Popular: {POPULAR.map((t) => ( ))}
📊 Technical Charts
🏢 Company Financials
🤖 ML Prediction
📰 News Sentiment
) } // ── Loading ─────────────────────────────────────────────────────────────────── function LoadingScreen({ ticker }) { useEffect(() => { anime({ targets: '.loading-dot', translateY: [-10, 0], delay: anime.stagger(160), loop: true, direction: 'alternate', easing: 'easeInOutSine', duration: 450, }) }, []) return (

Analysing {ticker}

Fetching price data, financials, ML signals & news
) } // ── Error ───────────────────────────────────────────────────────────────────── function ErrorScreen({ error, onBack }) { return (
⚠️

Couldn't find that ticker

{error}
) } // ── Dashboard ───────────────────────────────────────────────────────────────── function Dashboard({ ticker, onBack }) { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [deepMode, setDeepMode] = useState(false) useEffect(() => { setLoading(true) setError(null) setData(null) setDeepMode(false) fetch(`/quick/${ticker}`) .then((r) => { if (!r.ok) throw new Error(`Ticker "${ticker}" not found or API error`) return r.json() }) .then((d) => { setData(d) setLoading(false) }) .catch((e) => { setError(e.message) setLoading(false) }) }, [ticker]) if (loading) return if (error) return return (
{/* Header */}
{ticker} {data.current_price > 0 && ( ${data.current_price.toFixed(2)} )}
{/* Content */}
{/* Forecast */} {data.forecast_upside !== undefined && data.forecast_upside !== 0 && (

📈 30-Day Price Forecast

0 ? 'up' : 'down'}`} > {data.forecast_upside > 0 ? '↑' : '↓'}{' '} {Math.abs(data.forecast_upside).toFixed(1)}%

{data.forecast_upside > 0 ? `Our AI forecasts the price could rise roughly ${data.forecast_upside.toFixed(1)}% over the next 30 days — though forecasts are never guaranteed.` : `Our AI forecasts the price could dip roughly ${Math.abs(data.forecast_upside).toFixed(1)}% over the next 30 days — though forecasts can be wrong.`}

)} {/* Risk flags */} {data.risk_flags?.length > 0 && } {/* Deep analysis */}
{!deepMode ? (

🔍 Want the full picture?

Run 6 specialised AI agents to get a detailed investment report with step-by-step reasoning.

⏱ Takes about 2–3 minutes
) : ( )}
) } // ── Root App ────────────────────────────────────────────────────────────────── export default function App() { const [ticker, setTicker] = useState(null) const [showPortfolio, setPortfolio] = useState(false) if (showPortfolio) return { setPortfolio(false); setTicker(t) }} onBack={() => setPortfolio(false)} /> return ticker ? ( setTicker(null)} /> ) : ( setPortfolio(true)} /> ) }