@blocklet/payment-react
Version:
Reusable react components for payment kit v2
154 lines (153 loc) • 4.68 kB
JavaScript
import { jsx, jsxs } from "react/jsx-runtime";
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
import { TextField, Button, Alert, Box, InputAdornment } from "@mui/material";
import { Add } from "@mui/icons-material";
import { useState } from "react";
import LoadingButton from "./loading-button.js";
import api from "../libs/api.js";
import { usePaymentContext } from "../contexts/payment.js";
export default function PromotionCode({
checkoutSessionId,
initialAppliedCodes = [],
disabled = false,
className = "",
placeholder = "",
onUpdate = void 0,
currencyId
}) {
const { t } = useLocaleContext();
const [showInput, setShowInput] = useState(false);
const [code, setCode] = useState("");
const [error, setError] = useState("");
const [applying, setApplying] = useState(false);
const [appliedCodes, setAppliedCodes] = useState(initialAppliedCodes);
const { session, paymentState } = usePaymentContext();
const handleLoginCheck = () => {
if (!session.user) {
session?.login(() => {
handleApply();
});
} else {
handleApply();
}
};
const handleApply = async () => {
if (!code.trim()) return;
if (paymentState.paying || paymentState.stripePaying) {
return;
}
setApplying(true);
setError("");
try {
const response = await api.post(`/api/checkout-sessions/${checkoutSessionId}/apply-promotion`, {
promotion_code: code.trim(),
currency_id: currencyId
});
const discounts = response.data.discounts || [];
const appliedDiscount = discounts[0];
if (appliedDiscount) {
const newCode = {
id: appliedDiscount.promotion_code || appliedDiscount.coupon,
code: code.trim(),
discount_amount: appliedDiscount.discount_amount
};
setAppliedCodes([newCode]);
setCode("");
setShowInput(false);
onUpdate?.({
appliedCodes: [newCode],
discountAmount: appliedDiscount.discount_amount
});
}
} catch (err) {
const errorMessage = err.response?.data?.error || err.message;
setError(errorMessage);
} finally {
setApplying(false);
}
};
const handleKeyPress = (event) => {
if (event.key === "Enter" && !applying && code.trim()) {
handleLoginCheck();
}
};
const isPaymentInProgress = paymentState.paying || paymentState.stripePaying;
return /* @__PURE__ */ jsx(Box, { className, children: appliedCodes.length === 0 && !disabled && !isPaymentInProgress && (showInput ? /* @__PURE__ */ jsxs(
Box,
{
onBlur: () => {
if (!code.trim()) {
setShowInput(false);
}
},
children: [
/* @__PURE__ */ jsx(
TextField,
{
fullWidth: true,
value: code,
onChange: (e) => setCode(e.target.value),
onKeyPress: handleKeyPress,
placeholder: placeholder || t("payment.checkout.promotion.placeholder"),
variant: "outlined",
size: "small",
disabled: applying,
autoFocus: true,
slotProps: {
input: {
endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
LoadingButton,
{
size: "small",
onClick: handleLoginCheck,
loading: applying,
disabled: !code.trim(),
variant: "text",
sx: {
color: "primary.main",
fontSize: "small"
},
children: t("payment.checkout.promotion.apply")
}
) })
}
},
sx: {
"& .MuiOutlinedInput-root": {
pr: 1
}
}
}
),
error && /* @__PURE__ */ jsx(
Alert,
{
severity: "error",
sx: {
my: 1
},
children: error
}
)
]
}
) : /* @__PURE__ */ jsx(
Button,
{
onClick: () => setShowInput(true),
startIcon: /* @__PURE__ */ jsx(Add, { fontSize: "small" }),
variant: "text",
sx: {
fontWeight: "normal",
textTransform: "none",
justifyContent: "flex-start",
p: 0,
"&:hover": {
backgroundColor: "transparent",
textDecoration: "underline"
}
},
children: t("payment.checkout.promotion.add_code")
}
)) });
}