import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useTranslation } from "react-i18next"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { useToast } from "@/hooks/use-toast"; import { apiRequest } from "@/lib/queryClient"; import { format } from "date-fns"; import { MessageSquare, Search, Filter, BookOpen, Trash2, Download, Star, Clock, Brain, User, Bot, Volume2 } from "lucide-react"; interface Conversation { id: number; type: string; prompt: string; response: string; modelUsed: string; processingTime: number; wasSpoken: boolean; rating?: number; tags?: string[]; createdAt: string; } interface ConversationStats { totalConversations: number; averageRating: number; totalProcessingTime: number; favoriteTopics: string[]; mostUsedModel: string; } export function ConversationHistory() { const { t } = useTranslation(); const { toast } = useToast(); const queryClient = useQueryClient(); const [searchQuery, setSearchQuery] = useState(""); const [typeFilter, setTypeFilter] = useState("all"); const [selectedConversation, setSelectedConversation] = useState(null); const { data: conversations = [], isLoading } = useQuery({ queryKey: ["/api/ai/conversations", searchQuery, typeFilter], queryFn: () => apiRequest(`/api/ai/conversations?search=${searchQuery}&type=${typeFilter}`), }); const { data: stats } = useQuery({ queryKey: ["/api/ai/conversations/stats"], queryFn: () => apiRequest("/api/ai/conversations/stats"), }); const deleteConversationMutation = useMutation({ mutationFn: (id: number) => apiRequest(`/api/ai/conversations/${id}`, { method: "DELETE" }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/ai/conversations"] }); queryClient.invalidateQueries({ queryKey: ["/api/ai/conversations/stats"] }); toast({ title: t("success.deleted"), description: t("ai.conversationDeleted"), }); }, }); const rateConversationMutation = useMutation({ mutationFn: ({ id, rating }: { id: number; rating: number }) => apiRequest(`/api/ai/conversations/${id}/rate`, { method: "POST", body: JSON.stringify({ rating }), }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/ai/conversations"] }); queryClient.invalidateQueries({ queryKey: ["/api/ai/conversations/stats"] }); toast({ title: t("success.updated"), description: t("ai.conversationRated"), }); }, }); const exportConversationsMutation = useMutation({ mutationFn: () => apiRequest("/api/ai/conversations/export"), onSuccess: (data) => { const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `conversations-${new Date().toISOString().split('T')[0]}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); toast({ title: t("success.exported"), description: t("ai.conversationsExported"), }); }, }); const filteredConversations = conversations.filter((conv: Conversation) => { const matchesSearch = !searchQuery || conv.prompt.toLowerCase().includes(searchQuery.toLowerCase()) || conv.response.toLowerCase().includes(searchQuery.toLowerCase()); const matchesType = typeFilter === "all" || conv.type === typeFilter; return matchesSearch && matchesType; }); const conversationTypes = [ { value: "all", label: t("ai.allTypes") }, { value: "joke", label: t("ai.jokes") }, { value: "insight", label: t("ai.insights") }, { value: "response", label: t("ai.responses") }, { value: "task_help", label: t("ai.taskHelp") }, { value: "financial_advice", label: t("ai.financialAdvice") }, ]; const getTypeIcon = (type: string) => { switch (type) { case "joke": return "😄"; case "insight": return "💡"; case "task_help": return "✅"; case "financial_advice": return "💰"; default: return "💬"; } }; if (isLoading) { return (
{[...Array(3)].map((_, i) => (
))}
); } return (

{t("ai.conversationHistory")}

{/* Stats Cards */} {stats && (
{t("ai.totalConversations")}
{stats.totalConversations}
{t("ai.averageRating")}
{stats.averageRating?.toFixed(1) || "N/A"}
{t("ai.averageResponseTime")}
{(stats.totalProcessingTime / stats.totalConversations)?.toFixed(0) || "N/A"}ms
{t("ai.mostUsedModel")}
{stats.mostUsedModel || "N/A"}
)} {/* Filters */}
setSearchQuery(e.target.value)} className="pl-10" />
{/* Conversations List */}
{filteredConversations.length > 0 ? ( filteredConversations.map((conversation: Conversation) => (
{getTypeIcon(conversation.type)} {t(`ai.${conversation.type}`)} {conversation.wasSpoken && ( {t("ai.spoken")} )} {conversation.processingTime}ms
{format(new Date(conversation.createdAt), "MMM dd, yyyy HH:mm")}

{t("ai.userPrompt")}

{conversation.prompt}

{t("ai.aiResponse")}

{conversation.response}

{t("ai.model")}: {conversation.modelUsed}
{[1, 2, 3, 4, 5].map((star) => ( ))}
)) ) : (

{t("ai.noConversations")}

{searchQuery || typeFilter !== "all" ? t("ai.noMatchingConversations") : t("ai.noConversationsDescription") }

)}
{/* Detailed View Dialog */} setSelectedConversation(null)}> {t("ai.conversationDetails")} {selectedConversation && format(new Date(selectedConversation.createdAt), "MMMM dd, yyyy 'at' HH:mm")} {selectedConversation && (
{t("ai.type")}: {t(`ai.${selectedConversation.type}`)}
{t("ai.processingTime")}: {selectedConversation.processingTime}ms
{t("ai.model")}: {selectedConversation.modelUsed}
{t("ai.wasSpoken")}: {selectedConversation.wasSpoken ? t("common.yes") : t("common.no")}

{t("ai.userPrompt")}

{selectedConversation.prompt}

{t("ai.aiResponse")}

{selectedConversation.response}

)}
); }