fix: pre-launch UI hardening + KOL reduce-action type, proxy IP relay, settings redesign
Frontend half of the pre-launch audit campaign: - types/index.ts + kol/KolPageClient.tsx: add missing 'reduce' KolAction (backend emits it; frontend lacked the type + color/label maps → undefined styling). Adds ACTION_COLOR/actionLabel/postActionLabel entries. - proxy/[...path]/route.ts: relay real client IP (x-forwarded-for / x-real-ip) so the backend rate limiter buckets per-user instead of per-Next-server (BUG-02). - Settings/BotConfigPanel redesign, paper-mode clarity, copy cleanup. - Assorted page/display fixes, loading states, Pagination component. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import type {
|
||||
import { getKolPosts, getKolPost, getKolDigest, getKolChanges, getKolDivergence } from '@/lib/api'
|
||||
import { swrFetch } from '@/lib/cache'
|
||||
import PageHint from '@/components/ui/PageHint'
|
||||
import Pagination from '@/components/ui/Pagination'
|
||||
|
||||
/**
|
||||
* KOL feed — independent module. Lists analyzed posts from tracked KOLs
|
||||
@@ -22,6 +23,7 @@ const ACTION_COLOR: Record<KolTicker['action'], string> = {
|
||||
bullish: '#16a34a',
|
||||
sell: '#dc2626',
|
||||
bearish: '#dc2626',
|
||||
reduce: '#f59e0b',
|
||||
mention: '#9ca3af',
|
||||
}
|
||||
|
||||
@@ -31,6 +33,7 @@ function actionLabel(action: KolTicker['action'], isZh: boolean) {
|
||||
const labels: Record<KolTicker['action'], string> = {
|
||||
buy: 'BUY',
|
||||
sell: 'SELL',
|
||||
reduce: 'Reduce',
|
||||
bullish: 'Bullish',
|
||||
bearish: 'Bearish',
|
||||
mention: 'Mention',
|
||||
@@ -78,6 +81,7 @@ function postActionLabel(action: string, isZh: boolean) {
|
||||
const labels: Record<string, string> = {
|
||||
buy: 'BUY',
|
||||
sell: 'SELL',
|
||||
reduce: 'Reducing',
|
||||
bullish: 'Bullish post',
|
||||
bearish: 'Bearish post',
|
||||
}
|
||||
@@ -780,12 +784,14 @@ export default function KolPage({
|
||||
const locale = useLocale()
|
||||
const isZh = false // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json
|
||||
const dateLocale = isZh ? 'zh-CN' : 'en-US'
|
||||
const KOL_PAGE_SIZE = 20
|
||||
const [posts, setPosts] = useState<KolPostSummary[]>(initialPosts ?? [])
|
||||
const [loading, setLoading] = useState(initialPosts === null)
|
||||
const [err, setErr] = useState('')
|
||||
const [openPost, setOpenPost] = useState<KolPostDetail | null>(null)
|
||||
const [handleFilter, setHandleFilter] = useState<string>('all')
|
||||
const [tickerFilter, setTickerFilter] = useState<string | null>(null)
|
||||
const [kolPage, setKolPage] = useState(1)
|
||||
|
||||
useEffect(() => {
|
||||
swrFetch(
|
||||
@@ -812,6 +818,10 @@ export default function KolPage({
|
||||
return out
|
||||
}, [posts, handleFilter, tickerFilter])
|
||||
|
||||
const kolTotalPages = Math.max(1, Math.ceil(filtered.length / KOL_PAGE_SIZE))
|
||||
const kolSafePage = Math.min(kolPage, kolTotalPages)
|
||||
const kolPageItems = filtered.slice((kolSafePage - 1) * KOL_PAGE_SIZE, kolSafePage * KOL_PAGE_SIZE)
|
||||
|
||||
async function openDetail(id: number) {
|
||||
try {
|
||||
const detail = await getKolPost(id)
|
||||
@@ -837,8 +847,10 @@ export default function KolPage({
|
||||
isZh={isZh}
|
||||
initialDigest={initialDigest}
|
||||
activeTicker={tickerFilter}
|
||||
onTickerClick={(sym) =>
|
||||
setTickerFilter(prev => prev === sym ? null : sym)}
|
||||
onTickerClick={(sym) => {
|
||||
setTickerFilter(prev => prev === sym ? null : sym)
|
||||
setKolPage(1)
|
||||
}}
|
||||
/>
|
||||
|
||||
<WalletCheckWidget
|
||||
@@ -858,7 +870,7 @@ export default function KolPage({
|
||||
<span style={{ color: 'var(--ink-3)' }}>{isZh ? '当前筛选标的:' : 'Filtered asset:'}</span>
|
||||
<strong>{tickerFilter}</strong>
|
||||
<button
|
||||
onClick={() => setTickerFilter(null)}
|
||||
onClick={() => { setTickerFilter(null); setKolPage(1) }}
|
||||
style={{
|
||||
background: 'var(--bg-sunk)', border: '1px solid var(--line)',
|
||||
borderRadius: 4, padding: '2px 8px',
|
||||
@@ -873,7 +885,7 @@ export default function KolPage({
|
||||
{handles.map(h => (
|
||||
<button
|
||||
key={h}
|
||||
onClick={() => setHandleFilter(h)}
|
||||
onClick={() => { setHandleFilter(h); setKolPage(1) }}
|
||||
className={`nav-tab ${handleFilter === h ? 'active' : ''}`}
|
||||
style={{ border: 'none', cursor: 'pointer' }}
|
||||
>
|
||||
@@ -895,7 +907,7 @@ export default function KolPage({
|
||||
: 'No data yet. Wait for the next feed ingestion run (daily 01:15 UTC).'}
|
||||
</div>
|
||||
)}
|
||||
{filtered.map(p => (
|
||||
{kolPageItems.map(p => (
|
||||
<div
|
||||
key={p.id}
|
||||
onClick={() => openDetail(p.id)}
|
||||
@@ -954,6 +966,15 @@ export default function KolPage({
|
||||
<TickerChips tickers={p.tickers} isZh={isZh} />
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Pagination
|
||||
page={kolSafePage}
|
||||
total={kolTotalPages}
|
||||
count={filtered.length}
|
||||
pageSize={KOL_PAGE_SIZE}
|
||||
onChange={setKolPage}
|
||||
scrollTop={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user