feat: revamp dashboard, trades, and add landing/legal pages

- Major UI updates across dashboard, analytics, posts, trades, settings
- New landing page, robots/sitemap, contact/privacy/terms pages
- Updated globals.css with extensive styling and new landing.css
- Refactor signedRequest, realtime data hook, and dashboard store

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
k
2026-04-25 16:04:57 +08:00
parent 83e5892ddf
commit 040e1df685
28 changed files with 4133 additions and 690 deletions
+10 -1
View File
@@ -16,9 +16,12 @@ interface Handlers {
export function usePriceSocket(handlers: Handlers) {
const wsRef = useRef<WebSocket | null>(null)
const handlersRef = useRef(handlers)
const unmountedRef = useRef(false)
const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
handlersRef.current = handlers
const connect = useCallback(() => {
if (unmountedRef.current) return
const ws = new WebSocket(`${WS_URL}/ws/prices`)
wsRef.current = ws
@@ -36,7 +39,10 @@ export function usePriceSocket(handlers: Handlers) {
}
ws.onclose = () => {
setTimeout(connect, 3000)
// Don't schedule a reconnect if the component already unmounted —
// otherwise we leak a socket per navigation forever.
if (unmountedRef.current) return
reconnectTimerRef.current = setTimeout(connect, 3000)
}
ws.onerror = () => {
@@ -45,8 +51,11 @@ export function usePriceSocket(handlers: Handlers) {
}, [])
useEffect(() => {
unmountedRef.current = false
connect()
return () => {
unmountedRef.current = true
if (reconnectTimerRef.current) clearTimeout(reconnectTimerRef.current)
wsRef.current?.close()
}
}, [connect])