// app/javascript/controllers/carrossel_controller.js // Stimulus — paginação em "carrossel" para listas longas no celular (painel do // motorista). Os itens já vêm todos no HTML; aqui só mostramos uma PÁGINA por // vez, com setas e o indicador "1 / 3". // // Por que no cliente e não com ?pg= no servidor: a lista divide a tela com os // cards de valor e o filtro de período — recarregar a página a cada seta faria o // motorista perder a posição e piscar a tela inteira num 3G. // // Sem itens suficientes para duas páginas, os controles somem sozinhos (nada de // seta morta ocupando espaço). import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["item", "controles", "indicador", "anterior", "proximo"] static values = { tamanho: { type: Number, default: 10 } } connect() { this.pagina = 0 this.render() } proxima() { this.ir(this.pagina + 1) } anterior() { this.ir(this.pagina - 1) } ir(destino) { this.pagina = Math.min(Math.max(destino, 0), this.totalPaginas - 1) this.render() // Volta ao topo da lista: sem isso, na 2ª página o motorista continua vendo // o fim da anterior e parece que nada mudou. this.element.scrollIntoView({ behavior: "smooth", block: "start" }) } get totalPaginas() { return Math.max(Math.ceil(this.itemTargets.length / this.tamanhoValue), 1) } render() { const inicio = this.pagina * this.tamanhoValue const fim = inicio + this.tamanhoValue this.itemTargets.forEach((item, i) => { item.classList.toggle("hidden", i < inicio || i >= fim) }) if (!this.hasControlesTarget) return this.controlesTarget.classList.toggle("hidden", this.totalPaginas < 2) if (this.hasIndicadorTarget) { // "1–10 de 12" e não "página 1 de 2": o motorista quer saber quantos // fechamentos existem, não quantas páginas a tela tem. const total = this.itemTargets.length this.indicadorTarget.textContent = `${inicio + 1}–${Math.min(fim, total)} de ${total}` } if (this.hasAnteriorTarget) this.alternar(this.anteriorTarget, this.pagina === 0) if (this.hasProximoTarget) this.alternar(this.proximoTarget, this.pagina >= this.totalPaginas - 1) } // Botão de ponta: desabilitado de verdade (não só apagado), para o toque não // "funcionar sem fazer nada". alternar(botao, desligado) { if (!botao) return botao.disabled = desligado botao.classList.toggle("opacity-30", desligado) botao.classList.toggle("pointer-events-none", desligado) } }