testes/Modulos Angular/projects/idt_app/docs/components/STATUS_SYSTEM_EXAMPLES.md

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: true em 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