front-hub/src/pages/Payment/Payment.tsx
2024-05-07 23:15:58 +03:00

360 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import bigDecimal from "js-big-decimal";
import SectionWrapper from "@components/SectionWrapper";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import {
Box,
Button,
IconButton,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import { activatePromocode } from "@root/api/promocode";
import { sendPayment, sendRSPayment } from "@root/api/wallet";
import b2bLogo from "@root/assets/bank-logo/b2b.png";
import tinkoffLogo from "@root/assets/bank-logo/logo-tinkoff.png";
import rsPayLogo from "@root/assets/bank-logo/rs-pay.png";
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";
import bankCardLogo from "@root/assets/bank-logo/bankcard.png";
import InputTextfield from "@root/components/InputTextfield";
import { VerificationStatus } from "@root/model/account";
import { useUserStore } from "@root/stores/user";
import { currencyFormatter } from "@root/utils/currencyFormatter";
import { useHistoryTracker } from "@root/utils/hooks/useHistoryTracker";
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";
import { SorryModal } from "./SorryModal";
import { WarnModal } from "./WarnModal";
import { mutate } from "swr";
type PaymentMethod = {
label: string;
name: string;
image: string;
unpopular?: boolean;
};
const paymentMethods: PaymentMethod[] = [
{ label: "Банковская карта", name: "bankCard", image: bankCardLogo },
// { label: "Тинькофф", name: "tinkoffBank", image: tinkoffLogo },
// { label: "СБП", name: "sbp", image: spbLogo },
{ label: "SberPay", name: "sberbank", image: sberpayLogo },
// { label: "B2B Сбербанк", name: "b2bSberbank", image: b2bLogo },
{ label: "ЮMoney", name: "yoomoney", image: umoneyLogo },
];
type PaymentMethodType = (typeof paymentMethods)[number]["name"];
export default function Payment() {
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();
console.log("location", location)
const verificationStatus = useUserStore((state) => state.verificationStatus);
const userId = useUserStore((state) => state.userId);
const navigate = useNavigate();
const handleCustomBackNavigation = useHistoryTracker();
const notEnoughMoneyAmount =
(location.state?.notEnoughMoneyAmount as number) ?? 0;
const paymentValue = parseFloat(
bigDecimal.multiply(parseFloat(paymentValueField), 100)
);
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());
}
navigate(`/payment`, {
replace: true,
});
}, []);
async function handleChoosePaymentClick() {
if (!selectedPaymentMethod) {
enqueueSnackbar("Введите метод оплаты");
return;
}
if (Number(paymentValueField) === 0) {
enqueueSnackbar("Введите сумму");
return;
}
if (selectedPaymentMethod !== "rspay") {
const [sendPaymentResponse, sendPaymentError] = await sendPayment({
userId: userId ?? "",
fromSquiz,
body: {
type: selectedPaymentMethod,
amount: Number(
bigDecimal.floor(
bigDecimal.multiply(Number(paymentValueField), 100)
)
),
},
paymentPurpose: notEnoughMoneyAmount ? "paycart" : "replenishwallet",
});
if (sendPaymentError) {
return enqueueSnackbar(sendPaymentError);
}
if (sendPaymentResponse) {
setPaymentLink(sendPaymentResponse.link);
}
return;
} else {
if (verificationStatus !== VerificationStatus.VERIFICATED) {
setWarnModalOpen(true);
return;
}
if (Number(paymentValueField) < 900) {
enqueueSnackbar("Минимальная сумма 900р");
return;
}
const sendRSPaymentError = await sendRSPayment(Number(paymentValueField));
if (sendRSPaymentError) {
return enqueueSnackbar(sendRSPaymentError);
}
enqueueSnackbar(
"Cпасибо за заявку, в течении 24 часов вам будет выставлен счёт для оплаты услуг."
);
navigate("/settings");
}
}
function handleApplyPromocode() {
if (!promocodeField) return;
activatePromocode(promocodeField)
.then((response) => {
enqueueSnackbar(response);
mutate("discounts");
})
.catch((error) => {if (error.message !== "" && typeof(error.message)==="string")
enqueueSnackbar(error.message);
});
}
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
sx={{
width: "100%",
display: "flex",
flexDirection: upSm ? "row" : "column",
flexWrap: "wrap",
gap: upMd ? "14px" : "20px",
alignContent: "start",
}}
>
{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,
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
maxWidth: "85%",
}}
>
{upMd && <Typography mb="56px">Выберите способ оплаты</Typography>}
<Typography mb="20px">К оплате</Typography>
{paymentLink ? (
<Typography
sx={{
fontWeight: 500,
fontSize: "20px",
lineHeight: "48px",
mb: "28px",
}}
>
{currencyFormatter.format(
Number(bigDecimal.divide(bigDecimal.floor(paymentValue), 100))
)}
</Typography>
) : (
<InputTextfield
TextfieldProps={{
placeholder: "К оплате",
value: paymentValueField,
type: "number",
}}
onChange={(e) => {
const value = parseFloat(
e.target.value.replace(/^0+(?=\d\.)/, "")
);
setPaymentValueField(isNaN(value) ? "" : value.toString());
}}
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",
},
}}
>
Выбрать
</Button>
)}
</Box>
</Box>
<WarnModal open={warnModalOpen} setOpen={setWarnModalOpen} />
<SorryModal open={sorryModalOpen} setOpen={setSorryModalOpen} />
</SectionWrapper>
);
}