# Ajuste de Dados — Filtro "Sem Código de Barras"

**Data:** 2026-05-26  
**Escopo:** Frontend only — `designar_unificado.php` + `designar_unificado.js`  
**Tipo:** Feature de filtro client-side

---

## Problema

Na tela de designação de Ajuste de Dados, o usuário precisa gerar uma missão contendo apenas produtos sem código de barras. Hoje é necessário identificar e selecionar esses produtos manualmente na lista.

## Solução

Toggle pill "Sem c. barras" que filtra a lista de produtos para exibir somente os que não possuem `codigo_barras`. O usuário aciona o toggle, a lista reduz para os produtos sem barras, seleciona os desejados (ou "Todos") e confirma a missão normalmente.

---

## Arquitetura

Mudança puramente client-side. Nenhum laboratório, sonda ou endpoint novo.

O filtro opera sobre os dados já carregados em `State.data.primary` — o mesmo mecanismo do filtro de busca textual existente. Performance garantida por pré-computação de Set no `init()`.

---

## Componentes Alterados

### `designar_unificado.php`

Adicionar toggle pill imediatamente abaixo de `#search-primary`, visível **somente quando `$tipo === 'ajuste'`**:

```html
<?php if ($tipo === 'ajuste'): ?>
<div id="filtro-sem-barras-container" style="margin-bottom: 0.75rem;">
    <button type="button"
            id="toggle-sem-barras"
            class="btn-action"
            title="Mostrar apenas produtos sem código de barras">
        <i class="bi bi-upc-scan"></i> Sem c. barras
    </button>
</div>
<?php endif; ?>
```

Estado ativo sinalizado pela classe CSS `active` no botão. Adicionar regra no `<style>` do próprio PHP:

```css
.btn-action.active {
    background: var(--dm-primary);
    border-color: var(--dm-primary);
    color: white;
}
```

---

### `designar_unificado.js`

#### 1. `State.init()` — pré-computação do Set (uma vez, O(n))

Após carregar `rawPrimaryData`, construir o Set com IDs dos produtos **sem** código de barras:

```js
// Pré-computa IDs de produtos sem código de barras
this.semBarrasIds = new Set(
    this.rawPrimaryData
        .filter(p => !p.codigo_barras)
        .map(p => String(p.id))
);
```

Garantia: o Set nunca é reconstruído após o init. Lookup posterior é O(1).

#### 2. `State.filters.primary` — novo flag

```js
filters: {
    primary:    { search: '', semCodigoBarras: false },
    operadores: { search: '' }
},
```

#### 3. `State.getFiltered()` — aplicar filtro no bloco `tipo === 'ajuste'`

Adicionar verificação após o filtro de texto existente:

```js
if (this.tipo === 'ajuste') {
    // ... filtro de texto existente (inalterado) ...

    // Filtro sem código de barras
    if (filter.semCodigoBarras && !State.semBarrasIds.has(String(item.id))) {
        return false;  // exclui quem TEM barras
    }
    return true;
}
```

#### 4. Event listener — wiring do toggle

Na seção de event listeners do controller:

```js
const toggleBtn = document.getElementById('toggle-sem-barras');
if (toggleBtn) {
    toggleBtn.addEventListener('click', () => {
        State.filters.primary.semCodigoBarras = !State.filters.primary.semCodigoBarras;
        toggleBtn.classList.toggle('active', State.filters.primary.semCodigoBarras);
        State.pagination.primary.page = 1;
        View.renderPrimary();
    });
}
```

---

## Fluxo de Dados

```
init()
  └─ rawPrimaryData → semBarrasIds (Set, one-time)

[clique no toggle]
  └─ filters.primary.semCodigoBarras = true
  └─ pagination.primary.page = 1
  └─ View.renderPrimary()
       └─ State.getPaginated('primary')
            └─ State.getFiltered('primary')
                 └─ Set.has(item.id) → exclui com barras   [O(1)/item]
            └─ slice(0, PAGE_SIZE)                          [20 itens]
       └─ container.innerHTML = cards (20 itens)

[clique novamente]
  └─ filters.primary.semCodigoBarras = false
  └─ lista volta ao estado original (com/sem busca textual)
```

---

## Comportamento

| Cenário | Resultado |
|---|---|
| Toggle OFF (padrão) | Lista completa de produtos (comportamento atual) |
| Toggle ON | Somente produtos com `codigo_barras` falsy (null, `''`, undefined) |
| Toggle ON + busca textual | Filtros cumulativos: sem barras E que contenham o texto buscado |
| Toggle ON + "Todos" | Seleciona todos os produtos visíveis (sem barras) |
| Toggle OFF após seleção | Seleção preservada; lista volta completa |

---

## Restrições

- O filtro opera somente sobre os dados carregados no init. Produtos adicionados dinamicamente (modo avulso) **não** são afetados — o toggle é ocultado no modo avulso pelo próprio container `#modo-romaneio-container`.
- Não exibe contagem de "X produtos sem barras" — a badge counter existente (`#count-primary`) já reflete os selecionados.

---

## Fora do Escopo

- Backend: nenhuma mudança em laboratórios, sondas ou rotas.
- Outros tipos de designação (separação, romaneio): toggle não renderiza.
- Modo avulso: não se aplica.
