import { useState, useEffect, useCallback } from "react"; import { Plus, Search, Eye, Trash2, ArrowUpDown, Download, Loader2, CheckCircle2, XCircle } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { OpinionDialog } from "./OpinionDialog"; import { AgentSearch } from "./AgentSearch"; import { agentService, OpinionRecord } from "@/services/agent"; import { useToast } from "@/hooks/use-toast"; type SortField = "titulo" | "created_at" | "categoria"; type SortOrder = "asc" | "desc"; export const AgentView = () => { const [opinions, setOpinions] = useState([]); const [pendingOpinions, setPendingOpinions] = useState([]); // Registros temporários sendo processados const [searchTerm, setSearchTerm] = useState(""); const [currentPage, setCurrentPage] = useState(1); const [itemsPerPage, setItemsPerPage] = useState(10); const [sortField, setSortField] = useState("created_at"); const [sortOrder, setSortOrder] = useState("desc"); const [isDialogOpen, setIsDialogOpen] = useState(false); const [selectedOpinion, setSelectedOpinion] = useState(null); const [showSearch, setShowSearch] = useState(false); const [isLoading, setIsLoading] = useState(false); const [opinionToDelete, setOpinionToDelete] = useState(null); const [isDeleting, setIsDeleting] = useState(false); const { toast } = useToast(); // Carrega pareceres da API const loadOpinions = useCallback(async () => { setIsLoading(true); try { const data = await agentService.getOpinions({ page: currentPage, per_page: itemsPerPage, search: searchTerm, }); // Adiciona status aos pareceres da API const opinionsWithStatus = data.map(opinion => ({ ...opinion, status: (opinion.file_url || opinion.file_url_melhoria) ? 'concluido' : 'processando' as const, })); setOpinions(opinionsWithStatus); // Remove registros temporários que agora estão na API setPendingOpinions(prev => prev.filter(pending => !opinionsWithStatus.some(opinion => opinion.titulo === pending.titulo && opinion.created_at.substring(0, 10) === pending.created_at.substring(0, 10) ) ) ); } catch (error: any) { console.error('Erro ao carregar pareceres:', error); toast({ title: "Erro ao carregar pareceres", description: error.message || "Não foi possível carregar a lista de pareceres.", variant: "destructive", }); } finally { setIsLoading(false); } }, [currentPage, itemsPerPage, searchTerm, toast]); // Polling automático para atualizar status dos pareceres useEffect(() => { // Carrega imediatamente loadOpinions(); // Configura polling a cada 10 segundos se houver pareceres pendentes const interval = setInterval(() => { if (pendingOpinions.length > 0) { console.log('Polling: Atualizando lista de pareceres...'); loadOpinions(); } }, 10000); // 10 segundos return () => clearInterval(interval); }, [currentPage, itemsPerPage, pendingOpinions.length, loadOpinions]); // Debounce para busca useEffect(() => { const timer = setTimeout(() => { if (currentPage === 1) { loadOpinions(); } else { setCurrentPage(1); // Volta para a primeira página ao buscar } }, 500); return () => clearTimeout(timer); }, [searchTerm, loadOpinions]); const handleSort = (field: SortField) => { if (sortField === field) { setSortOrder(sortOrder === "asc" ? "desc" : "asc"); } else { setSortField(field); setSortOrder("asc"); } }; // Mescla pareceres da API com registros temporários const allOpinions = [...pendingOpinions, ...opinions]; const sortedOpinions = [...allOpinions].sort((a, b) => { const multiplier = sortOrder === "asc" ? 1 : -1; if (sortField === "created_at") { return multiplier * (new Date(a.created_at).getTime() - new Date(b.created_at).getTime()); } const aValue = a[sortField] || ""; const bValue = b[sortField] || ""; return multiplier * aValue.toString().localeCompare(bValue.toString()); }); const totalPages = Math.ceil(sortedOpinions.length / itemsPerPage); // Callback quando um parecer está sendo criado (registro temporário) const handleOpinionCreating = (tempOpinion: OpinionRecord) => { setPendingOpinions(prev => [tempOpinion, ...prev]); }; // Callback quando um parecer foi criado (recarrega da API) const handleOpinionCreated = () => { loadOpinions(); }; const handleViewOpinion = (opinion: OpinionRecord) => { setSelectedOpinion(opinion); setIsDialogOpen(true); }; const handleNewOpinion = () => { setSelectedOpinion(null); setIsDialogOpen(true); }; const handleSelectFromSearch = (opinion: OpinionRecord) => { setSelectedOpinion(opinion); setShowSearch(false); setIsDialogOpen(true); }; const handleDownloadVersion = async (opinion: OpinionRecord, version: 'v1' | 'v2') => { const fileUrl = version === 'v1' ? opinion.file_url : opinion.file_url_melhoria; if (!fileUrl) { toast({ title: "Arquivo não disponível", description: `A ${version === 'v1' ? 'versão 1' : 'versão melhorada'} ainda não está disponível.`, variant: "destructive", }); return; } try { const fileName = `${opinion.titulo}_${version === 'v1' ? 'v1' : 'melhorada'}.docx`; await agentService.downloadOpinion(fileUrl, fileName); toast({ title: "Download iniciado", description: "O parecer está sendo baixado.", }); } catch (error: any) { toast({ title: "Erro ao fazer download", description: error.message || "Não foi possível baixar o arquivo.", variant: "destructive", }); } }; const handleDeleteOpinion = async () => { if (!opinionToDelete) return; setIsDeleting(true); try { await agentService.deleteOpinion(opinionToDelete.id); toast({ title: "Parecer excluído", description: "O parecer foi excluído com sucesso.", }); // Recarrega a lista de pareceres await loadOpinions(); // Fecha o diálogo de confirmação setOpinionToDelete(null); } catch (error: any) { toast({ title: "Erro ao excluir parecer", description: error.message || "Não foi possível excluir o parecer.", variant: "destructive", }); } finally { setIsDeleting(false); } }; if (showSearch) { return (
); } return (

Gerador de Modelos de Parecer Jurídico

setSearchTerm(e.target.value)} className="w-full md:max-w-sm text-sm" />
Itens:
Status Ações {isLoading ? ( Carregando pareceres... ) : sortedOpinions.length === 0 ? ( {searchTerm ? "Nenhum parecer encontrado" : "Nenhum parecer criado ainda. Clique em 'Novo Parecer' para começar."} ) : ( sortedOpinions.map((opinion) => ( {opinion.titulo} {opinion.categoria || "-"} {opinion.status === 'processando' && ( Gerando... )} {opinion.status === 'concluido' && ( Concluído )} {opinion.status === 'erro' && ( Erro )} {new Date(opinion.created_at).toLocaleDateString("pt-BR")}
handleDownloadVersion(opinion, 'v1')} disabled={!opinion.file_url} > Versão 1 handleDownloadVersion(opinion, 'v2')} disabled={!opinion.file_url_melhoria} > Versão Melhorada
)) )}
{sortedOpinions.length > 0 && (

Mostrando {sortedOpinions.length} {sortedOpinions.length === 1 ? 'parecer' : 'pareceres'}

{Array.from({ length: Math.min(totalPages, 5) }, (_, i) => { let page; if (totalPages <= 5) { page = i + 1; } else if (currentPage <= 3) { page = i + 1; } else if (currentPage >= totalPages - 2) { page = totalPages - 4 + i; } else { page = currentPage - 2 + i; } return ( ); })}
)}
!open && setOpinionToDelete(null)}> Confirmar exclusão Tem certeza que deseja excluir o parecer "{opinionToDelete?.titulo}"? Esta ação não pode ser desfeita. Cancelar {isDeleting ? "Excluindo..." : "Excluir"}
); };