377 lines
12 KiB
TypeScript
377 lines
12 KiB
TypeScript
import { activatePromocode } from "@api/promocode";
|
||
import { useToken } from "@frontend/kitui";
|
||
import {
|
||
Box,
|
||
Typography,
|
||
useMediaQuery,
|
||
useTheme,
|
||
} from "@mui/material";
|
||
import { useUserStore } from "@root/user";
|
||
import { useDomainDefine } from "@utils/hooks/useDomainDefine";
|
||
import { enqueueSnackbar } from "notistack";
|
||
import { useEffect, useState } from "react";
|
||
import { withErrorBoundary } from "react-error-boundary";
|
||
import { useNavigate } from "react-router-dom";
|
||
import CollapsiblePromocodeField from "./CollapsiblePromocodeField";
|
||
import { Tabs } from "./Tabs";
|
||
import { createTariffElements } from "./tariffsUtils/createTariffElements";
|
||
import { currencyFormatter } from "./tariffsUtils/currencyFormatter";
|
||
import { useWallet, setCash } from "@root/cash";
|
||
import { cartApi } from "@api/cart";
|
||
|
||
import { TariffCardDisplaySelector } from "./TariffCardDisplaySelector";
|
||
import { ModalRequestCreate } from "./ModalRequestCreate";
|
||
import { cancelCC, useCC } from "@/stores/cc";
|
||
import { NavSelect } from "./NavSelect";
|
||
import { useTariffs } from '@utils/hooks/useTariffs';
|
||
import { useDiscounts } from '@utils/hooks/useDiscounts';
|
||
import { PaymentConfirmationModal } from "./components/PaymentConfirmationModal";
|
||
import { TariffsHeader } from "./components/TariffsHeader";
|
||
import { inCart, outCart } from "./utils";
|
||
import { generateHubWalletRequestURL } from "@/utils/generateHubWalletRequest";
|
||
|
||
const StepperText: Record<string, string> = {
|
||
day: "Тарифы на время",
|
||
count: "Тарифы на объём",
|
||
dop: "Доп. услуги",
|
||
};
|
||
|
||
function TariffPage() {
|
||
const userPrivilegies = useUserStore(store => store.userAccount?.privileges);
|
||
const theme = useTheme();
|
||
const token = useToken();
|
||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||
const userId = useUserStore((state) => state.userId);
|
||
const navigate = useNavigate();
|
||
const user = useUserStore((state) => state.customerAccount);
|
||
const userWithWallet = useUserStore((state) => state.customerAccount); //c wallet
|
||
const userAccount = useUserStore((state) => state.userAccount);
|
||
// console.info("________________userWithWallet_____________USERRRRRRR")
|
||
// console.info(userWithWallet)
|
||
// console.info("________________userAccount_____________")
|
||
// console.info(userAccount)
|
||
// console.info("________________customerAccount_____________")
|
||
// console.info(user)
|
||
const { data: discounts, error: discountsError, isLoading: discountsLoading } = useDiscounts(userId);
|
||
const [isRequestCreate, setIsRequestCreate] = useState(false);
|
||
const [openModal, setOpenModal] = useState<{ id?: string; price?: number }>({});
|
||
const { cashString, cashCop, cashRub } = useWallet();
|
||
const [selectedItem, setSelectedItem] = useState<TypePages>("day");
|
||
const { isTestServer } = useDomainDefine();
|
||
const [promocodeField, setPromocodeField] = useState<string>("");
|
||
const cc = useCC(store => store.cc)
|
||
|
||
|
||
const { data: tariffs, error: tariffsError, isLoading: tariffsLoading } = useTariffs();
|
||
|
||
useEffect(() => {
|
||
if (userWithWallet && user) {
|
||
let cs = currencyFormatter.format(Number(user.wallet.cash) / 100);
|
||
let cc = Number(user.wallet.cash);
|
||
let cr = Number(user.wallet.cash) / 100;
|
||
setCash(cs, cc, cr);
|
||
}
|
||
}, [userWithWallet, user]);
|
||
|
||
useEffect(() => {
|
||
if (cc) {
|
||
setIsRequestCreate(true)
|
||
cancelCC()
|
||
}
|
||
}, [])
|
||
|
||
// Проверяем, что все данные загружены и нет ошибок
|
||
const isDataLoading = tariffsLoading || (userId && discountsLoading);
|
||
const hasErrors = tariffsError || discountsError;
|
||
|
||
// Если userId есть, но customerAccount еще не загружен, показываем загрузку
|
||
const isCustomerAccountLoading = userId && !user;
|
||
const hasAllData = user && tariffs && (userId ? discounts : true);
|
||
|
||
if (isDataLoading || isCustomerAccountLoading) {
|
||
return <LoadingPage />;
|
||
}
|
||
|
||
if (hasErrors) {
|
||
return <LoadingPage />;
|
||
}
|
||
|
||
if (!hasAllData) {
|
||
return <LoadingPage />;
|
||
}
|
||
|
||
const openModalHC = (tariffInfo: any) => setOpenModal(tariffInfo);
|
||
const tryBuy = async ({ id, price }: { id: string; price: number }) => {
|
||
openModalHC({});
|
||
//Если в корзине что-то было - выкладываем содержимое и запоминаем чо там лежало
|
||
if (user.cart.length > 0) {
|
||
outCart(user.cart);
|
||
}
|
||
//Добавляем желаемый тариф в корзину
|
||
const [_, addError] = await cartApi.add(id);
|
||
|
||
if (addError) {
|
||
//Развращаем товары в корзину
|
||
inCart();
|
||
|
||
return;
|
||
}
|
||
|
||
//Если нам хватает денежек - покупаем тариф
|
||
const [data, payError] = await cartApi.pay();
|
||
|
||
if (payError || !data) {
|
||
//если денег не хватило
|
||
if (payError?.includes("insufficient funds") || payError?.includes("Payment Required")) {
|
||
let cashDif = Number(payError.split(":")[1]);
|
||
|
||
if (!userId) {
|
||
enqueueSnackbar("Ошибка: ID пользователя не найден");
|
||
return;
|
||
}
|
||
|
||
const l = generateHubWalletRequestURL({
|
||
action: cc ? "createquizcc" : "buy",
|
||
dif: cashDif.toString(),
|
||
userid: userId,
|
||
wayback: "list",
|
||
token
|
||
});
|
||
window.location.href = l;
|
||
return;
|
||
}
|
||
|
||
//другая ошибка
|
||
enqueueSnackbar("Произошла ошибка. Попробуйте позже");
|
||
|
||
return;
|
||
}
|
||
|
||
setCash(
|
||
currencyFormatter.format(Number(data.wallet.cash) / 100),
|
||
Number(data.wallet.cash),
|
||
Number(data.wallet.cash) / 100,
|
||
);
|
||
|
||
//cc - пометка что мы хотим заказать квиз. Если хотели, то открываем модалку
|
||
if (cc) setIsRequestCreate(true)
|
||
cancelCC()//но в любом случае в конце перехотим
|
||
enqueueSnackbar("Тариф успешно приобретён");
|
||
|
||
//Развращаем товары в корзину
|
||
inCart();
|
||
};
|
||
|
||
const filteredTariffs = tariffs.filter((tariff, i) => {
|
||
return (
|
||
tariff.privileges[0].serviceKey === "squiz" &&
|
||
!tariff.isDeleted &&
|
||
!tariff.isCustom &&
|
||
tariff.privileges[0]?.type === selectedItem
|
||
);
|
||
});
|
||
|
||
|
||
const filteredBaseTariffs = filteredTariffs.filter((tariff) => {
|
||
return tariff.privileges[0].privilegeId !== "squizHideBadge";
|
||
});
|
||
|
||
async function handleApplyPromocode() {
|
||
if (!promocodeField) return;
|
||
|
||
const [greetings, error] = await activatePromocode(promocodeField);
|
||
|
||
if (error) {
|
||
enqueueSnackbar(error);
|
||
return;
|
||
}
|
||
|
||
enqueueSnackbar(greetings);
|
||
}
|
||
|
||
const startRequestCreate = () => {
|
||
setIsRequestCreate(true)
|
||
}
|
||
|
||
if (!userWithWallet) return null;
|
||
return (
|
||
<>
|
||
<TariffsHeader cashString={cashString} />
|
||
<Box
|
||
sx={{
|
||
p: "25px",
|
||
pb: 0,
|
||
}}
|
||
>
|
||
<CollapsiblePromocodeField
|
||
fieldValue={promocodeField}
|
||
onFieldChange={setPromocodeField}
|
||
onPromocodeApply={handleApplyPromocode}
|
||
/>
|
||
</Box>
|
||
{isMobile ?
|
||
<NavSelect
|
||
selectedItem={selectedItem}
|
||
setSelectedItem={setSelectedItem}
|
||
/>
|
||
:
|
||
<Tabs
|
||
names={Object.values(StepperText)}
|
||
items={Object.keys(StepperText)}
|
||
selectedItem={selectedItem}
|
||
setSelectedItem={setSelectedItem}
|
||
toDop={() => setSelectedItem("dop")}
|
||
/>
|
||
}
|
||
|
||
|
||
<Box
|
||
sx={{
|
||
justifyContent: "left",
|
||
display: selectedItem === "dop" ? "flex" : "grid",
|
||
gap: "40px",
|
||
p: "20px",
|
||
gridTemplateColumns: `repeat(auto-fit, minmax(300px, ${isTablet ? "436px" : "360px"
|
||
}))`,
|
||
flexDirection: selectedItem === "dop" ? "column" : undefined,
|
||
}}
|
||
>
|
||
{selectedItem === "day" &&
|
||
createTariffElements(
|
||
filteredBaseTariffs,
|
||
true,
|
||
user,
|
||
discounts,
|
||
openModalHC,
|
||
)}
|
||
{selectedItem === "count" &&
|
||
createTariffElements(
|
||
filteredTariffs,
|
||
true,
|
||
user,
|
||
discounts,
|
||
openModalHC,
|
||
)}
|
||
{(selectedItem === "hide" || selectedItem === "create" || selectedItem === "premium" || selectedItem === "analytics" || selectedItem === "custom")
|
||
&& (
|
||
<TariffCardDisplaySelector
|
||
selectedItem={selectedItem}
|
||
content={[
|
||
{
|
||
title: `Убрать логотип "PenaQuiz"`,
|
||
onClick: () => setSelectedItem("hide")
|
||
},
|
||
{
|
||
title: "Создать квиз на заказ",
|
||
onClick: () => setSelectedItem("create")
|
||
},
|
||
{
|
||
title: "Премиум функции",
|
||
onClick: () => setSelectedItem("premium")
|
||
},
|
||
{
|
||
title: "Расширенная аналитика",
|
||
onClick: () => setSelectedItem("analytics")
|
||
},
|
||
{
|
||
title: "Кастомные тарифы",
|
||
onClick: () => setSelectedItem("custom")
|
||
},
|
||
]}
|
||
|
||
tariffs={tariffs}
|
||
user={user}
|
||
discounts={discounts || []}
|
||
openModalHC={openModalHC}
|
||
userPrivilegies={userPrivilegies}
|
||
startRequestCreate={startRequestCreate}
|
||
/>
|
||
)}
|
||
{selectedItem === "dop" && (
|
||
<TariffCardDisplaySelector
|
||
selectedItem={selectedItem}
|
||
content={
|
||
selectedItem === "dop"
|
||
? [
|
||
{
|
||
title: `Убрать логотип "PenaQuiz"`,
|
||
onClick: () => setSelectedItem("hide")
|
||
},
|
||
{
|
||
title: "Создать квиз на заказ",
|
||
onClick: () => setSelectedItem("create")
|
||
},
|
||
]
|
||
: [
|
||
{
|
||
title: `Убрать логотип "PenaQuiz"`,
|
||
onClick: () => setSelectedItem("hide")
|
||
},
|
||
{
|
||
title: "Создать квиз на заказ",
|
||
onClick: () => setSelectedItem("create")
|
||
},
|
||
{
|
||
title: "Премиум функции",
|
||
onClick: () => setSelectedItem("premium")
|
||
},
|
||
{
|
||
title: "Расширенная аналитика",
|
||
onClick: () => setSelectedItem("analytics")
|
||
},
|
||
{
|
||
title: "Кастомные тарифы",
|
||
onClick: () => setSelectedItem("custom")
|
||
},
|
||
]
|
||
}
|
||
|
||
tariffs={tariffs}
|
||
user={user}
|
||
discounts={discounts || []}
|
||
openModalHC={openModalHC}
|
||
userPrivilegies={userPrivilegies}
|
||
startRequestCreate={startRequestCreate}
|
||
/>
|
||
)}
|
||
</Box>
|
||
<PaymentConfirmationModal
|
||
open={Object.values(openModal).length > 0}
|
||
onClose={() => setOpenModal({})}
|
||
onConfirm={() => {
|
||
if (openModal.id && openModal.price !== undefined) {
|
||
tryBuy({ id: openModal.id, price: openModal.price });
|
||
}
|
||
}}
|
||
price={openModal.price || 0}
|
||
/>
|
||
<ModalRequestCreate open={isRequestCreate} onClose={() => setIsRequestCreate(false)} />
|
||
</>
|
||
);
|
||
}
|
||
|
||
export const Tariffs = withErrorBoundary(TariffPage, {
|
||
fallback: (
|
||
<Typography mt="8px" textAlign="center">
|
||
Ошибка загрузки тарифов
|
||
</Typography>
|
||
),
|
||
onError: () => { },
|
||
});
|
||
|
||
const LoadingPage = () => (
|
||
<Box
|
||
sx={{
|
||
height: "100vh",
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
}}
|
||
>
|
||
<Typography sx={{ textAlign: "center" }}>
|
||
{"Подождите, пожалуйста, идёт загрузка"}
|
||
</Typography>
|
||
</Box>
|
||
);
|