11 KiB
11 KiB
🎯 EXEMPLOS PRÁTICOS - Sistema Global de Status
Exemplos reais de como implementar o Sistema Global de Status nos componentes da aplicação PraFrota.
📋 Exemplo Completo - Fines Component
1. TypeScript Configuration
// fines.component.ts - Configuração de status na coluna
{
field: "status",
header: "Status",
sortable: true,
filterable: false,
allowHtml: true, // ✅ OBRIGATÓRIO para HTML
label: (status: string) => {
const statusConfig: { [key: string]: { label: string, class: string } } = {
'Pending': { label: 'Pendente', class: 'status-pending' },
'Paid': { label: 'Pago', class: 'status-paid' },
'Approved': { label: 'Aprovado', class: 'status-approved' },
'Cancelled': { label: 'Cancelado', class: 'status-cancelled' },
'Processing': { label: 'Processando', class: 'status-processing' },
'Failed': { label: 'Falhou', class: 'status-failed' }
};
const config = statusConfig[status] || { label: status, class: 'status-unknown' };
return `<span class="status-badge ${config.class}">${config.label}</span>`;
}
}
2. HTML Template
<!-- fines.component.html -->
<div class="domain-container">
<div class="main-content">
<!-- Header com resumo de status -->
<div class="items-header">
<h3>
<i class="fas fa-gavel"></i>
Gestão de Multas
</h3>
<div class="items-summary">
<span class="badge badge-info">
<i class="fas fa-list"></i>
Total: {{totalItems}}
</span>
<span class="badge badge-warning">
<i class="fas fa-clock"></i>
Pendentes: {{pendingCount}}
</span>
<span class="badge badge-secondary">
<i class="fas fa-check"></i>
Pagas: {{paidCount}}
</span>
</div>
</div>
<!-- Tab System com status automático -->
<app-tab-system
#tabSystem
[config]="tabConfig"
[events]="tabEvents"
[showDebugInfo]="false"
(tabSelected)="onTabSelected($event)"
(tabClosed)="onTabClosed($event)"
(tabAdded)="onTabAdded($event)"
(tableEvent)="onTableEvent($event)">
</app-tab-system>
</div>
</div>
3. SCSS Styles
// fines.component.scss
// 🎨 Fines Component Styles - V2.0
// Estilos específicos para o domínio Multas
//
// 📋 Status Badges: Utiliza sistema global de _status.scss
// Exemplo: <span class="status-badge status-pending">Pendente</span>
.domain-container {
height: 100%;
display: flex;
flex-direction: column;
background: var(--background);
.main-content {
flex: 1;
overflow: hidden;
padding: 0;
}
}
// ✅ Não precisa definir estilos de status - usa global!
// Os estilos vêm automaticamente de _status.scss
🔄 Exemplo de Migração - Account Payable Items
Antes (Estilos Locais)
// ❌ ANTES - account-payable-items.component.scss
:deep(.status-badge) {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.025em;
&.status-pending {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffeaa7;
}
// ... mais estilos duplicados
}
Depois (Sistema Global)
// ✅ DEPOIS - account-payable-items.component.scss
// 🎨 Status Badges - Agora usando estilos globais de _status.scss
// Os estilos foram movidos para assets/styles/_status.scss para uso global
📊 Exemplo Avançado - Dashboard com KPIs
TypeScript
// dashboard.component.ts
export class DashboardComponent {
getStatusSummary() {
return {
total: this.allItems.length,
pending: this.allItems.filter(item => item.status === 'Pending').length,
paid: this.allItems.filter(item => item.status === 'Paid').length,
cancelled: this.allItems.filter(item => item.status === 'Cancelled').length
};
}
getStatusBadge(status: string, count: number): string {
const statusMap = {
'pending': { class: 'status-pending', label: 'Pendentes' },
'paid': { class: 'status-paid', label: 'Pagas' },
'cancelled': { class: 'status-cancelled', label: 'Canceladas' }
};
const config = statusMap[status.toLowerCase()];
return `<span class="status-badge ${config.class}">${config.label}: ${count}</span>`;
}
}
HTML Template
<!-- dashboard.component.html -->
<div class="dashboard-container">
<!-- KPIs com status -->
<div class="kpi-grid">
<div class="kpi-card">
<div class="kpi-header">
<h4>Status Financeiro</h4>
</div>
<div class="kpi-content">
<div class="status-list">
<span class="status-badge status-pending">
Pendentes: {{statusSummary.pending}}
</span>
<span class="status-badge status-paid">
Pagas: {{statusSummary.paid}}
</span>
<span class="status-badge status-cancelled">
Canceladas: {{statusSummary.cancelled}}
</span>
</div>
</div>
</div>
<!-- Mais KPIs... -->
</div>
<!-- Tabela com status -->
<div class="data-section">
<app-data-table
[data]="tableData"
[columns]="tableColumns">
</app-data-table>
</div>
</div>
🎨 Exemplo de Estados Visuais
Estado Vazio
<!-- Quando não há dados -->
<div class="empty-state" *ngIf="items.length === 0 && !loading">
<i class="fas fa-inbox fa-3x"></i>
<h4>Nenhuma multa encontrada</h4>
<p>Não há multas cadastradas para exibir no momento.</p>
<button class="btn btn-primary" (click)="openCreateForm()">
<i class="fas fa-plus"></i>
Cadastrar Nova Multa
</button>
</div>
Estado de Erro
<!-- Quando há erro -->
<div class="error-state" *ngIf="hasError">
<i class="fas fa-exclamation-triangle fa-3x"></i>
<h4>Erro ao carregar multas</h4>
<p>Ocorreu um problema ao buscar as informações das multas.</p>
<button class="btn btn-primary" (click)="retryLoad()">
<i class="fas fa-refresh"></i>
Tentar Novamente
</button>
</div>
Estado de Carregamento
<!-- Durante carregamento -->
<div class="loading-state" *ngIf="loading">
<div class="spinner"></div>
<h4>Carregando multas...</h4>
<p>Aguarde enquanto buscamos os dados.</p>
</div>
🔧 Exemplo de Customização
Adicionando Status Específico
// _status.scss - Adicionando novo status
.status-badge {
// Status específico para multas
&.status-contested {
background-color: #fff3e0;
color: #f57c00;
border-color: #ffcc02;
&:hover {
background-color: #ffcc02;
transform: translateY(-1px);
}
}
&.status-expired {
background-color: #ffebee;
color: #d32f2f;
border-color: #f44336;
&:hover {
background-color: #f44336;
color: white;
transform: translateY(-1px);
}
}
}
Usando Status Customizado
// fines.component.ts
const statusConfig = {
'Pending': { label: 'Pendente', class: 'status-pending' },
'Paid': { label: 'Pago', class: 'status-paid' },
'Contested': { label: 'Contestada', class: 'status-contested' }, // ✅ Novo
'Expired': { label: 'Vencida', class: 'status-expired' } // ✅ Novo
};
📱 Exemplo Mobile-First
HTML Responsivo
<!-- Layout que se adapta ao mobile -->
<div class="status-container">
<!-- Desktop: Lista horizontal -->
<div class="status-list hide-mobile">
<span class="status-badge status-pending">Pendentes: 5</span>
<span class="status-badge status-paid">Pagas: 15</span>
<span class="status-badge status-cancelled">Canceladas: 2</span>
</div>
<!-- Mobile: Lista vertical compacta -->
<div class="status-grid show-mobile">
<div class="status-item">
<span class="status-badge status-sm status-pending">5</span>
<span class="status-label">Pendentes</span>
</div>
<div class="status-item">
<span class="status-badge status-sm status-paid">15</span>
<span class="status-label">Pagas</span>
</div>
<div class="status-item">
<span class="status-badge status-sm status-cancelled">2</span>
<span class="status-label">Canceladas</span>
</div>
</div>
</div>
SCSS Responsivo
// Estilos específicos para mobile
.status-container {
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 0.5rem;
.status-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.25rem;
.status-label {
font-size: 0.75rem;
color: var(--text-secondary);
}
}
}
}
🧪 Exemplo de Testes
Teste de Componente
// fines.component.spec.ts
describe('FinesComponent Status', () => {
it('should display correct status badge for pending fine', () => {
const mockFine = { status: 'Pending', id: 1 };
component.fines = [mockFine];
fixture.detectChanges();
const statusBadge = fixture.debugElement.query(By.css('.status-pending'));
expect(statusBadge).toBeTruthy();
expect(statusBadge.nativeElement.textContent).toContain('Pendente');
});
it('should handle unknown status gracefully', () => {
const mockFine = { status: 'UnknownStatus', id: 1 };
component.fines = [mockFine];
fixture.detectChanges();
const statusBadge = fixture.debugElement.query(By.css('.status-unknown'));
expect(statusBadge).toBeTruthy();
});
});
Teste E2E
// fines.e2e-spec.ts
describe('Fines Status Display', () => {
it('should show correct status colors', async () => {
await page.goto('/fines');
// Verificar se status pending tem cor amarela
const pendingBadge = await page.locator('.status-pending').first();
const bgColor = await pendingBadge.evaluate(el =>
getComputedStyle(el).backgroundColor
);
expect(bgColor).toBe('rgb(255, 243, 205)'); // #fff3cd
});
});
📚 Checklist de Implementação
✅ Para Novos Componentes
- Usar classes
status-badge+status-* - Configurar
allowHtml: trueem colunas de tabela - Incluir fallback para status desconhecidos
- Testar responsividade mobile
- Verificar suporte a dark mode
- Adicionar testes unitários
✅ Para Migração de Componentes Existentes
- Identificar estilos de status locais
- Mapear status existentes para classes globais
- Remover estilos CSS duplicados
- Atualizar configuração de colunas
- Testar funcionamento
- Documentar mudanças
✅ Para Customizações
- Adicionar novos status em
_status.scss - Incluir suporte a dark mode
- Testar em diferentes tamanhos de tela
- Documentar novos status
- Atualizar guia de uso
Exemplos Práticos | Sistema Global de Status | PraFrota Angular 19.2.x