510 lines
25 KiB
TypeScript
510 lines
25 KiB
TypeScript
'use client';
|
||
import { useState, useEffect } from 'react';
|
||
import { Check, Crown, Zap, Building2, Rocket, AlertTriangle, ShieldAlert, CreditCard, QrCode, FileText, CheckCircle2, ShieldCheck } from 'lucide-react';
|
||
|
||
const staticPlans = [
|
||
{
|
||
name: 'Starter', price: 49.90, icon: Zap, color: '#3b82f6',
|
||
features: ['1 profissional', '10 serviços', '200 agendamentos/mês', 'Agendamento online', 'Página de reservas', 'Lembretes por e-mail', 'Relatórios básicos']
|
||
},
|
||
{
|
||
name: 'Professional', price: 99.90, icon: Crown, color: '#6C63FF', featured: true,
|
||
features: ['5 profissionais', '30 serviços', 'Agendamentos ilimitados', 'Tudo do Starter', 'Múltiplos profissionais', 'Comissionamento', 'Relatórios avançados', 'Personalização da marca']
|
||
},
|
||
{
|
||
name: 'Business', price: 199.90, icon: Building2, color: '#a855f7',
|
||
features: ['15 profissionais', '100 serviços', 'Agendamentos ilimitados', 'Tudo do Professional', 'API de integração', 'Suporte prioritário', 'Multi-unidades', 'Automações avançadas']
|
||
},
|
||
{
|
||
name: 'Enterprise', price: 399.90, icon: Rocket, color: '#f59e0b',
|
||
features: ['Profissionais ilimitados', 'Serviços ilimitados', 'Agendamentos ilimitados', 'Tudo do Business', 'Gerente dedicado', 'SLA garantido', 'Integrações customizadas', 'White-label']
|
||
},
|
||
];
|
||
|
||
// Máscaras de entrada
|
||
const formatCpfCnpj = (value: string) => {
|
||
const v = value.replace(/\D/g, '');
|
||
if (v.length <= 11) {
|
||
return v.replace(/(\d{3})(\d)/, '$1.$2')
|
||
.replace(/(\d{3})(\d)/, '$1.$2')
|
||
.replace(/(\d{3})(\d{1,2})$/, '$1-$2');
|
||
}
|
||
return v.replace(/^(\d{2})(\d)/, '$1.$2')
|
||
.replace(/^(\d{2})\.(\d{3})(\d)/, '$1.$2.$3')
|
||
.replace(/\.(\d{3})(\d)/, '.$1/$2')
|
||
.replace(/(\d{4})(\d)/, '$1-$2')
|
||
.slice(0, 18);
|
||
};
|
||
|
||
const formatPhone = (value: string) => {
|
||
const v = value.replace(/\D/g, '');
|
||
return v.replace(/(\d{2})(\d)/, '($1) $2')
|
||
.replace(/(\d{5})(\d)/, '$1-$2')
|
||
.slice(0, 15);
|
||
};
|
||
|
||
const formatCep = (value: string) => {
|
||
const v = value.replace(/\D/g, '');
|
||
return v.replace(/(\d{5})(\d)/, '$1-$2')
|
||
.slice(0, 9);
|
||
};
|
||
|
||
const formatCardNumber = (value: string) => {
|
||
const v = value.replace(/\D/g, '');
|
||
return v.replace(/(\d{4})(?=\d)/g, '$1 ').slice(0, 19);
|
||
};
|
||
|
||
const formatExpiry = (value: string) => {
|
||
const v = value.replace(/\D/g, '');
|
||
return v.replace(/(\d{2})(\d)/, '$1/$2').slice(0, 5);
|
||
};
|
||
|
||
const formatCvv = (value: string) => {
|
||
return value.replace(/\D/g, '').slice(0, 4);
|
||
};
|
||
|
||
interface SubscriptionProps {
|
||
currentPlan: string;
|
||
onPlanChange: (newPlan: string) => void;
|
||
isLocked?: boolean;
|
||
onPaymentSuccess?: () => void;
|
||
}
|
||
|
||
export default function Subscription({ currentPlan, onPlanChange, isLocked = false, onPaymentSuccess }: SubscriptionProps) {
|
||
const [selectedPlan, setSelectedPlan] = useState<any>(null);
|
||
const [paymentMethod, setPaymentMethod] = useState<'PIX' | 'BOLETO' | 'CREDIT_CARD'>('PIX');
|
||
const [loading, setLoading] = useState(false);
|
||
const [successData, setSuccessData] = useState<any>(null);
|
||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||
const [dbPlans, setDbPlans] = useState<any[]>([]);
|
||
|
||
useEffect(() => {
|
||
const fetchSubscriptionData = async () => {
|
||
const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium';
|
||
try {
|
||
const res = await fetch(`/api/tenant/subscription?slug=${slug}`);
|
||
if (res.ok) {
|
||
const data = await res.json();
|
||
if (data.plans && data.plans.length > 0) {
|
||
setDbPlans(data.plans);
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.error('Erro ao buscar planos da API:', e);
|
||
}
|
||
};
|
||
fetchSubscriptionData();
|
||
}, []);
|
||
|
||
const iconMap: Record<string, any> = { Starter: Zap, Professional: Crown, Business: Building2, Enterprise: Rocket };
|
||
const colorMap: Record<string, string> = { Starter: '#3b82f6', Professional: '#6C63FF', Business: '#a855f7', Enterprise: '#f59e0b' };
|
||
|
||
const plans = dbPlans.length > 0 ? dbPlans.map(p => {
|
||
let featuresList: string[] = [];
|
||
try {
|
||
if (typeof p.features === 'string') featuresList = JSON.parse(p.features);
|
||
else if (Array.isArray(p.features)) featuresList = p.features;
|
||
} catch (e) {}
|
||
|
||
return {
|
||
id: p.id,
|
||
name: p.name,
|
||
price: Number(p.price || p.price_monthly || 0),
|
||
icon: iconMap[p.name] || Crown,
|
||
color: colorMap[p.name] || '#6C63FF',
|
||
featured: p.name === 'Professional',
|
||
features: featuresList.length > 0 ? featuresList : ['Agendamento online']
|
||
};
|
||
}) : staticPlans;
|
||
|
||
// Form de cartão
|
||
const [cardHolder, setCardHolder] = useState('');
|
||
const [cardNumber, setCardNumber] = useState('');
|
||
const [cardExpiry, setCardExpiry] = useState('');
|
||
const [cardCvv, setCardCvv] = useState('');
|
||
|
||
// Dados de Faturamento
|
||
const [billingInfo, setBillingInfo] = useState({
|
||
name: '',
|
||
cpfCnpj: '',
|
||
phone: '',
|
||
email: '',
|
||
postalCode: '',
|
||
addressNumber: '',
|
||
});
|
||
|
||
const activePlanData = plans.find(p => p.name === currentPlan) || plans[1];
|
||
|
||
const handleOpenPayment = (plan: any) => {
|
||
setSelectedPlan(plan);
|
||
setSuccessData(null);
|
||
setErrorMsg(null);
|
||
};
|
||
|
||
const handlePay = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
setLoading(true);
|
||
setErrorMsg(null);
|
||
|
||
const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium';
|
||
|
||
let creditCard = undefined;
|
||
let creditCardHolderInfo = undefined;
|
||
|
||
if (paymentMethod === 'CREDIT_CARD') {
|
||
const [month, year] = cardExpiry.split('/');
|
||
creditCard = {
|
||
holderName: cardHolder,
|
||
number: cardNumber.replace(/\s/g, ''),
|
||
expiryMonth: month || '12',
|
||
expiryYear: year ? `20${year}` : '2030',
|
||
ccv: cardCvv,
|
||
};
|
||
creditCardHolderInfo = {
|
||
name: cardHolder,
|
||
email: `${slug}@agendapro.com`,
|
||
cpfCnpj: '00000000000',
|
||
postalCode: '01310000',
|
||
addressNumber: '123',
|
||
phone: '11999991234',
|
||
};
|
||
}
|
||
|
||
try {
|
||
const res = await fetch('/api/tenant/subscription', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
slug,
|
||
planName: selectedPlan.name,
|
||
billingType: paymentMethod,
|
||
billingInfo,
|
||
creditCard,
|
||
creditCardHolderInfo,
|
||
}),
|
||
});
|
||
|
||
const data = await res.json();
|
||
if (!res.ok) {
|
||
throw new Error(data.error || 'Falha ao processar pagamento');
|
||
}
|
||
|
||
setSuccessData(data);
|
||
onPlanChange(selectedPlan.name);
|
||
} catch (err: any) {
|
||
console.error(err);
|
||
setErrorMsg(err.message || 'Erro inesperado no servidor');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
// Simulação de pagamento no Sandbox / Dev
|
||
const handleSimulatePayment = async () => {
|
||
setLoading(true);
|
||
const slug = localStorage.getItem('agendapro_tenant_slug') || 'barbearia-premium';
|
||
|
||
// Configura o cookie e localStorage de homologação local
|
||
localStorage.setItem('agendapro_subscription_status', 'active');
|
||
document.cookie = "agendapro_subscription_status=active; path=/; max-age=2592000";
|
||
|
||
try {
|
||
const res = await fetch('/api/tenant/subscription/simulate', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ slug, status: 'active' }),
|
||
});
|
||
|
||
alert('Pagamento simulado com sucesso! O sistema foi desbloqueado.');
|
||
setSelectedPlan(null);
|
||
if (onPaymentSuccess) {
|
||
onPaymentSuccess();
|
||
}
|
||
} catch (err) {
|
||
console.warn('Erro ao conectar com API de simulação, utilizando fallback local de homologação.', err);
|
||
alert('Pagamento simulado localmente! O sistema foi desbloqueado (modo offline).');
|
||
setSelectedPlan(null);
|
||
if (onPaymentSuccess) {
|
||
onPaymentSuccess();
|
||
}
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="slide-up">
|
||
{/* BANNER DE BLOQUEIO */}
|
||
{isLocked && (
|
||
<div style={{
|
||
background: 'linear-gradient(135deg, rgba(239,68,68,0.15), rgba(245,158,11,0.1))',
|
||
border: '2px solid rgba(239,68,68,0.4)', borderRadius: 'var(--radius-lg)',
|
||
padding: '20px', marginBottom: '28px', display: 'flex', gap: '16px', alignItems: 'center'
|
||
}}>
|
||
<div style={{ background: 'var(--danger)', borderRadius: '50%', width: 44, height: 44, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
|
||
<ShieldAlert size={24} color="white" />
|
||
</div>
|
||
<div>
|
||
<h4 style={{ fontWeight: 800, color: 'var(--danger)', fontSize: '16px', marginBottom: '4px' }}>Acesso Pendente / Bloqueado 🔒</h4>
|
||
<p style={{ fontSize: '13px', color: 'var(--text-secondary)' }}>
|
||
Sua assinatura do AgendaPRO não está ativa. Para reativar seu acesso completo e continuar gerenciando seus agendamentos, clientes e equipe, escolha um plano abaixo e efetue o pagamento.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* PLANO ATUAL INFO */}
|
||
{!isLocked && (
|
||
<div className="card mb-6" style={{ background: 'var(--gradient-primary)', border: 'none' }}>
|
||
<div className="flex-between">
|
||
<div>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '8px' }}>
|
||
<Crown size={24} color="white" />
|
||
<h2 style={{ fontSize: '22px', fontWeight: 800, color: 'white' }}>Plano {activePlanData.name}</h2>
|
||
</div>
|
||
<p style={{ color: 'rgba(255,255,255,0.9)' }}>Sua assinatura está ativa e regularizada.</p>
|
||
</div>
|
||
<div style={{ textAlign: 'right', color: 'white' }}>
|
||
<div style={{ fontSize: '32px', fontWeight: 900 }}>
|
||
R$ {activePlanData.price.toFixed(2).replace('.', ',')}
|
||
<span style={{ fontSize: '14px', fontWeight: 400 }}>/mês</span>
|
||
</div>
|
||
<span className="badge" style={{ background: 'rgba(255,255,255,0.2)', color: 'white' }}>Ativo</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<h3 style={{ fontSize: '18px', fontWeight: 700, marginBottom: '20px' }}>Escolha o plano ideal</h3>
|
||
|
||
<div className="pricing-grid">
|
||
{plans.map(plan => {
|
||
const Icon = plan.icon;
|
||
const isActive = currentPlan === plan.name && !isLocked;
|
||
return (
|
||
<div key={plan.name} className={`pricing-card ${isActive ? 'featured' : ''}`} style={isLocked ? { border: '1px solid var(--border-color)' } : {}}>
|
||
<div style={{ width: 56, height: 56, borderRadius: 'var(--radius-md)', background: `${plan.color}20`, display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 16px' }}>
|
||
<Icon size={28} color={plan.color} />
|
||
</div>
|
||
<div className="pricing-name">{plan.name}</div>
|
||
<div className="pricing-price">
|
||
R$ {plan.price.toFixed(2).replace('.', ',')}
|
||
<span>/mês</span>
|
||
</div>
|
||
<ul className="pricing-features">
|
||
{plan.features.map(f => (
|
||
<li key={f}><Check size={16} /> {f}</li>
|
||
))}
|
||
</ul>
|
||
<button
|
||
className={`btn ${isActive ? 'btn-primary' : 'btn-secondary'}`}
|
||
style={{ width: '100%', justifyContent: 'center' }}
|
||
onClick={() => handleOpenPayment(plan)}
|
||
>
|
||
{isActive ? 'Plano Atual (Pagar de Novo)' : 'Assinar Plano'}
|
||
</button>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* MODAL DE PAGAMENTO */}
|
||
{selectedPlan && (
|
||
<div className="modal-overlay" onClick={() => setSelectedPlan(null)}>
|
||
<div className="modal" onClick={e => e.stopPropagation()} style={{ maxWidth: '500px' }}>
|
||
<div className="modal-header">
|
||
<h2 className="modal-title">Assinar Plano {selectedPlan.name}</h2>
|
||
<button className="btn-ghost btn-icon" onClick={() => setSelectedPlan(null)}>✕</button>
|
||
</div>
|
||
|
||
<div className="modal-body">
|
||
{!successData ? (
|
||
<form onSubmit={handlePay} style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
|
||
{/* Seleção de meio de pagamento */}
|
||
<div>
|
||
<label className="form-label">Meio de Pagamento</label>
|
||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '8px' }}>
|
||
<button type="button" className={`btn ${paymentMethod === 'PIX' ? 'btn-primary' : 'btn-secondary'}`}
|
||
style={{ flexDirection: 'column', padding: '12px 6px', gap: '4px', fontSize: '13px' }}
|
||
onClick={() => setPaymentMethod('PIX')}>
|
||
<QrCode size={18} /> Pix
|
||
</button>
|
||
<button type="button" className={`btn ${paymentMethod === 'BOLETO' ? 'btn-primary' : 'btn-secondary'}`}
|
||
style={{ flexDirection: 'column', padding: '12px 6px', gap: '4px', fontSize: '13px' }}
|
||
onClick={() => setPaymentMethod('BOLETO')}>
|
||
<FileText size={18} /> Boleto
|
||
</button>
|
||
<button type="button" className={`btn ${paymentMethod === 'CREDIT_CARD' ? 'btn-primary' : 'btn-secondary'}`}
|
||
style={{ flexDirection: 'column', padding: '12px 6px', gap: '4px', fontSize: '13px' }}
|
||
onClick={() => setPaymentMethod('CREDIT_CARD')}>
|
||
<CreditCard size={18} /> Cartão
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ borderTop: '1px solid var(--border-color)', paddingTop: '16px' }}>
|
||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '8px' }}>
|
||
<span style={{ color: 'var(--text-secondary)' }}>Plano:</span>
|
||
<strong style={{ color: 'var(--text-primary)' }}>{selectedPlan.name} (Mensal)</strong>
|
||
</div>
|
||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||
<span style={{ color: 'var(--text-secondary)' }}>Valor total:</span>
|
||
<strong style={{ color: 'var(--accent)', fontSize: '18px' }}>R$ {selectedPlan.price.toFixed(2).replace('.', ',')}</strong>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Dados de Faturamento */}
|
||
<div style={{ borderTop: '1px solid var(--border-color)', paddingTop: '16px', display: 'flex', flexDirection: 'column', gap: '12px' }}>
|
||
<h4 style={{ fontSize: '14px', fontWeight: 600, color: 'var(--text-primary)', marginBottom: '4px' }}>Dados do Pagador</h4>
|
||
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">Nome Completo / Razão Social</label>
|
||
<input required className="form-input" placeholder="João da Silva" value={billingInfo.name} onChange={e => setBillingInfo({...billingInfo, name: e.target.value})} />
|
||
</div>
|
||
|
||
<div className="grid-2">
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">CPF ou CNPJ</label>
|
||
<input required className="form-input" placeholder="000.000.000-00" value={billingInfo.cpfCnpj} onChange={e => setBillingInfo({...billingInfo, cpfCnpj: formatCpfCnpj(e.target.value)})} />
|
||
</div>
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">Celular</label>
|
||
<input required className="form-input" placeholder="(00) 90000-0000" value={billingInfo.phone} onChange={e => setBillingInfo({...billingInfo, phone: formatPhone(e.target.value)})} />
|
||
</div>
|
||
</div>
|
||
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">E-mail</label>
|
||
<input type="email" required className="form-input" placeholder="seu@email.com" value={billingInfo.email} onChange={e => setBillingInfo({...billingInfo, email: e.target.value})} />
|
||
</div>
|
||
|
||
{paymentMethod === 'CREDIT_CARD' && (
|
||
<div className="grid-2">
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">CEP</label>
|
||
<input required className="form-input" placeholder="00000-000" value={billingInfo.postalCode} onChange={e => setBillingInfo({...billingInfo, postalCode: formatCep(e.target.value)})} />
|
||
</div>
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">Número</label>
|
||
<input required className="form-input" placeholder="123" value={billingInfo.addressNumber} onChange={e => setBillingInfo({...billingInfo, addressNumber: e.target.value})} />
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Inputs específicos do Cartão */}
|
||
{paymentMethod === 'CREDIT_CARD' && (
|
||
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px', animation: 'fadeIn 0.2s' }}>
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">Nome do Titular (como no cartão)</label>
|
||
<input required className="form-input" placeholder="Nome Completo" value={cardHolder} onChange={e => setCardHolder(e.target.value)} />
|
||
</div>
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">Número do Cartão</label>
|
||
<input required className="form-input" placeholder="0000 0000 0000 0000" value={cardNumber} onChange={e => setCardNumber(formatCardNumber(e.target.value))} />
|
||
</div>
|
||
<div className="grid-2">
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">Validade (MM/AA)</label>
|
||
<input required className="form-input" placeholder="MM/AA" value={cardExpiry} onChange={e => setCardExpiry(formatExpiry(e.target.value))} />
|
||
</div>
|
||
<div className="form-group" style={{ margin: 0 }}>
|
||
<label className="form-label">CVV</label>
|
||
<input required className="form-input" placeholder="000" value={cardCvv} onChange={e => setCardCvv(formatCvv(e.target.value))} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{errorMsg && (
|
||
<div style={{ color: 'var(--danger)', fontSize: '13px', background: 'rgba(239,68,68,0.1)', padding: '10px', borderRadius: 'var(--radius-sm)', border: '1px solid var(--danger)' }}>
|
||
⚠️ {errorMsg}
|
||
</div>
|
||
)}
|
||
|
||
<button type="submit" className="btn btn-primary" style={{ width: '100%', justifyContent: 'center', padding: '12px' }} disabled={loading}>
|
||
{loading ? 'Processando transação...' : `Confirmar e Pagar R$ ${selectedPlan.price.toFixed(2).replace('.', ',')}`}
|
||
</button>
|
||
</form>
|
||
) : (
|
||
/* RESPOSTA DE SUCESSO DE PAGAMENTO */
|
||
<div style={{ textAlign: 'center', padding: '12px 0', animation: 'fadeIn 0.3s' }}>
|
||
{paymentMethod === 'PIX' && successData.pixCode && (
|
||
<div>
|
||
<div style={{ width: 44, height: 44, background: 'var(--success-bg)', color: 'var(--success)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 16px' }}>
|
||
<CheckCircle2 size={24} />
|
||
</div>
|
||
<h3 style={{ fontSize: '18px', fontWeight: 800, marginBottom: '8px' }}>Cobrança Pix Gerada!</h3>
|
||
<p style={{ fontSize: '13px', color: 'var(--text-secondary)', marginBottom: '20px' }}>Escaneie o QR Code abaixo com seu banco para efetuar o pagamento da assinatura.</p>
|
||
|
||
{successData.pixQrCodeImage && (
|
||
<div style={{ background: 'white', padding: '16px', width: '200px', height: '200px', margin: '0 auto 20px', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid var(--border-color)' }}>
|
||
<img src={`data:image/png;base64,${successData.pixQrCodeImage}`} alt="QR Code Pix" style={{ width: '100%', height: '100%' }} />
|
||
</div>
|
||
)}
|
||
|
||
<div className="form-group">
|
||
<label className="form-label" style={{ fontSize: '11px', textTransform: 'uppercase' }}>Código Copia e Cola</label>
|
||
<div style={{ display: 'flex', gap: '8px' }}>
|
||
<input readOnly className="form-input" style={{ fontSize: '12px' }} value={successData.pixCode} />
|
||
<button className="btn btn-secondary" onClick={() => { navigator.clipboard.writeText(successData.pixCode); alert('Código copiado!'); }}>Copiar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{paymentMethod === 'BOLETO' && (
|
||
<div>
|
||
<div style={{ width: 44, height: 44, background: 'var(--success-bg)', color: 'var(--success)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 16px' }}>
|
||
<CheckCircle2 size={24} />
|
||
</div>
|
||
<h3 style={{ fontSize: '18px', fontWeight: 800, marginBottom: '8px' }}>Boleto Emitido com Sucesso!</h3>
|
||
<p style={{ fontSize: '13px', color: 'var(--text-secondary)', marginBottom: '24px' }}>
|
||
O boleto de cobrança foi emitido. Você receberá um e-mail com as instruções, ou poderá realizar o pagamento usando o link do painel de controle.
|
||
</p>
|
||
<button className="btn btn-primary" style={{ margin: '0 auto' }} onClick={() => window.open('https://sandbox.asaas.com', '_blank')}>
|
||
Visualizar Boleto PDF
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
{paymentMethod === 'CREDIT_CARD' && (
|
||
<div>
|
||
<div style={{ width: 44, height: 44, background: 'var(--success-bg)', color: 'var(--success)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 16px' }}>
|
||
<ShieldCheck size={24} />
|
||
</div>
|
||
<h3 style={{ fontSize: '18px', fontWeight: 800, marginBottom: '8px' }}>Transação Aprovada!</h3>
|
||
<p style={{ fontSize: '13px', color: 'var(--text-secondary)', marginBottom: '24px' }}>
|
||
Sua assinatura do plano <strong>{selectedPlan.name}</strong> foi confirmada e está ativa. Obrigado!
|
||
</p>
|
||
<button className="btn btn-primary" style={{ margin: '0 auto' }} onClick={() => { setSelectedPlan(null); if (onPaymentSuccess) onPaymentSuccess(); }}>
|
||
Entrar no Sistema
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* BARRA DE FERRAMENTAS DE SIMULAÇÃO (SANDBOX DEVELOPER MODE) */}
|
||
<div className="modal-footer" style={{ background: 'var(--bg-elevated)', flexDirection: 'column', gap: '12px', alignItems: 'stretch' }}>
|
||
<div style={{ fontSize: '12px', color: 'var(--text-muted)', textAlign: 'center', display: 'flex', alignItems: 'center', gap: '6px', justifyContent: 'center' }}>
|
||
<ShieldCheck size={14} color="var(--warning)" /> Modo Homologação Sandbox Ativo
|
||
</div>
|
||
<div style={{ display: 'flex', gap: '8px' }}>
|
||
<button className="btn btn-secondary" style={{ flex: 1 }} onClick={() => setSelectedPlan(null)}>
|
||
Fechar Janela
|
||
</button>
|
||
<button className="btn btn-primary" style={{ flex: 1.5, background: 'var(--warning)', border: 'none', color: 'black', fontWeight: 700 }}
|
||
onClick={handleSimulatePayment} disabled={loading}>
|
||
⚡ Simular Pagamento Webhook
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|