Título

Mensagem...

Excluir Chave?

Esta chave Pix será desconectada e liberada do Banco Central.

Processando

Aguarde um momento de forma segura...

Excluir Conta?

Essa ação é permanente e não pode ser desfeita. Tem certeza?

Excluir Cofrinho?

Todo o saldo será transferido de volta para sua conta principal.

Cancelar Plano Pro?

Você perderá todos os benefícios e voltará ao plano Grátis.

Ativar Plano Pro?

Será debitado R$ 9,90 da sua conta corrente.

CdrPay

Boas-vindas
Digite o seu CPF ou CNPJ para acessar à sua conta.
Sua Senha
Informe a sua senha segura para entrar.
Verificação
Enviamos um código de segurança para o e-mail
Tipo de Conta
Selecione se você é Pessoa Física ou Jurídica.

Pessoa Física

Para você, indivíduo

Pessoa Jurídica

Para sua empresa

Dados Pessoais
Informe seus dados conforme documento.
Dados da Empresa
Informe os dados do CNPJ.
Endereço
Obrigatório pelo Banco Central para abrir a sua conta.

Contato e Renda
Complete com os seus dados para validação.

Validar E-mail
Enviamos um código para
.direction === 'out') { titleIcon = ''; } else if (t.type === 'cofrinho' && t.direction === 'in') { titleIcon = ''; } return `
${titleIcon}${title} ${dateStr}

${desc}

`; } // ============= SINCRONIZAR SALDO COM ASAAS ============= async function syncBalanceWithAsaas() { const fd = new FormData(); fd.append('action', 'sync_asaas_balance'); fd.append('csrf_token', CSRF_TOKEN); try { const res = await fetch(API_URL, { method: 'POST', body: fd }); const data = await res.json(); if (data.success) { console.log('Saldo sincronizado com Asaas:', data.total_balance); userFreeBalance = parseFloat(data.balance) || 0; currentVaultBalance = parseFloat(data.vault_balance) || 0; currentBalanceValue = data.total_balance; updateBalanceText(currentBalanceValue); updateBalanceDetail(userFreeBalance, currentVaultBalance); const vbDisplay = document.getElementById('vault-total-display'); if(vbDisplay) vbDisplay.innerText = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(currentVaultBalance); const availablePixText = document.getElementById('availablePixText'); if(availablePixText) { availablePixText.innerText = 'Saldo disponível: ' + new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance); } const vaultOpAvailable = document.getElementById('vaultOpAvailable'); if(vaultOpAvailable) { const type = document.getElementById('vaultOpType')?.value; if(type === 'deposit') { vaultOpAvailable.innerText = `Saldo disponível na conta: ${new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance)}`; } } if (data.tx_synced > 0) { console.log(data.tx_synced + ' transações sincronizadas'); } return true; } } catch (e) { console.error('Erro ao sincronizar saldo:', e); } return false; } async function fetchRealtimeData() { const fd = new FormData(); fd.append('action', 'get_realtime_data'); fd.append('csrf_token', CSRF_TOKEN); try { const res = await fetch(API_URL, { method: 'POST', body: fd }); if(res.ok) { const data = await res.json(); if(data.success) { userFreeBalance = parseFloat(data.balance) || 0; currentVaultBalance = parseFloat(data.vault_balance) || 0; currentBalanceValue = data.total_balance; updateBalanceText(currentBalanceValue); updateBalanceDetail(userFreeBalance, currentVaultBalance); const availablePixText = document.getElementById('availablePixText'); if(availablePixText) { availablePixText.innerText = 'Saldo disponível: ' + new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance); } const vbDisplay = document.getElementById('vault-total-display'); if(vbDisplay) vbDisplay.innerText = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(currentVaultBalance); const vaultOpAvailable = document.getElementById('vaultOpAvailable'); if(vaultOpAvailable) { const type = document.getElementById('vaultOpType')?.value; if(type === 'deposit') { vaultOpAvailable.innerText = `Saldo disponível na conta: ${new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance)}`; } } if (data.transactions.length > 0) { const newestTx = data.transactions[0]; const newestId = parseInt(newestTx.id); if (lastTxId === null) lastTxId = newestId; else if (newestId > lastTxId) { lastTxId = newestId; } } let recentHTML = ''; let extractHTML = ''; data.transactions.slice(0, 5).forEach(t => { recentHTML += generateTransactionHTML(t); }); data.transactions.forEach(t => { extractHTML += generateTransactionHTML(t); }); const recentList = document.getElementById('recent-activity-list'); const extractList = document.getElementById('full-extract-list'); if(recentList) recentList.innerHTML = recentHTML || '
Nenhuma movimentação recente.
'; if(extractList) { extractList.innerHTML = extractHTML || '
Nenhuma transação encontrada.
'; applyExtractFilter(); } let notifHTML = ''; let unreadCount = 0; const uid = 0; const lastSeenTxId = parseInt(localStorage.getItem('lastSeenTxId_' + uid)) || 0; data.transactions.forEach(t => { if (parseInt(t.id) > lastSeenTxId) unreadCount++; notifHTML += generateNotificationHTML(t); }); const notifList = document.getElementById('notifications-list'); if(notifList) { if(notifHTML === '') { notifList.innerHTML = '

Nenhuma notificação ainda.
'; } else { notifList.innerHTML = notifHTML; } } const badge = document.getElementById('notification-badge'); if(badge) { badge.style.display = unreadCount > 0 ? 'block' : 'none'; } } } } catch(e) { console.error('Erro ao buscar dados:', e); } } document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible" && document.getElementById('home-screen')?.classList.contains('active')) { fetchRealtimeData(); } }); // ============= COMPROVANTES PDF ============= function generateReceiptPDF(receipt) { if (!receipt) return; const { jsPDF } = window.jspdf; const doc = new jsPDF(); const primaryColor = "#0F172A"; doc.setFillColor(primaryColor); doc.rect(0, 0, 210, 40, 'F'); doc.setTextColor(255, 255, 255); doc.setFontSize(26); doc.setFont("helvetica", "bold"); doc.text("CdrPay", 105, 25, null, null, "center"); doc.setTextColor(0, 0, 0); doc.setFontSize(16); doc.setFont("helvetica", "bold"); doc.text("Comprovante de Transação", 105, 60, null, null, "center"); let rawAmount = receipt.amount.toString().replace('R$', '').trim(); doc.setFontSize(36); doc.setTextColor(15, 23, 42); doc.text("R$ " + rawAmount, 105, 80, null, null, "center"); let y = 105; doc.setFontSize(10); doc.setTextColor(100, 100, 100); doc.text("ID da Transação", 20, y); doc.setTextColor(0, 0, 0); doc.setFontSize(12); doc.text(receipt.id || "---", 20, y + 5); y += 16; doc.setFontSize(10); doc.setTextColor(100, 100, 100); doc.text("Data e Hora", 20, y); doc.setTextColor(0, 0, 0); doc.setFontSize(12); doc.text(receipt.date || "---", 20, y + 5); y += 16; doc.setFontSize(10); doc.setTextColor(100, 100, 100); doc.text("Descrição", 20, y); doc.setTextColor(0, 0, 0); doc.setFontSize(12); doc.text(receipt.description || "Transferência / Pagamento", 20, y + 5); y += 14; doc.setDrawColor(226, 232, 240); doc.line(20, y, 190, y); y += 10; doc.setFontSize(11); doc.setTextColor(15, 23, 42); doc.setFont("helvetica", "bold"); doc.text("DADOS DO PAGADOR", 20, y); y += 7; doc.setFontSize(10); doc.setFont("helvetica", "normal"); doc.setTextColor(80, 80, 80); doc.text("Nome: " + (receipt.sender || "---"), 20, y); y += 6; doc.text("CPF/CNPJ: " + (receipt.sender_cpf || "---"), 20, y); y += 6; doc.text("Banco: " + (receipt.sender_bank || "---"), 20, y); y += 6; doc.text("Agência: " + (receipt.sender_agency || "---"), 20, y); y += 10; doc.setDrawColor(226, 232, 240); doc.line(20, y, 190, y); y += 10; doc.setFontSize(11); doc.setTextColor(15, 23, 42); doc.setFont("helvetica", "bold"); doc.text("DADOS DO RECEBEDOR", 20, y); y += 7; doc.setFontSize(10); doc.setFont("helvetica", "normal"); doc.setTextColor(80, 80, 80); doc.text("Nome: " + (receipt.receiver || "---"), 20, y); y += 6; doc.text("CPF/CNPJ: " + (receipt.receiver_cpf || "---"), 20, y); y += 6; doc.text("Banco: " + (receipt.receiver_bank || "---"), 20, y); y += 6; doc.text("Agência: " + (receipt.receiver_agency || "---"), 20, y); y += 16; doc.setDrawColor(226, 232, 240); doc.line(20, y, 190, y); y += 12; doc.setFontSize(9); doc.setTextColor(150, 150, 150); doc.text("CdrPay", 105, y, null, null, "center"); doc.text("Este comprovante possui valor legal e atesta que a transação foi realizada com sucesso.", 105, y + 5, null, null, "center"); const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); if (isMobile) { const blob = doc.output('blob'); const url = URL.createObjectURL(blob); window.open(url, '_blank'); } else { doc.save("comprovante-cdrpay-" + (receipt.id || "tx") + ".pdf"); } } async function generateHistoryPDF(localTxId) { showWait(); const fd = new FormData(); fd.append('action', 'get_receipt_data'); fd.append('tx_id', localTxId); fd.append('csrf_token', CSRF_TOKEN); try { const res = await fetch(API_URL, { method: 'POST', body: fd }); const data = await res.json(); if (data.success) { generateReceiptPDF(data.receipt); } else { showModal('Erro', data.message || 'Erro ao gerar comprovante.', 'error'); } } catch(e) { showModal('Erro', 'Falha ao buscar dados do comprovante.', 'error'); } finally { hideWait(); } } // ============= INICIALIZAÇÃO ============= -paper-plane" style="margin-right: 6px; color: var(--text-main);">'; } else if (t.type === 'boleto') { titleIcon = ''; } else if (t.type === 'cofrinho' && t.direction === 'out') { titleIcon = ''; } else if (t.type === 'cofrinho' && t.direction === 'in') { titleIcon = ''; } return `
${titleIcon}${title} ${dateStr}

${desc}

`; } // ============= SINCRONIZAR SALDO COM ASAAS ============= async function syncBalanceWithAsaas() { const fd = new FormData(); fd.append('action', 'sync_asaas_balance'); fd.append('csrf_token', CSRF_TOKEN); try { const res = await fetch(API_URL, { method: 'POST', body: fd }); const data = await res.json(); if (data.success) { console.log('Saldo sincronizado com Asaas:', data.total_balance); userFreeBalance = parseFloat(data.balance) || 0; currentVaultBalance = parseFloat(data.vault_balance) || 0; currentBalanceValue = data.total_balance; updateBalanceText(currentBalanceValue); updateBalanceDetail(userFreeBalance, currentVaultBalance); const vbDisplay = document.getElementById('vault-total-display'); if(vbDisplay) vbDisplay.innerText = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(currentVaultBalance); const availablePixText = document.getElementById('availablePixText'); if(availablePixText) { availablePixText.innerText = 'Saldo disponível: ' + new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance); } const vaultOpAvailable = document.getElementById('vaultOpAvailable'); if(vaultOpAvailable) { const type = document.getElementById('vaultOpType')?.value; if(type === 'deposit') { vaultOpAvailable.innerText = `Saldo disponível na conta: ${new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance)}`; } } if (data.tx_synced > 0) { console.log(data.tx_synced + ' transações sincronizadas'); } return true; } } catch (e) { console.error('Erro ao sincronizar saldo:', e); } return false; } async function fetchRealtimeData() { const fd = new FormData(); fd.append('action', 'get_realtime_data'); fd.append('csrf_token', CSRF_TOKEN); try { const res = await fetch(API_URL, { method: 'POST', body: fd }); if(res.ok) { const data = await res.json(); if(data.success) { userFreeBalance = parseFloat(data.balance) || 0; currentVaultBalance = parseFloat(data.vault_balance) || 0; currentBalanceValue = data.total_balance; updateBalanceText(currentBalanceValue); updateBalanceDetail(userFreeBalance, currentVaultBalance); const availablePixText = document.getElementById('availablePixText'); if(availablePixText) { availablePixText.innerText = 'Saldo disponível: ' + new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance); } const vbDisplay = document.getElementById('vault-total-display'); if(vbDisplay) vbDisplay.innerText = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(currentVaultBalance); const vaultOpAvailable = document.getElementById('vaultOpAvailable'); if(vaultOpAvailable) { const type = document.getElementById('vaultOpType')?.value; if(type === 'deposit') { vaultOpAvailable.innerText = `Saldo disponível na conta: ${new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(userFreeBalance)}`; } } if (data.transactions.length > 0) { const newestTx = data.transactions[0]; const newestId = parseInt(newestTx.id); if (lastTxId === null) lastTxId = newestId; else if (newestId > lastTxId) { lastTxId = newestId; } } let recentHTML = ''; let extractHTML = ''; data.transactions.slice(0, 5).forEach(t => { recentHTML += generateTransactionHTML(t); }); data.transactions.forEach(t => { extractHTML += generateTransactionHTML(t); }); const recentList = document.getElementById('recent-activity-list'); const extractList = document.getElementById('full-extract-list'); if(recentList) recentList.innerHTML = recentHTML || '
Nenhuma movimentação recente.
'; if(extractList) { extractList.innerHTML = extractHTML || '
Nenhuma transação encontrada.
'; applyExtractFilter(); } let notifHTML = ''; let unreadCount = 0; const uid = 0; const lastSeenTxId = parseInt(localStorage.getItem('lastSeenTxId_' + uid)) || 0; data.transactions.forEach(t => { if (parseInt(t.id) > lastSeenTxId) unreadCount++; notifHTML += generateNotificationHTML(t); }); const notifList = document.getElementById('notifications-list'); if(notifList) { if(notifHTML === '') { notifList.innerHTML = '

Nenhuma notificação ainda.
'; } else { notifList.innerHTML = notifHTML; } } const badge = document.getElementById('notification-badge'); if(badge) { badge.style.display = unreadCount > 0 ? 'block' : 'none'; } } } } catch(e) { console.error('Erro ao buscar dados:', e); } } document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible" && document.getElementById('home-screen')?.classList.contains('active')) { fetchRealtimeData(); } }); // ============= COMPROVANTES PDF ============= function generateReceiptPDF(receipt) { if (!receipt) return; const { jsPDF } = window.jspdf; const doc = new jsPDF(); const primaryColor = "#0F172A"; doc.setFillColor(primaryColor); doc.rect(0, 0, 210, 40, 'F'); doc.setTextColor(255, 255, 255); doc.setFontSize(26); doc.setFont("helvetica", "bold"); doc.text("CdrPay", 105, 25, null, null, "center"); doc.setTextColor(0, 0, 0); doc.setFontSize(16); doc.setFont("helvetica", "bold"); doc.text("Comprovante de Transação", 105, 60, null, null, "center"); let rawAmount = receipt.amount.toString().replace('R$', '').trim(); doc.setFontSize(36); doc.setTextColor(15, 23, 42); doc.text("R$ " + rawAmount, 105, 80, null, null, "center"); let y = 105; doc.setFontSize(10); doc.setTextColor(100, 100, 100); doc.text("ID da Transação", 20, y); doc.setTextColor(0, 0, 0); doc.setFontSize(12); doc.text(receipt.id || "---", 20, y + 5); y += 16; doc.setFontSize(10); doc.setTextColor(100, 100, 100); doc.text("Data e Hora", 20, y); doc.setTextColor(0, 0, 0); doc.setFontSize(12); doc.text(receipt.date || "---", 20, y + 5); y += 16; doc.setFontSize(10); doc.setTextColor(100, 100, 100); doc.text("Descrição", 20, y); doc.setTextColor(0, 0, 0); doc.setFontSize(12); doc.text(receipt.description || "Transferência / Pagamento", 20, y + 5); y += 14; doc.setDrawColor(226, 232, 240); doc.line(20, y, 190, y); y += 10; doc.setFontSize(11); doc.setTextColor(15, 23, 42); doc.setFont("helvetica", "bold"); doc.text("DADOS DO PAGADOR", 20, y); y += 7; doc.setFontSize(10); doc.setFont("helvetica", "normal"); doc.setTextColor(80, 80, 80); doc.text("Nome: " + (receipt.sender || "---"), 20, y); y += 6; doc.text("CPF/CNPJ: " + (receipt.sender_cpf || "---"), 20, y); y += 6; doc.text("Banco: " + (receipt.sender_bank || "---"), 20, y); y += 6; doc.text("Agência: " + (receipt.sender_agency || "---"), 20, y); y += 10; doc.setDrawColor(226, 232, 240); doc.line(20, y, 190, y); y += 10; doc.setFontSize(11); doc.setTextColor(15, 23, 42); doc.setFont("helvetica", "bold"); doc.text("DADOS DO RECEBEDOR", 20, y); y += 7; doc.setFontSize(10); doc.setFont("helvetica", "normal"); doc.setTextColor(80, 80, 80); doc.text("Nome: " + (receipt.receiver || "---"), 20, y); y += 6; doc.text("CPF/CNPJ: " + (receipt.receiver_cpf || "---"), 20, y); y += 6; doc.text("Banco: " + (receipt.receiver_bank || "---"), 20, y); y += 6; doc.text("Agência: " + (receipt.receiver_agency || "---"), 20, y); y += 16; doc.setDrawColor(226, 232, 240); doc.line(20, y, 190, y); y += 12; doc.setFontSize(9); doc.setTextColor(150, 150, 150); doc.text("CdrPay", 105, y, null, null, "center"); doc.text("Este comprovante possui valor legal e atesta que a transação foi realizada com sucesso.", 105, y + 5, null, null, "center"); const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); if (isMobile) { const blob = doc.output('blob'); const url = URL.createObjectURL(blob); window.open(url, '_blank'); } else { doc.save("comprovante-cdrpay-" + (receipt.id || "tx") + ".pdf"); } } async function generateHistoryPDF(localTxId) { showWait(); const fd = new FormData(); fd.append('action', 'get_receipt_data'); fd.append('tx_id', localTxId); fd.append('csrf_token', CSRF_TOKEN); try { const res = await fetch(API_URL, { method: 'POST', body: fd }); const data = await res.json(); if (data.success) { generateReceiptPDF(data.receipt); } else { showModal('Erro', data.message || 'Erro ao gerar comprovante.', 'error'); } } catch(e) { showModal('Erro', 'Falha ao buscar dados do comprovante.', 'error'); } finally { hideWait(); } } // ============= INICIALIZAÇÃO =============