# 🎯 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!