@datalayer/core
Version:
**Datalayer Core**
96 lines (95 loc) • 4.8 kB
JavaScript
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;
}