QrRapido/Views/Pagamento/SelecaoPlano.cshtml
Ricardo Carneiro 16a9720a12
All checks were successful
Deploy QR Rapido / test (push) Successful in 59s
Deploy QR Rapido / build-and-push (push) Successful in 9m57s
Deploy QR Rapido / deploy-staging (push) Has been skipped
Deploy QR Rapido / deploy-production (push) Successful in 2m11s
feat: qrcode por creditos.
2026-01-26 20:13:45 -03:00

248 lines
12 KiB
Plaintext

@model IEnumerable<QRRapidoApp.Controllers.PagamentoController.CreditPackageViewModel>
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<QRRapidoApp.Resources.SharedResource> Localizer
@{
ViewData["Title"] = "Comprar Créditos";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container py-5">
<div class="text-center mb-5">
<h1 class="display-4 fw-bold">Créditos Pré-Pagos</h1>
<p class="lead text-muted">Sem assinaturas. Sem renovação automática. Pague apenas pelo que usar.</p>
<p class="text-success"><i class="fas fa-check-circle"></i> Seus créditos valem por 5 anos!</p>
</div>
<div class="row justify-content-center g-4">
@foreach (var package in Model)
{
<div class="col-lg-4 col-md-6">
<div class="card h-100 shadow-sm border-0 hover-lift @(package.IsPopular ? "border-primary ring-2" : "")">
@if (package.IsPopular)
{
<div class="position-absolute top-0 start-50 translate-middle">
<span class="badge rounded-pill bg-primary px-3 py-2 shadow-sm">MAIS POPULAR</span>
</div>
}
<div class="card-body text-center p-4 d-flex flex-column">
<h3 class="fw-bold mb-3">@package.Name</h3>
<div class="mb-3">
<span class="display-4 fw-bold">@package.Credits</span>
<span class="text-muted d-block">QR Codes</span>
</div>
<!-- Preços Duplos -->
<div class="bg-light rounded p-3 mb-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="text-muted"><i class="fas fa-bolt text-warning"></i> PIX</span>
<span class="h4 text-success mb-0 fw-bold">R$ @package.PricePix.ToString("F2")</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<span class="text-muted"><i class="fas fa-credit-card"></i> Cartão</span>
<span class="h5 text-secondary mb-0">R$ @package.PriceCard.ToString("F2")</span>
</div>
</div>
<ul class="list-unstyled text-start mb-4 mx-auto" style="max-width: 250px;">
<li class="mb-2"><i class="fas fa-check text-success me-2"></i>QR Codes Estáticos e Dinâmicos</li>
<li class="mb-2"><i class="fas fa-check text-success me-2"></i>Sem validade mensal</li>
<li class="mb-2"><i class="fas fa-check text-success me-2"></i>Suporte Prioritário</li>
</ul>
@if (User.Identity.IsAuthenticated)
{
<div class="d-grid gap-2 mt-auto">
<button class="btn btn-outline-success btn-pix-checkout"
data-package-id="@package.Id">
<i class="fas fa-qrcode me-2"></i> Pagar com PIX
</button>
<button class="btn @(package.IsPopular ? "btn-primary" : "btn-outline-primary") btn-card-checkout"
data-package-id="@package.Id">
<i class="fas fa-credit-card me-2"></i> Pagar com Cartão
</button>
</div>
}
else
{
<a href="/Account/Login?returnUrl=/Pagamento/SelecaoPlano" class="btn btn-lg btn-success w-100 mt-auto">
<i class="fas fa-user-plus me-2"></i> Cadastrar para Comprar
</a>
<div class="text-muted small mt-2">Faça login para adicionar créditos</div>
}
</div>
</div>
</div>
}
</div>
<div class="row justify-content-center mt-5">
<div class="col-md-8 text-center">
<div class="alert alert-info border-0 bg-light">
<i class="fas fa-info-circle me-2"></i>
Pagamentos via PIX têm liberação em até 1 hora (dias úteis).
Pagamentos via Cartão são liberados instantaneamente.
</div>
</div>
</div>
</div>
<!-- Modal PIX -->
<div class="modal fade" id="pixModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header border-0 pb-0">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-center pb-5">
<div class="mb-4">
<i class="fas fa-check-circle text-success display-1"></i>
</div>
<h3 class="fw-bold mb-2">Pedido Criado!</h3>
<p class="text-muted mb-4">Escaneie o QR Code abaixo com seu app de banco</p>
<div class="bg-white p-3 d-inline-block border rounded mb-4 shadow-sm position-relative">
<div id="pix-qr-loading" class="position-absolute top-50 start-50 translate-middle">
<div class="spinner-border text-primary" role="status"></div>
</div>
<img id="pix-qr-image" src="" alt="QR Code PIX" width="200" height="200" style="opacity: 0; transition: opacity 0.3s;" onload="this.style.opacity=1; document.getElementById('pix-qr-loading').style.display='none';">
</div>
<div class="input-group mb-3 px-4">
<input type="text" class="form-control font-monospace" id="pix-copypaste" readonly value="">
<button class="btn btn-outline-secondary" type="button" id="btn-copy-pix">
<i class="fas fa-copy"></i> Copiar
</button>
</div>
<div class="alert alert-warning d-inline-block text-start small">
<strong>Importante:</strong><br>
Identificador do Pedido: <span id="order-id-display" class="fw-bold font-monospace">...</span><br>
Valor Exato: <span id="amount-display" class="fw-bold">...</span>
</div>
<div class="mt-4">
<button type="button" class="btn btn-primary px-5" data-bs-dismiss="modal">
Já paguei!
</button>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
document.addEventListener('DOMContentLoaded', function() {
const pixModal = new bootstrap.Modal(document.getElementById('pixModal'));
// PIX Checkout
document.querySelectorAll('.btn-pix-checkout').forEach(btn => {
btn.addEventListener('click', async function() {
const packageId = this.dataset.packageId;
const originalText = this.innerHTML;
this.disabled = true;
this.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span> Gerando...';
try {
const response = await fetch('/api/Pagamento/CreatePixOrder', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ packageId: packageId })
});
const result = await response.json();
if (response.ok && result.success) {
document.getElementById('pix-copypaste').value = result.pixCode;
document.getElementById('order-id-display').textContent = result.orderId;
const currencyFormatter = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });
document.getElementById('amount-display').textContent = currencyFormatter.format(result.amount);
const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${encodeURIComponent(result.pixCode)}`;
document.getElementById('pix-qr-image').src = qrUrl;
pixModal.show();
} else {
alert('Erro: ' + (result.error || 'Tente novamente'));
}
} catch (error) {
console.error(error);
alert('Erro de conexão.');
} finally {
this.disabled = false;
this.innerHTML = originalText;
}
});
});
// Card (Stripe) Checkout
document.querySelectorAll('.btn-card-checkout').forEach(btn => {
btn.addEventListener('click', async function() {
const packageId = this.dataset.packageId;
const originalText = this.innerHTML;
this.disabled = true;
this.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span> Redirecionando...';
try {
const response = await fetch('/api/Pagamento/CreateStripeSession', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ packageId: packageId })
});
const result = await response.json();
if (response.ok && result.success) {
window.location.href = result.url;
} else {
alert('Erro: ' + (result.error || 'Tente novamente'));
this.disabled = false;
this.innerHTML = originalText;
}
} catch (error) {
console.error(error);
alert('Erro de conexão.');
this.disabled = false;
this.innerHTML = originalText;
}
});
});
// Copy Button Logic
document.getElementById('btn-copy-pix').addEventListener('click', function() {
const copyText = document.getElementById('pix-copypaste');
copyText.select();
copyText.setSelectionRange(0, 99999);
navigator.clipboard.writeText(copyText.value).then(() => {
const originalBtnText = this.innerHTML;
this.innerHTML = '<i class="fas fa-check"></i> Copiado!';
this.classList.remove('btn-outline-secondary');
this.classList.add('btn-success');
setTimeout(() => {
this.innerHTML = originalBtnText;
this.classList.remove('btn-success');
this.classList.add('btn-outline-secondary');
}, 2000);
});
});
});
</script>
<style>
.hover-lift {
transition: transform 0.2s, box-shadow 0.2s;
}
.hover-lift:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1) !important;
}
.ring-2 {
border-width: 2px !important;
}
</style>
}