fix(dashboard): Strategy LAST SEEN = 'Invalid Date' contract drift
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
API GET /api/meet-kevin/strategy/tickers returns the field as latest_mention_at, but the dashboard's StrategyTicker type + table read t.last_mention_at — so new Date(undefined) produced 'Invalid Date' in every row. Aligned StrategyTicker to the actual API shape and renamed the table accessor. Also dropped two columns that referenced fields the API never returned (mention_count, unrealized_pnl_pct, current_price) and replaced them with what IS in the response (Horizon column + trade_entry_price renamed 'Entry'). t.is_held -> t.has_open_trade.
This commit is contained in:
parent
5fce576e33
commit
00a40c9d2f
2 changed files with 15 additions and 26 deletions
|
|
@ -50,17 +50,14 @@ export function TickerScorecardTable({ tickers, isLoading, onClose }: Props) {
|
|||
Conviction
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs text-slate-400 uppercase tracking-wide font-semibold">
|
||||
Price
|
||||
Horizon
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs text-slate-400 uppercase tracking-wide font-semibold">
|
||||
P&L
|
||||
Entry
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs text-slate-400 uppercase tracking-wide font-semibold">
|
||||
Status
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs text-slate-400 uppercase tracking-wide font-semibold">
|
||||
Mentions
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs text-slate-400 uppercase tracking-wide font-semibold">
|
||||
Last seen
|
||||
</th>
|
||||
|
|
@ -70,12 +67,11 @@ export function TickerScorecardTable({ tickers, isLoading, onClose }: Props) {
|
|||
<tbody className="divide-y divide-slate-700">
|
||||
{tickers.map((t) => {
|
||||
const badge = t.bridge_status ? BRIDGE_BADGE[t.bridge_status] : null;
|
||||
const pnl = t.unrealized_pnl_pct;
|
||||
return (
|
||||
<tr key={t.symbol} className="hover:bg-slate-700/30 transition-colors">
|
||||
<td className="px-5 py-3.5">
|
||||
<span className="font-mono font-bold text-white">${t.symbol}</span>
|
||||
{t.is_held && (
|
||||
{t.has_open_trade && (
|
||||
<span className="ml-2 px-1.5 py-0.5 text-xs bg-green-600/20 text-green-400 border border-green-500/30 rounded">
|
||||
HOLDING
|
||||
</span>
|
||||
|
|
@ -94,20 +90,12 @@ export function TickerScorecardTable({ tickers, isLoading, onClose }: Props) {
|
|||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-5 py-3.5 text-slate-400">{t.latest_horizon}</td>
|
||||
<td className="px-5 py-3.5 text-slate-300 font-mono">
|
||||
{t.current_price != null
|
||||
? `$${t.current_price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
||||
{t.trade_entry_price != null
|
||||
? `$${t.trade_entry_price.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
||||
: '—'}
|
||||
</td>
|
||||
<td className="px-5 py-3.5 font-mono">
|
||||
{pnl != null ? (
|
||||
<span className={pnl >= 0 ? 'text-green-400' : 'text-red-400'}>
|
||||
{pnl >= 0 ? '+' : ''}{pnl.toFixed(2)}%
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-slate-500">—</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-5 py-3.5">
|
||||
{badge ? (
|
||||
<span className={`px-2 py-0.5 text-xs font-semibold uppercase rounded-md border ${badge.cls}`}>
|
||||
|
|
@ -117,12 +105,13 @@ export function TickerScorecardTable({ tickers, isLoading, onClose }: Props) {
|
|||
<span className="text-slate-500">—</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-5 py-3.5 text-slate-300">{t.mention_count}</td>
|
||||
<td className="px-5 py-3.5 text-slate-400">
|
||||
{new Date(t.last_mention_at).toLocaleDateString()}
|
||||
{t.latest_mention_at
|
||||
? new Date(t.latest_mention_at).toLocaleDateString()
|
||||
: '—'}
|
||||
</td>
|
||||
<td className="px-5 py-3.5">
|
||||
{t.is_held && (
|
||||
{t.has_open_trade && (
|
||||
<button
|
||||
onClick={() => onClose(t.symbol)}
|
||||
className="px-2.5 py-1 text-xs bg-red-600/20 hover:bg-red-600/40 text-red-300 border border-red-500/30 rounded transition-colors"
|
||||
|
|
|
|||
|
|
@ -182,12 +182,12 @@ export interface StrategyTicker {
|
|||
symbol: string;
|
||||
latest_action: TickerAction;
|
||||
latest_conviction: number;
|
||||
mention_count: number;
|
||||
last_mention_at: string;
|
||||
latest_horizon: TimeHorizon;
|
||||
latest_mention_at: string | null;
|
||||
bridge_status: BridgeStatus | null;
|
||||
is_held: boolean;
|
||||
current_price: number | null;
|
||||
unrealized_pnl_pct: number | null;
|
||||
effective_conviction: number | null;
|
||||
has_open_trade: boolean;
|
||||
trade_entry_price: number | null;
|
||||
}
|
||||
|
||||
export interface EquityCurvePoint {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue