frontPanel/src/pages/Tariffs/Tariffs.tsx
Nastya 84f1011de0
Some checks are pending
Deploy / CreateImage (push) Waiting to run
Deploy / DeployService (push) Blocked by required conditions
чистка логов
2025-08-07 01:24:00 +03:00

377 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 { 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>
);