diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a3c0faa..d559828 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,19 +2,105 @@ module ApplicationHelper include Pagy::Frontend + # --------------------------------------------------------------------------- + # Ícones + # + # Substituem os emojis antigos (que davam aparência "genérica de IA" e variavam + # de forma/cor conforme o sistema operacional). Agora são SVG chapados vindos do + # sprite em public/icons.svg (subset do Bootstrap Icons, licença MIT). + # + # O SVG usa `currentColor`, então a cor vem da classe CSS: + # - padrão → laranja da marca (#f97316) + # - ícones de status → passe `cor:` para preservar a leitura semântica + # (ex.: icone(:sucesso, cor: "text-green-400")) + # --------------------------------------------------------------------------- + + # Nome semântico (pt-BR) → id do símbolo no sprite. + ICONES = { + # Navegação + dashboard: "bar-chart-fill", operacoes: "graph-up-arrow", consolidacoes: "box-seam-fill", + arquivadas: "folder-fill", painel: "house-fill", usuarios: "people-fill", + configuracoes: "gear-fill", auditoria: "search", planilha: "box-arrow-in-down", + editar_lancamento: "pencil-fill", sair: "box-arrow-right", menu: "list", + # Domínio + caminhao: "truck", veiculo: "car-front-fill", motorista: "person-badge-fill", + dinheiro: "cash-coin", pagamento: "cash-stack", custo: "cash", + consolidado_pago: "briefcase-fill", calendario: "calendar-event", nota_fiscal: "receipt", + documento: "file-earmark-text-fill", termo_especial: "clipboard-data-fill", + apontamento: "pencil-square", local: "geo-alt-fill", operacao: "hospital-fill", + retirada: "box-seam-fill", desconto: "exclamation-triangle-fill", + global: "globe2", comparar: "arrow-left-right", pessoa: "person-fill", + ticket: "ticket-perforated-fill", tag: "tag-fill", composicao: "puzzle-fill", + ranking: "trophy-fill", historico: "clock-history", relogio: "clock-fill", + parcial: "hourglass-split", diario: "journal-text", vazio: "inbox", + dica: "lightbulb-fill", bonus: "star-fill", extraordinaria: "stars", + calor: "fire", foto: "camera-fill", mapa: "map-fill", + satelite: "broadcast-pin", escuro: "moon-fill", tela_cheia: "arrows-fullscreen", + email: "envelope-fill", telefone: "telephone-fill", chave: "key-fill", + # Ações + adicionar: "plus-lg", fechar: "x-lg", confirmar: "check-lg", + buscar: "search", editar: "pencil-fill", excluir: "trash-fill", + arquivar: "archive-fill", restaurar: "arrow-clockwise", salvar: "floppy-fill", + imprimir: "printer-fill", visualizar: "eye-fill", baixar: "download", + pasta: "folder2-open", travado: "lock-fill", destravado: "unlock-fill", + expandir: "chevron-down", recolher: "chevron-left", + voltar: "arrow-left", avancar: "arrow-right", estornar: "arrow-counterclockwise", + # Status (use sempre com `cor:` semântica) + sucesso: "check-circle-fill", alerta: "exclamation-triangle-fill", + erro: "x-circle-fill", desconhecido: "question-circle", + cancelado: "slash-circle", ponto: "circle-fill", ponto_vazio: "circle" + }.freeze + + # Renderiza um ícone do sprite. + # + # icone(:caminhao) # laranja da marca + # icone(:sucesso, cor: "text-green-400") # status verde + # icone(:fechar, cor: nil) # herda a cor do elemento pai + # icone(:dashboard, titulo: "Painel") # acessível (vira role="img") + def icone(nome, cor: "text-brand-laranja", tamanho: "w-[1.05em] h-[1.05em]", classe: nil, titulo: nil) + simbolo = ICONES.fetch(nome.to_sym) { nome.to_s } + css = ["inline-block align-[-0.125em] shrink-0", tamanho, cor, classe].compact.join(" ") + + tag.svg(class: css, fill: "currentColor", role: (titulo ? "img" : nil), + aria: { hidden: (titulo ? nil : true), label: titulo }) do + tag.use(href: "/icons.svg##{simbolo}") + end + end + + # Rótulo "ícone + texto" para link_to / button_to (que recebem o label como + # argumento, onde não dá para escrever ERB). + # + # link_to rotulo(:salvar, 'Salvar rascunho'), caminho, class: '...' + # + # Atenção: NÃO serve para `f.submit` nem `button_to` sem bloco — ambos geram + # , que não aceita HTML dentro. Nesses casos use + # `button_tag`/`button_to ... do`. + def rotulo(nome, texto, cor: "text-brand-laranja", tamanho: "w-4 h-4") + safe_join([icone(nome, cor: cor, tamanho: tamanho), texto], " ") + end + # Opções [label, valor] para o select de perfil de usuário (form de usuário) def role_options_for_select User::ROLES_LABEL.map { |value, label| [label, value] } end - # Link de navegação com estado ativo - def nav_link_to(label, path, **opts) + # Link de navegação com estado ativo. + # `icon:` aceita um nome semântico de ICONES; no estado ativo o ícone herda o + # preto do fundo laranja, fora dele fica laranja da marca. + def nav_link_to(label, path, icon: nil, **opts) active = current_page?(path) css = [ - "flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px]", + "flex items-center gap-2.5 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px]", active ? "bg-orange-500 text-black" : "text-gray-400 hover:bg-[#1a1a1a] hover:text-white" ].join(" ") - link_to label, path, class: css + + conteudo = if icon + safe_join([icone(icon, cor: (active ? "text-black" : "text-brand-laranja"), + tamanho: "w-4 h-4"), label]) + else + label + end + link_to conteudo, path, class: css end # Formata moeda BR (milhar com ".", decimais com ","): R$ 1.234,56 @@ -22,31 +108,34 @@ module ApplicationHelper number_to_currency(valor.to_f, unit: 'R$ ', separator: ',', delimiter: '.', precision: 2) end - # Badge de status de consolidação + # Badge de status de consolidação. + # O ícone herda a cor do texto do badge (cor: nil) para não brigar com o fundo. def badge_status(status) cfg = case status.to_s - when 'rascunho' then { cor: 'bg-yellow-500 text-black', icone: '📝', label: 'Rascunho' } - when 'finalizada' then { cor: 'bg-green-600 text-white', icone: '✅', label: 'Finalizada' } - when 'arquivada' then { cor: 'bg-gray-700 text-gray-300', icone: '📁', label: 'Arquivada' } - else { cor: 'bg-gray-800 text-gray-400', icone: '❓', label: status.humanize } + when 'rascunho' then { cor: 'bg-yellow-500 text-black', icone: :apontamento, label: 'Rascunho' } + when 'finalizada' then { cor: 'bg-green-600 text-white', icone: :sucesso, label: 'Finalizada' } + when 'arquivada' then { cor: 'bg-gray-700 text-gray-300', icone: :arquivar, label: 'Arquivada' } + else { cor: 'bg-gray-800 text-gray-400', icone: :desconhecido, label: status.humanize } end - tag.span class: "inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-bold #{cfg[:cor]}" do - "#{cfg[:icone]} #{cfg[:label]}" - end + badge_com_icone(cfg) end # Badge de status de pagamento de uma consolidação (derivado dos motoristas) def badge_pagamento(status) cfg = case status.to_s - when 'pago' then { cor: 'bg-green-600 text-white', icone: '💰', label: 'Pago' } - when 'parcial' then { cor: 'bg-yellow-500 text-black', icone: '⏳', label: 'Parcial' } - when 'pendente' then { cor: 'bg-gray-700 text-gray-300', icone: '🕗', label: 'Pendente' } - else { cor: 'bg-gray-800 text-gray-400', icone: '❓', label: status.to_s.humanize } + when 'pago' then { cor: 'bg-green-600 text-white', icone: :dinheiro, label: 'Pago' } + when 'parcial' then { cor: 'bg-yellow-500 text-black', icone: :parcial, label: 'Parcial' } + when 'pendente' then { cor: 'bg-gray-700 text-gray-300', icone: :relogio, label: 'Pendente' } + else { cor: 'bg-gray-800 text-gray-400', icone: :desconhecido, label: status.to_s.humanize } end - tag.span class: "inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-bold #{cfg[:cor]}" do - "#{cfg[:icone]} #{cfg[:label]}" + badge_com_icone(cfg) + end + + def badge_com_icone(cfg) + tag.span class: "inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-bold #{cfg[:cor]}" do + safe_join([icone(cfg[:icone], cor: nil, tamanho: "w-3.5 h-3.5"), cfg[:label]]) end end diff --git a/app/javascript/controllers/validacao_controller.js b/app/javascript/controllers/validacao_controller.js index e75c130..3b1245c 100644 --- a/app/javascript/controllers/validacao_controller.js +++ b/app/javascript/controllers/validacao_controller.js @@ -263,10 +263,12 @@ export default class extends Controller { const lock = chip.querySelector("[data-chip-lock]") if (feito) feito.textContent = dados.classificadas if (total) total.textContent = dados.eligible - if (check) check.textContent = dados.completo ? "✓" : "" + // O check e o cadeado agora são fixos no HTML — alterna a visibilidade + // em vez de trocar textContent (que apagaria o SVG). + if (check) check.classList.toggle("hidden", !dados.completo) if (lock) lock.classList.toggle("hidden", !dados.fechado) - // Cor determinística: selecionado(laranja) > consolidado(verde+🔒) > + // Cor determinística: selecionado(laranja) > consolidado(cadeado+verde) > // pronto(verde) > arquivado(cinza) > neutro. chip.classList.remove(...TODAS) if (this.veiculosValue.includes(chip.dataset.vehicle)) { diff --git a/app/views/admin/auditoria_logs/index.html.erb b/app/views/admin/auditoria_logs/index.html.erb index 7f5aaa8..45f70c5 100644 --- a/app/views/admin/auditoria_logs/index.html.erb +++ b/app/views/admin/auditoria_logs/index.html.erb @@ -1,7 +1,7 @@ <%# app/views/admin/auditoria_logs/index.html.erb %> <% content_for :title, 'Auditoria' %> -

🔍 Auditoria

+

<%= icone :auditoria %> Auditoria

<%= form_with url: admin_auditoria_logs_path, method: :get, class: 'bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-4 mb-6 flex flex-wrap gap-3' do %> diff --git a/app/views/admin/configuracoes/index.html.erb b/app/views/admin/configuracoes/index.html.erb index 4661a99..0ba6c12 100644 --- a/app/views/admin/configuracoes/index.html.erb +++ b/app/views/admin/configuracoes/index.html.erb @@ -10,7 +10,7 @@ <%# Pilares de preço %>
-

💰 Pilares de Preço

+

<%= icone :dinheiro %> Pilares de Preço

<% @configuracoes.each do |cfg| %>
@@ -39,7 +39,7 @@ <%# Informações do banco externo %>
-

🗄️ Banco de Dados Externo

+

<%= icone :arquivar %> Banco de Dados Externo

Tabela monitorada

diff --git a/app/views/admin/edicao_lancamentos/show.html.erb b/app/views/admin/edicao_lancamentos/show.html.erb index 20a8158..5dd0520 100644 --- a/app/views/admin/edicao_lancamentos/show.html.erb +++ b/app/views/admin/edicao_lancamentos/show.html.erb @@ -20,8 +20,8 @@ <%# Aviso de sincronização %>
- ⚠️ -

As alterações são gravadas no SimpliRoute na hora (cada campo salva ao confirmar ✓), + <%= icone :alerta, cor: nil, tamanho: 'w-4 h-4 mt-0.5' %> +

As alterações são gravadas no SimpliRoute na hora (cada campo salva ao confirmar <%= icone :confirmar, cor: nil, tamanho: 'w-3 h-3' %>), mas o painel e as consolidações só refletem após a próxima sincronização da base de rastreio. Toda alteração fica registrada na auditoria.

@@ -57,15 +57,15 @@
NF Visita - 🚚 - 🚗 - 📞 + <%= icone :caminhao %> + <%= icone :veiculo %> + <%= icone :telefone %>
@@ -96,9 +96,9 @@
-

🕑 Histórico de alterações

+

<%= icone :historico %> Histórico de alterações

+ class="w-9 h-9 rounded-lg bg-white/5 hover:bg-white/10 text-gray-300" aria-label="Fechar"><%= icone :fechar, cor: nil, tamanho: 'w-4 h-4' %>
'; } const extras = [...(visita.pictures || [])]; @@ -257,7 +263,7 @@ '

' + esc(def.label) + '

' + '
' + '

' + esc(valorExibicao(def)) + '

' + - '✏️' + + '' + ico('pencil-fill') + '' + '
'; div.onclick = () => abrirEdicao(div, def); if (flash) { @@ -297,8 +303,8 @@ '

' + esc(def.label) + '

' + editorHtml + '
' + - '' + - '' + + '' + + '' + '' + '
' + ''; @@ -388,7 +394,7 @@ function htmlHistorico(data) { let html = '
' + - '

📒 Nosso sistema (auditoria)

'; + '

' + ico('journal-text') + ' Nosso sistema (auditoria)

'; const interno = (data.interno || []); if (!interno.length) { html += '

Nenhuma alteração registrada pelo sistema.

'; @@ -400,14 +406,14 @@ ' → ' + esc(fmtValor(campo, l.para[campo])) + '').join(''); return '
' + '
' + - '👤 ' + esc(l.usuario) + '' + esc(l.quando) + '' + + '' + ico('person-fill') + ' ' + esc(l.usuario) + '' + esc(l.quando) + '' + '
' + '
    ' + (mudancas || '
  • ') + '
' + '
'; }).join(''); } html += '
' + - '

🌐 SimpliRoute (API)

'; + '

' + ico('globe2') + ' SimpliRoute (API)

'; const api = (data.api || []); if (!api.length) { html += '

Sem registros de histórico na API do SimpliRoute.

'; diff --git a/app/views/admin/planilhas_simpli_route/show.html.erb b/app/views/admin/planilhas_simpli_route/show.html.erb index 70a8eb3..190c32b 100644 --- a/app/views/admin/planilhas_simpli_route/show.html.erb +++ b/app/views/admin/planilhas_simpli_route/show.html.erb @@ -43,7 +43,7 @@ <% end %> <% end %> diff --git a/app/views/admin/usuarios/index.html.erb b/app/views/admin/usuarios/index.html.erb index b9f6139..ae63790 100644 --- a/app/views/admin/usuarios/index.html.erb +++ b/app/views/admin/usuarios/index.html.erb @@ -103,7 +103,7 @@ <% if @usuarios.empty? %> -
👥
+
<%= icone :usuarios, tamanho: 'w-10 h-10', cor: 'text-gray-600' %>

Nenhum usuário encontrado.

diff --git a/app/views/configuracoes/index.html.erb b/app/views/configuracoes/index.html.erb index 1e985c8..2350bd9 100644 --- a/app/views/configuracoes/index.html.erb +++ b/app/views/configuracoes/index.html.erb @@ -10,7 +10,7 @@ <%# Pilares de preço %>
-

💰 Pilares de Preço

+

<%= icone :dinheiro %> Pilares de Preço

<% @configuracoes.each do |cfg| %>
@@ -39,7 +39,7 @@ <%# Informações do banco externo %>
-

🗄️ Banco de Dados Externo

+

<%= icone :arquivar %> Banco de Dados Externo

Tabela monitorada

diff --git a/app/views/consolidacao_entregas/revisar.html.erb b/app/views/consolidacao_entregas/revisar.html.erb index c5dc270..bdf75d0 100644 --- a/app/views/consolidacao_entregas/revisar.html.erb +++ b/app/views/consolidacao_entregas/revisar.html.erb @@ -4,10 +4,10 @@
- <%= link_to '← Voltar (Passo 2)', + <%= link_to rotulo(:voltar, 'Voltar (Passo 2)', cor: nil), validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista), class: 'inline-flex items-center gap-1 bg-[#1a1a1a] hover:bg-[#2a2a2a] text-white border border-[#2a2a2a] hover:border-orange-500 font-semibold px-4 py-2.5 rounded-lg text-sm min-h-[44px]' %> -

📋 Revisão — <%= @motorista %>

+

<%= icone :planilha %> Revisão — <%= @motorista %>

<%= @consolidacao.nome %>

@@ -71,19 +71,20 @@ <%= c.tipo_cor[:label] %><% if (c.termo? || c.termo_especial?) && c.quantidade > 1 %> ×<%= c.quantidade %><% end %> <% if c.manual? %> - ➕ Apontamento + <%= icone :adicionar, cor: nil, tamanho: 'w-3 h-3' %> Apontamento <% end %>
<%= c.desconto? ? '-' : '' %><%= moeda(c.valor_aplicado) %> <% if c.manual? && !(@consolidacao.finalizada? && current_user.operador?) %> - <%= button_to '✕', - remover_apontamento_consolidacao_consolidacao_entregas_path(@consolidacao, id: c.id, motorista: @motorista), + <%= button_to remover_apontamento_consolidacao_consolidacao_entregas_path(@consolidacao, id: c.id, motorista: @motorista), method: :delete, form: { data: { turbo_confirm: 'Remover este apontamento manual?' } }, - class: 'text-gray-500 hover:text-red-400 text-sm leading-none px-1', - title: 'Remover apontamento' %> + class: 'text-gray-500 hover:text-red-400 leading-none px-1', + title: 'Remover apontamento' do %> + <%= icone :fechar, cor: nil, tamanho: 'w-3.5 h-3.5' %> + <% end %> <% end %>
@@ -127,11 +128,11 @@ <%# Ações finais %>
<% if @proximo %> - <%= link_to "Próximo motorista: #{@proximo} →", + <%= link_to safe_join(["Próximo motorista: #{@proximo}", icone(:avancar, cor: nil)], ' '), validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @proximo), class: 'flex-1 bg-orange-500 hover:bg-orange-600 text-black font-bold py-3.5 rounded-lg min-h-[48px] flex items-center justify-center text-center' %> <% end %> - <%= link_to '💾 Salvar rascunho e voltar', wizard_consolidacao_path(@consolidacao), + <%= link_to rotulo(:salvar, 'Salvar rascunho e voltar', cor: nil), wizard_consolidacao_path(@consolidacao), class: 'flex-1 bg-[#1a1a1a] hover:bg-[#2a2a2a] text-white border border-[#2a2a2a] font-bold py-3.5 rounded-lg min-h-[48px] flex items-center justify-center' %>
diff --git a/app/views/consolidacao_entregas/validar.html.erb b/app/views/consolidacao_entregas/validar.html.erb index 1bff40e..8c36a79 100644 --- a/app/views/consolidacao_entregas/validar.html.erb +++ b/app/views/consolidacao_entregas/validar.html.erb @@ -18,10 +18,10 @@ class: 'inline-flex items-center gap-1 bg-[#1a1a1a] hover:bg-[#2a2a2a] text-white border border-[#2a2a2a] hover:border-orange-500 font-semibold px-4 py-2.5 rounded-lg text-sm min-h-[44px]' %>
-

🚚 <%= @motorista %>

+

<%= icone :caminhao %> <%= @motorista %>

<%= @consolidacao.nome %> · <%= l @consolidacao.data_inicio, format: :short %> → <%= l @consolidacao.data_fim, format: :short %>

- <%= link_to 'Revisar (Passo 3) →', + <%= link_to safe_join(['Revisar (Passo 3)', icone(:avancar, cor: nil)], ' '), revisar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista), class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-5 py-3 rounded-lg min-h-[48px] flex items-center' %>
@@ -31,7 +31,7 @@
- <% if @veiculos_sel.any? %>🚚 <%= @veiculos_sel.join(', ') %> — <% end %> + <% if @veiculos_sel.any? %><%= icone :caminhao %> <%= @veiculos_sel.join(', ') %> — <% end %> <%= @classificadas %> de <%= @total_entregas %> entregas classificadas · @@ -53,8 +53,8 @@ <% if @veiculos_status.size > 1 %>
- 🚗 Fechar por veículo: - clique no nome para filtrar; consolide o carro quando estiver 100% (🔒) + <%= icone :veiculo %> Fechar por veículo: + clique no nome para filtrar; consolide o carro quando estiver 100% (<%= icone :travado, cor: nil, tamanho: 'w-3 h-3' %>)
<%# Chip "Todos" — limpa a seleção (mostra todos os carros) %> @@ -68,7 +68,7 @@ <% selecionado = @veiculos_sel.include?(v[:vehicle]) %> <%# Alterna este veículo dentro da seleção atual (multi-seleção) %> <% nova_sel = selecionado ? (@veiculos_sel - [v[:vehicle]]) : (@veiculos_sel + [v[:vehicle]]) %> - <%# Cor determinística: selecionado(laranja) > consolidado(verde+🔒) > + <%# Cor determinística: selecionado(laranja) > consolidado(verde+cadeado) > pronto(verde) > arquivado(cinza tracejado) > neutro. %> <% cor = if selecionado then 'border-orange-500 text-orange-400 bg-orange-500/10' elsif v[:fechado] then 'border-green-500 text-green-400 bg-green-500/10' @@ -78,11 +78,11 @@ <%= link_to validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista, vehicle: nova_sel.presence), data: { 'validacao-target': 'chipVeiculo', vehicle: v[:vehicle], eligible: v[:eligible] }, class: "px-3 py-2 rounded-lg text-sm font-semibold border min-h-[40px] flex items-center gap-2 transition-colors #{cor}" do %> - 🔒 + <%= icone :travado, cor: nil, tamanho: 'w-3 h-3' %> <%= v[:vehicle] %> <%= v[:classificadas] %>/<%= v[:eligible] %> - <%= '✓' if v[:completo] %> + <%= icone :confirmar, cor: nil, tamanho: 'w-3 h-3' %> <% end %> <% end %> @@ -97,32 +97,35 @@

Selecione um veículo (clique no nome) para consolidá-lo separadamente.

<% elsif status_unico[:fechado] %>
- 🔒 <%= sel_unico %> consolidado. - <%= button_to '🔓 Reabrir veículo', - reabrir_veiculo_consolidacao_consolidacao_entregas_path(@consolidacao), + <%= icone :travado, cor: nil %> <%= sel_unico %> consolidado. + <%= button_to reabrir_veiculo_consolidacao_consolidacao_entregas_path(@consolidacao), method: :post, params: { motorista: @motorista, vehicle: sel_unico, vehicle_sel: @veiculos_sel }, - data: { turbo_confirm: "Reabrir o veículo #{sel_unico} para edição?" }, - class: 'text-gray-400 hover:text-white border border-[#2a2a2a] hover:border-orange-500 px-3 py-2 rounded-lg text-xs min-h-[40px]' %> + form: { data: { turbo_confirm: "Reabrir o veículo #{sel_unico} para edição?" } }, + class: 'text-gray-400 hover:text-white border border-[#2a2a2a] hover:border-orange-500 px-3 py-2 rounded-lg text-xs min-h-[40px] inline-flex items-center gap-1.5' do %> + <%= icone :destravado, cor: nil, tamanho: 'w-3.5 h-3.5' %> Reabrir veículo + <% end %>
<% else %>
<%# Habilita só quando o carro está 100% classificado; o JS liga/desliga conforme a barra do escopo selecionado chega (ou não) a 100%. %> - <%= button_to '🔒 Consolidar este veículo', - fechar_veiculo_consolidacao_consolidacao_entregas_path(@consolidacao), + <%= button_to fechar_veiculo_consolidacao_consolidacao_entregas_path(@consolidacao), method: :post, params: { motorista: @motorista, vehicle: sel_unico, vehicle_sel: @veiculos_sel }, disabled: !status_unico[:completo], - data: { 'validacao-target': 'consolidarBtn', - turbo_confirm: "Consolidar o veículo #{sel_unico}? Você poderá reabrir depois." }, - class: "font-bold px-4 py-2 rounded-lg text-xs min-h-[40px] #{status_unico[:completo] ? 'bg-green-600 hover:bg-green-500 text-white cursor-pointer' : 'bg-[#2a2a2a] text-gray-600 cursor-not-allowed'}" %> - <%= button_to '🗄️ Arquivar veículo', - arquivar_veiculo_consolidacao_consolidacao_entregas_path(@consolidacao), + data: { 'validacao-target': 'consolidarBtn' }, + form: { data: { turbo_confirm: "Consolidar o veículo #{sel_unico}? Você poderá reabrir depois." } }, + class: "font-bold px-4 py-2 rounded-lg text-xs min-h-[40px] inline-flex items-center gap-1.5 #{status_unico[:completo] ? 'bg-green-600 hover:bg-green-500 text-white cursor-pointer' : 'bg-[#2a2a2a] text-gray-600 cursor-not-allowed'}" do %> + <%= icone :travado, cor: nil, tamanho: 'w-3.5 h-3.5' %> Consolidar este veículo + <% end %> + <%= button_to arquivar_veiculo_consolidacao_consolidacao_entregas_path(@consolidacao), method: :post, params: { motorista: @motorista, vehicle: sel_unico, vehicle_sel: @veiculos_sel }, - data: { turbo_confirm: "Arquivar o veículo #{sel_unico}? Ele sai da finalização (as entregas já classificadas continuam no pagamento)." }, - class: 'text-gray-400 hover:text-white border border-[#2a2a2a] hover:border-red-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px]' %> + form: { data: { turbo_confirm: "Arquivar o veículo #{sel_unico}? Ele sai da finalização (as entregas já classificadas continuam no pagamento)." } }, + class: 'text-gray-400 hover:text-white border border-[#2a2a2a] hover:border-red-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px] inline-flex items-center gap-1.5' do %> + <%= icone :arquivar, cor: nil, tamanho: 'w-3.5 h-3.5' %> Arquivar veículo + <% end %> <%= status_unico[:completo] ? 'Pronto para consolidar.' : 'Classifique 100% deste veículo para consolidar.' %> @@ -160,7 +163,7 @@ <%# Oculta/mostra o resumo lateral (mais largura para a lista) %> <%= link_to params[:apenas_pendentes] == '1' ? 'Mostrar todas' : 'Apenas não classificadas', validar_consolidacao_consolidacao_entregas_path(@consolidacao, motorista: @motorista, vehicle: @veiculos_sel.presence, @@ -182,20 +185,20 @@ <%# Botão único + menu suspenso %> @@ -207,7 +210,7 @@

Registro manual de entrega

+ class="text-gray-500 hover:text-white leading-none" aria-label="Fechar"><%= icone :fechar, cor: nil, tamanho: 'w-5 h-5' %>

Lançe uma entrega à mão, sem buscar na base de rastreio. Use quando o motorista foi ao local mas a nota ficou registrada com outro motorista.

@@ -251,16 +254,16 @@ <%# Pilares (múltiplos) %>
- <% [['entrega_normal', '🚚 Entrega Normal', Configuracao.preco_entrega], - ['retirada', '📦 Retirada', Configuracao.preco_retirada], - ['bonus', '⭐ Bônus', Configuracao.preco_bonus], - ['desconto', '⚠️ Desconto', Configuracao.preco_desconto], - ['extraordinaria', '✨ Entrega Extraordinária', Configuracao.preco_extraordinaria]].each do |tipo, label, preco| %> + <% [['entrega_normal', :caminhao, 'Entrega Normal', Configuracao.preco_entrega], + ['retirada', :retirada, 'Retirada', Configuracao.preco_retirada], + ['bonus', :bonus, 'Bônus', Configuracao.preco_bonus], + ['desconto', :desconto, 'Desconto', Configuracao.preco_desconto], + ['extraordinaria', :extraordinaria, 'Entrega Extraordinária', Configuracao.preco_extraordinaria]].each do |tipo, ic, label, preco| %> <% end %>
@@ -274,7 +277,7 @@
@@ -284,9 +287,9 @@ class="hidden fixed inset-0 z-50 bg-black/70 flex items-center justify-center p-4">
-

📄 Entrega de termo

+

<%= icone :documento %> Entrega de termo

+ class="text-gray-500 hover:text-white leading-none" aria-label="Fechar"><%= icone :fechar, cor: nil, tamanho: 'w-5 h-5' %>

Entrega sem nota fiscal nem código de rastreio. Informe quantos termos de cada tipo foram entregues.

@@ -295,7 +298,7 @@ <%# Motorista (contexto da tela) %>

Motorista

-

🚚 <%= @motorista %>

+

<%= icone :caminhao %> <%= @motorista %>

<%# Veículo (Q3) — a qual carro estes termos pertencem %> @@ -311,7 +314,7 @@ <%# Steppers de quantidade — termo normal e termo especial %>
-

📄 Termo Normal

+

<%= icone :documento %> Termo Normal

<%= moeda(@precos[:termo]) %> cada

-

📋 Termo Especial

+

<%= icone :termo_especial %> Termo Especial

<%= moeda(@precos[:termo_especial]) %> cada

@@ -351,10 +354,10 @@ <%# ── Lista de entregas (3 colunas) — área rolável ──── %>
- <%# 🔍 Busca na listagem — filtra os cards por NF, local, endereço ou veículo %> + <%# Busca na listagem — filtra os cards por NF, local, endereço ou veículo %>
- 🔍 + <%= icone :buscar, cor: 'text-gray-500' %> @@ -379,15 +382,15 @@

NF <%= e.numero_nf %> · <%= e.local %> <% if e.falhada? %> - ⚠️ Insucesso + <%= icone :alerta, cor: nil, tamanho: 'w-3 h-3' %> Insucesso <% else %> - ✓ Entregue + <%= icone :confirmar, cor: nil, tamanho: 'w-3 h-3' %> Entregue <% end %>

-

📍 <%= e.address.presence || 'sem endereço' %>

+

<%= icone :local %> <%= e.address.presence || 'sem endereço' %>

- 📅 <%= e.checkout&.strftime('%d/%m/%Y') || '—' %> · 🚚 <%= e.vehicle.presence || 'sem veículo' %> - <% if e.atraso_minutos > 0 %> · ⏱️ atraso <%= e.atraso_minutos %>min<% end %> + <%= icone :calendario %> <%= e.checkout&.strftime('%d/%m/%Y') || '—' %> · <%= icone :caminhao %> <%= e.vehicle.presence || 'sem veículo' %> + <% if e.atraso_minutos > 0 %> · <%= icone :relogio, cor: 'text-amber-400' %> atraso <%= e.atraso_minutos %>min<% end %>

@@ -412,7 +415,7 @@ <% end %> <% else %>
-

🎉

+

<%= icone :sucesso, tamanho: 'w-10 h-10', cor: 'text-green-500' %>

Nenhuma entrega pendente neste filtro.

<% end %> @@ -421,7 +424,7 @@ <%# ── Resumo lateral (1 coluna) — rola junto se precisar ─────── %>
-

📊 Resumo

+

<%= icone :dashboard %> Resumo

@@ -465,13 +468,13 @@
-

💰 Normal: <%= moeda(@precos[:entrega_normal]) %>

-

📦 Retirada: <%= moeda(@precos[:retirada]) %>

-

⭐ Bônus: <%= moeda(@precos[:bonus]) %>

-

⚠️ Desconto: -<%= moeda(@precos[:desconto]) %>

-

✨ Extraordinária: <%= moeda(@precos[:extraordinaria]) %> (valor por entrega)

-

📄 Termo: <%= moeda(@precos[:termo]) %>

-

📋 Termo Especial: <%= moeda(@precos[:termo_especial]) %>

+

<%= icone :dinheiro %> Normal: <%= moeda(@precos[:entrega_normal]) %>

+

<%= icone :retirada %> Retirada: <%= moeda(@precos[:retirada]) %>

+

<%= icone :bonus %> Bônus: <%= moeda(@precos[:bonus]) %>

+

<%= icone :desconto %> Desconto: -<%= moeda(@precos[:desconto]) %>

+

<%= icone :extraordinaria %> Extraordinária: <%= moeda(@precos[:extraordinaria]) %> (valor por entrega)

+

<%= icone :documento %> Termo: <%= moeda(@precos[:termo]) %>

+

<%= icone :termo_especial %> Termo Especial: <%= moeda(@precos[:termo_especial]) %>

diff --git a/app/views/consolidacao_mailer/pagamento_efetuado.html.erb b/app/views/consolidacao_mailer/pagamento_efetuado.html.erb index 412d753..fcdcefa 100644 --- a/app/views/consolidacao_mailer/pagamento_efetuado.html.erb +++ b/app/views/consolidacao_mailer/pagamento_efetuado.html.erb @@ -7,7 +7,7 @@
-

Olá, <%= @user.nome.split.first %>! ✅

+

Olá, <%= @user.nome.split.first %>!

Seu pagamento de entregas foi efetuado pela empresa. diff --git a/app/views/consolidacao_mailer/pagamento_fechado.html.erb b/app/views/consolidacao_mailer/pagamento_fechado.html.erb index 1a5606f..99aa8f2 100644 --- a/app/views/consolidacao_mailer/pagamento_fechado.html.erb +++ b/app/views/consolidacao_mailer/pagamento_fechado.html.erb @@ -7,7 +7,7 @@

-

Olá, <%= @user.nome.split.first %>! 👋

+

Olá, <%= @user.nome.split.first %>!

Seu pagamento de entregas foi fechado pela empresa. diff --git a/app/views/consolidacoes/arquivadas.html.erb b/app/views/consolidacoes/arquivadas.html.erb index 2a97621..9ad50f8 100644 --- a/app/views/consolidacoes/arquivadas.html.erb +++ b/app/views/consolidacoes/arquivadas.html.erb @@ -2,8 +2,8 @@ <% content_for :title, 'Consolidações arquivadas' %>

-

📁 Consolidações arquivadas

- <%= link_to '← Voltar às ativas', consolidacoes_path, +

<%= icone :arquivadas %> Consolidações arquivadas

+ <%= link_to rotulo(:voltar, 'Voltar às ativas', cor: nil), consolidacoes_path, class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-3 rounded-lg min-h-[48px] flex items-center' %>
@@ -26,12 +26,12 @@ <%= badge_status(c.status) %>

- 📅 <%= l c.data_inicio, format: :short %> → <%= l c.data_fim, format: :short %> - · 👤 <%= c.consolidacao_motoristas.count %> motorista(s) + <%= icone :calendario %> <%= l c.data_inicio, format: :short %> <%= icone :avancar, tamanho: 'w-3 h-3' %> <%= l c.data_fim, format: :short %> + · <%= icone :pessoa %> <%= c.consolidacao_motoristas.count %> motorista(s) · Criada por <%= c.criador.nome_display %>

- 📁 Arquivada + <%= icone :arquivar %> Arquivada <% if c.arquivado_em.present? %>em <%= l c.arquivado_em, format: :short %><% end %> <% if c.arquivador.present? %>por <%= c.arquivador.nome_display %><% end %>

@@ -45,12 +45,16 @@ <% if policy(c).destroy? %>
- <%= button_to '♻️ Reativar', reativar_consolidacao_path(c), method: :post, + <%= button_to reativar_consolidacao_path(c), method: :post, form: { data: { turbo_confirm: 'Reativar esta consolidação? Ela voltará para a lista de ativas.' } }, - class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-4 py-2.5 rounded-lg text-sm min-h-[44px]' %> - <%= button_to '🗑️ Excluir', consolidacao_path(c), method: :delete, + class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-4 py-2.5 rounded-lg text-sm min-h-[44px] inline-flex items-center gap-2' do %> + <%= icone :restaurar, cor: nil, tamanho: 'w-4 h-4' %> Reativar + <% end %> + <%= button_to consolidacao_path(c), method: :delete, form: { data: { turbo_confirm: 'EXCLUIR PERMANENTEMENTE esta consolidação e todas as suas classificações? Esta ação NÃO pode ser desfeita.' } }, - class: 'text-red-400 hover:text-white hover:bg-red-600 border border-red-900 px-4 py-2.5 rounded-lg text-sm min-h-[44px]' %> + class: 'text-red-400 hover:text-white hover:bg-red-600 border border-red-900 px-4 py-2.5 rounded-lg text-sm min-h-[44px] inline-flex items-center gap-2' do %> + <%= icone :excluir, cor: nil, tamanho: 'w-4 h-4' %> Excluir + <% end %>
<% end %>
@@ -60,7 +64,7 @@
<% else %>
-

🗂️

+

<%= icone :pasta, tamanho: 'w-12 h-12', cor: 'text-gray-600' %>

Nenhuma consolidação arquivada.

<%= link_to 'Ver consolidações ativas', consolidacoes_path, class: 'inline-block bg-orange-500 hover:bg-orange-600 text-black font-bold px-5 py-3 rounded-lg' %> diff --git a/app/views/consolidacoes/index.html.erb b/app/views/consolidacoes/index.html.erb index 31dad30..8441018 100644 --- a/app/views/consolidacoes/index.html.erb +++ b/app/views/consolidacoes/index.html.erb @@ -4,14 +4,14 @@
-

📦 Consolidações

+

<%= icone :consolidacoes %> Consolidações

- <%= link_to '📁 Arquivadas', arquivadas_consolidacoes_path, + <%= link_to rotulo(:arquivadas, 'Arquivadas'), arquivadas_consolidacoes_path, class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-3 rounded-lg min-h-[48px] flex items-center transition-colors' %> <% if policy(Consolidacao).create? %> <% end %> <%= link_to '+ Nova Consolidação', new_consolidacao_path, @@ -25,9 +25,9 @@ class="hidden fixed inset-0 z-50 bg-black/70 flex items-center justify-center p-4">
-

➕ Nota avulsa

+

<%= icone :adicionar %> Nota avulsa

+ class="text-gray-500 hover:text-white leading-none" aria-label="Fechar"><%= icone :fechar, cor: nil, tamanho: 'w-5 h-5' %>

Para uma nota que chegou por fora: busque a NF e crie uma consolidação já com o apontamento do motorista.

@@ -50,14 +50,14 @@

- 📅 <%= l c.data_inicio, format: :short %> → <%= l c.data_fim, format: :short %> - · 👤 <%= c.consolidacao_motoristas.count %> motorista(s) + <%= icone :calendario %> <%= l c.data_inicio, format: :short %> → <%= l c.data_fim, format: :short %> + · <%= icone :pessoa %> <%= c.consolidacao_motoristas.count %> motorista(s) · Criada por <%= c.criador.nome_display %>

<% if c.operacoes.present? %> -

🗂️ <%= c.operacoes_label.join(' · ') %>

+

<%= icone :pasta %> <%= c.operacoes_label.join(' · ') %>

<% end %>
@@ -128,7 +128,7 @@
<% else %>
-

📭

+

<%= icone :vazio, tamanho: 'w-12 h-12', cor: 'text-gray-600' %>

Nenhuma consolidação encontrada.

<%= link_to 'Criar primeira consolidação', new_consolidacao_path, class: 'inline-block bg-orange-500 hover:bg-orange-600 text-black font-bold px-5 py-3 rounded-lg' %> diff --git a/app/views/consolidacoes/new.html.erb b/app/views/consolidacoes/new.html.erb index 23e3c69..876bf0b 100644 --- a/app/views/consolidacoes/new.html.erb +++ b/app/views/consolidacoes/new.html.erb @@ -2,13 +2,13 @@ <% content_for :title, 'Nova Consolidação' %>
-

➕ Nova Consolidação

+

<%= icone :adicionar %> Nova Consolidação

<%= form_with model: @consolidacao, class: 'bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-6 space-y-6' do |f| %> <% if @consolidacao.errors.any? %>
-

⚠️ Corrija os erros:

+

<%= icone :alerta, cor: nil %> Corrija os erros:

    <% @consolidacao.errors.full_messages.each do |msg| %>
  • <%= msg %>
  • @@ -20,7 +20,7 @@ <%# Operação — multi-select opcional (pré-preenche e filtra por NF) %>
    diff --git a/app/views/consolidacoes/show.html.erb b/app/views/consolidacoes/show.html.erb index 27cdb67..730a25e 100644 --- a/app/views/consolidacoes/show.html.erb +++ b/app/views/consolidacoes/show.html.erb @@ -15,7 +15,7 @@ <% if @consolidacao.finalizada? %><%= badge_pagamento(@consolidacao.status_pagamento) %><% end %>

    - 📅 <%= l @consolidacao.data_inicio, format: :short %> → <%= l @consolidacao.data_fim, format: :short %> + <%= icone :calendario %> <%= l @consolidacao.data_inicio, format: :short %> <%= icone :avancar, tamanho: 'w-3 h-3' %> <%= l @consolidacao.data_fim, format: :short %> · Criada por <%= @consolidacao.criador.nome_display %> <% if @consolidacao.finalizada? %> · Finalizada por <%= @consolidacao.finalizador&.nome_display %> em <%= l @consolidacao.finalizado_em, format: :short %> @@ -23,7 +23,7 @@

    <% if @consolidacao.operacoes.present? %>

    - 🗂️ Operação: + <%= icone :pasta %> Operação: <% @consolidacao.operacoes_label.each do |op| %> <%= op %> <% end %> @@ -32,16 +32,18 @@

    <% if @consolidacao.rascunho? %> - <%= link_to '✏️ Continuar validação', wizard_consolidacao_path(@consolidacao), + <%= link_to rotulo(:editar, 'Continuar validação', cor: nil), wizard_consolidacao_path(@consolidacao), class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-5 py-3 rounded-lg min-h-[48px] flex items-center' %> <% end %> - <%= link_to '📊 Relatório financeiro', gerar_pdf_financeiro_consolidacao_path(@consolidacao), + <%= link_to rotulo(:dashboard, 'Relatório financeiro'), gerar_pdf_financeiro_consolidacao_path(@consolidacao), data: { turbo: false }, class: 'bg-[#1a1a1a] hover:bg-[#2a2a2a] text-white border border-orange-500 font-semibold px-4 py-3 rounded-lg min-h-[48px] flex items-center' %> <% if policy(@consolidacao).destroy? && !@consolidacao.arquivada? %> - <%= button_to '📁 Arquivar', arquivar_consolidacao_path(@consolidacao), method: :post, + <%= button_to arquivar_consolidacao_path(@consolidacao), method: :post, form: { data: { turbo_confirm: 'Arquivar esta consolidação? Ela não será excluída, apenas movida para o arquivo.' } }, - class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-3 rounded-lg min-h-[48px]' %> + class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-3 rounded-lg min-h-[48px] flex items-center gap-2' do %> + <%= icone :arquivar, cor: nil, tamanho: 'w-4 h-4' %> Arquivar + <% end %> <% end %>
@@ -49,7 +51,7 @@ <%# ── Pagamento da operação inteira ─────────────────────── %> <% if pode_pagar %>
- 💵 Operação inteira: + <%= icone :pagamento %> Operação inteira: <% if @consolidacao.status_pagamento != :pago %> <%# Form único (id) — os inputs de NF e os botões "Marcar pago" de cada linha se associam a ele via atributo HTML5 form=, evitando
aninhado. %> @@ -57,15 +59,19 @@ id: 'form-pagar-tudo', class: 'flex items-center gap-2' do |f| %> <%= f.select :forma_pagamento, options_for_select(formas_pagamento, 'pix'), {}, class: 'bg-[#0a0a0a] border border-[#2a2a2a] text-white rounded-lg px-3 py-2.5 text-sm' %> - <%= f.submit '💰 Marcar tudo como pago', + <%= f.button type: :submit, data: { turbo_confirm: 'Marcar TODOS os motoristas pendentes desta consolidação como PAGOS? Confirme que a Nota Fiscal de cada um foi preenchida.' }, - class: 'bg-green-600 hover:bg-green-700 text-white font-bold px-4 py-2.5 rounded-lg text-sm cursor-pointer min-h-[44px]' %> + class: 'bg-green-600 hover:bg-green-700 text-white font-bold px-4 py-2.5 rounded-lg text-sm cursor-pointer min-h-[44px] inline-flex items-center gap-2' do %> + <%= icone :dinheiro, cor: nil, tamanho: 'w-4 h-4' %> Marcar tudo como pago + <% end %> <% end %> <% end %> <% if @consolidacao.status_pagamento != :pendente %> - <%= button_to '↩ Estornar tudo', cancelar_pagamento_consolidacao_path(@consolidacao), method: :post, - data: { turbo_confirm: 'Estornar o pagamento de TODOS os motoristas?' }, - class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-2.5 rounded-lg text-sm min-h-[44px]' %> + <%= button_to cancelar_pagamento_consolidacao_path(@consolidacao), method: :post, + form: { data: { turbo_confirm: 'Estornar o pagamento de TODOS os motoristas?' } }, + class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-2.5 rounded-lg text-sm min-h-[44px] inline-flex items-center gap-2' do %> + <%= icone :estornar, cor: nil, tamanho: 'w-4 h-4' %> Estornar tudo + <% end %> <% end %>
<% end %> @@ -78,7 +84,7 @@
<%# Motoristas + botões de PDF %> -

👥 Motoristas

+

<%= icone :usuarios %> Motoristas

<% @motoristas.each do |cm| %>
@@ -91,45 +97,49 @@ <% end %>

<%= moeda(cm.valor_total) %>

- <%# Breakdown por veículo (consolidados 🔒 / abertos). Informativo — o + <%# Breakdown por veículo (consolidados / abertos). Informativo — o pagamento continua sendo do motorista inteiro. %> <% veiculos = @veiculos_por_motorista[cm.motorista_nome] %> <% if veiculos.present? %>
<% veiculos.each do |cv| %> - <%= cv.fechado? ? '🔒' : '○' %> <%= cv.vehicle %> · <%= moeda(cv.valor_total) %> + <%= cv.fechado? ? icone(:travado, cor: nil, tamanho: 'w-3 h-3') : icone(:ponto_vazio, cor: nil, tamanho: 'w-3 h-3') %> <%= cv.vehicle %> · <%= moeda(cv.valor_total) %> <% end %>
<% end %> <% if cm.pago? %>

- 💰 Pago em <%= l cm.pago_em, format: :short %> + <%= icone :dinheiro, cor: nil %> Pago em <%= l cm.pago_em, format: :short %> <% if cm.forma_pagamento.present? %>via <%= cm.forma_pagamento.humanize %><% end %> <% if cm.pagador.present? %>por <%= cm.pagador.nome_display %><% end %>

<% if cm.nota_fiscal.present? %> -

🧾 NF <%= cm.nota_fiscal %>

+

<%= icone :nota_fiscal %> NF <%= cm.nota_fiscal %>

<% end %> <% end %> <% if pode_pagar %>
<% if cm.pago? %> - <%= button_to '↩ Estornar pagamento', cancelar_pagamento_consolidacao_path(@consolidacao, consolidacao_motorista_id: cm.id), method: :post, - data: { turbo_confirm: "Estornar o pagamento de #{cm.motorista_nome}?" }, - class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-3 py-2 rounded-lg text-xs min-h-[40px]' %> + <%= button_to cancelar_pagamento_consolidacao_path(@consolidacao, consolidacao_motorista_id: cm.id), method: :post, + form: { data: { turbo_confirm: "Estornar o pagamento de #{cm.motorista_nome}?" } }, + class: 'text-gray-400 hover:text-white border border-[#2a2a2a] px-3 py-2 rounded-lg text-xs min-h-[40px] inline-flex items-center gap-1.5' do %> + <%= icone :estornar, cor: nil, tamanho: 'w-3.5 h-3.5' %> Estornar pagamento + <% end %> <% else %> <%# Inputs/botão associados ao form único #form-pagar-tudo via atributo form=. %>
<%= text_field_tag "notas_fiscais[#{cm.id}]", nil, form: 'form-pagar-tudo', placeholder: 'Nº Nota Fiscal', class: 'bg-[#0a0a0a] border border-[#2a2a2a] text-white rounded-lg px-2 py-2 text-xs w-36' %> - <%= button_tag '💰 Marcar pago', type: :submit, form: 'form-pagar-tudo', + <%= button_tag type: :submit, form: 'form-pagar-tudo', name: 'consolidacao_motorista_id', value: cm.id, data: { turbo_confirm: "Marcar #{cm.motorista_nome} como pago?" }, - class: 'bg-green-600 hover:bg-green-700 text-white font-bold px-3 py-2 rounded-lg text-xs cursor-pointer min-h-[40px]' %> + class: 'bg-green-600 hover:bg-green-700 text-white font-bold px-3 py-2 rounded-lg text-xs cursor-pointer min-h-[40px] inline-flex items-center gap-1.5' do %> + <%= icone :dinheiro, cor: nil, tamanho: 'w-3.5 h-3.5' %> Marcar pago + <% end %>
<% end %>
@@ -139,13 +149,13 @@ <%# Preview abre modal %> - <%= link_to '📄 Relatório Individual', + <%= link_to rotulo(:documento, 'Relatório Individual', cor: nil), gerar_pdf_relatorio_consolidacao_path(@consolidacao, motorista: cm.motorista_nome), data: { turbo: false }, class: 'bg-orange-800 hover:bg-orange-700 text-white font-semibold px-4 py-3 rounded-lg text-sm min-h-[48px] flex items-center' %> - <%= link_to '🧾 Gerar Extrato', + <%= link_to rotulo(:nota_fiscal, 'Gerar Extrato', cor: nil), gerar_pdf_extrato_consolidacao_path(@consolidacao, motorista: cm.motorista_nome), data: { turbo: false }, class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-4 py-3 rounded-lg text-sm min-h-[48px] flex items-center' %> @@ -158,7 +168,7 @@ <%# ── Apontamentos manuais (notas que chegaram por fora) ─────────────── %> <% if @apontamentos.present? %> <% pode_editar = !(@consolidacao.finalizada? && current_user.operador?) %> -

➕ Apontamentos manuais

+

<%= icone :adicionar %> Apontamentos manuais

@@ -179,9 +189,9 @@ <% if pode_editar %> <% end %> @@ -219,8 +230,8 @@ @@ -115,9 +115,9 @@ class="hidden fixed inset-0 z-50 bg-black/70 flex items-center justify-center p-4">
-

🧑‍✈️ Adicionar motorista

+

<%= icone :motorista %> Adicionar motorista

+ class="text-gray-500 hover:text-white leading-none" aria-label="Fechar"><%= icone :fechar, cor: nil, tamanho: 'w-5 h-5' %>

Inclua um motorista nesta consolidação. Se ele estava arquivado, será restaurado.

@@ -128,7 +128,7 @@ class="w-full bg-[#0a0a0a] border border-[#2a2a2a] text-white rounded-lg px-3 py-3 text-base focus:border-orange-500 focus:outline-none mb-4"> <% Array(@motoristas_periodo).each do |m| %> - + <% end %> @@ -141,7 +141,7 @@ class="w-full text-left px-3 py-2 bg-[#0a0a0a] border border-[#2a2a2a] hover:border-orange-500 rounded-lg"> <%= m[:nome] %> <% if m[:veiculos].any? %> - 🚚 <%= m[:veiculos].join(', ') %> + <%= icone :caminhao %> <%= m[:veiculos].join(', ') %> <% end %> <% end %> @@ -152,7 +152,7 @@ <% end %>
@@ -174,7 +174,7 @@
- <%= m[:completo] ? '✓' : m[:registro].motorista_nome.first.upcase %> + <%= m[:completo] ? icone(:confirmar, cor: nil, tamanho: 'w-6 h-6') : m[:registro].motorista_nome.first.upcase %>

<%= m[:registro].motorista_nome %>

@@ -184,13 +184,13 @@ <%= m[:classificadas] %>/<%= m[:total] %> classificadas <% if m[:apontamentos].positive? %> - · ➕ <%= m[:apontamentos] %> apontamento<%= 's' if m[:apontamentos] > 1 %> + · <%= icone :adicionar, cor: nil, tamanho: 'w-3 h-3' %> <%= m[:apontamentos] %> apontamento<%= 's' if m[:apontamentos] > 1 %> <% end %>

<% if m[:veiculos_total] > 0 %>

- 🚗 <%= m[:veiculos_fechados] %>/<%= m[:veiculos_total] %> veículo<%= 's' if m[:veiculos_total] > 1 %> consolidado<%= 's' if m[:veiculos_fechados] != 1 %> + <%= icone :veiculo, cor: nil %> <%= m[:veiculos_fechados] %>/<%= m[:veiculos_total] %> veículo<%= 's' if m[:veiculos_total] > 1 %> consolidado<%= 's' if m[:veiculos_fechados] != 1 %> <% if m[:veiculos_pendentes].any? %> · pendente<%= 's' if m[:veiculos_pendentes].size > 1 %>: <%= m[:veiculos_pendentes].join(', ') %> @@ -201,7 +201,7 @@

<%= moeda(m[:registro].valor_total) %>

- + <%= icone :avancar, cor: 'text-gray-600', tamanho: 'w-5 h-5' %>
@@ -214,13 +214,14 @@ <% end %> <% if pode_arquivar_motorista %> - <%= button_to '🗄️', - arquivar_motorista_consolidacao_path(@consolidacao, consolidacao_motorista_id: m[:registro].id), + <%= button_to arquivar_motorista_consolidacao_path(@consolidacao, consolidacao_motorista_id: m[:registro].id), method: :post, form: { data: { turbo_confirm: "Arquivar #{m[:registro].motorista_nome} desta consolidação? Você poderá restaurar depois." }, class: 'absolute top-3 right-3' }, class: 'text-gray-500 hover:text-red-400 border border-[#2a2a2a] hover:border-red-500/50 rounded-lg w-9 h-9 flex items-center justify-center', - title: "Arquivar #{m[:registro].motorista_nome}" %> + title: "Arquivar #{m[:registro].motorista_nome}" do %> + <%= icone :arquivar, cor: nil, tamanho: 'w-4 h-4' %> + <% end %> <% end %>
<% end %> @@ -229,7 +230,7 @@ <%# Motoristas arquivados — restauráveis %> <% if @arquivados.present? %>
-

🗄️ Motoristas arquivados (<%= @arquivados.size %>)

+

<%= icone :arquivar %> Motoristas arquivados (<%= @arquivados.size %>)

<% @arquivados.each do |cm| %>
@@ -239,17 +240,19 @@
<% if pode_arquivar_motorista %> - <%= button_to '♻️ Restaurar', - desarquivar_motorista_consolidacao_path(@consolidacao, consolidacao_motorista_id: cm.id), + <%= button_to desarquivar_motorista_consolidacao_path(@consolidacao, consolidacao_motorista_id: cm.id), method: :post, - class: 'text-green-400 hover:text-green-300 border border-[#2a2a2a] hover:border-green-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px]' %> + class: 'text-green-400 hover:text-green-300 border border-[#2a2a2a] hover:border-green-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px] inline-flex items-center gap-1.5' do %> + <%= icone :restaurar, cor: nil, tamanho: 'w-3.5 h-3.5' %> Restaurar + <% end %> <% end %> <% if policy(@consolidacao).destroy? %> - <%= button_to '🗑️ Excluir', - excluir_motorista_consolidacao_path(@consolidacao, consolidacao_motorista_id: cm.id), + <%= button_to excluir_motorista_consolidacao_path(@consolidacao, consolidacao_motorista_id: cm.id), method: :delete, form: { data: { turbo_confirm: "Excluir DEFINITIVAMENTE #{cm.motorista_nome} desta consolidação? Os lançamentos dele serão apagados e isso não pode ser desfeito." } }, - class: 'text-red-400 hover:text-red-300 border border-[#2a2a2a] hover:border-red-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px]' %> + class: 'text-red-400 hover:text-red-300 border border-[#2a2a2a] hover:border-red-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px] inline-flex items-center gap-1.5' do %> + <%= icone :excluir, cor: nil, tamanho: 'w-3.5 h-3.5' %> Excluir + <% end %> <% end %>
@@ -272,25 +275,28 @@ <% if @consolidacao.rascunho? %>
<% if !tudo_completo && tem_consolidados && tem_pendentes %> - <%= button_to '🔒 Arquivar pendentes e finalizar', - finalizar_parcial_consolidacao_path(@consolidacao), + <%= button_to finalizar_parcial_consolidacao_path(@consolidacao), method: :post, - data: { turbo_confirm: 'Arquivar TODOS os veículos ainda não classificados 100% e finalizar? Eles ficam de fora desta consolidação (você resolve depois). Os veículos consolidados são pagos normalmente.' }, - class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-5 py-3.5 rounded-lg min-h-[48px] flex items-center justify-center text-center' %> + form: { data: { turbo_confirm: 'Arquivar TODOS os veículos ainda não classificados 100% e finalizar? Eles ficam de fora desta consolidação (você resolve depois). Os veículos consolidados são pagos normalmente.' } }, + class: 'bg-orange-500 hover:bg-orange-600 text-black font-bold px-5 py-3.5 rounded-lg min-h-[48px] flex items-center justify-center text-center gap-2' do %> + <%= icone :travado, cor: nil, tamanho: 'w-4 h-4' %> Arquivar pendentes e finalizar + <% end %> <% end %> - <%= button_to 'Finalizar consolidação ✓', finalizar_consolidacao_path(@consolidacao), + <%= button_to finalizar_consolidacao_path(@consolidacao), method: :post, disabled: !tudo_completo, - data: { turbo_confirm: 'Finalizar? Após finalizada, a consolidação não poderá ser editada por operadores.' }, - class: "font-bold px-6 py-3.5 rounded-lg min-h-[48px] transition-colors - #{tudo_completo ? 'bg-green-600 hover:bg-green-500 text-white cursor-pointer' : 'bg-[#2a2a2a] text-gray-600 cursor-not-allowed'}" %> + form: { data: { turbo_confirm: 'Finalizar? Após finalizada, a consolidação não poderá ser editada por operadores.' } }, + class: "font-bold px-6 py-3.5 rounded-lg min-h-[48px] transition-colors inline-flex items-center justify-center gap-2 + #{tudo_completo ? 'bg-green-600 hover:bg-green-500 text-white cursor-pointer' : 'bg-[#2a2a2a] text-gray-600 cursor-not-allowed'}" do %> + Finalizar consolidação <%= icone :confirmar, cor: nil %> + <% end %>
<% end %>
<% unless tudo_completo %>

- ⚠️ Classifique todas as entregas de todos os motoristas para finalizar tudo<% if tem_consolidados && tem_pendentes %> — ou use “Arquivar pendentes e finalizar” para fechar só os veículos já consolidados.<% end %> + <%= icone :alerta, cor: 'text-amber-400' %> Classifique todas as entregas de todos os motoristas para finalizar tudo<% if tem_consolidados && tem_pendentes %> — ou use “Arquivar pendentes e finalizar” para fechar só os veículos já consolidados.<% end %>

<% end %> diff --git a/app/views/dashboard/index.html.erb b/app/views/dashboard/index.html.erb index cede46d..a784221 100644 --- a/app/views/dashboard/index.html.erb +++ b/app/views/dashboard/index.html.erb @@ -55,7 +55,7 @@ <%# Filtro de calendário — seleciona uma faixa de datas %>
- 📅 + <%= icone :calendario %> - 🗂️ <%= @operacao_filtro.present? ? "#{@operacao_filtro.size} operação(ões)" : 'Todas as operações' %> + <%= icone :pasta %> <%= @operacao_filtro.present? ? "#{@operacao_filtro.size} operação(ões)" : 'Todas as operações' %>
<%# Limpar seleção — recarrega o dashboard sem filtro de operação %>
Operações <% if @operacao_filtro.present? %> - <%= link_to '✕ Limpar', dashboard_path(inicio: @periodo_inicio.strftime('%Y-%m-%d'), fim: @periodo_fim.strftime('%Y-%m-%d')), + <%= link_to rotulo(:fechar, 'Limpar', cor: nil, tamanho: 'w-3 h-3'), dashboard_path(inicio: @periodo_inicio.strftime('%Y-%m-%d'), fim: @periodo_fim.strftime('%Y-%m-%d')), data: { turbo: false }, class: 'text-xs text-orange-400 hover:text-orange-300 font-semibold' %> <% end %>
@@ -107,7 +107,7 @@ <% end %> <%# Imprimir relatório financeiro do período/operação atuais %> - <%= link_to '🖨️ Relatório', + <%= link_to rotulo(:imprimir, 'Relatório'), dashboard_relatorio_financeiro_path( inicio: @periodo_inicio.strftime('%Y-%m-%d'), fim: @periodo_fim.strftime('%Y-%m-%d'), @@ -124,7 +124,7 @@
-

💰 Valor Estimado

+

<%= icone :dinheiro, cor: nil %> Valor Estimado

<%= moeda(@valor_estimado) %>

@@ -136,7 +136,7 @@ <%# Card destacado: total consolidado e pago (consolidações finalizadas do período) %>
-

💼 Consolidado / Pago

+

<%= icone :consolidado_pago %> Consolidado / Pago

<%= moeda(@fin_custo_total) %>

consolidado no período

@@ -147,7 +147,7 @@ <%# Card 2: Total de entregas %>
-

📦 Total Entregas

+

<%= icone :consolidacoes %> Total Entregas

<%= @total_entregas %>

<%= @entregas_pagas %> entregues @@ -160,7 +160,7 @@ <%# Card 3: Consolidações %>
-

📋 Consolidações

+

<%= icone :planilha %> Consolidações

<%= @consolidacoes_mes.count %>

<%= @consolidacoes_abertas %> abertas @@ -171,7 +171,7 @@ <%# Card 4: Motoristas ativos %>
-

🚗 Motoristas

+

<%= icone :veiculo %> Motoristas

<%= @motoristas.count %>

com entregas no período

@@ -180,22 +180,22 @@ <%# KPIs FINANCEIROS (consolidações finalizadas, já com filtro de operação) %>
-

💰 Custo total

+

<%= icone :dinheiro %> Custo total

<%= moeda(@fin_custo_total) %>

<%= @fin_qtd_entregas %> entregas classificadas

-

🎫 Ticket médio

+

<%= icone :ticket %> Ticket médio

<%= moeda(@fin_ticket_medio) %>

por entrega

-

✅ Pago

+

<%= icone :sucesso, cor: 'text-green-500' %> Pago

<%= moeda(@fin_pago) %>

já confirmado

-

🕗 A pagar

+

<%= icone :relogio, cor: 'text-amber-400' %> A pagar

<%= moeda(@fin_pendente) %>

pendente

@@ -238,7 +238,7 @@
<% else %>
-
💸
+
<%= icone :custo, tamanho: 'w-8 h-8', cor: 'text-gray-600' %>

Nenhum pagamento realizado neste período

<% if @pag_pend_valor.positive? %>

@@ -252,7 +252,7 @@ <%# Top motoristas %>

-

🏆 Motoristas

+

<%= icone :ranking %> Motoristas

<% if @motoristas.any? %>
@@ -282,7 +282,7 @@
<% else %>
-
🚚
+
<%= icone :caminhao, tamanho: 'w-8 h-8', cor: 'text-gray-600' %>

Nenhuma entrega concluída neste período

<% end %> @@ -294,34 +294,34 @@ <%# Custo por operação (barra) %>
-

🏷️ Custo por operação

+

<%= icone :tag %> Custo por operação

Valor consolidado no período

<% if @fin_por_operacao.any? %>
<% else %> -
🏷️

Sem dados no período

+
<%= icone :tag, tamanho: 'w-8 h-8', cor: 'text-gray-600' %>

Sem dados no período

<% end %>
<%# Composição por tipo (rosca) %>
-

🧩 Composição do custo

+

<%= icone :composicao %> Composição do custo

Por tipo de lançamento

<% if @fin_por_tipo.any? %>
<% else %> -
🧩

Sem dados no período

+
<%= icone :composicao, tamanho: 'w-8 h-8', cor: 'text-gray-600' %>

Sem dados no período

<% end %>
<%# Custo por motorista (barra) %>
-

👤 Custo por motorista

+

<%= icone :pessoa %> Custo por motorista

Por motorista no período

<% if @fin_por_motorista.any? %>
<% else %> -
👤

Sem dados no período

+
<%= icone :pessoa, tamanho: 'w-8 h-8', cor: 'text-gray-600' %>

Sem dados no período

<% end %>
@@ -331,12 +331,12 @@ <%# Rosca pago vs a pagar (por valor) %>
-

💵 Pagamentos

+

<%= icone :pagamento %> Pagamentos

Pagos por data de pagamento · pendentes no período

<% if (@pag_pago_qtd + @pag_pend_qtd).zero? %>
-
🧾
+
<%= icone :nota_fiscal, tamanho: 'w-8 h-8', cor: 'text-gray-600' %>

Nenhum pagamento ou pendência no período

<% else %> @@ -365,7 +365,7 @@ <%# Pagamentos realizados no período (filtrados por pago_em) %>
-

✅ Pagamentos realizados no período

+

<%= icone :sucesso, cor: 'text-green-500' %> Pagamentos realizados no período

<% if @pagamentos_feitos.any? %>

<%= if pilares.first.termo? - '📄 Entrega de termo' + rotulo(:documento, 'Entrega de termo') elsif pilares.first.termo_especial? - '📋 Entrega de termo especial' + rotulo(:termo_especial, 'Entrega de termo especial') else "NF #{nf_exibida.presence || '—'}" end %>

@@ -200,11 +210,12 @@
<%= moeda(total) %> - <%= button_to '✕ Remover', - remover_apontamento_consolidacao_consolidacao_entregas_path(@consolidacao, tracking_id: pilares.first.tracking_id, motorista: motorista), + <%= button_to remover_apontamento_consolidacao_consolidacao_entregas_path(@consolidacao, tracking_id: pilares.first.tracking_id, motorista: motorista), method: :delete, form: { data: { turbo_confirm: eh_termo ? "Remover a entrega de termo de #{motorista}?" : "Remover o apontamento da NF #{nf_exibida.presence || '—'} de #{motorista}?" } }, - class: 'text-gray-400 hover:text-red-400 border border-[#2a2a2a] hover:border-red-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px]' %> + class: 'text-gray-400 hover:text-red-400 border border-[#2a2a2a] hover:border-red-500/50 px-3 py-2 rounded-lg text-xs min-h-[40px] inline-flex items-center gap-1.5' do %> + <%= icone :fechar, cor: nil, tamanho: 'w-3 h-3' %> Remover + <% end %>
@@ -405,7 +405,7 @@ <%# Pendentes (consolidações finalizadas do período sem pagamento) %>
-

🕗 Pagamentos pendentes

+

<%= icone :relogio, cor: 'text-amber-400' %> Pagamentos pendentes

<% if @pagamentos_pendentes.any? %>
@@ -435,7 +435,7 @@
<% else %> -

Nenhuma pendência no período. 🎉

+

Nenhuma pendência no período. <%= icone :sucesso, cor: 'text-green-500' %>

<% end %> @@ -444,7 +444,7 @@ <%# Por operação %> <% if @por_operacao.any? %>
-

🏥 Entregas por Local

+

<%= icone :operacao %> Entregas por Local

<% total_op = @por_operacao.values.sum.to_f %> <% @por_operacao.each do |local, qtd| %> diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb index bc5f0df..eefff5d 100644 --- a/app/views/devise/passwords/edit.html.erb +++ b/app/views/devise/passwords/edit.html.erb @@ -6,7 +6,7 @@
- 🔒 + <%= icone :travado, tamanho: 'w-8 h-8' %>

Definir nova senha

diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb index b4083c1..2aee723 100644 --- a/app/views/devise/passwords/new.html.erb +++ b/app/views/devise/passwords/new.html.erb @@ -6,7 +6,7 @@
- 🔑 + <%= icone :chave, tamanho: 'w-8 h-8' %>

Recuperar senha

Informe seu e-mail para receber as instruções

@@ -38,7 +38,7 @@

- ⚠️ O envio de e-mail depende da configuração SMTP no servidor.
+ <%= icone :alerta, cor: 'text-amber-400' %> O envio de e-mail depende da configuração SMTP no servidor.
Sem SMTP, peça ao administrador para redefinir sua senha.

diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 15a6456..6277aed 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -25,12 +25,12 @@
@@ -114,7 +114,7 @@ class="h-14 rounded-xl bg-[#0a0a0a] border border-white/10 text-gray-400 text-sm hover:bg-red-900/40 hover:border-red-500/50 hover:text-red-400 active:scale-95 transition-all"> - ✕ + <%= icone :fechar, cor: nil, tamanho: 'w-4 h-4' %>
<%# Topbar mobile %>
<%= image_tag '/logo-reem.png', alt: 'Reem Transporte', class: 'h-8 w-auto object-contain' %> @@ -121,8 +125,8 @@ } function syncSidebarToggleIcon() { const icon = document.getElementById('sidebar-toggle-icon'); - if (icon) icon.textContent = - document.documentElement.classList.contains('sidebar-collapsed') ? '▶' : '◀'; + if (icon) icon.classList.toggle('rotate-180', + document.documentElement.classList.contains('sidebar-collapsed')); } syncSidebarToggleIcon(); diff --git a/app/views/layouts/_sidebar.html.erb b/app/views/layouts/_sidebar.html.erb index 74f76b1..b6efd81 100644 --- a/app/views/layouts/_sidebar.html.erb +++ b/app/views/layouts/_sidebar.html.erb @@ -18,11 +18,11 @@
- <%= nav_link_to 'Usuários', usuarios_path, icon: '👥' %> - <%= nav_link_to 'Configurações', configuracoes_path, icon: '⚙️' %> + <%= nav_link_to 'Usuários', usuarios_path, icon: :usuarios %> + <%= nav_link_to 'Configurações', configuracoes_path, icon: :configuracoes %> <% end %> <%# PDFs (fase 7 — link desabilitado por enquanto) %> @@ -41,7 +41,7 @@

Relatórios

- 📄 + <%= icone :documento, cor: nil, tamanho: 'w-5 h-5' %> Relatórios PDF Em breve
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index e9d0fda..2e73575 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -100,7 +100,7 @@