feat: enhance webhook for payment confirmation and add frontend detection
Improve webhook handling in AbacatePay route to accurately detect paid events, support anonymous donations, and log structured data for future database and email integrations. Add frontend logic in DonationCard to check payment confirmation via localStorage for real-time UI updates without API polling.
This commit is contained in:
1 parent
ef521876eb
commit
2697e2d1f5
3 files changed
+190
-19
No files matched your search
@@ -15,6 +15,7 @@ import {
|
||||
Lock,
|
||||
User,
|
||||
CheckCircle,
|
||||
CheckCircle2,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -56,6 +57,8 @@ export function DonationCard({
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [timeRemaining, setTimeRemaining] = useState<string | null>(null);
|
||||
const [paymentConfirmed, setPaymentConfirmed] = useState(false);
|
||||
const [showThankYouModal, setShowThankYouModal] = useState(false);
|
||||
|
||||
const icons = {
|
||||
coffee: Coffee,
|
||||
@@ -92,11 +95,39 @@ export function DonationCard({
|
||||
}
|
||||
};
|
||||
|
||||
// Verificar pagamento via localStorage
|
||||
const checkPaymentConfirmation = () => {
|
||||
const savedPixId = localStorage.getItem("currentPixId");
|
||||
const confirmedPixIds = localStorage.getItem("confirmedPixIds");
|
||||
|
||||
if (savedPixId && confirmedPixIds) {
|
||||
try {
|
||||
const confirmed = JSON.parse(confirmedPixIds);
|
||||
if (confirmed.includes(savedPixId)) {
|
||||
console.log("✅ Pagamento confirmado!");
|
||||
setPaymentConfirmed(true);
|
||||
setTimeout(() => {
|
||||
setShowPixModal(false);
|
||||
setShowThankYouModal(true);
|
||||
// Limpar
|
||||
localStorage.removeItem("currentPixId");
|
||||
}, 1000);
|
||||
clearInterval(timerInterval);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Erro ao verificar pagamento:", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Atualizar timer imediatamente
|
||||
updateTimer();
|
||||
|
||||
// Atualizar timer a cada segundo
|
||||
const timerInterval = setInterval(updateTimer, 1000);
|
||||
// Atualizar timer e verificar pagamento a cada 2 segundos
|
||||
const timerInterval = setInterval(() => {
|
||||
updateTimer();
|
||||
checkPaymentConfirmation();
|
||||
}, 2000);
|
||||
|
||||
return () => clearInterval(timerInterval);
|
||||
}, [pixData?.expiresAt, pixData?.pixId]);
|
||||
@@ -165,6 +196,8 @@ export function DonationCard({
|
||||
brCodeBase64: data.brCodeBase64,
|
||||
expiresAt: data.expiresAt,
|
||||
});
|
||||
// Salvar pixId no localStorage para verificação
|
||||
localStorage.setItem("currentPixId", data.pixId);
|
||||
setShowPixModal(true);
|
||||
} else {
|
||||
setError(data.error || "Erro ao processar doação");
|
||||
@@ -239,6 +272,8 @@ export function DonationCard({
|
||||
brCodeBase64: data.brCodeBase64,
|
||||
expiresAt: data.expiresAt,
|
||||
});
|
||||
// Salvar pixId no localStorage
|
||||
localStorage.setItem("currentPixId", data.pixId);
|
||||
setShowDonorForm(false);
|
||||
setShowPixModal(true);
|
||||
} else {
|
||||
@@ -588,6 +623,67 @@ export function DonationCard({
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Modal de Agradecimento */}
|
||||
<Dialog open={showThankYouModal} onOpenChange={setShowThankYouModal}>
|
||||
<DialogContent className="max-w-md">
|
||||
<div className="text-center space-y-6 py-4">
|
||||
{/* Ícone de sucesso animado */}
|
||||
<div className="flex justify-center">
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 bg-green-500/20 rounded-full animate-ping" />
|
||||
<div className="relative p-4 rounded-full bg-green-500/10 border-4 border-green-500">
|
||||
<CheckCircle2 className="w-16 h-16 text-green-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Título e mensagem */}
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold mb-2">
|
||||
Pagamento Confirmado! 🎉
|
||||
</h2>
|
||||
<p className="text-muted-foreground">
|
||||
Obrigado pela sua contribuição! Cada doação nos ajuda a manter o
|
||||
projeto funcionando.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Mensagem especial */}
|
||||
<div className="p-4 rounded-lg bg-primary/5 border border-primary/20">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Sua doação faz toda a diferença para nossa comunidade. Muito
|
||||
obrigado pelo apoio! ❤️
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Botões */}
|
||||
<div className="flex gap-3">
|
||||
<Button
|
||||
onClick={() => {
|
||||
setShowThankYouModal(false);
|
||||
window.location.href = "/apoiar/obrigado";
|
||||
}}
|
||||
className="flex-1"
|
||||
size="lg"
|
||||
>
|
||||
Ver Página de Agradecimento
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setShowThankYouModal(false);
|
||||
window.location.href = "/";
|
||||
}}
|
||||
variant="outline"
|
||||
className="flex-1"
|
||||
size="lg"
|
||||
>
|
||||
Voltar ao Início
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user