@blocklet/payment-react
Version:
Reusable react components for payment kit v2
282 lines (281 loc) • 9.6 kB
JavaScript
;
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
})
})]
})]
});
}