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;
}