# 🎯 RemoteSelect Component - Documentação Completa ## 📖 Visão Geral O `RemoteSelectComponent` é um componente universal de busca dinâmica que permite autocomplete e seleção de registros de qualquer domínio da aplicação PraFrota. ### ✨ Funcionalidades Principais - 🔍 **Autocomplete inteligente** com debounce configurável - ⌨️ **Navegação por teclado** (setas, Enter, Escape) - 🔑 **Tecla F2** para abrir modal de seleção completa - 📱 **Responsivo** e acessível (WCAG 2.1) - 🔄 **Reactive Forms** - implementa `ControlValueAccessor` - 💾 **Cache automático** de resultados - 🎨 **Material Design** + PraFrota Design System - ⚡ **Performance otimizada** para grandes datasets ## 🚀 Instalação e Setup ### 1. Importar o Componente ```typescript import { RemoteSelectComponent } from './shared/components/remote-select/remote-select.component'; @Component({ // ... imports: [RemoteSelectComponent] }) ``` ### 2. Configuração Básica ```typescript import { RemoteSelectConfig } from './shared/components/remote-select/interfaces/remote-select.interface'; export class YourComponent { driversConfig: RemoteSelectConfig = { service: this.driversService, searchField: 'name', displayField: 'name', valueField: 'id', modalTitle: 'Selecionar Motorista', placeholder: 'Digite o nome do motorista...' }; constructor(private driversService: DriversService) {} } ``` ### 3. Uso no Template ```html ``` ## 🎛️ API do Componente ### Inputs | Propriedade | Tipo | Padrão | Descrição | |-------------|------|--------|-----------| | `config` | `RemoteSelectConfig` | - | **Obrigatório.** Configuração do componente | | `label` | `string` | `''` | Label exibido acima do campo | | `disabled` | `boolean` | `false` | Desabilita o componente | | `required` | `boolean` | `false` | Marca o campo como obrigatório | | `hideLabel` | `boolean` | `false` | Oculta o label | ### Outputs | Evento | Tipo | Descrição | |--------|------|-----------| | `selectionChange` | `RemoteSelectEvent` | Emitido quando item é selecionado/limpo | | `searchQuery` | `string` | Emitido durante a busca (para debug) | | `modalToggle` | `boolean` | Emitido quando modal F2 abre/fecha | ### RemoteSelectConfig ```typescript interface RemoteSelectConfig { service: any; // Service com método getEntities() searchField: string; // Campo usado na busca displayField: string; // Campo mostrado na UI valueField: string; // Campo do valor retornado modalTitle?: string; // Título do modal F2 placeholder?: string; // Placeholder do input additionalFields?: string[]; // Campos extras para busca minLength?: number; // Min. caracteres (padrão: 3) debounceTime?: number; // Debounce em ms (padrão: 300) multiple?: boolean; // Seleção múltipla (padrão: false) maxResults?: number; // Max. resultados (padrão: 10) } ``` ### RemoteSelectEvent ```typescript interface RemoteSelectEvent { value: any | any[]; // Valor(es) selecionado(s) item: RemoteSelectItem | RemoteSelectItem[]; // Item(s) completo(s) source: 'dropdown' | 'modal' | 'clear'; // Origem da seleção } ``` ## 🎯 Exemplos de Uso ### 1. Busca Simples de Motoristas ```typescript // Component driversConfig: RemoteSelectConfig = { service: this.driversService, searchField: 'name', displayField: 'name', valueField: 'id', modalTitle: 'Selecionar Motorista' }; onDriverSelected(event: RemoteSelectEvent) { console.log('Motorista:', event.item); console.log('ID:', event.value); } ``` ```html ``` ### 2. Integração com Reactive Forms ```typescript // Component form = this.fb.group({ driverId: [null, Validators.required], vehicleId: [null] }); vehiclesConfig: RemoteSelectConfig = { service: this.vehiclesService, searchField: 'license_plate', displayField: 'license_plate', valueField: 'id', additionalFields: ['brand', 'model'], // Busca também em marca/modelo placeholder: 'Placa, marca ou modelo...' }; ``` ```html

Veículo selecionado: {{ form.get('vehicleId')?.value }}

``` ### 3. Busca com Múltiplos Campos ```typescript // Busca por nome, CPF ou email usersConfig: RemoteSelectConfig = { service: this.usersService, searchField: 'name', displayField: 'name', valueField: 'id', additionalFields: ['cpf', 'email'], placeholder: 'Nome, CPF ou email...', minLength: 2 }; ``` ### 4. Configuração para Formulários de Domínio ```typescript // vehicles.component.ts - Exemplo de integração getFormConfig(): TabFormConfig { return { // ... fields: [ { key: 'driver_id', label: 'Motorista Atual', type: 'remote-select', remoteConfig: { service: this.driversService, searchField: 'name', displayField: 'name', valueField: 'id', modalTitle: 'Selecionar Motorista', placeholder: 'Digite o nome...' } } ] }; } ``` ## ⌨️ Navegação por Teclado | Tecla | Ação | |-------|------| | `↓` | Navegar para próximo item | | `↑` | Navegar para item anterior | | `Enter` | Selecionar item destacado | | `Escape` | Fechar dropdown | | `F2` | Abrir modal de seleção completa | ## 🎨 Customização Visual ### Variáveis CSS Disponíveis ```scss :root { --primary-color: #ffc82e; --text-primary: #333; --text-secondary: #666; --surface-hover: #f5f5f5; --divider: #e0e0e0; --error-color: #f44336; --success-color: #4caf50; } ``` ### Classes CSS Personalizáveis ```scss .remote-select-container { // Container principal .remote-select-dropdown { // Dropdown de resultados .dropdown-item { // Itens individuais &.selected { // Item selecionado via teclado } &.highlighted { // Item já selecionado } } } } ``` ## 🔧 Requisitos do Service O service configurado deve implementar o método `getEntities()`: ```typescript interface DomainService { getEntities( page: number, pageSize: number, filters?: any ): Observable<{ data: T[]; total: number; page: number; pageSize: number; }>; } ``` ### Exemplo de Service Compatível ```typescript @Injectable({ providedIn: 'root' }) export class DriversService { getEntities(page: number, pageSize: number, filters?: any): Observable { let params = new HttpParams() .set('page', page.toString()) .set('pageSize', pageSize.toString()); // Aplicar filtros de busca if (filters) { Object.keys(filters).forEach(key => { if (filters[key]) { params = params.set(key, filters[key]); } }); } return this.http.get(`${this.apiUrl}/drivers`, { params }); } } ``` ## 📱 Responsividade ### Desktop (≥768px) - Botão F2 visível - Dropdown completo - Tooltips habilitados ### Mobile (<768px) - Botão F2 oculto - Dropdown otimizado - Touch-friendly ## 🎯 Integração com GenericTabFormComponent Para usar em formulários de domínio, adicione o tipo `remote-select`: ```typescript // generic-tab-form.component.html
``` ## 🔮 Funcionalidades Futuras ### 🚧 Em Desenvolvimento 1. **Modal F2 Completo** - Integração com DataTableComponent - Seleção múltipla com checkboxes - Filtros avançados 2. **Cache Inteligente** - Invalidação automática - Armazenamento local - Sincronização offline 3. **Validações Avançadas** - Validação de dependências - Regras de negócio customizáveis ## ⚡ Performance ### Otimizações Implementadas - **Debounce**: Evita requisições excessivas - **Cache**: Resultados armazenados automaticamente - **Virtual Scrolling**: Para listas grandes (futuro) - **Change Detection**: OnPush strategy ### Métricas Esperadas - Tempo de resposta: <200ms - Cache hit rate: >80% - Memória utilizada: <10MB ## 🧪 Testing ### Exemplo de Teste ```typescript describe('RemoteSelectComponent', () => { let component: RemoteSelectComponent; let fixture: ComponentFixture; let mockService: jasmine.SpyObj; beforeEach(() => { const spy = jasmine.createSpyObj('MockService', ['getEntities']); TestBed.configureTestingModule({ imports: [RemoteSelectComponent], providers: [ { provide: 'service', useValue: spy } ] }); mockService = TestBed.inject('service'); }); it('should search on input', fakeAsync(() => { component.config = { service: mockService, searchField: 'name', displayField: 'name', valueField: 'id' }; mockService.getEntities.and.returnValue(of({ data: [{ id: 1, name: 'João' }], total: 1 })); component.onSearchInput({ target: { value: 'João' } } as any); tick(300); expect(mockService.getEntities).toHaveBeenCalled(); expect(component.state.items.length).toBe(1); })); }); ``` ## 🔍 Debugging ### Console Logs Disponíveis ```typescript // Busca executada console.log('RemoteSelect: Busca por "joão" executada'); // Cache hit console.log('RemoteSelect: Cache hit para "joão"'); // Erro na busca console.error('RemoteSelect: Erro na busca', error); ``` ### Debug Template ```html
{{ debugRef.state | json }}
``` ## 📚 Referências - [Material Design - Text Fields](https://material.io/components/text-fields) - [WCAG 2.1 - Combobox Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/) - [Angular - ControlValueAccessor](https://angular.io/api/forms/ControlValueAccessor) --- ## 📝 Changelog ### v1.0.0 (2024-01-XX) - ✨ Implementação inicial - 🔍 Autocomplete com debounce - ⌨️ Navegação por teclado - 📱 Design responsivo - 🔄 Integração com Reactive Forms