UNPKG

@blocklet/payment-react

Version:

Reusable react components for payment kit v2

171 lines (170 loc) 6.38 kB
import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import SettingsIcon from "@mui/icons-material/Settings"; import { Box, Collapse, Dialog, DialogTitle, DialogContent, Fade, IconButton, Stack, Tooltip, Typography } from "@mui/material"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useLocaleContext } from "@arcblock/ux/lib/Locale/context"; import SlippageConfig from "./slippage-config.js"; export default function QuoteDetailsPanel({ rateLine, rows, isSubscription = false, slippageValue = 0.5, onSlippageChange = void 0, slippageConfig = void 0, exchangeRate = null, baseCurrency = "USD", disabled = false }) { const { t } = useLocaleContext(); const [open, setOpen] = useState(false); const [showContent, setShowContent] = useState(true); const [dialogOpen, setDialogOpen] = useState(false); const [pendingConfig, setPendingConfig] = useState(null); const [submitting, setSubmitting] = useState(false); const hasRows = rows.length > 0; const handleOpenDialog = useCallback(() => { setPendingConfig(slippageConfig || { mode: "percent", percent: slippageValue }); setDialogOpen(true); }, [slippageValue, slippageConfig]); 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 || !onSlippageChange) return; setSubmitting(true); try { const configToSave = { ...pendingConfig, ...baseCurrency ? { base_currency: baseCurrency } : {} }; await onSlippageChange(configToSave); setDialogOpen(false); setPendingConfig(null); } catch (err) { console.error("Failed to update slippage", err); } finally { setSubmitting(false); } }; useEffect(() => { if (!rateLine) return void 0; setShowContent(false); const timer = setTimeout(() => { setShowContent(true); }, 150); return () => clearTimeout(timer); }, [rateLine]); const renderedRows = useMemo( () => rows.map((row) => { const isSlippageRow = row.isSlippage && isSubscription && onSlippageChange; return /* @__PURE__ */ jsxs( Stack, { direction: "row", sx: { alignItems: "center", justifyContent: "space-between", gap: 2 }, children: [ /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, alignItems: "center", children: [ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "0.75rem", color: "text.secondary" }, children: row.label }), row.tooltip && /* @__PURE__ */ jsx(Tooltip, { title: row.tooltip, placement: "top", children: /* @__PURE__ */ jsx(InfoOutlinedIcon, { sx: { fontSize: "0.75rem", color: "text.lighter" } }) }) ] }), /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "0.75rem", color: "text.primary" }, children: row.value }), isSlippageRow && !disabled && /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: handleOpenDialog, sx: { p: 0.25 }, children: /* @__PURE__ */ jsx(SettingsIcon, { sx: { fontSize: "0.875rem", color: "text.secondary" } }) }) ] }) ] }, row.label ); }), [rows, isSubscription, onSlippageChange, disabled, handleOpenDialog] ); const showSlippageOnly = !rateLine && isSubscription && onSlippageChange && rows.some((r) => r.isSlippage); if (!rateLine && !showSlippageOnly) { return null; } return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs(Box, { sx: { width: "100%", mt: 0.5 }, children: [ /* @__PURE__ */ jsxs( Stack, { direction: "row", sx: { alignItems: "center", justifyContent: "space-between", gap: 1 }, children: [ rateLine ? /* @__PURE__ */ jsx(Fade, { in: showContent, timeout: 300, children: /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "0.7875rem", color: "text.lighter" }, children: rateLine }) }) : /* @__PURE__ */ jsx(Box, {}), hasRows && /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: () => setOpen((prev) => !prev), "aria-label": open ? "collapse" : "expand", children: /* @__PURE__ */ jsx( ExpandMoreIcon, { sx: { fontSize: "1rem", transition: "transform 0.2s ease", transform: open ? "rotate(180deg)" : "rotate(0deg)" } } ) }) ] } ), hasRows && /* @__PURE__ */ jsx(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsx(Fade, { in: showContent, timeout: 300, children: /* @__PURE__ */ jsx( Stack, { sx: { mt: 1, p: 1.25, borderRadius: 1, border: "1px solid", borderColor: "divider", bgcolor: "action.hover" }, spacing: 1, children: renderedRows } ) }) }) ] }), /* @__PURE__ */ jsxs(Dialog, { open: dialogOpen, onClose: handleCloseDialog, maxWidth: "sm", fullWidth: true, children: [ /* @__PURE__ */ jsx(DialogTitle, { children: t("payment.checkout.quote.slippage.title") }), /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsx( SlippageConfig, { value: pendingConfig?.percent ?? slippageValue, onChange: handleSlippageChange, config: pendingConfig || slippageConfig, onConfigChange: handleConfigChange, exchangeRate, baseCurrency, disabled: disabled || submitting, sx: { mt: 1 }, onCancel: handleCloseDialog, onSave: handleSubmit } ) }) ] }) ] }); }