"use client"; import { useState, useEffect, useCallback } from "react"; import { useActiveSymbol } from "@/stores/active-symbol-store"; import { api } from "@/lib/trpc"; import { UI_STRINGS } from "@/lib/strings"; /** * Persistent top bar showing the active symbol, price, change, and search. * This is the "central nervous system" — switching symbols updates everything globally. */ export function SymbolHeader() { const symbol = useActiveSymbol((s) => s.activeSymbol); const setActive = useActiveSymbol((s) => s.setActive); const [draft, setDraft] = useState(symbol); const [showSearch, setShowSearch] = useState(false); const [snap, setSnap] = useState | null>(null); // Fetch current price for display useEffect(() => { const sym = draft || symbol; api.market.snapshot(sym).then(setSnap).catch(() => {}); }, [draft, symbol]); const quote = snap?.quote ?? null; const sector = snap?.sector ?? null; const up = (quote?.change ?? 0) >= 0; const priceLabel = quote ? `$${quote.price?.toFixed(2)}` : ""; const changeLabel = quote && quote.change !== undefined ? `${up ? "▲" : "▼"}${up ? "+" : ""}${quote.change.toFixed(2)} (${up ? "+" : ""}${(quote.changePercent ?? 0).toFixed(2)}%)` : ""; const sectorLabel = sector ? `${sector.sector} · ${sector.tickerKind}` : ""; const handleSubmit = useCallback((e: React.FormEvent) => { e.preventDefault(); const sym = draft.trim().toUpperCase() || symbol; setActive(sym); setShowSearch(false); }, [draft, symbol, setActive]); // Keyboard shortcut: Ctrl+K to toggle search useEffect(() => { const handler = (e: KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); setShowSearch(prev => !prev); } if (e.key === "Escape" && showSearch) { setShowSearch(false); } }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [showSearch]); // Sync draft when active symbol changes externally useEffect(() => { setDraft(symbol); }, [symbol]); return (
{/* Left: Logo mark */}
IF

Investor Flow

{/* Right: Ticker info + Search grouped together */}
{/* Active symbol — compact, next to search */}
{symbol} {priceLabel && ( {priceLabel} )} {changeLabel && ( {changeLabel} )}
{/* Mobile: just ticker */}
{symbol} {priceLabel && ( {priceLabel} )}
{/* Search */}
setDraft(e.target.value)} onFocus={() => setShowSearch(true)} onBlur={() => setTimeout(() => setShowSearch(false), 200)} placeholder="Search…" className="w-full bg-[#1a1b24] border border-[#2a2b3a] rounded-lg px-3 py-1.5 text-xs text-[#e6e7ec] placeholder:text-[#5a5b6a] focus:outline-none focus:border-[#4f8cff] focus:ring-1 focus:ring-[#4f8cff]" /> ⌘K
); }