import { BrowserFrame } from "@/components/Browser/BrowserFrame"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { ScrollArea } from "@/components/ui/scroll-area"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; import { useAuth } from "@/hooks/use-auth"; import { useToast } from "@/hooks/use-toast"; import { Plus, Ticket, MessageSquare, BookOpen, Bot, Send, Clock, AlertCircle, CheckCircle2, MoreHorizontal, ArrowRight } from "lucide-react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; interface SupportTicket { id: number; title: string; description?: string; category: string; priority: string; status: string; createdAt: string; customerId?: number; customerName?: string; } interface Conversation { id: number; ticketId: number; senderType: string; content: string; createdAt: string; } interface KnowledgeBaseArticle { id: number; title: string; content: string; category?: string; tags?: string[]; } export default function Support() { const { user } = useAuth(); const { toast } = useToast(); const queryClient = useQueryClient(); const [selectedTicket, setSelectedTicket] = useState(null); const [newTicketOpen, setNewTicketOpen] = useState(false); const [newArticleOpen, setNewArticleOpen] = useState(false); const [messageInput, setMessageInput] = useState(""); const [aiQuestion, setAiQuestion] = useState(""); const [isAiLoading, setIsAiLoading] = useState(false); const { data: tickets = [] } = useQuery({ queryKey: ["/api/support/tickets"], queryFn: async () => { const res = await fetch("/api/support/tickets", { credentials: "include" }); if (!res.ok) return []; return res.json(); }, }); const { data: conversations = [] } = useQuery({ queryKey: ["/api/support/tickets", selectedTicket?.id, "conversations"], queryFn: async () => { if (!selectedTicket) return []; const res = await fetch(`/api/support/tickets/${selectedTicket.id}/conversations`, { credentials: "include" }); if (!res.ok) return []; return res.json(); }, enabled: !!selectedTicket, }); const { data: articles = [] } = useQuery({ queryKey: ["/api/support/knowledge-base"], queryFn: async () => { const res = await fetch("/api/support/knowledge-base", { credentials: "include" }); if (!res.ok) return []; return res.json(); }, }); const [newTicket, setNewTicket] = useState({ title: "", description: "", category: "general", priority: "medium" }); const [newArticle, setNewArticle] = useState({ title: "", content: "", category: "", tags: "" }); const createTicketMutation = useMutation({ mutationFn: async (data: typeof newTicket) => { const res = await fetch("/api/support/tickets", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Failed to create ticket"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/support/tickets"] }); setNewTicketOpen(false); setNewTicket({ title: "", description: "", category: "general", priority: "medium" }); toast({ title: "Ticket criado com sucesso" }); }, }); const updateTicketMutation = useMutation({ mutationFn: async ({ id, data }: { id: number; data: Partial }) => { const res = await fetch(`/api/support/tickets/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), credentials: "include", }); if (!res.ok) throw new Error("Failed to update ticket"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/support/tickets"] }); }, }); const sendMessageMutation = useMutation({ mutationFn: async ({ ticketId, content }: { ticketId: number; content: string }) => { const res = await fetch(`/api/support/tickets/${ticketId}/conversations`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content, senderType: "agent" }), credentials: "include", }); if (!res.ok) throw new Error("Failed to send message"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/support/tickets", selectedTicket?.id, "conversations"] }); setMessageInput(""); }, }); const createArticleMutation = useMutation({ mutationFn: async (data: typeof newArticle) => { const res = await fetch("/api/support/knowledge-base", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...data, tags: data.tags.split(",").map((t) => t.trim()).filter(Boolean) }), credentials: "include", }); if (!res.ok) throw new Error("Failed to create article"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/support/knowledge-base"] }); setNewArticleOpen(false); setNewArticle({ title: "", content: "", category: "", tags: "" }); toast({ title: "Artigo criado" }); }, }); const convertToWorkItemMutation = useMutation({ mutationFn: async (ticketId: number) => { const res = await fetch(`/api/support/tickets/${ticketId}/convert-to-work-item`, { method: "POST", credentials: "include", }); if (!res.ok) throw new Error("Failed to convert"); return res.json(); }, onSuccess: () => { toast({ title: "Ticket convertido em item de trabalho" }); }, }); const askAiMutation = useMutation({ mutationFn: async ({ ticketId, question }: { ticketId: number; question: string }) => { const res = await fetch(`/api/support/tickets/${ticketId}/ai-response`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ question }), credentials: "include", }); if (!res.ok) throw new Error("Failed to get AI response"); return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/support/tickets", selectedTicket?.id, "conversations"] }); setAiQuestion(""); }, }); const handleAskAi = async () => { if (!selectedTicket || !aiQuestion.trim()) return; setIsAiLoading(true); try { await askAiMutation.mutateAsync({ ticketId: selectedTicket.id, question: aiQuestion }); } finally { setIsAiLoading(false); } }; const statusColors: Record = { open: "bg-blue-100 text-blue-600", in_progress: "bg-yellow-100 text-yellow-700", waiting_customer: "bg-purple-100 text-purple-600", resolved: "bg-green-100 text-green-600", closed: "bg-slate-100 text-slate-600", }; const priorityColors: Record = { low: "border-l-green-400", medium: "border-l-yellow-400", high: "border-l-orange-400", critical: "border-l-red-500", }; const openTickets = tickets.filter((t) => t.status === "open" || t.status === "in_progress"); const closedTickets = tickets.filter((t) => t.status === "resolved" || t.status === "closed"); return (