UNPKG

@datalayer/core

Version:
96 lines (95 loc) 4.8 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /* * Copyright (c) 2023-2025 Datalayer, Inc. * Distributed under the terms of the Modified BSD License. */ import { createElement, useCallback, useEffect, useState } from 'react'; import { Button, Flash, FormControl, Spinner, Text } from '@primer/react'; import { Box } from "@datalayer/primer-addons"; import { useCache } from '../../hooks'; import { useIAMStore } from '../../state'; /** * Stripe checkout. */ export function StripeCheckout({ checkoutPortal }) { const { iamRunUrl } = useIAMStore(); const { createCheckoutSession, refreshStripePrices } = useCache(); const [stripe, setStripe] = useState(null); const [components, setComponents] = useState(null); const [items, setItems] = useState(null); const [product, setProduct] = useState(null); const [checkout, setCheckout] = useState(false); // Refresh Stripe items. useEffect(() => { refreshStripePrices() .then(response => { if (response.success) { setItems(response.prices); } else { setItems([]); } }) .catch(error => { console.error('Failed to fetch product items.', error); setItems([]); }); }, []); // Load stripe components. useEffect(() => { import('@stripe/react-stripe-js').then(module => { setComponents(module); }); }, []); // Load stripe API useEffect(() => { if (checkoutPortal?.metadata?.stripe_key) { import('@stripe/stripe-js').then(module => { setStripe(module.loadStripe(checkoutPortal.metadata.stripe_key)); }); } }, [checkoutPortal?.metadata?.stripe_key]); const fetchClientSecret = useCallback(() => { const location = document.location; // Create a Checkout Session. return createCheckoutSession(product, location); }, [iamRunUrl, location, product?.id]); const options = { fetchClientSecret }; let view = (_jsx(Box, { sx: { minHeight: '40px' }, children: _jsx(Spinner, {}) })); if (checkout) { if (stripe && components) { view = createElement(Box, { id: 'checkout', sx: { flex: '1 1 auto' } }, createElement(components.EmbeddedCheckoutProvider, { stripe, options }, createElement(components.EmbeddedCheckout))); } } else if (items) { view = items.length ? (_jsxs(Box, { sx: { flex: '1 1 auto' }, onKeyDown: event => { if (product && event.key === 'Enter') { setCheckout(true); } }, children: [_jsx(Text, { as: "h3", children: "Choose a credits package" }), _jsx(Box, { role: "radiogroup", sx: { display: 'grid', gap: 'var(--stack-gap-normal)', gridTemplateColumns: Array(items.length).fill('1fr').join(' '), padding: 'var(--stack-padding-normal) 0' }, children: items.map(item => (_jsx(Box, { role: "radio", "aria-labelledby": `checkout-price-${item.id}`, "aria-checked": product?.id === item.id, onClick: () => { setProduct(item); }, sx: { borderStyle: 'solid', borderRadius: 'var(--borderRadius-medium)', borderWidth: 'var(--borderWidth-thick)', borderColor: product?.id === item.id ? 'var(--borderColor-accent-emphasis)' : 'var(--borderColor-default)', padding: 'var(--stack-padding-condensed)', cursor: 'pointer' }, children: _jsxs(FormControl, { sx: { alignItems: 'center' }, children: [_jsx(FormControl.Label, { id: `checkout-price-${item.id}`, sx: { alignSelf: 'center' }, children: item.name }), _jsx(Text, { as: "p", children: new Intl.NumberFormat(undefined, { style: 'currency', currency: item.currency }).format(item.amount / 100) }), _jsxs(Text, { as: "p", children: [item.credits, " credits"] })] }, item.id) }))) }), _jsx(Button, { variant: "primary", onClick: () => { setCheckout(true); }, disabled: product === null, sx: { float: 'right' }, children: "Checkout" })] })) : (_jsx(Box, { children: _jsx(Flash, { variant: "danger", children: "Unable to fetch the available products. Please try again later." }) })); } return view; }