Created
December 23, 2024 17:36
-
-
Save becomevocal/c922e3736d9174372379b6bbb7572e3e to your computer and use it in GitHub Desktop.
PayPal Pay Later component for Catalyst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use client'; | |
// [>] Developer Notes | |
// | |
// * Made for use with Catalyst, by BigCommerce: https://www.catalyst.dev/ | |
// | |
// * Requires NEXT_PUBLIC_PAYPAL_CLIENT_ID env var | |
// - By default it will fall back to 'test' if not set, which uses the non-transacting PayPal sandbox | |
// - You can get your PayPal Client ID here: https://developer.paypal.com/dashboard/applications/live | |
// | |
// * PayPal documentation is here: https://developer.paypal.com/docs/checkout/pay-later/us/integrate/reference/ | |
// | |
// Use this component like: <PayPalPayLater amount={product.price} currency="USD" /> | |
import Script from 'next/script'; | |
import { useEffect, useRef, useState } from 'react'; | |
interface PriceRange { | |
type: 'range'; | |
minValue: string; | |
maxValue: string; | |
} | |
interface PriceSale { | |
type: 'sale'; | |
previousValue: string; | |
currentValue: string; | |
} | |
type Price = string | PriceRange | PriceSale; | |
interface PayPalPayLaterProps { | |
amount: Price; | |
currency: string; | |
} | |
interface PayPalMessageOptions { | |
amount: number; | |
currency: string; | |
style?: { | |
layout?: 'text' | 'flex' | 'custom'; | |
logo?: { | |
type?: 'inline' | 'primary' | 'alternative' | 'none'; | |
position?: 'left' | 'right' | 'top'; | |
}; | |
text?: { | |
color?: string; | |
size?: number; | |
align?: 'left' | 'center' | 'right'; | |
}; | |
color?: string; | |
}; | |
} | |
declare global { | |
interface Window { | |
paypal?: { | |
Messages: new (options: PayPalMessageOptions) => { render: (target: HTMLElement) => void }; | |
}; | |
} | |
} | |
export function removeCurrencySymbol(price: string): string { | |
// Remove common currency symbols and thousands separators | |
return price.replace(/[£$€¥,]/g, '').trim(); | |
} | |
export function getDisplayPrice(price: Price): number { | |
if (typeof price === 'string') { | |
// Remove common currency symbols and thousands separators | |
return parseFloat(price.replace(/[£$€¥,]/g, '').trim()); | |
} | |
switch (price.type) { | |
case 'range': | |
return parseFloat(price.minValue); | |
case 'sale': | |
return parseFloat(price.currentValue); | |
default: | |
return 0; | |
} | |
} | |
export function PayPalPayLater({ amount, currency }: PayPalPayLaterProps) { | |
const paypalRef = useRef<HTMLDivElement>(null); | |
const [scriptReady, setScriptReady] = useState(false); | |
const displayAmount = getDisplayPrice(amount); | |
// As of 12/23/2024 PayPal Pay Later supports these currencies | |
const supportedCurrencies = ['USD', 'GBP', 'EUR', 'AUD']; | |
useEffect(() => { | |
if (scriptReady && paypalRef.current && window.paypal) { | |
const paypalMessages = new window.paypal.Messages({ | |
amount: displayAmount, | |
currency, | |
style: { | |
layout: 'text', | |
text: { | |
size: 14, | |
}, | |
logo: { | |
type: 'primary', | |
}, | |
}, | |
}); | |
paypalMessages.render(paypalRef.current); | |
} | |
}, [scriptReady, displayAmount, currency]); | |
if (!supportedCurrencies.includes(currency)) { | |
return null; | |
} | |
return ( | |
<> | |
<Script | |
onReady={() => setScriptReady(true)} | |
src={`https://www.paypal.com/sdk/js?client-id=${process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID || 'test'}&components=messages`} | |
strategy="lazyOnload" | |
/> | |
<div className="min-h-7" ref={paypalRef} /> | |
</> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment