1 2 function obterUrlPosLogin() { 3 try { 4 const next = new URLSearchParams(window.location.search).get('next'); 5 if (next && next.startsWith('/') && !next.startsWith('//')) { 6 return next; 7 } 8 } catch (_) {} 9 return '/'; 10 } 11 12 function scrollAndFocus(id, offset = 200) { 13 const el = document.getElementById(id); 14 if (!el) return; 15 const top = el.getBoundingClientRect().top + window.scrollY - offset; 16 window.scrollTo({ top, behavior: 'smooth' }); 17 setTimeout(() => el.focus(), 500); 18 } 19 20 function isCampoVisivel(campo) { 21 if (!campo || campo.disabled) return false; 22 if (campo.closest('.hidden, [hidden]')) return false; 23 24 const estilo = window.getComputedStyle(campo); 25 if (estilo.display === 'none' || estilo.visibility === 'hidden') return false; 26 27 return campo.offsetParent !== null || estilo.position === 'fixed'; 28 } 29 30 // Rosario: login com CPF ou CNPJ alfanumérico (data-login-cpf-cnpj no form_cpf). 31 function isLoginCpfCnpjHabilitado() { 32 const cpfCnpj = document.getElementById('form_cpf')?.dataset?.loginCpfCnpj; 33 34 if (cpfCnpj === 'true') { 35 return true; 36 } 37 return false; 38 } 39 40 function normalizarDocumentoLogin(valor) { 41 return (valor || '').replace(/[.\-\/\s]/g, '').toUpperCase(); 42 } 43 44 function obterDocumentoLogin(valor) { 45 if (isLoginCpfCnpjHabilitado()) { 46 return normalizarDocumentoLogin(valor); 47 } 48 return (valor || '').replace(/\D/g, ''); 49 } 50 51 function validarDocumentoLogin(valor) { 52 const documento = obterDocumentoLogin(valor); 53 if (/^\d{11}$/.test(documento)) { 54 return validarCPF(documento); 55 } 56 if (isLoginCpfCnpjHabilitado() && /^[A-Z0-9]{14}$/.test(documento)) { 57 return validarCNPJ(documento); 58 } 59 return false; 60 } 61 62 function destacarPrimeiroCampoInvalido(form) { 63 if (!form) return; 64 const campos = form.querySelectorAll('input, select, textarea'); 65 for (const campo of campos) { 66 if (campo.type === 'hidden' || campo.disabled) continue; 67 if (campo.checkValidity()) continue; 68 69 campo.classList.add('invalid'); 70 campo.classList.remove('valid'); 71 72 const feedback = campo.parentElement?.nextElementSibling; 73 if (feedback?.classList?.contains('invalid-feedback')) { 74 feedback.classList.add('show'); 75 } 76 77 if (campo.id) { 78 scrollAndFocus(campo.id); 79 } else { 80 campo.scrollIntoView({ behavior: 'smooth', block: 'center' }); 81 campo.focus(); 82 } 83 return; 84 } 85 } 86 87 function resetValidation(formId) { 88 const form = document.getElementById(formId); 89 if (!form) return; 90 91 // limpa classes de validação nos inputs/selects/textarea 92 form.querySelectorAll('.valid, .invalid') 93 .forEach(el => el.classList.remove('valid','invalid')); 94 95 // limpa mensagens/customValidity e feedbacks 96 form.querySelectorAll('input, select, textarea').forEach(el => { 97 el.setCustomValidity(''); 98 el.removeAttribute('aria-invalid'); 99 }); 100 form.querySelectorAll('.invalid-feedback, .valid-feedback') 101 .forEach(fb => fb.classList.remove('show')); 102 } 103 104 let cadastroData = {}; 105 let loginData = {}; 106 107 // Estado do fluxo de token no cadastro. 108 // A decisão final é feita pelo retorno de "solicitar/token": 109 // status false -> pula step de token e vai para criação de senha. 110 const LOGIN_FLOW_FLAGS = { 111 enableSignupTokenStep: true, 112 }; 113 114 function isSignupTokenStepEnabled() { 115 return !!LOGIN_FLOW_FLAGS.enableSignupTokenStep; 116 } 117 118 function disableFieldsInForm(formId, disabled) { 119 const form = document.getElementById(formId); 120 if (!form) return; 121 const fields = form.querySelectorAll('input, select, textarea, button'); 122 fields.forEach((field) => { 123 if (field.id === 'btn-verificar-cpf') return; // mantém ação do botão principal 124 field.disabled = !!disabled; 125 }); 126 } 127 128 function getFormObject(formId) { 129 const form = document.getElementById(formId); 130 if (!form) return {}; 131 const fields = form.querySelectorAll('input, select, textarea'); 132 const data = {}; 133 fields.forEach((field) => { 134 const name = field.name; 135 if (!name || field.disabled) return; 136 if (field.type === 'radio') { 137 if (field.checked) data[name] = field.value; 138 } else if (field.type === 'checkbox') { 139 data[name] = field.checked; 140 } else { 141 data[name] = field.value; 142 } 143 }); 144 return data; 145 } 146 147 function mostrarFormRetornaCadastroCpf() {
148 document.getElementById('form_cpf').classList.remove('hidden'); 149 document.querySelectorAll('#form_cadastro_encontrado, #form_cadastro_nao_encontrado, #form_valida_token, #redefinir-senha') 150 .forEach(el => el.classList.add('hidden')); 151 document.getElementById('email-mascarado').innerHTML = ''; 152 document.getElementById('btn-verificar-cpf').classList.remove('hidden'); 153 disableFieldsInForm('form_cadastro_encontrado', true); 154 disableFieldsInForm('form_cadastro_nao_encontrado', true); 155 disableFieldsInForm('form_valida_token', true); 156 disableFieldsInForm('redefinir-senha', true); 157 disableFieldsInForm('form_redefinir_senha', true); 158 disableFieldsInForm('form_finaliza_cadastro', true); 159 } 160 161 function mostrarFormCadastroEncontrado() { 162 document.getElementById('form_cpf').classList.remove('hidden'); 163 document.getElementById('form_cadastro_encontrado').classList.remove('hidden'); 164 document.querySelectorAll('#form_cadastro_nao_encontrado, #form_valida_token, #form_finaliza_cadastro, #form_redefinir_senha') 165 .forEach(el => el.classList.add('hidden')); 166 disableFieldsInForm('form_cadastro_encontrado', false); 167 disableFieldsInForm('form_cadastro_nao_encontrado', true); 168 disableFieldsInForm('form_valida_token', true); 169 disableFieldsInForm('form_redefinir_senha', true); 170 disableFieldsInForm('form_finaliza_cadastro', true); 171 } 172 173 function mostrarFormCadastroNaoEncontrado() { 174 document.getElementById('form_cpf').classList.remove('hidden'); 175 document.getElementById('form_cadastro_nao_encontrado').classList.remove('hidden'); 176 document.querySelectorAll('#form_cadastro_encontrado, #form_valida_token, #redefinir-senha, #form_finaliza_cadastro, #form_redefinir_senha') 177 .forEach(el => el.classList.add('hidden')); 178 disableFieldsInForm('form_cadastro_encontrado', true); 179 disableFieldsInForm('form_cadastro_nao_encontrado', false); 180 disableFieldsInForm('form_valida_token', true); 181 disableFieldsInForm('redefinir-senha', true); 182 disableFieldsInForm('form_finaliza_cadastro', true); 183 disableFieldsInForm('form_redefinir_senha', true); 184 disableFieldsInForm('form_finaliza_cadastro', true); 185 } 186 187 function mostrarFormToken(is_reset = false) { 188 TokenCtx.setFlow(is_reset ? 'reset' : 'cadastro'); 189 document.getElementById('form_cpf').focus() 190 document.querySelectorAll('#form_cpf, #form_cadastro_encontrado, #form_cadastro_nao_encontrado, #redefinir-senha, #form_finaliza_cadastro, #form_redefinir_senha') 191 .forEach(el => el.classList.add('hidden')); 192 document.getElementById('form_valida_token').classList.remove('hidden') 193 document.getElementById('form_valida_token').classList.remove('valid') 194 disableFieldsInForm('form_cadastro_encontrado', true); 195 disableFieldsInForm('form_cadastro_nao_encontrado', true); 196 disableFieldsInForm('form_valida_token', false); 197 disableFieldsInForm('redefinir-senha', true); 198 disableFieldsInForm('form_redefinir_senha', true); 199 disableFieldsInForm('form_finaliza_cadastro', true); 200 if (is_reset) { 201 document.getElementById('enviar-token-celular').classList.add('hidden') 202 const email = document.getElementById('email-redefinir').value; 203 const emailMask = document.getElementById('email-mascarado'); 204 if (emailMask) emailMask.textContent = mascararEmail(email); 205 } 206 scrollToTop(); 207 iniciarTimer(); 208 } 209 210 function mostrarFormCadastraSenha(is_reset = false) { 211 document.getElementById('form_finaliza_cadastro').reset(); 212 document.getElementById('form_redefinir_senha').reset(); 213 document.querySelectorAll('#form_cpf, #form_cadastro_encontrado, #form_cadastro_nao_encontrado, #redefinir-senha, #form_valida_token, #form_finaliza_cadastro, #form_redefinir_senha') 214 .forEach(el => el.classList.add('hidden')); 215 disableFieldsInForm('form_cadastro_encontrado', true); 216 disableFieldsInForm('form_cadastro_nao_encontrado', true); 217 disableFieldsInForm('redefinir-senha', true); 218 disableFieldsInForm('form_valida_token', true); 219 disableFieldsInForm('form_finaliza_cadastro', true); 220 disableFieldsInForm('form_redefinir_senha', true); 221 if(is_reset) { 222 document.getElementById('form_redefinir_senha').classList.remove('hidden') 223 disableFieldsInForm('form_redefinir_senha', false); 224 } else { 225 document.getElementById('form_finaliza_cadastro').classList.remove('hidden') 226 disableFieldsInForm('form_finaliza_cadastro', false); 227 } 228 scrollToTop(); 229 } 230 231 function navegarPara(formId, is_reset = false) { 232 document.getElementById('btn-verificar-cpf').classList.add('hidden') 233 switch (formId) {
234 case 'form_cadastro_encontrado': 235 mostrarFormCadastroEncontrado(); 236 document.getElementById('retorna_cadastro_cpf').classList.remove('hidden') 237 break; 238 case 'form_cadastro_nao_encontrado': 239 mostrarFormCadastroNaoEncontrado(); 240 document.getElementById('retorna_cadastro_cpf').classList.remove('hidden') 241 break; 242 case 'form_valida_token': 243 document.getElementById('enviar-token').classList.add('hidden') 244 mostrarFormToken(is_reset); 245 break; 246 case 'form_finaliza_cadastro': 247 mostrarFormCadastraSenha(); 248 break; 249 default: 250 console.warn(`Formulário desconhecido: ${formId}`); 251 } 252 } 253 254 const TokenCtx = (() => { 255 let tokenId = null; 256 let flow = null; // 'reset' | 'signup' 257 258 return { 259 setFlow: (t) => flow = t, 260 getFlow: () => flow, 261 setTokenId: (id) => tokenId = id, 262 getTokenId: () => tokenId, 263 takeTokenId: () => { const t = tokenId; tokenId = null; return t; }, 264 clear: () => { tokenId = null; flow = null; } 265 }; 266 })(); 267 268 function getCode6() { 269 return Array.from(document.querySelectorAll('.codigo-token')) 270 .map(i => (i.value || '').replace(/\D/g,'')) 271 .join(''); 272 } 273 274 //Chama funcao global 275 async function executarRecaptchaGoogle(action = 'LOGIN') { 276 if (!window.SecurityRecaptcha || typeof window.SecurityRecaptcha.execute !== 'function') { 277 if (window.toastr) toastr.error('Verificação de segurança indisponÃvel. Atualize a página e tente novamente.'); 278 return null; 279 } 280 return window.SecurityRecaptcha.execute(action); 281 } 282 283 async function enviarToken(tipo_envio, dat_nasc = false) { 284 285 let celular; 286 let email; 287 288 if(tipo_envio === 'celular') { 289 const telEl = document.getElementById('celular'); 290 celular = (telEl ? telEl.value : '').replace(/\D/g, ''); 291 } else if (tipo_envio === 'email') { 292 const emailEl = document.getElementById('email'); 293 const emailRedef = document.getElementById('email-redefinir'); 294 email = emailEl.value ? emailEl.value : emailRedef.value ? emailRedef.value : ''; 295 296 if (!validarEmail(email)) { 297 exibirErroCampoEmail(emailEl || emailRedef, 'Por favor, insira um email válido.'); 298 return; 299 } 300 } else { 301 return; 302 } 303 const recaptchaToken = await executarRecaptchaGoogle('LOGIN'); 304 if (recaptchaToken === null) return; 305 306 const data_nascimento = document.getElementById('dat_nasc').value; 307 308 load('on', document.body); 309 310 let payload = {}; 311 if (email) payload = { email, tipo: TokenCtx.getFlow() }; 312 if (celular) payload = { celular, tipo: TokenCtx.getFlow() }; 313 if (TokenCtx.getFlow() === 'cadastro' && dat_nasc && data_nascimento) payload = { email, tipo: TokenCtx.getFlow(), dat_nasc: data_nascimento }; 314 if (recaptchaToken) payload.recaptcha = recaptchaToken; 315 316 const resp = await fetch("solicitar/token", { 317 method: "POST", 318 headers: { 319 "Content-Type": "application/json", 320 "X-CSRFToken": window.CSRF_TOKEN(), 321 }, 322 body: JSON.stringify(payload), 323 }); 324 325 const data = await resp.json(); 326 327 const verificarAuth = ( 328 TokenCtx.getFlow() === 'cadastro' && 329 tipo_envio === 'email' && 330 resp.ok && 331 data && 332 data.dual_auth !== true 333 ); 334 335 if (verificarAuth) { 336 LOGIN_FLOW_FLAGS.enableSignupTokenStep = false; 337 TokenCtx.setTokenId(null); 338 //if (window.toastr) toastr.info(data.descricao || 'Cadastro sem validação por token.'); 339 navegarPara('form_finaliza_cadastro'); 340 load('off', document.body); 341 return; 342 } 343 344 const ok = resp.ok && data.status && data.token_id; 345 if(ok) { 346 LOGIN_FLOW_FLAGS.enableSignupTokenStep = true; 347 TokenCtx.setTokenId(data.token_id); 348 } 349 350 if (ok) { 351 if(tipo_envio === 'celular') { 352 if (window.toastr) toastr.success('Verifique seu celular e informe o código no campo sinalizado.', 'Token enviado com sucesso'); 353 const avisoToken = document.getElementById('aviso_token'); 354 avisoToken.innerHTML = 'Enviamos um código para o celular: <span id="telefone-mascarado"></span>'; 355 avisoToken.classList.add('mb-2'); 356 const telMask = document.getElementById('telefone-mascarado'); 357 if (telMask) telMask.textContent = mascararTelefone(celular); 358 const lixo = document.getElementById('aviso_lixo_eletronico'); 359 if (lixo) lixo.style.display = 'none'; 360 } else { 361 if (window.toastr) toastr.success('Verifique seu e-mail e informe o código no campo sinalizado.', 'Token enviado com sucesso'); 362 const avisoToken = document.getElementById('aviso_token'); 363 avisoToken.innerHTML = 'Enviamos um código para o e-mail: <span id="email-mascarado"></span>'; 364 avisoToken.classList.remove('mb-2'); 365 const emailMask = document.getElementById('email-mascarado'); 366 if (emailMask) emailMask.textContent = mascararEmail(email); 367 const lixo = document.getElementById('aviso_lixo_eletronico'); 368 if (lixo) lixo.style.display = ''; 369 } 370 navegarPara('form_valida_token') 371 } else { 372 if (data.idade_minima) { 373 document.getElementById('min-data').classList.add('show'); 374 document.getElementById('dat_nasc').classList.add('invalid'); 375 document.getElementById('dat_nasc').classList.remove('valid'); 376 document.getElementById('min-data').textContent = data.idade_minima; 377 scrollAndFocus('dat_nasc'); 378 } 379 if (tipo_envio === 'email') { 380 const emailElErro = document.getElementById('email') || document.getElementById('email-redefinir'); 381 const mensagemErroEmail = data.email || data.descricao; 382 if (mensagemErroEmail) { 383 exibirErroCampoEmail(emailElErro, mensagemErroEmail); 384 } 385 } 386 if (window.toastr) toastr.error(data.descricao ? data.descricao : 'Erro ao enviar token', 'Erro'); 387 } 388 389 load('off', document.body); 390 } 391 392 async function validarCodigoToken() { 393 const token = getCode6(); 394 if (token.length !== 6) { 395 toastr?.error('Informe os 6 dÃgitos.'); 396 return; 397 } 398 const email = document.getElementById('email').value || document.getElementById('email-redefinir').value; 399 const celular = document.getElementById('celular').value || ''; 400 401 load('on', document.body); 402 try { 403 const resp = await fetch("confirmar/token", { 404 method: "POST", 405 headers: { "Content-Type": "application/json", "X-CSRFToken": window.CSRF_TOKEN() }, 406 body: JSON.stringify({ token, email, celular, tipo: TokenCtx.getFlow() }) 407 }); 408 const data = await resp.json(); 409 410 if (resp.ok && data.status) { 411 //Campos de senha conforme o fluxo: 412 if (TokenCtx.getFlow() === 'reset') { 413 mostrarFormCadastraSenha(true); 414 } else { 415 mostrarFormCadastraSenha(false); 416 } 417 } else { 418 toastr?.error(data.descricao || 'Código inválido ou expirado.'); 419 } 420 } finally { 421 document.querySelectorAll('.codigo-token').forEach(i => i.value = ''); 422 load('off', document.body); 423 } 424 } 425 426 document.getElementById('form_valida_token')?.addEventListener('submit', (e) => { 427 e.preventDefault(); 428 e.stopPropagation();
429 validarCodigoToken(); 430 }); 431 432 document.getElementById('form_redefinir_senha')?.addEventListener('submit', async (e) => { 433 e.preventDefault(); 434 435 const form = e.currentTarget; 436 const novaSenhaEl = document.getElementById('senha_redefinir'); 437 const confirmaEl = document.getElementById('senha_redefinir_confirmacao'); 438 const novaSenha = novaSenhaEl?.value || ''; 439 const confirma = confirmaEl?.value || ''; 440 441 // força de senha e confirmação 442 exibeErrosSenha(novaSenha, true); 443 if (confirmaEl) { 444 const ok = validaSenhaConfirmacao(novaSenha, confirma); 445 confirmaEl.setCustomValidity(ok ? '' : 'As senhas não conferem!'); 446 } 447 448 if(form && form.checkValidity()) { 449 const tokenId = TokenCtx.getTokenId(); 450 if (!tokenId) { 451 toastr?.error('Código expirado. Reenvie o token.'); 452 return; 453 } 454 455 const recaptchaToken = await executarRecaptchaGoogle('LOGIN'); 456 if (recaptchaToken === null) { 457 return; 458 } 459 460 const redefinirPayload = { nova_senha: novaSenha, token: tokenId }; 461 if (recaptchaToken) redefinirPayload.recaptcha = recaptchaToken; 462 redefinir_senha(redefinirPayload); 463 464 //if (!tokenId) { toastr?.error('Código expirado. Reenvie o token.'); return; } 465 466 } else { 467 toastr?.error('Verifique os campos em destaque.'); 468 } 469 }); 470 471 async function redefinir_senha(dados) { 472 load('on', document.body); 473 try { 474 const resp = await fetch("alterar/senha", { 475 method: "POST", 476 headers: { "Content-Type": "application/json", "X-CSRFToken": window.CSRF_TOKEN() }, 477 body: JSON.stringify(dados) 478 }); 479 const data = await resp.json(); 480 481 if (resp.ok && data.status) { 482 TokenCtx.clear(); 483 toastr?.success('Senha redefinida com sucesso!'); 484 //TokenCtx.clear(); 485 window.location.href = '/login'; 486 } else { 487 toastr?.error(data.descricao || 'Não foi possÃvel redefinir a senha.'); 488 } 489 } finally { 490 load('off', document.body); 491 } 492 493 } 494 495 document.getElementById('form_cadastro_nao_encontrado')?.addEventListener('submit', async function(event){ 496 const cpfverificado = document.getElementById('username') 497 const cpf = document.getElementById('documento'); 498 cpf.value = cpfverificado.value; 499 500 var sexo = document.getElementsByName('sexo'); 501 var data = document.getElementsByName('dat_nasc')[0]; 502 var tel = document.getElementById('celular'); 503 const emailCadastro = document.getElementById('email'); 504 const form = document.getElementById('form_cadastro_nao_encontrado'); 505 const is_data_visivel = isCampoVisivel(data); 506 507 var aux = 0; 508 sexo.forEach((value) => { 509 if (value.checked) { 510 aux++ 511 } 512 }); 513 // garantir obrigatoriedade do grupo e refletir no validity 514 Array.from(sexo).forEach(r => r.required = true); 515 if (aux > 0) { 516 document.getElementsByName('sexo').forEach(value => value.classList.remove('invalid')); 517 Array.from(sexo).forEach(r => r.setCustomValidity('')); 518 } else { 519 document.getElementsByName('sexo').forEach(value => value.classList.add('invalid')); 520 if (sexo[0]) sexo[0].setCustomValidity('Selecione uma opção'); 521 } 522 if (!validarCampoCelular(tel)) { 523 tel.focus(); 524 } 525 if(validarDocumentoLogin(cpf.value)){ 526 cpf.setCustomValidity(''); 527 } else { 528 document.getElementById('invalid_cpf').classList.add('show'); 529 cpf.classList.add('invalid'); 530 cpf.classList.remove('valid'); 531 } 532 533 // Exige data de nascimento apenas quando o campo estiver visÃvel. 534 if (data) { 535 data.required = is_data_visivel; 536 } 537 if (is_data_visivel) { 538 if (compareDates(data.value) && data.value && data.value.length === 10) { 539 document.getElementById('invalid-data').classList.remove('show'); 540 data.classList.remove('invalid'); 541 data.classList.add('valid'); 542 } else { 543 if(data.value) { 544 document.getElementById('invalid-data').innerHTML = 'Informe uma data válida'; 545 document.getElementById('invalid-data').classList.add('show'); 546 } 547 data.classList.add('invalid'); 548 data.classList.remove('valid'); 549 data.focus(); 550 } 551 } else if (data) { 552 document.getElementById('invalid-data')?.classList.remove('show'); 553 data.classList.remove('invalid'); 554 data.classList.remove('valid'); 555 if (!data.value) { 556 data.value = '01/01/2000'; 557 } 558 } 559 if (!validarCampoEmail(emailCadastro)) { 560 scrollAndFocus('email'); 561 } 562 if (this.checkValidity() === false) { 563 event.preventDefault(); 564 event.stopPropagation();
565 destacarPrimeiroCampoInvalido(form); 566 toastr?.error('Verifique os campos em destaque.'); 567 } else { 568 event.preventDefault(); 569 event.stopPropagation(); 570 cadastroData = Object.assign({}, getFormObject('form_cpf'), getFormObject('form_cadastro_nao_encontrado')); 571 if (!is_data_visivel) { 572 cadastroData.dat_nasc = '01/01/2000'; 573 } 574 TokenCtx.setFlow('cadastro'); 575 LOGIN_FLOW_FLAGS.enableSignupTokenStep = true; 576 enviarToken('email', true); 577 } 578 this.classList.add('was-validated'); 579 580 }); 581 582 document.getElementById('btn-sair')?.addEventListener('click', function (event) { 583 event.preventDefault(); 584 logout(); 585 }); 586 document.getElementById('btn-reenviar-token')?.addEventListener('click', function (event) { 587 event.preventDefault(); 588 enviarToken('email'); 589 }); 590 document.getElementById('retorna_cadastro')?.addEventListener('click', function (event) { 591 event.preventDefault(); 592 if(TokenCtx.getFlow() === 'reset') { 593 document.getElementById('form_cpf')?.classList.remove('hidden'); 594 document.getElementById('btn-verificar-cpf')?.classList.remove('hidden'); 595 document.getElementById('form_valida_token')?.classList.add('hidden'); 596 document.getElementById('form_cpf')?.focus(); 597 } else { 598 navegarPara('form_cadastro_nao_encontrado') 599 } 600 }); 601 document.getElementById('retorna_cadastro2')?.addEventListener('click', function (event) { 602 event.preventDefault(); 603 navegarPara('form_cadastro_nao_encontrado') 604 }); 605 document.getElementById('retorna_redefinir')?.addEventListener('click', function (event) { 606 event.preventDefault(); 607 TokenCtx.clear(); 608 document.getElementById('redefinir-senha')?.classList.add('hidden'); 609 document.getElementById('form_redefinir_senha')?.classList.add('hidden'); 610 document.getElementById('form_valida_token')?.classList.add('hidden'); 611 mostrarFormRetornaCadastroCpf(); 612 document.getElementById('form_cpf')?.classList.remove('hidden'); 613 document.getElementById('retorna_cadastro_cpf')?.classList.add('hidden'); 614 615 // document.getElementById('btn-verificar-cpf')?.classList.remove('hidden'); 616 // document.getElementById('form_cpf')?.focus(); 617 }); 618 619 document.getElementById('retorna_cadastro_cpf')?.addEventListener('click', function (event) { 620 event.preventDefault(); 621 cadastroData = {}; 622 loginData = {}; 623 document.getElementById('form_cpf')?.classList.remove('valid'); 624 document.getElementById('form_cadastro_nao_encontrado')?.classList.remove('valid'); 625 document.getElementById('form_cadastro_encontrado')?.classList.remove('valid'); 626 document.getElementById('form_valida_token')?.classList.remove('valid'); 627 document.querySelectorAll('#form_cadastro_encontrado, #form_cadastro_nao_encontrado, #form_valida_token, #btn-reenviar-token, #enviar-token, #redefinir-senha') 628 .forEach(el => el.classList.add('hidden')); 629 630 const telMask = document.getElementById('telefone-mascarado'); 631 if (telMask) telMask.textContent = ''; 632 const emailMask = document.getElementById('email-mascarado'); 633 if (emailMask) emailMask.textContent = ''; 634 document.getElementById('btn-verificar-cpf')?.classList.remove('hidden'); 635 document.getElementById('form_cpf')?.classList.remove('hidden'); 636 document.getElementById('retorna_cadastro_cpf')?.classList.add('hidden'); 637 }); 638 639 const tempoEnvio = 60; 640 let timerEnvio; 641 642 document.getElementById('btn-enviar-token-telefone')?.addEventListener('click', function (event) { 643 event.preventDefault(); 644 enviarToken('celular'); 645 const enviarCel = document.getElementById('enviar-token-celular'); 646 const timerCel = document.getElementById('timer-token-celular'); 647 enviarCel && enviarCel.classList.add('hidden'); 648 timerCel && timerCel.classList.remove('hidden'); 649 let contador = tempoEnvio; 650 const contadorEl = document.getElementById('contador-token'); 651 if (contadorEl) contadorEl.textContent = String(contador); 652 timerEnvio = setInterval(() => { 653 contador--; 654 if (contadorEl) contadorEl.textContent = String(contador); 655 if (contador <= 0) { 656 clearInterval(timerEnvio); 657 timerCel && timerCel.classList.add('hidden'); 658 enviarCel && enviarCel.classList.remove('hidden'); 659 } 660 }, 1000); 661 }); 662 663 function limparCamposToken() { 664 document.querySelectorAll('.codigo-token').forEach(el => el.value = ''); 665 const hidden = document.getElementById('token_hidden'); 666 if (hidden) hidden.value = ''; 667 const focus = document.getElementById('focus_token'); 668 focus && focus.focus(); 669 } 670 671 document.getElementById('form_finaliza_cadastro')?.addEventListener('submit', async function(event){ 672 event.preventDefault(); 673 event.stopPropagation(); 674 675 const cpfUsername = (getFormObject('form_cpf') || {}).username; 676 677 // força de senha e confirmação antes de checar validade do form 678 const senhaEl = document.getElementById('senha_cadastro'); 679 const confirmaEl = document.getElementById('senha_cadastro_confirmacao'); 680 const senha = senhaEl?.value || ''; 681 const confirma = confirmaEl?.value || ''; 682 exibeErrosSenha(senha, false); 683 if (confirmaEl) { 684 const ok = validaSenhaConfirmacao(senha, confirma); 685 confirmaEl.setCustomValidity(ok ? '' : 'As senhas não conferem!'); 686 if(!ok) toastr?.error('Verifique as senhas e tente novamente.', 'Erro'); 687 } 688 689 if (this.checkValidity() === true) { 690 disableFieldsInForm('form_cadastro_nao_encontrado', false); 691 let payload = Object.assign({}, getFormObject('form_finaliza_cadastro'), getFormObject('form_cadastro_nao_encontrado')); 692 const tokenId = TokenCtx.takeTokenId(); 693 694 if (isSignupTokenStepEnabled()) { 695 if (!tokenId) { 696 toastr?.error('Código expirado. Reenvie o token.'); 697 return; 698 } 699 payload.token_id = tokenId; 700 } 701 702 const recaptchaToken = await executarRecaptchaGoogle('LOGIN'); 703 if (recaptchaToken === null) { 704 return; 705 } 706 707 if (recaptchaToken) payload.recaptcha = recaptchaToken; 708 cadastrar_usuario(payload); 709 //TokenCtx.clear(); 710 } 711 }); 712 713 function validarEmail(email) { 714 const valor = (email || '').trim().toLowerCase(); 715 if (!valor || valor.length > 254) return false;
716 717 const regex = /^[a-z0-9._%+-]+@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,6}$/; 718 if (!regex.test(valor)) return false; 719 720 const partes = valor.split('@')[1].split('.'); 721 const tld = partes[partes.length - 1]; 722 723 if (partes.length === 2) { 724 if (tld.length < 3) return false; 725 if (tld.length >= 4 && !/[aeiou]/.test(tld)) return false; 726 } 727 728 return true; 729 } 730 731 function buscarFeedbackServidorEmail(inputEl) { 732 if (!inputEl) return null; 733 if (inputEl.id === 'email-redefinir') { 734 return document.getElementById('invalid-email-redefinir'); 735 } 736 return document.getElementById('invalid-email'); 737 } 738 739 function exibirErroCampoEmail(inputEl, mensagem, feedbackServidorEl = null) { 740 if (!inputEl) return; 741 742 const feedbackServidor = feedbackServidorEl || buscarFeedbackServidorEmail(inputEl); 743 const feedbackGenerico = inputEl.parentElement?.nextElementSibling; 744 745 inputEl.classList.add('invalid'); 746 inputEl.classList.remove('valid'); 747 inputEl.setCustomValidity(mensagem || 'Erro no e-mail'); 748 749 if (feedbackGenerico?.classList?.contains('invalid-feedback') && feedbackGenerico !== feedbackServidor) { 750 feedbackGenerico.classList.remove('show'); 751 } 752 753 if (feedbackServidor) { 754 feedbackServidor.textContent = mensagem || ''; 755 feedbackServidor.classList.add('show'); 756 } 757 758 if (inputEl.id) { 759 scrollAndFocus(inputEl.id); 760 } else { 761 inputEl.scrollIntoView({ behavior: 'smooth', block: 'center' }); 762 inputEl.focus(); 763 } 764 } 765 766 function limparErroServidorEmail(inputEl) { 767 const feedbackServidor = buscarFeedbackServidorEmail(inputEl); 768 if (feedbackServidor) { 769 feedbackServidor.classList.remove('show'); 770 feedbackServidor.textContent = ''; 771 } 772 } 773 774 function validarCampoEmail(inputEl, feedbackEl = null) { 775 if (!inputEl) return true; 776 const valor = (inputEl.value || '').trim(); 777 const valido = !!valor && validarEmail(valor); 778 const feedbackPadrao = feedbackEl || inputEl.parentElement?.nextElementSibling; 779 const feedbackServidor = buscarFeedbackServidorEmail(inputEl); 780 781 if (valido) { 782 inputEl.classList.remove('invalid'); 783 inputEl.classList.add('valid'); 784 inputEl.setCustomValidity(''); 785 limparErroServidorEmail(inputEl); 786 if (feedbackPadrao?.classList?.contains('invalid-feedback')) { 787 feedbackPadrao.classList.remove('show'); 788 } 789 } else { 790 inputEl.classList.add('invalid'); 791 inputEl.classList.remove('valid'); 792 inputEl.setCustomValidity('Informe um e-mail válido'); 793 if (feedbackPadrao?.classList?.contains('invalid-feedback')) { 794 feedbackPadrao.textContent = 'Informe um e-mail válido'; 795 feedbackPadrao.classList.add('show'); 796 } 797 if (feedbackServidor && feedbackServidor !== feedbackPadrao) { 798 feedbackServidor.classList.remove('show'); 799 feedbackServidor.textContent = ''; 800 } 801 } 802 803 return valido; 804 } 805 806 function validarCampoCelular(inputEl) { 807 if (!inputEl) return true; 808 const valido = (inputEl.value || '').length >= 15; 809 const feedback = inputEl.parentElement?.nextElementSibling; 810 811 if (valido) { 812 inputEl.classList.remove('invalid'); 813 inputEl.classList.add('valid'); 814 inputEl.setCustomValidity(''); 815 if (feedback?.classList?.contains('invalid-feedback')) { 816 feedback.classList.remove('show'); 817 } 818 } else { 819 inputEl.classList.add('invalid'); 820 inputEl.classList.remove('valid'); 821 inputEl.setCustomValidity('Informe um celular válido'); 822 if (feedback?.classList?.contains('invalid-feedback')) { 823 feedback.classList.add('show'); 824 } 825 } 826 827 return valido; 828 } 829 830 document.addEventListener('input', function(e) { 831 if (e.target && e.target.classList.contains('codigo-token')) { 832 const el = e.target; 833 el.value = (el.value || '').replace(/\D/g, ''); 834 if (el.value.length === 1) { 835 const next = el.nextElementSibling; 836 if (next && next.classList.contains('codigo-token')) next.focus(); 837 } 838 atualizarTokenHidden(); 839 } 840 }); 841 842 document.addEventListener('keydown', function(e) { 843 if (e.target && e.target.classList.contains('codigo-token')) { 844 const el = e.target; 845 if (e.key === 'Backspace' && !el.value) { 846 const prev = el.previousElementSibling; 847 if (prev && prev.classList.contains('codigo-token')) prev.focus(); 848 } 849 // Quando pressionar Enter no campo de token, submeter apenas o formulário de validação de token 850 if (e.key === 'Enter') { 851 e.preventDefault(); 852 e.stopPropagation(); 853 const formToken = document.getElementById('form_valida_token'); 854 if (formToken && !formToken.classList.contains('hidden')) { 855 // Verifica se todos os 6 dÃgitos foram preenchidos antes de submeter 856 const token = getCode6(); 857 if (token.length === 6) { 858 formToken.requestSubmit(); 859 } else {
860 // Se não estiver completo, apenas move para o próximo campo 861 const next = el.nextElementSibling; 862 if (next && next.classList.contains('codigo-token')) { 863 next.focus(); 864 } 865 } 866 } 867 } 868 } 869 }); 870 871 function atualizarTokenHidden() { 872 let token = ''; 873 document.querySelectorAll('.codigo-token').forEach(inp => token += (inp.value || '')); 874 const hidden = document.getElementById('token_hidden'); 875 if (hidden) hidden.value = token; 876 } 877 878 document.addEventListener('paste', function(e) { 879 if (e.target && e.target.classList.contains('codigo-token')) { 880 e.preventDefault(); 881 const pasted = (e.clipboardData || window.clipboardData).getData('text').replace(/\D/g, ''); 882 const inputs = Array.from(document.querySelectorAll('.codigo-token')); 883 inputs.forEach((inp, i) => inp.value = pasted[i] || ''); 884 if (pasted.length === 6 && inputs[5]) inputs[5].focus(); 885 atualizarTokenHidden(); 886 } 887 }); 888 889 let intervalo; 890 891 function iniciarTimer() { 892 let tempo = 59; 893 const botao = document.getElementById('enviar-token'); 894 const timerDisplay = document.getElementById('timer'); 895 if (botao) botao.classList.add('hidden'); 896 if (intervalo) clearInterval(intervalo); 897 intervalo = setInterval(function() { 898 if (tempo > 0) { 899 if (timerDisplay) timerDisplay.textContent = 'Reenviar em ' + tempo + 's'; 900 tempo--; 901 } else { 902 if (botao) botao.classList.remove('hidden'); 903 if (timerDisplay) timerDisplay.textContent = ''; 904 clearInterval(intervalo); 905 intervalo = null; 906 } 907 }, 1000); 908 } 909 910 function mascararEmail(email) { 911 const [usuario, dominio] = email.split('@'); 912 913 if (usuario.length <= 3) { 914 return `${usuario}@${dominio}`; 915 } 916 917 const visiveis = usuario.slice(0, 3); 918 const mascarados = '*'.repeat(usuario.length - 3); 919 920 return `${visiveis}${mascarados}@${dominio}`; 921 } 922 923 function mascararTelefone(telefone) { 924 const ddd = telefone.slice(0, 2); 925 const primeiroDigito = telefone.slice(2, 3); 926 const ultimosDigitos = telefone.slice(-2); 927 const mascarados = '*'.repeat(telefone.length - 2 - 3); 928 929 return `(${ddd}) ${primeiroDigito}${mascarados}${ultimosDigitos}`; 930 } 931 932 function scrollToTop(){ 933 window.scrollTo({ top: 0, behavior: 'smooth' }); 934 } 935 936 // document.querySelectorAll('.input-busca').forEach(inp => { 937 // inp.addEventListener('focus', function(){ onoffbody && onoffbody('off'); }); 938 // inp.addEventListener('blur', function(){ onoffbody && onoffbody('on'); }); 939 // }); 940 941 document.getElementById('email-redefinicao')?.addEventListener('submit', async function (event) { 942 event.preventDefault(); 943 944 const form = this; 945 const input = document.getElementById('email-redefinir'); 946 const email = (input?.value || '').trim(); 947 948 if (!validarEmail(email)) { 949 input.classList.add('invalid'); 950 input.classList.remove('valid'); 951 document.getElementById('invalid-email-redefinir').classList.add('show'); 952 return; 953 } 954 document.getElementById('invalid-email-redefinir').classList.remove('show'); 955 input.classList.remove('invalid'); 956 input.classList.add('valid'); 957 958 const recaptchaToken = await executarRecaptchaGoogle('LOGIN'); 959 if (recaptchaToken === null) return; 960 961 load('on', document.body); 962 963 const resp = await fetch("solicitar/token", { 964 method: "POST", 965 headers: { 966 "Content-Type": "application/json", 967 "X-CSRFToken": window.CSRF_TOKEN(), 968 }, 969 body: JSON.stringify(recaptchaToken ? { email, tipo: 'reset', recaptcha: recaptchaToken } : { email, tipo: 'reset' }), 970 }); 971 972 const data = await resp.json(); 973 974 load('off', document.body); 975 const ok = resp.ok && data.status && data.token_id; 976 if(ok) { 977 TokenCtx.setFlow('reset'); 978 TokenCtx.setTokenId(data.token_id); 979 toastr.success(data.descricao || 'E-mail enviado com sucesso! Verifique sua caixa de entrada.'); 980 if (data.dual_auth !== true) { 981 mostrarFormCadastraSenha(true); 982 } else { 983 navegarPara('form_valida_token', true); 984 } 985 } else { 986 document.getElementById('email-redefinir').classList.add('invalid'); 987 document.getElementById('email-redefinir').classList.remove('valid'); 988 document.getElementById('nao-encontrado-email-redefinir').classList.add('show'); 989 toastr.error(data.descricao || 'Erro ao enviar e-mail. Verifique se o e-mail está cadastrado.'); 990 } 991 }); 992 993 document.getElementById('celular')?.addEventListener('blur', function () {
994 validarCampoCelular(this); 995 }); 996 997 document.getElementById('celular')?.addEventListener('input', function () { 998 const valor = (this.value || '').trim(); 999 if (!valor) { 1000 this.classList.remove('invalid', 'valid'); 1001 this.setCustomValidity(''); 1002 const feedback = this.parentElement?.nextElementSibling; 1003 if (feedback?.classList?.contains('invalid-feedback')) { 1004 feedback.classList.remove('show'); 1005 } 1006 return; 1007 } 1008 validarCampoCelular(this); 1009 }); 1010 1011 document.getElementById('email')?.addEventListener('blur', function () { 1012 validarCampoEmail(this); 1013 }); 1014 1015 document.getElementById('email')?.addEventListener('input', function () { 1016 limparErroServidorEmail(this); 1017 const valor = (this.value || '').trim(); 1018 if (!valor) { 1019 this.classList.remove('invalid', 'valid'); 1020 this.setCustomValidity(''); 1021 return; 1022 } 1023 validarCampoEmail(this); 1024 }); 1025 1026 document.getElementById('email-redefinir')?.addEventListener('blur', function () { 1027 validarCampoEmail(this, document.getElementById('invalid-email-redefinir')); 1028 }); 1029 1030 document.getElementById('email-redefinir')?.addEventListener('input', function () { 1031 const valor = (this.value || '').trim(); 1032 if (!valor) { 1033 this.classList.remove('invalid', 'valid'); 1034 this.setCustomValidity(''); 1035 document.getElementById('invalid-email-redefinir')?.classList.remove('show'); 1036 return; 1037 } 1038 validarCampoEmail(this, document.getElementById('invalid-email-redefinir')); 1039 }); 1040 1041 1042 function fechaAlert() { 1043 const el = document.getElementById('alert_envio-email'); 1044 if (!el) return; 1045 el.remove(); 1046 } 1047 1048 1049 const campos = document.getElementsByName('sexo'); // NodeList 1050 1051 Array.from(campos).forEach((el) => { 1052 el.addEventListener('change', () => { 1053 Array.from(campos).forEach((e) => e.classList.remove('is-invalid')); 1054 }); 1055 }); 1056 1057 function resetLoginValidity(campos = ['username','senha_login']) { 1058 for (const id of campos) document.getElementById(id)?.setCustomValidity(''); 1059 } 1060 1061 function markLoginInvalid({ descricao = 'Credenciais inválidas', campos = ['username','senha_login'] } = {}) { 1062 if (window.toastr) toastr.error(descricao, 'Erro no Login'); 1063 1064 const inputCpf = document.getElementById('username'); 1065 const inputSenha = document.getElementById('senha_login'); 1066 document.getElementById('invalid_senha_login').classList.add('show'); 1067 // marca erro uma vez 1068 for (const id of campos) document.getElementById(id)?.classList.add('invalid'); 1069 1070 // mensagens de feedback (se existirem) 1071 const fbCpf = inputCpf && inputCpf.parentNode && inputCpf.parentNode.children[2]; 1072 const fbSenha = inputSenha && inputSenha.parentNode && inputSenha.parentNode.children[2]; 1073 if (fbCpf) fbCpf.innerHTML = descricao; 1074 if (fbSenha) fbSenha.innerHTML = ''; 1075
1076 // limpar erro quando o usuário voltar a digitar 1077 for (const name of campos) { 1078 const el = document.getElementsByName(name)[0]; 1079 if (!el) continue; 1080 el.addEventListener('input', function clearValidity() { 1081 el.setCustomValidity(''); 1082 el.removeEventListener('input', clearValidity); 1083 }, { once: true }); 1084 } 1085 1086 inputCpf?.focus(); 1087 } 1088 1089 document.getElementById('form_cadastro_encontrado')?.addEventListener('submit', async function(event){ 1090 event.preventDefault(); 1091 event.stopPropagation(); 1092 1093 const form = this; 1094 1095 // limpa erros customizados remanescentes 1096 resetLoginValidity(); 1097 1098 // se quiser evitar campos required ocultos travando, desabilite-os: 1099 // form.querySelectorAll('[required]').forEach(el => { 1100 // const hidden = el.offsetParent === null; 1101 // if (hidden) el.setAttribute('disabled','disabled'); 1102 // else el.removeAttribute('disabled'); 1103 // }); 1104 1105 if (!form.checkValidity()) { 1106 form.classList.add('was-validated'); 1107 form.reportValidity(); 1108 return; 1109 } 1110 document.getElementById('username').classList.remove('invalid'); 1111 document.getElementById('senha_login').classList.remove('invalid'); 1112 document.getElementById('senha_login').classList.add('valid') 1113 document.getElementById('username').classList.add('valid'); 1114 const username = obterDocumentoLogin(document.getElementById('username')?.value || ''); 1115 const password = document.getElementById('senha_login')?.value || ''; 1116 1117 const recaptchaToken = await executarRecaptchaGoogle('LOGIN'); 1118 if (recaptchaToken === null) return; 1119 1120 const loginPayload = { username, password }; 1121 if (recaptchaToken) loginPayload.recaptcha = recaptchaToken; 1122 logar_usuario(loginPayload); 1123 }); 1124 1125 function compareDates(date) { 1126 let parts = date.split('/'); // separa a data pelo caracter '/' 1127 let today = new Date(); // pega a data atual 1128 date = new Date(parts[2], parts[1] - 1, parts[0]); // formata 'date' 1129 // compara se a data informada é maior que a data atual 1130 // e retorna true ou false 1131 return date >= today ? false : true 1132 } 1133 1134 async function cadastrar_usuario(dados) { 1135 load('on', document.body); 1136 1137 const device_id = localStorage.getItem('fmcToken'); 1138 if (device_id) { 1139 dados.device_id = device_id; 1140 dados.location = localStorage.getItem('location'); 1141 } 1142 1143 const resp = await fetch("cadastrar/cliente", { 1144 method: 'POST', 1145 headers: { 1146 "Content-Type": "application/json", 1147 "X-CSRFToken": window.CSRF_TOKEN(), 1148 }, 1149 body: JSON.stringify(dados), 1150 }); 1151 const data = await resp.json(); 1152 1153 if (data.status) { 1154 try { if (typeof filtroParaDadosAnaliticos === 'function') filtroParaDadosAnaliticos('CompleteRegistration', { method: 'site_credentials' }); } catch(_){} 1155 1156 if (window.toastr) toastr.success('Cadastro realizado com sucesso!'); 1157 setTimeout(function(){ 1158 if (document.referrer !== '') { 1159 window.location = document.referrer; 1160 console.log('logou'); 1161 console.log('cliente_id:', dados.documento.replace(/\D/g,'')); 1162 console.log('NM_PRIMEIRO:', dados.nome.split(' ')[0].trim()); 1163 } else { 1164 window.location = '/'; 1165 } 1166 //atualizar_melhor(); 1167 }, 1000); 1168 } else { 1169 if (data.campos && data.campos.length > 0) { 1170 navegarPara('form_cadastro_nao_encontrado') 1171 const input = document.getElementsByName(data.campos[0])[0]; 1172 if (input) { 1173 input.setCustomValidity('Erro input'); 1174 const feedback = input.parentNode && input.parentNode.children[2]; 1175 if (feedback) feedback.innerHTML = data.descricao; 1176 input.focus(); 1177 } 1178 } else { 1179 limparCamposToken(); 1180 if (window.toastr) toastr.error(data.descricao, 'Erro ao cadastrar cliente'); 1181 } 1182 } 1183 1184 load('off', document.body); 1185 } 1186 1187 1188 async function logar_usuario(dados) { 1189 const recaptchaConfigurado = !!(window.recaptcha_site_key && window.recaptcha_site_key()); 1190 if (recaptchaConfigurado && !dados.recaptcha) { 1191 if (window.toastr) toastr.error('Verificação de segurança obrigatória. Tente novamente.'); 1192 return; 1193 } 1194 load('on', document.body); 1195 try { 1196 const device_id = localStorage.getItem('fmcToken'); 1197 if (device_id) { 1198 dados.device_id = device_id; 1199 dados.location = localStorage.getItem('location'); 1200 } 1201 1202 const resp = await fetch('login', { 1203 method: 'POST', 1204 headers: { 1205 'Content-Type': 'application/json', 1206 'X-CSRFToken': window.CSRF_TOKEN(), 1207 }, 1208 body: JSON.stringify(dados), 1209 }); 1210 1211 const data = await resp.json(); 1212 1213 if (data.status) { 1214 document.getElementById('invalid_senha_login').classList.remove('show'); 1215 document.getElementById('username').classList.remove('invalid');
1216 document.getElementById('username').classList.add('valid'); 1217 document.getElementById('senha_login').classList.remove('invalid'); 1218 document.getElementById('senha_login').classList.add('valid'); 1219 1220 try { if (typeof filtroParaDadosAnaliticos === 'function') filtroParaDadosAnaliticos('Login', { method: 'site_credentials' }); } catch(_){} 1221 1222 console.log('logou'); 1223 console.log('cliente_id:', dados.username); 1224 console.log('NM_PRIMEIRO:', data.nm_primeiro); 1225 1226 window.location = obterUrlPosLogin(); 1227 return true; 1228 } else { 1229 // ð um único lugar cuidando dos erros de credencial 1230 markLoginInvalid({ descricao: data.descricao, campos: data.campos }); 1231 return false; 1232 } 1233 } catch (e) { 1234 if (e && e.statusText !== 'error') { 1235 window.toastr && toastr.error('Ocorreu um erro inesperado ao fazer login.', 'Erro ao enviar'); 1236 } 1237 return false; 1238 } finally { 1239 load('off', document.body); 1240 } 1241 } 1242 1243 1244 // TODO: Verificar novos eventos. 1245 // function formAnalytics(dados){ 1246 // for (let dado in dados) { 1247 // if (dado) { 1248 // console.log(dado.value); 1249 1250 // filtroParaDadosAnaliticos('MenuAndCallToAction', { 1251 // event: 'select_content', 1252 // content_type: 'form', 1253 // content_id: 'form:' + dado, 1254 // }); 1255 // } 1256 // } 1257 // filtroParaDadosAnaliticos('GenerateLead', { 1258 // event: 'generate_lead', 1259 // lead_source: 'pagina_cadastro', 1260 // }); 1261 1262 // } 1263 1264 // async function atualizar_melhor() { 1265 // try { 1266 // const resp = await fetch("ecommerce/carrinho/verificar_melhor", { method: 'POST', credentials: 'same-origin' }); 1267 // if (resp.ok) { 1268 // if (typeof atualizarCarrinho === 'function') atualizarCarrinho('inicio'); 1269 // } else { 1270 // if (window.toastr) toastr.error('Ocorreu um erro inesperado ao verificar o melhor carrinho.', 'Erro ao enviar'); 1271 // } 1272 // } catch(e) { 1273 // if (window.toastr) toastr.error('Ocorreu um erro inesperado ao verificar o melhor carrinho.', 'Erro ao enviar'); 1274 // } 1275 // } 1276 1277 /* Função para validar o cadastro */ 1278 1279 1280 async function validarCadastroCPF(documento) { 1281 const f1 = document.getElementById('form_cadastro_encontrado'); 1282 const f2 = document.getElementById('form_valida_token'); 1283 const f3 = document.getElementById('form_cadastro_nao_encontrado'); 1284 f1 && f1.reset(); 1285 f2 && f2.reset(); 1286 f3 && f3.reset(); 1287 1288 load('on', document.body); 1289 1290 const csrf = window.CSRF_TOKEN(); 1291 const body = new URLSearchParams(); 1292 if (csrf) body.set('csrfmiddlewaretoken', csrf); 1293 body.set('documento', documento); 1294 const resp = await fetch("verificar/cadastro", { 1295 method: "POST", 1296 headers: { 1297 "Content-Type": "application/json", 1298 "X-CSRFToken": window.CSRF_TOKEN(), 1299 }, 1300 body: JSON.stringify({ 1301 documento: documento, 1302 }), 1303 }); 1304 const data = await resp.json(); 1305 if (data.status) { 1306 if (data.is_existe) { 1307 document.getElementById('btn-verificar-cpf')?.classList.add('hidden'); 1308 navegarPara('form_cadastro_encontrado'); 1309 document.getElementById('cadastro_nao_econtrado')?.classList.add('hidden'); 1310 document.getElementById('cadastro_econtrado')?.classList.remove('hidden'); 1311 document.getElementById('senha_login')?.focus(); 1312 } else { 1313 resetValidation('form_cadastro_nao_encontrado'); 1314 1315 document.getElementById('btn-verificar-cpf')?.classList.add('hidden'); 1316 navegarPara('form_cadastro_nao_encontrado'); 1317 document.getElementById('cadastro_econtrado')?.classList.add('hidden'); 1318 document.getElementById('cadastro_nao_econtrado')?.classList.remove('hidden'); 1319 } 1320 const emailRedef = document.getElementById('email-redefinir'); 1321 if (emailRedef) emailRedef.value = ''; 1322 fechaAlert(); 1323 } else { 1324 document.getElementById('btn-verificar-cpf')?.classList.remove('hidden'); 1325 document.getElementById('cadastro_nao_econtrado')?.classList.add('hidden'); 1326 document.getElementById('cadastro_econtrado')?.classList.add('hidden'); 1327 const errCpf = document.getElementById('passwordErrorsCpf'); 1328 const errSenha = document.getElementById('passwordErrorsSenha'); 1329 const errCad = document.getElementById('passwordErrorsCadastro'); 1330 if (errCpf) { errCpf.innerHTML = ''; errCpf.classList.remove('text-danger'); } 1331 if (errSenha) { errSenha.innerHTML = ''; errSenha.classList.remove('text-danger'); } 1332 if (errCad) { errCad.innerHTML = ''; errCad.classList.remove('text-danger'); } 1333 // {% if not request|is_mobile and not request|is_tablet %} 1334 // const bg = document.querySelector('.bg-fundo'); 1335 // if (bg) bg.style.paddingBottom = '0px'; 1336 // {% endif %} 1337 } 1338 1339 load('off', document.body); 1340 1341 } 1342 1343 document.getElementById('link-redefinir-senha')?.addEventListener('click', function (event) { 1344 document.getElementById('email-redefinir').removeAttribute('disabled'); 1345 document.getElementById('btn-enviar-email-redefinir').removeAttribute('disabled') 1346 }); 1347 1348 document.getElementById('btn-verificar-cpf')?.addEventListener('click', function (event) { 1349 event.preventDefault(); 1350 event.stopPropagation(); 1351 const form = document.getElementById('form_cpf'); 1352 const cpf = document.getElementById('username') 1353 document.getElementById('invalid_cpf').classList.remove('show'); 1354 cpf.classList.remove('invalid'); 1355 cpf.classList.remove('valid'); 1356 1357 let validacao = validarDocumentoLogin(cpf.value); 1358 1359 if(validacao) { 1360 validarForm(form);
1361 validarCadastroCPF(obterDocumentoLogin(cpf.value)) 1362 } else { 1363 document.getElementById('invalid_cpf').classList.add('show'); 1364 cpf.classList.add('invalid'); 1365 cpf.classList.remove('valid'); 1366 } 1367 }); 1368 1369 let typingTimer; 1370 const typingDelay = 1000; 1371 1372 document.getElementById('username').addEventListener('input', function(){ 1373 const cpfEl = document.getElementById('username'); 1374 const form = document.getElementById('form_cpf'); 1375 const btn = document.getElementById('btn-verificar-cpf'); 1376 if (btn && btn.offsetParent !== null) return; 1377 clearTimeout(typingTimer); 1378 typingTimer = setTimeout(function(){ 1379 if(validarDocumentoLogin(cpfEl.value)){ 1380 validarForm(form); 1381 validarCadastroCPF(obterDocumentoLogin(cpfEl.value)) 1382 } 1383 }, typingDelay); 1384 }); 1385 1386 document.getElementById('form_cpf')?.addEventListener('submit', (e) => { 1387 e.preventDefault(); 1388 const cpfEl = document.getElementById('username'); 1389 const form = document.getElementById('form_cpf'); 1390 const btn = document.getElementById('btn-verificar-cpf'); 1391 //if (btn && btn.offsetParent !== null) return; 1392 clearTimeout(typingTimer); 1393 const documentoLogin = obterDocumentoLogin(cpfEl.value); 1394 if (validarDocumentoLogin(documentoLogin)) { 1395 validarForm(form); 1396 validarCadastroCPF(documentoLogin); 1397 } 1398 }); 1399 1400 // (function(){ 1401 // const cpfEl = document.getElementById('username'); 1402 // if (!cpfEl) return; 1403 // let typingTimer; 1404 // const typingDelay = 1000; 1405 // cpfEl.addEventListener('input', function(){ 1406 // const btn = document.getElementById('btn-verificar-cpf'); 1407 // if (btn && btn.offsetParent !== null) return; 1408 // clearTimeout(typingTimer); 1409 // typingTimer = setTimeout(function(){ 1410 // validarCPF(cpfEl); 1411 // }, typingDelay); 1412 // }); 1413 // })(); 1414 1415function show(el) { el?.classList.remove('hidden'); } 1416function hide(el) { el?.classList.add('hidden'); } 1417 1418function setEnabledRequired(el, enabled) { 1419 if (!el) return; 1420 el.disabled = !enabled; 1421 if (enabled) el.setAttribute('required', 'required'); 1422 else el.removeAttribute('required'); 1423} 1424 1425function atualizarProfSaude() { 1426 const checked = document.querySelector('input[name="is_profissional_saude"]:checked'); 1427 const isProf = checked?.value === 'sim'; 1428 1429 const bloco = document.getElementById('profissionais_saude'); 1430 const ufSelect = document.getElementById('uf_id'); 1431 const crSelect = document.getElementById('cr'); 1432 const codigoCR = document.getElementById('codigo_cr'); 1433 1434 if (isProf) { 1435 show(bloco); 1436 setEnabledRequired(ufSelect, true); 1437 setEnabledRequired(crSelect, true); 1438 setEnabledRequired(codigoCR, true); 1439 if (ufSelect?.querySelector('option[value="41"]')) ufSelect.value = '41'; 1440 if (crSelect) { 1441 const crmOpt = Array.from(crSelect.options || []).find( 1442 (o) => (o?.value || '').toLowerCase() === 'crm' 1443 ); 1444 if (crmOpt) crSelect.value = crmOpt.value; 1445 } 1446 requestAnimationFrame(() => { 1447 codigoCR?.classList.remove('is-valid','is-invalid'); 1448 codigoCR?.focus(); 1449 codigoCR?.setSelectionRange(0, codigoCR.value.length); 1450 }); 1451 } else { 1452 hide(bloco); 1453 // Limpa valores e desabilita/retira required 1454 if (ufSelect) ufSelect.value = ''; 1455 if (crSelect) crSelect.value = ''; 1456 if (codigoCR) codigoCR.value = ''; 1457 setEnabledRequired(ufSelect, false); 1458 setEnabledRequired(crSelect, false); 1459 setEnabledRequired(codigoCR, false); 1460 } 1461} 1462 1463document.addEventListener('change', (e) => { 1464 if (e.target.matches('input[name="is_profissional_saude"]')) { 1465 atualizarProfSaude(); 1466 } 1467}); 1468 1469document.addEventListener('DOMContentLoaded', atualizarProfSaude); 1470 1471 1472/* Função para validar a força da senha e igualdade entre as senhas */ 1473 1474 function validaSenhaConfirmacao(password, confirm) { 1475 let senha = password; 1476 let confirmacao = confirm; 1477 1478 if (senha !== confirmacao) { 1479 return false; 1480 } else { 1481 return true; 1482 } 1483 } 1484 1485 let reduceErrorsCadastro = []; 1486 1487 function validaSenhaForca(password) { 1488 let senha = password; 1489 let errorsSenha = []; 1490 1491 // Regras de validação 1492 if (senha.length < 8) { 1493 errorsSenha.push("Pelo menos 8 caracteres"); 1494 } 1495 if (!/[A-Z]/.test(senha)) { 1496 errorsSenha.push("Pelo menos 1 caractere maiúsculo"); 1497 } 1498 if (!/[a-z]/.test(senha)) { 1499 errorsSenha.push("Pelo menos 1 caractere minúsculo"); 1500 } 1501 if (!/[0-9]/.test(senha)) { 1502 errorsSenha.push("Pelo menos 1 número"); 1503 } 1504 if (!/[$*&@#!?.,;:_\-+=%|/\\(){}[\]]/.test(senha)) { 1505 errorsSenha.push(`Pelo menos 1 caractere especial (Ex: $*&@#!?.,;:_-+=%|/\\(){}[])`); 1506 } else if (senha.length === 0) { 1507 errorsSenha = []; 1508 } 1509 1510 // Usar reduce para retornar apenas mensagens únicas
1511 let reduceErrorsCadastro = errorsSenha.reduce((acc, current) => { 1512 if (!acc.includes(current)) { 1513 acc.push(current); 1514 } 1515 return acc; 1516 }, []); 1517 1518 return reduceErrorsCadastro; 1519 } 1520 1521 function exibeErrosSenha(password, is_reset = false) { 1522 let errors = validaSenhaForca(password); 1523 const error_length = is_reset ? 'req-length-reset' : 'req-length'; 1524 const error_uppercase = is_reset ? 'req-uppercase-reset' : 'req-uppercase'; 1525 const error_lowercase = is_reset ? 'req-lowercase-reset' : 'req-lowercase'; 1526 const error_number = is_reset ? 'req-number-reset' : 'req-number'; 1527 const error_special = is_reset ? 'req-special-reset' : 'req-special'; 1528 1529 // Atualizar a lista de requisitos 1530 if (password.length >= 8) { 1531 document.getElementById(error_length).classList.remove('text-danger'); 1532 document.getElementById(error_length).classList.add('text-success'); 1533 } else { 1534 document.getElementById(error_length).classList.remove('text-success'); 1535 document.getElementById(error_length).classList.add('text-danger'); 1536 } 1537 1538 if (/[A-Z]/.test(password)) { 1539 document.getElementById(error_uppercase).classList.remove('text-danger'); 1540 document.getElementById(error_uppercase).classList.add('text-success'); 1541 } else { 1542 document.getElementById(error_uppercase).classList.remove('text-success'); 1543 document.getElementById(error_uppercase).classList.add('text-danger'); 1544 } 1545 1546 if (/[a-z]/.test(password)) { 1547 document.getElementById(error_lowercase).classList.remove('text-danger'); 1548 document.getElementById(error_lowercase).classList.add('text-success'); 1549 } else { 1550 document.getElementById(error_lowercase).classList.remove('text-success'); 1551 document.getElementById(error_lowercase).classList.add('text-danger'); 1552 } 1553 1554 if (/[0-9]/.test(password)) { 1555 document.getElementById(error_number).classList.remove('text-danger'); 1556 document.getElementById(error_number).classList.add('text-success'); 1557 } else { 1558 document.getElementById(error_number).classList.remove('text-success'); 1559 document.getElementById(error_number).classList.add('text-danger'); 1560 } 1561 1562 if (/[$*&@#!?.,;:_\-+=%|/\\(){}[\]]/.test(password)) { 1563 document.getElementById(error_special).classList.remove('text-danger'); 1564 document.getElementById(error_special).classList.add('text-success'); 1565 } else { 1566 document.getElementById(error_special).classList.remove('text-success'); 1567 document.getElementById(error_special).classList.add('text-danger'); 1568 } 1569 1570 // // Exibir erros gerais 1571 if (errors.length > 0) { 1572 if (is_reset) { 1573 document.getElementById('senha_redefinir').classList.add('invalid'); 1574 document.getElementById('senha_redefinir').classList.remove('valid'); 1575 } else { 1576 document.getElementById('senha_cadastro').classList.add('invalid'); 1577 document.getElementById('senha_cadastro').classList.remove('valid'); 1578 } 1579 } else { 1580 if (is_reset) { 1581 document.getElementById('senha_redefinir').classList.remove('invalid'); 1582 document.getElementById('senha_redefinir').classList.add('valid'); 1583 } else { 1584 document.getElementById('senha_cadastro').classList.remove('invalid'); 1585 document.getElementById('senha_cadastro').classList.add('valid'); 1586 } 1587 } 1588 1589 // refletir no validity do campo 1590 const inputSenha = is_reset ? document.getElementById('senha_redefinir') : document.getElementById('senha_cadastro'); 1591 if (inputSenha) inputSenha.setCustomValidity(errors.length > 0 ? 'A senha não atende os requisitos.' : ''); 1592 } 1593 document.querySelectorAll('[name="senha"]').forEach((el) => { 1594 let timer; // cada input tem seu próprio timer 1595 el.addEventListener('input', () => { 1596 clearTimeout(timer); 1597 timer = setTimeout(() => { 1598 const password = document.getElementById('senha_cadastro')?.value || ''; 1599 const passwordRedefinir = document.getElementById('senha_redefinir')?.value || ''; 1600 exibeErrosSenha(password || passwordRedefinir, !password); // segundo arg true = redefinição 1601 }, 1000); 1602 }); 1603 }); 1604 1605 function atualizarStatusConfirmacao(is_reset = false) { 1606 const senhaId = is_reset ? 'senha_redefinir' : 'senha_cadastro'; 1607 const confirmaId = is_reset ? 'senha_redefinir_confirmacao' : 'senha_cadastro_confirmacao'; 1608 const msgId = is_reset ? 'passwordErrorsConfirmacaoReset' : 'passwordErrorsConfirmacao'; 1609 1610 const senha = document.getElementById(senhaId)?.value || ''; 1611 const confirmacao = document.getElementById(confirmaId)?.value || ''; 1612 const msg = document.getElementById(msgId); 1613 const inp = document.getElementById(confirmaId); 1614 if (!inp || !msg) return; 1615 1616 if (!confirmacao) { 1617 msg.textContent = ''; 1618 msg.classList.remove('text-danger', 'text-success'); 1619 inp.classList.remove('invalid', 'valid'); 1620 inp.setCustomValidity(''); 1621 return; 1622 } 1623 1624 const isConfirmada = validaSenhaConfirmacao(senha, confirmacao); 1625 if (!isConfirmada) { 1626 msg.textContent = 'As senhas não conferem!'; 1627 msg.classList.remove('text-success'); 1628 msg.classList.add('text-danger'); 1629 inp.classList.add('invalid'); 1630 inp.classList.remove('valid'); 1631 inp.setCustomValidity('As senhas não conferem!'); 1632 } else { 1633 msg.textContent = ''; 1634 msg.classList.remove('text-danger'); 1635 msg.classList.add('text-success'); 1636 inp.classList.remove('invalid');
1637 inp.classList.add('valid'); 1638 inp.setCustomValidity(''); 1639 } 1640 } 1641 1642 // CONFIRMAÃÃO (revalida também quando a senha principal muda) 1643 [ 1644 'senha_cadastro', 1645 'senha_cadastro_confirmacao', 1646 'senha_redefinir', 1647 'senha_redefinir_confirmacao' 1648 ].forEach((id) => { 1649 const el = document.getElementById(id); 1650 if (!el) return; 1651 let timer; 1652 el.addEventListener('input', () => { 1653 clearTimeout(timer); 1654 timer = setTimeout(() => { 1655 atualizarStatusConfirmacao(false); 1656 atualizarStatusConfirmacao(true); 1657 }, 300); 1658 }); 1659 }); 1660 1661 function initIMask(){ 1662 // Codigo que troca o CPF para texto livre caso email seja preenchido 1663 1664 // const el = document.getElementById('username'); 1665 // const mask = IMask(el, { 1666 // mask: [ 1667 // { mask: '000.000.000-00', overwrite: true, lazy: true }, // CPF 1668 // { mask: /[\s\S]*/ } // texto livre 1669 // ], 1670 // dispatch: (appended, ctx) => { 1671 // const v = (ctx.value + appended); 1672 // const digits = v.replace(/\D/g,''); 1673 // const soNumOuPont = /^[\d.\-\s]*$/.test(v); 1674 // return (!/[A-Za-z@]/.test(v) && soNumOuPont && digits.length > 0) 1675 // ? ctx.compiledMasks[0] // CPF 1676 // : ctx.compiledMasks[1]; // texto 1677 // } 1678 // }); 1679 // mask.on('accept', () => { 1680 // const isCPF = mask.masked.currentMask && mask.masked.currentMask.mask === '000.000.000-00'; 1681 // if (isCPF) { 1682 // el.setAttribute('inputmode','numeric'); 1683 // el.setAttribute('maxlength','14'); 1684 // } else { 1685 // el.setAttribute('inputmode','text'); 1686 // el.removeAttribute('maxlength'); 1687 // } 1688 // }); 1689 const tel = document.querySelector('#celular, [name="celular"]'); 1690 const dat_nasc = document.querySelector('#dat_nasc, [name="dat_nasc"]'); 1691 const username = document.querySelector('#username, [name="username"]'); 1692 if(tel) { 1693 IMask(tel, { mask: '(00) 00000-0000' }) 1694 } 1695 if(dat_nasc) { 1696 IMask(dat_nasc, { mask: '00/00/0000' }) 1697 } 1698 if(username) { 1699 if (isLoginCpfCnpjHabilitado()) { 1700 // Máscara CPF/CNPJ alfanumérico â ativa só com data-login-cpf-cnpj (Rosario). 1701 IMask(username, { 1702 mask: [ 1703 { 1704 mask: '000.000.000-00', 1705 regex: '^\\d{0,11}$' 1706 }, 1707 { 1708 mask: 'SS.SSS.SSS/SSSS-00', 1709 regex: '^(?:[A-Z]|\\d{12,})[0-9A-Z]*$', 1710 definitions: { 1711 S: /[0-9A-Z]/i 1712 } 1713 } 1714 ], 1715 prepare: (str) => str.toUpperCase(), 1716 dispatch: (appended, dynamicMasked) => { 1717 const base = (dynamicMasked.value + appended) 1718 .replace(/[^0-9A-Za-z]/g, '') 1719 .toUpperCase(); 1720 return dynamicMasked.compiledMasks.find( 1721 m => m.regex && base.match(new RegExp(m.regex)) 1722 ) || dynamicMasked.compiledMasks[1]; 1723 } 1724 }); 1725 } else { 1726 IMask(username, { mask: '000.000.000-00' }) 1727 } 1728 1729 const usernameInput = document.querySelector('#username, [name="username"]'); 1730 usernameInput?.addEventListener('keyup', () => { 1731 console.log('keyup'); 1732 }) 1733 usernameInput?.addEventListener('change', () => { 1734 console.log('change'); 1735 }) 1736 usernameInput?.addEventListener('input', () => { 1737 console.log('input'); 1738 }) 1739 usernameInput?.addEventListener('paste', () => { 1740 console.log('paste'); 1741 }) 1742 } 1743 1744 } 1745 1746 1747 1748 1749 if (window._iMaskCarregado) { 1750 initIMask(); 1751 } else { 1752 window.addEventListener('imask:ready', initIMask, { once: true }); 1753 } 1754 1755 document.addEventListener('DOMContentLoaded', async () => { 1756 1757 }); 1758 1759 1760 document.addEventListener('DOMContentLoaded', function () { 1761 // captura todos os gatilhos com data-toggle="collapse" 1762 const triggers = document.querySelectorAll('[data-toggle="collapse"]'); 1763
1764 triggers.forEach(function (trigger) { 1765 trigger.addEventListener('click', function (e) { 1766 e.preventDefault(); 1767 1768 const selector = trigger.getAttribute('data-target'); 1769 const panel = document.querySelector(selector); 1770 if (!panel) return; 1771 1772 const isOpen = !panel.classList.contains('hidden'); 1773 1774 // toggle visibilidade 1775 panel.classList.toggle('hidden', isOpen); 1776 1777 // acessibilidade 1778 trigger.setAttribute('aria-expanded', String(!isOpen)); 1779 panel.setAttribute('aria-hidden', String(isOpen)); 1780 1781 // foco no input ao abrir 1782 if (!isOpen) { 1783 const firstInput = panel.querySelector('input[type="email"], input[type="text"]'); 1784 if (firstInput) setTimeout(() => firstInput.focus(), 50); 1785 } 1786 }); 1787 }); 1788 }); 1789 1790 1791 1792 1793 // Toggle de visibilidade de senha (olho mágico) 1794 (function initPasswordToggle(){ 1795 const ICON_EYE = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#6b7280" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8Z"/><circle cx="12" cy="12" r="3"/></svg>'; 1796 const ICON_EYE_OFF = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#6b7280" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.94 10.94 0 0 1 12 20c-7 0-11-8-11-8a20.3 20.3 0 0 1 5.06-6.94"/><path d="M1 1l22 22"/><path d="M10.58 10.58a2 2 0 1 0 2.83 2.83"/><path d="M9.88 4.26A10.94 10.94 0 0 1 12 4c7 0 11 8 11 8a20.3 20.3 0 0 1-3.12 4.88"/></svg>'; 1797 1798 function setIcon(el, isVisible){ 1799 if (!el) return; 1800 el.innerHTML = isVisible ? ICON_EYE_OFF : ICON_EYE; 1801 el.setAttribute('aria-pressed', isVisible ? 'true' : 'false'); 1802 el.setAttribute('aria-label', isVisible ? 'Ocultar senha' : 'Mostrar senha'); 1803 } 1804 1805 function getPasswordInputForToggle(toggleEl){ 1806 if (!toggleEl) return null; 1807 // estrutura esperada: <div class="relative"> <input.senha /> <span.mostra-senha /> <label /> </div> 1808 const prev = toggleEl.previousElementSibling; 1809 if (prev && prev.matches('input.senha')) return prev; 1810 const container = toggleEl.closest('.relative') || toggleEl.parentElement; 1811 return container ? container.querySelector('input.senha') : null; 1812 } 1813 1814 function toggleVisibility(toggleEl){ 1815 const input = getPasswordInputForToggle(toggleEl); 1816 if (!input) return; 1817 const toText = input.getAttribute('type') === 'password'; 1818 input.setAttribute('type', toText ? 'text' : 'password'); 1819 setIcon(toggleEl, toText); 1820 // manter foco no input após alternar, para melhor UX 1821 input.focus({ preventScroll: true }); 1822 // reposiciona cursor ao final 1823 const val = input.value; 1824 input.setSelectionRange(val.length, val.length); 1825 } 1826 1827 function initOne(toggleEl){ 1828 if (!toggleEl || toggleEl._pwInit) return; 1829 toggleEl._pwInit = true; 1830 toggleEl.setAttribute('role', 'button'); 1831 toggleEl.setAttribute('tabindex', '0'); 1832 toggleEl.style.userSelect = 'none'; 1833 setIcon(toggleEl, false); 1834 toggleEl.addEventListener('click', (e) => { 1835 e.preventDefault(); 1836 toggleVisibility(toggleEl); 1837 }); 1838 toggleEl.addEventListener('keydown', (e) => { 1839 if (e.key === 'Enter' || e.key === ' ') { 1840 e.preventDefault(); 1841 toggleVisibility(toggleEl); 1842 } 1843 }); 1844 } 1845 1846 function initAll(){ 1847 document.querySelectorAll('.mostra-senha').forEach(initOne); 1848 } 1849 1850 if (document.readyState === 'loading') { 1851 document.addEventListener('DOMContentLoaded', initAll, { once: true }); 1852 } else { 1853 initAll(); 1854 } 1855 })(); 1856 1857 1858 // Abrir modal de login integrado voai 1859 function abrirLoginIntegrado(modal) { 1860 openModal(modal); 1861 document.getElementById('form-voai').reset(); 1862 document.getElementById('invalid_cpf_voai').innerHTML = ''; 1863 document.getElementById('invalid_password_voai').innerHTML = ''; 1864 document.getElementById('cpf_voai').classList.remove('valid'); 1865 document.getElementById('password_voai').classList.remove('valid'); 1866 document.getElementById('invalid_cpf_voai').classList.remove('show'); 1867 document.getElementById('invalid_password_voai').classList.remove('show'); 1868 document.getElementById('cpf_voai').classList.remove('invalid'); 1869 document.getElementById('password_voai').classList.remove('invalid'); 1870 document.getElementById('cpf_voai').focus(); 1871 aplicarIMask(); 1872 1873 } 1874 1875 function aplicarIMask() { 1876 const cpf = document.querySelector('#cpf_voai, [name="cpf_voai"]'); 1877 if(cpf) { 1878 IMask(cpf, { mask: '000.000.000-00' }) 1879 } 1880 } 1881 1882 function logarVoai() { 1883 const form = document.getElementById('form-voai'); 1884 const cpfInput = document.getElementById('cpf_voai'); 1885 const senhaInput = document.getElementById('password_voai'); 1886 const cpfFb = document.getElementById('invalid_cpf_voai'); 1887 const senhaFb = document.getElementById('invalid_password_voai'); 1888 1889 // limpa feedbacks e estados 1890 cpfFb.innerHTML = ''; 1891 senhaFb.innerHTML = ''; 1892 cpfFb.classList.remove('show'); 1893 senhaFb.classList.remove('show'); 1894 cpfInput.classList.remove('invalid'); 1895 senhaInput.classList.remove('invalid'); 1896 1897 const cpfDigits = (cpfInput.value || '').replace(/\D/g, ''); 1898 let hasError = false;
1899 1900 if (!cpfDigits || cpfDigits.length !== 11) { 1901 cpfFb.innerHTML = 'Informe um CPF válido'; 1902 cpfFb.classList.add('show'); 1903 cpfInput.classList.add('invalid'); 1904 hasError = true; 1905 } 1906 if (!senhaInput.value) { 1907 senhaFb.innerHTML = 'Informe uma senha válida'; 1908 senhaFb.classList.add('show'); 1909 senhaInput.classList.add('invalid'); 1910 hasError = true; 1911 } 1912 1913 if (hasError) { 1914 if (cpfInput.classList.contains('invalid')) cpfInput.focus(); 1915 else senhaInput.focus(); 1916 form?.classList.add('invalid'); 1917 return; 1918 } 1919 1920 load('on', document.body); 1921 1922 fetch('auth/voai/login', { 1923 method: 'POST', 1924 headers: { 1925 'Content-Type': 'application/json', 1926 'X-CSRFToken': window.CSRF_TOKEN(), 1927 }, 1928 body: JSON.stringify({ username: cpfDigits, password: senhaInput.value }), 1929 }).then(response => response.json()).then(data => { 1930 console.log(data); 1931 if(data.status) { 1932 toastr.success('Login realizado com sucesso!'); 1933 closeModal(); 1934 window.location.href = obterUrlPosLogin(); 1935 } else { 1936 toastr.error(data.descricao); 1937 cpfInput.focus(); 1938 } 1939 }).catch(error => { 1940 console.error('Erro ao fazer login:', error); 1941 }).finally(() => { 1942 load('off', document.body); 1943 }); 1944 } 1945 1946 document.getElementById('form-voai')?.addEventListener('submit', function(e){ 1947 e.preventDefault(); 1948 e.stopPropagation(); 1949 logarVoai(); 1950 }); 1951 1952 // feedback imediato ao digitar 1953 document.getElementById('cpf_voai')?.addEventListener('input', () => { 1954 const el = document.getElementById('cpf_voai'); 1955 const fb = document.getElementById('invalid_cpf_voai'); 1956 el.classList.remove('invalid'); 1957 fb.classList.remove('show'); 1958 fb.innerHTML = ''; 1959 }); 1960 document.getElementById('password_voai')?.addEventListener('input', () => { 1961 const el = document.getElementById('password_voai'); 1962 const fb = document.getElementById('invalid_password_voai'); 1963 el.classList.remove('invalid'); 1964 fb.classList.remove('show'); 1965 fb.innerHTML = ''; 1966 }); 1967 1968 document.getElementById('form-voai')?.addEventListener('keydown', (e) => { 1969 if (e.key === 'Enter') { 1970 e.preventDefault(); 1971 const form = e.currentTarget; 1972 if (form && typeof form.requestSubmit === 'function') { 1973 form.requestSubmit(); 1974 } else { 1975 logarVoai(); 1976 } 1977 } 1978 }); 1979 1980 // Google OAuth: redireciona para a rota do backend que fará o redirect para o Google 1981 (function() { 1982 const originalFetch = window.fetch; 1983 window.fetch = function(...args) { 1984 const url = args[0]; 1985 if (typeof url === 'string' && url.includes('accounts.google.com/o/oauth2')) { 1986 console.warn('Bloqueada tentativa de fetch para Google OAuth. Redirecionando corretamente...'); 1987 window.location.href = '/auth/google/redirect'; 1988 return Promise.reject(new Error('OAuth deve usar redirect, não fetch')); 1989 } 1990 return originalFetch.apply(this, args); 1991 }; 1992 1993 const btnGoogle = document.getElementById('btn-entrar-com-google'); 1994 if (btnGoogle) { 1995 const newBtn = btnGoogle.cloneNode(true); 1996 btnGoogle.parentNode.replaceChild(newBtn, btnGoogle); 1997 1998 newBtn.addEventListener('click', function (e) { 1999 e.preventDefault(); 2000 e.stopPropagation(); 2001 e.stopImmediatePropagation(); 2002 2003 if (this.disabled) return; 2004 this.disabled = true; 2005 2006 const redirectUrl = '/auth/google/redirect'; 2007 2008 window.location.href = redirectUrl; 2009 return false; 2010 }, true); 2011 } 2012 })(); 2013 2014 2015
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.