новая система покупок
Some checks failed
Deploy / CreateImage (push) Failing after 42s
Deploy / DeployService (push) Has been skipped

This commit is contained in:
Nastya 2025-07-09 10:57:33 +03:00
parent b0b21c74c0
commit 15cf5cd21f
33 changed files with 282 additions and 406 deletions

@ -5,7 +5,7 @@ import { clearUserData } from "@root/stores/user";
import { clearCustomTariffs } from "@root/stores/customTariffs";
import { clearTickets } from "@root/stores/tickets";
import { redirect } from "react-router-dom";
import { setNotEnoughMoneyAmount } from "@stores/notEnoughMoneyAmount";
import { setNotEnoughMoneyAmount } from "@stores/allTypesOfPurchases";
interface MakeRequest {
method?: Method | undefined;

@ -72,18 +72,6 @@ export const updateDocuments = async (
documents: UpdateDocumentsArgs
): Promise<[Verification | "OK" | null, string?]> => {
try {
// .replace(/\s/g, '_')
// if (documents.inn) {
// documents.inn.append("name", "blob");
// }
// if (documents.rule) {
// documents.rule.append("name", "blob");
// }
// if (documents.certificate) {
// documents.certificate.append("name", "blob");
// }
console.log("documents")
console.log(documents)
const updateDocumentsResponse = await makeRequest<FormData, Verification>({
method: "PUT",
url: `${API_URL}`,
@ -105,8 +93,6 @@ export const updateDocuments = async (
export const updateDocument = async (
body: FormData
): Promise<[Verification | "OK" | null, string?]> => {
console.log("body")
console.log(body)
try {
const updateDocumentResponse = await makeRequest<FormData, Verification>({
method: "PATCH",

@ -1,5 +1,6 @@
import makeRequest from "@api/makeRequest";
import { SendPaymentRequest, SendPaymentResponse } from "@root/model/wallet";
import { allTypesOfPurchases } from "@root/stores/allTypesOfPurchases";
import { parseAxiosError } from "@root/utils/parse-error";
const isStaging = (() => {
@ -20,32 +21,21 @@ interface PaymentBody {
export const sendPayment = async ({
userId,
wayback,
body,
fromSquiz,
paymentPurpose,
cc
}: {
userId: string;
wayback: string;
body: PaymentBody;
fromSquiz: boolean;
paymentPurpose: "paycart" | "replenishwallet";
cc?: boolean
}): Promise<[SendPaymentResponse | null, string?]> => {
console.log(" я sendPayment и вот мой wayback = " + wayback)
const action = allTypesOfPurchases(state => state.action);
const fromDomain = allTypesOfPurchases(state => state.fromDomain);
const backWay = allTypesOfPurchases(state => state.backWay);
let returnUrl= `https://${isStaging}hub.pena.digital/afterpay?from=${
fromSquiz ? "quiz" : "hub"
}&purpose=${paymentPurpose}&userid=${userId}`
let returnUrl = `https://${fromDomain}/${backWay}?&userid=${userId}&action=${action}`
if (wayback) returnUrl += `&wayback=${wayback}`
if (cc) returnUrl = returnLink + "&cc=true"
console.log("returnUrl")
console.log(returnUrl)
console.log("returnUrl")
console.log(returnUrl)
const reqeustBody = {
currency: "RUB",
bankCard: {

@ -13,7 +13,7 @@ import { ReactComponent as CrossIcon } from "@root/assets/Icons/cross.svg";
import type { MouseEvent } from "react";
import CustomTariffAccordion from "@root/components/CustomTariffAccordion";
import { setNotEnoughMoneyAmount } from "@root/stores/notEnoughMoneyAmount";
import { setNotEnoughMoneyAmount } from "@root/stores/allTypesOfPurchases";
const name: Record<string, string> = {
templategen: "Шаблонизатор",

@ -19,7 +19,7 @@ import { Link, useNavigate } from "react-router-dom";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import { setNotEnoughMoneyAmount, startPayCartProcess, useNotEnoughMoneyAmount } from "@root/stores/notEnoughMoneyAmount";
import { setNotEnoughMoneyAmount, startPayCartProcess, allTypesOfPurchases } from "@root/stores/allTypesOfPurchases";
import { RSCOpen } from "@root/stores/requestSquizCreate";
function Drawers() {
@ -36,8 +36,8 @@ function Drawers() {
const userAccount = useUserStore((state) => state.userAccount);
const userId = useUserStore((state) => state.userId) || "";
const tickets = useTicketStore((state) => state.tickets);
const notEnoughMoneyAmount = useNotEnoughMoneyAmount(state => state.notEnoughMoneyAmount);
const siteReadyPayCart = useNotEnoughMoneyAmount(state => state.siteReadyPayCart)
const notEnoughMoneyAmount = allTypesOfPurchases(state => state.notEnoughMoneyAmount);
const siteReadyPayCart = allTypesOfPurchases(state => state.siteReadyPayCart)
const notificationsCount = tickets.filter(
({ user, top_message }) => user !== top_message.user_id && top_message.shown.me !== 1

@ -151,8 +151,6 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
}, []),
onFetchStateChange: setUnauthTicketMessageFetchState,
});
console.log("sessionData")
console.log(sessionData)
useSSESubscription<TicketMessage>({
enabled: sseEnabled && isActiveSSETab && Boolean(sessionData),
url:
@ -160,10 +158,6 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
`/heruvym/v1.0.0/ticket?ticket=${sessionData?.ticketId}&s=${sessionData?.sessionId}`,
onNewData: (ticketMessages) => {
console.log("Chat")
console.log("ticketMessages useSSESubscription ")
console.log(ticketMessages)
const isTicketClosed = ticketMessages.some(
(message) => message.session_id === "close"
);
@ -176,13 +170,10 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
return;
}
console.log("under checking some close message -----------------------------------------")
updateSSEValue(ticketMessages);
addOrUpdateUnauthMessages(ticketMessages);
},
onDisconnect: useCallback(() => {
console.log("DISCONNECT")
setUnauthIsPreventAutoscroll(false);
setSseEnabled(false);
}, []),

@ -28,7 +28,7 @@ import {
import { currencyFormatter } from "@root/utils/currencyFormatter";
import { clearCustomTariffs } from "@root/stores/customTariffs";
import { clearTickets } from "@root/stores/tickets";
import {setNotEnoughMoneyAmount} from "@stores/notEnoughMoneyAmount"
import {setNotEnoughMoneyAmount} from "@stores/allTypesOfPurchases"
interface Props {
isLoggedIn: boolean;

@ -17,7 +17,7 @@ import { logout } from "@root/api/auth";
import { enqueueSnackbar } from "notistack";
import { clearCustomTariffs } from "@root/stores/customTariffs";
import { clearTickets } from "@root/stores/tickets";
import {setNotEnoughMoneyAmount} from "@stores/notEnoughMoneyAmount"
import {setNotEnoughMoneyAmount} from "@stores/allTypesOfPurchases"
type MenuItem = {
name: string;

@ -17,7 +17,7 @@ import { currencyFormatter } from "@root/utils/currencyFormatter";
import { clearTickets } from "@root/stores/tickets";
import type { ReactNode } from "react";
import {setNotEnoughMoneyAmount} from "@stores/notEnoughMoneyAmount"
import {setNotEnoughMoneyAmount} from "@stores/allTypesOfPurchases"
interface Props {
children: ReactNode;

@ -18,7 +18,7 @@ import { clearTickets } from "@root/stores/tickets";
import { currencyFormatter } from "@root/utils/currencyFormatter";
import walletIcon from "@root/assets/Icons/wallet_icon.svg";
import {setNotEnoughMoneyAmount} from "@stores/notEnoughMoneyAmount"
import {setNotEnoughMoneyAmount} from "@stores/allTypesOfPurchases"
export const NavbarPanel = () => {
const navigate = useNavigate();

@ -40,7 +40,6 @@ export default function ProtectedLayout() {
process.env.REACT_APP_DOMAIN +
`/heruvym/v1.0.0/subscribe?Authorization=${token}`,
onNewData: (data) => {
console.log("ProtectedLayout")
updateSSEValue(data);
updateTickets(data.filter((d) => Boolean(d.id)));
setTicketCount(data.length);

@ -8,7 +8,7 @@ import { Loader } from "./Loader";
import { currencyFormatter } from "@root/utils/currencyFormatter";
import { payCart } from "@root/api/cart";
import { setUserAccount, useUserStore } from "@root/stores/user";
import { setNotEnoughMoneyAmount, startPayCartProcess, useNotEnoughMoneyAmount } from "@root/stores/notEnoughMoneyAmount";
import { setNotEnoughMoneyAmount, startPayCartProcess, allTypesOfPurchases } from "@root/stores/allTypesOfPurchases";
import { RSCOpen } from "@root/stores/requestSquizCreate";
import { useCart } from "@root/utils/hooks/useCart";
@ -21,7 +21,7 @@ interface Props {
export default function TotalPrice({ priceAfterDiscounts, priceBeforeDiscounts, isConstructor = false }: Props) {
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const notEnoughMoneyAmount = useNotEnoughMoneyAmount(state => state.notEnoughMoneyAmount);
const notEnoughMoneyAmount = allTypesOfPurchases(state => state.notEnoughMoneyAmount);
const userId = useUserStore(store => store.userId) || ""
const [loading, setLoading] = useState<boolean>(false);
const navigate = useNavigate();

@ -1,4 +1,3 @@
import React, { useEffect } from "react";
import ReactDOM from "react-dom/client";
import {
BrowserRouter,
@ -13,7 +12,6 @@ import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
import Faq from "./pages/Faq/Faq";
import Wallet from "./pages/Wallet";
import Payment from "./pages/Payment/Payment";
import QuizPayment from "./pages/QuizPayment/QuizPayment";
import Support from "./pages/Support/Support";
import ChatImageNewWindow from "./pages/Support/ChatImageNewWindow";
import AccountSettings from "./pages/AccountSettings/AccountSettings";
@ -57,15 +55,13 @@ import PrivacyPolicy from "@root/docs/content/PrivacyPolicy";
import RecoverPassword from "@root/pages/auth/RecoverPassword";
import OutdatedLink from "@root/pages/auth/OutdatedLink";
import { verify } from "./pages/AccountSettings/helper";
import AfterPay from "./pages/AfterPay";
import { PageNotFound } from "./pages/PageNotFound";
import { useNotEnoughMoneyAmount } from "@stores/notEnoughMoneyAmount"
import { usePipeSubscriber } from "./utils/hooks/usePipeSubscriber";
import { useAfterPay } from "./utils/hooks/useAutoPay";
import { LocalizationProvider } from "@mui/x-date-pickers";
import { ModalRequestCreate } from "./pages/Tariffs/ModalRequestCreate";
import * as crutch from "./useUserAccountFetcher";
import { useCart } from "./utils/hooks/useCart";
import { useTryBuy } from "./utils/hooks/useTryBuy";
import { useReauthorization } from "./utils/hooks/useReauthorization";
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;
@ -119,17 +115,12 @@ const App = () => {
},
});
usePipeSubscriber()
usePipeSubscriber();
useTryBuy();
useReauthorization();
verify(userId);
useAfterPay()
console.log("location")
console.log(location)
console.log("window.location")
console.log(window.location)
if (location.state?.redirectTo)
return (
<Navigate
@ -218,7 +209,6 @@ console.log(window.location)
</Route>
</Route>
<Route path="/ppdd" element={<PPofData />} />
<Route path="/quizpayment" element={<QuizPayment />} />
<Route element={<Docs />}>
<Route path={"/docs/oferta"} element={<Oferta />} />
<Route
@ -227,7 +217,6 @@ console.log(window.location)
/>
<Route path={"/docs/privacy"} element={<PrivacyPolicy />} />
</Route>
<Route path="/afterpay" element={<AfterPay />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
</>

2
src/model/autoPay.ts Normal file

@ -0,0 +1,2 @@
export type FromDomain = "quiz" | "squiz" | "hub" | "shub" | "localhost:3000";
export type Action = "topupwallet" | "createquizcc" | "buy";

@ -67,7 +67,7 @@ export default function DocumentItem({
.then(e => {
setReadyShowDocument(true)
})
.catch(e => console.log(e))
.catch(e => console.error(e))
}
}
}, [])

@ -47,7 +47,7 @@ export default function DocumentUploadItem({
.then(e => {
setReadyShowDocument(true)
})
.catch(e => console.log(e))
.catch(e => console.error(e))
}
} else {
setReadyShowDocument(true)

@ -1,28 +0,0 @@
import { useNavigate, useSearchParams } from "react-router-dom";
//Раньше эта страничка благодарила за покупку и перенаправляла сталкера своей дорогой.
//Чтобы не мелькать хабом перед перенаправлением на другие домены - логика останется на этом отдельном url адресе
//Эта страничка ТОЛЬКО перенаправляет на нужный адрес. Процесс автопокупки после пополнения лежит на хуке useAutoPay
export default () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const userId = searchParams.get("userid");
const from = searchParams.get("from") || "hub";
const purpose = searchParams.get("purpose")
const isCC = searchParams.get("cc")
const host = window.location.hostname;
const domain = (host.includes("s") ? "s" : "") + from;
const pathname = from.includes("hub") ? "/tariffs" : "/list";
let link = `https://${domain}.pena.digital${pathname}?purpose=${purpose}&userid=${userId}`
console.log("isCC")
if (isCC) link = link + "&cc=true"
document.location.href = link
return <></>;
};

@ -11,11 +11,8 @@ import {
} 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";
@ -25,14 +22,15 @@ import { currencyFormatter } from "@root/utils/currencyFormatter";
import { useHistoryTracker } from "@root/utils/hooks/useHistoryTracker";
import { cardShadow } from "@root/utils/theme";
import { enqueueSnackbar } from "notistack";
import { useEffect, useLayoutEffect, useState } from "react";
import { 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";
import { calcTimeOfReadyPayCart, cancelPayCartProcess, setNotEnoughMoneyAmount, startPayCartProcess, useNotEnoughMoneyAmount } from "@root/stores/notEnoughMoneyAmount";
import { allTypesOfPurchases } from "@root/stores/allTypesOfPurchases";
import { useAutoPay } from "@root/utils/hooks/useAutoPay";
type PaymentMethod = {
label: string;
@ -54,78 +52,38 @@ type PaymentMethodType = (typeof paymentMethods)[number]["name"];
export default function Payment() {
const theme = useTheme();
const location = useLocation();
const navigate = useNavigate();
const handleCustomBackNavigation = useHistoryTracker();
const userId = useUserStore((state) => state.userId) || "";
const verificationStatus = useUserStore((state) => state.verificationStatus);
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 [paymentValueField, setPaymentValueField] = useState<string>("0");
const [paymentLink, setPaymentLink] = useState<string>("");
const [fromSquiz, setIsFromSquiz] = useState<boolean>(false);
const location = useLocation();
const verificationStatus = useUserStore((state) => state.verificationStatus);
const userId = useUserStore((state) => state.userId);
const navigate = useNavigate();
const handleCustomBackNavigation = useHistoryTracker();
const [cc, setCC] = useState<boolean>(false);
//Логика сбора данных из урла "чё мы ваще пришли на эту страницу"
useAutoPay();
const userId = useUserStore((state) => state.userId) || "";
const notEnoughMoneyAmount = allTypesOfPurchases(state => state.notEnoughMoneyAmount);
const siteReadyPayCart = allTypesOfPurchases(state => state.siteReadyPayCart)
const verificationStatus = useUserStore((state) => state.verificationStatus);
const [promocodeField, setPromocodeField] = useState<string>("");
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState<PaymentMethodType | null>("");
const [paymentValueField, setPaymentValueField] = useState<string>(siteReadyPayCart ? (notEnoughMoneyAmount / 100).toString() : "0");
const [warnModalOpen, setWarnModalOpen] = useState<boolean>(false);
const [sorryModalOpen, setSorryModalOpen] = useState<boolean>(false);
const notEnoughMoneyAmount = useNotEnoughMoneyAmount(state => state.notEnoughMoneyAmount)
const siteReadyPayCart = useNotEnoughMoneyAmount(state => state.siteReadyPayCart)
const [fromSquiz, setIsFromSquiz] = useState<boolean>(false);
const [waybackToSomeSite, setWaybackToSomeSite] = useState<string>("");
const { diffMoney, setNewDiff } = useDiffMoney()
const notEnoughMoneyAmount =
(location.state?.notEnoughMoneyAmount as number) ?? 0;
const paymentValue = parseFloat(
bigDecimal.multiply(parseFloat(paymentValueField), 100)
);
//Отмена состояния сайта "в процессе покупки корзины, просто нехватило деняк"
useEffect(() => {
return () => {
//При выходе со страницы оплаты мы точно не в состоянии покупки корзины
cancelPayCartProcess()
}
}, [])
//Тут записываем начальную сумму в инпут (если стоит флаг что мы в процессе покупки)
useEffect(() => {
if (siteReadyPayCart !== null && siteReadyPayCart[userId] !== undefined && calcTimeOfReadyPayCart(siteReadyPayCart[userId]))
setPaymentValueField((notEnoughMoneyAmount / 100).toString());//Сколько нехватило на хабе
}, [notEnoughMoneyAmount, siteReadyPayCart])
useLayoutEffect(() => {
//Предустановленное значение - это либо 0, либо сколько нам нехватило на хабе, либо сколько нам нехватило на квизе
const params = new URLSearchParams(window.location.search);
const fromSquiz = params.get("action");
const userid = params.get("user");
const currentCC = params.get("cc");
if (currentCC) setCC(true)
if (fromSquiz === "squizpay" && userid !== null) {
setIsFromSquiz(true);
}
//Принимаем параметры из странички и очищаем url адрес до красивого состояния
navigate(`/payment`, {
replace: true,
});
}, []);
//https://shub.pena.digital/quizpayment?action=squizpay&dif=9800&data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY2ODVhNTc4OTgzZWU3N2Y4ZTFlNjNkYyIsImF1ZCI6InBlbmEiLCJpc3MiOiJwZW5hLWF1dGgtc2VydmljZSIsImlhdCI6MTcyMjIyMjgzMywiZXhwIjoxNzI3NDA2ODMzfQ.My1KJWFk034MiMdImQSlzf5p4Sn5Dhboj2VvPQteh59tD_CwXyPtePEyev3thV_58IbOOgJ5cgeBm0JKn7atgMgRMpNQVdeYKtf6HYvVoAqkrMcT1LHgAlEQ0TcaXssFKCQGuiCVltHY3UE-kQv5TeydBpO3U9BDKvMqRqv5-Xo&userid=6685a578983ee77f8e1e63dc
const handlePaymentClick = () => {
if (Number(paymentValueField) === 0) {
@ -170,8 +128,7 @@ export default function Payment() {
return
}
const [sendPaymentResponse, sendPaymentError] = await sendPayment({
userId: userId ?? "",
fromSquiz,
userId,
body: {
type: selectedPaymentMethod,
amount: Number(
@ -179,9 +136,7 @@ export default function Payment() {
bigDecimal.multiply(Number(paymentValueField), 100)
)
),
},
paymentPurpose: notEnoughMoneyAmount ? "paycart" : "replenishwallet",
cc
}
});
if (sendPaymentError) {
@ -277,7 +232,6 @@ export default function Payment() {
image={image}
onClick={() => {
setSelectedPaymentMethod(name);
setPaymentLink("");
}}
unpopular={false}
/>
@ -288,7 +242,6 @@ export default function Payment() {
image={rsPayLogo}
onClick={async () => {
setSelectedPaymentMethod("rspay");
setPaymentLink("");
}}
unpopular={false}
/>

@ -1,113 +0,0 @@
import { useEffect, useState } from "react";
import { ApologyPage } from "../ApologyPage";
import { redirect, useNavigate } from "react-router-dom";
import {
clearAuthToken,
getMessageFromFetchError,
setAuthToken,
useUserAccountFetcher,
useUserFetcher,
getAuthToken,
} from "@frontend/kitui";
import {
clearUserData,
setUser,
setUserAccount,
setUserId,
useUserStore,
} from "@root/stores/user";
import { logout } from "@root/api/auth";
import { clearCustomTariffs } from "@root/stores/customTariffs";
import { clearTickets } from "@root/stores/tickets";
import { setNotEnoughMoneyAmount, startPayCartProcess } from "@stores/notEnoughMoneyAmount"
const params = new URLSearchParams(window.location.search);
let action = params.get("action");
let dif = params.get("dif");
let token = params.get("data");
let userId = params.get("userid");
let currentCC = params.get("cc");
let first = true;
export default function QuizPayment() {
const navigate = useNavigate();
const [message, setMessage] = useState("Идёт загрузка");
const user = useUserStore((state) => state.user);
const currentUserId = useUserStore((state) => state.user?._id);
const fromSquiz = params.get("action");
useEffect(
function redirectIfSignedIn() {
if (!first && user?._id === userId) {
let returnUrl = `/payment?action=${action}&dif=${dif}&user=${userId}`
if (wayback) returnUrl += `&wayback=${wayback}`
navigate(returnUrl, {
replace: true,
});
}
},
[navigate, user]
useEffect(() => {
if (!first && userId !== null && currentUserId === userId) {
if (fromSquiz === "squizpay") {
setNotEnoughMoneyAmount(Number(params.get("dif") || 0));//Сколько нехватило на квизе
startPayCartProcess(userId)
let link = `/payment?action=${action}&dif=${dif}&user=${userId}`
if (currentCC) link = link + "&cc=true"
navigate(link, {
replace: true,
});
}
}
},
[currentUserId]
);
if (first) {
navigate(`/quizpayment`, {
replace: true,
});
try {
first = false;
if (user?._id === userId) {
return;
}
if (action && dif && token) {
(async () => {
if (getAuthToken()) {
clearAuthToken();
clearUserData();
clearCustomTariffs();
clearTickets();
setNotEnoughMoneyAmount(0)
logout();
}
setUserId(userId);
setAuthToken(token);
return;
})();
} else {
var link = document.createElement("a");
link.href = "https://quiz.pena.digital/tariffs";
document.body.appendChild(link);
link.click();
}
} catch (e) {
setMessage("Произошла ошибка");
var link = document.createElement("a");
link.href = "https://quiz.pena.digital/tariffs";
document.body.appendChild(link);
link.click();
}
}
return <ApologyPage message={message} />;
}

@ -101,17 +101,8 @@ function SupportChat() {
`/heruvym/v1.0.0/ticket?ticket=${ticketId}&Authorization=${token}`,
onNewData: (ticketMessages) => {
console.log("SupportChat")
console.log("ticketMessages")
console.log(ticketMessages)
const data = ticketMessages.filter(t => {
if (typeof t === "object" && t !== null && "event" in t && t.event !== "ping") {
console.log("---------------------------------------------------")
console.log(t)
console.log(typeof t === "object")
console.log("event" in t)
console.log(t.event !== "ping")
console.log("---------------------------------------------------")
return true
}
})
@ -235,9 +226,6 @@ function SupportChat() {
setDisableFileButton(false);
};
console.log("messages messmessagesmessagesmessages messages")
console.log(messages)
return (
<Box
sx={{
@ -353,8 +341,6 @@ function SupportChat() {
message?.files?.length > 0 &&
isFileImage()
) {
console.log("message NEWNEWNENWNEW _WE__WE_W_EW_E_WENWNEWNENWEWNE")
console.log(message)
return (
<ChatImage
unAuthenticated

@ -84,7 +84,6 @@ export const ModalRequestCreate = () => {
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const [isSending, setIsSending] = useState(false)
const open = useRequestSquizCreate(store => store.isRSCOpen)
console.log(open)
if (isSending) return (
<Modal

@ -51,7 +51,6 @@ function TariffPage() {
useUserStore((state) => state.userAccount?.wallet.spent) ?? 0;
const userId = useUserStore((state) => state.user?._id) ?? "";
const userPrivilegies = useUserStore(store => store.quizUserAccount?.privileges);
console.log(userPrivilegies)
const discounts = useDiscounts(userId);
const isUserNko =
useUserStore((state) => state.userAccount?.status) === "nko";

@ -75,8 +75,6 @@ export default function RecoverPassword() {
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const authToken = params.get("auth");
console.log("authToken")
console.log(authToken)
setTokenUser(authToken);
history.pushState(null, document.title, "/changepwd");

@ -0,0 +1,64 @@
import moment from "moment";
import { create } from "zustand";
import { devtools, persist } from "zustand/middleware";
import type { Action, FromDomain } from "@root/model/autoPay";
interface CartStore {
notEnoughMoneyAmount: number;
siteReadyPayCart: Record<string, string> | null;
fromDomain: FromDomain | null;
backWay: string;
action: Action | null;
}
const initialState: CartStore = {
notEnoughMoneyAmount: 0,
siteReadyPayCart: null,
fromDomain: null,
backWay: "",
action: null
}
//Была попытка оплатить корзину. Тут записанна недостающая сумма.
export const allTypesOfPurchases = create<CartStore>()(
devtools(
persist(
() => initialState,
{
name: 'siteReadyPayCart', // Ключ для localStorage
partialize: (state) => ({
// Сохраняем ТОЛЬКО siteReadyPayCart
siteReadyPayCart: state.siteReadyPayCart
}),
}
),
{
name: "cartStore",
enabled: process.env.NODE_ENV === "development",
}
)
);
export const setSiteReadyPayCart = (flag: Record<string, string> | null) => allTypesOfPurchases.setState({ siteReadyPayCart: flag });
export const setNotEnoughMoneyAmount = (amount: number) => allTypesOfPurchases.setState({ notEnoughMoneyAmount: amount });
export const setFromDomain = (fromDomain: FromDomain) => allTypesOfPurchases.setState({ fromDomain });
export const setBackWay = (backWay: string) => allTypesOfPurchases.setState({ backWay });
export const setAction = (action: Action) => allTypesOfPurchases.setState({ action });
export const startPayCartProcess = (userId: string) => setSiteReadyPayCart({ [userId]: moment().add(20, 'minutes').format("X") });
export const cancelPayCartProcess = () => {
setSiteReadyPayCart(null);
allTypesOfPurchases.setState({
fromDomain: null,
backWay: "",
action: null
})
};
export const calcTimeOfReadyPayCart = (deadline: string) => {
const ready = Number(deadline) > Number(moment().format("X"))
if (!ready) {
cancelPayCartProcess()
}
return ready
}

@ -1,38 +0,0 @@
import moment from "moment";
import { create } from "zustand";
import { devtools } from "zustand/middleware";
interface CartStore {
notEnoughMoneyAmount: number;
siteReadyPayCart: Record<string, string> | null;
}
const initialState: CartStore = {
notEnoughMoneyAmount: 0,
siteReadyPayCart: null
}
//Была попытка оплатить корзину. Тут записанна недостающая сумма.
export const useNotEnoughMoneyAmount = create<CartStore>()(
devtools(
(get, set) => initialState,
{
name: "notEnoughMoneyAmount",
enabled: process.env.NODE_ENV === "development",
trace: true,
actionsBlacklist: "rejected",
}
)
);
export const setNotEnoughMoneyAmount = (amount: number) => useNotEnoughMoneyAmount.setState({ notEnoughMoneyAmount: amount });
export const setSiteReadyPayCart = (flag: Record<string, string> | null) => useNotEnoughMoneyAmount.setState({ siteReadyPayCart: flag });
export const startPayCartProcess = (userId: string) => setSiteReadyPayCart({ [userId]: moment().add(20, 'minutes').format("X") });
export const cancelPayCartProcess = () => setSiteReadyPayCart(null);
export const calcTimeOfReadyPayCart = (deadline: string) => {
const ready = Number(deadline) > Number(moment().format("X"))
if (!ready) {
cancelPayCartProcess()
}
return ready
}

@ -14,7 +14,7 @@ import { patchUser } from "@root/api/user"
import { UserAccountSettingsFieldStatus, VerificationStatus } from "@root/model/account"
import { patchCurrency, deleteCart, patchCart } from "@root/api/cart"
import { User, UserAccount, UserName, getInitials, patchUserAccount } from "@frontend/kitui"
import { cancelPayCartProcess, setNotEnoughMoneyAmount, setSiteReadyPayCart, useNotEnoughMoneyAmount } from "./notEnoughMoneyAmount";
import { cancelPayCartProcess, setNotEnoughMoneyAmount, setSiteReadyPayCart, allTypesOfPurchases } from "./allTypesOfPurchases";
type Privilege = {
amount: number;

@ -17,7 +17,6 @@ export const useUserAccountFetcher = <T = UserAccount>({
onNewUserAccount: (response: T) => void;
onError?: (error: any) => void;
}) => {
console.log("начало работы useUserAccountFetcher")
const onNewUserAccountRef = useRef(onNewUserAccount);
const onErrorRef = useRef(onError);
useLayoutEffect(() => {

@ -1,72 +1,51 @@
import { payCart } from "@root/api/cart";
import { calcTimeOfReadyPayCart, cancelPayCartProcess, setNotEnoughMoneyAmount, setSiteReadyPayCart, startPayCartProcess, useNotEnoughMoneyAmount } from "@root/stores/notEnoughMoneyAmount";
import { useUserStore } from "@root/stores/user";
import moment from "moment";
import { enqueueSnackbar } from "notistack";
import { useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import { RSCOpen } from "@root/stores/requestSquizCreate";
import { useCartTariffs } from "./useCartTariffs";
import { useNavigate, useSearchParams } from "react-router-dom";
import { cancelPayCartProcess, setNotEnoughMoneyAmount, startPayCartProcess } from "@root/stores/allTypesOfPurchases";
import { clearUserData, useUserStore } from "@root/stores/user";
import { clearAuthToken, getAuthToken, setAuthToken } from "@frontend/kitui";
import { clearCustomTariffs } from "@root/stores/customTariffs";
import { clearTickets } from "@root/stores/tickets";
import { logout } from "@root/api/auth";
import { setAction, setBackWay, setFromDomain } from "@root/stores/allTypesOfPurchases";
import { Action, FromDomain } from "@root/model/autoPay";
export const useAutoPay = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
export const useAfterPay = () => {
const [searchParams, setSearchParams] = useSearchParams();
const userId = useUserStore(store => store.userId)
const userAccount = useUserStore(state => state.userAccount);
const siteReadyPayCart = useNotEnoughMoneyAmount(state => state.siteReadyPayCart);
const cartTariffs = useCartTariffs();
console.log("cartTariffs")
// console.log(cartTariffs)
// const isCC = cartTariffs !== null && cartTariffs !== undefined && cartTariffs.length > 0 && cartTariffs.some(t => t.privileges[0].privilegeId === "quizManual")
const purpose = searchParams.get("purpose");
const from = searchParams.get("from");
const action = searchParams.get("action");
const paymentUserId = searchParams.get("userid");
useEffect(() => {
//Звёзды сошлись, будем оплачивать корзину
if (from !== "quiz" && paymentUserId && paymentUserId === userId) {
//Чистим url адрес от параметров. (Если нет action. Если есть - значит мы пришли из квиза)
if (action === null) setSearchParams({}, { replace: true })
// navigate(`/tariffs`, {
// replace: true,
// });
let URLfromDomain = searchParams.get("fromdomain");//домен откуда произошёл запрос на финансовые работы
let URLaction = searchParams.get("action");//что мы, собсна, хотим: оплатить, пополнить, купить и создать квиз
let URLuserId = searchParams.get("userid");//тот кто начал всё это действо
let URLtoken = searchParams.get("wayback");//его токен
const URLwayBack = searchParams.get("wayback") ?? "";//путь по которому нужно будет пройти после того как закончим манипуляции (без домена)
let URLmoneyDifferent = Number(searchParams.get("dif"));//сколько нужно деняк
if (purpose === "paycart") {
(async () => {
navigate("/payment", { replace: true });//запомнили данные, затёрли их из адресной строки, шоб красиво было
//Проверяем можем ли мы оплатить корзину здесь и сейчас
const [, payCartError] = await payCart();
let continueWork = true;
if (payCartError) {
//Не получилось купить корзину. Ставим флаг, что сайт в состоянии ожидания пополнения счёта для оплаты
startPayCartProcess(paymentUserId)
} else {
enqueueSnackbar("Товары успешно приобретены")
cancelPayCartProcess()
if (true) RSCOpen()
}
})()
}
//Анализ нужно ли вообще вмешательство этого хука
if (
URLuserId !== null && URLuserId &&
(URLfromDomain === "quiz" || URLfromDomain === "squiz" || URLfromDomain === "hub" || URLfromDomain === "shub" || URLfromDomain === "localhost:3000") &&
(URLaction === "topupwallet" || URLaction === "createquizcc" || URLaction === "buy") &&
!Number.isNaN(URLmoneyDifferent)
) {
// Ставим флаг, что сайт в состоянии ожидания пополнения счёта для оплаты
startPayCartProcess(URLuserId);
setFromDomain(URLfromDomain as FromDomain);
setBackWay(URLwayBack.startsWith('/') ? URLwayBack.slice(1) : URLwayBack);
setAction(URLaction as Action);
} else {
cancelPayCartProcess();
}
}, [purpose, from, paymentUserId])
useEffect(() => {
if (userId !== null && siteReadyPayCart !== null && siteReadyPayCart[userId] !== undefined) {
const deadline = siteReadyPayCart[userId]
if (calcTimeOfReadyPayCart(deadline)) {
//Время ещё не вышло. У нас стоит флаг покупать корзину если время не вышло.
(async () => {
const [, payCartError] = await payCart();
if (!payCartError) {
enqueueSnackbar("Товары успешно приобретены")
cancelPayCartProcess()
}
})()
}
return () => {
cancelPayCartProcess();
}
}, [userAccount, userId, siteReadyPayCart])
}, [])
}

@ -1,7 +1,7 @@
import { Ticket, UserAccount, UserName, getAuthToken, useSSESubscription } from "@frontend/kitui"
import { setCart, setNewNames, setUserStatus, setWallet, useUserStore } from "@root/stores/user";
import { useSSETab } from "./useSSETab";
import { cancelPayCartProcess } from "@root/stores/notEnoughMoneyAmount";
import { cancelPayCartProcess } from "@root/stores/allTypesOfPurchases";
type Ping = [{ event: "ping" }]

@ -0,0 +1,34 @@
import { clearAuthToken, getAuthToken, setAuthToken } from '@frontend/kitui';
import { logout } from '@root/api/auth';
import { setNotEnoughMoneyAmount } from '@root/stores/allTypesOfPurchases';
import { clearCustomTariffs } from '@root/stores/customTariffs';
import { clearTickets } from '@root/stores/tickets';
import { clearUserData, useUserStore } from '@root/stores/user';
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
export const useReauthorization = () => {
const userId = useUserStore(store => store.userId)
const { search } = useLocation();
useEffect(() => {
// Этот эффект сработает при каждом изменении query-параметров
const params = new URLSearchParams(search);
const URLuserId = params.get('userId');
const URLtoken = params.get('action');
if (URLuserId !== userId && URLtoken) {
if (getAuthToken()) {
clearAuthToken();
clearUserData();
clearCustomTariffs();
clearTickets();
setNotEnoughMoneyAmount(0)
logout();
}
setAuthToken(URLtoken);//перелогиниваемся
}
}, [search]);
};

@ -0,0 +1,29 @@
import { payCart } from "@root/api/cart";
import { allTypesOfPurchases, calcTimeOfReadyPayCart, cancelPayCartProcess } from "@root/stores/allTypesOfPurchases"
import { useUserStore } from "@root/stores/user";
import { enqueueSnackbar } from "notistack";
import { useEffect } from "react"
export const useTryBuy = () => {
const userId = useUserStore(store => store.userId)
const userAccount = useUserStore(state => state.userAccount);
const siteReadyPayCart = allTypesOfPurchases(state => state.siteReadyPayCart);
useEffect(() => {
if (userId !== null && siteReadyPayCart !== null && siteReadyPayCart[userId] !== undefined) {
const deadline = siteReadyPayCart[userId]
if (calcTimeOfReadyPayCart(deadline)) {
//Время ещё не вышло. У нас стоит флаг покупать корзину если время не вышло.
(async () => {
const [, payCartError] = await payCart();
if (!payCartError) {
enqueueSnackbar("Товары успешно приобретены")
cancelPayCartProcess()
}
})()
}
}
}, [userAccount, userId, siteReadyPayCart])
}

@ -26,8 +26,6 @@ export const jsonToFormdata = (
): FormData => {
const formData = new FormData()
if (json.egrule !== undefined) delete json.egrule
console.log("json")
console.log(json)
for (const key in json) {
if (!key) continue
@ -43,7 +41,5 @@ export const jsonToFormdata = (
formData.append(key, value)
}
console.log("formData")
console.log(formData)
return formData
}

@ -1059,6 +1059,11 @@
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.1.tgz#9fce313d12c9a77507f264de74626e87fd0dc541"
integrity sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==
"@babel/runtime@^7.25.7", "@babel/runtime@^7.27.6":
version "7.27.6"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6"
integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==
"@babel/template@^7.27.1", "@babel/template@^7.3.3":
version "7.27.2"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d"
@ -2104,11 +2109,30 @@
csstype "^3.1.3"
prop-types "^15.8.1"
"@mui/types@^7.4.4":
version "7.4.4"
resolved "https://registry.npmjs.org/@mui/types/-/types-7.4.4.tgz#0c5cd56905231e27096b41d096f1c948c26bdd5d"
integrity sha512-p63yhbX52MO/ajXC7hDHJA5yjzJekvWD3q4YDLl1rSg+OXLczMYPvTuSuviPRCgRX8+E42RXz1D/dz9SxPSlWg==
dependencies:
"@babel/runtime" "^7.27.6"
"@mui/types@~7.2.15":
version "7.2.24"
resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.24.tgz#5eff63129d9c29d80bbf2d2e561bd0690314dec2"
integrity sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==
"@mui/utils@^5.16.6 || ^6.0.0 || ^7.0.0":
version "7.2.0"
resolved "https://registry.npmjs.org/@mui/utils/-/utils-7.2.0.tgz#31062697b41aa8ea8ef04e3d3fadca1dec3e1de1"
integrity sha512-O0i1GQL6MDzhKdy9iAu5Yr0Sz1wZjROH1o3aoztuivdCXqEeQYnEjTDiRLGuFxI9zrUbTHBwobMyQH5sNtyacw==
dependencies:
"@babel/runtime" "^7.27.6"
"@mui/types" "^7.4.4"
"@types/prop-types" "^15.7.15"
clsx "^2.1.1"
prop-types "^15.8.1"
react-is "^19.1.0"
"@mui/utils@^5.17.1":
version "5.17.1"
resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.17.1.tgz#72ba4ffa79f7bdf69d67458139390f18484b6e6b"
@ -2121,6 +2145,27 @@
prop-types "^15.8.1"
react-is "^19.0.0"
"@mui/x-date-pickers@^7.13.0":
version "7.29.4"
resolved "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.29.4.tgz#b8808cb8e28c1d4e528b37b336effc8074e65faf"
integrity sha512-wJ3tsqk/y6dp+mXGtT9czciAMEO5Zr3IIAHg9x6IL0Eqanqy0N3chbmQQZv3iq0m2qUpQDLvZ4utZBUTJdjNzw==
dependencies:
"@babel/runtime" "^7.25.7"
"@mui/utils" "^5.16.6 || ^6.0.0 || ^7.0.0"
"@mui/x-internals" "7.29.0"
"@types/react-transition-group" "^4.4.11"
clsx "^2.1.1"
prop-types "^15.8.1"
react-transition-group "^4.4.5"
"@mui/x-internals@7.29.0":
version "7.29.0"
resolved "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.29.0.tgz#1f353b697ed1bf5594ac549556ade2e6841f4bf5"
integrity sha512-+Gk6VTZIFD70XreWvdXBwKd8GZ2FlSCuecQFzm6znwqXg1ZsndavrhG9tkxpxo2fM1Zf7Tk8+HcOO0hCbhTQFA==
dependencies:
"@babel/runtime" "^7.25.7"
"@mui/utils" "^5.16.6 || ^6.0.0 || ^7.0.0"
"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
version "5.1.1-v1"
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
@ -2807,6 +2852,11 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2"
integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==
"@types/prop-types@^15.7.15":
version "15.7.15"
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz#e6e5a86d602beaca71ce5163fadf5f95d70931c7"
integrity sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==
"@types/q@^1.5.1":
version "1.5.8"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.8.tgz#95f6c6a08f2ad868ba230ead1d2d7f7be3db3837"
@ -2834,7 +2884,7 @@
dependencies:
"@types/react" "*"
"@types/react-transition-group@^4.4.10":
"@types/react-transition-group@^4.4.10", "@types/react-transition-group@^4.4.11":
version "4.4.12"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz#b5d76568485b02a307238270bfe96cb51ee2a044"
integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==
@ -8903,6 +8953,11 @@ mlly@^1.7.3, mlly@^1.7.4:
pkg-types "^1.3.0"
ufo "^1.5.4"
moment@^2.30.1:
version "2.30.1"
resolved "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@ -10344,7 +10399,7 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
react-is@^19.0.0:
react-is@^19.0.0, react-is@^19.1.0:
version "19.1.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.1.0.tgz#805bce321546b7e14c084989c77022351bbdd11b"
integrity sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==
@ -11854,6 +11909,13 @@ tr46@~0.0.3:
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
transliteration@^2.3.5:
version "2.3.5"
resolved "https://registry.npmjs.org/transliteration/-/transliteration-2.3.5.tgz#8f92309575f69e4a8a525dab4ff705ebcf961c45"
integrity sha512-HAGI4Lq4Q9dZ3Utu2phaWgtm3vB6PkLUFqWAScg/UW+1eZ/Tg6Exo4oC0/3VUol/w4BlefLhUUSVBr/9/ZGQOw==
dependencies:
yargs "^17.5.1"
tryer@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
@ -12893,9 +12955,9 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
yargs@^17.3.1:
yargs@^17.3.1, yargs@^17.5.1:
version "17.7.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"