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
- Reutilização: Um código serve para todas as entidades
- Consistência: Mesma interface para todos os tipos
- Manutenibilidade: Mudanças em um local afetam todos
- Escalabilidade: Fácil adicionar novas entidades
- 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!