// pages/PayPalCheckout.jsx — Verigo Global: real PayPal "Buy Now" button. // Talks to /api/paypal/create-order and /api/paypal/capture-order in server.js — // only works when the site is running as a Node app (`node server.js`), not on // plain static hosting. Prices are never sent from the browser; the server looks // them up itself from server/pricing.js. let sdkPromise = null; function loadPayPalSdk(clientId) { if (sdkPromise) return sdkPromise; sdkPromise = new Promise((resolve, reject) => { if (window.paypal) return resolve(window.paypal); const s = document.createElement('script'); s.src = `https://www.paypal.com/sdk/js?client-id=${encodeURIComponent(clientId)}¤cy=USD&intent=capture`; s.onload = () => resolve(window.paypal); s.onerror = () => reject(new Error('Could not load PayPal.')); document.head.appendChild(s); }); return sdkPromise; } // status: 'checking' | 'unavailable' | 'ready' const PayPalCheckout = ({ itemType, itemKey, tier, customer, disabled, disabledReason, onSuccess, onError }) => { const ref = React.useRef(null); const [status, setStatus] = React.useState('checking'); const customerRef = React.useRef(customer); customerRef.current = customer; React.useEffect(() => { let cancelled = false; fetch('/api/paypal/client-id') .then((r) => r.json()) .then((data) => { if (cancelled) return; if (!data.configured) { setStatus('unavailable'); return; } return loadPayPalSdk(data.clientId).then(() => { if (!cancelled) setStatus('ready'); }); }) .catch(() => { if (!cancelled) setStatus('unavailable'); }); return () => { cancelled = true; }; }, []); React.useEffect(() => { if (status !== 'ready' || !ref.current || !window.paypal) return; ref.current.innerHTML = ''; const buttons = window.paypal.Buttons({ style: { layout: 'horizontal', height: 45, tagline: false, shape: 'pill' }, createOrder: async () => { const res = await fetch('/api/paypal/create-order', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemType, itemKey, tier }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Could not start checkout.'); return data.id; }, onApprove: async (data) => { const res = await fetch('/api/paypal/capture-order', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ orderId: data.orderID, itemType, itemKey, tier, customer: customerRef.current }), }); const result = await res.json(); if (!res.ok || result.status !== 'COMPLETED') throw new Error(result.error || 'Payment could not be completed.'); onSuccess && onSuccess(result); }, onError: (err) => { onError && onError(err); }, }); buttons.render(ref.current); return () => { try { buttons.close(); } catch (e) {} }; }, [status, itemType, itemKey, tier]); if (status === 'checking') return null; if (status === 'unavailable') { return

Online payment isn't available right now — please use the form above and we'll follow up with a secure payment link.

; } if (disabled) { return

{disabledReason || 'Fill in your details above to pay.'}

; } return
; }; Object.assign(window, { PayPalCheckout });