diff --git a/dashboard/src/pages/meetKevin/Home.tsx b/dashboard/src/pages/meetKevin/Home.tsx index be1daa9..44e8b4c 100644 --- a/dashboard/src/pages/meetKevin/Home.tsx +++ b/dashboard/src/pages/meetKevin/Home.tsx @@ -118,12 +118,13 @@ export default function MeetKevinHome() { {video.outlook} )} - {video.top_tickers.slice(0, 5).map((ticker: string) => ( + {video.top_tickers.slice(0, 5).map((t) => ( - ${ticker} + {t.symbol} ))} diff --git a/dashboard/src/pages/meetKevin/Videos.tsx b/dashboard/src/pages/meetKevin/Videos.tsx index e11a508..45c0341 100644 --- a/dashboard/src/pages/meetKevin/Videos.tsx +++ b/dashboard/src/pages/meetKevin/Videos.tsx @@ -2,7 +2,7 @@ import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Link } from 'react-router-dom'; import meetKevinApi from '../../api/meetKevin'; -import type { VideoStatus } from '../../types/meetKevin'; +import type { MarketOutlook, TickerAction, VideoStatus } from '../../types/meetKevin'; const STATUS_OPTIONS: { value: VideoStatus | ''; label: string }[] = [ { value: '', label: 'All' }, @@ -19,6 +19,21 @@ function statusColor(status: VideoStatus): string { return 'text-yellow-300'; } +const ACTION_CHIP: Record = { + buy: 'bg-green-600/30 text-green-300 border-green-500/40', + sell: 'bg-red-600/30 text-red-300 border-red-500/40', + hold: 'bg-slate-600/30 text-slate-300 border-slate-500/40', + watch: 'bg-yellow-600/30 text-yellow-200 border-yellow-500/40', + avoid: 'bg-rose-600/40 text-rose-200 border-rose-500/40', +}; + +const OUTLOOK_PILL: Record = { + bullish: 'bg-green-600/20 text-green-300 border-green-500/40', + bearish: 'bg-red-600/20 text-red-300 border-red-500/40', + neutral: 'bg-slate-600/20 text-slate-300 border-slate-500/40', + mixed: 'bg-purple-600/20 text-purple-300 border-purple-500/40', +}; + export default function MeetKevinVideos() { const [status, setStatus] = useState(''); const [q, setQ] = useState(''); @@ -146,18 +161,38 @@ export default function MeetKevinVideos() {

)} + {video.outlook && ( +
+ + {video.outlook} + +
+ )} + {video.top_tickers.length > 0 && ( -
- {video.top_tickers.map((ticker) => ( +
+ {video.top_tickers.map((t) => ( - {ticker} + {t.symbol} + + {Math.round(t.conviction * 100)} + ))}
)} + + {video.one_line_summary && ( +

+ {video.one_line_summary} +

+ )}
))} diff --git a/dashboard/src/types/meetKevin.ts b/dashboard/src/types/meetKevin.ts index 8a67325..3c04ef4 100644 --- a/dashboard/src/types/meetKevin.ts +++ b/dashboard/src/types/meetKevin.ts @@ -14,6 +14,12 @@ export type VideoStatus = | 'failed' | 'skipped'; +export interface VideoTopTicker { + symbol: string; + action: TickerAction; + conviction: number; +} + export interface VideoSummary { id: number; youtube_video_id: string; @@ -23,7 +29,7 @@ export interface VideoSummary { thumbnail_url: string | null; status: VideoStatus; failure_reason: string | null; - top_tickers: string[]; + top_tickers: VideoTopTicker[]; outlook: MarketOutlook | null; one_line_summary: string | null; }