import React from 'react'; // New interface for the transformed JSON structure interface TransformedAnalysisData { metadata: { company_ticker: string; company_name: string; analysis_date: string; final_recommendation: 'BUY' | 'SELL' | 'HOLD'; confidence_level: 'HIGH' | 'MEDIUM' | 'LOW'; }; financial_data: { current_price: number; price_change: number; price_change_percent: number; market_cap: string; enterprise_value: string; shares_outstanding: string; trading_range: { high: number; low: number; open: number; }; volume: number; valuation_ratios: { current_ps_ratio: number; fair_value_ps_ratio: number; forward_pe: number; forward_ps: number; forward_pcf: number; forward_pocf: number; }; ownership: { insider_percent: number; institutional_percent: number; }; analyst_data: { consensus_rating: string; price_target: number; forecast_price: number; }; }; technical_indicators: { sma_50: number; sma_200: number; ema_10: number; macd: number; macd_signal: number; rsi: number; atr: number; trend_directions: { sma_50: 'BULLISH' | 'BEARISH' | 'NEUTRAL'; sma_200: 'BULLISH' | 'BEARISH' | 'NEUTRAL'; ema_10: 'BULLISH' | 'BEARISH' | 'NEUTRAL'; macd: 'BULLISH' | 'BEARISH' | 'NEUTRAL'; rsi_condition: 'OVERSOLD' | 'OVERBOUGHT' | 'NEUTRAL'; }; }; investment_strategy: { position_sizing: { total_allocation_percent: string; entry_strategy: string; tranche_1_percent: string; tranche_2_percent: string; }; risk_management: { initial_stop_loss: number; stop_loss_percent: number; breakeven_strategy: string; }; profit_targets: Array<{ target_price: number; action: string; rationale: string; }>; monitoring_points: string[]; }; debate_summary: { bull_key_points: string[]; bear_key_points: string[]; neutral_perspective: string; final_decision_rationale: string; }; text_content: { market_report: { title: string; content: string; key_takeaways: string[]; }; sentiment_report: { title: string; content: string; recent_developments: string[]; }; fundamentals_report: { title: string; content: string; financial_highlights: string[]; }; news_report: { title: string; content: string; key_developments: Array<{ date: string; event: string; impact: string; }>; }; investment_plan_full: { title: string; content: string; }; debate_transcripts: { bull_analysis: string; bear_analysis: string; neutral_analysis: string; risk_discussion: string; }; }; widgets_config: { charts_needed: Array<{ type: string; data_source: string; timeframe: string; }>; text_widgets: Array<{ type: string; title: string; content_source: string; }>; }; } // Legacy interface for backward compatibility interface LegacyTradingAgentsResult { symbol: string; final_decision?: { decision: string; reasoning: string; }; technical_analysis?: { current_price: number; rsi: number; macd: number; moving_averages: { ma_50: number; ma_200: number; }; }; fundamental_analysis?: { market_cap: string; ps_ratio: number; forward_pe: number; analyst_target: number; }; bull_arguments?: string[]; bear_arguments?: string[]; neutral_perspective?: string; risk_assessment?: { overall_risk: number; }; sentiment_analysis?: { overall_score: number; }; ownership_structure?: { insider_ownership: number; institutional_ownership: number; retail_ownership: number; }; investment_plan?: { stop_loss: number; profit_targets: number[]; }; earnings_date?: string; } interface TransformedDataAdapterProps { analysisData: TransformedAnalysisData | LegacyTradingAgentsResult; } const TransformedDataAdapter: React.FC = ({ analysisData }) => { // Check if this is the new transformed format or legacy format const isTransformedFormat = (data: any): data is TransformedAnalysisData => { return data.metadata && data.financial_data && data.technical_indicators; }; // Convert legacy format to new format for backward compatibility const convertLegacyToTransformed = (legacyData: LegacyTradingAgentsResult): TransformedAnalysisData => { return { metadata: { company_ticker: legacyData.symbol || 'UNKNOWN', company_name: legacyData.symbol || 'Unknown Company', analysis_date: new Date().toISOString().split('T')[0], final_recommendation: (legacyData.final_decision?.decision?.toUpperCase() as 'BUY' | 'SELL' | 'HOLD') || 'HOLD', confidence_level: 'MEDIUM' }, financial_data: { current_price: legacyData.technical_analysis?.current_price || 0, price_change: 0, price_change_percent: 0, market_cap: legacyData.fundamental_analysis?.market_cap || 'N/A', enterprise_value: 'N/A', shares_outstanding: 'N/A', trading_range: { high: 0, low: 0, open: 0 }, volume: 0, valuation_ratios: { current_ps_ratio: legacyData.fundamental_analysis?.ps_ratio || 0, fair_value_ps_ratio: 0, forward_pe: legacyData.fundamental_analysis?.forward_pe || 0, forward_ps: 0, forward_pcf: 0, forward_pocf: 0 }, ownership: { insider_percent: legacyData.ownership_structure?.insider_ownership || 0, institutional_percent: legacyData.ownership_structure?.institutional_ownership || 0 }, analyst_data: { consensus_rating: 'N/A', price_target: legacyData.fundamental_analysis?.analyst_target || 0, forecast_price: 0 } }, technical_indicators: { sma_50: legacyData.technical_analysis?.moving_averages?.ma_50 || 0, sma_200: legacyData.technical_analysis?.moving_averages?.ma_200 || 0, ema_10: 0, macd: legacyData.technical_analysis?.macd || 0, macd_signal: 0, rsi: legacyData.technical_analysis?.rsi || 50, atr: 0, trend_directions: { sma_50: 'NEUTRAL', sma_200: 'NEUTRAL', ema_10: 'NEUTRAL', macd: 'NEUTRAL', rsi_condition: 'NEUTRAL' } }, investment_strategy: { position_sizing: { total_allocation_percent: '0%', entry_strategy: 'N/A', tranche_1_percent: '0%', tranche_2_percent: '0%' }, risk_management: { initial_stop_loss: legacyData.investment_plan?.stop_loss || 0, stop_loss_percent: 0, breakeven_strategy: 'N/A' }, profit_targets: legacyData.investment_plan?.profit_targets?.map(target => ({ target_price: target, action: 'SELL', rationale: 'Profit target' })) || [], monitoring_points: [] }, debate_summary: { bull_key_points: legacyData.bull_arguments || [], bear_key_points: legacyData.bear_arguments || [], neutral_perspective: legacyData.neutral_perspective || 'No neutral perspective available', final_decision_rationale: legacyData.final_decision?.reasoning || 'No decision rationale available' }, text_content: { market_report: { title: 'Technical Analysis Report', content: 'Legacy data - detailed technical analysis not available', key_takeaways: [] }, sentiment_report: { title: 'Company Sentiment Analysis', content: 'Legacy data - detailed sentiment analysis not available', recent_developments: [] }, fundamentals_report: { title: 'Fundamental Analysis', content: 'Legacy data - detailed fundamental analysis not available', financial_highlights: [] }, news_report: { title: 'Macroeconomic Context', content: 'Legacy data - news report not available', key_developments: [] }, investment_plan_full: { title: 'Complete Investment Strategy', content: 'Legacy data - detailed investment plan not available' }, debate_transcripts: { bull_analysis: legacyData.bull_arguments?.join('\n') || '', bear_analysis: legacyData.bear_arguments?.join('\n') || '', neutral_analysis: legacyData.neutral_perspective || '', risk_discussion: '' } }, widgets_config: { charts_needed: [ { type: 'price_chart', data_source: 'financial_data.current_price', timeframe: '30_days' }, { type: 'technical_indicators', data_source: 'technical_indicators', timeframe: '30_days' } ], text_widgets: [ { type: 'expandable_report', title: 'Technical Analysis', content_source: 'text_content.market_report' } ] } }; }; // Get the transformed data (either already transformed or converted from legacy) const transformedData: TransformedAnalysisData = isTransformedFormat(analysisData) ? analysisData : convertLegacyToTransformed(analysisData); // Builds a default widgets_config for transformed analyses when missing const buildTransformedWidgetsConfig = (data: any) => { const confidenceMap: Record = { LOW: 33, MEDIUM: 66, HIGH: 90 }; return { layout: [ ["kpi_recommendation", "kpi_confidence", "kpi_price_change", "kpi_marketcap", "kpi_ev"], ["ownership_donut", "range_bar", "volume_chip"], ["rsi_gauge", "macd_mini", "ma_trends", "atr_chip"], ["strategy_ladder", "position_sizing", "monitoring_points"], ["analyst_target_vs_price"], ["report_technical", "report_sentiment"], ["report_fundamentals", "report_investment_plan"], ["debate_summary"] ], widgets: [ { id: "kpi_recommendation", type: "kpi_badge", title: "Recommendation", dataPath: "metadata.final_recommendation", colorMapping: { BUY: "green", HOLD: "yellow", SELL: "red" } }, { id: "kpi_confidence", type: "radial_gauge", title: "Confidence", value: confidenceMap[(data?.metadata?.confidence_level || "MEDIUM").toUpperCase()] || 66 }, { id: "kpi_price_change", type: "price_kpi", title: "Current Price", valuePath: "financial_data.current_price", deltaPath: "financial_data.price_change_percent", format: { value: "currency", delta: "percent" } }, { id: "kpi_marketcap", type: "kpi_text", title: "Market Cap", dataPath: "financial_data.market_cap" }, { id: "kpi_ev", type: "kpi_text", title: "Enterprise Value", dataPath: "financial_data.enterprise_value" }, { id: "ownership_donut", type: "donut", title: "Ownership", series: [ { label: "Insider %", valuePath: "financial_data.ownership.insider_percent" }, { label: "Institutional %", valuePath: "financial_data.ownership.institutional_percent" } ], valueFormat: "percent" }, { id: "range_bar", type: "range_bar", title: "Trading Range", lowPath: "financial_data.trading_range.low", highPath: "financial_data.trading_range.high", openPath: "financial_data.trading_range.open", currentPath: "financial_data.current_price" }, { id: "volume_chip", type: "kpi_text", title: "Volume", dataPath: "financial_data.volume", format: { value: "number_compact" } }, { id: "rsi_gauge", type: "linear_gauge", title: "RSI", dataPath: "technical_indicators.rsi", min: 0, max: 100, zones: [ { to: 30, color: "blue", label: "Oversold" }, { from: 70, to: 100, color: "red", label: "Overbought" } ] }, { id: "macd_mini", type: "macd_snapshot", title: "MACD", macdPath: "technical_indicators.macd", signalPath: "technical_indicators.macd_signal", histogramCompute: "macd - macd_signal" }, { id: "ma_trends", type: "badges", title: "MA & Trend", badges: [ { label: "SMA 50", valuePath: "technical_indicators.sma_50", trendPath: "technical_indicators.trend_directions.sma_50" }, { label: "SMA 200", valuePath: "technical_indicators.sma_200", trendPath: "technical_indicators.trend_directions.sma_200" }, { label: "EMA 10", valuePath: "technical_indicators.ema_10", trendPath: "technical_indicators.trend_directions.ema_10" } ], trendColors: { BULLISH: "green", BEARISH: "red", NEUTRAL: "gray" } }, { id: "atr_chip", type: "kpi_text", title: "ATR (Volatility)", dataPath: "technical_indicators.atr" }, { id: "strategy_ladder", type: "price_ladder", title: "Entry, Stop, Targets", entryStrategyPath: "investment_strategy.position_sizing.entry_strategy", stopPricePath: "investment_strategy.risk_management.initial_stop_loss", stopPercentPath: "investment_strategy.risk_management.stop_loss_percent", targetsPath: "investment_strategy.profit_targets", targetMapping: { price: "target_price", label: "action" }, currentPricePath: "financial_data.current_price" }, { id: "position_sizing", type: "chips", title: "Position Sizing", items: [ { label: "Total Allocation", valuePath: "investment_strategy.position_sizing.total_allocation_percent" }, { label: "Tranche 1", valuePath: "investment_strategy.position_sizing.tranche_1_percent" }, { label: "Tranche 2", valuePath: "investment_strategy.position_sizing.tranche_2_percent" } ] }, { id: "monitoring_points", type: "bullet_list", title: "Monitoring Points", itemsPath: "investment_strategy.monitoring_points" }, { id: "analyst_target_vs_price", type: "bar_compare", title: "Analyst Target vs Current", series: [ { label: "Current", valuePath: "financial_data.current_price" }, { label: "Target", valuePath: "financial_data.analyst_data.price_target" } ], yFormat: "currency" }, { id: "report_technical", type: "expandable_report", titlePath: "text_content.market_report.title", contentPath: "text_content.market_report.content", bulletsPath: "text_content.market_report.key_takeaways" }, { id: "report_sentiment", type: "expandable_report", titlePath: "text_content.sentiment_report.title", contentPath: "text_content.sentiment_report.content", bulletsPath: "text_content.sentiment_report.recent_developments" }, { id: "report_fundamentals", type: "expandable_report", titlePath: "text_content.fundamentals_report.title", contentPath: "text_content.fundamentals_report.content", bulletsPath: "text_content.fundamentals_report.financial_highlights" }, { id: "report_investment_plan", type: "expandable_report", titlePath: "text_content.investment_plan_full.title", contentPath: "text_content.investment_plan_full.content" }, { id: "debate_summary", type: "debate_viewer", bullPath: "debate_summary.bull_key_points", bearPath: "debate_summary.bear_key_points", neutralPath: "debate_summary.neutral_perspective", finalPath: "debate_summary.final_decision_rationale" } ] }; }; // Ensure we have a widgets_config; if missing, build a sensible default const transformedWithConfig = { ...transformedData, widgets_config: transformedData?.widgets_config || buildTransformedWidgetsConfig(transformedData) }; // Minimalist dashboard that shows ALL main sections of transformed JSON const MinimalTransformedDashboard: React.FC<{ data: TransformedAnalysisData }> = ({ data }) => { const md = (data?.metadata as any) || {}; const fd = (data?.financial_data as any) || {}; const ti = (data?.technical_indicators as any) || {}; const istrat = (data?.investment_strategy as any) || {}; const ds = React.useMemo(() => ((data?.debate_summary as any) || {}), [data]); const txt = React.useMemo(() => ((data?.text_content as any) || {}), [data]); const trends = ti?.trend_directions || {}; const fmt = (v: any, d = 0) => { const n = Number(v); if (v === null || v === undefined || Number.isNaN(n)) return '-'; return Number.isFinite(n) ? n.toFixed(d) : String(v); }; const fmtNumber = (v: any, d = 0) => { const n = Number(v); if (!Number.isFinite(n)) return '-'; return n.toLocaleString(undefined, { maximumFractionDigits: d, minimumFractionDigits: d }); }; const fmtCurrency = (v: any, d = 2) => { const n = Number(v); if (!Number.isFinite(n)) return '-'; return n.toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: d, minimumFractionDigits: d }); }; const fmtPercent = (v: any, d = 2) => { const n = Number(v); if (!Number.isFinite(n)) return '-'; return `${n.toFixed(d)}%`; }; const toneFromNumber = (v: any): 'pos' | 'neg' | 'neutral' => { const n = Number(v); if (!Number.isFinite(n)) return 'neutral'; if (n > 0) return 'pos'; if (n < 0) return 'neg'; return 'neutral'; }; const Stat: React.FC<{ label: string; value: React.ReactNode; sub?: React.ReactNode; tone?: 'pos' | 'neg' | 'neutral' }> = ({ label, value, sub, tone = 'neutral' }) => { const toneCls = tone === 'pos' ? 'text-green-600' : tone === 'neg' ? 'text-red-600' : 'text-gray-900'; const ringCls = tone === 'pos' ? 'ring-green-200' : tone === 'neg' ? 'ring-red-200' : 'ring-gray-200'; return (

{label}

{value}

{sub &&

{sub}

}
); }; const chip = (label: string, val?: string) => ( {label}: {val ?? '-'} ); // Tabs state and memoized content for text-heavy sections const debateTabs = React.useMemo(() => ([ { key: 'bull', label: 'Bull', content: Array.isArray(ds?.bull_key_points) ? ds.bull_key_points : [] as any[] }, { key: 'bear', label: 'Bear', content: Array.isArray(ds?.bear_key_points) ? ds.bear_key_points : [] as any[] }, { key: 'neutral', label: 'Neutral', content: ds?.neutral_perspective ? [ds.neutral_perspective] : [] as any[] }, { key: 'final', label: 'Final', content: ds?.final_decision_rationale ? [ds.final_decision_rationale] : [] as any[] }, ]), [ds]); const firstDebateWithContent = React.useMemo( () => debateTabs.find(t => (t.content?.length ?? 0) > 0)?.key || 'bull', [debateTabs] ); const [activeDebateTab, setActiveDebateTab] = React.useState(firstDebateWithContent); React.useEffect(() => { setActiveDebateTab(firstDebateWithContent); }, [firstDebateWithContent]); const reportTabsAll = React.useMemo(() => ([ { key: 'market', title: txt?.market_report?.title || 'Market Report', bullets: txt?.market_report?.key_takeaways, content: txt?.market_report?.content }, { key: 'sentiment', title: txt?.sentiment_report?.title || 'Sentiment Report', bullets: txt?.sentiment_report?.recent_developments, content: txt?.sentiment_report?.content }, { key: 'fundamentals', title: txt?.fundamentals_report?.title || 'Fundamentals Report', bullets: txt?.fundamentals_report?.financial_highlights, content: txt?.fundamentals_report?.content }, ]), [txt]); const availableReports = React.useMemo( () => reportTabsAll.filter(t => t.title || (Array.isArray(t.bullets) && t.bullets.length) || t.content), [reportTabsAll] ); const [activeReportTab, setActiveReportTab] = React.useState(availableReports[0]?.key || 'market'); React.useEffect(() => { setActiveReportTab(availableReports[0]?.key || 'market'); }, [availableReports]); return (
{/* Metadata - Full width */}

Company Information

{/* Two column layout for remaining sections */}
{/* Debate Summary with sub-tabs */}

Debate Summary

{debateTabs.map(t => ( ))}
{debateTabs.find(t => t.key === activeDebateTab)?.content?.length ? (
    {(debateTabs.find(t => t.key === activeDebateTab)?.content as any[]).map((c, i) =>
  • {c}
  • )}
) : (

No content.

)}
{/* Text Content with sub-tabs */}

Reports

{!availableReports.length ? (

No reports available.

) : (
{availableReports.map(t => ( ))}
{(() => { const activeTab = availableReports.find(t => t.key === activeReportTab); if (!activeTab) return null; return (
{Array.isArray(activeTab.bullets) && activeTab.bullets.length > 0 && (
    {activeTab.bullets.map((k: string, i: number) =>
  • {k}
  • )}
)} {activeTab.content && (

{activeTab.content}

)}
); })()}
)}
{/* Financial Data */}

Financial Data

{/* Technical Indicators */}

Technical Indicators

{chip('Trend SMA 50', trends?.sma_50)} {chip('Trend SMA 200', trends?.sma_200)} {trends?.ema_10 !== undefined && chip('Trend EMA 10', trends?.ema_10)} {trends?.price_action !== undefined && chip('Price', trends?.price_action)}
{/* Investment Strategy */}

Investment Strategy

(
  • {fmtCurrency(t?.target_price)} {t?.action && {t.action}} {t?.rationale && {t.rationale}}
  • ))} />
    ); }; // Render minimalist dashboard with all keys from the transformed JSON return ; }; export default TransformedDataAdapter; export type { TransformedAnalysisData, LegacyTradingAgentsResult };