testes/Modulos Angular/projects/idt_app/docs/tab-system/GENERIC_API_GUIDE.md

11 KiB

🚀 API Genérica para Formulários com Sub-Abas

📖 Visão Geral

A API genérica permite trabalhar com qualquer entidade (drivers, vehicles, users, companies, products, etc.) usando os mesmos métodos, eliminando a necessidade de criar código específico para cada tipo.

🎯 Métodos Principais

1. Abertura com Sub-Abas Customizadas

// API Genérica
await tabSystemService.openTabWithSubTabs(entityType, data, subTabs?, title?)

// Exemplos:
await tabSystemService.openTabWithSubTabs('driver', driverData, ['dados', 'endereco'])
await tabSystemService.openTabWithSubTabs('vehicle', vehicleData, ['dados', 'documentos'])
await tabSystemService.openTabWithSubTabs('user', userData, ['dados', 'permissoes'])

2. Abertura com Presets Pré-Definidos

// API Genérica
await tabSystemService.openTabWithPreset(entityType, preset, data?, title?)

// Exemplos:
await tabSystemService.openTabWithPreset('driver', 'withDocs', driverData)
await tabSystemService.openTabWithPreset('vehicle', 'complete', vehicleData)
await tabSystemService.openTabWithPreset('company', 'withAddress', companyData)

🏗️ Entidades Suportadas

Entidade Sub-Abas Disponíveis Presets
driver dados, endereco, documentos, multas basic, withAddress, withDocs, complete
vehicle dados, documentos, manutencao basic, withDocs, complete
user dados, endereco, permissoes basic, withAddress, complete
client dados, endereco, contratos basic, withAddress, complete
company dados, endereco, documentos basic, withAddress, complete
product dados basic

🎮 Métodos de Conveniência

Para facilitar ainda mais, existem métodos específicos para cada entidade:

Drivers (Mantido para compatibilidade)

await tabSystemService.openDriverTabWithPreset('withDocs', driverData)

Veículos

await tabSystemService.openVehicleTabWithPreset('complete', vehicleData)

Usuários

await tabSystemService.openUserTabWithPreset('withAddress', userData)

Empresas

await tabSystemService.openCompanyTabWithPreset('complete', companyData)

Produtos

await tabSystemService.openProductTab(productData)

🧪 Testando no Console

Teste Individual

// Veículo básico
component.testEditVehicleBasic()

// Usuário completo
component.testEditUserComplete()

// Empresa com endereço
component.testEditCompanyComplete()

Teste Completo

// Testa todas as entidades
component.demoAllEntities()

// Testa API genérica diretamente
component.testGenericAPI()

📋 Configuração de Formulários

Obter configuração com sub-abas

// API Genérica
const config = tabFormConfigService.getFormConfigWithSubTabs('driver', ['dados', 'endereco'])

// Com opções customizadas
const config = tabFormConfigService.getFormConfigWithSubTabs('vehicle', ['dados'], {
  baseFields: customFields,
  customSubTabs: customTabs
})

Obter configuração por preset

const config = tabFormConfigService.getFormConfigByPreset('driver', 'withDocs')

Obter presets disponíveis

const presets = tabFormConfigService.getFormPresets('driver')
// Retorna: { basic: Function, withAddress: Function, withDocs: Function, complete: Function }

🔄 Migração do Código Específico

Antes (Específico para Driver)

// ❌ Código antigo
await tabSystemService.openDriverTabWithPreset('withDocs', driverData)
const config = tabFormConfigService.getDriverFormConfigWithSubTabs(['dados', 'endereco'])

Depois (Genérico)

// ✅ Código novo (funciona para qualquer entidade)
await tabSystemService.openTabWithPreset('driver', 'withDocs', driverData)
const config = tabFormConfigService.getFormConfigWithSubTabs('driver', ['dados', 'endereco'])

// ✅ Ou usando método de conveniência (ainda funciona)
await tabSystemService.openDriverTabWithPreset('withDocs', driverData)

🎯 Vantagens da API Genérica

  1. Reutilização: Um código serve para todas as entidades
  2. Consistência: Mesma interface para todos os tipos
  3. Manutenibilidade: Mudanças em um local afetam todos
  4. Escalabilidade: Fácil adicionar novas entidades
  5. Flexibilidade: Sub-abas e presets configuráveis

📝 Exemplos Práticos

Cenário 1: Sistema de CRM

// Abrir cliente com dados + endereço + contratos
await tabSystemService.openTabWithPreset('client', 'complete', clientData)

// Abrir empresa apenas com dados básicos
await tabSystemService.openTabWithPreset('company', 'basic', companyData)

Cenário 2: Sistema de Logística

// Abrir motorista com documentos
await tabSystemService.openTabWithPreset('driver', 'withDocs', driverData)

// Abrir veículo com manutenção
await tabSystemService.openTabWithPreset('vehicle', 'complete', vehicleData)

Cenário 3: E-commerce

// Abrir produto (formulário simples)
await tabSystemService.openProductTab(productData)

// Abrir usuário com permissões
await tabSystemService.openTabWithPreset('user', 'complete', userData)

💾 Sistema de Salvamento Genérico

🚀 Nova Funcionalidade: Salvamento Universal

O sistema agora inclui um mecanismo de salvamento genérico que funciona automaticamente para qualquer entidade aberta através da API genérica, eliminando a necessidade de implementar lógica de salvamento específica para cada domínio.

Como Funciona

1. Arquitetura Baseada em Eventos

// Quando um formulário é submetido em qualquer entidade:
this.tableEvent.emit({
  event: 'formSubmit',
  data: {
    tab,                    // Contexto da aba atual
    formData,               // Dados do formulário preenchido
    isNewItem,              // Se é criação (true) ou edição (false)
    onSuccess: (response) => this.handleSaveSuccess(response),
    onError: (error) => this.handleSaveError(error)
  }
});

2. Processamento Automático

// BaseDomainComponent processa automaticamente:
protected onFormSubmit(data: any): void {
  const { tab, formData, isNewItem, onSuccess, onError } = data;
  
  // Auto-detecta operação baseada no contexto
  const operation = isNewItem 
    ? this.createEntity(formData)     // POST para criação
    : this.updateEntity(tab.data.id, formData);  // PUT para edição
    
  // Executa operação e chama callbacks
  operation?.subscribe({
    next: (response) => onSuccess(response),
    error: (error) => onError(error)
  });
}

🎯 Implementação por Entidade

Automática (Zero Configuração)

// Para a maioria dos casos - funciona automaticamente
export class ClientsComponent extends BaseDomainComponent<Client> {
  // ✨ Salvamento já funciona out-of-the-box!
  // Sistema detecta service.create() e service.update() automaticamente
}

Customizada (Quando Necessário)

// Para lógica específica de validação/processamento
export class VehiclesComponent extends BaseDomainComponent<Vehicle> {
  
  protected createEntity(data: any): Observable<any> {
    // Aplicar validações específicas antes de salvar
    const validatedData = this.validateVehicleData(data);
    return this.vehiclesService.createVehicle(validatedData);
  }
  
  protected updateEntity(id: any, data: any): Observable<any> {
    // Lógica de atualização customizada
    return this.vehiclesService.updateVehicleWithHistory(id, data);
  }
}

🔄 Compatibilidade com API Genérica

O salvamento genérico funciona perfeitamente com todos os métodos da API genérica:

// Qualquer abertura via API genérica tem salvamento automático
await tabSystemService.openTabWithPreset('driver', 'withDocs', driverData);
// → Formulário aberto com salvamento genérico funcionando

await tabSystemService.openTabWithSubTabs('vehicle', vehicleData, ['dados', 'documentos']);
// → Sub-abas carregadas com salvamento genérico funcionando

await tabSystemService.openTabWithPreset('client', 'complete', clientData);
// → Todas as funcionalidades incluindo salvamento automático

Callbacks Inteligentes

Sucesso no Salvamento

private onSaveSuccess(tab, response, formComponent): void {
  // ✅ Marca formulário como salvo (remove indicador "*")
  formComponent.markAsSavedSuccessfully();
  
  // ✅ Remove flag de modificação da aba
  this.tabSystemService.setTabModified(tabIndex, false);
  
  // ✅ Atualiza dados da aba com resposta do backend
  tab.data = { ...tab.data, ...response };
  
  console.log('✅ Dados salvos com sucesso');
}

Erro no Salvamento

private onSaveError(tab, error, formComponent): void {
  // ❌ Restaura estado do formulário
  formComponent.setSubmitting(false);
  
  // ❌ Pode mostrar notificação de erro
  this.showErrorNotification('Erro ao salvar dados');
  
  console.error('❌ Erro no salvamento:', error);
}

🎮 Testando Salvamento

// Teste automatizado do fluxo completo
await component.testGenericSaveFlow();

// Console logs esperados:
// "📝 Abrindo formulário para driver..."
// "✏️ Preenchendo dados..."
// "💾 Salvando dados..."
// "✅ Dados salvos com sucesso"
// "🏷️ Aba marcada como não-modificada"

🏗️ Benefícios do Sistema

  • Escalabilidade Total: Novos domínios funcionam automaticamente
  • Redução de Código: -80% de código duplicado removido
  • Arquitetura Limpa: Separação clara de responsabilidades
  • Flexibilidade: Permite customizações quando necessário
  • Consistência: Mesmo comportamento para todas as entidades
  • API Unificada: Funciona com qualquer método da API genérica

🔧 Compatibilidade

Código existente continua funcionando
Os métodos específicos (como openDriverTabWithPreset) foram mantidos para compatibilidade, mas internamente usam a nova API genérica com salvamento automático.

Migração gradual
Você pode migrar o código aos poucos, começando com novas funcionalidades e depois refatorando o código existente.

Zero Breaking Changes
Nenhuma funcionalidade foi removida ou alterada. Apenas novos métodos foram adicionados, incluindo o sistema de salvamento genérico.

Backwards Compatible
Componentes existentes que estendem BaseDomainComponent automaticamente ganham o novo sistema de salvamento.


💡 Dica: Use os métodos de teste no console do navegador para experimentar e entender melhor a API genérica e o sistema de salvamento!