UNPKG

@blocklet/payment-react

Version:

Reusable react components for payment kit v2

282 lines (281 loc) 9.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); module.exports = ExchangeRateFooter; var _jsxRuntime = require("react/jsx-runtime"); var _react = require("react"); var _Tune = _interopRequireDefault(require("@mui/icons-material/Tune")); var _material = require("@mui/material"); var _context = require("@arcblock/ux/lib/Locale/context"); var _slippageConfig = _interopRequireDefault(require("../../../components/slippage-config")); var _format = require("../../utils/format"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const ping = (0, _material.keyframes)` 75%, 100% { transform: scale(2); opacity: 0; } `; function formatDateTime(ts) { if (!ts) return "\u2014"; const d = new Date(ts); const pad = n => String(n).padStart(2, "0"); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; } function ExchangeRateFooter({ hasDynamicPricing, rate, slippage, currencySymbol, isSubscription }) { const { t } = (0, _context.useLocaleContext)(); const [dialogOpen, setDialogOpen] = (0, _react.useState)(false); const [pendingConfig, setPendingConfig] = (0, _react.useState)(null); const [submitting, setSubmitting] = (0, _react.useState)(false); const [localSlippage, setLocalSlippage] = (0, _react.useState)(slippage?.percent ?? 0.5); (0, _react.useEffect)(() => { setLocalSlippage(slippage?.percent ?? 0.5); }, [slippage?.percent]); if (!hasDynamicPricing || !rate.value || rate.status === "unavailable") return null; const rateDisplay = rate.display || `$${Number(rate.value).toFixed(2)}`; const showSlippage = isSubscription && typeof slippage?.set === "function"; const handleOpenDialog = () => { setPendingConfig({ mode: "percent", percent: localSlippage }); setDialogOpen(true); }; const handleCloseDialog = () => { setDialogOpen(false); setPendingConfig(null); }; const handleSlippageChange = value => { setPendingConfig(prev => prev ? { ...prev, percent: value } : { mode: "percent", percent: value }); }; const handleConfigChange = config => { setPendingConfig(config); }; const handleSubmit = async () => { if (!pendingConfig || !slippage?.set) return; setSubmitting(true); try { setLocalSlippage(pendingConfig.percent); await slippage.set({ ...pendingConfig, base_currency: "USD" }); setDialogOpen(false); setPendingConfig(null); } catch (err) { setLocalSlippage(slippage?.percent ?? 0.5); console.error("Failed to update slippage", err); } finally { setSubmitting(false); } }; const labelSx = { fontSize: 11, fontWeight: 700, color: "primary.main", letterSpacing: "0.02em" }; const providerName = rate.providerDisplay || rate.provider || "\u2014"; const updatedAt = formatDateTime(rate.fetchedAt); const fullRate = `$${rate.value}`; const tooltipSx = _format.whiteTooltipSx; const rowSx = { fontSize: 12, color: "text.secondary", lineHeight: 1.4 }; const valSx = { fontSize: 12, fontWeight: 600, color: "text.primary", lineHeight: 1.4 }; const tooltipContent = /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, { spacing: 0.75, children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, { sx: { fontSize: 13, fontWeight: 700, color: "text.primary", mb: 0.25 }, children: ["1 ", currencySymbol, " = ", fullRate] }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, { sx: { borderTop: "1px solid", borderColor: "divider", pt: 0.75 }, children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, { spacing: 0.5, children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, { direction: "row", justifyContent: "space-between", spacing: 2, children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, { sx: rowSx, children: t("payment.checkout.quote.detailProvider") }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, { sx: valSx, children: providerName })] }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, { direction: "row", justifyContent: "space-between", spacing: 2, children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, { sx: rowSx, children: t("payment.checkout.quote.detailUpdatedAt") }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Typography, { sx: valSx, children: updatedAt })] })] }) })] }); const slippageTooltip = t("payment.checkout.quote.slippage.tooltip"); return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, { sx: { width: "100%", pt: 3, pb: 1, borderTop: "1px solid", borderColor: "divider" }, children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Fade, { in: true, timeout: 300, children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, { direction: "row", sx: { alignItems: "center", justifyContent: "space-between" }, children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Tooltip, { title: tooltipContent, placement: "top", arrow: true, slotProps: { popper: { sx: tooltipSx } }, children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, { direction: "row", alignItems: "center", spacing: 1, sx: { cursor: "default" }, children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Box, { sx: { position: "relative", width: 8, height: 8, flexShrink: 0 }, children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, { sx: { position: "absolute", inset: 0, borderRadius: "50%", bgcolor: "#60a5fa", opacity: 0.6, animation: `${ping} 1s cubic-bezier(0, 0, 0.2, 1) infinite` } }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, { sx: { position: "relative", width: 8, height: 8, borderRadius: "50%", bgcolor: "primary.main" } })] }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, { sx: labelSx, children: ["1 ", currencySymbol, " \u2248 ", rateDisplay] })] }) }), showSlippage && /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Tooltip, { title: slippageTooltip, placement: "top", arrow: true, slotProps: { popper: { sx: _format.whiteTooltipSx } }, children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, { direction: "row", alignItems: "center", spacing: 0.75, onClick: handleOpenDialog, sx: { cursor: "pointer", "&:hover": { opacity: 1 }, "&:hover .tune-icon": { transform: "rotate(90deg)" }, transition: "opacity 0.2s" }, children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_Tune.default, { className: "tune-icon", sx: { fontSize: 16, color: "primary.main", transition: "transform 0.5s" } }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, { sx: labelSx, children: [t("payment.checkout.quote.detailSlippage"), " ", localSlippage, "%"] })] }) })] }) }) }), /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Dialog, { open: dialogOpen, onClose: handleCloseDialog, maxWidth: "sm", fullWidth: true, children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.DialogTitle, { children: t("payment.checkout.quote.slippage.title") }), /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.DialogContent, { children: /* @__PURE__ */(0, _jsxRuntime.jsx)(_slippageConfig.default, { value: pendingConfig?.percent ?? localSlippage, onChange: handleSlippageChange, config: pendingConfig || { mode: "percent", percent: localSlippage }, onConfigChange: handleConfigChange, exchangeRate: rate.value ? String(rate.value) : null, baseCurrency: "USD", disabled: submitting, sx: { mt: 1 }, onCancel: handleCloseDialog, onSave: handleSubmit }) })] })] }); }