import { useGameStore } from '@/store'; import { formatNumber, formatPercent } from '@token-empire/shared'; import type { TAMSegmentId } from '@token-empire/shared'; import { Globe, TrendingUp, Clock, Thermometer } from 'lucide-react'; const SEGMENT_LABELS: Record = { consumer: 'Consumer', developer: 'Developer', enterprise: 'Enterprise', government: 'Government', }; const SEGMENT_COLORS: Record = { consumer: 'bg-orange-500', developer: 'bg-blue-500', enterprise: 'bg-purple-500', government: 'bg-green-500', }; const SEASON_LABELS: Record = { q1: 'Q1 — Slow Start', q2: 'Q2 — Baseline', q3: 'Q3 — Summer Dip', q4: 'Q4 — Budget Surge', }; export function MarketOverviewPanel() { const tam = useGameStore((s) => s.market.tam); const seasonalPhase = useGameStore((s) => s.market.seasonalPhase); const seasonalMultiplier = useGameStore((s) => s.market.seasonalMultiplier); const obsolescence = useGameStore((s) => s.market.obsolescence); const bestScore = useGameStore((s) => s.models.bestDeployedModelScore); const competitors = useGameStore((s) => s.competitors.rivals); const segments = Object.entries(tam.segments) as [TAMSegmentId, typeof tam.segments.consumer][]; return (
Market Share by Segment
{segments.map(([id, seg]) => { const playerShare = seg.shares.find(s => s.playerId === 'player'); const share = playerShare?.sharePercent ?? 0; return (
{SEGMENT_LABELS[id]} {formatPercent(share)} · {formatNumber(playerShare?.customers ?? 0)} customers
{seg.shares .filter(s => s.sharePercent > 0.001) .sort((a, b) => b.sharePercent - a.sharePercent) .map((s, i) => (
))}
); })}
Season
{SEASON_LABELS[seasonalPhase] ?? seasonalPhase}
Demand multiplier: {formatPercent(seasonalMultiplier)}
Technology Pressure
Market Quality Baseline {(obsolescence.marketQualityBaseline * 100).toFixed(1)}
Your Best Model {bestScore.toFixed(1)}
Model Freshness {formatPercent(obsolescence.playerModelFreshness)}
{obsolescence.newModelBoostRemaining > 0 && (
New model boost active!
)} {bestScore / 100 < obsolescence.marketQualityBaseline && (
Below market baseline — losing attractiveness
)}
Competitive Landscape
{competitors.filter(r => r.status === 'active').map(r => ( ))}
Competitor Consumer Developer Enterprise Freshness Dev Eco
You {formatPercent(tam.segments.consumer.shares.find(s => s.playerId === 'player')?.sharePercent ?? 0)} {formatPercent(tam.segments.developer.shares.find(s => s.playerId === 'player')?.sharePercent ?? 0)} {formatPercent(tam.segments.enterprise.shares.find(s => s.playerId === 'player')?.sharePercent ?? 0)} {formatPercent(obsolescence.playerModelFreshness)}
{r.name} {formatPercent(r.marketShares.consumer)} {formatPercent(r.marketShares.developer)} {formatPercent(r.marketShares.enterprise)} {formatPercent(r.modelFreshness)} {r.developerEcosystemScore.toFixed(0)}
); }