69 lines
2.5 KiB
JavaScript
69 lines
2.5 KiB
JavaScript
// 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)
|
||
}
|
||
}
|