261 lines
7.4 KiB
TypeScript
261 lines
7.4 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
/* eslint-disable react-hooks/set-state-in-effect */
|
|
'use client';
|
|
|
|
import { getCounts, getProtocols } from '@/services/protocolService';
|
|
import { Button } from '@/views/components/ui/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from '@/views/components/ui/dialog';
|
|
import {
|
|
Pagination,
|
|
PaginationContent,
|
|
PaginationEllipsis,
|
|
PaginationItem,
|
|
PaginationLink,
|
|
PaginationNext,
|
|
PaginationPrevious,
|
|
} from '@/views/components/ui/pagination';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/views/components/ui/table';
|
|
import { useEffect, useState } from 'react';
|
|
|
|
import type { Protocol } from '@/services/protocolService';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '../components/ui/card';
|
|
|
|
type Props = {
|
|
status: string;
|
|
};
|
|
|
|
export function ProtocolsDialog({ status }: Props) {
|
|
const [open, setOpen] = useState(false);
|
|
const [search, setSearch] = useState('');
|
|
const [page, setPage] = useState(1);
|
|
const [pageSize] = useState(10);
|
|
const [allItems, setAllItems] = useState<Protocol[]>([]);
|
|
const [paginatedItems, setPaginatedItems] = useState<Protocol[]>([]);
|
|
const [total, setTotal] = useState(0);
|
|
const [loading, setLoading] = useState(false);
|
|
const [counts, setCounts] = useState<Record<string, number>>({ Todos: 0 });
|
|
|
|
const label = `${status} (${counts[status] ?? 0})`;
|
|
|
|
useEffect(() => {
|
|
setCounts(getCounts());
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!open) return;
|
|
|
|
setLoading(true);
|
|
getProtocols({
|
|
status: status as any,
|
|
page: 1,
|
|
pageSize: 1000,
|
|
search,
|
|
}).then((r) => {
|
|
setAllItems(r.items);
|
|
setTotal(r.total);
|
|
setLoading(false);
|
|
setPage(1); // Reset para primeira página quando buscar
|
|
});
|
|
}, [open, search, status]);
|
|
|
|
// Efeito para aplicar a paginação local
|
|
useEffect(() => {
|
|
if (allItems.length === 0) {
|
|
setPaginatedItems([]);
|
|
return;
|
|
}
|
|
|
|
const startIndex = (page - 1) * pageSize;
|
|
const endIndex = startIndex + pageSize;
|
|
const itemsForCurrentPage = allItems.slice(startIndex, endIndex);
|
|
|
|
setPaginatedItems(itemsForCurrentPage);
|
|
}, [allItems, page, pageSize]);
|
|
|
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
|
|
function getPageItems(totalPages: number, current: number) {
|
|
const pages: Array<number | 'ellipsis'> = [];
|
|
if (totalPages <= 7) {
|
|
for (let i = 1; i <= totalPages; i++) pages.push(i);
|
|
return pages;
|
|
}
|
|
|
|
pages.push(1);
|
|
const left = Math.max(2, current - 1);
|
|
const right = Math.min(totalPages - 1, current + 1);
|
|
|
|
if (left > 2) pages.push('ellipsis');
|
|
|
|
for (let i = left; i <= right; i++) pages.push(i);
|
|
|
|
if (right < totalPages - 1) pages.push('ellipsis');
|
|
|
|
pages.push(totalPages);
|
|
return pages;
|
|
}
|
|
|
|
const handlePreviousPage = () => {
|
|
if (page > 1) {
|
|
setPage(page - 1);
|
|
}
|
|
};
|
|
|
|
const handleNextPage = () => {
|
|
if (page < totalPages) {
|
|
setPage(page + 1);
|
|
}
|
|
};
|
|
|
|
const handlePageClick = (pageNumber: number) => {
|
|
setPage(pageNumber);
|
|
};
|
|
|
|
const pageItems = getPageItems(totalPages, page);
|
|
|
|
return (
|
|
<Dialog
|
|
open={open}
|
|
onOpenChange={(v) => {
|
|
setOpen(v);
|
|
if (!v) {
|
|
// Resetar estado quando o dialog fechar
|
|
setSearch('');
|
|
setPage(1);
|
|
}
|
|
}}>
|
|
<DialogTrigger asChild>
|
|
<Card className="hover:shadow-md transition-shadow duration-200 cursor-pointer">
|
|
<CardHeader>
|
|
<CardTitle className="text-sm">{`Protocolos ${status.toLowerCase()}`}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold mb-3">{counts[status] ?? 0}</div>
|
|
</CardContent>
|
|
</Card>
|
|
</DialogTrigger>
|
|
|
|
<DialogContent className="min-w-[80vw] max-w-[80vw] h-full max-h-[80vh] overflow-auto">
|
|
<DialogHeader>
|
|
<DialogTitle>{label}</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
<div className="flex gap-2 items-center mb-4">
|
|
<input
|
|
className="flex-1 rounded-sm border px-3 py-2"
|
|
placeholder={`Pesquisar em ${label.toLowerCase()}...`}
|
|
value={search}
|
|
onChange={(e) => {
|
|
setSearch(e.target.value);
|
|
setPage(1);
|
|
}}
|
|
/>
|
|
<div className="text-sm text-muted-foreground">
|
|
{loading ? 'Carregando...' : `${total} encontrados`}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="overflow-auto">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead className="w-[100px]">Código</TableHead>
|
|
<TableHead>Assunto</TableHead>
|
|
<TableHead className="w-[120px]">Data</TableHead>
|
|
<TableHead>Solicitante</TableHead>
|
|
<TableHead>Local</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{paginatedItems.map((protocol) => (
|
|
<TableRow key={protocol.id}>
|
|
<TableCell className="font-medium">{protocol.id}</TableCell>
|
|
<TableCell>{protocol.title}</TableCell>
|
|
<TableCell>{protocol.date}</TableCell>
|
|
<TableCell>{protocol.sender}</TableCell>
|
|
<TableCell>{protocol.location}</TableCell>
|
|
</TableRow>
|
|
))}
|
|
{paginatedItems.length === 0 && (
|
|
<TableRow>
|
|
<TableCell colSpan={5} className="h-24 text-center">
|
|
{loading ? 'Carregando...' : 'Nenhum protocolo encontrado.'}
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between gap-2 mt-4">
|
|
<div className="text-sm text-muted-foreground">
|
|
Página {page} de {totalPages}
|
|
</div>
|
|
|
|
<Pagination className='w-fit m-0'>
|
|
<PaginationContent>
|
|
<PaginationItem>
|
|
<PaginationPrevious
|
|
href="#"
|
|
onClick={handlePreviousPage}
|
|
className={page <= 1 ? 'pointer-events-none opacity-50' : ''}
|
|
/>
|
|
</PaginationItem>
|
|
|
|
{pageItems.map((pageItem, index) => (
|
|
<PaginationItem key={index}>
|
|
{pageItem === 'ellipsis' ? (
|
|
<PaginationEllipsis />
|
|
) : (
|
|
<PaginationLink
|
|
href="#"
|
|
onClick={() => handlePageClick(pageItem)}
|
|
isActive={pageItem === page}>
|
|
{pageItem}
|
|
</PaginationLink>
|
|
)}
|
|
</PaginationItem>
|
|
))}
|
|
|
|
<PaginationItem>
|
|
<PaginationNext
|
|
href="#"
|
|
onClick={handleNextPage}
|
|
className={
|
|
page >= totalPages ? 'pointer-events-none opacity-50' : ''
|
|
}
|
|
/>
|
|
</PaginationItem>
|
|
</PaginationContent>
|
|
</Pagination>
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button onClick={() => setOpen(false)}>Fechar</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|
|
export default ProtocolsDialog;
|