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/components/chat/session-history.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 { useQuery } from "@tanstack/react-query";18import { Button } from "@/components/ui/button";19import { ScrollArea } from "@/components/ui/scroll-area";20import { Clock, MessageSquare } from "lucide-react";21import { formatDistanceToNow } from "date-fns";2223interface SessionListItem {24 sessionId: string;25 title: string;26 createdAt: string;27 updatedAt: string;28}2930interface SessionHistoryProps {31 onLoadSession: (sessionId: string) => void;32 currentSessionId: string | null;33}3435export function SessionHistory({ onLoadSession, currentSessionId }: SessionHistoryProps) {36 const { data: sessions = [], isLoading } = useQuery<SessionListItem[]>({37 queryKey: ['/api/sessions'],38 });3940 if (isLoading) {41 return (42 <div className="p-4 text-sm text-muted-foreground">43 Loading sessions...44 </div>45 );46 }4748 if (sessions.length === 0) {49 return (50 <div className="p-4 text-center">51 <MessageSquare className="w-12 h-12 mx-auto mb-3 text-muted-foreground/50" />52 <p className="text-sm text-muted-foreground">53 No conversation history yet54 </p>55 </div>56 );57 }5859 return (60 <ScrollArea className="h-full">61 <div className="p-4 space-y-2">62 <h2 className="text-sm font-semibold mb-4 text-muted-foreground uppercase tracking-wide">63 History64 </h2>65 {sessions.map((session) => (66 <Button67 key={session.sessionId}68 variant={currentSessionId === session.sessionId ? "secondary" : "ghost"}69 className="w-full justify-start text-left h-auto py-3 px-3"70 onClick={() => onLoadSession(session.sessionId)}71 data-testid={`session-${session.sessionId}`}72 >73 <div className="flex flex-col items-start w-full gap-1">74 <p className="text-sm font-medium line-clamp-2">75 {session.title}76 </p>77 <div className="flex items-center gap-1 text-xs text-muted-foreground">78 <Clock className="w-3 h-3" />79 <span>80 {formatDistanceToNow(new Date(session.updatedAt), { addSuffix: true })}81 </span>82 </div>83 </div>84 </Button>85 ))}86 </div>87 </ScrollArea>88 );89}90