Fix emprestimos table layout shift during filter changes

- Replace centered spinner with skeleton table rows
- Maintain table structure and width during loading
- Show 5 skeleton rows with proper column widths
- Prevents layout collapse when changing filters

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-05 10:11:43 -03:00
parent 7c5bc828cf
commit b7e7f99f99

View file

@ -48,6 +48,7 @@ import {
TableRow, TableRow,
} from "@/components/ui/table" } from "@/components/ui/table"
import { Spinner } from "@/components/ui/spinner" import { Spinner } from "@/components/ui/spinner"
import { Skeleton } from "@/components/ui/skeleton"
import { SearchableCombobox, type SearchableComboboxOption } from "@/components/ui/searchable-combobox" import { SearchableCombobox, type SearchableComboboxOption } from "@/components/ui/searchable-combobox"
import { DateRangeButton, type DateRangeValue } from "@/components/date-range-button" import { DateRangeButton, type DateRangeValue } from "@/components/date-range-button"
import { DatePicker } from "@/components/ui/date-picker" import { DatePicker } from "@/components/ui/date-picker"
@ -503,20 +504,15 @@ export function EmprestimosPageClient() {
{/* Table Section */} {/* Table Section */}
<section className="rounded-3xl border border-slate-200 bg-white/90 shadow-sm overflow-hidden"> <section className="rounded-3xl border border-slate-200 bg-white/90 shadow-sm overflow-hidden">
{!emprestimos ? ( {emprestimos && filteredEmprestimos.length === 0 ? (
<div className="flex items-center justify-center gap-2 py-16">
<Spinner className="size-5 text-neutral-500" />
<span className="text-sm text-neutral-600">Carregando empréstimos...</span>
</div>
) : filteredEmprestimos.length === 0 ? (
<Empty className="m-4 border-dashed"> <Empty className="m-4 border-dashed">
<EmptyHeader> <EmptyHeader>
<EmptyMedia variant="icon" className="bg-slate-100 text-slate-600"> <EmptyMedia variant="icon" className="bg-slate-100 text-slate-600">
<IconPackage className="size-5" /> <IconPackage className="size-5" />
</EmptyMedia> </EmptyMedia>
<EmptyTitle>Nenhum empréstimo encontrado</EmptyTitle> <EmptyTitle>Nenhum emprestimo encontrado</EmptyTitle>
<EmptyDescription> <EmptyDescription>
Ajuste os filtros ou crie um novo empréstimo para começar. Ajuste os filtros ou crie um novo emprestimo para comecar.
</EmptyDescription> </EmptyDescription>
</EmptyHeader> </EmptyHeader>
</Empty> </Empty>
@ -527,17 +523,32 @@ export function EmprestimosPageClient() {
<TableRow className="bg-transparent text-[11px] uppercase tracking-wide text-neutral-600 hover:bg-transparent"> <TableRow className="bg-transparent text-[11px] uppercase tracking-wide text-neutral-600 hover:bg-transparent">
<TableHead className="w-[6%] px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Ref</TableHead> <TableHead className="w-[6%] px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Ref</TableHead>
<TableHead className="w-[14%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Cliente</TableHead> <TableHead className="w-[14%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Cliente</TableHead>
<TableHead className="w-[12%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Responsável</TableHead> <TableHead className="w-[12%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Responsavel</TableHead>
<TableHead className="w-[16%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Equipamentos</TableHead> <TableHead className="w-[16%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Equipamentos</TableHead>
<TableHead className="w-[11%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Empréstimo</TableHead> <TableHead className="w-[11%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Emprestimo</TableHead>
<TableHead className="w-[11%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Prevista</TableHead> <TableHead className="w-[11%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Prevista</TableHead>
<TableHead className="w-[9%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Status</TableHead> <TableHead className="w-[9%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Status</TableHead>
<TableHead className="w-[10%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Valor</TableHead> <TableHead className="w-[10%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Valor</TableHead>
<TableHead className="w-[11%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Ações</TableHead> <TableHead className="w-[11%] border-l border-slate-200 px-3 py-3 text-center text-[11px] font-semibold uppercase tracking-wide text-neutral-600">Acoes</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{filteredEmprestimos.map((emp) => ( {!emprestimos ? (
// Skeleton rows durante o loading
Array.from({ length: 5 }).map((_, idx) => (
<TableRow key={`skeleton-${idx}`} className="animate-pulse">
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-8" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-24" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-20" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-28" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-16" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-16" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-14" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-4 w-16" /></TableCell>
<TableCell className="text-center"><Skeleton className="mx-auto h-8 w-20 rounded-full" /></TableCell>
</TableRow>
))
) : filteredEmprestimos.map((emp) => (
<TableRow <TableRow
key={emp.id} key={emp.id}
className="cursor-pointer transition-colors hover:bg-cyan-50/30" className="cursor-pointer transition-colors hover:bg-cyan-50/30"