Files
Reem-Notas/app/javascript/controllers/carrossel_controller.js

69 lines
2.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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) {
// "110 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)
}
}