1import { Controller } from "@hotwired/stimulus" 2import { paraNumero, paraTexto } from "lib/moeda" 3 4// Transferencia de saldo entre alunos da mesma escola. 5// 6// O impedimento e comunicado em texto e o botao continua clicavel: botao desabilitado 7// sem mensagem foi o impasse que esta tela veio desfazer â inclusive sem aluno destino, 8// que e escolhido pela busca e recarrega a tela. 9export default class extends Controller { 10 static targets = ["busca", "destino", "valor", "motivo", "erroValor", "erroMotivo", "erroDestino", "aviso"] 11 static values = { disponivel: Number, buscaUrl: String, destinoUrl: String } 12 13 connect() { 14 $(this.buscaTarget).autocomplete({ 15 source: this.buscaUrlValue, 16 minLength: 2, 17 select: (evento, ui) => { 18 window.location.href = `${this.destinoUrlValue}?target_student_id=${ui.item.value}` 19 return false 20 }, 21 }) 22 $(".ui-autocomplete").css("z-index", 1000) 23 } 24 25 disconnect() { 26 $(this.buscaTarget).autocomplete("destroy") 27 } 28 29 limparValor() { 30 this.#mostrarProblema(null) 31 } 32 33 limparMotivo() { 34 if (this.motivoTarget.value.trim() !== "") this.erroMotivoTarget.style.display = "none" 35 } 36 37 // Adiado para o fim da fila porque a mascara de moeda reformata o campo no mesmo 38 // evento: lido antes dela, o valor fica uma tecla atrasado (90,01 com 90 disponivel 39 // so reclamava ao apertar Enter). 40 conferirValor() { 41 setTimeout(() => this.#mostrarProblema(this.#problemaDoValor()), 0) 42 } 43 44 enviar(evento) { 45 const semDestino = !this.destinoTarget.value 46 const semMotivo = this.motivoTarget.value.trim() === "" 47 const problema = this.#problemaDoValor() 48 49 this.erroDestinoTarget.style.display = semDestino ? "" : "none" 50 this.erroMotivoTarget.style.display = semMotivo ? "" : "none" 51 this.#mostrarProblema(problema) 52 53 if (!semDestino && !semMotivo && !problema) return 54 55 evento.preventDefault() 56 57 const primeiro = semDestino ? this.buscaTarget : problema ? this.valorTarget : this.motivoTarget 58 primeiro.scrollIntoView({ block: "center" }) 59 primeiro.focus() 60 } 61 62 #problemaDoValor() { 63 const valor = paraNumero(this.valorTarget.value) 64 if (Number.isNaN(valor) || valor <= 0) return "Informe um valor maior que zero." 65 if (valor > this.disponivelValue) { 66 return `Valor de transferência não pode ser maior que o saldo do aluno (máximo R$ ${paraTexto(this.disponivelValue)}).` 67 } 68 return null 69 } 70 71 #mostrarProblema(problema) { 72 this.erroValorTarget.textContent = problema || "" 73 this.erroValorTarget.style.display = problema ? "" : "none" 74 this.avisoTarget.style.color = problema ? "#dc2626" : "#94a3b8" 75 } 76}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.