Atualização da função de adicionar entregas por fora da operação

This commit is contained in:
2026-06-19 14:59:26 -03:00
parent 79c0f646da
commit 7b83f2e248
13 changed files with 399 additions and 77 deletions

View File

@@ -6,7 +6,7 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["modal", "nf", "erro", "resultados", "confirmar", "tipo"]
static targets = ["modal", "nf", "erro", "resultados", "confirmar", "tipoCheck"]
static values = { buscarUrl: String, apontarUrl: String }
// ── Modal ──────────────────────────────────────────────────
@@ -85,6 +85,9 @@ export default class extends Controller {
const selecionado = this.resultadosTarget.querySelector('input[name="apontamento_entrega"]:checked')
if (!selecionado) { this.mostrarErro("Selecione uma entrega."); return }
const tipos = this.tipoCheckTargets.filter(c => c.checked).map(c => c.value)
if (!tipos.length) { this.mostrarErro("Selecione ao menos uma classificação."); return }
const btn = event.currentTarget
btn.disabled = true
try {
@@ -95,7 +98,7 @@ export default class extends Controller {
"Accept": "application/json",
"X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify({ tracking_id: selecionado.value, tipo: this.tipoTarget.value })
body: JSON.stringify({ tracking_id: selecionado.value, tipos: tipos })
})
const data = await resp.json()
if (!resp.ok || data.ok === false) {

View File

@@ -0,0 +1,92 @@
// app/javascript/controllers/nota_avulsa_controller.js
// Stimulus controller — "Nota avulsa": busca a NF na base de rastreio e, ao
// prosseguir, o formulário cria JÁ uma consolidação avulsa para o motorista.
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["modal", "nf", "erro", "resultados", "confirmar"]
static values = { buscarUrl: String }
abrir() {
this.reset()
this.modalTarget.classList.remove("hidden")
this.nfTarget.focus()
}
fechar() {
this.modalTarget.classList.add("hidden")
}
fundo(event) {
if (event.target === this.modalTarget) this.fechar()
}
reset() {
this.nfTarget.value = ""
this.erroTarget.classList.add("hidden")
this.resultadosTarget.innerHTML = ""
this.confirmarTarget.classList.add("hidden")
}
// ── Busca da NF (Enter ou botão) ───────────────────────────
async buscar(event) {
event?.preventDefault()
const nf = this.nfTarget.value.trim()
if (!nf) { this.mostrarErro("Informe o número da nota."); return }
this.erroTarget.classList.add("hidden")
this.resultadosTarget.innerHTML = `<p class="text-gray-400 text-sm">Buscando…</p>`
this.confirmarTarget.classList.add("hidden")
try {
const url = `${this.buscarUrlValue}?nf=${encodeURIComponent(nf)}`
const resp = await fetch(url, { headers: { "Accept": "application/json" } })
const data = await resp.json()
if (!data.ok) {
this.resultadosTarget.innerHTML = ""
this.mostrarErro(data.erro || "Nota não encontrada.")
return
}
this.renderResultados(data.entregas)
} catch (e) {
this.resultadosTarget.innerHTML = ""
this.mostrarErro("Erro ao buscar a nota. Tente novamente.")
}
}
renderResultados(entregas) {
const cards = entregas.map((e, i) => {
const pago = e.pago
? `<span class="text-green-400">paga</span>`
: `<span class="text-yellow-400">${e.status || "pendente"}</span>`
return `
<label class="flex gap-3 items-start bg-[#0a0a0a] border border-[#2a2a2a] rounded-lg p-3 cursor-pointer hover:border-orange-500">
<input type="radio" name="tracking_id" value="${e.tracking_id}" ${i === 0 ? "checked" : ""} required class="mt-1 accent-orange-500">
<div class="text-sm">
<p class="text-white font-bold">NF ${e.nf || "—"} · ${e.motorista || "sem motorista"}</p>
<p class="text-gray-400">${e.veiculo || "—"} · ${e.local || "—"}</p>
<p class="text-gray-500 text-xs">${e.data || "—"} · ${pago}</p>
</div>
</label>`
}).join("")
this.resultadosTarget.innerHTML = cards
this.confirmarTarget.classList.remove("hidden")
}
// Garante que há uma entrega selecionada antes de enviar o formulário.
validar(event) {
const selecionado = this.resultadosTarget.querySelector('input[name="tracking_id"]:checked')
if (!selecionado) {
event.preventDefault()
this.mostrarErro("Busque e selecione uma nota antes de criar.")
}
}
mostrarErro(msg) {
this.erroTarget.textContent = msg
this.erroTarget.classList.remove("hidden")
}
}