From ea4c238813b1b02236f104348bd5f23839a9b0f1 Mon Sep 17 00:00:00 2001 From: Nastya Date: Wed, 3 Jan 2024 22:41:41 +0300 Subject: [PATCH 1/9] =?UTF-8?q?=D0=B2=D1=81=D0=B5=20=D1=80=D0=BE=D1=83?= =?UTF-8?q?=D1=82=D1=8B=20=D0=B2=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B5=20Main=20=D0=B8=20=D1=8D=D1=82=D0=BE?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BB=D0=BE=D0=BC=D0=B0=D0=BB=D0=BE=20=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5.?= =?UTF-8?q?=20=D0=92=D0=B5=D1=81=D0=B5=D0=BB=D0=BE=20:)=20=D0=A1=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B0=20=D1=82=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D1=84=D0=BE=D0=B2=20=D1=83=D0=BC=D0=B5=D0=B5=D1=82=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BA=D1=83=D0=BF=D0=B0=D1=82=D1=8C=20=D1=82=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D1=84=D1=8B=20=D0=B5=D1=81=D0=BB=D0=B8=20=D1=85=D0=B2?= =?UTF-8?q?=D0=B0=D1=82=D0=B0=D0=B5=D1=82=20=D1=88=D0=B5=D0=BA=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 10 +- src/assets/icons/NumberIcon.tsx | 208 +++++++++++++++ src/model/privilege.ts | 5 + src/model/tariff.ts | 6 + src/pages/Tariffs/Tariffs.tsx | 201 ++++++++++++++ .../Tariffs/tariffsUtils/FreeTariffCard.tsx | 33 +++ src/pages/Tariffs/tariffsUtils/TariffCard.tsx | 145 ++++++++++ src/pages/Tariffs/tariffsUtils/calcCart.ts | 250 ++++++++++++++++++ .../Tariffs/tariffsUtils/calcTariffPrices.ts | 54 ++++ .../tariffsUtils/createTariffElements.tsx | 76 ++++++ .../Tariffs/tariffsUtils/currencyFormatter.ts | 6 + src/ui_kit/Header/Header.tsx | 1 + src/ui_kit/Header/HeaderFull.tsx | 2 + src/ui_kit/Header/NavMenuItem.tsx | 1 + src/ui_kit/Header/NavbarCollapsed.tsx | 1 + src/ui_kit/Toolbars/ToTariffsButton.tsx | 10 + 16 files changed, 1004 insertions(+), 5 deletions(-) create mode 100644 src/assets/icons/NumberIcon.tsx create mode 100644 src/model/privilege.ts create mode 100644 src/model/tariff.ts create mode 100644 src/pages/Tariffs/Tariffs.tsx create mode 100644 src/pages/Tariffs/tariffsUtils/FreeTariffCard.tsx create mode 100644 src/pages/Tariffs/tariffsUtils/TariffCard.tsx create mode 100644 src/pages/Tariffs/tariffsUtils/calcCart.ts create mode 100644 src/pages/Tariffs/tariffsUtils/calcTariffPrices.ts create mode 100644 src/pages/Tariffs/tariffsUtils/createTariffElements.tsx create mode 100644 src/pages/Tariffs/tariffsUtils/currencyFormatter.ts create mode 100644 src/ui_kit/Toolbars/ToTariffsButton.tsx diff --git a/src/App.tsx b/src/App.tsx index 35ccd8d3..2b2460fe 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,6 +23,7 @@ import { ResultSettings } from "./pages/ResultPage/ResultSettings"; import MyQuizzesFull from "./pages/createQuize/MyQuizzesFull"; import Main from "./pages/main"; import EditPage from "./pages/startPage/EditPage"; +import Tariffs from "./pages/Tariffs/Tariffs"; import { clearAuthToken, getMessageFromFetchError, @@ -110,6 +111,10 @@ const routeslink = [ { path: "/contacts", page: , header: true, sidebar: true }, { path: "/result", page: , header: true, sidebar: true }, { path: "/settings", page: , header: true, sidebar: true }, + { path: "/tariffs", page: , header: true, sidebar: false }, + { path: "/edit", page: , header: true, sidebar: true }, + { path: "/view", page: , header: false, sidebar: false }, + { path: "/design", page: , header: true, sidebar: true }, ] as const; export default function App() { @@ -195,11 +200,6 @@ export default function App() { } /> ))} - - } /> - } /> - } /> - } /> diff --git a/src/assets/icons/NumberIcon.tsx b/src/assets/icons/NumberIcon.tsx new file mode 100644 index 00000000..0402e39e --- /dev/null +++ b/src/assets/icons/NumberIcon.tsx @@ -0,0 +1,208 @@ +import { Box, SxProps, Theme } from "@mui/material"; +import { ReactElement } from "react"; + +interface Props { + number: number; + color: string; + backgroundColor?: string; + sx?: SxProps; +} + +export default function NumberIcon({ + number, + backgroundColor = "rgb(0 0 0 / 0)", + color, + sx, +}: Props) { + number = number % 100; + + const firstDigit = Math.floor(number / 10); + const secondDigit = number % 10; + + const firstDigitTranslateX = 6; + const secondDigitTranslateX = number < 10 ? 9 : number < 20 ? 11 : 12; + + const firstDigitElement = digitSvgs[firstDigit](firstDigitTranslateX); + const secondDigitElement = digitSvgs[secondDigit](secondDigitTranslateX); + + return ( + + + {circleSvg} + {number > 9 && firstDigitElement} + {secondDigitElement} + + + ); +} + +const circleSvg = ( + +); + +const digitSvgs: Record ReactElement> = { + 0: (translateX: number) => ( + + ), + 1: (translateX: number) => ( + + ), + 2: (translateX: number) => ( + + ), + 3: (translateX: number) => ( + + ), + 4: (translateX: number) => ( + <> + + + + ), + 5: (translateX: number) => ( + + ), + 6: (translateX: number) => ( + <> + + + + ), + 7: (translateX: number) => ( + + ), + 8: (translateX: number) => ( + <> + + + + ), + 9: (translateX: number) => ( + <> + + + + ), +}; diff --git a/src/model/privilege.ts b/src/model/privilege.ts new file mode 100644 index 00000000..2df7f763 --- /dev/null +++ b/src/model/privilege.ts @@ -0,0 +1,5 @@ +import { Privilege, PrivilegeWithAmount } from "@frontend/kitui"; + +export type ServiceKeyToPrivilegesMap = Record; + +export type PrivilegeWithoutPrice = Omit; diff --git a/src/model/tariff.ts b/src/model/tariff.ts new file mode 100644 index 00000000..39ebab6b --- /dev/null +++ b/src/model/tariff.ts @@ -0,0 +1,6 @@ +import { Tariff } from "@frontend/kitui"; + +export interface GetTariffsResponse { + totalPages: number; + tariffs: Tariff[]; +} diff --git a/src/pages/Tariffs/Tariffs.tsx b/src/pages/Tariffs/Tariffs.tsx new file mode 100644 index 00000000..44f2d77a --- /dev/null +++ b/src/pages/Tariffs/Tariffs.tsx @@ -0,0 +1,201 @@ +import { useLocation, useNavigate } from "react-router-dom"; +import { makeRequest } from "@frontend/kitui"; +import { useEffect, useState } from "react"; +import type { GetTariffsResponse } from "@model/tariff"; + +import { + Box, + Button, + Modal, + Paper, + Typography, + useMediaQuery, + useTheme, +} from "@mui/material"; +import { enqueueSnackbar } from "notistack"; +import { Tariff, getMessageFromFetchError } from "@frontend/kitui"; +import { withErrorBoundary } from "react-error-boundary"; +import { createTariffElements } from "./tariffsUtils/createTariffElements"; + +function TariffPage() { + const theme = useTheme(); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); + const location = useLocation(); + const navigate = useNavigate(); + + const [tariffs, setTariffs] = useState(); + const [user, setUser] = useState(); + const [discounts, setDiscounts] = useState(); + const [cartTariffMap, setCartTariffMap] = useState(); + const [openModal, setOpenModal] = useState({}); + + useEffect(() => { + const get = async () => { + const user = await makeRequest({ + method: "GET", + url: "https://squiz.pena.digital/customer/account", + }); + const tariffs = await makeRequest({ + method: "GET", + url: "https://squiz.pena.digital/strator/tariff?page=1&limit=100", + }); + const discounts = await makeRequest({ + method: "GET", + url: "https://squiz.pena.digital/price/discounts", + }); + setUser(user); + setTariffs(tariffs); + setDiscounts(discounts.Discounts); + }; + get(); + }, []); + + if (!user || !tariffs || !discounts) return ; + + console.log("user ", user); + console.log("tariffs ", tariffs); + console.log("discounts ", discounts); + + const openModalHC = (tariffInfo: any) => setOpenModal(tariffInfo); + const tryBuy = async ({ id, price }: { id: string, price: number }) => { + openModalHC({}) + //Если в корзине что-то было - выкладываем содержимое и запоминаем чо там лежало + if (user.cart.length > 0) { + outCart(user.cart) + } + //Если нам хватает денежек - покупаем тариф + if (price <= user.wallet.cash) { + try { + await makeRequest({ + method: "POST", + url: "https://suiz.pena.digital/customer/cart/pay" + }) + } catch (e) { + enqueueSnackbar("Произошла ошибка. Попробуйте позже") + } + //Развращаем товары в корзину + inCart() + } else { + //Деняк не хватило + navigate("https://hub.pena.digital/wallet?action=squizpay") + } + }; + + const purchasesAmount = user?.wallet.purchasesAmount ?? 0; + const isUserNko = user?.status === "nko"; + const filteredTariffs = tariffs.tariffs.filter((tariff) => { + return ( + tariff.privileges[0].serviceKey === "squiz" && + !tariff.isDeleted && + !tariff.isCustom + ); + }); + + return ( + <> + + {createTariffElements( + filteredTariffs, + true, + user, + discounts, + openModalHC, + )} + + 0} + onClose={() => setOpenModal({})} + > + + + Вы подтверждаете платёж в сумму {openModal.price} ₽ + + + + + + ); +} + +export default withErrorBoundary(TariffPage, { + fallback: ( + + Ошибка загрузки тарифов + + ), + onError: () => { }, +}); + +const LoadingPage = () => ( + + + {"Подождите, пожалуйста, идёт загрузка :)"} + + +); + +const inCart = () => { + let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]") + saveCart.forEach(async (id: string) => { + try { + await makeRequest({ + method: "PATCH", + url: `https://hub.pena.digital/customer/cart?id=${id}` + }) + + let index = saveCart.indexOf('green'); + if (index !== -1) { + saveCart.splice(index, 1); + } + localStorage.setItem("saveCart", JSON.stringify(saveCart)) + } catch (e) { + console.log("Я не смог добавить тариф в корзину :( " + id) + } + }) +} +const outCart = (cart: string[]) => { + //Сделаем муторно и подольше, зато при прерывании сессии данные потеряются минимально + cart.forEach(async (id: string) => { + try { + await makeRequest({ + method: "DELETE", + url: `https://suiz.pena.digital/customer/cart?id=${id}` + }) + let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]") + saveCart = saveCart.push(id) + localStorage.setItem("saveCart", JSON.stringify(saveCart)) + } catch (e) { + console.log("Я не смог удалить из корзины тариф :(") + } + }) +} + + diff --git a/src/pages/Tariffs/tariffsUtils/FreeTariffCard.tsx b/src/pages/Tariffs/tariffsUtils/FreeTariffCard.tsx new file mode 100644 index 00000000..a5aaab30 --- /dev/null +++ b/src/pages/Tariffs/tariffsUtils/FreeTariffCard.tsx @@ -0,0 +1,33 @@ +import Typography from "@mui/material/Typography"; +import TariffCard from "./TariffCard"; +import NumberIcon from "@icons/NumberIcon"; +import { useTheme } from "@mui/material"; + +export default function FreeTariffCard() { + const theme = useTheme(); + + return ( + } + discount={""} + headerText="бесплатно" + text="Первые 14 дней после регистрации, вы можете пользоваться полным функционалом сервиса совершенно бесплатно" + price={ + + 0 руб. + + } + sx={{ + backgroundColor: "#7e2aea", + color: "white", + }} + buttonProps={{ + text: "Выбрать", + sx: { + color: "white", + borderColor: "white", + }, + }} + /> + ); +} diff --git a/src/pages/Tariffs/tariffsUtils/TariffCard.tsx b/src/pages/Tariffs/tariffsUtils/TariffCard.tsx new file mode 100644 index 00000000..ae5a21cc --- /dev/null +++ b/src/pages/Tariffs/tariffsUtils/TariffCard.tsx @@ -0,0 +1,145 @@ +import { + Box, + Typography, + Tooltip, + SxProps, + Theme, + Button, + Badge, +} from "@mui/material"; +import { MouseEventHandler, ReactNode } from "react"; + +interface Props { + icon: ReactNode; + headerText: string; + discount?: string; + text: string | string[]; + sx?: SxProps; + buttonProps?: { + sx?: SxProps; + onClick?: MouseEventHandler; + text?: string; + }; + price?: ReactNode; +} + +export default function TariffCard({ + icon, + headerText, + text, + sx, + price, + buttonProps, + discount, +}: Props) { + text = Array.isArray(text) ? text : [text]; + + return ( + + + {icon} + {price && ( + + {price} + + )} + + {discount && discount !== "0%" && ( + + -{discount} + + )} + + {headerText}} placement="top"> + + {headerText} + + + ( + {line} + ))} + placement="top" + > + + {text.map((line, index) => ( + + {line} + + ))} + + + {buttonProps && ( + + )} + + ); +} diff --git a/src/pages/Tariffs/tariffsUtils/calcCart.ts b/src/pages/Tariffs/tariffsUtils/calcCart.ts new file mode 100644 index 00000000..b2a3f74f --- /dev/null +++ b/src/pages/Tariffs/tariffsUtils/calcCart.ts @@ -0,0 +1,250 @@ +import { + CartData, + Discount, + PrivilegeCartData, + Tariff, + TariffCartData, + findPrivilegeDiscount, + findDiscountFactor, + applyLoyaltyDiscount, +} from "@frontend/kitui"; + +function applyPrivilegeDiscounts(cartData: CartData, discounts: Discount[]) { + cartData.services.forEach((service) => { + const privMap = new Map(); + service.tariffs.forEach((tariff) => + tariff.privileges.forEach((p) => { + privMap.set( + p.privilegeId, + p.amount + (privMap.get(p.privilegeId) || 0), + ); + }), + ); + + service.tariffs.forEach((tariff) => { + tariff.privileges.forEach((privilege) => { + const privilegeDiscount = findPrivilegeDiscount( + privilege.privilegeId, + privMap.get(privilege.privilegeId) || 0, + discounts, + ); + if (!privilegeDiscount) return; + + const discountAmount = + privilege.price * (1 - findDiscountFactor(privilegeDiscount)); + privilege.price -= discountAmount; + cartData.allAppliedDiscounts.push(privilegeDiscount); + privilege.appliedPrivilegeDiscount = privilegeDiscount; + + tariff.price -= discountAmount; + service.price -= discountAmount; + cartData.priceAfterDiscounts -= discountAmount; + }); + }); + }); +} +function findServiceDiscount( + serviceKey: string, + currentPrice: number, + discounts: Discount[], +): Discount | null { + const applicableDiscounts = discounts.filter((discount) => { + return ( + discount.Layer === 2 && + discount.Condition.Group === serviceKey && + currentPrice >= Number(discount.Condition.PriceFrom) + ); + }); + + if (!applicableDiscounts.length) return null; + + const maxValueDiscount = applicableDiscounts.reduce((prev, current) => { + return Number(current.Condition.PriceFrom) > + Number(prev.Condition.PriceFrom) + ? current + : prev; + }); + + return maxValueDiscount; +} + +function findCartDiscount( + cartPurchasesAmount: number, + discounts: Discount[], +): Discount | null { + const applicableDiscounts = discounts.filter((discount) => { + return ( + discount.Layer === 3 && + cartPurchasesAmount >= Number(discount.Condition.CartPurchasesAmount) + ); + }); + console.log("FCD", applicableDiscounts); + + if (!applicableDiscounts.length) return null; + + const maxValueDiscount = applicableDiscounts.reduce((prev, current) => { + return Number(current.Condition.CartPurchasesAmount) > + Number(prev.Condition.CartPurchasesAmount) + ? current + : prev; + }); + + return maxValueDiscount; +} + +function applyCartDiscount(cartData: CartData, discounts: Discount[]) { + const cartDiscount = findCartDiscount( + cartData.priceAfterDiscounts, + discounts, + ); + if (!cartDiscount) return; + + cartData.priceAfterDiscounts *= findDiscountFactor(cartDiscount); + cartData.allAppliedDiscounts.push(cartDiscount); + cartData.appliedCartPurchasesDiscount = cartDiscount; +} + +function applyServiceDiscounts(cartData: CartData, discounts: Discount[]) { + const privMap = new Map(); + cartData.services.forEach((service) => { + service.tariffs.forEach((tariff) => + tariff.privileges.forEach((p) => { + privMap.set(p.serviceKey, p.price + (privMap.get(p.serviceKey) || 0)); + }), + ); + }); + + cartData.services.forEach((service) => { + service.tariffs.map((tariff) => { + tariff.privileges.forEach((privilege) => { + const privilegeDiscount = findServiceDiscount( + privilege.serviceKey, + privMap.get(privilege.serviceKey), + discounts, + ); + if (!privilegeDiscount) return; + + const discountAmount = + privilege.price * (1 - findDiscountFactor(privilegeDiscount)); + privilege.price -= discountAmount; + cartData.allAppliedDiscounts.push(privilegeDiscount); + service.appliedServiceDiscount = privilegeDiscount; + + tariff.price -= discountAmount; + service.price -= discountAmount; + cartData.priceAfterDiscounts -= discountAmount; + }); + }); + }); +} + +export function calcCart( + tariffs: Tariff[], + discounts: Discount[], + purchasesAmount: number, + isUserNko?: boolean, +): CartData { + const cartData: CartData = { + services: [], + priceBeforeDiscounts: 0, + priceAfterDiscounts: 0, + itemCount: 0, + appliedCartPurchasesDiscount: null, + appliedLoyaltyDiscount: null, + allAppliedDiscounts: [], + }; + + tariffs.forEach((tariff) => { + if (tariff.price !== undefined && tariff.privileges.length !== 1) + throw new Error("Price is defined for tariff with several"); + + let serviceData = cartData.services.find( + (service) => service.serviceKey === "custom" && tariff.isCustom, + ); + if (!serviceData && !tariff.isCustom) + serviceData = cartData.services.find( + (service) => service.serviceKey === tariff.privileges[0].serviceKey, + ); + + if (!serviceData) { + serviceData = { + serviceKey: tariff.isCustom + ? "custom" + : tariff.privileges[0].serviceKey, + tariffs: [], + price: 0, + appliedServiceDiscount: null, + }; + cartData.services.push(serviceData); + } + + const tariffCartData: TariffCartData = { + price: tariff.price ?? 0, + isCustom: tariff.isCustom, + privileges: [], + id: tariff._id, + name: tariff.name, + }; + serviceData.tariffs.push(tariffCartData); + + tariff.privileges.forEach((privilege) => { + let privilegePrice = privilege.amount * privilege.price; + if (!tariff.price) tariffCartData.price += privilegePrice; + else privilegePrice = tariff.price; + + const privilegeCartData: PrivilegeCartData = { + serviceKey: privilege.serviceKey, + privilegeId: privilege.privilegeId, + description: privilege.description, + price: privilegePrice, + amount: privilege.amount, + appliedPrivilegeDiscount: null, + }; + + tariffCartData.privileges.push(privilegeCartData); + cartData.priceAfterDiscounts += privilegePrice; + cartData.itemCount++; + }); + + cartData.priceBeforeDiscounts += tariffCartData.price; + serviceData.price += tariffCartData.price; + }); + + const nkoDiscount = findNkoDiscount(discounts); + if (isUserNko && nkoDiscount) { + applyNkoDiscount(cartData, nkoDiscount); + } else { + applyPrivilegeDiscounts(cartData, discounts); + applyServiceDiscounts(cartData, discounts); + applyCartDiscount(cartData, discounts); + applyLoyaltyDiscount(cartData, discounts, purchasesAmount); + } + + cartData.allAppliedDiscounts = Array.from( + new Set(cartData.allAppliedDiscounts), + ); + + return cartData; +} + +function applyNkoDiscount(cartData: CartData, discount: Discount) { + cartData.priceAfterDiscounts *= discount.Target.Factor; + cartData.allAppliedDiscounts.push(discount); +} + +export function findNkoDiscount(discounts: Discount[]): Discount | null { + const applicableDiscounts = discounts.filter( + (discount) => discount.Condition.UserType === "nko", + ); + + if (!applicableDiscounts.length) return null; + + const maxValueDiscount = applicableDiscounts.reduce((prev, current) => { + return current.Condition.CartPurchasesAmount > + prev.Condition.CartPurchasesAmount + ? current + : prev; + }); + + return maxValueDiscount; +} diff --git a/src/pages/Tariffs/tariffsUtils/calcTariffPrices.ts b/src/pages/Tariffs/tariffsUtils/calcTariffPrices.ts new file mode 100644 index 00000000..42dd1d6b --- /dev/null +++ b/src/pages/Tariffs/tariffsUtils/calcTariffPrices.ts @@ -0,0 +1,54 @@ +import { Discount, Tariff, findDiscountFactor } from "@frontend/kitui"; +import { calcCart } from "./calcCart"; + +export function calcIndividualTariffPrices( + tariff: Tariff, + discounts: Discount[], + purchasesAmount: number, + currentTariffs: Tariff[], + isUserNko?: boolean, +): { + priceBeforeDiscounts: number; + priceAfterDiscounts: number; +} { + const priceBeforeDiscounts = + tariff.price || + tariff.privileges.reduce( + (sum, privilege) => sum + privilege.amount * privilege.price, + 0, + ); + let priceAfterDiscounts = 0; + + const cart = calcCart( + [...currentTariffs, tariff], + discounts, + purchasesAmount, + isUserNko, + ); + if (cart.allAppliedDiscounts[0]?.Target.Overhelm) + return { + priceBeforeDiscounts: priceBeforeDiscounts, + priceAfterDiscounts: + priceBeforeDiscounts * cart.allAppliedDiscounts[0].Target.Factor, + }; + cart.services.forEach((s) => { + if (s.serviceKey === tariff.privileges[0].serviceKey) { + let processed = false; + s.tariffs.forEach((t) => { + if (t.id === tariff._id && !processed) { + processed = true; + t.privileges.forEach((p) => (priceAfterDiscounts += p.price)); + } + }); + priceAfterDiscounts *= findDiscountFactor(s.appliedServiceDiscount); + } + }); + priceAfterDiscounts *= findDiscountFactor(cart.appliedLoyaltyDiscount); + priceAfterDiscounts *= findDiscountFactor(cart.appliedCartPurchasesDiscount); + + // cart.allAppliedDiscounts.forEach((discount) => { + // priceAfterDiscounts *= findDiscountFactor(discount) + // }) + //priceAfterDiscounts = cart.priceAfterDiscounts + return { priceBeforeDiscounts, priceAfterDiscounts }; +} diff --git a/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx new file mode 100644 index 00000000..4d5ff78d --- /dev/null +++ b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx @@ -0,0 +1,76 @@ +import { Tariff } from "@frontend/kitui"; +import TariffCard from "./TariffCard"; +import NumberIcon from "@icons/NumberIcon"; +import { calcIndividualTariffPrices } from "./calcTariffPrices"; +import { currencyFormatter } from "./currencyFormatter"; +import FreeTariffCard from "./FreeTariffCard"; +import { Typography, useTheme } from "@mui/material"; + +export const createTariffElements = ( + filteredTariffs: Tariff[], + addFreeTariff = false, + user: any, + discounts: any, + onclick: any, +) => { + const theme = useTheme(); + const tariffElements = filteredTariffs + .filter((tariff) => tariff.privileges.length > 0) + .map((tariff, index) => { + const { priceBeforeDiscounts, priceAfterDiscounts } = + calcIndividualTariffPrices( + tariff, + discounts, + user.purchasesAmount, + [], + user.isUserNko, + ); + + return ( + + } + buttonProps={{ + text: "Выбрать", + onClick: () => onclick({id: tariff._id, price: priceBeforeDiscounts / 100}), + }} + headerText={tariff.name} + text={tariff.privileges.map((p) => `${p.name} - ${p.amount}`)} + price={ + <> + {priceBeforeDiscounts !== priceAfterDiscounts && ( + + {currencyFormatter.format(priceBeforeDiscounts / 100)} + + )} + + {currencyFormatter.format(priceAfterDiscounts / 100)} + + + } + /> + ); + }); + + if (addFreeTariff) { + if (tariffElements.length < 6) + tariffElements.push(); + else tariffElements.splice(5, 0, ); + } + + return tariffElements; +}; diff --git a/src/pages/Tariffs/tariffsUtils/currencyFormatter.ts b/src/pages/Tariffs/tariffsUtils/currencyFormatter.ts new file mode 100644 index 00000000..5924c6bd --- /dev/null +++ b/src/pages/Tariffs/tariffsUtils/currencyFormatter.ts @@ -0,0 +1,6 @@ +export const currencyFormatter = new Intl.NumberFormat("ru", { + currency: "RUB", + style: "currency", + compactDisplay: "short", + minimumFractionDigits: 0, +}); diff --git a/src/ui_kit/Header/Header.tsx b/src/ui_kit/Header/Header.tsx index 8a891dd5..68cd4850 100755 --- a/src/ui_kit/Header/Header.tsx +++ b/src/ui_kit/Header/Header.tsx @@ -94,6 +94,7 @@ export default function Header() { */} + а я типа обычный хедер )} + ); } diff --git a/src/ui_kit/Header/NavMenuItem.tsx b/src/ui_kit/Header/NavMenuItem.tsx index fe4dd953..d602c3c8 100755 --- a/src/ui_kit/Header/NavMenuItem.tsx +++ b/src/ui_kit/Header/NavMenuItem.tsx @@ -17,6 +17,7 @@ export default function NavMenuItem({ return ( + я есть навбар меню итем + я подписан как навбар коллапсед { + return ( + + + + ); +}; From f1abade62bb9ade6e89c0e17f008cddff6bf9f53 Mon Sep 17 00:00:00 2001 From: Tamara Date: Thu, 4 Jan 2024 01:55:01 +0300 Subject: [PATCH 2/9] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B2=D0=BE=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=88=D0=B0?= =?UTF-8?q?=D0=BF=D0=BA=D0=B8=20=D0=B8=20=D1=81=D0=B0=D0=B9=D0=B4=D0=B1?= =?UTF-8?q?=D0=B0=D1=80=D0=B0(=D0=BD=D1=83=D0=B6=D0=BD=D0=B0=20=D0=B4?= =?UTF-8?q?=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 41 ++- src/pages/DesignPage/DesignPage.tsx | 12 +- src/pages/Tariffs/Tariffs.tsx | 347 +++++++++--------- .../tariffsUtils/createTariffElements.tsx | 3 +- src/pages/main.tsx | 181 ++++++++- src/pages/startPage/EditPage.tsx | 204 +++++----- src/pages/startPage/Header.tsx | 12 +- 7 files changed, 496 insertions(+), 304 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 2b2460fe..09a95a93 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -101,20 +101,41 @@ export function useUserAccountFetcher({ dayjs.locale("ru"); const routeslink = [ - { path: "/list", page: , header: false, sidebar: false }, { - path: "/questions/:quizId", - page: , + path: "/list", + page: , + header: false, + sidebar: false, + footer: false, + }, + { + path: "/tariffs", + page: , + header: true, + sidebar: false, + footer: false, + }, + { + path: "/edit", + page: , header: true, sidebar: true, + footer: true, + }, + { + path: "/view", + page: , + header: false, + sidebar: false, + footer: false, + }, + { + path: "/design", + page: , + header: true, + sidebar: true, + footer: true, }, - { path: "/contacts", page: , header: true, sidebar: true }, - { path: "/result", page: , header: true, sidebar: true }, - { path: "/settings", page: , header: true, sidebar: true }, - { path: "/tariffs", page: , header: true, sidebar: false }, - { path: "/edit", page: , header: true, sidebar: true }, - { path: "/view", page: , header: false, sidebar: false }, - { path: "/design", page: , header: true, sidebar: true }, ] as const; export default function App() { diff --git a/src/pages/DesignPage/DesignPage.tsx b/src/pages/DesignPage/DesignPage.tsx index d35b5c51..94c5f547 100644 --- a/src/pages/DesignPage/DesignPage.tsx +++ b/src/pages/DesignPage/DesignPage.tsx @@ -82,13 +82,13 @@ export const DesignPage = () => { ); return ( <> -
+ {/*
*/} - {isMobile ? ( - - ) : ( - - )} + {/*{isMobile ? (*/} + {/* */} + {/*) : (*/} + {/* */} + {/*)}*/} {createPortal(, document.body)} diff --git a/src/pages/Tariffs/Tariffs.tsx b/src/pages/Tariffs/Tariffs.tsx index 44f2d77a..b1c20050 100644 --- a/src/pages/Tariffs/Tariffs.tsx +++ b/src/pages/Tariffs/Tariffs.tsx @@ -4,13 +4,13 @@ import { useEffect, useState } from "react"; import type { GetTariffsResponse } from "@model/tariff"; import { - Box, - Button, - Modal, - Paper, - Typography, - useMediaQuery, - useTheme, + Box, + Button, + Modal, + Paper, + Typography, + useMediaQuery, + useTheme, } from "@mui/material"; import { enqueueSnackbar } from "notistack"; import { Tariff, getMessageFromFetchError } from "@frontend/kitui"; @@ -18,184 +18,191 @@ import { withErrorBoundary } from "react-error-boundary"; import { createTariffElements } from "./tariffsUtils/createTariffElements"; function TariffPage() { - const theme = useTheme(); - const isTablet = useMediaQuery(theme.breakpoints.down(1000)); - const location = useLocation(); - const navigate = useNavigate(); + const theme = useTheme(); + const isTablet = useMediaQuery(theme.breakpoints.down(1000)); + const location = useLocation(); + const navigate = useNavigate(); - const [tariffs, setTariffs] = useState(); - const [user, setUser] = useState(); - const [discounts, setDiscounts] = useState(); - const [cartTariffMap, setCartTariffMap] = useState(); - const [openModal, setOpenModal] = useState({}); + const [tariffs, setTariffs] = useState(); + const [user, setUser] = useState(); + const [discounts, setDiscounts] = useState(); + const [cartTariffMap, setCartTariffMap] = useState(); + const [openModal, setOpenModal] = useState({}); - useEffect(() => { - const get = async () => { - const user = await makeRequest({ - method: "GET", - url: "https://squiz.pena.digital/customer/account", - }); - const tariffs = await makeRequest({ - method: "GET", - url: "https://squiz.pena.digital/strator/tariff?page=1&limit=100", - }); - const discounts = await makeRequest({ - method: "GET", - url: "https://squiz.pena.digital/price/discounts", - }); - setUser(user); - setTariffs(tariffs); - setDiscounts(discounts.Discounts); - }; - get(); - }, []); - - if (!user || !tariffs || !discounts) return ; - - console.log("user ", user); - console.log("tariffs ", tariffs); - console.log("discounts ", discounts); - - const openModalHC = (tariffInfo: any) => setOpenModal(tariffInfo); - const tryBuy = async ({ id, price }: { id: string, price: number }) => { - openModalHC({}) - //Если в корзине что-то было - выкладываем содержимое и запоминаем чо там лежало - if (user.cart.length > 0) { - outCart(user.cart) - } - //Если нам хватает денежек - покупаем тариф - if (price <= user.wallet.cash) { - try { - await makeRequest({ - method: "POST", - url: "https://suiz.pena.digital/customer/cart/pay" - }) - } catch (e) { - enqueueSnackbar("Произошла ошибка. Попробуйте позже") - } - //Развращаем товары в корзину - inCart() - } else { - //Деняк не хватило - navigate("https://hub.pena.digital/wallet?action=squizpay") - } + useEffect(() => { + const get = async () => { + const user = await makeRequest({ + method: "GET", + url: "https://squiz.pena.digital/customer/account", + }); + const tariffs = await makeRequest({ + method: "GET", + url: "https://squiz.pena.digital/strator/tariff?page=1&limit=100", + }); + const discounts = await makeRequest({ + method: "GET", + url: "https://squiz.pena.digital/price/discounts", + }); + setUser(user); + setTariffs(tariffs); + setDiscounts(discounts.Discounts); }; + get(); + }, []); - const purchasesAmount = user?.wallet.purchasesAmount ?? 0; - const isUserNko = user?.status === "nko"; - const filteredTariffs = tariffs.tariffs.filter((tariff) => { - return ( - tariff.privileges[0].serviceKey === "squiz" && - !tariff.isDeleted && - !tariff.isCustom - ); - }); + if (!user || !tariffs || !discounts) return ; + console.log("user ", user); + console.log("tariffs ", tariffs); + console.log("discounts ", discounts); + + const openModalHC = (tariffInfo: any) => setOpenModal(tariffInfo); + const tryBuy = async ({ id, price }: { id: string; price: number }) => { + openModalHC({}); + //Если в корзине что-то было - выкладываем содержимое и запоминаем чо там лежало + if (user.cart.length > 0) { + outCart(user.cart); + } + //Если нам хватает денежек - покупаем тариф + if (price <= user.wallet.cash) { + try { + await makeRequest({ + method: "POST", + url: "https://suiz.pena.digital/customer/cart/pay", + }); + } catch (e) { + enqueueSnackbar("Произошла ошибка. Попробуйте позже"); + } + //Развращаем товары в корзину + inCart(); + } else { + //Деняк не хватило + navigate("https://hub.pena.digital/wallet?action=squizpay"); + } + }; + + const purchasesAmount = user?.wallet.purchasesAmount ?? 0; + const isUserNko = user?.status === "nko"; + const filteredTariffs = tariffs.tariffs.filter((tariff) => { return ( - <> - - {createTariffElements( - filteredTariffs, - true, - user, - discounts, - openModalHC, - )} - - 0} - onClose={() => setOpenModal({})} - > - - - Вы подтверждаете платёж в сумму {openModal.price} ₽ - - - - - + tariff.privileges[0].serviceKey === "squiz" && + !tariff.isDeleted && + !tariff.isCustom ); + }); + + return ( + <> + + {createTariffElements( + filteredTariffs, + true, + user, + discounts, + openModalHC, + )} + + 0} + onClose={() => setOpenModal({})} + > + + + Вы подтверждаете платёж в сумму {openModal.price} ₽ + + + + + + ); } export default withErrorBoundary(TariffPage, { - fallback: ( - - Ошибка загрузки тарифов - - ), - onError: () => { }, + fallback: ( + + Ошибка загрузки тарифов + + ), + onError: () => {}, }); const LoadingPage = () => ( - - - {"Подождите, пожалуйста, идёт загрузка :)"} - - + + + {"Подождите, пожалуйста, идёт загрузка :)"} + + ); const inCart = () => { - let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]") - saveCart.forEach(async (id: string) => { - try { - await makeRequest({ - method: "PATCH", - url: `https://hub.pena.digital/customer/cart?id=${id}` - }) + let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]"); + saveCart.forEach(async (id: string) => { + try { + await makeRequest({ + method: "PATCH", + url: `https://hub.pena.digital/customer/cart?id=${id}`, + }); - let index = saveCart.indexOf('green'); - if (index !== -1) { - saveCart.splice(index, 1); - } - localStorage.setItem("saveCart", JSON.stringify(saveCart)) - } catch (e) { - console.log("Я не смог добавить тариф в корзину :( " + id) - } - }) -} + let index = saveCart.indexOf("green"); + if (index !== -1) { + saveCart.splice(index, 1); + } + localStorage.setItem("saveCart", JSON.stringify(saveCart)); + } catch (e) { + console.log("Я не смог добавить тариф в корзину :( " + id); + } + }); +}; const outCart = (cart: string[]) => { - //Сделаем муторно и подольше, зато при прерывании сессии данные потеряются минимально - cart.forEach(async (id: string) => { - try { - await makeRequest({ - method: "DELETE", - url: `https://suiz.pena.digital/customer/cart?id=${id}` - }) - let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]") - saveCart = saveCart.push(id) - localStorage.setItem("saveCart", JSON.stringify(saveCart)) - } catch (e) { - console.log("Я не смог удалить из корзины тариф :(") - } - }) -} - - + //Сделаем муторно и подольше, зато при прерывании сессии данные потеряются минимально + cart.forEach(async (id: string) => { + try { + await makeRequest({ + method: "DELETE", + url: `https://suiz.pena.digital/customer/cart?id=${id}`, + }); + let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]"); + saveCart = saveCart.push(id); + localStorage.setItem("saveCart", JSON.stringify(saveCart)); + } catch (e) { + console.log("Я не смог удалить из корзины тариф :("); + } + }); +}; diff --git a/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx index 4d5ff78d..f552bb85 100644 --- a/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx +++ b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx @@ -46,7 +46,8 @@ export const createTariffElements = ( } buttonProps={{ text: "Выбрать", - onClick: () => onclick({id: tariff._id, price: priceBeforeDiscounts / 100}), + onClick: () => + onclick({ id: tariff._id, price: priceBeforeDiscounts / 100 }), }} headerText={tariff.name} text={tariff.privileges.map((p) => `${p.name} - ${p.amount}`)} diff --git a/src/pages/main.tsx b/src/pages/main.tsx index 311a6e8f..0aee0fe8 100755 --- a/src/pages/main.tsx +++ b/src/pages/main.tsx @@ -1,39 +1,202 @@ -import Header from "@ui_kit/Header/Header"; +import { Header } from "../../src/pages/startPage/Header"; import Sidebar from "@ui_kit/Sidebar"; import Box from "@mui/material/Box"; import { useTheme, useMediaQuery } from "@mui/material"; import HeaderFull from "@ui_kit/Header/HeaderFull"; +import { useState } from "react"; +import { SidebarMobile } from "./startPage/Sidebar/SidebarMobile"; +import { setShowConfirmLeaveModal } from "@root/uiTools/actions"; +import { setCurrentStep } from "@root/quizes/actions"; +import { useQuizStore } from "@root/quizes/store"; +import { SmallSwitchQuestionListGraph } from "@ui_kit/Toolbars/SmallSwitchQuestionListGraph"; +import { PanelSwitchQuestionListGraph } from "@ui_kit/Toolbars/PanelSwitchQuestionListGraph"; +import { ButtonTestPublication } from "@ui_kit/Toolbars/ButtonTestPublication"; +import { ButtonRecallQuiz } from "@ui_kit/Toolbars/ButtonRecallQuiz"; +import { Link } from "react-router-dom"; +import { LinkSimple } from "@icons/LinkSimple"; +import { useCurrentQuiz } from "@root/quizes/hooks"; +import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions"; +import { useQuestionsStore } from "@root/questions/store"; interface Props { sidebar: boolean; header?: boolean; + footer?: boolean; page: JSX.Element; } -export default function Main({ sidebar, header, page }: Props) { +export default function Main({ sidebar, header, footer, page }: Props) { const theme = useTheme(); + const quiz = useCurrentQuiz(); + const quizConfig = quiz?.config; + const { questions } = useQuestionsStore(); + const currentStep = useQuizStore((state) => state.currentStep); const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isMobileSm = useMediaQuery(theme.breakpoints.down(370)); + const isBranchingLogic = useMediaQuery(theme.breakpoints.down(1100)); + const isLinkButton = useMediaQuery(theme.breakpoints.down(708)); + const [mobileSidebar, setMobileSidebar] = useState(false); + const [nextStep, setNextStep] = useState(0); + const [openBranchingPage, setOpenBranchingPage] = useState(false); + const openBranchingPageHC = () => { + if (!openBranchingPage) { + deleteTimeoutedQuestions(questions, quiz); + } + setOpenBranchingPage((old) => !old); + }; + const isConditionMet = + [1].includes(currentStep) && quizConfig.type !== "form"; + + const changePage = (index: number) => { + if (currentStep === 2) { + setNextStep(index); + setShowConfirmLeaveModal(true); + + return; + } + + setCurrentStep(index); + }; return ( <> - {header ?
: } + {header ?
: } - {sidebar ? : <>} + {sidebar ? ( + <> + {isMobile ? ( + + ) : ( + + )} + + ) : ( + <> + )} - {page} + + {page} + + {footer ? ( + + {isConditionMet && + (isBranchingLogic ? ( + + ) : ( + + ))} + {/* Кнопка тестового просмотра */} + + {/* Кнопка отозвать */} + + {/* Ссылка */} + {quiz?.status === "start" && + (!isLinkButton ? ( + + https://hbpn.link/{quiz.qid} + + ) : ( + + + + ))} + {/* Маленькая кнопка ссылки */} + {isMobile && quiz?.status === "start" && ( + + + + )} + + ) : ( + <> + )} diff --git a/src/pages/startPage/EditPage.tsx b/src/pages/startPage/EditPage.tsx index ff8649ca..b5fe6a2d 100755 --- a/src/pages/startPage/EditPage.tsx +++ b/src/pages/startPage/EditPage.tsx @@ -157,7 +157,7 @@ export default function EditPage() { return ( <> -
+ {/*
*/} - {isMobile ? ( - - ) : ( - - )} + {/*{isMobile ? (*/} + {/* */} + {/*) : (*/} + {/* */} + {/*)}*/} - - {isConditionMet && - (isBranchingLogic ? ( - - ) : ( - - ))} - {/* Кнопка тестового просмотра */} - - {/* Кнопка отозвать */} - - {/* Ссылка */} - {quiz?.status === "start" && - (!isLinkButton ? ( - - https://hbpn.link/{quiz.qid} - - ) : ( - - - - ))} - {/* Маленькая кнопка ссылки */} - {isMobile && quiz?.status === "start" && ( - - - - )} - + {/**/} + {/* {isConditionMet &&*/} + {/* (isBranchingLogic ? (*/} + {/* */} + {/* ) : (*/} + {/* */} + {/* ))}*/} + {/* /!* Кнопка тестового просмотра *!/*/} + {/* */} + {/* /!* Кнопка отозвать *!/*/} + {/* */} + {/* /!* Ссылка *!/*/} + {/* {quiz?.status === "start" &&*/} + {/* (!isLinkButton ? (*/} + {/* */} + {/* https://hbpn.link/{quiz.qid}*/} + {/* */} + {/* ) : (*/} + {/* */} + {/* */} + {/* */} + {/* ))}*/} + {/* /!* Маленькая кнопка ссылки *!/*/} + {/* {isMobile && quiz?.status === "start" && (*/} + {/* */} + {/* */} + {/* */} + {/* )}*/} + {/**/} diff --git a/src/pages/startPage/Header.tsx b/src/pages/startPage/Header.tsx index 4789ba97..6100d001 100644 --- a/src/pages/startPage/Header.tsx +++ b/src/pages/startPage/Header.tsx @@ -80,12 +80,12 @@ export const Header = ({ setMobileSidebar }: HeaderProps) => { - updateQuiz(quiz.id, (quiz) => { - quiz.name = e.target.value; - }) - } + // value={quiz.name} + // onChange={(e) => + // updateQuiz(quiz.id, (quiz) => { + // quiz.name = e.target.value; + // }) + // } fullWidth id="project-name" placeholder="Название проекта окно" From 219041ead6fd87c6b74ddd5fdadd01a35b44fb60 Mon Sep 17 00:00:00 2001 From: Nastya Date: Thu, 4 Jan 2024 01:56:50 +0300 Subject: [PATCH 3/9] -- --- src/pages/Tariffs/Tariffs.tsx | 72 +++++++++++-------- .../tariffsUtils/createTariffElements.tsx | 3 +- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/pages/Tariffs/Tariffs.tsx b/src/pages/Tariffs/Tariffs.tsx index 44f2d77a..b2e630dd 100644 --- a/src/pages/Tariffs/Tariffs.tsx +++ b/src/pages/Tariffs/Tariffs.tsx @@ -20,7 +20,7 @@ import { createTariffElements } from "./tariffsUtils/createTariffElements"; function TariffPage() { const theme = useTheme(); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); - const location = useLocation(); + // const location = useLocation(); const navigate = useNavigate(); const [tariffs, setTariffs] = useState(); @@ -57,27 +57,31 @@ function TariffPage() { console.log("discounts ", discounts); const openModalHC = (tariffInfo: any) => setOpenModal(tariffInfo); - const tryBuy = async ({ id, price }: { id: string, price: number }) => { - openModalHC({}) + const tryBuy = async ({ id, price }: { id: string; price: number }) => { + openModalHC({}); //Если в корзине что-то было - выкладываем содержимое и запоминаем чо там лежало if (user.cart.length > 0) { - outCart(user.cart) + outCart(user.cart); } //Если нам хватает денежек - покупаем тариф if (price <= user.wallet.cash) { try { await makeRequest({ method: "POST", - url: "https://suiz.pena.digital/customer/cart/pay" - }) + url: "https://suiz.pena.digital/customer/cart/pay", + }); } catch (e) { - enqueueSnackbar("Произошла ошибка. Попробуйте позже") + enqueueSnackbar("Произошла ошибка. Попробуйте позже"); } //Развращаем товары в корзину - inCart() + inCart(); } else { //Деняк не хватило - navigate("https://hub.pena.digital/wallet?action=squizpay") + // history.pushState({}, null, "https://hub.pena.digital/wallet?action=squizpay"); + var link = document.createElement('a'); + link.href = `https://hub.pena.digital/payment?action=squizpay&dif=${(price - user.wallet) * 100}` + document.body.appendChild(link); + link.click(); } }; @@ -126,12 +130,20 @@ function TariffPage() { p: 4, display: "flex", justifyContent: "center", - flexDirection: "column" - }}> - + flexDirection: "column", + }} + > + Вы подтверждаете платёж в сумму {openModal.price} ₽ - + @@ -163,39 +175,37 @@ const LoadingPage = () => ( ); const inCart = () => { - let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]") + let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]"); saveCart.forEach(async (id: string) => { try { await makeRequest({ method: "PATCH", - url: `https://hub.pena.digital/customer/cart?id=${id}` - }) + url: `https://hub.pena.digital/customer/cart?id=${id}`, + }); - let index = saveCart.indexOf('green'); + let index = saveCart.indexOf("green"); if (index !== -1) { saveCart.splice(index, 1); } - localStorage.setItem("saveCart", JSON.stringify(saveCart)) + localStorage.setItem("saveCart", JSON.stringify(saveCart)); } catch (e) { - console.log("Я не смог добавить тариф в корзину :( " + id) + console.log("Я не смог добавить тариф в корзину :( " + id); } - }) -} + }); +}; const outCart = (cart: string[]) => { //Сделаем муторно и подольше, зато при прерывании сессии данные потеряются минимально cart.forEach(async (id: string) => { try { await makeRequest({ method: "DELETE", - url: `https://suiz.pena.digital/customer/cart?id=${id}` - }) - let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]") - saveCart = saveCart.push(id) - localStorage.setItem("saveCart", JSON.stringify(saveCart)) + url: `https://suiz.pena.digital/customer/cart?id=${id}`, + }); + let saveCart = JSON.parse(localStorage.getItem("saveCart") || "[]"); + saveCart = saveCart.push(id); + localStorage.setItem("saveCart", JSON.stringify(saveCart)); } catch (e) { - console.log("Я не смог удалить из корзины тариф :(") + console.log("Я не смог удалить из корзины тариф :("); } - }) -} - - + }); +}; diff --git a/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx index 4d5ff78d..f552bb85 100644 --- a/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx +++ b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx @@ -46,7 +46,8 @@ export const createTariffElements = ( } buttonProps={{ text: "Выбрать", - onClick: () => onclick({id: tariff._id, price: priceBeforeDiscounts / 100}), + onClick: () => + onclick({ id: tariff._id, price: priceBeforeDiscounts / 100 }), }} headerText={tariff.name} text={tariff.privileges.map((p) => `${p.name} - ${p.amount}`)} From 7c396f1f5099b51e5c1a1a6142469461ccbf645c Mon Sep 17 00:00:00 2001 From: Tamara Date: Thu, 4 Jan 2024 03:12:12 +0300 Subject: [PATCH 4/9] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B2=D0=BE=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=88=D0=B0?= =?UTF-8?q?=D0=BF=D0=BA=D0=B8=20=D0=B8=20=D1=81=D0=B0=D0=B9=D0=B4=D0=B1?= =?UTF-8?q?=D0=B0=D1=80=D0=B0+=D0=BD=D0=B8=D0=B6=D0=BD=D0=B5=D0=B5=20?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=8E(=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 23 ++-- src/pages/DesignPage/DesignPage.tsx | 13 -- src/pages/createQuize/MyQuizzesFull.tsx | 2 + src/pages/main.tsx | 48 +++++-- src/pages/startPage/EditPage.tsx | 159 ------------------------ 5 files changed, 51 insertions(+), 194 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 09a95a93..ff27dd94 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -101,13 +101,6 @@ export function useUserAccountFetcher({ dayjs.locale("ru"); const routeslink = [ - { - path: "/list", - page: , - header: false, - sidebar: false, - footer: false, - }, { path: "/tariffs", page: , @@ -122,13 +115,6 @@ const routeslink = [ sidebar: true, footer: true, }, - { - path: "/view", - page: , - header: false, - sidebar: false, - footer: false, - }, { path: "/design", page: , @@ -211,13 +197,20 @@ export default function App() { } /> + } /> + } /> }> {routeslink.map((e, i) => ( +
} /> ))} diff --git a/src/pages/DesignPage/DesignPage.tsx b/src/pages/DesignPage/DesignPage.tsx index 94c5f547..8940a67c 100644 --- a/src/pages/DesignPage/DesignPage.tsx +++ b/src/pages/DesignPage/DesignPage.tsx @@ -25,19 +25,6 @@ import QuizPreview from "@ui_kit/QuizPreview/QuizPreview"; export const DesignPage = () => { const quiz = useCurrentQuiz(); const { editQuizId } = useQuizStore(); - - useEffect(() => { - const getData = async () => { - const quizes = await quizApi.getList(); - setQuizes(quizes); - if (editQuizId) { - const questions = await questionApi.getList({ quiz_id: editQuizId }); - setQuestions(questions); - } - }; - getData(); - }, []); - const { showConfirmLeaveModal } = useUiTools(); const theme = useTheme(); const navigate = useNavigate(); diff --git a/src/pages/createQuize/MyQuizzesFull.tsx b/src/pages/createQuize/MyQuizzesFull.tsx index b0f15fe1..44c2099d 100644 --- a/src/pages/createQuize/MyQuizzesFull.tsx +++ b/src/pages/createQuize/MyQuizzesFull.tsx @@ -15,6 +15,7 @@ import { useNavigate } from "react-router-dom"; import { resetEditConfig } from "@root/quizes/actions"; import FirstQuiz from "./FirstQuiz"; import QuizCard from "./QuizCard"; +import HeaderFull from "@ui_kit/Header/HeaderFull"; interface Props { outerContainerSx?: SxProps; @@ -32,6 +33,7 @@ export default function MyQuizzesFull({ return ( <> + {quizes.length === 0 ? ( ) : ( diff --git a/src/pages/main.tsx b/src/pages/main.tsx index 0aee0fe8..50ca3118 100755 --- a/src/pages/main.tsx +++ b/src/pages/main.tsx @@ -3,10 +3,10 @@ import Sidebar from "@ui_kit/Sidebar"; import Box from "@mui/material/Box"; import { useTheme, useMediaQuery } from "@mui/material"; import HeaderFull from "@ui_kit/Header/HeaderFull"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { SidebarMobile } from "./startPage/Sidebar/SidebarMobile"; import { setShowConfirmLeaveModal } from "@root/uiTools/actions"; -import { setCurrentStep } from "@root/quizes/actions"; +import { setCurrentStep, setQuizes } from "@root/quizes/actions"; import { useQuizStore } from "@root/quizes/store"; import { SmallSwitchQuestionListGraph } from "@ui_kit/Toolbars/SmallSwitchQuestionListGraph"; import { PanelSwitchQuestionListGraph } from "@ui_kit/Toolbars/PanelSwitchQuestionListGraph"; @@ -17,6 +17,9 @@ import { LinkSimple } from "@icons/LinkSimple"; import { useCurrentQuiz } from "@root/quizes/hooks"; import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions"; import { useQuestionsStore } from "@root/questions/store"; +import { quizApi } from "@api/quiz"; +import { questionApi } from "@api/question"; +import { createResult, setQuestions } from "@root/questions/actions"; interface Props { sidebar: boolean; @@ -30,7 +33,34 @@ export default function Main({ sidebar, header, footer, page }: Props) { const quiz = useCurrentQuiz(); const quizConfig = quiz?.config; const { questions } = useQuestionsStore(); + const { editQuizId } = useQuizStore(); const currentStep = useQuizStore((state) => state.currentStep); + + useEffect(() => { + const getData = async () => { + const quizes = await quizApi.getList(); + setQuizes(quizes); + + if (editQuizId) { + const questions = await questionApi.getList({ quiz_id: editQuizId }); + + setQuestions(questions); + //Всегда должен существовать хоть 1 резулт - "line" + if ( + !questions?.find( + (q) => + (q.type === "result" && q.content.includes(':"line"')) || + q.content.includes(":'line'"), + ) + ) { + createResult(quiz?.backendId, "line"); + console.log("Я не нашёл линейный резулт и собираюсь создать новый"); + } + } + }; + getData(); + }, []); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobileSm = useMediaQuery(theme.breakpoints.down(370)); const isBranchingLogic = useMediaQuery(theme.breakpoints.down(1100)); @@ -45,6 +75,9 @@ export default function Main({ sidebar, header, footer, page }: Props) { } setOpenBranchingPage((old) => !old); }; + + if (!quizConfig) return <>; + const isConditionMet = [1].includes(currentStep) && quizConfig.type !== "form"; @@ -58,9 +91,10 @@ export default function Main({ sidebar, header, footer, page }: Props) { setCurrentStep(index); }; + return ( <> - {header ?
: } +
{page} - {footer ? ( + + {footer && ( )} - ) : ( - <> )} diff --git a/src/pages/startPage/EditPage.tsx b/src/pages/startPage/EditPage.tsx index b5fe6a2d..3b4a15c8 100755 --- a/src/pages/startPage/EditPage.tsx +++ b/src/pages/startPage/EditPage.tsx @@ -41,65 +41,22 @@ import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; import { ModalInfoWhyCantCreate } from "./ModalInfoWhyCantCreate"; import { ConfirmLeaveModal } from "./ConfirmLeaveModal"; import { checkQuestionHint } from "@utils/checkQuestionHint"; -import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions"; -import { toggleQuizPreview } from "@root/quizPreview"; -import { LinkSimple } from "@icons/LinkSimple"; -import { SmallSwitchQuestionListGraph } from "@ui_kit/Toolbars/SmallSwitchQuestionListGraph"; -import { PanelSwitchQuestionListGraph } from "@ui_kit/Toolbars/PanelSwitchQuestionListGraph"; -import { ButtonTestPublication } from "@ui_kit/Toolbars/ButtonTestPublication"; -import { ButtonRecallQuiz } from "@ui_kit/Toolbars/ButtonRecallQuiz"; export default function EditPage() { const quiz = useCurrentQuiz(); const { editQuizId } = useQuizStore(); const { questions } = useQuestionsStore(); console.log(questions); - - useEffect(() => { - const getData = async () => { - const quizes = await quizApi.getList(); - setQuizes(quizes); - - if (editQuizId) { - const questions = await questionApi.getList({ quiz_id: editQuizId }); - - setQuestions(questions); - //Всегда должен существовать хоть 1 резулт - "line" - if ( - !questions?.find( - (q) => - (q.type === "result" && q.content.includes(':"line"')) || - q.content.includes(":'line'"), - ) - ) { - createResult(quiz?.backendId, "line"); - console.log("Я не нашёл линейный резулт и собираюсь создать новый"); - } - } - }; - getData(); - }, []); - const { whyCantCreatePublic, showConfirmLeaveModal } = useUiTools(); const theme = useTheme(); const navigate = useNavigate(); const currentStep = useQuizStore((state) => state.currentStep); const isBranchingLogic = useMediaQuery(theme.breakpoints.down(1100)); const isMobile = useMediaQuery(theme.breakpoints.down(660)); - const isLinkButton = useMediaQuery(theme.breakpoints.down(708)); - const isMobileSm = useMediaQuery(theme.breakpoints.down(370)); - const [mobileSidebar, setMobileSidebar] = useState(false); const [nextStep, setNextStep] = useState(0); const quizConfig = quiz?.config; const [openBranchingPage, setOpenBranchingPage] = useState(false); - const openBranchingPageHC = () => { - if (!openBranchingPage) { - deleteTimeoutedQuestions(questions, quiz); - } - setOpenBranchingPage((old) => !old); - }; - useEffect(() => { if (editQuizId === null) navigate("/list"); }, [navigate, editQuizId]); @@ -144,33 +101,14 @@ export default function EditPage() { const isConditionMet = [1].includes(currentStep) && quizConfig.type !== "form"; - const changePage = (index: number) => { - if (currentStep === 2) { - setNextStep(index); - setShowConfirmLeaveModal(true); - - return; - } - - setCurrentStep(index); - }; - return ( <> - {/*
*/} - - {/*{isMobile ? (*/} - {/* */} - {/*) : (*/} - {/* */} - {/*)}*/} - )} - - {/**/} - {/* {isConditionMet &&*/} - {/* (isBranchingLogic ? (*/} - {/* */} - {/* ) : (*/} - {/* */} - {/* ))}*/} - {/* /!* Кнопка тестового просмотра *!/*/} - {/* */} - {/* /!* Кнопка отозвать *!/*/} - {/* */} - {/* /!* Ссылка *!/*/} - {/* {quiz?.status === "start" &&*/} - {/* (!isLinkButton ? (*/} - {/* */} - {/* https://hbpn.link/{quiz.qid}*/} - {/* */} - {/* ) : (*/} - {/* */} - {/* */} - {/* */} - {/* ))}*/} - {/* /!* Маленькая кнопка ссылки *!/*/} - {/* {isMobile && quiz?.status === "start" && (*/} - {/* */} - {/* */} - {/* */} - {/* )}*/} - {/**/} From 97b2d3ac979f844ef8896dcfc4e925a0274d6210 Mon Sep 17 00:00:00 2001 From: Tamara Date: Thu, 4 Jan 2024 05:04:44 +0300 Subject: [PATCH 5/9] =?UTF-8?q?=D0=BD=D0=B5=20=D0=BE=D1=82=D0=BA=D1=80?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0=20=D0=B2=D0=B5=D1=82=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 8 +- src/pages/DesignPage/DesignFilling.tsx | 14 -- src/pages/DesignPage/DesignPage.tsx | 10 +- src/pages/Questions/QuestionsPage.tsx | 2 +- .../SwitchBranchingPanel/QuestionsList.tsx | 2 +- src/pages/Tariffs/Tariffs.tsx | 2 + src/pages/main.tsx | 36 +++- src/pages/startPage/EditPage.tsx | 4 +- src/pages/startPage/Header.tsx | 178 ------------------ src/ui_kit/Header/Header.tsx | 111 ++++++++--- .../Sidebar/SidebarMobile.tsx | 0 .../Sidebar/SidebarModal/index.tsx | 0 .../Sidebar/icons/ArrowDown.tsx | 0 .../Sidebar/icons/ChartLineUp.tsx | 0 .../Sidebar/icons/Pencil.tsx | 0 .../Sidebar/icons/People.tsx | 0 .../Sidebar/icons/Question.tsx | 0 .../Sidebar/icons/ReturnTime.tsx | 0 .../Sidebar/icons/Settings.tsx | 0 19 files changed, 124 insertions(+), 243 deletions(-) delete mode 100644 src/pages/startPage/Header.tsx mode change 100755 => 100644 src/ui_kit/Header/Header.tsx rename src/{pages/startPage => ui_kit}/Sidebar/SidebarMobile.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/SidebarModal/index.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/icons/ArrowDown.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/icons/ChartLineUp.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/icons/Pencil.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/icons/People.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/icons/Question.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/icons/ReturnTime.tsx (100%) rename src/{pages/startPage => ui_kit}/Sidebar/icons/Settings.tsx (100%) diff --git a/src/App.tsx b/src/App.tsx index ff27dd94..e94417e5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -101,13 +101,6 @@ export function useUserAccountFetcher({ dayjs.locale("ru"); const routeslink = [ - { - path: "/tariffs", - page: , - header: true, - sidebar: false, - footer: false, - }, { path: "/edit", page: , @@ -199,6 +192,7 @@ export default function App() { /> } /> } /> + } /> }> {routeslink.map((e, i) => ( { ))} - - - - - ); }; diff --git a/src/pages/DesignPage/DesignPage.tsx b/src/pages/DesignPage/DesignPage.tsx index 8940a67c..94a2c716 100644 --- a/src/pages/DesignPage/DesignPage.tsx +++ b/src/pages/DesignPage/DesignPage.tsx @@ -6,7 +6,7 @@ import { useQuizStore } from "@root/quizes/store"; import Sidebar from "@ui_kit/Sidebar"; import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { SidebarMobile } from "../startPage/Sidebar/SidebarMobile"; +import { SidebarMobile } from "../../ui_kit/Sidebar/SidebarMobile"; import { cleanQuestions, setQuestions } from "@root/questions/actions"; import { updateModalInfoWhyCantCreate, @@ -17,7 +17,7 @@ import { questionApi } from "@api/question"; import { useUiTools } from "@root/uiTools/store"; import { ConfirmLeaveModal } from "../startPage/ConfirmLeaveModal"; -import { Header } from "../startPage/Header"; +import { Header } from "@ui_kit/Header/Header"; import { DesignFilling } from "./DesignFilling"; import { createPortal } from "react-dom"; import QuizPreview from "@ui_kit/QuizPreview/QuizPreview"; @@ -69,13 +69,7 @@ export const DesignPage = () => { ); return ( <> - {/*
*/} - {/*{isMobile ? (*/} - {/* */} - {/*) : (*/} - {/* */} - {/*)}*/} {createPortal(, document.body)} diff --git a/src/pages/Questions/QuestionsPage.tsx b/src/pages/Questions/QuestionsPage.tsx index e08a5fa2..84e50667 100755 --- a/src/pages/Questions/QuestionsPage.tsx +++ b/src/pages/Questions/QuestionsPage.tsx @@ -85,6 +85,7 @@ export default function QuestionsPage({ display: "flex", justifyContent: "space-between", maxWidth: "796px", + position: "relative", }} > + - {page} + {footer && ( @@ -229,6 +231,20 @@ export default function Main({ sidebar, header, footer, page }: Props) { )} + + + + + )} diff --git a/src/pages/startPage/EditPage.tsx b/src/pages/startPage/EditPage.tsx index 3b4a15c8..74528fa6 100755 --- a/src/pages/startPage/EditPage.tsx +++ b/src/pages/startPage/EditPage.tsx @@ -20,7 +20,7 @@ import SwitchStepPages from "@ui_kit/switchStepPages"; import { useEffect, useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import { useDebouncedCallback } from "use-debounce"; -import { SidebarMobile } from "./Sidebar/SidebarMobile"; +import { SidebarMobile } from "../../ui_kit/Sidebar/SidebarMobile"; import { cleanQuestions, createResult, @@ -32,7 +32,7 @@ import { setShowConfirmLeaveModal, updateSomeWorkBackend, } from "@root/uiTools/actions"; -import { Header } from "./Header"; +import { Header } from "@ui_kit/Header/Header"; import { useQuestionsStore } from "@root/questions/store"; import { questionApi } from "@api/question"; import { useUiTools } from "@root/uiTools/store"; diff --git a/src/pages/startPage/Header.tsx b/src/pages/startPage/Header.tsx deleted file mode 100644 index 6100d001..00000000 --- a/src/pages/startPage/Header.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import { LogoutButton } from "@ui_kit/LogoutButton"; -import BackArrowIcon from "@icons/BackArrowIcon"; -import { Burger } from "@icons/Burger"; - -import { - Box, - Container, - FormControl, - IconButton, - TextField, - useMediaQuery, - useTheme, -} from "@mui/material"; -import { updateQuiz } from "@root/quizes/actions"; -import { useCurrentQuiz } from "@root/quizes/hooks"; -import CustomAvatar from "@ui_kit/Header/Avatar"; -import NavMenuItem from "@ui_kit/Header/NavMenuItem"; - -import { enqueueSnackbar } from "notistack"; -import { useState } from "react"; -import { Link, useNavigate } from "react-router-dom"; - -import Logotip from "../Landing/images/icons/QuizLogo"; -import { clearUserData } from "@root/user"; -import { clearAuthToken } from "@frontend/kitui"; -import { logout } from "@api/auth"; - -type HeaderProps = { - setMobileSidebar: (callback: (visible: boolean) => boolean) => void; -}; - -export const Header = ({ setMobileSidebar }: HeaderProps) => { - const quiz = useCurrentQuiz(); - const theme = useTheme(); - const navigate = useNavigate(); - const isTablet = useMediaQuery(theme.breakpoints.down(1000)); - const isMobile = useMediaQuery(theme.breakpoints.down(660)); - - async function handleLogoutClick() { - const [, logoutError] = await logout(); - - if (logoutError) { - return enqueueSnackbar(logoutError); - } - - clearAuthToken(); - clearUserData(); - navigate("/"); - } - - return ( - - - {isMobile ? : } - - - - - - - - - - // updateQuiz(quiz.id, (quiz) => { - // quiz.name = e.target.value; - // }) - // } - fullWidth - id="project-name" - placeholder="Название проекта окно" - sx={{ - width: "270px", - "& .MuiInputBase-root": { - height: "34px", - borderRadius: "8px", - p: 0, - }, - }} - inputProps={{ - sx: { - height: "20px", - borderRadius: "8px", - fontSize: "16px", - lineHeight: "20px", - p: "7px", - color: "black", - "&::placeholder": { - opacity: 1, - }, - }, - }} - /> - - - {isTablet ? ( - - {isMobile ? ( - setMobileSidebar((visible: boolean) => !visible)} - style={{ fontSize: "30px", color: "white", cursor: "pointer" }} - /> - ) : ( - - {/* */} - - )} - - ) : ( - <> - - {/* */} - {/* - - - */} - - - {/* */} - - - - )} - - ); -}; diff --git a/src/ui_kit/Header/Header.tsx b/src/ui_kit/Header/Header.tsx old mode 100755 new mode 100644 index 68cd4850..d8c29d75 --- a/src/ui_kit/Header/Header.tsx +++ b/src/ui_kit/Header/Header.tsx @@ -1,8 +1,9 @@ +import { LogoutButton } from "@ui_kit/LogoutButton"; import BackArrowIcon from "@icons/BackArrowIcon"; -import EyeIcon from "@icons/EyeIcon"; +import { Burger } from "@icons/Burger"; + import { Box, - Button, Container, FormControl, IconButton, @@ -10,15 +11,43 @@ import { useMediaQuery, useTheme, } from "@mui/material"; -import { decrementCurrentStep } from "@root/quizes/actions"; -import PenaLogo from "../PenaLogo"; -import CustomAvatar from "./Avatar"; -import NavMenuItem from "./NavMenuItem"; -import { Link } from "react-router-dom"; +import { updateQuiz } from "@root/quizes/actions"; +import { useCurrentQuiz } from "@root/quizes/hooks"; +import CustomAvatar from "@ui_kit/Header/Avatar"; +import NavMenuItem from "@ui_kit/Header/NavMenuItem"; -export default function Header() { +import { enqueueSnackbar } from "notistack"; +import { useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; + +import Logotip from "../../pages/Landing/images/icons/QuizLogo"; +import { clearUserData } from "@root/user"; +import { clearAuthToken } from "@frontend/kitui"; +import { logout } from "@api/auth"; +import { ToTariffsButton } from "@ui_kit/Toolbars/ToTariffsButton"; + +type HeaderProps = { + setMobileSidebar: (callback: (visible: boolean) => boolean) => void; +}; + +export const Header = ({ setMobileSidebar }: HeaderProps) => { + const quiz = useCurrentQuiz(); const theme = useTheme(); + const navigate = useNavigate(); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); + const isMobile = useMediaQuery(theme.breakpoints.down(600)); + + async function handleLogoutClick() { + const [, logoutError] = await logout(); + + if (logoutError) { + return enqueueSnackbar(logoutError); + } + + clearAuthToken(); + clearUserData(); + navigate("/"); + } return ( - - + + {isMobile ? : } - - - + + + + + + updateQuiz(quiz.id, (quiz) => { + quiz.name = e.target.value; + }) + } fullWidth id="project-name" placeholder="Название проекта окно" @@ -77,13 +114,37 @@ export default function Header() { /> - - {isTablet ? null : ( + {isTablet ? ( + + {isMobile ? ( + setMobileSidebar((visible: boolean) => !visible)} + style={{ fontSize: "30px", color: "white", cursor: "pointer" }} + /> + ) : ( + + {/* */} + + )} + + ) : ( <> */} - а я типа обычный хедер {/* */} + + )} ); -} +}; diff --git a/src/pages/startPage/Sidebar/SidebarMobile.tsx b/src/ui_kit/Sidebar/SidebarMobile.tsx similarity index 100% rename from src/pages/startPage/Sidebar/SidebarMobile.tsx rename to src/ui_kit/Sidebar/SidebarMobile.tsx diff --git a/src/pages/startPage/Sidebar/SidebarModal/index.tsx b/src/ui_kit/Sidebar/SidebarModal/index.tsx similarity index 100% rename from src/pages/startPage/Sidebar/SidebarModal/index.tsx rename to src/ui_kit/Sidebar/SidebarModal/index.tsx diff --git a/src/pages/startPage/Sidebar/icons/ArrowDown.tsx b/src/ui_kit/Sidebar/icons/ArrowDown.tsx similarity index 100% rename from src/pages/startPage/Sidebar/icons/ArrowDown.tsx rename to src/ui_kit/Sidebar/icons/ArrowDown.tsx diff --git a/src/pages/startPage/Sidebar/icons/ChartLineUp.tsx b/src/ui_kit/Sidebar/icons/ChartLineUp.tsx similarity index 100% rename from src/pages/startPage/Sidebar/icons/ChartLineUp.tsx rename to src/ui_kit/Sidebar/icons/ChartLineUp.tsx diff --git a/src/pages/startPage/Sidebar/icons/Pencil.tsx b/src/ui_kit/Sidebar/icons/Pencil.tsx similarity index 100% rename from src/pages/startPage/Sidebar/icons/Pencil.tsx rename to src/ui_kit/Sidebar/icons/Pencil.tsx diff --git a/src/pages/startPage/Sidebar/icons/People.tsx b/src/ui_kit/Sidebar/icons/People.tsx similarity index 100% rename from src/pages/startPage/Sidebar/icons/People.tsx rename to src/ui_kit/Sidebar/icons/People.tsx diff --git a/src/pages/startPage/Sidebar/icons/Question.tsx b/src/ui_kit/Sidebar/icons/Question.tsx similarity index 100% rename from src/pages/startPage/Sidebar/icons/Question.tsx rename to src/ui_kit/Sidebar/icons/Question.tsx diff --git a/src/pages/startPage/Sidebar/icons/ReturnTime.tsx b/src/ui_kit/Sidebar/icons/ReturnTime.tsx similarity index 100% rename from src/pages/startPage/Sidebar/icons/ReturnTime.tsx rename to src/ui_kit/Sidebar/icons/ReturnTime.tsx diff --git a/src/pages/startPage/Sidebar/icons/Settings.tsx b/src/ui_kit/Sidebar/icons/Settings.tsx similarity index 100% rename from src/pages/startPage/Sidebar/icons/Settings.tsx rename to src/ui_kit/Sidebar/icons/Settings.tsx From d35b65fc05e462be713c67f0bdd56b30585a3720 Mon Sep 17 00:00:00 2001 From: Tamara Date: Thu, 4 Jan 2024 14:00:13 +0300 Subject: [PATCH 6/9] =?UTF-8?q?fix:=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BB=D0=BE=D0=B3=D0=B8?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B2=D0=B5=D1=82=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B5=D0=BB=D0=BA=D0=B8=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 6 +++--- src/assets/icons/BackButtonIcon.tsx | 6 +++--- src/pages/main.tsx | 7 +++++-- src/pages/startPage/EditPage.tsx | 11 +++++++++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index e94417e5..66564c2a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -103,14 +103,14 @@ dayjs.locale("ru"); const routeslink = [ { path: "/edit", - page: , + page: EditPage, header: true, sidebar: true, footer: true, }, { path: "/design", - page: , + page: DesignPage, header: true, sidebar: true, footer: true, @@ -200,7 +200,7 @@ export default function App() { path={e.path} element={
( ); diff --git a/src/pages/main.tsx b/src/pages/main.tsx index f745a727..850e1c74 100755 --- a/src/pages/main.tsx +++ b/src/pages/main.tsx @@ -27,7 +27,7 @@ interface Props { sidebar: boolean; header?: boolean; footer?: boolean; - Page: JSX.Element; + Page?: React.Component; } export default function Main({ sidebar, header, footer, Page }: Props) { @@ -132,7 +132,10 @@ export default function Main({ sidebar, header, footer, Page }: Props) { boxSizing: "border-box", }} > - + {footer && ( diff --git a/src/pages/startPage/EditPage.tsx b/src/pages/startPage/EditPage.tsx index 74528fa6..cb50dd5f 100755 --- a/src/pages/startPage/EditPage.tsx +++ b/src/pages/startPage/EditPage.tsx @@ -42,7 +42,14 @@ import { ModalInfoWhyCantCreate } from "./ModalInfoWhyCantCreate"; import { ConfirmLeaveModal } from "./ConfirmLeaveModal"; import { checkQuestionHint } from "@utils/checkQuestionHint"; -export default function EditPage() { +interface Props { + openBranchingPage: boolean; + setOpenBranchingPage: (a: boolean) => void; +} +export default function EditPage({ + openBranchingPage, + setOpenBranchingPage, +}: Props) { const quiz = useCurrentQuiz(); const { editQuizId } = useQuizStore(); const { questions } = useQuestionsStore(); @@ -55,7 +62,7 @@ export default function EditPage() { const isMobile = useMediaQuery(theme.breakpoints.down(660)); const [nextStep, setNextStep] = useState(0); const quizConfig = quiz?.config; - const [openBranchingPage, setOpenBranchingPage] = useState(false); + // const [openBranchingPage, setOpenBranchingPage] = useState(false); useEffect(() => { if (editQuizId === null) navigate("/list"); From b1e1817685c275387917f2de284ac24a94c579f2 Mon Sep 17 00:00:00 2001 From: Tamara Date: Thu, 4 Jan 2024 18:18:29 +0300 Subject: [PATCH 7/9] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20=D1=88=D0=B0=D0=BF=D0=BA=D0=B8=20=D0=B2=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D0=BD=D1=8B=D1=85=20=D1=81=D0=BE=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=8F=D0=BD=D0=B8=D1=8F=D1=85(=D1=83=D0=B1=D1=80=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=B2=20=D0=BD=D0=B8=D1=85),=20=D0=B0=D0=B4?= =?UTF-8?q?=D0=B0=D0=BF=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B8=20=D1=80=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B8=D0=B7=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20+=20=D0=BC=D0=B5=D0=BB?= =?UTF-8?q?=D0=BA=D0=B8=D0=B5=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=B4=D0=B8=D0=B7=D0=B0=D0=B9=D0=BD=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AnswerDraggableList/AnswerItem.tsx | 64 ++++----- .../Questions/DataOptions/settingData.tsx | 2 +- .../Questions/DropDown/settingDropDown.tsx | 4 +- src/pages/Questions/Emoji/settingEmoji.tsx | 2 +- .../FormDraggableList/QuestionPageCard.tsx | 4 +- .../OwnTextField/settingTextField.tsx | 2 +- .../Questions/PageOptions/PageOptions.tsx | 136 ++++++++++++++++-- src/pages/Questions/QuestionsPage.tsx | 28 ++-- .../Questions/UploadFile/settingUpload.tsx | 11 +- .../UploadImage/UploadImageModal.tsx | 8 +- .../answerOptions/responseSettings.tsx | 2 +- src/pages/createQuize/MyQuizzesFull.tsx | 5 +- src/pages/createQuize/QuizCard.tsx | 1 + src/pages/main.tsx | 2 +- src/ui_kit/Header/Header.tsx | 93 ++++-------- src/ui_kit/Header/HeaderFull.tsx | 65 ++------- src/ui_kit/Modal/CropModal.tsx | 9 +- src/ui_kit/Sidebar.tsx | 6 +- src/ui_kit/Sidebar/SidebarMobile.tsx | 105 +++++++++++--- 19 files changed, 343 insertions(+), 206 deletions(-) diff --git a/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx b/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx index a62ff46f..6b6fc883 100644 --- a/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx +++ b/src/pages/Questions/AnswerDraggableList/AnswerItem.tsx @@ -108,38 +108,38 @@ export const AnswerItem = ({ ), endAdornment: ( - - - - - - setQuestionVariantAnswer(e.target.value || " ") - } - onKeyDown={( - event: KeyboardEvent, - ) => event.stopPropagation()} - /> - + {/**/} + {/* */} + {/**/} + {/**/} + {/* */} + {/* setQuestionVariantAnswer(e.target.value || " ")*/} + {/* }*/} + {/* onKeyDown={(*/} + {/* event: KeyboardEvent,*/} + {/* ) => event.stopPropagation()}*/} + {/* />*/} + {/**/} diff --git a/src/pages/Questions/DataOptions/settingData.tsx b/src/pages/Questions/DataOptions/settingData.tsx index 8115e2e2..39a4fd7d 100644 --- a/src/pages/Questions/DataOptions/settingData.tsx +++ b/src/pages/Questions/DataOptions/settingData.tsx @@ -75,7 +75,7 @@ export default function SettingsData({ question }: SettingsDataProps) { */} */} */} (false); + + const openedModal = () => { + updateDesireToOpenABranchingModal(question.content.id); + }; + const SSHC = (data: string) => { setSwitchState(data); }; @@ -59,12 +86,105 @@ export default function PageOptions({ disableInput, question }: Props) { - - + + + {/* + + */} + copyQuestion(question.id, question.quizId)} + > + + + { + if (question.type === null) { + deleteQuestion(question.id); + } + if (question.content.rule.parentId.length !== 0) { + setOpenDelete(true); + } else { + deleteQuestionWithTimeout(question.id, () => + DeleteFunction(questions, question, quiz), + ); + } + }} + data-cy="delete-question" + > + + + setOpenDelete(false)}> + + + Вы удаляете вопрос, участвующий в ветвлении. Все его потомки + потеряют данные ветвления. Вы уверены, что хотите удалить + вопрос? + + + + + + + + + + + {/**/} + {/**/} ); } diff --git a/src/pages/Questions/QuestionsPage.tsx b/src/pages/Questions/QuestionsPage.tsx index 84e50667..df8d2a24 100755 --- a/src/pages/Questions/QuestionsPage.tsx +++ b/src/pages/Questions/QuestionsPage.tsx @@ -62,19 +62,21 @@ export default function QuestionsPage({ {quiz.name ? quiz.name : "Заголовок quiz"} - + {!openBranchingPage && ( + + )} - Настройки вопроса + + Настройки вопросов + {/* = ({ const theme = useTheme(); const dropZone = useRef(null); const [ready, setReady] = useState(false); - + const isMobile = useMediaQuery(theme.breakpoints.down(600)); const handleDragEnter = (event: DragEvent) => { event.preventDefault(); setReady(true); @@ -65,7 +66,7 @@ export const UploadImageModal: React.FC = ({ top: "50%", left: "50%", transform: "translate(-50%, -50%)", - maxWidth: "690px", + maxWidth: isMobile ? "300px" : "690px", bgcolor: "background.paper", borderRadius: "12px", boxShadow: 24, @@ -106,13 +107,14 @@ export const UploadImageModal: React.FC = ({ ref={dropZone} sx={{ width: "580px", - padding: "33px 10px 33px 55px", + padding: isMobile ? "33px" : "33px 10px 33px 55px", display: "flex", alignItems: "center", backgroundColor: theme.palette.background.default, border: `1px solid ${ready ? "red" : theme.palette.grey2.main}`, borderRadius: "8px", gap: "55px", + flexDirection: isMobile ? "column" : undefined, }} onDragEnter={handleDragEnter} // Применяем обработчик onDragEnter напрямую > diff --git a/src/pages/Questions/answerOptions/responseSettings.tsx b/src/pages/Questions/answerOptions/responseSettings.tsx index 27b77271..51546395 100644 --- a/src/pages/Questions/answerOptions/responseSettings.tsx +++ b/src/pages/Questions/answerOptions/responseSettings.tsx @@ -98,7 +98,7 @@ export default function ResponseSettings({ question }: Props) { ) : ( - + diff --git a/src/pages/main.tsx b/src/pages/main.tsx index 850e1c74..dc944572 100755 --- a/src/pages/main.tsx +++ b/src/pages/main.tsx @@ -63,7 +63,7 @@ export default function Main({ sidebar, header, footer, Page }: Props) { getData(); }, []); - const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isMobile = useMediaQuery(theme.breakpoints.down(650)); const isMobileSm = useMediaQuery(theme.breakpoints.down(370)); const isBranchingLogic = useMediaQuery(theme.breakpoints.down(1100)); const isLinkButton = useMediaQuery(theme.breakpoints.down(708)); diff --git a/src/ui_kit/Header/Header.tsx b/src/ui_kit/Header/Header.tsx index d8c29d75..6e692666 100644 --- a/src/ui_kit/Header/Header.tsx +++ b/src/ui_kit/Header/Header.tsx @@ -35,7 +35,7 @@ export const Header = ({ setMobileSidebar }: HeaderProps) => { const theme = useTheme(); const navigate = useNavigate(); const isTablet = useMediaQuery(theme.breakpoints.down(1000)); - const isMobile = useMediaQuery(theme.breakpoints.down(600)); + const isMobile = useMediaQuery(theme.breakpoints.down(650)); async function handleLogoutClick() { const [, logoutError] = await logout(); @@ -65,7 +65,11 @@ export const Header = ({ setMobileSidebar }: HeaderProps) => { }} > - {isMobile ? : } + {isMobile ? ( + + ) : ( + + )} { } fullWidth id="project-name" - placeholder="Название проекта окно" + placeholder="Название проекта" sx={{ width: "270px", "& .MuiInputBase-root": { @@ -114,67 +118,32 @@ export const Header = ({ setMobileSidebar }: HeaderProps) => { /> - {isTablet ? ( - - {isMobile ? ( - setMobileSidebar((visible: boolean) => !visible)} - style={{ fontSize: "30px", color: "white", cursor: "pointer" }} - /> - ) : ( - - {/* */} - - )} - - ) : ( - <> - - {/* */} - {/* - - - */} - - - {/* + {isMobile ? ( + setMobileSidebar((visible: boolean) => !visible)} + style={{ fontSize: "30px", color: "white", cursor: "pointer" }} + /> + ) : ( + <> + */} - - - - - )} + > + + + + + )} + ); }; diff --git a/src/ui_kit/Header/HeaderFull.tsx b/src/ui_kit/Header/HeaderFull.tsx index 97dbaadb..e2074429 100644 --- a/src/ui_kit/Header/HeaderFull.tsx +++ b/src/ui_kit/Header/HeaderFull.tsx @@ -48,18 +48,12 @@ export default function HeaderFull() { height: "80px", alignItems: "center", gap: isTablet ? "20px" : "60px", - flexDirection: isMobile ? "row-reverse" : "row", + flexDirection: "row", justifyContent: isMobile ? "space-between" : "center", bgcolor: "white", borderBottom: "1px solid #E3E3E3", }} > - {isTablet && ( - setMobileSidebar(!mobileSidebar)} - style={{ fontSize: "30px", color: "#000000", cursor: "pointer" }} - /> - )} @@ -70,56 +64,15 @@ export default function HeaderFull() { gap: "30px", overflow: "hidden", }} - > - {/* - - - - - - */} - + > )} - - {/* {!isTablet && ( - <> - - - - - - Мой баланс - - - 00.00 руб. - - - - )} */} - {!isMobile && ( - <> - {/* */} - - - )} + + diff --git a/src/ui_kit/Modal/CropModal.tsx b/src/ui_kit/Modal/CropModal.tsx index 51ae9722..9d6b2988 100644 --- a/src/ui_kit/Modal/CropModal.tsx +++ b/src/ui_kit/Modal/CropModal.tsx @@ -170,6 +170,10 @@ export const CropModal: FC = ({ padding: "20px", borderRadius: "8px", width: isMobile ? "343px" : "620px", + height: isMobile ? "80vh" : undefined, + display: isMobile ? "flex" : undefined, + flexDirection: isMobile ? "column" : undefined, + justifyContent: isMobile ? "space-evenly" : undefined, }} > = ({ sx={[ styleSlider, { - width: isMobile ? "350px" : "250px", + width: isMobile ? undefined : "250px", }, ]} value={scale * 100} @@ -278,7 +282,7 @@ export const CropModal: FC = ({ sx={[ styleSlider, { - width: isMobile ? "350px" : "250px", + width: isMobile ? undefined : "250px", }, ]} value={darken} @@ -295,6 +299,7 @@ export const CropModal: FC = ({ width: "100%", display: "flex", gap: "10px", + flexWrap: isMobile ? "wrap" : undefined, }} >