# 🎯 Sistema de Sub-Abas Configuráveis
## 📖 **Visão Geral**
O sistema de sub-abas foi projetado para tornar o `GenericTabFormComponent` verdadeiramente **genérico** e **escalável**. Agora você pode configurar dinamicamente quais sub-abas aparecem em cada domínio, pensando em **desempenho** e **flexibilidade**.
## 🏗️ **Arquitetura da Solução**
### **1. Interface SubTabConfig**
```typescript
export interface SubTabConfig {
id: string; // Identificador único ('dados', 'endereco', etc.)
label: string; // Rótulo exibido ('Dados Pessoais', 'Endereço')
icon: string; // Ícone FontAwesome ('fa-user', 'fa-map-marker-alt')
component?: 'address' | 'documents' | 'fines' | 'custom'; // Componente especializado
enabled?: boolean; // Se a aba está habilitada (default: true)
order?: number; // Ordem de exibição (default: 999)
data?: any; // Dados adicionais para a aba
requiredFields?: string[]; // Campos obrigatórios desta aba
}
```
### **2. Integração com TabFormConfig**
```typescript
export interface TabFormConfig {
// ... campos existentes
subTabs?: SubTabConfig[]; // ✨ Nova configuração de sub-abas
}
```
## 🎮 **Como Usar**
### **Configuração Básica - Apenas Dados Pessoais**
```typescript
const config = tabFormConfigService.getDriverFormConfigWithSubTabs(['dados']);
// Resultado: Apenas uma aba, renderizada diretamente (sem headers de sub-abas)
```
### **Configuração com Endereço**
```typescript
const config = tabFormConfigService.getDriverFormConfigWithSubTabs(['dados', 'endereco']);
// Resultado: Duas sub-abas - Dados Pessoais + Endereço
```
### **Configuração Completa**
```typescript
const config = tabFormConfigService.getDriverFormConfigWithSubTabs([
'dados', 'endereco', 'documentos', 'multas'
]);
// Resultado: Quatro sub-abas com sistema completo
```
### **Usando Presets Pré-Definidos**
```typescript
const presets = tabFormConfigService.getDriverFormPresets();
// Apenas dados básicos
const basicConfig = presets.basic();
// Com endereço
const withAddressConfig = presets.withAddress();
// Com documentos
const withDocsConfig = presets.withDocs();
// Completo
const completeConfig = presets.complete();
```
## 🚀 **Exemplos Práticos**
### **1. Domínio Motoristas - Completo**
```typescript
// Em drivers.component.ts ou tab-system.service.ts
await tabSystemService.openDriverTabWithPreset('complete', driverData);
// Abas: Dados + Endereço + Documentos + Multas
```
### **2. Domínio Veículos - Só Dados**
```typescript
await tabSystemService.openInTab('vehicle', vehicleData);
// Resultado: Apenas aba de dados (sem sub-abas)
```
### **3. Configuração Dinâmica**
```typescript
// Baseado no tipo de usuário ou permissões
const enabledTabs = user.canManageDocuments
? ['dados', 'endereco', 'documentos']
: ['dados', 'endereco'];
await tabSystemService.openDriverTab(driverData, enabledTabs);
```
## ⚡ **Benefícios de Desempenho**
### **1. Lazy Loading de Componentes**
- ✅ Só carrega `AddressFormComponent` se aba 'endereco' estiver habilitada
- ✅ Componentes futuros (documentos, multas) só são instanciados quando necessário
### **2. Renderização Condicional**
```typescript
// Template otimizado
```
### **3. Fallback Inteligente**
```typescript
// Se há apenas 1 sub-aba, remove overhead das headers
```
## 🎨 **Interface de Usuário**
### **Múltiplas Sub-Abas**
```
┌─────────────────────────────────────┐
│ [👤 Dados Básicos] [📍 Endereço] │
├─────────────────────────────────────┤
│ │
│ Conteúdo da aba selecionada │
│ │
└─────────────────────────────────────┘
```
### **Aba Única (Otimizada)**
```
┌─────────────────────────────────────┐
│ │
│ Conteúdo direto (sem tabs) │
│ │
└─────────────────────────────────────┘
```
## 🔧 **Métodos Principais**
### **No GenericTabFormComponent**
```typescript
// Obtém sub-abas disponíveis
getAvailableSubTabs(): SubTabConfig[]
// Verifica se sub-aba está disponível
isSubTabAvailable(tabId: string): boolean
// Obtém configuração de sub-aba
getSubTabConfig(tabId: string): SubTabConfig | undefined
// Seleciona sub-aba
selectSubTab(tabId: string): void
```
### **No TabFormConfigService**
```typescript
// Configuração customizada
getDriverFormConfigWithSubTabs(enabledSubTabs: string[]): TabFormConfig
// Presets pré-definidos
getDriverFormPresets(): { basic, withAddress, withDocs, complete }
```
### **No TabSystemService**
```typescript
// Abre aba com sub-abas específicas
openDriverTab(itemData?, enabledSubTabs?, customTitle?): Promise
// Abre aba com preset
openDriverTabWithPreset(preset, itemData?, customTitle?): Promise
```
## 🔮 **Expansão Futura**
### **1. Novas Sub-Abas**
```typescript
// Adicionar nova sub-aba é simples:
{
id: 'historico',
label: 'Histórico',
icon: 'fa-history',
component: 'history',
enabled: true,
order: 5
}
```
### **2. Componentes Especializados**
```typescript
// Template se expande automaticamente
```
### **3. Configuração por Domínio**
```typescript
// Cada domínio pode ter suas sub-abas específicas
const vehicleSubTabs = ['dados', 'manutencao', 'historico'];
const userSubTabs = ['dados', 'endereco', 'permissoes'];
```
## 💾 **Sistema de Salvamento Genérico**
### **🚀 Nova Arquitetura**
O sistema foi **refatorado** para utilizar uma arquitetura **genérica e escalável** de salvamento que funciona com qualquer domínio e qualquer configuração de sub-abas.
### **Como Funciona**
#### **1. Fluxo de Eventos**
```typescript
// 1️⃣ TabSystemComponent emite evento genérico
this.tableEvent.emit({
event: 'formSubmit',
data: {
tab, // Contexto da aba
formData, // Dados do formulário
isNewItem, // Se é criação ou edição
onSuccess: (response) => this.onSaveSuccess(tab, response, component),
onError: (error) => this.onSaveError(tab, error, component)
}
});
// 2️⃣ BaseDomainComponent recebe e processa
protected onFormSubmit(data: any): void {
const { tab, formData, isNewItem, onSuccess, onError } = data;
const operation = isNewItem
? this.createEntity(formData)
: this.updateEntity(tab.data.id, formData);
operation?.subscribe({
next: (response) => onSuccess(response),
error: (error) => onError(error)
});
}
```
#### **2. Callbacks Inteligentes**
```typescript
// ✅ Sucesso: Marca formulário como salvo e remove modificações
private onSaveSuccess(tab, response, component): void {
component.markAsSavedSuccessfully();
this.tabSystemService.setTabModified(tabIndex, false);
tab.data = { ...tab.data, ...response };
}
// ❌ Erro: Restaura estado de submissão
private onSaveError(tab, error, component): void {
component.setSubmitting(false);
// Pode mostrar notificação de erro
}
```
### **💡 Vantagens**
- ✅ **Escalável**: Funciona automaticamente para qualquer novo domínio
- ✅ **Limpo**: Sem código específico no TabSystemComponent
- ✅ **Flexível**: Permite customizações quando necessário
- ✅ **Consistente**: Mesma API para todos os domínios
- ✅ **Sub-Abas**: Funciona com qualquer configuração de sub-abas
### **🎯 Implementação por Domínio**
```typescript
// Para novos domínios - ZERO CÓDIGO adicional
export class ClientsComponent extends BaseDomainComponent {
// ✨ Salvamento já funciona automaticamente!
}
// Para customizações específicas
export class VehiclesComponent extends BaseDomainComponent {
protected createEntity(data: any): Observable {
// Lógica específica de validação/processamento
return this.vehiclesService.createVehicleWithSpecialValidation(data);
}
}
```
### **🔄 Compatibilidade com Sub-Abas**
O sistema de salvamento genérico funciona **perfeitamente** com qualquer configuração de sub-abas:
```typescript
// Configuração simples (1 aba)
await openDriverTab(data, ['dados']);
// Salvamento: onFormSubmit() → createEntity() → onSuccess()
// Configuração completa (4 abas)
await openDriverTab(data, ['dados', 'endereco', 'documentos', 'multas']);
// Salvamento: Mesmo fluxo, funciona automaticamente
// Preset customizado
await openDriverTabWithPreset('withAddress', data);
// Salvamento: Funciona independente do preset escolhido
```
### **🧪 Testing**
```typescript
// Teste do fluxo de salvamento
it('should save driver data using generic system', async () => {
const component = new DriversComponent(...);
const mockData = { name: 'João', cpf: '123.456.789-00' };
// Sistema genérico deve lidar automaticamente
await component.onFormSubmit({
tab: mockTab,
formData: mockData,
isNewItem: true,
onSuccess: jasmine.createSpy(),
onError: jasmine.createSpy()
});
expect(mockService.createDriver).toHaveBeenCalledWith(mockData);
});
```
vehicles: ['dados', 'manutencao', 'rotas']
users: ['dados', 'permissoes']
clients: ['dados', 'endereco', 'contratos']
```
## 📱 **Responsividade**
- ✅ Headers de sub-abas se adaptam em mobile
- ✅ Ícones e textos otimizados para telas pequenas
- ✅ Conteúdo das abas com padding responsivo
## 🧪 **Como Testar**
### **1. Console do Navegador**
```javascript
// Testar diferentes configurações
debugHelpers.getTabFormComponent().getAvailableSubTabs()
// Trocar sub-aba
debugHelpers.switchSubTab('endereco')
// Ver estado atual
debugHelpers.showFormState()
```
### **2. Configuração Dinâmica**
```typescript
// No DriversComponent, você pode criar métodos:
testBasicDriverForm() {
this.tabSystemService.openDriverTabWithPreset('basic', mockDriver);
}
testCompleteDriverForm() {
this.tabSystemService.openDriverTabWithPreset('complete', mockDriver);
}
```
## 🎯 **Conclusão**
Esta implementação resolve todos os problemas identificados:
- ✅ **Parametrização**: Sub-abas configuráveis via `enabledSubTabs`
- ✅ **Desempenho**: Lazy loading + renderização condicional
- ✅ **Escalabilidade**: Fácil adição de novas abas/domínios
- ✅ **Genericidade**: Funciona para qualquer domínio
- ✅ **Flexibilidade**: Presets + configuração customizada
O sistema está pronto para **motoristas**, **veículos**, **documentos**, **multas** e qualquer futuro domínio que precise de sub-abas!