Correção de responsividade e atualização do read.me
This commit is contained in:
114
README.md
114
README.md
@@ -1638,3 +1638,117 @@ app/javascript/controllers/validacao_controller.js (chip usa SVG, não emoji)
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>🔁 NF com mais de um lançamento + varredura de responsividade (21–22/07/2026)</strong></summary>
|
||||||
|
|
||||||
|
## Parte 1 — Editar Lançamento: quando a mesma NF tem 2 visitas
|
||||||
|
|
||||||
|
### 🎯 O problema real
|
||||||
|
Quando um plano é **duplicado** no SimpliRoute, nasce uma **visita nova** (outro `tracking_id`) com a
|
||||||
|
**mesma NF**, e a antiga continua existindo. Caso que motivou tudo: **NF 82891** com visita em
|
||||||
|
**17/07** (pendente, motorista Thiago Rabello Bittencourt) e outra em **21/07** (sucesso, sem
|
||||||
|
motorista). A tela mostrava **uma só** — e depois, por regressão, **nenhuma**.
|
||||||
|
|
||||||
|
### 🔴 Causas corrigidas (foram 7, em camadas)
|
||||||
|
1. **`Entrega.por_nf(nf).first`** — pegava uma linha só, sem `ORDER BY`. Agora carrega todas e a
|
||||||
|
tela lista as ocorrências para o ADM escolher qual editar.
|
||||||
|
2. **`SimpliRoute::Client#resolver_id` abortava na ambiguidade** (`"Mais de uma visita para a NF…"`)
|
||||||
|
em vez de deixar escolher. A tela de edição não passa mais por ele.
|
||||||
|
3. **As datas vinham só do espelho local.** Como a API **não busca NF por intervalo**, a visita de
|
||||||
|
17/07 era inalcançável se o painel só conhecia a de 21/07. Entraram campos **De/Até** + botão
|
||||||
|
**"Últimos 30 dias"** (varredura dia a dia, teto de 62 dias).
|
||||||
|
4. **Um dia com falha derrubava a busca inteira** → agora é *fail-soft* por dia: registra em
|
||||||
|
`falhas` e segue. A tela informa o período consultado e quais dias falharam.
|
||||||
|
5. **`carregar?` faltando em `EdicaoLancamentoPolicy`** → o Pundit levantava `NoMethodError` (500),
|
||||||
|
o `fetch` recebia HTML e o JS reportava "erro de conexão". Falhou **fechado** (negou acesso),
|
||||||
|
sem brecha de segurança.
|
||||||
|
6. **Tela em branco:** `renderOcorrencias()` montava a lista inteira mas **nunca removia a classe
|
||||||
|
`hidden`** do container. O conteúdo estava no DOM (contador já dizia "2 lançamentos"), invisível.
|
||||||
|
7. **Fuso horário:** `new Date('2026-07-15')` é meia-noite **UTC** e, em UTC−3, o `toLocale`
|
||||||
|
devolvia **14/07**. Datas puras agora são formatadas direto do texto ISO; horários de checkout
|
||||||
|
continuam convertendo (correto para instante).
|
||||||
|
|
||||||
|
### 🔑 Descobertas sobre a API do SimpliRoute (medidas contra a API real, 21/07/2026)
|
||||||
|
| Parâmetro | Resultado |
|
||||||
|
|---|---|
|
||||||
|
| **`&search=<NF>`** | ✅ **Funciona e não é documentado.** Um dia cai de **3,8 MB / ~9 s** (1879 visitas) para **~1 KB / ~0,6 s**. Varredura de 31 dias em lotes paralelos: **3,4 s / 3,2 KB** |
|
||||||
|
| `reference`, `reference_id`, `q`, `title`, `reference__*` | ❌ **Ignorados em silêncio** — devolvem 200 com o dia inteiro |
|
||||||
|
| `planned_date_from/to`, `since/until`, `__gte/__lte`, `date_from/to` | ❌ **Não existe filtro de intervalo** — todos devolveram 2469, idêntico ao controle **sem parâmetro nenhum** |
|
||||||
|
| `GET /v1/routes/visits/` sem `planned_date` | ⚠️ Devolve um **conjunto padrão (~2469)** que **não cobre o histórico** — para a NF 82891 voltava só a visita de 21/07 e escondia a de 17/07 |
|
||||||
|
|
||||||
|
> ⚠️ **Lição:** parâmetro não registrado no backend Django é **ignorado sem erro**. "Voltou 200 com
|
||||||
|
> resultados" **não** prova que filtrou — a prova é a **contagem diminuir** em relação ao dia sem o
|
||||||
|
> filtro. Ferramenta: **`bin/sondar_busca_nf --nf <n> --data <YYYY-MM-DD> [--sem-data]`** (só GET).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Parte 2 — Responsividade
|
||||||
|
|
||||||
|
### 🎯 A raiz comum
|
||||||
|
Os breakpoints do Tailwind (`md:`, `lg:`, `xl:`) enxergam a **janela**, mas o conteúdo perde
|
||||||
|
**256px** para a sidebar (`main.md:ml-64`). **A mesma janela de 1280px tem duas larguras** conforme
|
||||||
|
o menu esteja aberto ou recolhido — e grades de colunas fixas não ficam sabendo. Daí "quando a barra
|
||||||
|
de menu é acionada, quebra o layout". Solução: **`flex-wrap` / `auto-fit + minmax`**, que reagem ao
|
||||||
|
espaço **real**.
|
||||||
|
|
||||||
|
### 🔧 Corrigido
|
||||||
|
| Tela | Antes | Sintoma | Depois |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `consolidacoes/index` | `md:grid-cols-6` | Campos a ~150px; texto do botão **"Filtrar" vazava** para fora do fundo | `flex-wrap` + `basis-*` |
|
||||||
|
| `dashboard/index` | `xl:grid-cols-5` | **"R$ 82.692,"** — valor cortado pelo `overflow-hidden` do card | `auto-fit,minmax(13rem,1fr)` |
|
||||||
|
| `consolidacao_entregas/revisar` | `md:grid-cols-7` | 7 cards de **~55px**, destruindo "Extraordinária"/"Termo Especial" | `auto-fit,minmax(9rem,1fr)` |
|
||||||
|
| `configuracoes` + `admin/configuracoes` | `lg:grid-cols-4` | ~128px úteis para valores em moeda | `auto-fit,minmax(14rem,1fr)` |
|
||||||
|
|
||||||
|
**Mantidos de propósito:** `validar.html.erb` (`lg:grid-cols-4` é a divisão 3:1 lista/Resumo, não
|
||||||
|
grade de cards) e os `xl:grid-cols-3` de gráficos — nesses o conteúdo encolhe sem cortar.
|
||||||
|
|
||||||
|
### 📐 Passo 2 (validar) — cabeçalho fixo
|
||||||
|
Medido a 1280×577: **442px de cabeçalho contra 67px de lista** (menos que um card).
|
||||||
|
|
||||||
|
- Voltar + título + progresso passaram a **uma faixa só**; o card de progresso (70px de moldura para
|
||||||
|
uma barra de 12px) virou linha de 8px.
|
||||||
|
- **"Adicionar lançamento"** entrou na barra de ações via `order` do flex — sem mover os ~170 linhas
|
||||||
|
de modais que vivem dentro do `data-controller`.
|
||||||
|
- **Pilares (Normal/Retirada/Bônus/Desconto/Extra) continuam SEMPRE visíveis**, apenas **esmaecidos**
|
||||||
|
(`opacity-40`) enquanto não há seleção, com contador e "limpar" aparecendo ao selecionar.
|
||||||
|
⚠️ Uma versão intermediária os **escondia** até haver seleção — revertido: são a ação principal da
|
||||||
|
tela e sumir com eles esconde o que dá para fazer de quem ainda não sabe que precisa selecionar.
|
||||||
|
- Legibilidade preservada: título `text-2xl`, subtítulo e progresso `text-sm`, números em branco/negrito.
|
||||||
|
|
||||||
|
**Resultado:** cabeçalho **442px → 210px**, lista **67px → 299px**.
|
||||||
|
|
||||||
|
### 📂 Arquivos
|
||||||
|
```
|
||||||
|
app/controllers/admin/edicao_lancamentos_controller.rb # lista ocorrências, período, fail-soft, carregar
|
||||||
|
app/policies/edicao_lancamento_policy.rb # + carregar? (era o 500)
|
||||||
|
app/services/simpli_route/client.rb # visitas_da_data(data, busca:) → &search=
|
||||||
|
app/views/admin/edicao_lancamentos/show.html.erb # lista de ocorrências, De/Até, avisos, fuso
|
||||||
|
config/routes.rb # + get :carregar
|
||||||
|
bin/sondar_busca_nf # NOVO — sondagem de filtros da API (só GET)
|
||||||
|
app/views/consolidacao_entregas/validar.html.erb # cabeçalho compacto + barra de ações
|
||||||
|
app/javascript/controllers/validacao_controller.js # atualizarSelecao / limparSelecao
|
||||||
|
app/views/consolidacao_entregas/revisar.html.erb # grid-cols-7 → auto-fit
|
||||||
|
app/views/consolidacoes/index.html.erb # filtros → flex-wrap
|
||||||
|
app/views/dashboard/index.html.erb # KPIs → auto-fit
|
||||||
|
app/views/configuracoes/index.html.erb # preços → auto-fit
|
||||||
|
app/views/admin/configuracoes/index.html.erb # idem (arquivo distinto, também vivo)
|
||||||
|
```
|
||||||
|
|
||||||
|
### ⚠️ Pendências e alertas
|
||||||
|
- **Tailwind vem do Play CDN** (`cdn.tailwindcss.com`, em `application.html.erb:15`), que gera CSS no
|
||||||
|
navegador em tempo real. A documentação oficial **desaconselha em produção** (~380KB bloqueando a
|
||||||
|
renderização, recompilação a cada carregamento). O **`tailwind.config.js` do repositório não está
|
||||||
|
sendo usado** — a config real está embutida no layout (linha 17), e a gem `tailwindcss-rails` está
|
||||||
|
no Gemfile sem servir CSS.
|
||||||
|
- **Não existe teste para `Admin::EdicaoLancamentosController`** (`spec/` não tem nada de
|
||||||
|
`edicao_lancamento`). Duas das quebras acima — policy faltando e `hidden` não removido — seriam
|
||||||
|
pegas por um teste de request/sistema em segundos, sem custar deploy.
|
||||||
|
- **Token do SimpliRoute:** se passou por chat/e-mail, **rotacione** em `app2.simpliroute.com`.
|
||||||
|
|
||||||
|
> **Sem migration e sem gem nova** — controller, policy, service, views e JS.
|
||||||
|
> ⚠️ Reiniciar o Puma após o deploy (cache de classes/views).
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Controller } from "@hotwired/stimulus"
|
|||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [
|
static targets = [
|
||||||
"linha", "checkbox", "selecionarTodos", "busca", "buscaVazia",
|
"linha", "checkbox", "selecionarTodos", "busca", "buscaVazia",
|
||||||
"barraSelecao", "contadorSelecao",
|
"grupoPilares", "chipSelecao", "contadorSelecao", "btnLimpar",
|
||||||
"resumo", "listaCol", "btnResumoLabel",
|
"resumo", "listaCol", "btnResumoLabel",
|
||||||
"toggles", "barra", "barraManuais", "percentual", "chipVeiculo",
|
"toggles", "barra", "barraManuais", "percentual", "chipVeiculo",
|
||||||
"consolidarBtn", "consolidarHint",
|
"consolidarBtn", "consolidarHint",
|
||||||
@@ -102,13 +102,23 @@ export default class extends Controller {
|
|||||||
this.atualizarSelecao()
|
this.atualizarSelecao()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Barra de ações em massa: só existe quando há seleção ──
|
// ── Estado da seleção ──
|
||||||
// Sem isto os 5 botões de pilar ficavam fixos no topo o tempo todo, comendo
|
// Os pilares ficam SEMPRE na tela; sem seleção apenas esmaecem. Esconder e
|
||||||
// a altura da lista para não fazer nada (clicar sem seleção só alertava).
|
// remostrar mexia na altura do cabeçalho a cada clique e escondia a ação
|
||||||
|
// principal justamente de quem ainda não sabe que precisa selecionar antes.
|
||||||
atualizarSelecao() {
|
atualizarSelecao() {
|
||||||
const n = this.checkboxTargets.filter(c => c.checked).length
|
const n = this.checkboxTargets.filter(c => c.checked).length
|
||||||
|
|
||||||
if (this.hasContadorSelecaoTarget) this.contadorSelecaoTarget.textContent = n
|
if (this.hasContadorSelecaoTarget) this.contadorSelecaoTarget.textContent = n
|
||||||
if (this.hasBarraSelecaoTarget) this.barraSelecaoTarget.classList.toggle("hidden", n === 0)
|
if (this.hasChipSelecaoTarget) this.chipSelecaoTarget.classList.toggle("hidden", n === 0)
|
||||||
|
if (this.hasBtnLimparTarget) this.btnLimparTarget.classList.toggle("hidden", n === 0)
|
||||||
|
|
||||||
|
if (this.hasGrupoPilaresTarget) {
|
||||||
|
this.grupoPilaresTarget.classList.toggle("opacity-40", n === 0)
|
||||||
|
this.grupoPilaresTarget.title = n === 0
|
||||||
|
? "Marque ao menos uma entrega para aplicar em massa"
|
||||||
|
: `Aplicar em ${n} entrega(s) — clique de novo no pilar para remover`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
limparSelecao() {
|
limparSelecao() {
|
||||||
|
|||||||
@@ -11,7 +11,10 @@
|
|||||||
<%# Pilares de preço %>
|
<%# Pilares de preço %>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-lg font-semibold text-white mb-4 flex items-center gap-2"><%= icone :dinheiro, espaco: false %> Pilares de Preço</h2>
|
<h2 class="text-lg font-semibold text-white mb-4 flex items-center gap-2"><%= icone :dinheiro, espaco: false %> Pilares de Preço</h2>
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
<%# auto-fit: `lg:grid-cols-4` mede a JANELA, mas a sidebar come 256px do
|
||||||
|
conteúdo — os cards de preço ficavam com ~128px úteis e o valor em
|
||||||
|
moeda espremia. Aqui o número de colunas segue a largura REAL. %>
|
||||||
|
<div class="grid grid-cols-[repeat(auto-fit,minmax(14rem,1fr))] gap-4">
|
||||||
<% @configuracoes.each do |cfg| %>
|
<% @configuracoes.each do |cfg| %>
|
||||||
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6 group relative">
|
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6 group relative">
|
||||||
<div class="flex items-start justify-between mb-4">
|
<div class="flex items-start justify-between mb-4">
|
||||||
|
|||||||
@@ -11,7 +11,10 @@
|
|||||||
<%# Pilares de preço %>
|
<%# Pilares de preço %>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-lg font-semibold text-white mb-4 flex items-center gap-2"><%= icone :dinheiro, espaco: false %> Pilares de Preço</h2>
|
<h2 class="text-lg font-semibold text-white mb-4 flex items-center gap-2"><%= icone :dinheiro, espaco: false %> Pilares de Preço</h2>
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
<%# auto-fit: `lg:grid-cols-4` mede a JANELA, mas a sidebar come 256px do
|
||||||
|
conteúdo — os cards de preço ficavam com ~128px úteis e o valor em
|
||||||
|
moeda espremia. Aqui o número de colunas segue a largura REAL. %>
|
||||||
|
<div class="grid grid-cols-[repeat(auto-fit,minmax(14rem,1fr))] gap-4">
|
||||||
<% @configuracoes.each do |cfg| %>
|
<% @configuracoes.each do |cfg| %>
|
||||||
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6 group relative">
|
<div class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-6 group relative">
|
||||||
<div class="flex items-start justify-between mb-4">
|
<div class="flex items-start justify-between mb-4">
|
||||||
|
|||||||
@@ -11,8 +11,11 @@
|
|||||||
<p class="text-gray-400 text-sm"><%= @consolidacao.nome %></p>
|
<p class="text-gray-400 text-sm"><%= @consolidacao.nome %></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%# Resumo por tipo %>
|
<%# Resumo por tipo — auto-fit em vez de `md:grid-cols-7`.
|
||||||
<div class="grid grid-cols-2 md:grid-cols-7 gap-3 mb-6">
|
Sete colunas fixas a partir de 768px dão ~55px cada quando a sidebar está
|
||||||
|
aberta (768 − 256 de menu − padding), destruindo rótulos como
|
||||||
|
"Extraordinária" e "Termo Especial". O mínimo de 9rem cabe o maior rótulo. %>
|
||||||
|
<div class="grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-3 mb-6">
|
||||||
<% [
|
<% [
|
||||||
['entrega_normal', 'Normal', 'bg-orange-500 text-black'],
|
['entrega_normal', 'Normal', 'bg-orange-500 text-black'],
|
||||||
['retirada', 'Retirada', 'bg-orange-800 text-white'],
|
['retirada', 'Retirada', 'bg-orange-800 text-white'],
|
||||||
|
|||||||
@@ -147,14 +147,39 @@
|
|||||||
abaixo, que carrega os modais) entra NESTA mesma faixa via flex `order`,
|
abaixo, que carrega os modais) entra NESTA mesma faixa via flex `order`,
|
||||||
sem precisar mover os modais de lugar. %>
|
sem precisar mover os modais de lugar. %>
|
||||||
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl px-3 py-2 mb-2 flex flex-wrap items-center gap-x-3 gap-y-2">
|
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl px-3 py-2 mb-2 flex flex-wrap items-center gap-x-3 gap-y-2">
|
||||||
<label class="order-1 flex items-center gap-2 text-gray-300 text-sm cursor-pointer select-none h-11">
|
<label class="order-1 flex items-center gap-2 text-gray-300 text-sm cursor-pointer select-none h-11 whitespace-nowrap">
|
||||||
<input type="checkbox" data-validacao-target="selecionarTodos"
|
<input type="checkbox" data-validacao-target="selecionarTodos"
|
||||||
data-action="change->validacao#selecionarTodos"
|
data-action="change->validacao#selecionarTodos"
|
||||||
class="rounded text-orange-500 bg-[#0a0a0a] border-[#2a2a2a] w-5 h-5">
|
class="rounded text-orange-500 bg-[#0a0a0a] border-[#2a2a2a] w-5 h-5">
|
||||||
Selecionar todos
|
Selecionar
|
||||||
|
<%# Contador aparece só quando há seleção — é o retorno visual de que os
|
||||||
|
pilares saíram do estado inerte. %>
|
||||||
|
<span data-validacao-target="chipSelecao"
|
||||||
|
class="hidden px-2 py-0.5 rounded-full bg-orange-500 text-black text-xs font-bold"><span data-validacao-target="contadorSelecao">0</span></span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="order-3 ml-auto flex items-center gap-2">
|
<%# Pilares SEMPRE visíveis: são a ação principal da tela e o ADM precisa
|
||||||
|
vê-los para saber o que pode fazer. Sem seleção eles ficam esmaecidos
|
||||||
|
(não escondidos) — a versão anterior os removia do DOM e obrigava a
|
||||||
|
descobrir que existiam depois de marcar algo. %>
|
||||||
|
<div data-validacao-target="grupoPilares"
|
||||||
|
class="order-2 flex items-center gap-1.5 flex-wrap opacity-40 transition-opacity"
|
||||||
|
title="Marque ao menos uma entrega para aplicar em massa">
|
||||||
|
<button data-action="click->validacao#marcarSelecionados" data-tipo="entrega_normal"
|
||||||
|
class="bg-orange-500 text-black font-bold px-3 h-11 rounded-lg text-xs">Normal</button>
|
||||||
|
<button data-action="click->validacao#marcarSelecionados" data-tipo="retirada"
|
||||||
|
class="bg-orange-800 text-white font-bold px-3 h-11 rounded-lg text-xs">Retirada</button>
|
||||||
|
<button data-action="click->validacao#marcarSelecionados" data-tipo="bonus"
|
||||||
|
class="bg-white text-black font-bold px-3 h-11 rounded-lg text-xs border border-orange-500">Bônus</button>
|
||||||
|
<button data-action="click->validacao#marcarSelecionados" data-tipo="desconto"
|
||||||
|
class="bg-black text-white font-bold px-3 h-11 rounded-lg text-xs border border-gray-700">Desconto</button>
|
||||||
|
<button data-action="click->validacao#marcarSelecionados" data-tipo="extraordinaria"
|
||||||
|
class="bg-purple-600 text-white font-bold px-3 h-11 rounded-lg text-xs">Extra</button>
|
||||||
|
<button type="button" data-action="validacao#limparSelecao" data-validacao-target="btnLimpar"
|
||||||
|
class="hidden text-gray-400 hover:text-white text-xs underline px-1">limpar</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="order-4 ml-auto flex items-center gap-2">
|
||||||
<%# Oculta/mostra o resumo lateral (mais largura para a lista) %>
|
<%# Oculta/mostra o resumo lateral (mais largura para a lista) %>
|
||||||
<button type="button" data-action="validacao#toggleResumo"
|
<button type="button" data-action="validacao#toggleResumo"
|
||||||
class="text-gray-400 hover:text-white text-sm border border-[#2a2a2a] hover:border-orange-500 px-3 h-11 rounded-lg whitespace-nowrap">
|
class="text-gray-400 hover:text-white text-sm border border-[#2a2a2a] hover:border-orange-500 px-3 h-11 rounded-lg whitespace-nowrap">
|
||||||
@@ -172,7 +197,7 @@
|
|||||||
Fica DENTRO da barra de ações (order-2) para não custar uma linha própria;
|
Fica DENTRO da barra de ações (order-2) para não custar uma linha própria;
|
||||||
os modais são `fixed`, então não afetam o layout da faixa. %>
|
os modais são `fixed`, então não afetam o layout da faixa. %>
|
||||||
<% unless @consolidacao.finalizada? && current_user.operador? %>
|
<% unless @consolidacao.finalizada? && current_user.operador? %>
|
||||||
<div class="order-2 relative"
|
<div class="order-3 relative"
|
||||||
data-controller="ferramentas apontamento-manual apontamento-termo"
|
data-controller="ferramentas apontamento-manual apontamento-termo"
|
||||||
data-apontamento-manual-apontar-manual-url-value="<%= apontar_manual_consolidacao_consolidacao_entregas_path(@consolidacao) %>"
|
data-apontamento-manual-apontar-manual-url-value="<%= apontar_manual_consolidacao_consolidacao_entregas_path(@consolidacao) %>"
|
||||||
data-apontamento-termo-apontar-termo-url-value="<%= apontar_termo_consolidacao_consolidacao_entregas_path(@consolidacao) %>"
|
data-apontamento-termo-apontar-termo-url-value="<%= apontar_termo_consolidacao_consolidacao_entregas_path(@consolidacao) %>"
|
||||||
@@ -346,31 +371,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<%# Fim da barra de ações %>
|
<%# Fim da barra de ações %>
|
||||||
|
|
||||||
<%# Ações em massa — SÓ aparecem quando há entregas selecionadas. Ocupavam
|
|
||||||
160px fixos para botões que, sem seleção, respondiam com um alerta
|
|
||||||
pedindo para selecionar algo. %>
|
|
||||||
<div data-validacao-target="barraSelecao"
|
|
||||||
class="hidden bg-orange-500/10 border border-orange-500/40 rounded-xl px-3 py-2 mb-2 flex flex-wrap items-center gap-x-3 gap-y-2">
|
|
||||||
<span class="text-sm text-white font-semibold whitespace-nowrap">
|
|
||||||
<span data-validacao-target="contadorSelecao">0</span> selecionada(s)
|
|
||||||
</span>
|
|
||||||
<span class="text-gray-400 text-xs">aplicar <span class="hidden sm:inline">(clique de novo p/ remover)</span>:</span>
|
|
||||||
<div class="flex items-center gap-2 flex-wrap">
|
|
||||||
<button data-action="click->validacao#marcarSelecionados" data-tipo="entrega_normal"
|
|
||||||
class="bg-orange-500 text-black font-bold px-3 h-11 rounded-lg text-xs">Normal</button>
|
|
||||||
<button data-action="click->validacao#marcarSelecionados" data-tipo="retirada"
|
|
||||||
class="bg-orange-800 text-white font-bold px-3 h-11 rounded-lg text-xs">Retirada</button>
|
|
||||||
<button data-action="click->validacao#marcarSelecionados" data-tipo="bonus"
|
|
||||||
class="bg-white text-black font-bold px-3 h-11 rounded-lg text-xs border border-orange-500">Bônus</button>
|
|
||||||
<button data-action="click->validacao#marcarSelecionados" data-tipo="desconto"
|
|
||||||
class="bg-black text-white font-bold px-3 h-11 rounded-lg text-xs border border-gray-700">Desconto</button>
|
|
||||||
<button data-action="click->validacao#marcarSelecionados" data-tipo="extraordinaria"
|
|
||||||
class="bg-purple-600 text-white font-bold px-3 h-11 rounded-lg text-xs">Extra</button>
|
|
||||||
</div>
|
|
||||||
<button type="button" data-action="validacao#limparSelecao"
|
|
||||||
class="ml-auto text-gray-400 hover:text-white text-xs underline whitespace-nowrap">limpar seleção</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<%# Fim do cabeçalho fixo — abaixo só a lista de NFs rola. %>
|
<%# Fim do cabeçalho fixo — abaixo só a lista de NFs rola. %>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user