({
mapped,
unmapped,
activeCategories,
onFlyTo,
onSelectMarket,
loading,
externalSearch,
isWatched,
onToggleWatch,
colSpan,
onColSpanChange,
onColSpanReset,
rowSpan,
onRowSpanChange,
onRowSpanReset,
maxColSpan,
selectedMarketId,
onTrade,
dragRootRef,
dragHandleProps,
dragStyle,
dragClassName,
}: MarketsPanelProps)
| 53 | const NEW_THRESHOLD_MS = 6 * 60 * 60 * 1000; |
| 54 | |
| 55 | function MarketsPanelInner({ |
| 56 | mapped, |
| 57 | unmapped, |
| 58 | activeCategories, |
| 59 | onFlyTo, |
| 60 | onSelectMarket, |
| 61 | loading, |
| 62 | externalSearch, |
| 63 | isWatched, |
| 64 | onToggleWatch, |
| 65 | colSpan, |
| 66 | onColSpanChange, |
| 67 | onColSpanReset, |
| 68 | rowSpan, |
| 69 | onRowSpanChange, |
| 70 | onRowSpanReset, |
| 71 | maxColSpan, |
| 72 | selectedMarketId, |
| 73 | onTrade, |
| 74 | dragRootRef, |
| 75 | dragHandleProps, |
| 76 | dragStyle, |
| 77 | dragClassName, |
| 78 | }: MarketsPanelProps) { |
| 79 | const { t, locale } = useI18n(); |
| 80 | const [search, setSearch] = useState(""); |
| 81 | const [renderNow] = useState(() => Date.now()); |
| 82 | const [localCategoryFilter, setLocalCategoryFilter] = useState<Set<string>>(new Set()); |
| 83 | const [localSortSet, setLocalSortSet] = useState<Set<string>>(new Set(["impact"])); |
| 84 | const sortHydrated = useRef(false); |
| 85 | useEffect(() => { |
| 86 | if (sortHydrated.current) return; |
| 87 | sortHydrated.current = true; |
| 88 | const saved = localStorage.getItem("pw:marketSort"); |
| 89 | if (saved && ["sections", "volume", "impact", "change", "new"].includes(saved)) { |
| 90 | setLocalSortSet(new Set([saved])); |
| 91 | } |
| 92 | }, []); |
| 93 | |
| 94 | // Sync external search (e.g. tag click from detail panel) |
| 95 | useEffect(() => { |
| 96 | if (externalSearch === undefined) return; |
| 97 | const timer = window.setTimeout(() => { |
| 98 | setSearch(externalSearch); |
| 99 | }, 0); |
| 100 | return () => window.clearTimeout(timer); |
| 101 | }, [externalSearch]); |
| 102 | const [expanded, setExpanded] = useState(false); |
| 103 | |
| 104 | useEffect(() => { |
| 105 | if (!expanded) return; |
| 106 | const handler = (e: KeyboardEvent) => { |
| 107 | if (e.key === "Escape") setExpanded(false); |
| 108 | }; |
| 109 | document.addEventListener("keydown", handler); |
| 110 | return () => document.removeEventListener("keydown", handler); |
| 111 | }, [expanded]); |
| 112 |
nothing calls this directly
no test coverage detected