Merge branch 'dev' into 'staging'

адаптация тарифов, увеличено огранчения для ввода ссылки на сайт пользователя,...

See merge request frontend/squiz!216
This commit is contained in:
Nastya 2024-03-19 21:55:26 +00:00
commit 7f11b79aac
22 changed files with 365 additions and 196 deletions

@ -105,12 +105,12 @@ export const DesignFilling = ({
<Box
sx={{
width: "100%",
padding: "25px",
height: isMobile
padding: isMobile
? mobileSidebar
? `calc(100vh - ${heightBar}px)`
: "calc(100vh - 127px)"
: "calc(100vh - 80px)",
? `calc(${heightBar}px - 92px) 16px 70px 16px`
: "67px 16px 70px 16px"
: "25px",
height: isMobile ? "100vh" : "calc(100vh - 80px)",
}}
>
<Typography variant="h5" sx={{ marginBottom: "40px", color: "#333647" }}>
@ -118,63 +118,79 @@ export const DesignFilling = ({
</Typography>
<Paper
sx={{
padding: "20px",
padding: "5px",
maxWidth: "796px",
width: "100%",
borderRadius: "12px",
height: "calc(100vh - 280px)",
overflow: "auto",
height: "calc(100vh - 300px)",
}}
>
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
<DesignGroup
title="Со светлым фоном"
value={quiz?.config.design ? "" : quiz?.config.theme || ""}
list={LIGHT_THEME_BUTTONS}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = false;
quiz.config.theme = name;
})
}
/>
<DesignGroup
title="С тёмным фоном"
value={quiz?.config.design ? "" : quiz?.config.theme || ""}
list={DARK_THEME_BUTTONS}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = false;
quiz.config.theme = name;
})
}
/>
</Box>
<Box>
<Divider sx={{ margin: "20px 0", background: "#7E2AEA33" }} />
</Box>
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
<DesignGroup
title="С картинкой"
value={quiz?.config.theme || ""}
list={DESIGNG_LIST_FIRST}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = true;
quiz.config.theme = name;
})
}
/>
<DesignGroup
value={quiz?.config.theme || ""}
list={DESIGNG_LIST_SECOND}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = true;
quiz.config.theme = name;
})
}
/>
<Box
sx={{
padding: "20px",
height: "100%",
overflow: "auto",
scrollbarWidth: "auto",
"&::-webkit-scrollbar": {
display: "block",
width: "8px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: theme.palette.brightPurple.main,
borderRadius: "4px",
},
}}
>
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
<DesignGroup
title="Со светлым фоном"
value={quiz?.config.design ? "" : quiz?.config.theme || ""}
list={LIGHT_THEME_BUTTONS}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = false;
quiz.config.theme = name;
})
}
/>
<DesignGroup
title="С тёмным фоном"
value={quiz?.config.design ? "" : quiz?.config.theme || ""}
list={DARK_THEME_BUTTONS}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = false;
quiz.config.theme = name;
})
}
/>
</Box>
<Box>
<Divider sx={{ margin: "20px 0", background: "#7E2AEA33" }} />
</Box>
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
<DesignGroup
title="С картинкой"
value={quiz?.config.theme || ""}
list={DESIGNG_LIST_FIRST}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = true;
quiz.config.theme = name;
})
}
/>
<DesignGroup
value={quiz?.config.theme || ""}
list={DESIGNG_LIST_SECOND}
onChange={(name) =>
updateQuiz(quiz?.id, (quiz) => {
quiz.config.design = true;
quiz.config.theme = name;
})
}
/>
</Box>
</Box>
</Paper>
</Box>

@ -3,10 +3,8 @@ import { Box, useMediaQuery, useTheme, Skeleton } from "@mui/material";
import { setQuizes, setCurrentStep } from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuizStore } from "@root/quizes/store";
import Sidebar from "@ui_kit/Sidebar/Sidebar";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { SidebarMobile } from "../../ui_kit/Sidebar/SidebarMobile";
import { cleanQuestions, setQuestions } from "@root/questions/actions";
import {
updateModalInfoWhyCantCreate,
@ -17,7 +15,6 @@ import { questionApi } from "@api/question";
import { useUiTools } from "@root/uiTools/store";
import { ConfirmLeaveModal } from "../startPage/ConfirmLeaveModal";
import { Header } from "@ui_kit/Header/Header";
import { DesignFilling } from "./DesignFilling";
import { createPortal } from "react-dom";
import QuizPreview from "@ui_kit/QuizPreview/QuizPreview";

@ -1,22 +1,23 @@
import React, { useState } from "react";
import {
Box,
Button,
ButtonBase,
FormControl,
IconButton,
InputAdornment,
Link,
MenuItem,
Modal,
OutlinedInput,
Paper,
Select,
SelectChangeEvent,
TextField,
Typography,
Tooltip,
useTheme, useMediaQuery,
Box,
Button,
ButtonBase,
FormControl,
IconButton,
InputAdornment,
Link,
MenuItem,
Modal,
OutlinedInput,
Paper,
Select,
SelectChangeEvent,
TextField,
Typography,
Tooltip,
useTheme,
useMediaQuery,
} from "@mui/material";
import LinkIcon from "../../assets/icons/LinkIcon";
import InfoIcon from "../../assets/icons/InfoIcon";
@ -41,7 +42,11 @@ import InBodyInstall from "./InBodyInstall";
import AutoOpenInstall from "./AutoOpenInstall";
import VidjetInstall from "./VidjetInstall";
import InstallQzCode from "./InstallQzCode";
import {decrementCurrentStep, incrementCurrentStep, updateQuiz} from "@root/quizes/actions";
import {
decrementCurrentStep,
incrementCurrentStep,
updateQuiz,
} from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
import { useDomainDefine } from "@utils/hooks/useDomainDefine";
import NumberTwo from "@icons/NumberTwo";
@ -56,7 +61,6 @@ export default function InstallQuiz() {
setDisplay(event.target.value);
};
const [openVk, setOpenVk] = React.useState(false);
const [stepState, setStepState] = React.useState("step1");
const handleOpenVk = () => setOpenVk(true);
@ -70,6 +74,7 @@ export default function InstallQuiz() {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600));
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1065));
const CopyLink = () => {
let one = document.getElementById("inputLinkone").value;
let text = document.getElementById("inputLink").value;
@ -101,16 +106,22 @@ export default function InstallQuiz() {
"0px 100px 309px rgba(210, 208, 225, 0.24), 0px 41.7776px 129.093px rgba(210, 208, 225, 0.172525), 0px 22.3363px 69.0192px rgba(210, 208, 225, 0.143066), 0px 12.5216px 38.6916px rgba(210, 208, 225, 0.12), 0px 6.6501px 20.5488px rgba(210, 208, 225, 0.0969343), 0px 2.76726px 8.55082px rgba(210, 208, 225, 0.0674749)",
}}
>
<Box sx={{ display: "flex", alignItems: isMobile ? "flex-start" : "center", gap: "10px", flexDirection: isMobile ? "column" : "row" }}>
<Box sx={{display: "flex", alignItems: "center", gap: "10px"}}>
<LinkIcon
color={theme.palette.brightPurple.main}
bgcolor={"#EEE4FC"}
/>
<Typography>Ссылка на quiz</Typography>
<Box
sx={{
display: "flex",
alignItems: isMobile ? "flex-start" : "center",
gap: "10px",
flexDirection: isMobile ? "column" : "row",
}}
>
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
<LinkIcon
color={theme.palette.brightPurple.main}
bgcolor={"#EEE4FC"}
/>
<Typography>Ссылка на quiz</Typography>
</Box>
{/*<Tooltip*/}
{/* title="Скопируйте или укажите свою ссылку на quiz. Ссылка должна быть от 4 до 20 символов включительно, может содержать латинские буквы, цифры, тире '-' и нижнее подчеркивание '_'."*/}
{/* placement="top"*/}
@ -282,9 +293,16 @@ export default function InstallQuiz() {
"0px 100px 309px rgba(210, 208, 225, 0.24), 0px 41.7776px 129.093px rgba(210, 208, 225, 0.172525), 0px 22.3363px 69.0192px rgba(210, 208, 225, 0.143066), 0px 12.5216px 38.6916px rgba(210, 208, 225, 0.12), 0px 6.6501px 20.5488px rgba(210, 208, 225, 0.0969343), 0px 2.76726px 8.55082px rgba(210, 208, 225, 0.0674749)",
}}
>
<Box sx={{ display: "flex", alignItems: isMobile ? "flex-start" : "center", gap: "30px", flexDirection: isMobile ? "column" : "row" }}>
<Box
sx={{
display: "flex",
alignItems: isSmallMonitor ? "flex-start" : "center",
gap: "30px",
flexDirection: isSmallMonitor ? "column" : "row",
}}
>
<Typography variant="h5" sx={{ paddingRight: "30px" }}>
Установка квизов на сайте
Установка quiz на сайте
</Typography>
<ButtonBase
onClick={() => {
@ -382,9 +400,9 @@ export default function InstallQuiz() {
gap: "20px",
}}
>
<Typography>1. Код вставки опросника</Typography>
<Typography>1. Код вставки quiz</Typography>
<Typography sx={{ color: theme.palette.grey2.main }}>
Установите код в то место, где должен быть опросник
Установите код в то место, где должен быть quiz
</Typography>
<TextField
id="outlined-multiline-static"
@ -453,7 +471,7 @@ export default function InstallQuiz() {
gap: "8px",
justifyContent: "end",
mt: "30px",
mr: "60px"
mr: "60px",
}}
>
<Button

@ -20,6 +20,7 @@ import {
addNode,
isElementANode,
isNodeInViewport,
isQuestionProhibited,
storeToNodes,
} from "./helper";
@ -47,7 +48,6 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
(acc, node) => ((acc[node.data.id] = {}), acc),
{},
);
return (
<Box
sx={{
@ -80,18 +80,19 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
cleardragQuestionContentId();
}}
/>,
!csElement.data.isRoot && (
(!csElement.data.isRoot && !isQuestionProhibited(csElement.data.qtype)) && (
<CsSettingsButton
key={`settings-${csElement.data.id}`}
ref={(r) => {
const buttonData = buttonRefsById.current[csElement.data.id];
if (buttonData) buttonData.settings = r;
}}
onClick={() => {
updateOpenedModalSettingsId(csElement.data.id);
}}
onClick={() => {
updateOpenedModalSettingsId(csElement.data.id,);
}}
/>
),
//оболочка узла
<CsSelectButton
key={`select-${csElement.data.id}`}
ref={(r) => {
@ -100,7 +101,8 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
}}
onClick={() => {
setModalQuestionParentContentId(csElement.data.id);
setOpenedModalQuestions(true);
console.log("csElement ", csElement)
setOpenedModalQuestions(!(isQuestionProhibited(csElement.data.type) && csElement.data.children > 0));
}}
/>,
])}

@ -1,3 +1,4 @@
import { QuestionType } from "@model/question/question";
import { QuizQuestionResult } from "@model/questionTypes/result";
import {
AnyTypedQuizQuestion,
@ -22,7 +23,10 @@ export interface Node {
isRoot: boolean;
id: string;
label: string;
qtype: string;
type: string;
parent?: string;
children: number;
};
classes: string;
}
@ -55,17 +59,23 @@ export const storeToNodes = (questions: AnyTypedQuizQuestion[]) => {
const edges: Edge[] = [];
questions.forEach((question) => {
if (question.content.rule.parentId) {
const parentQuestion = {
...getQuestionByContentId(question.content.rule.parentId),
} as AnyTypedQuizQuestion;
let label =
question.title === "" || question.title === " "
? "noname"
: question.title;
if (label.length > 25) label = label.slice(0, 25) + "…";
if (label.length > 10) label = label.slice(0, 10).toLowerCase() + "…";
nodes.push({
data: {
isRoot: question.content.rule.parentId === "root",
id: question.content.id,
label,
qtype: question.content.rule.parentId === "root" ? "root" : parentQuestion.type,
type: question.type,
children: question.content.rule.children.length
},
classes: "multiline-auto",
});
@ -330,6 +340,18 @@ export const addNode = ({
//запрещаем работу родителя-ребенка если это один и тот же вопрос
if (parentNodeContentId === targetNodeContentId) return;
//У 4 типов вопросов не может быть больше 1 потомка
const parentQuestion = {
...getQuestionByContentId(parentNodeContentId),
} as AnyTypedQuizQuestion;
if ((parentQuestion.type !== undefined && isQuestionProhibited(parentQuestion.type)) &&
parentQuestion.content.rule.children.length > 0
) {
enqueueSnackbar("у вопроса этого типа может быть только 1 потомок");
return;
}
//если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
const targetQuestion = {
...getQuestionByContentId(
@ -341,6 +363,13 @@ export const addNode = ({
clearDataAfterAddNode({ parentNodeContentId, targetQuestion });
createResult(useQuizStore.getState().editQuizId, targetQuestion.content.id);
} else {
enqueueSnackbar("Добавляемый вопрос не найден");
enqueueSnackbar("Добавляемый вопрос не найден. Перетащите вопрос из списка");
}
};
export const isQuestionProhibited = (parentQType: string) => (
parentQType === "text" ||
parentQType === "date" ||
parentQType === "number" ||
parentQType === "page"
)

@ -39,6 +39,7 @@ import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
export default function BranchingQuestions() {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const isSmallMobile = useMediaQuery(theme.breakpoints.down(400));
const { openedModalSettingsId } = useUiTools();
const [targetQuestion, setTargetQuestion] =
useState<AnyTypedQuizQuestion | null>(
@ -119,7 +120,23 @@ export default function BranchingQuestions() {
}}
>
<Box sx={{ color: "#4d4d4d" }}>
<Typography component="span">{targetQuestion.title}</Typography>
<Typography
component="span"
sx={{
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
maxWidth: isSmallMobile
? "250px"
: isMobile
? "350px"
: "450px",
display: "inline-block",
width: "100%",
}}
>
{targetQuestion.title}
</Typography>
</Box>
{isMobile ? (
<TooltipClickInfo

@ -29,6 +29,7 @@ import {
useTheme,
} from "@mui/material";
import {
collapseAllQuestions,
copyQuestion,
deleteQuestion,
deleteQuestionWithTimeout,
@ -99,7 +100,8 @@ const QuestionPageCardTitle = memo<Props>(function ({
display: "flex",
alignItems: "center",
padding: isMobile ? "10px" : "20px 10px 20px 20px",
flexDirection: isMobile ? "column" : null,
flexDirection: "row",
flexWrap: isMobile && isExpanded ? "wrap" : "nowrap",
}}
>
<FormControl
@ -109,6 +111,9 @@ const QuestionPageCardTitle = memo<Props>(function ({
maxWidth: isTablet ? "549px" : "640px",
width: "100%",
marginRight: isMobile ? "0px" : "16.1px",
display: "flex",
flexDirection: "row",
flexBasis: isMobile && isExpanded ? "calc(100% - 30px)" : null,
}}
>
<TextField
@ -161,6 +166,7 @@ const QuestionPageCardTitle = memo<Props>(function ({
),
}}
sx={{
flexGrow: 1,
margin: isMobile ? "10px 0" : 0,
"& .MuiInputBase-root": {
color: "#000000",
@ -181,6 +187,21 @@ const QuestionPageCardTitle = memo<Props>(function ({
}}
/>
</FormControl>
<IconButton
disableRipple
sx={{
order: isMobile && isExpanded ? "0" : "1",
padding: isMobile ? "0" : "0 5px",
right: isMobile ? "0" : null,
bottom: isMobile ? "0" : null,
marginLeft: !isMobile && isExpanded ? "10px" : null,
}}
{...draggableProps}
onMouseDown={collapseAllQuestions}
onTouchStart={collapseAllQuestions}
>
<PointsIcon style={{ color: "#4D4D4D", fontSize: "30px" }} />
</IconButton>
<Box
sx={{
display: "flex",
@ -324,17 +345,6 @@ const QuestionPageCardTitle = memo<Props>(function ({
{page + 1}
</Box>
)}
<IconButton
disableRipple
sx={{
padding: isMobile ? "0" : "0 5px",
right: isMobile ? "0" : null,
bottom: isMobile ? "0" : null,
}}
{...draggableProps}
>
<PointsIcon style={{ color: "#4D4D4D", fontSize: "30px" }} />
</IconButton>
</Box>
</Box>
);

@ -1,18 +1,24 @@
import { useEffect } from "react";
import { Box } from "@mui/material";
import { reorderQuestions } from "@root/questions/actions";
import type { DropResult } from "react-beautiful-dnd";
import { DragDropContext, Droppable } from "react-beautiful-dnd";
import DraggableListItem from "./DraggableListItem";
import { useQuestions } from "@root/questions/hooks";
import { createUntypedQuestion } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
interface Props {
openBranchingPage: boolean;
setOpenBranchingPage: (a: boolean) => void;
}
export const DraggableList = ({
openBranchingPage,
setOpenBranchingPage,
}: Props) => {
const { questions } = useQuestions();
const quiz = useCurrentQuiz();
const { isLoading, questions } = useQuestions();
const filteredQuestions = questions.filter(
(question) => question.type !== "result",
);
@ -20,6 +26,12 @@ export const DraggableList = ({
if (destination) reorderQuestions(source.index, destination.index);
};
useEffect(() => {
if (!isLoading && quiz && !filteredQuestions.length) {
createUntypedQuestion(Number(quiz.id));
}
}, [quiz, filteredQuestions]);
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable-list">

@ -84,13 +84,8 @@ export default function QuestionsPage({
>
{!openBranchingPage && (
<IconButton
onClick={() => {
createUntypedQuestion(quiz.backendId);
}}
sx={{
position: "fixed",
bottom: "103px",
}}
onClick={() => createUntypedQuestion(quiz.backendId)}
sx={{ position: "fixed", bottom: "103px" }}
data-cy="create-question"
>
<AddPlus />

@ -63,10 +63,37 @@ export const CardAnswer = ({
const { editQuizId } = useQuizStore();
const { questions } = useQuestionsStore();
const openResults = async () => {
setIsOpen(!isOpen);
if (!isOpen) {
try {
let resAnswer = await resultApi.getAnswerList(Number(idResult));
let resAnswerOnly = resAnswer.filter((res) => res.Result !== true);
let resQuiz = resAnswer.filter((res) => res.Result === true);
setResultQuiz(resQuiz);
setResultsAnswer(resAnswerOnly);
let idResults = resQuiz[0].question_id;
let questionsResult = questions.filter(
(q) => q.backendId === idResults,
);
setQuestionsResultState(questionsResult);
console.log("тут хранятся ответы", resAnswerOnly);
} catch (nativeError) {
const error = nativeError as AxiosError;
if (error.response?.statusText === "Payment Required") {
openPrePaymentModal();
}
}
}
};
return (
<Box
onClick={() => {
obsolescenceResult(idResult, editQuizId);
openResults();
}}
sx={{
borderRadius: "12px",
@ -129,39 +156,7 @@ export const CardAnswer = ({
>
{idResult}
</Box>
<IconButton
onClick={async () => {
setIsOpen(!isOpen);
if (!isOpen) {
try {
let resAnswer = await resultApi.getAnswerList(
Number(idResult),
);
let resAnswerOnly = resAnswer.filter(
(res) => res.Result !== true,
);
let resQuiz = resAnswer.filter(
(res) => res.Result === true,
);
setResultQuiz(resQuiz);
setResultsAnswer(resAnswerOnly);
let idResults = resQuiz[0].question_id;
let questionsResult = questions.filter(
(q) => q.backendId === idResults,
);
setQuestionsResultState(questionsResult);
console.log("тут хранятся ответы", resAnswerOnly);
} catch (nativeError) {
const error = nativeError as AxiosError;
if (error.response?.statusText === "Payment Required") {
openPrePaymentModal();
}
}
}
}}
>
<IconButton onClick={openResults}>
<ArrowDownIcon
style={{
transform: isOpen ? "rotate(180deg)" : "rotate(360deg)",

@ -128,9 +128,9 @@ export const QuizAnswersPage: FC = () => {
return (
<Box>
<HeaderFull isRequest={true} />
<HeaderFull isRequest={true} sx={{ position: "fixed", zIndex: 9 }} />
<SectionWrapper
sx={{ padding: isMobile ? "0 16px" : "20px" }}
sx={{ padding: isMobile ? "115px 16px" : "115px 20px 20px" }}
maxWidth="lg"
>
<Typography
@ -138,8 +138,9 @@ export const QuizAnswersPage: FC = () => {
fontSize: "36px",
fontWeight: "500",
mb: "50px",
mt: "60px",
lineHeight: "normal",
wordBreak: "break-word",
}}
>
{quiz.name}

@ -31,6 +31,7 @@ import { currencyFormatter } from "./tariffsUtils/currencyFormatter";
import type { Tariff } from "@frontend/kitui";
import { Tabs } from "./Tabs";
import { cleanAuthTicketData } from "@root/ticket";
import { useDomainDefine } from "@utils/hooks/useDomainDefine";
const StepperText: Record<string, string> = {
count: "Тарифы на объём",
@ -41,6 +42,7 @@ function TariffPage() {
const theme = useTheme();
const token = useToken();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(600));
const userId = useUserStore((state) => state.userId);
const location = useLocation();
const navigate = useNavigate();
@ -52,6 +54,7 @@ function TariffPage() {
const [openModal, setOpenModal] = useState({});
const [cash, setCash] = useState("0");
const [selectedItem, setSelectedItem] = useState<"count" | "day">("count");
const { isTestServer } = useDomainDefine();
const getTariffsList = async (): Promise<Tariff[]> => {
const tariffsList: Tariff[] = [];
@ -132,11 +135,9 @@ function TariffPage() {
// history.pushState({}, null, "https://hub.pena.digital/wallet?action=squizpay");
var link = document.createElement("a");
link.href =
"https://hub.pena.digital" +
`/quizpayment?action=squizpay&dif=${
(price - Number(user.wallet.cash)) * 100
}&data=${token}&userid=${userId}
link.href = `https://${isTestServer ? "s" : ""}hub.pena.digital/quizpayment?action=squizpay&dif=${
(price - Number(user.wallet.cash)) * 100
}&data=${token}&userid=${userId}
`;
document.body.appendChild(link);
link.click();
@ -175,7 +176,7 @@ function TariffPage() {
display: "flex",
height: "80px",
alignItems: "center",
gap: isTablet ? "20px" : "60px",
gap: isMobile ? "7px" : isTablet ? "20px" : "60px",
flexDirection: "row",
justifyContent: "space-between",
bgcolor: "white",
@ -189,7 +190,7 @@ function TariffPage() {
<ArrowLeft color="black" />
</IconButton>
<Box sx={{ display: "flex", ml: "auto" }}>
<Box sx={{ whiteSpace: "nowrap" }}>
<Box sx={{ whiteSpace: "nowrap" }} onClick={() => console.log(cash)}>
<Typography
sx={{
fontSize: "12px",
@ -199,7 +200,11 @@ function TariffPage() {
>
Мой баланс
</Typography>
<Typography variant="body2" color={"#7e2aea"}>
<Typography
variant="body2"
color={"#7e2aea"}
fontSize={isMobile ? (cash.length > 9 ? "13px" : "16px") : "16px"}
>
{cash}
</Typography>
</Box>

@ -6,6 +6,8 @@ import {
Theme,
Button,
Badge,
useTheme,
useMediaQuery,
} from "@mui/material";
import { MouseEventHandler, ReactNode } from "react";
@ -33,7 +35,8 @@ export default function TariffCard({
discount,
}: Props) {
text = Array.isArray(text) ? text : [text];
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600));
return (
<Box
sx={{
@ -68,6 +71,7 @@ export default function TariffCard({
flexWrap: "wrap",
columnGap: "10px",
rowGap: 0,
flexDirection: isMobile ? "column-reverse" : undefined,
}}
>
{price}

@ -95,6 +95,7 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
const [widthMain, setWidthMain] = useState(null);
const [heightSidebar, setHeightSidebar] = useState(null);
const [scrollDown, setScrollDown] = useState<boolean | null>(null);
const mainBlock = useRef(0);
const heightHeader = heightSidebar + 51 + 36;
const observer = useRef(
@ -111,7 +112,7 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
if (!quizConfig) return <></>;
return (
<>
<Header setMobileSidebar={setMobileSidebar} />
<Header setMobileSidebar={setMobileSidebar} scrollDown={scrollDown} />
<Box
sx={{
display: "flex",
@ -125,6 +126,7 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
open={mobileSidebar}
changePage={changePage}
setHeightSitebar={setHeightSidebar}
scrollDown={scrollDown}
/>
) : (
<Sidebar changePage={changePage} />
@ -137,9 +139,10 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
sx={{
width: "100%",
height: isMobile
? mobileSidebar
? `calc(100vh - ${heightHeader}px)`
: "calc(100vh - 51px)"
? // ? mobileSidebar
// ? `calc(100vh - ${heightHeader}px)`
// "calc(100vh - 51px)"
"100vh"
: "calc(100vh - 80px)",
display: "flex",
flexDirection: "column",
@ -162,6 +165,8 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
widthMain={widthMain}
mobileSidebar={mobileSidebar}
heightSidebar={heightSidebar}
scrollDown={scrollDown}
setScrollDown={setScrollDown}
/>
</Box>
@ -182,6 +187,8 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
background: "#FFF",
borderTop: "#f2f3f7 2px solid",
zIndex: 1,
position: isMobile ? "fixed" : undefined,
bottom: isMobile ? 0 : undefined,
}}
>
{isConditionMet &&

@ -17,7 +17,7 @@ import { useQuizStore } from "@root/quizes/store";
import Sidebar from "@ui_kit/Sidebar/Sidebar";
import Stepper from "@ui_kit/Stepper";
import SwitchStepPages from "@ui_kit/switchStepPages";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { useDebouncedCallback } from "use-debounce";
import { SidebarMobile } from "../../ui_kit/Sidebar/SidebarMobile";
@ -48,6 +48,8 @@ interface Props {
widthMain: number;
mobileSidebar: boolean;
heightSidebar: number;
scrollDown: boolean;
setScrollDown: (a: boolean) => void;
}
export default function EditPage({
openBranchingPage,
@ -55,6 +57,8 @@ export default function EditPage({
widthMain,
mobileSidebar,
heightSidebar,
scrollDown,
setScrollDown,
}: Props) {
const quiz = useCurrentQuiz();
const { editQuizId } = useQuizStore();
@ -67,8 +71,9 @@ export default function EditPage({
const isMobile = useMediaQuery(theme.breakpoints.down(650));
const quizConfig = quiz?.config;
// const [openBranchingPage, setOpenBranchingPage] = useState<boolean>(false);
const mainBlock = useRef(0);
const heightBar = heightSidebar + 51 + 88 + 23;
const heightBar = heightSidebar + 51 + 88;
useEffect(() => {
if (editQuizId === null) navigate("/list");
}, [navigate, editQuizId]);
@ -108,6 +113,17 @@ export default function EditPage({
setCurrentStep(nextStep);
};
let lastScroll = mainBlock.current.scrollTop;
const onScroll = (e) => {
if ((mainBlock.current.scrollTop > lastScroll && !scrollDown) || null) {
setScrollDown(true);
}
if (mainBlock.current.scrollTop < lastScroll && scrollDown) {
setScrollDown(false);
}
lastScroll = mainBlock.current.scrollTop;
};
if (!quizConfig) return <></>;
const isConditionMet =
@ -129,19 +145,25 @@ export default function EditPage({
}}
>
<Box
onScroll={onScroll}
ref={mainBlock}
sx={{
padding: isMobile ? "16px 16px 20px 16px" : "25px 25px 20px 25px",
padding: isMobile
? mobileSidebar
? `${heightBar}px 16px 70px 16px`
: "67px 16px 70px 16px"
: "25px 25px 20px 25px",
overflow: "auto",
height: isMobile
? mobileSidebar
? `calc(100vh - ${heightBar}px)`
: `calc(100vh - 125px)`
? "100vh"
: isConditionMet
? isBranchingLogic
? `calc(100vh - 166px)`
: `calc(100vh - 186px)`
: `calc(100vh - 166px)`,
boxSizing: "border-box",
transition: "transform 0.3s",
paddingBottom: scrollDown && isMobile ? "120px" : undefined,
}}
>
{/* Выбор текущей страницы редактирования чего-либо - находится здесь */}
@ -162,7 +184,6 @@ export default function EditPage({
</Box>
</Box>
</Box>
<ModalInfoWhyCantCreate />
<ConfirmLeaveModal
open={showConfirmLeaveModal}

@ -817,7 +817,7 @@ export default function StartPageSettings() {
quiz.config.info.site = e.target.value;
})
}
maxLength={100}
maxLength={2000}
/>
<Typography
sx={{

@ -1,3 +1,4 @@
import { useState, useEffect, forwardRef } from "react";
import {
Box,
Fab,
@ -9,9 +10,7 @@ import {
Modal,
Typography,
} from "@mui/material";
import { ReactNode } from "react";
import CircleDoubleDown from "./QuestionIcon";
import * as React from "react";
import Chat from "./Chat";
import { TransitionProps } from "@mui/material/transitions";
import { useLocation } from "react-router-dom";
@ -19,6 +18,8 @@ import { useTicketStore } from "@root/ticket";
import { useUserStore } from "@root/user";
import { ACCEPT_SEND_FILE_TYPES_MAP } from "@frontend/squzanswerer/dist-package/components/ViewPublicationPage/tools/fileUpload";
import type { ReactNode, Ref } from "react";
const animation = {
"@keyframes runningStripe": {
"0%": { left: "10%", backgroundColor: "transparent" },
@ -29,11 +30,11 @@ const animation = {
},
};
const Transition = React.forwardRef(function Transition(
const Transition = forwardRef(function Transition(
props: TransitionProps & {
children: ReactNode;
},
ref: React.Ref<unknown>,
ref: Ref<unknown>,
) {
return <Slide direction="up" ref={ref} {...props} />;
});
@ -59,7 +60,9 @@ export default function FloatingSupportChat({
modalWarningType,
setModalWarningType,
}: Props) {
const [monitorType, setMonitorType] = useState<"desktop" | "mobile" | "">("");
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(800));
const location = useLocation();
const locationChat = location.pathname;
const user = useUserStore((state) => state.user?._id);
@ -68,9 +71,24 @@ export default function FloatingSupportChat({
(state) => state[user ? "authData" : "unauthData"],
);
const isMobile = useMediaQuery(theme.breakpoints.down(800));
useEffect(() => {
const onResize = () => {
if (document.fullscreenElement) {
setMonitorType(isMobile ? "mobile" : "desktop");
return;
}
setMonitorType("");
};
window.addEventListener("resize", onResize);
return () => {
window.removeEventListener("resize", onResize);
};
}, [isMobile]);
console.log(messages);
return (
<Box
sx={{
@ -85,19 +103,19 @@ export default function FloatingSupportChat({
}}
>
<Chat
open={isChatOpened && !isMobile}
open={isChatOpened && (monitorType === "desktop" || !isMobile)}
sx={{ alignSelf: "start", width: "clamp(200px, 100%, 400px)" }}
sendMessage={sendMessage}
sendFile={sendFile}
/>
<Dialog
fullScreen
open={isChatOpened && isMobile}
open={isChatOpened && (monitorType === "mobile" || isMobile)}
onClose={handleChatClickClose}
TransitionComponent={Transition}
>
<Chat
open={isChatOpened && isMobile}
open={isChatOpened && (monitorType === "mobile" || isMobile)}
onclickArrow={handleChatClickClose}
sendMessage={sendMessage}
sendFile={sendFile}

@ -30,9 +30,10 @@ import { cleanAuthTicketData } from "@root/ticket";
type HeaderProps = {
setMobileSidebar: (callback: (visible: boolean) => boolean) => void;
scrollDown: boolean;
};
export const Header = ({ setMobileSidebar }: HeaderProps) => {
export const Header = ({ setMobileSidebar, scrollDown }: HeaderProps) => {
const quiz = useCurrentQuiz();
const theme = useTheme();
const navigate = useNavigate();
@ -65,6 +66,10 @@ export const Header = ({ setMobileSidebar }: HeaderProps) => {
bgcolor: isMobile ? "#333647" : "white",
borderBottom: "1px solid #E3E3E3",
zIndex: theme.zIndex.drawer + 1,
transition: "transform 0.3s",
transform: scrollDown && isMobile ? "translateY(-51px)" : undefined,
position: isMobile ? "fixed" : undefined,
top: isMobile ? 0 : undefined,
}}
>
<Link to="/" style={{ display: "flex" }}>

@ -5,6 +5,8 @@ import {
Typography,
useTheme,
useMediaQuery,
SxProps,
Theme,
} from "@mui/material";
import NavMenuItem from "./NavMenuItem";
import Logotip from "../../pages/Landing/images/icons/QuizLogo";
@ -21,7 +23,12 @@ import { ToTariffsButton } from "@ui_kit/Toolbars/ToTariffsButton";
import ArrowLeft from "@icons/questionsPage/arrowLeft";
import { cleanAuthTicketData } from "@root/ticket";
export default function HeaderFull({ isRequest }: boolean) {
interface Props {
isRequest: boolean;
sx?: SxProps<Theme>;
}
export default function HeaderFull({ isRequest, sx }: Props) {
const theme = useTheme();
const navigate = useNavigate();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
@ -55,6 +62,7 @@ export default function HeaderFull({ isRequest }: boolean) {
justifyContent: isMobile ? "space-between" : "center",
bgcolor: "white",
borderBottom: "1px solid #E3E3E3",
...sx,
}}
>
<Link to="/">

@ -81,7 +81,7 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) {
color: theme.palette.grey2.main,
}}
>
Создание quiz
{`Создание ${quiz.config.type}`}
</Typography>
)}
{!disableCollapse && (
@ -145,7 +145,7 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) {
color: theme.palette.grey2.main,
}}
>
Настройки quiz
{`Настройки ${quiz.config.type}`}
</Typography>
)}
<List disablePadding>

@ -48,12 +48,14 @@ interface Iprops {
open: boolean;
changePage: (step: number) => void;
setHeightSitebar: any;
scrollDown: boolean;
}
export const SidebarMobile: FC<Iprops> = ({
open,
changePage,
setHeightSitebar,
scrollDown,
}) => {
const theme = useTheme();
const isWrappSidebar = useMediaQuery(theme.breakpoints.down(400));
@ -118,7 +120,9 @@ export const SidebarMobile: FC<Iprops> = ({
<Box
ref={heightSidebar}
sx={{
display: open ? "block" : "none",
display: open ? "flex" : "none",
flexDirection: "column",
width: "100%",
minHeight: "134px",
padding: "20px 16px 16px 16px",
background: "#333647",
@ -126,6 +130,11 @@ export const SidebarMobile: FC<Iprops> = ({
borderBottomLeftRadius: "8px",
borderBottomRightRadius: "8px",
transitionDuration: "200ms",
position: "fixed",
top: "51px",
zIndex: theme.zIndex.drawer + 1,
transition: "transform 0.3s",
transform: scrollDown ? "translateY(-200px)" : undefined,
}}
>
<Box sx={{ display: "flex", alignItems: "center", position: "relative" }}>
@ -139,7 +148,7 @@ export const SidebarMobile: FC<Iprops> = ({
sx={{
ml: "15px",
display: "flex",
alignItems: "end",
alignItems: "center",
width: "100%",
justifyContent: "space-between",
}}
@ -165,7 +174,7 @@ export const SidebarMobile: FC<Iprops> = ({
id="project-name"
placeholder="Название проекта"
sx={{
width: "270px",
width: "85%",
"& .MuiInputBase-root": {
height: "34px",
borderRadius: "8px",
@ -193,7 +202,7 @@ export const SidebarMobile: FC<Iprops> = ({
</Typography>
)}
</Box>
<IconButton onClick={() => setInputOpen(true)}>
<IconButton onClick={() => setInputOpen(true)} sx={{ mt: "10px" }}>
<Pencil
style={{
position: "absolute",

@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
export function useDomainDefine(): { isTestServer: boolean } {
const [isTestServer, setIsTestServer] = useState<boolean>(null);
const [isTestServer, setIsTestServer] = useState<boolean>(false);
useEffect(() => {
const host = window.location.hostname;