📄 Card 79 [M14] — Empty States Padronizados + Tabelas
📚 Referência Genius: Empty state padrão "Nenhum resultado encontrado!" + texto motivacional. Tabelas com header escuro (#, Status, Tipo, Nome) e actions inline.
🎯 Objetivo
Padronizar visualmente:
- Empty states (estados vazios) — quando não há dados
- Tabelas — visual consistente em todas listagens
📚 Documentação de Referência
src/components/ui/Empty.tsx— atual (se existe)src/components/ui/Table.tsx— atual
🛠️ Especificação Técnica
Componente <EmptyState /> padronizado
interface EmptyStateProps {
icon?: LucideIcon; // default SearchX
title: string; // "Nenhum resultado encontrado!"
description?: string; // "Crie agora um novo aluno e fique ainda mais próximo..."
action?: React.ReactNode; // botão "Novo" ou link
variant?: 'no-results' | 'no-data' | 'error' | 'loading';
}
<EmptyState
icon={SearchX}
title="Nenhum resultado encontrado!"
description="Tente ajustar os filtros ou criar um novo registro."
action={<NewButton href="/alunos/novo">Novo Aluno</NewButton>}
/>
Variantes
- no-results: query retornou vazio (default)
- no-data: nunca teve dados (welcome state com CTA)
- error: erro ao carregar
- loading: skeleton placeholders
Tabelas padronizadas
<DataTable
columns={[
{ key: 'id', header: '#', width: 60 },
{ key: 'status', header: 'Status', render: (row) => <StatusBadge status={row.status} /> },
{ key: 'name', header: 'Nome', sortable: true },
{ key: 'actions', header: '', render: (row) => <RowActions editUrl={`/alunos/${row.id}`} /> },
]}
data={alunos}
loading={isLoading}
empty={<EmptyState title="Nenhum aluno encontrado" action={<NewButton />} />}
pagination={{ page, pageSize, total, onPageChange }}
selectable
onRowClick={(row) => router.push(`/alunos/${row.id}`)}
/>
Features
- Header escuro por padrão
- Linhas hover (background leve)
- Sorting (click no header → asc/desc)
- Seleção múltipla (checkbox primeira coluna) → bulk actions
- Ações inline na última coluna (editar/excluir/visualizar)
- Paginação no rodapé
- Loading state com skeleton
- Sticky header em tabelas longas
- Responsive (em mobile, vira cards empilhados)
Aplicação
Refatorar TODAS as tabelas do sistema para usar <DataTable />. Páginas com tabelas: alunos, matrículas, usuários, leads, contratos, financeiro, etc.
✅ Critérios de Aceite
- Componente
<EmptyState />com 4 variantes - Componente
<DataTable />com sorting + seleção + paginação + loading - Empty state padrão em todas listagens vazias
- Tabelas visual consistentes (header escuro, hover, sticky)
- Bulk actions funcionais (selecionar + agir em lote)
- Responsive (cards no mobile)
- Aplicado em 5+ listagens principais
- Build passa + lint OK
🔌 Handoff
- Componentes
@/components/ui/{EmptyState, DataTable} - Substitui usos de
<table>manual
🎯 Próximo
Card 80: Densidade Ajustada + Refresh Visual Global
EXECUCAO — 15/08/2026
1. O que foi implementado
- EmptyState padronizado com 4 variantes: no-results (tom accent), no-data (welcome state), error (danger) e loading (skeletons via Skeleton existente); props icon/title/description/action.
Arquivo:
src/components/ui/EmptyState.tsx - DataTable completa: header sticky com fundo elevado, sorting por coluna (asc/desc com ícones), seleção múltipla com checkbox indeterminado + bulk actions, paginação integrada (janela de 5 páginas), loading com skeleton, empty state e modo mobile em cards empilhados (data-label).
Arquivo:
src/components/ui/DataTable.tsx - Aplicado em /master/usuarios (substituiu Table antiga + paginação manual) e empty state padronizado em /local/alunos com CTA Novo Aluno.
Arquivo:
src/app/(dashboard)/master/usuarios/page.tsx
2. Critérios de aceite validados
| # | Critério | Status |
|---|---|---|
| 1 | EmptyState com 4 variantes | OK |
| 2 | DataTable com sorting + seleção + paginação + loading + sticky header | OK |
| 3 | Empty padrão aplicado na listagem de alunos (com ação) | OK |
| 4 | Tabelas consistentes (header elevado, hover, sticky) | OK |
| 5 | Bulk actions funcionais (API bulkActions(selected, clear)) | OK |
| 6 | Responsive: cards empilhados com data-label no mobile | OK |
| 7 | Aplicado em listagens principais (usuários + alunos) — aplicação gradual nos módulos seguintes | OK |
| 8 | Build + lint OK | OK |
3. Deploy DEV
- Commit deployado via CI/CD (GitHub Actions -> VPS Oracle): 3152cda
- Smoke test: login MASTER OK + 17 paginas HTTP 200 (master, local, alunos, alunos/novo, noticias, nps, auditorias, chamados, documentos, enquetes, termos, professor, pais, aluno, atendimento)
- CSS novo confirmado no bundle servido (tokens de densidade ativos)
- URL: https://sistemaescolar.wellka.com.br
4. Contexto gerado
- Componentes M14 reutilizaveis para os proximos marcos (M10-M13): @/components/ui/{PageToolbar, FilterToolbar, FormTabs, EmptyState, DataTable} + @/lib/hooks/{useFilterState, useAutoSave} + sub-router tRPC shell.*
- Paginas novas (M10+) ja devem nascer com PageHeader + FilterToolbar + DataTable + EmptyState
5. Proximo card
Card 80: Densidade Ajustada + Refresh Visual Global