@blocklet/payment-react
Version:
Reusable react components for payment kit v2
688 lines (687 loc) • 29.9 kB
JavaScript
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import CreditCardIcon from "@mui/icons-material/CreditCard";
import CurrencyBitcoinIcon from "@mui/icons-material/CurrencyBitcoin";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import LocalOfferOutlinedIcon from "@mui/icons-material/LocalOfferOutlined";
import CloseIcon from "@mui/icons-material/Close";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
import {
Avatar,
Box,
Button,
CircularProgress,
Collapse,
Divider,
Drawer,
MenuItem,
Select,
Skeleton,
Stack,
ToggleButton,
ToggleButtonGroup,
Tooltip,
Typography
} from "@mui/material";
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
import {
useCheckoutStatus,
usePaymentMethodFeature,
useCustomerFormFeature,
useSubmitFeature,
usePricingFeature,
useSessionContext,
useLineItems,
usePromotion,
useExchangeRate
} from "@blocklet/payment-react-headless";
import { joinURL } from "ufo";
import { usePaymentContext } from "../../../contexts/payment.js";
import { useMobile } from "../../../hooks/mobile.js";
import { getPrefix, getStatementDescriptor } from "../../../libs/util.js";
import OverdueInvoicePayment from "../../../components/over-due-invoice-payment.js";
import { tSafe, whiteTooltipSx, primaryContrastColor } from "../../utils/format.js";
import CustomerInfoCard from "../../components/right/customer-info-card.js";
import SubscriptionDisclaimer from "../../components/right/subscription-disclaimer.js";
import StatusFeedback from "../../components/right/status-feedback.js";
import PromotionInput from "../../components/left/promotion-input.js";
export default function PaymentPanel() {
const { t, locale } = useLocaleContext();
const { session, sessionData, subscription, refresh } = useSessionContext();
const { isDonation } = useCheckoutStatus();
const paymentMethod = usePaymentMethodFeature();
const form = useCustomerFormFeature();
const submit = useSubmitFeature();
const pricing = usePricingFeature();
const { session: didSession, connect, prefix: paymentKitPrefix } = usePaymentContext();
const { inventoryOk } = useLineItems();
const promotion = usePromotion();
const rate = useExchangeRate();
const { isMobile } = useMobile();
const isAmountLoading = paymentMethod.switching || rate.hasDynamicPricing && rate.status === "loading";
const { currency, types, isStripe, isCrypto } = paymentMethod;
const mode = session?.mode || "payment";
const discounts = session?.discounts || [];
const isLoggedIn = !!didSession?.user;
const actionLabel = isDonation ? t("payment.checkout.donate") : t(`payment.checkout.${mode}`);
const buttonLabel = isLoggedIn ? actionLabel : t("payment.checkout.connect", { action: actionLabel });
const [customerLimited, setCustomerLimited] = useState(false);
const [mobileDetailsOpen, setMobileDetailsOpen] = useState(false);
const [promoDrawerOpen, setPromoDrawerOpen] = useState(false);
useEffect(() => {
if (submit.status === "failed" && submit.context?.code === "CUSTOMER_LIMITED") {
setCustomerLimited(true);
}
}, [submit.status, submit.context]);
const canSubmit = submit.status === "idle" && session?.status === "open" && inventoryOk;
const isProcessing = ["submitting", "waiting_did"].includes(submit.status);
const handleAction = useCallback(() => {
if (!canSubmit) return;
submit.lock();
if (isLoggedIn || isDonation) {
submit.execute();
return;
}
didSession?.login?.(() => {
Promise.all([refresh(true), form.refetchCustomer()]).then(() => submit.execute()).catch((err) => {
console.error("Post-login refresh failed:", err);
});
});
}, [canSubmit, isLoggedIn, isDonation, didSession, refresh, form, submit]);
useEffect(() => {
if (didSession?.user && !submit.status.startsWith("submitting")) {
form.refetchCustomer();
}
}, [didSession?.user]);
const cryptoType = types.find((tp) => tp.type === "crypto");
const cryptoMethods = useMemo(
() => paymentMethod.available.filter((m) => m.type !== "stripe"),
[paymentMethod.available]
);
const networks = useMemo(() => {
if (!cryptoMethods.length) return [];
return cryptoMethods.map((m) => ({
id: m.id,
name: m.name,
logo: m.logo || "",
currencies: m.payment_currencies || []
}));
}, [cryptoMethods]);
const currentMethodId = paymentMethod.current?.id || "";
useEffect(() => {
const handleKeyDown = (e) => {
if (e.key === "Enter" && canSubmit && submit.status === "idle") {
const tag = e.target?.tagName?.toLowerCase();
if (tag === "textarea") return;
handleAction();
}
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [canSubmit, submit.status, handleAction]);
const didConnectOpenedRef = useRef(false);
const didConnectSucceededRef = useRef(false);
const submitStatusRef = useRef(submit.status);
useEffect(() => {
submitStatusRef.current = submit.status;
}, [submit.status]);
useEffect(() => {
if (submit.status !== "waiting_did") {
didConnectOpenedRef.current = false;
didConnectSucceededRef.current = false;
return;
}
const ctx = submit.context;
if (ctx?.type !== "did_connect" || !connect) return;
if (didConnectOpenedRef.current) return;
didConnectOpenedRef.current = true;
const didPrefix = `${paymentKitPrefix || window.location.origin}/api/did`.replace(/([^:])\/\//g, "$1/");
connect.open({
locale,
action: ctx.action,
prefix: didPrefix,
saveConnect: false,
extraParams: ctx.extraParams,
onSuccess: async () => {
didConnectSucceededRef.current = true;
connect.close();
await submit.didConnectComplete();
},
onClose: () => {
connect.close();
if (submitStatusRef.current !== "waiting_did") return;
if (!didConnectSucceededRef.current) {
submit.reset();
}
},
onError: (err) => {
console.error("DID Connect error:", err);
if (submitStatusRef.current !== "waiting_did") return;
submit.reset();
},
messages: {
title: t("payment.checkout.connectModal.title", { action: buttonLabel }),
scan: t("payment.checkout.connectModal.scan"),
confirm: t("payment.checkout.connectModal.confirm")
}
});
}, [submit.status, submit.context, connect, locale, t, buttonLabel]);
const activeType = types.find((tp) => tp.active)?.type || "crypto";
const hasMultipleTypes = types.length > 1;
return /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", flex: 1, minHeight: 0 }, children: [
/* @__PURE__ */ jsxs(
Box,
{
sx: {
flex: 1,
display: "flex",
flexDirection: "column",
overflowY: "auto",
minHeight: 0,
"&::-webkit-scrollbar": { display: "none" },
scrollbarWidth: "none"
},
children: [
/* @__PURE__ */ jsx(
Typography,
{
sx: {
fontSize: 13,
fontWeight: 700,
letterSpacing: "0.02em",
color: "text.primary",
mb: 2.5
},
children: t("payment.checkout.paymentDetails")
}
),
hasMultipleTypes && /* @__PURE__ */ jsx(
ToggleButtonGroup,
{
value: activeType,
exclusive: true,
onChange: (_, v) => v && paymentMethod.setType(v),
fullWidth: true,
size: "small",
sx: {
mb: 2.5,
bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(255,255,255,0.06)" : "grey.100",
borderRadius: "10px",
p: 0.5,
"& .MuiToggleButton-root": {
textTransform: "none",
borderRadius: "8px !important",
py: 0.75,
border: "none",
fontSize: 14,
fontWeight: 500,
gap: 0.75,
color: "text.secondary"
},
"& .Mui-selected": {
bgcolor: "background.paper !important",
color: "text.primary",
fontWeight: 600,
boxShadow: (theme) => theme.palette.mode === "dark" ? "0 1px 3px rgba(0,0,0,0.3)" : "0 1px 3px rgba(0,0,0,0.08)",
"&:hover": { bgcolor: "background.paper !important" }
}
},
children: types.map((tp) => /* @__PURE__ */ jsxs(ToggleButton, { value: tp.type, children: [
tp.type === "stripe" ? /* @__PURE__ */ jsx(CreditCardIcon, { sx: { fontSize: 18 } }) : /* @__PURE__ */ jsx(CurrencyBitcoinIcon, { sx: { fontSize: 18 } }),
tp.label || (tp.type === "stripe" ? "Card" : "Crypto")
] }, tp.type))
}
),
isCrypto && networks.length > 0 && /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1.5, sx: { mb: 2.5 }, children: [
networks.length > 1 && /* @__PURE__ */ jsxs(Box, { sx: { flex: 1 }, children: [
/* @__PURE__ */ jsx(
Typography,
{
sx: {
fontSize: 12,
fontWeight: 600,
color: "text.secondary",
mb: 0.5,
letterSpacing: "0.02em"
},
children: t("common.network")
}
),
/* @__PURE__ */ jsx(
Select,
{
value: currentMethodId,
onChange: (e) => {
const network = networks.find((n) => n.id === e.target.value);
if (network?.currencies?.[0]) {
paymentMethod.setCurrency(network.currencies[0].id);
}
},
fullWidth: true,
size: "small",
sx: {
borderRadius: "8px",
bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(255,255,255,0.06)" : "grey.50",
"& .MuiOutlinedInput-notchedOutline": { borderColor: "transparent" },
"&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "divider" },
"&.Mui-focused .MuiOutlinedInput-notchedOutline": { borderColor: "primary.main", borderWidth: 1 },
"& .MuiSelect-select": { display: "flex", alignItems: "center", gap: 1, py: 1 }
},
children: networks.map((net) => /* @__PURE__ */ jsxs(MenuItem, { value: net.id, sx: { gap: 1 }, children: [
net.logo && /* @__PURE__ */ jsx(Avatar, { src: net.logo, sx: { width: 20, height: 20 } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 14 }, children: net.name })
] }, net.id))
}
)
] }),
/* @__PURE__ */ jsxs(Box, { sx: { flex: 1 }, children: [
/* @__PURE__ */ jsx(
Typography,
{
sx: {
fontSize: 12,
fontWeight: 600,
color: "text.secondary",
mb: 0.5,
letterSpacing: "0.02em"
},
children: t("common.currency")
}
),
/* @__PURE__ */ jsx(
Select,
{
value: currency?.id || "",
onChange: (e) => paymentMethod.setCurrency(e.target.value),
fullWidth: true,
size: "small",
sx: {
borderRadius: "8px",
bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(255,255,255,0.06)" : "grey.50",
"& .MuiOutlinedInput-notchedOutline": { borderColor: "transparent" },
"&:hover .MuiOutlinedInput-notchedOutline": { borderColor: "divider" },
"&.Mui-focused .MuiOutlinedInput-notchedOutline": { borderColor: "primary.main", borderWidth: 1 },
"& .MuiSelect-select": { display: "flex", alignItems: "center", gap: 1, py: 1 }
},
children: (isCrypto && networks.length > 1 ? networks.find((n) => n.id === currentMethodId)?.currencies || [] : cryptoType?.currencies || []).map((cur) => /* @__PURE__ */ jsxs(MenuItem, { value: cur.id, sx: { gap: 1 }, children: [
cur.logo && /* @__PURE__ */ jsx(Avatar, { src: cur.logo, sx: { width: 20, height: 20 } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 14 }, children: cur.symbol }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 12, color: "text.secondary", ml: 0.5 }, children: cur.name })
] }, cur.id))
}
)
] })
] }),
isStripe && currency && /* @__PURE__ */ jsxs(Box, { sx: { mb: 2.5 }, children: [
/* @__PURE__ */ jsx(
Typography,
{
sx: {
fontSize: 12,
fontWeight: 600,
color: "text.secondary",
mb: 0.5,
letterSpacing: "0.02em"
},
children: t("common.currency")
}
),
/* @__PURE__ */ jsx(
Select,
{
value: currency.id || "usd",
readOnly: true,
fullWidth: true,
size: "small",
IconComponent: () => null,
sx: {
borderRadius: "8px",
bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(255,255,255,0.06)" : "grey.50",
"& .MuiOutlinedInput-notchedOutline": { borderColor: "transparent !important" },
"& .MuiSelect-select": { display: "flex", alignItems: "center", gap: 1, py: 1 }
},
children: /* @__PURE__ */ jsxs(MenuItem, { value: currency.id || "usd", sx: { gap: 1 }, children: [
currency.logo && /* @__PURE__ */ jsx(Avatar, { src: currency.logo, sx: { width: 20, height: 20 } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 14, fontWeight: 600 }, children: currency.symbol }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 12, color: "text.secondary", ml: 0.5 }, children: currency.name })
] })
}
)
] }),
/* @__PURE__ */ jsx(CustomerInfoCard, { form, isLoggedIn })
]
}
),
/* @__PURE__ */ jsxs(Box, { className: "cko-v2-submit-btn", sx: { flexShrink: 0 }, children: [
isMobile && pricing.staking && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsxs(
Box,
{
onClick: () => setMobileDetailsOpen(!mobileDetailsOpen),
sx: { display: "flex", alignItems: "center", justifyContent: "space-between", cursor: "pointer", mb: 1 },
children: [
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 13, fontWeight: 600, color: "text.secondary" }, children: t("payment.checkout.orderSummary") }),
/* @__PURE__ */ jsx(
ExpandMoreIcon,
{
sx: {
fontSize: 18,
color: "text.secondary",
transition: "0.2s",
transform: mobileDetailsOpen ? "rotate(180deg)" : "rotate(0deg)"
}
}
)
]
}
),
/* @__PURE__ */ jsxs(Collapse, { in: mobileDetailsOpen, children: [
/* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { mb: 1 }, children: [
/* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, alignItems: "center", children: [
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 13, color: "text.secondary" }, children: t("payment.checkout.staking.title") }),
/* @__PURE__ */ jsx(HelpOutlineIcon, { sx: { fontSize: 14, color: "text.disabled" } })
] }),
isAmountLoading ? /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: 60, height: 18 }) : /* @__PURE__ */ jsxs(Typography, { sx: { fontSize: 13, fontWeight: 600 }, children: [
"+",
pricing.staking
] })
] }),
/* @__PURE__ */ jsx(Divider, { sx: { mb: 1 } })
] })
] }),
!isMobile && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(Divider, { sx: { mb: 2 } }),
pricing.staking && /* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { mb: 1 }, children: [
/* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, alignItems: "center", children: [
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 14, color: "text.secondary" }, children: t("payment.checkout.staking.title") }),
/* @__PURE__ */ jsx(
Tooltip,
{
title: t("payment.checkout.staking.tooltip"),
placement: "top",
arrow: true,
slotProps: { popper: { sx: whiteTooltipSx } },
children: /* @__PURE__ */ jsx(HelpOutlineIcon, { sx: { fontSize: 16, color: "text.disabled" } })
}
)
] }),
isAmountLoading ? /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: 80, height: 22 }) : /* @__PURE__ */ jsxs(Typography, { sx: { fontSize: 14, fontWeight: 600 }, children: [
"+",
pricing.staking
] })
] }),
/* @__PURE__ */ jsx(
PromotionInput,
{
promotion: {
applied: promotion.applied,
code: promotion.code,
active: promotion.active,
inactiveReason: promotion.inactiveReason,
apply: promotion.apply,
remove: promotion.remove
},
discounts,
discountAmount: pricing.discount,
currency,
isAmountLoading
}
)
] }),
(() => {
const totalStr = pricing.total || "0";
const parts = totalStr.split(/\s+/);
const num = parts[0] || "0";
const sym = parts.slice(1).join(" ") || currency?.symbol || "";
const dotIdx = num.indexOf(".");
const intPart = dotIdx >= 0 ? num.slice(0, dotIdx) : num;
const decPart = dotIdx >= 0 ? num.slice(dotIdx) : "";
return /* @__PURE__ */ jsxs(Box, { sx: { mb: isMobile ? 1.5 : 2.5 }, children: [
/* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "flex-end", children: [
/* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 700, fontSize: 14, color: "text.secondary", pb: 0.5 }, children: t("common.totalDue") }),
isAmountLoading ? /* @__PURE__ */ jsx(Skeleton, { variant: "text", width: 140, height: 44 }) : /* @__PURE__ */ jsxs(Box, { sx: { textAlign: "right" }, children: [
/* @__PURE__ */ jsx(
Typography,
{
component: "span",
sx: {
fontSize: { xs: 28, md: 36 },
fontWeight: 800,
color: "text.primary",
lineHeight: 1,
transition: "opacity 0.3s ease"
},
children: intPart
}
),
decPart && /* @__PURE__ */ jsx(
Typography,
{
component: "span",
sx: { fontSize: { xs: 16, md: 20 }, fontWeight: 700, color: "text.secondary", lineHeight: 1 },
children: decPart
}
),
/* @__PURE__ */ jsx(
Typography,
{
component: "span",
sx: { fontSize: { xs: 14, md: 16 }, fontWeight: 600, color: "text.secondary", ml: 0.75 },
children: sym
}
)
] })
] }),
(pricing.usdEquivalent || isMobile && promotion.active) && !isAmountLoading && /* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { mt: 0.25 }, children: [
(() => {
if (isMobile && !promotion.applied && promotion.active) {
return /* @__PURE__ */ jsxs(
Box,
{
onClick: () => setPromoDrawerOpen(true),
sx: { display: "flex", alignItems: "center", gap: 0.5, cursor: "pointer" },
children: [
/* @__PURE__ */ jsx(LocalOfferOutlinedIcon, { sx: { fontSize: 14, color: "primary.main" } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 12, fontWeight: 600, color: "primary.main" }, children: tSafe(t, "payment.checkout.promotion.add", "Add promo code") })
]
}
);
}
if (isMobile && promotion.applied) {
return /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
/* @__PURE__ */ jsx(LocalOfferOutlinedIcon, { sx: { fontSize: 14, color: "success.main" } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 12, fontWeight: 600, color: "success.main" }, children: promotion.code }),
pricing.discount && /* @__PURE__ */ jsxs(Typography, { sx: { fontSize: 11, color: "text.secondary" }, children: [
"(-",
pricing.discount,
")"
] }),
/* @__PURE__ */ jsx(
CloseIcon,
{
onClick: promotion.remove,
sx: { fontSize: 14, color: "error.main", cursor: "pointer", ml: 0.25 }
}
)
] });
}
return /* @__PURE__ */ jsx(Box, {});
})(),
pricing.usdEquivalent && /* @__PURE__ */ jsxs(Typography, { sx: { fontSize: 13, color: "text.secondary" }, children: [
"\u2248 ",
pricing.usdEquivalent
] })
] })
] });
})(),
/* @__PURE__ */ jsxs(
Button,
{
variant: "contained",
size: "large",
fullWidth: true,
disabled: !canSubmit || submit.status === "waiting_stripe",
onClick: handleAction,
startIcon: isProcessing ? /* @__PURE__ */ jsx(CircularProgress, { size: 20, color: "inherit" }) : null,
sx: {
py: 1.5,
fontSize: "1.1rem",
fontWeight: 600,
textTransform: "none",
borderRadius: "12px",
color: (theme) => primaryContrastColor(theme),
position: "relative",
overflow: "hidden",
"&:hover": { bgcolor: "primary.main" },
"&:hover .arrow-icon": { transform: "translateX(4px)" },
"&:hover .shine-layer": { transform: "translateX(100%)" }
},
children: [
/* @__PURE__ */ jsx(Box, { component: "span", sx: { position: "relative", zIndex: 1 }, children: isProcessing ? `${t("payment.checkout.processing")}...` : buttonLabel }),
!isProcessing && /* @__PURE__ */ jsx(
ArrowForwardIcon,
{
className: "arrow-icon",
sx: { ml: 1, position: "relative", zIndex: 1, transition: "transform 0.2s ease" }
}
),
/* @__PURE__ */ jsx(
Box,
{
className: "shine-layer",
sx: {
position: "absolute",
inset: 0,
background: "linear-gradient(90deg, transparent, rgba(255,255,255,0.12), transparent)",
transform: "translateX(-100%)",
transition: "transform 0.7s ease",
pointerEvents: "none"
}
}
)
]
}
),
isMobile && /* @__PURE__ */ jsxs(
Stack,
{
direction: "row",
alignItems: "center",
justifyContent: "center",
spacing: 0.75,
sx: { mt: 1.5, opacity: 0.55 },
children: [
/* @__PURE__ */ jsx(LockOutlinedIcon, { sx: { fontSize: 13, color: "text.secondary" } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.secondary" }, children: tSafe(t, "payment.checkout.ssl", "SSL Secure") }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.disabled" }, children: "\xB7" }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.secondary" }, children: tSafe(t, "common.terms", "Terms") }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.disabled" }, children: "|" }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.secondary" }, children: tSafe(t, "common.privacy", "Privacy") })
]
}
)
] }),
isMobile && /* @__PURE__ */ jsxs(
Drawer,
{
anchor: "bottom",
open: promoDrawerOpen,
onClose: () => setPromoDrawerOpen(false),
PaperProps: {
sx: {
borderRadius: "16px 16px 0 0",
p: 3,
pb: 4,
minHeight: "30vh"
}
},
children: [
/* @__PURE__ */ jsx(Box, { sx: { width: 40, height: 4, bgcolor: "divider", borderRadius: 2, mx: "auto", mb: 3 } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 700, fontSize: 16, mb: 2 }, children: tSafe(t, "payment.checkout.promotion.add", "Add promo code") }),
/* @__PURE__ */ jsx(
PromotionInput,
{
initialShowInput: true,
promotion: {
applied: promotion.applied,
code: promotion.code,
active: promotion.active,
inactiveReason: promotion.inactiveReason,
apply: async (...args) => {
const result = await promotion.apply(...args);
if (result.success) setPromoDrawerOpen(false);
return result;
},
remove: promotion.remove
},
discounts,
discountAmount: pricing.discount,
currency
}
)
]
}
),
/* @__PURE__ */ jsxs(Box, { sx: { flexShrink: 0 }, children: [
/* @__PURE__ */ jsx(
SubscriptionDisclaimer,
{
mode,
subscription,
staking: pricing.staking,
appName: getStatementDescriptor(session?.line_items || [])
}
),
!isMobile && /* @__PURE__ */ jsxs(
Stack,
{
direction: "row",
alignItems: "center",
justifyContent: "center",
spacing: 0.75,
sx: { mt: 2.5, opacity: 0.55 },
children: [
/* @__PURE__ */ jsx(LockOutlinedIcon, { sx: { fontSize: 13, color: "text.secondary" } }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.secondary" }, children: tSafe(t, "payment.checkout.ssl", "SSL Secure") }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.disabled" }, children: "\xB7" }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.secondary" }, children: tSafe(t, "common.terms", "Terms") }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.disabled" }, children: "|" }),
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: 11, color: "text.secondary" }, children: tSafe(t, "common.privacy", "Privacy") })
]
}
)
] }),
/* @__PURE__ */ jsx(StatusFeedback, { status: submit.status, context: submit.context, onReset: submit.reset }),
customerLimited && /* @__PURE__ */ jsx(
OverdueInvoicePayment,
{
customerId: sessionData?.customer?.id || session?.user?.did,
onPaid: () => {
setCustomerLimited(false);
submit.retry();
},
alertMessage: t("payment.customer.pastDue.alert.customMessage"),
detailLinkOptions: {
enabled: true,
onClick: () => {
setCustomerLimited(false);
window.open(
joinURL(getPrefix(), `/customer/invoice/past-due?referer=${encodeURIComponent(window.location.href)}`),
"_self"
);
}
},
dialogProps: {
open: customerLimited,
onClose: () => {
setCustomerLimited(false);
submit.reset();
},
title: t("payment.customer.pastDue.alert.title")
}
}
)
] });
}