spb/vquant Public MIT
VibeQuant — AI-powered institutional-grade financial intelligence platform.
TypeScript 84.3%
Python 11.7%
JavaScript 1.6%
CSS 1.5%
HTML 0.7%
1/*2 * =============================================================================3 * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4 * -----------------------------------------------------------------------------5 * File: client/src/pages/showcase.tsx6 *7 * Author: Simon-Pierre Boucher8 * Contact: contact@spboucher.ai9 * Website: https://www.spboucher.ai10 * Demo: https://www.vquant.ai11 * License: MIT (see LICENSE)12 *13 * Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14 * =============================================================================15 */1617import { useState } from "react";18import { useQuery } from "@tanstack/react-query";19import { useLocation } from "wouter";20import { Sparkles, Search, ArrowLeft, Users, TrendingUp, Filter } from "lucide-react";21import { ThemeToggle } from "@/components/theme-toggle";22import { ThemeColorPicker } from "@/components/theme-color-picker";23import { Button } from "@/components/ui/button";24import { Input } from "@/components/ui/input";25import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";26import { Badge } from "@/components/ui/badge";27import { formatDistanceToNow } from "date-fns";28import { fr } from "date-fns/locale";2930interface SharedReport {31 id: number;32 shareId: string;33 question: string;34 answer: string;35 toolResults: any[];36 createdAt: string;37}3839export default function Showcase() {40 const [, setLocation] = useLocation();41 const [searchQuery, setSearchQuery] = useState("");42 const [toolFilter, setToolFilter] = useState<string | null>(null);4344 // Fetch all shared reports45 const { data: reports, isLoading } = useQuery<SharedReport[]>({46 queryKey: ["/api/shared-reports"],47 refetchInterval: 30000, // Refresh every 30 seconds48 });4950 // Extract unique tools used across all reports51 const allTools = new Set<string>();52 reports?.forEach(report => {53 report.toolResults?.forEach((tr: any) => {54 allTools.add(tr.tool);55 });56 });5758 // Filter reports based on search query and tool filter59 const filteredReports = reports?.filter(report => {60 const matchesSearch = searchQuery === "" ||61 report.question.toLowerCase().includes(searchQuery.toLowerCase()) ||62 report.answer.toLowerCase().includes(searchQuery.toLowerCase());6364 const matchesTool = !toolFilter || report.toolResults?.some((tr: any) => tr.tool === toolFilter);6566 return matchesSearch && matchesTool;67 });6869 // Complete tool metadata mapping for distinct badges70 const TOOL_METADATA: Record<string, { name: string; color: string }> = {71 // Fundamental Analysis72 get_company_profile: { name: 'Company Profile', color: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20' },73 get_income_statement: { name: 'Income Statement', color: 'bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border-indigo-500/20' },74 get_balance_sheet: { name: 'Balance Sheet', color: 'bg-violet-500/10 text-violet-600 dark:text-violet-400 border-violet-500/20' },75 get_cash_flow: { name: 'Cash Flow', color: 'bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20' },76 get_key_metrics: { name: 'Key Metrics', color: 'bg-sky-500/10 text-sky-600 dark:text-sky-400 border-sky-500/20' },77 get_financial_ratios: { name: 'Financial Ratios', color: 'bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 border-cyan-500/20' },78 get_financial_growth: { name: 'Financial Growth', color: 'bg-teal-500/10 text-teal-600 dark:text-teal-400 border-teal-500/20' },7980 // Market Data81 get_stock_quote: { name: 'Stock Quote', color: 'bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20' },82 get_historical_price: { name: 'Historical Prices', color: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/20' },83 get_intraday_price: { name: 'Intraday Prices', color: 'bg-lime-500/10 text-lime-600 dark:text-lime-400 border-lime-500/20' },8485 // Technical Indicators86 get_rsi: { name: 'RSI', color: 'bg-cyan-600/10 text-cyan-700 dark:text-cyan-300 border-cyan-600/20' },87 get_macd: { name: 'MACD', color: 'bg-blue-600/10 text-blue-700 dark:text-blue-300 border-blue-600/20' },88 get_ema: { name: 'EMA', color: 'bg-indigo-600/10 text-indigo-700 dark:text-indigo-300 border-indigo-600/20' },89 get_sma: { name: 'SMA', color: 'bg-violet-600/10 text-violet-700 dark:text-violet-300 border-violet-600/20' },90 get_adx: { name: 'ADX', color: 'bg-purple-600/10 text-purple-700 dark:text-purple-300 border-purple-600/20' },91 get_williams_r: { name: 'Williams %R', color: 'bg-fuchsia-500/10 text-fuchsia-600 dark:text-fuchsia-400 border-fuchsia-500/20' },92 get_cci: { name: 'CCI', color: 'bg-pink-500/10 text-pink-600 dark:text-pink-400 border-pink-500/20' },93 get_stochastic: { name: 'Stochastic', color: 'bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-500/20' },9495 // News & Events96 get_financial_news: { name: 'Financial News', color: 'bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20' },97 get_press_releases: { name: 'Press Releases', color: 'bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20' },98 get_stock_news_sentiment: { name: 'News Sentiment', color: 'bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 border-yellow-500/20' },99100 // Calendar & Events101 get_economic_calendar: { name: 'Economic Calendar', color: 'bg-slate-500/10 text-slate-600 dark:text-slate-400 border-slate-500/20' },102 get_earnings_calendar: { name: 'Earnings Calendar', color: 'bg-gray-500/10 text-gray-600 dark:text-gray-400 border-gray-500/20' },103 get_ipo_calendar: { name: 'IPO Calendar', color: 'bg-zinc-500/10 text-zinc-600 dark:text-zinc-400 border-zinc-500/20' },104105 // Trading Activity106 get_insider_trading: { name: 'Insider Trading', color: 'bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20' },107 get_congressional_trading: { name: 'Congressional Trading', color: 'bg-red-600/10 text-red-700 dark:text-red-300 border-red-600/20' },108 get_senate_trading: { name: 'Senate Trading', color: 'bg-rose-600/10 text-rose-700 dark:text-rose-300 border-rose-600/20' },109 get_institutional_holders: { name: 'Institutional Holders', color: 'bg-pink-600/10 text-pink-700 dark:text-pink-300 border-pink-600/20' },110111 // Forex & Commodities112 get_forex_quote: { name: 'Forex Quote', color: 'bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 border-cyan-500/20' },113 get_forex_historical: { name: 'Forex Historical', color: 'bg-teal-600/10 text-teal-700 dark:text-teal-300 border-teal-600/20' },114 get_commodity_quotes: { name: 'Commodity Prices', color: 'bg-amber-600/10 text-amber-700 dark:text-amber-300 border-amber-600/20' },115116 // Macro & Rates117 get_treasury_rates: { name: 'Treasury Rates', color: 'bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border-indigo-500/20' },118 get_economic_indicator: { name: 'Economic Indicator', color: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20' },119120 // Analyst & Estimates121 get_analyst_estimates: { name: 'Analyst Estimates', color: 'bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20' },122 get_earnings_surprises: { name: 'Earnings Surprises', color: 'bg-violet-500/10 text-violet-600 dark:text-violet-400 border-violet-500/20' },123 get_price_target: { name: 'Price Targets', color: 'bg-fuchsia-600/10 text-fuchsia-700 dark:text-fuchsia-300 border-fuchsia-600/20' },124 get_price_target_summary: { name: 'Price Target Summary', color: 'bg-pink-500/10 text-pink-600 dark:text-pink-400 border-pink-500/20' },125 get_upgrades_downgrades: { name: 'Upgrades/Downgrades', color: 'bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-500/20' },126127 // Dividends & Splits128 get_dividend_history: { name: 'Dividend History', color: 'bg-green-600/10 text-green-700 dark:text-green-300 border-green-600/20' },129 get_stock_split_history: { name: 'Stock Splits', color: 'bg-emerald-600/10 text-emerald-700 dark:text-emerald-300 border-emerald-600/20' },130131 // SEC & Filings132 get_sec_filings: { name: 'SEC Filings', color: 'bg-gray-600/10 text-gray-700 dark:text-gray-300 border-gray-600/20' },133 get_cot_report: { name: 'COT Report', color: 'bg-slate-600/10 text-slate-700 dark:text-slate-300 border-slate-600/20' },134135 // ESG136 get_esg_score: { name: 'ESG Score', color: 'bg-lime-600/10 text-lime-700 dark:text-lime-300 border-lime-600/20' },137138 // Screening & Search139 get_stock_screener: { name: 'Stock Screener', color: 'bg-orange-600/10 text-orange-700 dark:text-orange-300 border-orange-600/20' },140 search_companies: { name: 'Company Search', color: 'bg-teal-500/10 text-teal-600 dark:text-teal-400 border-teal-500/20' },141 get_stock_peers: { name: 'Peer Companies', color: 'bg-sky-600/10 text-sky-700 dark:text-sky-300 border-sky-600/20' },142143 // ETF144 get_etf_holdings: { name: 'ETF Holdings', color: 'bg-cyan-600/10 text-cyan-700 dark:text-cyan-300 border-cyan-600/20' },145 get_etf_sector_weightings: { name: 'ETF Sectors', color: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20' },146 get_etf_country_weightings: { name: 'ETF Countries', color: 'bg-indigo-600/10 text-indigo-700 dark:text-indigo-300 border-indigo-600/20' },147148 // Crypto149 get_crypto_quote: { name: 'Crypto Quote', color: 'bg-yellow-600/10 text-yellow-700 dark:text-yellow-300 border-yellow-600/20' },150 get_crypto_list: { name: 'Crypto List', color: 'bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20' },151152 // Advanced Analysis153 run_monte_carlo_simulation: { name: 'Monte Carlo Simulation', color: 'bg-purple-600/10 text-purple-700 dark:text-purple-300 border-purple-600/20' },154 calculate_options_price: { name: 'Options Pricing', color: 'bg-blue-600/10 text-blue-700 dark:text-blue-300 border-blue-600/20' },155 estimate_garch_volatility: { name: 'GARCH Volatility', color: 'bg-amber-600/10 text-amber-700 dark:text-amber-300 border-amber-600/20' },156 calculate_var: { name: 'Value at Risk', color: 'bg-red-600/10 text-red-700 dark:text-red-300 border-red-600/20' },157 optimize_portfolio: { name: 'Portfolio Optimization', color: 'bg-green-600/10 text-green-700 dark:text-green-300 border-green-600/20' },158 analyze_risk_metrics: { name: 'Risk Metrics', color: 'bg-orange-600/10 text-orange-700 dark:text-orange-300 border-orange-600/20' },159160 // Research161 web_search_exa: { name: 'Web Search', color: 'bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/20' },162163 // Market Hours & Misc164 get_market_hours: { name: 'Market Hours', color: 'bg-slate-500/10 text-slate-600 dark:text-slate-400 border-slate-500/20' },165 get_company_outlook: { name: 'Company Outlook', color: 'bg-violet-600/10 text-violet-700 dark:text-violet-300 border-violet-600/20' },166 get_social_sentiment: { name: 'Social Sentiment', color: 'bg-pink-500/10 text-pink-600 dark:text-pink-400 border-pink-500/20' },167168 // Data Downloads & Plots169 create_plot: { name: 'Custom Plot', color: 'bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 border-indigo-500/20' },170 download_fmp_data: { name: 'Data Download', color: 'bg-sky-500/10 text-sky-600 dark:text-sky-400 border-sky-500/20' },171 };172173 // Get tool metadata with fallback174 const getToolMetadata = (toolName: string) => {175 return TOOL_METADATA[toolName] || {176 name: toolName.replace(/_/g, ' ').replace(/^get /, ''),177 color: 'bg-gray-500/10 text-gray-600 dark:text-gray-400 border-gray-500/20'178 };179 };180181 return (182 <div className="min-h-screen bg-background relative overflow-hidden" data-testid="page-showcase">183 {/* Subtle Background */}184 <div className="fixed inset-0 z-0 pointer-events-none">185 <div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,hsl(var(--primary)/0.03),transparent_70%)]" />186 </div>187188 {/* Header */}189 <header className="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur-sm">190 <div className="container flex h-14 items-center justify-between px-6">191 <div className="flex items-center gap-4">192 <Button193 variant="ghost"194 size="sm"195 onClick={() => setLocation('/')}196 className="hover:bg-muted transition-colors gap-2"197 >198 <ArrowLeft className="w-4 h-4" />199 <span className="hidden sm:inline font-medium">Retour</span>200 </Button>201 <button202 onClick={() => setLocation('/')}203 className="flex items-center gap-2.5"204 >205 <Sparkles className="w-5 h-5 text-primary" />206 <div className="hidden md:flex items-baseline gap-1.5">207 <span className="text-base font-bold text-foreground leading-tight">208 VQuant209 </span>210 </div>211 </button>212 </div>213 <div className="flex items-center gap-3">214 <div className="h-8 w-px bg-border/50" />215 <ThemeColorPicker />216 <ThemeToggle />217 </div>218 </div>219 </header>220221 {/* Main Content */}222 <main className="container mx-auto px-4 py-8 max-w-7xl relative z-10">223 {/* Page Header */}224 <div className="mb-10 space-y-6">225 <div className="flex items-center gap-4">226 <div className="p-3 rounded-lg bg-primary/10 border border-primary/20">227 <Users className="w-6 h-6 text-primary" />228 </div>229 <div>230 <h1 className="text-3xl font-bold text-foreground tracking-tight">231 Showcase Communautaire232 </h1>233 <p className="text-muted-foreground text-base mt-1">234 Découvrez toutes les analyses générées par la communauté VQuant235 </p>236 </div>237 </div>238239 {/* Search and Filter Bar */}240 <div className="flex flex-col sm:flex-row gap-4">241 <div className="relative flex-1">242 <Input243 type="text"244 placeholder="Rechercher des analyses..."245 value={searchQuery}246 onChange={(e) => setSearchQuery(e.target.value)}247 className="pl-12 pr-4 h-11 border border-border focus:border-primary bg-card text-base transition-colors"248 />249 <Search className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />250 </div>251 {toolFilter && (252 <Button253 variant="outline"254 size="lg"255 onClick={() => setToolFilter(null)}256 className="gap-2 hover:bg-muted transition-colors"257 >258 <Filter className="w-4 h-4" />259 Effacer filtre260 </Button>261 )}262 </div>263264 {/* Stats */}265 {reports && (266 <div className="flex items-center gap-6 text-sm text-muted-foreground">267 <div className="flex items-center gap-2">268 <TrendingUp className="w-4 h-4" />269 <span>{reports.length} analyses publiques</span>270 </div>271 <div className="flex items-center gap-2">272 <Users className="w-4 h-4" />273 <span>{allTools.size} outils utilisés</span>274 </div>275 </div>276 )}277 </div>278279 {/* Loading State */}280 {isLoading && (281 <div className="text-center py-12">282 <div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>283 <p className="text-muted-foreground mt-4">Chargement des analyses...</p>284 </div>285 )}286287 {/* Reports Grid */}288 {filteredReports && filteredReports.length > 0 && (289 <div className="grid md:grid-cols-2 gap-8">290 {filteredReports.map((report) => (291 <Card292 key={report.id}293 className="group cursor-pointer border border-border hover:border-primary/40 transition-colors bg-card"294 onClick={() => setLocation(`/share/${report.shareId}`)}295 >296 <CardHeader className="pb-4">297 <div className="flex items-start justify-between gap-3">298 <CardTitle className="text-lg font-bold line-clamp-2 group-hover:text-primary transition-colors">299 {report.question}300 </CardTitle>301 </div>302 <div className="flex items-center gap-2 mt-2">303 <div className="w-1.5 h-1.5 rounded-full bg-primary" />304 <p className="text-xs text-muted-foreground font-medium">305 {formatDistanceToNow(new Date(report.createdAt), {306 addSuffix: true,307 locale: fr308 })}309 </p>310 </div>311 </CardHeader>312 <CardContent className="space-y-4">313 {/* Answer Preview */}314 <p className="text-sm text-muted-foreground line-clamp-3 leading-relaxed">315 {report.answer}316 </p>317318 {/* Tools Used */}319 {report.toolResults && report.toolResults.length > 0 && (320 <div className="flex flex-wrap gap-2">321 {Array.from(new Set(report.toolResults.map((tr: any) => tr.tool))).map((tool: any) => {322 const toolMeta = getToolMetadata(tool);323 return (324 <Badge325 key={tool}326 variant="outline"327 className={`text-xs font-medium px-2.5 py-0.5 ${toolMeta.color} cursor-pointer transition-colors`}328 onClick={(e) => {329 e.stopPropagation();330 setToolFilter(tool);331 }}332 >333 {toolMeta.name}334 </Badge>335 );336 })}337 </div>338 )}339 </CardContent>340 </Card>341 ))}342 </div>343 )}344345 {/* Empty State */}346 {filteredReports && filteredReports.length === 0 && !isLoading && (347 <Card className="text-center py-12">348 <CardContent>349 <Search className="w-12 h-12 mx-auto text-muted-foreground mb-4" />350 <h3 className="text-lg font-semibold mb-2">Aucune analyse trouvée</h3>351 <p className="text-muted-foreground mb-4">352 {searchQuery || toolFilter353 ? "Essayez de modifier vos critères de recherche"354 : "Aucune analyse n'a été partagée pour le moment"}355 </p>356 {(searchQuery || toolFilter) && (357 <Button358 variant="outline"359 onClick={() => {360 setSearchQuery("");361 setToolFilter(null);362 }}363 >364 Réinitialiser les filtres365 </Button>366 )}367 </CardContent>368 </Card>369 )}370 </main>371 </div>372 );373}374