2024-04-12 14:42:25 +00:00
|
|
|
|
import bigDecimal from "js-big-decimal";
|
2024-03-22 11:47:37 +00:00
|
|
|
|
import SectionWrapper from "@components/SectionWrapper";
|
|
|
|
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
2023-10-06 11:56:50 +00:00
|
|
|
|
import {
|
2024-04-08 12:56:14 +00:00
|
|
|
|
Box,
|
|
|
|
|
Button,
|
|
|
|
|
IconButton,
|
|
|
|
|
Typography,
|
|
|
|
|
useMediaQuery,
|
|
|
|
|
useTheme,
|
2024-02-14 14:22:12 +00:00
|
|
|
|
} from "@mui/material";
|
2024-03-22 11:47:37 +00:00
|
|
|
|
import { activatePromocode } from "@root/api/promocode";
|
|
|
|
|
import { sendPayment, sendRSPayment } from "@root/api/wallet";
|
2024-03-16 21:41:48 +00:00
|
|
|
|
import b2bLogo from "@root/assets/bank-logo/b2b.png";
|
2024-02-14 14:22:12 +00:00
|
|
|
|
import tinkoffLogo from "@root/assets/bank-logo/logo-tinkoff.png";
|
|
|
|
|
import rsPayLogo from "@root/assets/bank-logo/rs-pay.png";
|
2024-03-22 11:47:37 +00:00
|
|
|
|
import sberpayLogo from "@root/assets/bank-logo/sberpay.png";
|
|
|
|
|
import spbLogo from "@root/assets/bank-logo/spb.png";
|
|
|
|
|
import umoneyLogo from "@root/assets/bank-logo/umaney.png";
|
2024-03-29 20:31:06 +00:00
|
|
|
|
import bankCardLogo from "@root/assets/bank-logo/bankcard.png";
|
2024-02-14 14:22:12 +00:00
|
|
|
|
import InputTextfield from "@root/components/InputTextfield";
|
2024-03-22 11:47:37 +00:00
|
|
|
|
import { VerificationStatus } from "@root/model/account";
|
|
|
|
|
import { useUserStore } from "@root/stores/user";
|
2024-02-14 14:22:12 +00:00
|
|
|
|
import { currencyFormatter } from "@root/utils/currencyFormatter";
|
|
|
|
|
import { useHistoryTracker } from "@root/utils/hooks/useHistoryTracker";
|
2024-03-22 11:47:37 +00:00
|
|
|
|
import { cardShadow } from "@root/utils/theme";
|
|
|
|
|
import { enqueueSnackbar } from "notistack";
|
|
|
|
|
import { useLayoutEffect, useState } from "react";
|
|
|
|
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
|
|
|
import CollapsiblePromocodeField from "./CollapsiblePromocodeField";
|
|
|
|
|
import PaymentMethodCard from "./PaymentMethodCard";
|
2024-02-15 18:09:44 +00:00
|
|
|
|
import { SorryModal } from "./SorryModal";
|
2024-03-22 11:47:37 +00:00
|
|
|
|
import { WarnModal } from "./WarnModal";
|
2024-03-26 14:49:35 +00:00
|
|
|
|
import { mutate } from "swr";
|
2024-02-14 14:22:12 +00:00
|
|
|
|
|
|
|
|
|
type PaymentMethod = {
|
2024-04-08 12:56:14 +00:00
|
|
|
|
label: string;
|
|
|
|
|
name: string;
|
|
|
|
|
image: string;
|
|
|
|
|
unpopular?: boolean;
|
2024-02-14 14:22:12 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const paymentMethods: PaymentMethod[] = [
|
2024-04-08 12:56:14 +00:00
|
|
|
|
{ label: "Банковская карта", name: "bankCard", image: bankCardLogo },
|
2024-05-03 23:05:31 +00:00
|
|
|
|
// { label: "Тинькофф", name: "tinkoffBank", image: tinkoffLogo },
|
|
|
|
|
// { label: "СБП", name: "sbp", image: spbLogo },
|
2024-04-08 12:56:14 +00:00
|
|
|
|
{ label: "SberPay", name: "sberbank", image: sberpayLogo },
|
2024-05-03 23:05:31 +00:00
|
|
|
|
// { label: "B2B Сбербанк", name: "b2bSberbank", image: b2bLogo },
|
2024-04-08 12:56:14 +00:00
|
|
|
|
{ label: "ЮMoney", name: "yoomoney", image: umoneyLogo },
|
2024-02-14 14:22:12 +00:00
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
type PaymentMethodType = (typeof paymentMethods)[number]["name"];
|
2022-11-22 14:43:59 +00:00
|
|
|
|
|
|
|
|
|
export default function Payment() {
|
2024-04-08 12:56:14 +00:00
|
|
|
|
const theme = useTheme();
|
|
|
|
|
const upMd = useMediaQuery(theme.breakpoints.up("md"));
|
|
|
|
|
const upSm = useMediaQuery(theme.breakpoints.up("sm"));
|
|
|
|
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
|
|
|
|
const [promocodeField, setPromocodeField] = useState<string>("");
|
|
|
|
|
const [selectedPaymentMethod, setSelectedPaymentMethod] =
|
|
|
|
|
useState<PaymentMethodType | null>("");
|
|
|
|
|
const [warnModalOpen, setWarnModalOpen] = useState<boolean>(false);
|
|
|
|
|
const [sorryModalOpen, setSorryModalOpen] = useState<boolean>(false);
|
|
|
|
|
const [paymentValueField, setPaymentValueField] = useState<string>("0");
|
|
|
|
|
const [paymentLink, setPaymentLink] = useState<string>("");
|
|
|
|
|
const [fromSquiz, setIsFromSquiz] = useState<boolean>(false);
|
|
|
|
|
const location = useLocation();
|
2024-05-07 20:15:58 +00:00
|
|
|
|
console.log("location", location)
|
2024-04-08 12:56:14 +00:00
|
|
|
|
const verificationStatus = useUserStore((state) => state.verificationStatus);
|
|
|
|
|
const userId = useUserStore((state) => state.userId);
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const handleCustomBackNavigation = useHistoryTracker();
|
2024-03-21 16:34:44 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
const notEnoughMoneyAmount =
|
|
|
|
|
(location.state?.notEnoughMoneyAmount as number) ?? 0;
|
2024-03-21 16:34:44 +00:00
|
|
|
|
|
2024-04-12 14:42:25 +00:00
|
|
|
|
const paymentValue = parseFloat(
|
|
|
|
|
bigDecimal.multiply(parseFloat(paymentValueField), 100)
|
|
|
|
|
);
|
2024-03-21 16:34:44 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
useLayoutEffect(() => {
|
|
|
|
|
setPaymentValueField((notEnoughMoneyAmount / 100).toString());
|
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
|
|
|
const fromSquiz = params.get("action");
|
|
|
|
|
if (fromSquiz === "squizpay") {
|
|
|
|
|
setIsFromSquiz(true);
|
|
|
|
|
setPaymentValueField((Number(params.get("dif") || "0") / 100).toString());
|
|
|
|
|
}
|
2024-05-07 20:15:58 +00:00
|
|
|
|
navigate(`/payment`, {
|
|
|
|
|
replace: true,
|
|
|
|
|
});
|
2024-04-08 12:56:14 +00:00
|
|
|
|
}, []);
|
2024-03-21 16:34:44 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
async function handleChoosePaymentClick() {
|
|
|
|
|
if (!selectedPaymentMethod) {
|
|
|
|
|
enqueueSnackbar("Введите метод оплаты");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-02-14 14:22:12 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
if (Number(paymentValueField) === 0) {
|
|
|
|
|
enqueueSnackbar("Введите сумму");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-03-16 21:41:48 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
if (selectedPaymentMethod !== "rspay") {
|
|
|
|
|
const [sendPaymentResponse, sendPaymentError] = await sendPayment({
|
|
|
|
|
userId: userId ?? "",
|
|
|
|
|
fromSquiz,
|
|
|
|
|
body: {
|
|
|
|
|
type: selectedPaymentMethod,
|
2024-04-12 14:42:25 +00:00
|
|
|
|
amount: Number(
|
|
|
|
|
bigDecimal.floor(
|
|
|
|
|
bigDecimal.multiply(Number(paymentValueField), 100)
|
|
|
|
|
)
|
|
|
|
|
),
|
2024-04-08 12:56:14 +00:00
|
|
|
|
},
|
|
|
|
|
paymentPurpose: notEnoughMoneyAmount ? "paycart" : "replenishwallet",
|
|
|
|
|
});
|
2024-02-14 14:22:12 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
if (sendPaymentError) {
|
|
|
|
|
return enqueueSnackbar(sendPaymentError);
|
|
|
|
|
}
|
2024-02-14 14:22:12 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
if (sendPaymentResponse) {
|
|
|
|
|
setPaymentLink(sendPaymentResponse.link);
|
|
|
|
|
}
|
2024-04-02 13:35:55 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
if (verificationStatus !== VerificationStatus.VERIFICATED) {
|
|
|
|
|
setWarnModalOpen(true);
|
2024-03-17 09:22:49 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-03-17 09:22:49 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
if (Number(paymentValueField) < 900) {
|
|
|
|
|
enqueueSnackbar("Минимальная сумма 900р");
|
2024-03-17 09:22:49 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2024-03-17 09:22:49 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
const sendRSPaymentError = await sendRSPayment(Number(paymentValueField));
|
2024-03-17 09:22:49 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
if (sendRSPaymentError) {
|
|
|
|
|
return enqueueSnackbar(sendRSPaymentError);
|
|
|
|
|
}
|
2024-03-17 09:22:49 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
enqueueSnackbar(
|
|
|
|
|
"Cпасибо за заявку, в течении 24 часов вам будет выставлен счёт для оплаты услуг."
|
|
|
|
|
);
|
2024-03-17 09:22:49 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
navigate("/settings");
|
2024-02-14 14:22:12 +00:00
|
|
|
|
}
|
2024-04-08 12:56:14 +00:00
|
|
|
|
}
|
2024-02-14 14:22:12 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
function handleApplyPromocode() {
|
|
|
|
|
if (!promocodeField) return;
|
2024-02-14 14:22:12 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
activatePromocode(promocodeField)
|
|
|
|
|
.then((response) => {
|
|
|
|
|
enqueueSnackbar(response);
|
|
|
|
|
mutate("discounts");
|
|
|
|
|
})
|
2024-05-04 01:12:45 +00:00
|
|
|
|
.catch((error) => {if (error.message !== "" && typeof(error.message)==="string")
|
|
|
|
|
enqueueSnackbar(error.message);
|
2024-04-08 12:56:14 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
2024-02-14 14:22:12 +00:00
|
|
|
|
|
2024-04-08 12:56:14 +00:00
|
|
|
|
return (
|
|
|
|
|
<SectionWrapper
|
|
|
|
|
maxWidth="lg"
|
|
|
|
|
sx={{
|
|
|
|
|
mt: "25px",
|
|
|
|
|
mb: "70px",
|
|
|
|
|
px: isTablet ? (upMd ? "40px" : "18px") : "20px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
mt: "20px",
|
|
|
|
|
mb: "40px",
|
|
|
|
|
display: "flex",
|
|
|
|
|
gap: "10px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<IconButton
|
|
|
|
|
onClick={handleCustomBackNavigation}
|
|
|
|
|
sx={{ p: 0, height: "28px", width: "28px", color: "black" }}
|
|
|
|
|
>
|
|
|
|
|
<ArrowBackIcon />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<Typography variant="h4">Способ оплаты</Typography>
|
|
|
|
|
</Box>
|
|
|
|
|
{!upMd && (
|
|
|
|
|
<Typography variant="body2" mb="30px">
|
|
|
|
|
Выберите способ оплаты
|
|
|
|
|
</Typography>
|
|
|
|
|
)}
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
backgroundColor: upMd ? "white" : undefined,
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: upMd ? "row" : "column",
|
|
|
|
|
borderRadius: "12px",
|
|
|
|
|
boxShadow: upMd ? cardShadow : undefined,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
width: upMd ? "68.5%" : undefined,
|
|
|
|
|
p: upMd ? "20px" : undefined,
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
alignItems: "start",
|
|
|
|
|
gap: "40px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Box
|
2024-02-14 14:22:12 +00:00
|
|
|
|
sx={{
|
2024-04-08 12:56:14 +00:00
|
|
|
|
width: "100%",
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: upSm ? "row" : "column",
|
|
|
|
|
flexWrap: "wrap",
|
|
|
|
|
gap: upMd ? "14px" : "20px",
|
|
|
|
|
alignContent: "start",
|
2024-02-14 14:22:12 +00:00
|
|
|
|
}}
|
2024-04-08 12:56:14 +00:00
|
|
|
|
>
|
|
|
|
|
{paymentMethods.map(({ name, label, image, unpopular = false }) => (
|
|
|
|
|
<PaymentMethodCard
|
|
|
|
|
isSelected={selectedPaymentMethod === name}
|
|
|
|
|
key={name}
|
|
|
|
|
label={label}
|
|
|
|
|
image={image}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setSelectedPaymentMethod(name);
|
|
|
|
|
setPaymentLink("");
|
|
|
|
|
}}
|
|
|
|
|
unpopular={false}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
<PaymentMethodCard
|
|
|
|
|
isSelected={selectedPaymentMethod === "rspay"}
|
|
|
|
|
label={"Расчётный счёт"}
|
|
|
|
|
image={rsPayLogo}
|
|
|
|
|
onClick={async () => {
|
|
|
|
|
setSelectedPaymentMethod("rspay");
|
|
|
|
|
setPaymentLink("");
|
|
|
|
|
}}
|
|
|
|
|
unpopular={false}
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
<CollapsiblePromocodeField
|
|
|
|
|
fieldValue={promocodeField}
|
|
|
|
|
onFieldChange={setPromocodeField}
|
|
|
|
|
onPromocodeApply={handleApplyPromocode}
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
justifyContent: "space-between",
|
|
|
|
|
alignItems: "start",
|
|
|
|
|
color: theme.palette.gray.dark,
|
|
|
|
|
width: upMd ? "31.5%" : undefined,
|
|
|
|
|
p: upMd ? "20px" : undefined,
|
|
|
|
|
pl: upMd ? "33px" : undefined,
|
|
|
|
|
mt: upMd ? undefined : "30px",
|
|
|
|
|
borderLeft: upMd
|
|
|
|
|
? `1px solid ${theme.palette.gray.main}`
|
|
|
|
|
: undefined,
|
|
|
|
|
}}
|
2024-03-21 16:34:44 +00:00
|
|
|
|
>
|
2024-04-08 12:56:14 +00:00
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
maxWidth: "85%",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{upMd && <Typography mb="56px">Выберите способ оплаты</Typography>}
|
|
|
|
|
<Typography mb="20px">К оплате</Typography>
|
|
|
|
|
{paymentLink ? (
|
|
|
|
|
<Typography
|
2024-02-14 14:22:12 +00:00
|
|
|
|
sx={{
|
2024-04-08 12:56:14 +00:00
|
|
|
|
fontWeight: 500,
|
|
|
|
|
fontSize: "20px",
|
|
|
|
|
lineHeight: "48px",
|
|
|
|
|
mb: "28px",
|
2024-02-14 14:22:12 +00:00
|
|
|
|
}}
|
2024-04-08 12:56:14 +00:00
|
|
|
|
>
|
2024-04-12 10:53:31 +00:00
|
|
|
|
{currencyFormatter.format(
|
2024-04-12 14:42:25 +00:00
|
|
|
|
Number(bigDecimal.divide(bigDecimal.floor(paymentValue), 100))
|
2024-04-12 10:53:31 +00:00
|
|
|
|
)}
|
2024-04-08 12:56:14 +00:00
|
|
|
|
</Typography>
|
|
|
|
|
) : (
|
|
|
|
|
<InputTextfield
|
|
|
|
|
TextfieldProps={{
|
|
|
|
|
placeholder: "К оплате",
|
|
|
|
|
value: paymentValueField,
|
|
|
|
|
type: "number",
|
|
|
|
|
}}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
const value = parseFloat(
|
|
|
|
|
e.target.value.replace(/^0+(?=\d\.)/, "")
|
|
|
|
|
);
|
|
|
|
|
setPaymentValueField(isNaN(value) ? "" : value.toString());
|
2024-03-21 16:34:44 +00:00
|
|
|
|
}}
|
2024-04-08 12:56:14 +00:00
|
|
|
|
id="payment-amount"
|
|
|
|
|
gap={upMd ? "16px" : "10px"}
|
|
|
|
|
color={"#F2F3F7"}
|
|
|
|
|
FormInputSx={{ mb: "28px" }}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
|
|
|
|
{paymentLink ? (
|
|
|
|
|
<Button
|
|
|
|
|
variant="pena-outlined-light"
|
|
|
|
|
component="a"
|
|
|
|
|
href={paymentLink}
|
|
|
|
|
sx={{
|
|
|
|
|
mt: "auto",
|
|
|
|
|
color: "black",
|
|
|
|
|
border: `1px solid ${theme.palette.purple.main}`,
|
|
|
|
|
"&:hover": {
|
|
|
|
|
backgroundColor: theme.palette.purple.dark,
|
|
|
|
|
border: `1px solid ${theme.palette.purple.dark}`,
|
|
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Оплатить
|
|
|
|
|
</Button>
|
|
|
|
|
) : (
|
|
|
|
|
<Button
|
|
|
|
|
variant="pena-outlined-light"
|
|
|
|
|
disabled={!isFinite(paymentValue)}
|
|
|
|
|
onClick={handleChoosePaymentClick}
|
|
|
|
|
sx={{
|
|
|
|
|
mt: "auto",
|
|
|
|
|
color: "black",
|
|
|
|
|
border: `1px solid ${theme.palette.purple.main}`,
|
|
|
|
|
"&:hover": {
|
|
|
|
|
color: "white",
|
|
|
|
|
},
|
|
|
|
|
"&:active": {
|
|
|
|
|
color: "white",
|
|
|
|
|
},
|
|
|
|
|
}}
|
2024-02-14 14:22:12 +00:00
|
|
|
|
>
|
2024-04-08 12:56:14 +00:00
|
|
|
|
Выбрать
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
<WarnModal open={warnModalOpen} setOpen={setWarnModalOpen} />
|
|
|
|
|
<SorryModal open={sorryModalOpen} setOpen={setSorryModalOpen} />
|
|
|
|
|
</SectionWrapper>
|
|
|
|
|
);
|
2023-03-19 12:30:40 +00:00
|
|
|
|
}
|