Files
trumpsignal-frontend/app/[locale]/trades/TradesPageClient.tsx
T
k f34ae9eb00 feat(macro-vibes): rename BTC Signal → Macro Vibes; add MacroPanel UI
Module rename across page H1, navbar tab, URL (/en/btc → /en/macro),
all metadata/JSON-LD, sitemap, llms.txt, opengraph image, and SystemControl
copy. Old /btc route fully removed.

New components/btc/MacroPanel.tsx polls /api/macro/snapshot and lays out
the 8 indicators in four sections (Valuation / Bottom trigger reference /
Market structure / Sentiment & flows / Positioning) with tone-coloured
values, current-band threshold chips, and a single CoinGlass / source
chart link per card. Composite -100..+100 needle pulses on score change.

Also fixes the pinned bottom-reversal alert on the homepage, which still
linked to the now-404 /en/btc — now routes to /en/macro.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 01:05:18 +08:00

121 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState, useEffect } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { useLocale } from 'next-intl'
import { useAccount, useSignMessage } from 'wagmi'
import type { BotTrade, TrumpPost } from '@/types'
import { getTrades, getPosts } from '@/lib/api'
import { useDashboardStore } from '@/store/dashboard'
import { getCachedViewEnvelope, getOrCreateViewEnvelope } from '@/lib/signedRequest'
import TradeTable from '@/components/trades/TradeTable'
import OpenPositions from '@/components/positions/OpenPositions'
import PageHint from '@/components/ui/PageHint'
export default function TradesPageClient() {
const intlLocale = useLocale()
const isZh = false // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json
const { address, isConnected } = useAccount()
const { signMessageAsync } = useSignMessage()
const { isSubscribed, hlApiKeySet } = useDashboardStore()
const pathname = usePathname()
const locale = pathname.split('/')[1] || 'en'
const [mounted, setMounted] = useState(false)
const [trades, setTrades] = useState<BotTrade[]>([])
const [posts, setPosts] = useState<TrumpPost[]>([])
const [loading, setLoading] = useState(true)
const [loadErr, setLoadErr] = useState('')
useEffect(() => { setMounted(true) }, [])
useEffect(() => {
let cancelled = false
if (!address || !isConnected) {
setTrades([])
setPosts([])
setLoading(false)
setLoadErr('')
return
}
setLoading(true)
;(async () => {
let failed = false
try {
const env = getCachedViewEnvelope('view_trades', address)
?? await getOrCreateViewEnvelope({ action: 'view_trades', wallet: address, signMessageAsync })
const [t, p] = await Promise.all([
getTrades(address, env, 100, 1).catch(e => {
failed = true
setLoadErr(e instanceof Error ? e.message : (isZh ? '交易加载失败' : 'Failed to load trades'))
return [] as BotTrade[]
}),
getPosts(500, 1).catch(() => [] as TrumpPost[]),
])
if (!cancelled) {
setTrades(t)
setPosts(p)
if (!failed) setLoadErr('')
}
} finally {
if (!cancelled) setLoading(false)
}
})()
return () => { cancelled = true }
}, [address, isConnected, signMessageAsync, isZh])
const needsSetup = mounted && isConnected && (!isSubscribed || !hlApiKeySet)
return (
<div className="page">
<div className="page-head">
<div>
<h1 className="page-title">{isZh ? '交易执行' : 'Trades'}</h1>
<PageHint>
What the bot actually did with your money currently-open positions
on top, closed-trade history with realized P&amp;L below.
</PageHint>
</div>
</div>
{needsSetup && (
<div className="card" style={{
padding: '14px 18px', marginBottom: 16,
background: 'var(--amber-soft)',
borderColor: 'color-mix(in oklab, var(--amber) 22%, var(--line))',
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
flexWrap: 'wrap', gap: 12,
}}>
<div>
<div style={{ fontSize: 13, fontWeight: 600 }}>{isZh ? '机器人尚未配置完成' : 'Bot not configured'}</div>
<div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 2 }}>
{isZh ? '在机器人开始交易前,请先去设置页订阅并绑定 Hyperliquid API。' : 'Subscribe and link your Hyperliquid API wallet on the Settings page before the bot can trade.'}
</div>
</div>
<Link
href={`/${locale}/settings`}
className="btn amber"
style={{ padding: '8px 16px', fontSize: 13, textDecoration: 'none' }}
>
{isZh ? '前往设置 →' : 'Go to Settings →'}
</Link>
</div>
)}
<OpenPositions />
{!loading && loadErr && (
<div className="card" style={{ padding: 16, margin: '12px 0', textAlign: 'center',
color: 'var(--down)', fontSize: 13 }}>
{isZh ? `无法加载交易历史:${loadErr}` : `Couldnt load trade history — ${loadErr}`}
<button className="btn ghost" style={{ fontSize: 12, padding: '5px 12px', marginLeft: 10 }}
onClick={() => location.reload()}>{isZh ? '重试' : 'Retry'}</button>
</div>
)}
<TradeTable trades={trades} posts={posts} loading={loading} />
</div>
)
}