@blocklet/payment-react
Version:
Reusable react components for payment kit v2
804 lines (803 loc) • 29.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
module.exports = CreditTopupPanel;
var _jsxRuntime = require("react/jsx-runtime");
var _react = require("react");
var _material = require("@mui/material");
var _InfoOutlined = _interopRequireDefault(require("@mui/icons-material/InfoOutlined"));
var _AccessTimeOutlined = _interopRequireDefault(require("@mui/icons-material/AccessTimeOutlined"));
var _Inventory2Outlined = _interopRequireDefault(require("@mui/icons-material/Inventory2Outlined"));
var _ahooks = require("ahooks");
var _util = require("@ocap/util");
var _context = require("@arcblock/ux/lib/Locale/context");
var _WarningAmber = _interopRequireDefault(require("@mui/icons-material/WarningAmber"));
var _paymentReactHeadless = require("@blocklet/payment-react-headless");
var _payment = require("../../../contexts/payment");
var _api = _interopRequireDefault(require("../../../libs/api"));
var _util2 = require("../../../libs/util");
var _format = require("../../utils/format");
var _scenarioBadge = _interopRequireDefault(require("../../components/shared/scenario-badge"));
var _exchangeRateFooter = _interopRequireDefault(require("../../components/shared/exchange-rate-footer"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function CreditTopupPanel() {
const {
t,
locale
} = (0, _context.useLocaleContext)();
const {
session,
sessionData
} = (0, _paymentReactHeadless.useSessionContext)();
const {
livemode
} = (0, _paymentReactHeadless.useCheckoutStatus)();
const {
product
} = (0, _paymentReactHeadless.useProduct)();
const {
currency,
isStripe
} = (0, _paymentReactHeadless.usePaymentMethodContext)();
const lineItems = (0, _paymentReactHeadless.useLineItems)();
const rate = (0, _paymentReactHeadless.useExchangeRate)();
const slippage = (0, _paymentReactHeadless.useSlippage)();
const {
locked: configLocked
} = (0, _paymentReactHeadless.useSubmitFeature)();
const item = lineItems.items[0];
const activePrice = item ? item.upsell_price || item.price : null;
const creditConfig = activePrice?.metadata?.credit_config;
const creditAmount = creditConfig?.credit_amount ? Number(creditConfig.credit_amount) : 0;
const creditCurrencyId = creditConfig?.currency_id;
const {
session: didSession,
getCurrency
} = (0, _payment.usePaymentContext)();
const creditCurrency = creditCurrencyId ? getCurrency(creditCurrencyId) : null;
const userDid = didSession?.user?.did || sessionData?.customer?.did;
const creditCurrencyDecimal = creditCurrency?.decimal;
const creditCurrencySymbol = creditCurrency?.symbol || "Credits";
const currencySymbol = "Credits";
const meterId = activePrice?.metadata?.meter_id;
const {
data: meterData
} = (0, _ahooks.useRequest)(async () => {
if (!meterId) return null;
try {
const {
data
} = await _api.default.get(`/api/meters/public/${meterId}`);
return data;
} catch {
return null;
}
}, {
refreshDeps: [meterId]
});
const creditName = meterData?.name || product?.name || "Credits";
const validDuration = creditConfig?.valid_duration_value;
const validDurationUnit = creditConfig?.valid_duration_unit || "days";
const scheduleConfig = creditConfig?.schedule;
const hasSchedule = scheduleConfig?.enabled && scheduleConfig?.delivery_mode && scheduleConfig.delivery_mode !== "invoice";
const hasExpiry = validDuration && validDuration > 0;
const step = Math.max(creditAmount, 1);
const adjustableQty = item?.adjustable_quantity;
const canAdjust = adjustableQty?.enabled !== false;
const minQuantity = Math.max(adjustableQty?.minimum || 1, 1);
const quantityAvailable = Math.min(activePrice?.quantity_limit_per_checkout ?? Infinity, activePrice?.quantity_available ?? Infinity);
const maxQuantity = quantityAvailable ? Math.min(adjustableQty?.maximum || Infinity, quantityAvailable) : adjustableQty?.maximum || Infinity;
const {
data: pendingAmount
} = (0, _ahooks.useRequest)(async () => {
if (!creditConfig || !userDid || !creditCurrencyId || creditCurrencyDecimal == null) return null;
try {
const {
data
} = await _api.default.get("/api/meter-events/pending-amount", {
params: {
customer_id: userDid,
currency_id: creditCurrencyId
}
});
return data?.[creditCurrencyId];
} catch {
return null;
}
}, {
refreshDeps: [creditConfig, userDid, creditCurrencyId, creditCurrencyDecimal]
});
const minQtyForPending = (0, _react.useMemo)(() => {
if (!pendingAmount || !creditAmount || creditAmount <= 0) return null;
const pendingBN = new _util.BN(pendingAmount || "0");
if (!pendingBN.gt(new _util.BN(0))) return null;
const creditBN = (0, _util.fromTokenToUnit)(creditAmount, creditCurrencyDecimal);
if (!creditBN || creditBN.isZero()) return null;
return Math.ceil(pendingBN.mul(new _util.BN(100)).div(creditBN).toNumber() / 100);
}, [pendingAmount, creditAmount, creditCurrencyDecimal]);
const hasPendingAmount = pendingAmount && new _util.BN(pendingAmount || "0").gt(new _util.BN(0));
const pendingDisplayAmount = (0, _react.useMemo)(() => {
if (!hasPendingAmount) return "";
return (0, _util2.formatCreditForCheckout)((0, _util2.formatBNStr)(pendingAmount, creditCurrencyDecimal), creditCurrencySymbol, locale);
}, [hasPendingAmount, pendingAmount, creditCurrencyDecimal, creditCurrencySymbol, locale]);
const minCreditsForPending = minQtyForPending ? minQtyForPending * step : 0;
const minCreditsForPendingFormatted = minCreditsForPending ? (0, _util2.formatCreditForCheckout)((0, _util2.formatNumber)(minCreditsForPending), creditCurrencySymbol, locale) : "";
const creditInfoText = (0, _react.useMemo)(() => {
if (hasSchedule && scheduleConfig) {
const intervalUnit = scheduleConfig.interval_unit;
const intervalValue = scheduleConfig.interval_value;
let amountPerGrant;
if (scheduleConfig.amount_per_grant) {
amountPerGrant = Number(scheduleConfig.amount_per_grant);
} else {
amountPerGrant = creditAmount;
}
const formattedAmount = (0, _util2.formatCreditAmount)((0, _util2.formatNumber)(amountPerGrant), currencySymbol);
const intervalDisplay = intervalValue === 1 ? t(`common.${intervalUnit}`) : `${intervalValue} ${t(`common.${intervalUnit}s`)}`;
return scheduleConfig.expire_with_next_grant ? t("payment.checkout.credit.schedule.withRefresh", {
amount: formattedAmount,
interval: intervalDisplay
}) : t("payment.checkout.credit.schedule.periodic", {
amount: formattedAmount,
interval: intervalDisplay
});
}
return "";
}, [creditAmount, currencySymbol, hasSchedule, scheduleConfig, t]);
const validityText = (0, _react.useMemo)(() => {
if (!hasExpiry) return "";
return t("payment.checkout.creditTopup.validFor", {
duration: validDuration,
unit: t(`common.${validDurationUnit}`)
});
}, [hasExpiry, validDuration, validDurationUnit, t]);
const hasSubtitle = !!creditInfoText;
const currentQty = item?.quantity || 1;
const [localQty, setLocalQty] = (0, _react.useState)(currentQty);
const [desiredCredits, setDesiredCredits] = (0, _react.useState)(currentQty * step);
const [isEditing, setIsEditing] = (0, _react.useState)(false);
const [editValue, setEditValue] = (0, _react.useState)("");
const inputRef = (0, _react.useRef)(null);
(0, _react.useEffect)(() => {
if (configLocked || session?.status === "complete") return;
if (item?.quantity && item.quantity !== localQty) {
setLocalQty(item.quantity);
setDesiredCredits(item.quantity * step);
}
}, [item?.quantity]);
const pendingEnforcedRef = (0, _react.useRef)(false);
(0, _react.useEffect)(() => {
if (configLocked || session?.status === "complete") return;
if (pendingEnforcedRef.current) return;
if (minQtyForPending && minQtyForPending > localQty) {
pendingEnforcedRef.current = true;
const newQty = Math.min(Math.max(minQtyForPending, minQuantity), maxQuantity);
setLocalQty(newQty);
setDesiredCredits(newQty * step);
if (item) lineItems.updateQuantity(item.price_id, newQty);
}
}, [minQtyForPending]);
const maxCredits = maxQuantity * step;
const minCredits = minQuantity * step;
const debounceRef = (0, _react.useRef)(null);
(0, _react.useEffect)(() => () => {
if (debounceRef.current) clearTimeout(debounceRef.current);
}, []);
const commitCredits = (0, _react.useCallback)(credits => {
if (credits <= 0) return;
const clamped = Math.max(minCredits, Math.min(maxCredits, credits));
const packs = Math.ceil(clamped / step);
const clampedPacks = Math.max(minQuantity, Math.min(maxQuantity, packs));
setLocalQty(clampedPacks);
setDesiredCredits(clamped);
if (item) {
if (debounceRef.current) clearTimeout(debounceRef.current);
debounceRef.current = setTimeout(() => {
lineItems.updateQuantity(item.price_id, clampedPacks);
}, 400);
}
}, [step, minQuantity, maxQuantity, minCredits, maxCredits, item, lineItems]);
const handleStep = (0, _react.useCallback)(delta => {
const newCredits = desiredCredits + delta * step;
if (newCredits < step * minQuantity || Math.ceil(newCredits / step) > maxQuantity) return;
commitCredits(newCredits);
}, [desiredCredits, step, minQuantity, maxQuantity, commitCredits]);
const actualPacks = Math.max(minQuantity, Math.min(maxQuantity, Math.ceil(desiredCredits / step)));
const actualCredits = actualPacks * step;
const actualCreditsFormatted = (0, _util2.formatNumber)(actualCredits, 6, true, true);
const desiredCreditsFormatted = (0, _util2.formatNumber)(desiredCredits, 6, true, true);
const showReceiveSection = canAdjust && step > 1;
const pendingMessage = (0, _react.useMemo)(() => {
if (!hasPendingAmount) return "";
if (actualCredits >= minCreditsForPending) {
return t("payment.checkout.creditTopup.pendingEnough", {
pendingAmount: pendingDisplayAmount,
availableAmount: (0, _util2.formatCreditForCheckout)((0, _util2.formatNumber)(actualCredits - minCreditsForPending), creditCurrencySymbol, locale)
});
}
return t("payment.checkout.creditTopup.pendingWarning", {
pendingAmount: pendingDisplayAmount,
minCredits: minCreditsForPendingFormatted
});
}, [hasPendingAmount, actualCredits, minCreditsForPending, pendingDisplayAmount, creditCurrencySymbol, locale, minCreditsForPendingFormatted, t]);
const startEditing = (0, _react.useCallback)(() => {
if (!canAdjust) return;
setEditValue(String(desiredCredits));
setIsEditing(true);
setTimeout(() => inputRef.current?.select(), 0);
}, [canAdjust, desiredCredits]);
const commitEdit = (0, _react.useCallback)(() => {
setIsEditing(false);
const parsed = parseInt(editValue.replace(/,/g, ""), 10);
if (!Number.isFinite(parsed) || parsed <= 0) return;
commitCredits(parsed);
}, [editValue, commitCredits]);
const handleEditKeyDown = (0, _react.useCallback)(e => {
if (e.key === "Enter") commitEdit();else if (e.key === "Escape") setIsEditing(false);
}, [commitEdit]);
const numberHeight = {
xs: 48,
md: 72
};
const numberFontSx = {
fontSize: numberHeight,
fontWeight: 800,
lineHeight: 1,
letterSpacing: "-0.03em"
};
const circleBtnSx = {
width: {
xs: 40,
md: 56
},
height: {
xs: 40,
md: 56
},
borderRadius: "50%",
bgcolor: "background.paper",
border: "1px solid",
borderColor: theme => theme.palette.mode === "dark" ? "rgba(255,255,255,0.12)" : "divider",
color: "text.secondary",
transition: "all 0.2s ease",
"&:hover": {
borderColor: "primary.main",
color: "primary.main",
bgcolor: "background.paper"
},
"&.Mui-disabled": {
borderColor: theme => theme.palette.mode === "dark" ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)",
color: theme => theme.palette.mode === "dark" ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.12)"
}
};
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
flexDirection: "column",
height: "100%"
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
flex: 1,
display: "flex",
flexDirection: "column",
justifyContent: "center"
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_scenarioBadge.default, {
livemode,
label: (0, _format.tSafe)(t, "payment.checkout.typeBadge.topup", "TOP-UP")
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontWeight: 800,
fontSize: {
xs: 28,
md: 48
},
lineHeight: 1.1,
letterSpacing: "-0.03em",
color: "text.primary",
mb: {
xs: 0.5,
md: 1
}
},
children: t("payment.checkout.creditTopup.title", {
name: creditName
})
}), hasSubtitle && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
sx: {
display: "flex",
alignItems: "flex-start",
gap: 1,
mb: {
xs: 1.5,
md: 2.5
}
},
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 13,
md: 15
},
fontWeight: 500,
color: "text.secondary",
lineHeight: 1.5
},
children: creditInfoText
})
}), hasPendingAmount && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
direction: "row",
alignItems: "flex-start",
spacing: 1.5,
sx: {
mb: {
xs: 1.5,
md: 2.5
},
p: {
xs: 1.5,
md: 2
},
borderRadius: "12px",
bgcolor: theme => theme.palette.mode === "dark" ? "rgba(255,152,0,0.12)" : "rgba(255,152,0,0.08)",
border: "1px solid",
borderColor: theme => theme.palette.mode === "dark" ? "rgba(255,152,0,0.25)" : "rgba(255,152,0,0.2)"
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_WarningAmber.default, {
sx: {
fontSize: 18,
color: "warning.main",
mt: 0.25,
flexShrink: 0
}
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 12,
md: 13
},
fontWeight: 600,
lineHeight: 1.5,
color: "text.primary"
},
children: pendingMessage
})]
}), canAdjust ? /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
flexDirection: "column",
maxWidth: 480
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 14,
md: 17
},
fontWeight: 700,
color: "text.secondary",
mt: {
xs: 3,
md: 5
},
mb: {
xs: 2,
md: 3
}
},
children: t("payment.checkout.creditTopup.question", {
symbol: currencySymbol
})
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
alignItems: "center",
gap: {
xs: 1.5,
md: 2
}
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
onClick: () => handleStep(-1),
disabled: actualPacks <= minQuantity,
sx: circleBtnSx,
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
component: "span",
sx: {
fontSize: {
xs: 22,
md: 28
},
fontWeight: 300,
lineHeight: 1,
mt: "-1px"
},
children: "\u2212"
})
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
flex: 1,
minWidth: 0,
textAlign: "center",
cursor: canAdjust ? "text" : "default"
},
onClick: startEditing,
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
sx: {
height: numberHeight,
display: "flex",
alignItems: "center",
justifyContent: "center"
},
children: isEditing ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.InputBase, {
inputRef,
value: editValue,
onChange: e => setEditValue(e.target.value.replace(/\D/g, "")),
onBlur: commitEdit,
onKeyDown: handleEditKeyDown,
autoFocus: true,
inputProps: {
inputMode: "numeric",
pattern: "[0-9]*"
},
sx: {
width: "100%",
bgcolor: "transparent",
"&.Mui-focused": {
bgcolor: "transparent"
},
"& input": {
textAlign: "center",
...numberFontSx,
p: 0,
fontFamily: "inherit",
bgcolor: "transparent",
"&:focus": {
bgcolor: "transparent"
}
}
}
}) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
...numberFontSx,
color: "text.primary",
userSelect: "none"
},
children: desiredCreditsFormatted
})
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
sx: {
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 0.75,
mt: 1
},
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 12,
md: 14
},
fontWeight: 700,
color: "text.secondary",
textTransform: "uppercase",
letterSpacing: "0.05em"
},
children: currencySymbol
})
})]
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.IconButton, {
onClick: () => handleStep(1),
disabled: actualPacks >= maxQuantity,
sx: circleBtnSx,
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
component: "span",
sx: {
fontSize: {
xs: 22,
md: 28
},
fontWeight: 300,
lineHeight: 1
},
children: "+"
})
})]
}), step > 1 && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: 11,
fontWeight: 600,
color: "grey.500",
textTransform: "uppercase",
letterSpacing: "0.08em",
textAlign: "center",
mt: {
xs: 1.5,
md: 2
}
},
children: t("payment.checkout.creditTopup.increment", {
step: (0, _util2.formatNumber)(step, 6, true, true),
symbol: currencySymbol
})
}), showReceiveSection && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
flexDirection: "column",
mt: {
xs: 3,
md: 4
},
borderRadius: "20px",
backdropFilter: "blur(12px)",
bgcolor: theme => theme.palette.mode === "dark" ? "rgba(59,130,246,0.08)" : "rgba(59,130,246,0.04)",
border: "1px solid",
borderColor: theme => theme.palette.mode === "dark" ? "rgba(59,130,246,0.18)" : "rgba(59,130,246,0.10)",
boxShadow: theme => theme.palette.mode === "dark" ? "0 8px 32px rgba(59,130,246,0.06)" : "0 8px 32px rgba(59,130,246,0.04)"
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
p: {
xs: 2.5,
md: 3.5
}
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
sx: {
fontSize: {
xs: 16,
md: 20
},
fontWeight: 700,
color: "primary.main",
mb: 0.5
},
children: [t("payment.checkout.creditTopup.willReceive"), ": ", /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
component: "span",
sx: {
fontWeight: 800
},
children: (0, _util2.formatCreditForCheckout)(actualCreditsFormatted, currencySymbol, locale)
})]
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
alignItems: "center",
gap: 0.75,
mb: 0.5
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_Inventory2Outlined.default, {
sx: {
fontSize: 16,
color: "text.secondary"
}
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 12,
md: 14
},
fontWeight: 600,
color: "text.secondary"
},
children: t("payment.checkout.creditTopup.packInfo", {
packs: actualPacks,
perPack: (0, _util2.formatNumber)(step, 6, true, true)
})
})]
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 12,
md: 13
},
fontWeight: 500,
color: "grey.500"
},
children: t("payment.checkout.creditTopup.autoMatch")
})]
}), validityText && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
alignItems: "center",
gap: 0.75,
px: {
xs: 2.5,
md: 3.5
},
py: {
xs: 1.5,
md: 2
},
borderTop: "1px solid",
borderColor: theme => theme.palette.mode === "dark" ? "rgba(59,130,246,0.15)" : "rgba(59,130,246,0.08)"
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_AccessTimeOutlined.default, {
sx: {
fontSize: 14,
color: "grey.500"
}
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 12,
md: 13
},
fontWeight: 500,
color: "grey.500"
},
children: validityText
})]
})]
}), !showReceiveSection && validityText && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
alignItems: "center",
gap: 0.75,
mt: {
xs: 2.5,
md: 3.5
}
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_InfoOutlined.default, {
sx: {
fontSize: 14,
color: "grey.500"
}
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 12,
md: 13
},
fontWeight: 500,
color: "grey.500"
},
children: validityText
})]
})]
}) :
// ── Non-adjustable: show fixed credit amount in a styled card ──
/* @__PURE__ */
(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
flexDirection: "column",
mt: {
xs: 2,
md: 3
},
borderRadius: "20px",
backdropFilter: "blur(12px)",
bgcolor: theme => theme.palette.mode === "dark" ? "rgba(59,130,246,0.08)" : "rgba(59,130,246,0.04)",
border: "1px solid",
borderColor: theme => theme.palette.mode === "dark" ? "rgba(59,130,246,0.18)" : "rgba(59,130,246,0.10)",
boxShadow: theme => theme.palette.mode === "dark" ? "0 8px 32px rgba(59,130,246,0.06)" : "0 8px 32px rgba(59,130,246,0.04)"
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
p: {
xs: 2.5,
md: 3.5
}
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 13,
md: 14
},
fontWeight: 600,
color: "text.secondary",
mb: 1
},
children: t("payment.checkout.creditTopup.willReceive")
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
sx: {
display: "flex",
alignItems: "center",
gap: 1.5
},
children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 32,
md: 48
},
fontWeight: 800,
lineHeight: 1,
letterSpacing: "-0.03em",
color: "primary.main"
},
children: (0, _util2.formatCreditForCheckout)(actualCreditsFormatted, currencySymbol, locale)
})
})]
}), validityText && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
display: "flex",
alignItems: "center",
gap: 0.75,
px: {
xs: 2.5,
md: 3.5
},
py: {
xs: 1.5,
md: 2
},
borderTop: "1px solid",
borderColor: theme => theme.palette.mode === "dark" ? "rgba(59,130,246,0.15)" : "rgba(59,130,246,0.08)"
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_AccessTimeOutlined.default, {
sx: {
fontSize: 14,
color: "grey.500"
}
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: {
xs: 12,
md: 13
},
fontWeight: 500,
color: "grey.500"
},
children: validityText
})]
})]
})]
}), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, {
sx: {
flexShrink: 0
},
children: [rate.hasDynamicPricing && rate.status === "unavailable" && !isStripe && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
direction: "row",
alignItems: "center",
spacing: 0.75,
sx: {
mb: 2
},
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
sx: {
fontSize: 13,
color: "text.secondary",
fontWeight: 500
},
children: t("payment.dynamicPricing.unavailable.title")
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, {
component: "span",
onClick: rate.refresh,
sx: {
fontSize: 13,
color: "primary.main",
fontWeight: 600,
cursor: "pointer",
"&:hover": {
textDecoration: "underline"
}
},
children: t("payment.dynamicPricing.unavailable.retry")
})]
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_exchangeRateFooter.default, {
hasDynamicPricing: rate.hasDynamicPricing,
rate: {
value: rate.value,
display: rate.display,
provider: rate.provider,
providerDisplay: rate.providerDisplay,
fetchedAt: rate.fetchedAt,
status: rate.status
},
slippage: {
percent: slippage.percent,
set: slippage.set
},
currencySymbol: currency?.symbol || "",
isSubscription: ["subscription", "setup"].includes(session?.mode || "payment")
})]
})]
});
}