/* global usScheduler, Stripe */ (function () { 'use strict'; const { restUrl, nonce, stripeKey } = usScheduler; function apiFetch(path, options = {}) { return fetch(restUrl + path, { ...options, headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': nonce, ...(options.headers || {}), }, }).then(async (res) => { const data = await res.json(); if (!res.ok) throw new Error(data.message || 'Request failed'); return data; }); } function escHtml(str) { return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function money(amount, currency) { return `${Number(amount).toFixed(2)} ${escHtml(currency || '')}`.trim(); } // Render Stripe's Payment Element into mountEl and resolve once the card has // been confirmed. The server is told the result out-of-band via webhook, so a // successful confirm here just means "the charge is on its way". function confirmCard(intent, mountEl) { return new Promise((resolve, reject) => { if (typeof Stripe === 'undefined') { reject(new Error('Card payment is unavailable right now. Please try again later.')); return; } const stripe = Stripe(intent.publishable_key || stripeKey); const elements = stripe.elements({ clientSecret: intent.client_secret }); const paymentEl = elements.create('payment'); mountEl.innerHTML = `

Payment

Amount due: ${money(intent.amount, intent.currency)}

`; paymentEl.mount('#us-card-element'); const payBtn = mountEl.querySelector('#us-pay-btn'); const cardError = mountEl.querySelector('#us-card-error'); payBtn.addEventListener('click', () => { payBtn.disabled = true; cardError.style.display = 'none'; stripe.confirmPayment({ elements, redirect: 'if_required' }) .then((result) => { if (result.error) { cardError.textContent = result.error.message; cardError.style.display = 'block'; payBtn.disabled = false; return; } resolve(intent); }) .catch((err) => { cardError.textContent = err.message; cardError.style.display = 'block'; payBtn.disabled = false; }); }); }); } // Public helper used by the booking and group-class flows. Given a freshly // created registration, drive its payment step and resolve with the intent // result (method card/etransfer/comp) so the caller can show a message. window.usPayment = { collect(type, registrationId, mountEl) { if (!registrationId) { return Promise.resolve(null); } return apiFetch('payments/intent', { method: 'POST', body: JSON.stringify({ registration_type: type, registration_id: registrationId }), }).then((intent) => { if (intent.method === 'card' && intent.client_secret) { return confirmCard(intent, mountEl); } return intent; }); }, // Human-readable confirmation copy for a completed payment step. message(result) { if (!result) { return 'Your registration is confirmed.'; } if (result.method === 'etransfer') { const where = result.etransfer_email ? ` to ${escHtml(result.etransfer_email)}` : ''; return `Please send an e-transfer of ${money(result.amount, result.currency)}${where}. ` + 'Your spot is reserved and will be confirmed once payment is received.'; } if (result.method === 'card') { return 'Thank you — your payment is processing. Your registration will be confirmed shortly.'; } return 'Your registration is confirmed.'; }, }; }());