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