const pay = WeGive.Pay.init({ publishableKey: 'pk_test_REPLACE_WITH_YOUR_KEY' });
const form = document.querySelector('#donation-form');
const submit = form.querySelector('button[type="submit"]');
const message = document.querySelector('#payment-status');
let fields;
let busy = false;
let sentToBackend = false;
async function initializeFields() {
try {
fields = await pay.payframes.mount({
cardNumber: '#card-number',
cardExpiry: '#card-expiry',
cardCvv: '#card-cvv',
checkoutAttemptId: form.dataset.attemptId,
style: { 'font-size': '16px', color: '#17251e' },
});
await fields.ready();
submit.disabled = false;
} catch {
message.textContent = 'Payment fields could not load. Please contact us if this continues.';
}
}
form.addEventListener('submit', async (event) => {
event.preventDefault();
if (busy || sentToBackend || !fields) return;
if (!fields.isValid()) {
message.textContent = 'Please complete all card fields.';
return;
}
busy = true;
submit.disabled = true;
try {
const tokenized = await fields.tokenize();
// Obtain fresh context for this first submission, even if the form sat open.
const session = await pay.createFraudSession({ checkoutAttemptId: form.dataset.attemptId });
const data = new FormData(form);
const body = JSON.stringify({
attemptId: form.dataset.attemptId,
tokenized: { ...tokenized, fraudSessionId: session.id },
donor: {
email: data.get('email'),
firstName: data.get('firstName'),
lastName: data.get('lastName'),
},
cardholder: { name: data.get('cardholder'), zip: data.get('postal') },
utm: pay.getAttribution(),
});
// After this point, a lost response does not mean that payment failed.
sentToBackend = true;
const response = await fetch('/donation-attempts/submit', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': String(data.get('csrf')),
},
body,
});
if (!response.ok) throw new Error('Backend response requires review');
const result = await response.json();
if (result.outcome === 'success') {
message.textContent = `Thank you! Reference: ${result.transactionId}.`;
} else if (result.outcome === 'pending') {
message.textContent = 'Your payment is awaiting confirmation.';
} else {
message.textContent = 'Please check this donation attempt before submitting another payment.';
}
} catch {
message.textContent = sentToBackend
? 'We could not confirm the result. Please check this attempt before paying again.'
: 'Payment details could not be submitted. Please try again or contact us.';
} finally {
busy = false;
submit.disabled = sentToBackend;
}
});
void initializeFields();