Merge branch 'dev' into 'main'

поменял лого , обновил навигацию стрелок , обновил модалки (добавил ссылку на...

See merge request frontend/squiz!78
This commit is contained in:
Nastya 2023-12-17 23:30:08 +00:00
commit 2fcd6df97b
21 changed files with 1359 additions and 1084 deletions

45
src/api/quizRelase.ts Normal file

@ -0,0 +1,45 @@
import { makeRequest } from "@frontend/kitui";
import { CreateQuestionRequest } from "model/question/create";
import { RawQuestion } from "model/question/question";
import { GetQuestionListRequest, GetQuestionListResponse } from "@model/question/getList";
import { EditQuestionRequest, EditQuestionResponse } from "@model/question/edit";
import { DeleteQuestionRequest, DeleteQuestionResponse } from "@model/question/delete";
import { CopyQuestionRequest, CopyQuestionResponse } from "@model/question/copy";
const baseUrl = process.env.NODE_ENV === "production" ? "/squiz" : "https://squiz.pena.digital";
function get(quizId: string) {
return makeRequest<any>({
url: `${baseUrl}/question/copy`,
body: { id: questionId, quiz_id: quizId },
method: "POST",
});
}
function quizRelase(quizId: string, status: "start"|"stop") {
return makeRequest<any>({
url: `https://squiz.pena.digital/answer/quiz/get`,
body: {
quiz_id: quizId,
limit: 100,
page: 0,
need_config: true,
},
method: "POST",
});
}
export const relaseApi = {
relase: quizRelase,
get: quizRelase,
};
const defaultGetQuestionListBody: GetQuestionListRequest = {
"limit": 100,
"offset": 0,
"type": "",
};

@ -0,0 +1,18 @@
import { FC, SVGProps } from "react";
export const NameplateLogo: FC<SVGProps<SVGSVGElement>> = (props) => (
<svg {...props} height="1em" viewBox="0 0 89 81" fill="none">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M34.5604 0.0885217C24.3105 -1.09878 17.239 9.91147 10.6615 17.8703C4.88905 24.8549 0.590996 32.7441 0.0917664 41.7955C-0.439369 51.4255 1.3075 61.4545 7.86805 68.5172C14.6258 75.7923 24.7486 80.3889 34.5604 78.9028C43.5576 77.54 47.5388 67.6598 54.2372 61.4939C61.5105 54.799 75.061 51.6851 74.8731 41.7955C74.6848 31.8908 60.3836 29.952 53.5024 22.8328C46.3747 15.4585 44.7425 1.26797 34.5604 0.0885217Z"
fill="#7E2AEA"
/>
<circle cx="60.0543" cy="75.1555" r="5.65583" fill="#7E2AEA" />
<circle cx="54.4046" cy="12.3947" r="2.1546" fill="#7E2AEA" />
<path
d="M88.866 39.4685C88.2378 33.3607 85.3643 27.7037 80.8025 23.594C76.2408 19.4843 70.3156 17.2146 64.1757 17.2248C63.3039 17.2252 62.4328 17.2708 61.5658 17.3614C55.4608 18.0025 49.8093 20.8814 45.7015 25.443C41.5937 30.0046 39.3205 35.9256 39.3203 42.0642V42.0642V77.549H49.9658V62.468C54.128 65.3636 59.0787 66.9119 64.1491 66.9036C65.0208 66.9033 65.8919 66.8577 66.759 66.767C70.0031 66.426 73.1483 65.4494 76.0151 63.8929C78.8818 62.3364 81.4138 60.2305 83.4667 57.6955C85.5195 55.1604 87.0529 52.2458 87.9793 49.1181C88.9058 45.9904 89.2071 42.7109 88.866 39.4667V39.4685ZM75.1937 51.0011C74.0243 52.4537 72.5783 53.6599 70.9395 54.5498C69.3007 55.4397 67.5017 55.9956 65.6465 56.1854C65.149 56.2371 64.6492 56.2631 64.1491 56.2635C60.9296 56.2605 57.8068 55.1631 55.2932 53.1515C52.7796 51.1398 51.0245 48.3334 50.3161 45.1929C49.6077 42.0523 49.988 38.7642 51.3945 35.8683C52.8011 32.9723 55.1504 30.6406 58.0568 29.2558C60.9632 27.871 64.2541 27.5154 67.3892 28.2473C70.5244 28.9793 73.3176 30.7553 75.3103 33.284C77.303 35.8126 78.3769 38.9436 78.3558 42.1629C78.3346 45.3823 77.2196 48.4989 75.1937 51.0011Z"
fill="#151515"
/>
</svg>
);

File diff suppressed because it is too large Load Diff

@ -34,7 +34,7 @@ export const BranchingQuestionsModal = ({
<Box <Box
sx={{ sx={{
position: "absolute", position: "absolute",
overflow: "hidden", overflow: "auto",
top: "50%", top: "50%",
left: "50%", left: "50%",
transform: "translate(-50%, -50%)", transform: "translate(-50%, -50%)",
@ -44,6 +44,7 @@ export const BranchingQuestionsModal = ({
borderRadius: "12px", borderRadius: "12px",
boxShadow: 24, boxShadow: 24,
padding: "30px 0", padding: "30px 0",
height: "80vh"
}} }}
> >
<Box sx={{ margin: "0 auto", maxWidth: "350px" }}> <Box sx={{ margin: "0 auto", maxWidth: "350px" }}>

@ -232,6 +232,7 @@ export default function ButtonsOptions({
// myFunc(question); // myFunc(question);
}} }}
sx={{ sx={{
display: quiz.config.type === "form" ? "none" : "flex",
backgroundColor: backgroundColor:
switchState === value switchState === value
? theme.palette.brightPurple.main ? theme.palette.brightPurple.main

@ -259,6 +259,7 @@ export default function ButtonsOptionsAndPict({
updateDesireToOpenABranchingModal(question.content.id); updateDesireToOpenABranchingModal(question.content.id);
}} }}
sx={{ sx={{
display: quiz.config.type === "form" ? "none" : "flex",
height: "30px", height: "30px",
maxWidth: "103px", maxWidth: "103px",
minWidth: isIconMobile ? "30px" : "64px", minWidth: isIconMobile ? "30px" : "64px",

@ -70,7 +70,7 @@ export default function QuestionsPage() {
sx={{ sx={{
position: "fixed", position: "fixed",
left: isMobile ? "20px" : "250px", left: isMobile ? "20px" : "250px",
bottom: isMobile ? "140px" : "20px", bottom: "140px",
}} }}
data-cy="create-question" data-cy="create-question"
> >

@ -1,12 +1,13 @@
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
export const ApologyPage = (message: string) => { export const ApologyPage = ({message}:{message: string}) => {
return ( return (
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "center" justifyContent: "center",
height: "100vh"
}} }}
> >
<Typography <Typography

@ -1,16 +1,14 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Box, Button, useTheme } from "@mui/material"; import { Box, Button, Typography, useTheme } from "@mui/material";
import { useQuizViewStore } from "@root/quizView"; import { useQuizViewStore } from "@root/quizView";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuestionsStore } from "@root/questions/store"; import { useQuestionsStore } from "@root/questions/store";
import type { import type { AnyTypedQuizQuestion, QuizQuestionBase } from "../../model/questionTypes/shared";
AnyTypedQuizQuestion,
QuizQuestionBase,
} from "../../model/questionTypes/shared";
import { getQuestionByContentId } from "@root/questions/actions"; import { getQuestionByContentId } from "@root/questions/actions";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { NameplateLogo } from "@icons/NameplateLogo";
type FooterProps = { type FooterProps = {
setCurrentQuestion: (step: AnyTypedQuizQuestion) => void; setCurrentQuestion: (step: AnyTypedQuizQuestion) => void;
@ -19,22 +17,14 @@ type FooterProps = {
setShowResultForm: (show: boolean) => void; setShowResultForm: (show: boolean) => void;
}; };
export const Footer = ({ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setShowResultForm }: FooterProps) => {
setCurrentQuestion, const [disablePreviousButton, setDisablePreviousButton] = useState<boolean>(false);
question,
setShowContactForm,
setShowResultForm,
}: FooterProps) => {
const [disablePreviousButton, setDisablePreviousButton] =
useState<boolean>(false);
const [disableNextButton, setDisableNextButton] = useState<boolean>(false); const [disableNextButton, setDisableNextButton] = useState<boolean>(false);
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const { answers } = useQuizViewStore(); const { answers } = useQuizViewStore();
const questions = useQuestionsStore().questions as AnyTypedQuizQuestion[]; const questions = useQuestionsStore().questions as AnyTypedQuizQuestion[];
const theme = useTheme(); const theme = useTheme();
const linear = !questions.find( const linear = !questions.find(({ content }) => content.rule.parentId === "root");
({ content }) => content.rule.parentId === "root"
);
useEffect(() => { useEffect(() => {
// Логика для аргумента disabled у кнопки "Назад" // Логика для аргумента disabled у кнопки "Назад"
@ -57,9 +47,7 @@ export const Footer = ({
} }
// Логика для аргумента disabled у кнопки "Далее" // Логика для аргумента disabled у кнопки "Далее"
const answer = answers.find( const answer = answers.find(({ questionId }) => questionId === question.content.id);
({ questionId }) => questionId === question.content.id
);
if ("required" in question.content && question.content.required && answer) { if ("required" in question.content && question.content.required && answer) {
setDisableNextButton(false); setDisableNextButton(false);
@ -67,11 +55,7 @@ export const Footer = ({
return; return;
} }
if ( if ("required" in question.content && question.content.required && !answer) {
"required" in question.content &&
question.content.required &&
!answer
) {
setDisableNextButton(true); setDisableNextButton(true);
return; return;
@ -85,9 +69,7 @@ export const Footer = ({
if (nextQuestionId) { if (nextQuestionId) {
setDisableNextButton(false); setDisableNextButton(false);
} else { } else {
const nextQuestion = getQuestionByContentId( const nextQuestion = getQuestionByContentId(question.content.rule.default);
question.content.rule.default
);
if (nextQuestion?.type) { if (nextQuestion?.type) {
setDisableNextButton(false); setDisableNextButton(false);
@ -95,9 +77,8 @@ export const Footer = ({
} }
}, [question, answers]); }, [question, answers]);
const showResult = nextQuestion => { const showResult = (nextQuestion) => {
console.log(nextQuestion);
console.log(nextQuestion)
if (nextQuestion && quiz?.config.resultInfo.when === "before") { if (nextQuestion && quiz?.config.resultInfo.when === "before") {
setShowResultForm(true); setShowResultForm(true);
@ -108,44 +89,34 @@ export const Footer = ({
const getNextQuestionId = () => { const getNextQuestionId = () => {
if (answers.length) { if (answers.length) {
const answer = answers.find( const answer = answers.find(({ questionId }) => questionId === question.content.id);
({ questionId }) => questionId === question.content.id
);
let readyBeNextQuestion = ""; let readyBeNextQuestion = "";
(question as QuizQuestionBase).content.rule.main.forEach( (question as QuizQuestionBase).content.rule.main.forEach(({ next, rules }) => {
({ next, rules }) => { let longerArray = Math.max(
let longerArray = Math.max( rules[0].answers.length,
rules[0].answers.length, answer?.answer && Array.isArray(answer?.answer) ? answer?.answer.length : [answer?.answer].length
answer?.answer && Array.isArray(answer?.answer) );
? answer?.answer.length
: [answer?.answer].length
);
for ( for (
var i = 0; var i = 0;
i < longerArray; i < longerArray;
i++ // Цикл по всем эле­мен­там бОльшего массива i++ // Цикл по всем эле­мен­там бОльшего массива
) { ) {
if (Array.isArray(answer?.answer)) { if (Array.isArray(answer?.answer)) {
if ( if (answer?.answer.find((item) => String(item === rules[0].answers[i]))) {
answer?.answer.find((item) =>
String(item === rules[0].answers[i])
)
) {
readyBeNextQuestion = next; // Ес­ли хоть один эле­мент от­ли­ча­ет­ся, мас­си­вы не рав­ны
}
return;
}
if (String(rules[0].answers[i]) === answer?.answer) {
readyBeNextQuestion = next; // Ес­ли хоть один эле­мент от­ли­ча­ет­ся, мас­си­вы не рав­ны readyBeNextQuestion = next; // Ес­ли хоть один эле­мент от­ли­ча­ет­ся, мас­си­вы не рав­ны
} }
return;
}
if (String(rules[0].answers[i]) === answer?.answer) {
readyBeNextQuestion = next; // Ес­ли хоть один эле­мент от­ли­ча­ет­ся, мас­си­вы не рав­ны
} }
} }
); });
return readyBeNextQuestion; return readyBeNextQuestion;
} }
@ -181,12 +152,14 @@ export const Footer = ({
const questionIndex = questions.findIndex(({ id }) => id === question.id); const questionIndex = questions.findIndex(({ id }) => id === question.id);
const nextQuestion = questions[questionIndex + 1]; const nextQuestion = questions[questionIndex + 1];
console.log(nextQuestion) console.log("questionIndex ", questionIndex);
console.log(nextQuestion);
console.log(questions);
if (nextQuestion && nextQuestion.type !== "result") { if (nextQuestion && nextQuestion.type !== "result") {
console.log("следующий вопрос результирующий ", (nextQuestion.type === "result")) console.log("следующий вопрос результирующий ", nextQuestion.type === "result");
setCurrentQuestion(nextQuestion); setCurrentQuestion(nextQuestion);
} else { } else {
console.log("следующий вопрос результирующий ", (nextQuestion.type === "result")) console.log("следующий вопрос результирующий ", nextQuestion.type === "result");
showResult(nextQuestion); showResult(nextQuestion);
} }
@ -205,9 +178,7 @@ export const Footer = ({
enqueueSnackbar("не могу получить последующий вопрос"); enqueueSnackbar("не могу получить последующий вопрос");
} }
} else { } else {
const nextQuestion = getQuestionByContentId( const nextQuestion = getQuestionByContentId(question.content.rule.default);
question.content.rule.default
);
if (nextQuestion?.type && nextQuestion.type !== "result") { if (nextQuestion?.type && nextQuestion.type !== "result") {
setCurrentQuestion(nextQuestion); setCurrentQuestion(nextQuestion);
} else { } else {
@ -219,10 +190,25 @@ export const Footer = ({
return ( return (
<Box <Box
sx={{ sx={{
position: "relative",
padding: "15px 0", padding: "15px 0",
borderTop: `1px solid ${theme.palette.grey[400]}`, borderTop: `1px solid ${theme.palette.grey[400]}`,
}} }}
> >
<Box
sx={{
display: "flex",
alignItems: "center",
position: "absolute",
top: "-45px",
left: "50%",
transform: "translateX(-50%)",
gap: "8px",
}}
>
<NameplateLogo style={{ fontSize: "34px" }} />
<Typography sx={{ fontSize: "20px", color: "#4D4D4D", whiteSpace: "nowrap" }}>Сделано на PenaQuiz</Typography>
</Box>
<Box <Box
sx={{ sx={{
width: "100%", width: "100%",

@ -198,9 +198,14 @@ export default function SigninDialog() {
}} }}
> >
<Typography sx={{ color: "#7E2AEA", textAlign: "center" }}>Вы еще не присоединились?</Typography> <Typography sx={{ color: "#7E2AEA", textAlign: "center" }}>Вы еще не присоединились?</Typography>
<Link component={RouterLink} to="/signup" sx={{ color: "#7E2AEA" }}> <Box sx={{ display: "flex", alignItems: "center", gap: "4px" }}>
Регистрация <Link component={RouterLink} to="/signup" sx={{ color: "#7E2AEA" }}>
</Link> Регистрация
</Link>
<Link component={RouterLink} to="/restore" sx={{ color: "#7E2AEA" }}>
Забыли пароль
</Link>
</Box>
</Box> </Box>
</Box> </Box>
</Dialog> </Dialog>

@ -200,6 +200,7 @@ export default function SignupDialog() {
> >
Зарегистрироваться Зарегистрироваться
</Button> </Button>
<Link <Link
component={RouterLink} component={RouterLink}
to="/signin" to="/signin"
@ -211,6 +212,9 @@ export default function SignupDialog() {
> >
Вход в личный кабинет Вход в личный кабинет
</Link> </Link>
<Link component={RouterLink} to="/restore" sx={{ color: "#7E2AEA" }}>
Забыли пароль
</Link>
</Box> </Box>
</Dialog> </Dialog>
); );

@ -3,6 +3,7 @@ import SectionWrapper from "@ui_kit/SectionWrapper";
import ComplexNavText from "./ComplexNavText"; import ComplexNavText from "./ComplexNavText";
import { createQuiz } from "@root/quizes/actions"; import { createQuiz } from "@root/quizes/actions";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { resetEditConfig } from "@root/quizes/actions";
export default function FirstQuiz() { export default function FirstQuiz() {
@ -29,7 +30,10 @@ export default function FirstQuiz() {
<Button <Button
variant="contained" variant="contained"
data-cy="create-quiz" data-cy="create-quiz"
onClick={() => createQuiz(navigate)} onClick={() => {
resetEditConfig()
createQuiz(navigate)
}}
> >
Создать + Создать +
</Button> </Button>

@ -4,6 +4,7 @@ import { useQuizes } from "@root/quizes/hooks";
import SectionWrapper from "@ui_kit/SectionWrapper"; import SectionWrapper from "@ui_kit/SectionWrapper";
import React from "react"; import React from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { resetEditConfig } from "@root/quizes/actions";
import ComplexNavText from "./ComplexNavText"; import ComplexNavText from "./ComplexNavText";
import FirstQuiz from "./FirstQuiz"; import FirstQuiz from "./FirstQuiz";
import QuizCard from "./QuizCard"; import QuizCard from "./QuizCard";
@ -42,7 +43,10 @@ export default function MyQuizzesFull({ outerContainerSx: sx, children }: Props)
padding: isMobile ? "10px" : "10px 47px", padding: isMobile ? "10px" : "10px 47px",
minWidth: "44px", minWidth: "44px",
}} }}
onClick={() => createQuiz(navigate)} onClick={() => {
resetEditConfig();
createQuiz(navigate)
}}
data-cy="create-quiz" data-cy="create-quiz"
> >
{isMobile ? "+" : "Создать +"} {isMobile ? "+" : "Создать +"}

@ -4,159 +4,142 @@ import LinkIcon from "@icons/LinkIcon";
import PencilIcon from "@icons/PencilIcon"; import PencilIcon from "@icons/PencilIcon";
import { Quiz } from "@model/quiz/quiz"; import { Quiz } from "@model/quiz/quiz";
import MoreHorizIcon from "@mui/icons-material/MoreHoriz"; import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
import { import { Box, Button, IconButton, Typography, useMediaQuery, useTheme, Popover } from "@mui/material";
Box,
Button,
IconButton,
Typography,
useMediaQuery,
useTheme,
Popover,
} from "@mui/material";
import { deleteQuiz, setEditQuizId } from "@root/quizes/actions"; import { deleteQuiz, setEditQuizId } from "@root/quizes/actions";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
interface Props { interface Props {
quiz: Quiz; quiz: Quiz;
openCount?: number; openCount?: number;
applicationCount?: number; applicationCount?: number;
conversionPercent?: number; conversionPercent?: number;
} }
export default function QuizCard({ export default function QuizCard({ quiz, openCount = 0, applicationCount = 0, conversionPercent = 0 }: Props) {
quiz, const theme = useTheme();
openCount = 0, const isMobile = useMediaQuery(theme.breakpoints.down(600));
applicationCount = 0, const navigate = useNavigate();
conversionPercent = 0,
}: Props) {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(600));
const navigate = useNavigate();
const [subMenuOpen, setSubMenuOpen] = useState<boolean>(false); const [subMenuOpen, setSubMenuOpen] = useState<boolean>(false);
const subMenuRef = useRef<HTMLButtonElement | null>(null); const subMenuRef = useRef<HTMLButtonElement | null>(null);
function handleEditClick() { function handleEditClick() {
setEditQuizId(quiz.backendId); setEditQuizId(quiz.backendId);
navigate("/edit"); navigate("/edit");
} }
return ( return (
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
backgroundColor: "white", backgroundColor: "white",
width: "560px", width: "560px",
height: "280px", height: "280px",
p: "20px", p: "20px",
borderRadius: "12px", borderRadius: "12px",
boxSizing: "border-box", boxSizing: "border-box",
boxShadow: `0px 100px 309px rgba(210, 208, 225, 0.24), boxShadow: `0px 100px 309px rgba(210, 208, 225, 0.24),
0px 41.7776px 129.093px rgba(210, 208, 225, 0.172525), 0px 41.7776px 129.093px rgba(210, 208, 225, 0.172525),
0px 22.3363px 69.0192px rgba(210, 208, 225, 0.143066), 0px 22.3363px 69.0192px rgba(210, 208, 225, 0.143066),
0px 12.5216px 38.6916px rgba(210, 208, 225, 0.12), 0px 12.5216px 38.6916px rgba(210, 208, 225, 0.12),
0px 6.6501px 20.5488px rgba(210, 208, 225, 0.0969343), 0px 6.6501px 20.5488px rgba(210, 208, 225, 0.0969343),
0px 2.76726px 8.55082px rgba(210, 208, 225, 0.0674749)`, 0px 2.76726px 8.55082px rgba(210, 208, 225, 0.0674749)`,
}} }}
>
<Typography variant="h5">{quiz.name}</Typography>
<Box
sx={{
display: "flex",
alignItems: "center",
mt: "10px",
gap: "10px",
}}
>
<LinkIcon bgcolor="#EEE4FC" color={theme.palette.brightPurple.main} />
<Typography color={theme.palette.grey3.main}>быстрая ссылка ...</Typography>
</Box>
<Box
sx={{
display: "flex",
mt: "32px",
mr: "22px",
}}
>
<Box sx={{ flex: "1 1 0" }}>
<Typography variant="h5">{openCount}</Typography>
<Typography color={theme.palette.grey3.main}>Открытий</Typography>
</Box>
<Box sx={{ flex: "1 1 0" }}>
<Typography variant="h5">{applicationCount}</Typography>
<Typography color={theme.palette.grey3.main}>Заявок</Typography>
</Box>
<Box sx={{ flex: "1 1 0" }}>
<Typography variant="h5">{conversionPercent} %</Typography>
<Typography color={theme.palette.grey3.main}>Конверсия</Typography>
</Box>
</Box>
<Box
sx={{
mt: "auto",
display: "flex",
gap: isMobile ? "10px" : "20px",
}}
>
<Button
variant="contained"
sx={{
padding: "10px 39px",
}}
> >
<Typography variant="h5">{quiz.name}</Typography> Заявки
<Box </Button>
sx={{ <Button
display: "flex", variant="outlined"
alignItems: "center", startIcon={<PencilIcon />}
mt: "10px", onClick={handleEditClick}
gap: "10px", sx={{
}} padding: isMobile ? "10px" : "10px 20px",
> minWidth: "unset",
<LinkIcon bgcolor="#EEE4FC" color={theme.palette.brightPurple.main} /> color: theme.palette.brightPurple.main,
<Typography color={theme.palette.grey3.main}> "& .MuiButton-startIcon": {
быстрая ссылка ... marginRight: isMobile ? 0 : "4px",
</Typography> marginLeft: 0,
</Box> },
<Box }}
sx={{ >
display: "flex", {isMobile ? "" : "Редактировать"}
mt: "32px", </Button>
mr: "22px", <Button
}} variant="outlined"
> startIcon={<ChartIcon />}
<Box sx={{ flex: "1 1 0" }}> sx={{
<Typography variant="h5">{openCount}</Typography> minWidth: "46px",
<Typography color={theme.palette.grey3.main}>Открытий</Typography> padding: "10px 10px",
</Box> "& .MuiButton-startIcon": {
<Box sx={{ flex: "1 1 0" }}> mr: 0,
<Typography variant="h5">{applicationCount}</Typography> ml: 0,
<Typography color={theme.palette.grey3.main}>Заявок</Typography> },
</Box> }}
<Box sx={{ flex: "1 1 0" }}> />
<Typography variant="h5">{conversionPercent} %</Typography> <IconButton
<Typography color={theme.palette.grey3.main}>Конверсия</Typography> ref={subMenuRef}
</Box> sx={{
</Box> color: theme.palette.brightPurple.main,
<Box ml: "auto",
sx={{ }}
mt: "auto", onClick={() => setSubMenuOpen(true)}
display: "flex", data-cy="delete-quiz"
gap: isMobile ? "10px" : "20px", >
}} <MoreHorizIcon sx={{ transform: "scale(1.75)" }} />
> </IconButton>
<Button <Popover
variant="contained" open={subMenuOpen}
sx={{ anchorEl={subMenuRef.current}
padding: "10px 39px", onClose={() => setSubMenuOpen(false)}
}} anchorOrigin={{ vertical: "top", horizontal: "right" }}
> >
Заявки <Box onClick={() => setSubMenuOpen(false)}>
</Button> {/* <Button
<Button
variant="outlined"
startIcon={<PencilIcon />}
onClick={handleEditClick}
sx={{
padding: isMobile ? "10px" : "10px 20px",
minWidth: "unset",
color: theme.palette.brightPurple.main,
"& .MuiButton-startIcon": {
marginRight: isMobile ? 0 : "4px",
marginLeft: 0,
},
}}
>
{isMobile ? "" : "Редактировать"}
</Button>
<Button
variant="outlined"
startIcon={<ChartIcon />}
sx={{
minWidth: "46px",
padding: "10px 10px",
"& .MuiButton-startIcon": {
mr: 0,
ml: 0,
},
}}
/>
<IconButton
ref={subMenuRef}
sx={{
color: theme.palette.brightPurple.main,
ml: "auto",
}}
onClick={() => setSubMenuOpen(true)}
data-cy="delete-quiz"
>
<MoreHorizIcon sx={{ transform: "scale(1.75)" }} />
</IconButton>
<Popover
open={subMenuOpen}
anchorEl={subMenuRef.current}
onClose={() => setSubMenuOpen(false)}
anchorOrigin={{ vertical: "top", horizontal: "right" }}
>
<Box onClick={() => setSubMenuOpen(false)}>
{/* <Button
sx={{ sx={{
display: "block", display: "block",
width: "100%", width: "100%",
@ -166,19 +149,19 @@ export default function QuizCard({
> >
Копировать Копировать
</Button> */} </Button> */}
<Button <Button
sx={{ sx={{
display: "block", display: "block",
width: "100%", width: "100%",
padding: "15px 30px", padding: "15px 30px",
}} }}
onClick={() => deleteQuiz(quiz.id)} onClick={() => deleteQuiz(quiz.id)}
> >
Удалить Удалить
</Button> </Button>
</Box> </Box>
</Popover> </Popover>
</Box> </Box>
</Box> </Box>
); );
} }

@ -5,16 +5,18 @@ import { Burger } from "@icons/Burger";
import EyeIcon from "@icons/EyeIcon"; import EyeIcon from "@icons/EyeIcon";
import { PenaLogoIcon } from "@icons/PenaLogoIcon"; import { PenaLogoIcon } from "@icons/PenaLogoIcon";
import { import {
Box, Box,
Button, Button,
Container, Container,
FormControl, FormControl,
IconButton, Switch, IconButton,
TextField, Typography, Switch,
useMediaQuery, TextField,
useTheme, Typography,
useMediaQuery,
useTheme,
} from "@mui/material"; } from "@mui/material";
import { decrementCurrentStep, resetEditConfig, setQuizes } from "@root/quizes/actions"; import {decrementCurrentStep, resetEditConfig, setQuizes, updateQuiz} from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks"; import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuizStore } from "@root/quizes/store"; import { useQuizStore } from "@root/quizes/store";
import CustomAvatar from "@ui_kit/Header/Avatar"; import CustomAvatar from "@ui_kit/Header/Avatar";
@ -25,7 +27,7 @@ import Stepper from "@ui_kit/Stepper";
import SwitchStepPages from "@ui_kit/switchStepPages"; import SwitchStepPages from "@ui_kit/switchStepPages";
import { isAxiosError } from "axios"; import { isAxiosError } from "axios";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { useEffect, useState } from "react"; import React, { useEffect, useLayoutEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import useSWR from "swr"; import useSWR from "swr";
import { SidebarMobile } from "./Sidebar/SidebarMobile"; import { SidebarMobile } from "./Sidebar/SidebarMobile";
@ -37,307 +39,318 @@ import { useQuizes } from "@root/quizes/hooks";
import { questionApi } from "@api/question"; import { questionApi } from "@api/question";
import { useUiTools } from "@root/uiTools/store"; import { useUiTools } from "@root/uiTools/store";
import Logotip from "../Landing/images/icons/QuizLogo";
export default function EditPage() { export default function EditPage() {
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
const { editQuizId } = useQuizStore(); const { editQuizId } = useQuizStore();
useEffect(() => { useEffect(() => {
const getData = async () => { const getData = async () => {
const quizes = await quizApi.getList() const quizes = await quizApi.getList();
setQuizes(quizes) setQuizes(quizes);
const questions = await questionApi.getList({ quiz_id: editQuizId }) const questions = await questionApi.getList({ quiz_id: editQuizId });
setQuestions(questions) setQuestions(questions);
};
getData();
}, []);
} const { openBranchingPanel } = useUiTools();
getData() const theme = useTheme();
}, []) const navigate = useNavigate();
const currentStep = useQuizStore((state) => state.currentStep);
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(660));
const [mobileSidebar, setMobileSidebar] = useState<boolean>(false);
const quizConfig = quiz?.config;
const disableTest = quiz === undefined ? true : (quiz.config.type === null)
const { openBranchingPanel } = useUiTools() useEffect(() => {
const theme = useTheme(); if (editQuizId === null) navigate("/list");
const navigate = useNavigate(); }, [navigate, editQuizId]);
const currentStep = useQuizStore(state => state.currentStep);
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(660));
const [mobileSidebar, setMobileSidebar] = useState<boolean>(false);
const quizConfig = quiz?.config;
useEffect(() => { useEffect(
if (editQuizId === null) navigate("/list"); () => () => {
}, [navigate, editQuizId]); resetEditConfig();
cleanQuestions();
},
[]
);
console.log(currentStep)
useEffect(() => () => { return (
resetEditConfig(); <>
cleanQuestions(); {/*хедер*/}
}, []); <Container
component="nav"
maxWidth={false}
return ( disableGutters
<> sx={{
{/*хедер*/} px: "16px",
<Container display: "flex",
component="nav" height: isMobile ? "51px" : "80px",
maxWidth={false} alignItems: "center",
disableGutters bgcolor: isMobile ? "#333647" : "white",
borderBottom: "1px solid #E3E3E3",
zIndex: theme.zIndex.drawer + 1,
}}
>
<Link to="/" style={{ display: "flex" }}>
{isMobile ? <PenaLogoIcon style={{ fontSize: "39px", color: "white" }} /> : <PenaLogo width={124} />}
</Link>
<Box
sx={{
display: isMobile ? "none" : "flex",
alignItems: "center",
ml: "37px",
}}
>
<Link to="/list">
<IconButton sx={{ p: "6px" }}>
<BackArrowIcon />
</IconButton>
</Link>
<FormControl fullWidth variant="standard">
<TextField
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,
},
},
}}
/>
</FormControl>
</Box>
{isTablet ? (
<Box
sx={{
display: "flex",
ml: "auto",
}}
>
{isMobile ? (
<Burger
onClick={() => setMobileSidebar(!mobileSidebar)}
style={{ fontSize: "30px", color: "white", cursor: "pointer" }}
/>
) : (
<CustomAvatar
sx={{ sx={{
px: "16px", ml: "11px",
display: "flex", backgroundColor: theme.palette.orange.main,
height: isMobile ? "51px" : "80px", height: "36px",
alignItems: "center", width: "36px",
bgcolor: isMobile ? "#333647" : "white",
borderBottom: "1px solid #E3E3E3",
zIndex: theme.zIndex.drawer + 1,
}} }}
> />
<Link to="/" style={{ display: "flex" }}> )}
{isMobile ? ( </Box>
<PenaLogoIcon style={{ fontSize: "39px", color: "white" }} /> ) : (
) : ( <>
<PenaLogo width={124} />
)}
</Link>
<Box
sx={{
display: isMobile ? "none" : "flex",
alignItems: "center",
ml: "37px",
}}
>
<IconButton sx={{ p: "6px" }} onClick={decrementCurrentStep}>
<BackArrowIcon />
</IconButton>
<FormControl fullWidth variant="standard">
<TextField
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,
},
},
}}
/>
</FormControl>
</Box>
{isTablet ? (
<Box
sx={{
display: "flex",
ml: "auto",
}}
>
{isMobile ? (
<Burger
onClick={() => setMobileSidebar(!mobileSidebar)}
style={{ fontSize: "30px", color: "white", cursor: "pointer" }}
/>
) : (
<CustomAvatar
sx={{
ml: "11px",
backgroundColor: theme.palette.orange.main,
height: "36px",
width: "36px",
}}
/>
)}
</Box>
) : (
<>
<Box
sx={{
display: "flex",
gap: "30px",
overflow: "hidden",
ml: "20px",
}}
>
<NavMenuItem text="Редактировать" isActive />
<NavMenuItem text="Заявки" />
<NavMenuItem text="Аналитика" />
<NavMenuItem text="История" />
<NavMenuItem text="Помощь" />
</Box>
<Box
sx={{
display: "flex",
ml: "auto",
gap: "15px",
}}
>
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
<Button
variant="contained"
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
}}
>
Опубликовать
</Button>
</a>
<CustomAvatar
sx={{
ml: "11px",
backgroundColor: theme.palette.orange.main,
height: "36px",
width: "36px",
}}
/>
</Box>
</>
)}
</Container>
<Box <Box
sx={{ sx={{
display: isMobile ? "block" : "flex", display: "flex",
}} gap: "30px",
overflow: "hidden",
ml: "20px",
}}
> >
{isMobile ? <SidebarMobile open={mobileSidebar} /> : <Sidebar />} <NavMenuItem text="Редактировать" isActive />
<Box <NavMenuItem text="Заявки" />
sx={{ <NavMenuItem text="Аналитика" />
background: theme.palette.background.default, <NavMenuItem text="История" />
width: "100%", <NavMenuItem text="Помощь" />
padding: isMobile ? "16px 16px 140px 16px" : "25px",
height: "calc(100vh - 80px)",
overflow: "auto",
boxSizing: "border-box",
}}
>
{/* Выбор текущей страницы редактирования чего-либо находится здесь */}
{quizConfig &&
<>
<Stepper activeStep={currentStep} />
<SwitchStepPages
activeStep={currentStep}
quizType={quizConfig.type}
quizResults={quizConfig.results}
quizStartPageType={quizConfig.startpageType}
/>
</>
}
</Box>
{isTablet &&
<Box
sx={{
position: "absolute",
left: 0,
bottom: 0,
width: "100%",
padding: isMobile ? "20px 16px" : "20px 40px",
display: "flex",
justifyContent: "flex-end",
gap: "15px",
background: "#FFF",
}}
>
{[1, 2].includes(currentStep) && !openBranchingPanel && (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "15px",
padding: "18px",
background: "#fff",
borderRadius: "12px",
boxShadow: "0px 10px 30px #e7e7e7",
}}
>
<Switch
checked={openBranchingPanel}
onChange={
(e) => updateOpenBranchingPanel(e.target.checked)
}
sx={{
width: 50,
height: 30,
padding: 0,
"& .MuiSwitch-switchBase": {
padding: 0,
margin: "2px",
transitionDuration: "300ms",
"&.Mui-checked": {
transform: "translateX(20px)",
color: theme.palette.brightPurple.main,
"& + .MuiSwitch-track": {
backgroundColor: "#E8DCF9",
opacity: 1,
border: 0,
},
"&.Mui-disabled + .MuiSwitch-track": { opacity: 0.5 },
},
"&.Mui-disabled .MuiSwitch-thumb": {
color:
theme.palette.mode === "light"
? theme.palette.grey[100]
: theme.palette.grey[600],
},
"&.Mui-disabled + .MuiSwitch-track": {
opacity: theme.palette.mode === "light" ? 0.7 : 0.3,
},
},
"& .MuiSwitch-thumb": {
boxSizing: "border-box",
width: 25,
height: 25,
},
"& .MuiSwitch-track": {
borderRadius: 13,
backgroundColor:
theme.palette.mode === "light" ? "#E9E9EA" : "#39393D",
opacity: 1,
transition: theme.transitions.create(["background-color"], {
duration: 500,
}),
},
}}
/>
<Box>
<Typography sx={{ fontWeight: "bold", color: "#4D4D4D" }}>
Логика ветвления
</Typography>
</Box>
</Box>
)}
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
<Button
variant="contained"
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
minWidth: "130px"
}}
>
Опубликовать
</Button>
</a>
</Box>
}
</Box> </Box>
</> <Box
); sx={{
display: "flex",
ml: "auto",
gap: "15px",
}}
>
<CustomAvatar
sx={{
ml: "11px",
backgroundColor: theme.palette.orange.main,
height: "36px",
width: "36px",
}}
/>
</Box>
</>
)}
</Container>
<Box
sx={{
display: isMobile ? "block" : "flex",
}}
>
{isMobile ? <SidebarMobile open={mobileSidebar} /> : <Sidebar />}
<Box
sx={{
background: theme.palette.background.default,
width: "100%",
padding: isMobile ? "16px 16px 140px 16px" : "25px 25px 140px 25px",
height: "calc(100vh - 80px)",
overflow: "auto",
boxSizing: "border-box",
}}
>
{/* Выбор текущей страницы редактирования чего-либо находится здесь */}
{quizConfig && (
<>
<Stepper activeStep={currentStep} />
<SwitchStepPages
activeStep={currentStep}
quizType={quizConfig.type}
quizResults={quizConfig.results}
quizStartPageType={quizConfig.startpageType}
/>
</>
)}
</Box>
<Box
sx={{
position: "absolute",
left: 0,
bottom: 0,
width: "100%",
padding: isMobile ? "20px 16px" : "20px 40px 20px 250px",
display: "flex",
justifyContent: "flex-start",
alignItems: "center",
gap: "15px",
background: "#FFF",
}}
>
{[1].includes(currentStep) && !openBranchingPanel && quizConfig.type !== "form" && (
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "15px",
padding: "18px",
background: "#fff",
borderRadius: "12px",
boxShadow: "0px 10px 30px #e7e7e7",
}}
>
<Switch
checked={openBranchingPanel}
onChange={(e) => updateOpenBranchingPanel(e.target.checked)}
sx={{
width: 50,
height: 30,
padding: 0,
"& .MuiSwitch-switchBase": {
padding: 0,
margin: "2px",
transitionDuration: "300ms",
"&.Mui-checked": {
transform: "translateX(20px)",
color: theme.palette.brightPurple.main,
"& + .MuiSwitch-track": {
backgroundColor: "#E8DCF9",
opacity: 1,
border: 0,
},
"&.Mui-disabled + .MuiSwitch-track": { opacity: 0.5 },
},
"&.Mui-disabled .MuiSwitch-thumb": {
color: theme.palette.mode === "light" ? theme.palette.grey[100] : theme.palette.grey[600],
},
"&.Mui-disabled + .MuiSwitch-track": {
opacity: theme.palette.mode === "light" ? 0.7 : 0.3,
},
},
"& .MuiSwitch-thumb": {
boxSizing: "border-box",
width: 25,
height: 25,
},
"& .MuiSwitch-track": {
borderRadius: 13,
backgroundColor: theme.palette.mode === "light" ? "#E9E9EA" : "#39393D",
opacity: 1,
transition: theme.transitions.create(["background-color"], {
duration: 500,
}),
},
}}
/>
<Box>
<Typography sx={{ fontWeight: "bold", color: "#4D4D4D" }}>Логика ветвления</Typography>
</Box>
</Box>
)}
{disableTest ? (
<Button
variant="contained"
disabled
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
minWidth: "130px",
}}
>
Тестовый просмотр
</Button>
) : (
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
<Button
variant="contained"
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
minWidth: "130px",
}}
>
Тестовый просмотр
</Button>
</a>
)}
<Button
variant="outlined"
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
border: `1px solid ${theme.palette.brightPurple.main}`,
backgroundColor: quiz?.status === "start" ? theme.palette.brightPurple.main : "transparent",
color: quiz?.status === "start" ? "#FFFFFF" : theme.palette.brightPurple.main,
}}
onClick={() => {
updateQuiz(
quiz?.id, (state) => {
state.status = quiz?.status === "start" ? "stop" : "start"
}
)
}}
>{quiz?.status === "start" ? "Стоп" : "Старт"}</Button>
</Box>
</Box>
</>
);
} }

@ -51,139 +51,134 @@ export const Restore: FC = () => {
} }
return ( return (
<Box> <Dialog
<Button sx={{ width: "200px", height: "200px", background: "red" }} onClick={() => setIsDialogOpen(true)}> open={isDialogOpen}
open onClose={handleClose}
</Button> PaperProps={{
<Dialog sx: {
open={isDialogOpen} width: "600px",
onClose={handleClose} maxWidth: "600px",
PaperProps={{ },
sx: { }}
width: "600px", slotProps={{
maxWidth: "600px", backdrop: {
style: {
backgroundColor: "rgb(0 0 0 / 0.7)",
}, },
}} },
slotProps={{ }}
backdrop: { >
style: { <Box
backgroundColor: "rgb(0 0 0 / 0.7)", component="form"
}, onSubmit={formik.handleSubmit}
noValidate
sx={{
position: "relative",
backgroundColor: "white",
display: "flex",
alignItems: "center",
flexDirection: "column",
p: upMd ? "50px" : "18px",
pb: upMd ? "40px" : "30px",
gap: "15px",
borderRadius: "12px",
boxShadow: "0px 15px 80px rgb(210 208 225 / 70%)",
"& .MuiFormHelperText-root.Mui-error, & .MuiFormHelperText-root.Mui-error.MuiFormHelperText-filled": {
position: "absolute",
top: "46px",
margin: "0",
}, },
}} }}
> >
<Box <IconButton
component="form" onClick={handleClose}
onSubmit={formik.handleSubmit}
noValidate
sx={{ sx={{
position: "relative", position: "absolute",
backgroundColor: "white", right: "7px",
display: "flex", top: "7px",
alignItems: "center",
flexDirection: "column",
p: upMd ? "50px" : "18px",
pb: upMd ? "40px" : "30px",
gap: "15px",
borderRadius: "12px",
boxShadow: "0px 15px 80px rgb(210 208 225 / 70%)",
"& .MuiFormHelperText-root.Mui-error, & .MuiFormHelperText-root.Mui-error.MuiFormHelperText-filled": {
position: "absolute",
top: "46px",
margin: "0",
},
}} }}
> >
<IconButton <CloseIcon sx={{ transform: "scale(1.5)" }} />
onClick={handleClose} </IconButton>
sx={{ <Box sx={{ mt: upMd ? undefined : "62px" }}>
position: "absolute", <Logotip width={upMd ? 233 : 196} />
right: "7px",
top: "7px",
}}
>
<CloseIcon sx={{ transform: "scale(1.5)" }} />
</IconButton>
<Box sx={{ mt: upMd ? undefined : "62px" }}>
<Logotip width={upMd ? 233 : 196} />
</Box>
<Typography
sx={{
color: "#4D4D4D",
mt: "5px",
mb: upMd ? "30px" : "33px",
}}
>
Восстановление пароля
</Typography>
<InputTextfield
TextfieldProps={{
value: formik.values.email,
placeholder: "username",
onBlur: formik.handleBlur,
error: formik.touched.email && Boolean(formik.errors.email),
helperText: formik.touched.email && formik.errors.email,
"data-cy": "username",
}}
onChange={formik.handleChange}
color="#F2F3F7"
id="email"
label="Email"
gap={upMd ? "10px" : "10px"}
/>
<PasswordInput
TextfieldProps={{
value: formik.values.password,
placeholder: "Не менее 8 символов",
onBlur: formik.handleBlur,
error: formik.touched.password && Boolean(formik.errors.password),
helperText: formik.touched.password && formik.errors.password,
autoComplete: "new-password",
"data-cy": "password",
}}
onChange={formik.handleChange}
color="#F2F3F7"
id="password"
label="Пароль"
gap={upMd ? "10px" : "10px"}
/>
<PasswordInput
TextfieldProps={{
value: formik.values.repeatPassword,
placeholder: "Не менее 8 символов",
onBlur: formik.handleBlur,
error: formik.touched.repeatPassword && Boolean(formik.errors.repeatPassword),
helperText: formik.touched.repeatPassword && formik.errors.repeatPassword,
autoComplete: "new-password",
"data-cy": "repeat-password",
}}
onChange={formik.handleChange}
color="#F2F3F7"
id="repeatPassword"
label="Повторить пароль"
gap={upMd ? "10px" : "10px"}
/>
<Button
variant="contained"
fullWidth
type="submit"
disabled={formik.isSubmitting}
sx={{
py: "12px",
"&:hover": {
backgroundColor: "#581CA7",
},
"&:active": {
color: "white",
backgroundColor: "black",
},
}}
data-cy="signup"
>
Восстановить
</Button>
</Box> </Box>
</Dialog> <Typography
</Box> sx={{
color: "#4D4D4D",
mt: "5px",
mb: upMd ? "30px" : "33px",
}}
>
Восстановление пароля
</Typography>
<InputTextfield
TextfieldProps={{
value: formik.values.email,
placeholder: "username",
onBlur: formik.handleBlur,
error: formik.touched.email && Boolean(formik.errors.email),
helperText: formik.touched.email && formik.errors.email,
"data-cy": "username",
}}
onChange={formik.handleChange}
color="#F2F3F7"
id="email"
label="Email"
gap={upMd ? "10px" : "10px"}
/>
<PasswordInput
TextfieldProps={{
value: formik.values.password,
placeholder: "Не менее 8 символов",
onBlur: formik.handleBlur,
error: formik.touched.password && Boolean(formik.errors.password),
helperText: formik.touched.password && formik.errors.password,
autoComplete: "new-password",
"data-cy": "password",
}}
onChange={formik.handleChange}
color="#F2F3F7"
id="password"
label="Пароль"
gap={upMd ? "10px" : "10px"}
/>
<PasswordInput
TextfieldProps={{
value: formik.values.repeatPassword,
placeholder: "Не менее 8 символов",
onBlur: formik.handleBlur,
error: formik.touched.repeatPassword && Boolean(formik.errors.repeatPassword),
helperText: formik.touched.repeatPassword && formik.errors.repeatPassword,
autoComplete: "new-password",
"data-cy": "repeat-password",
}}
onChange={formik.handleChange}
color="#F2F3F7"
id="repeatPassword"
label="Повторить пароль"
gap={upMd ? "10px" : "10px"}
/>
<Button
variant="contained"
fullWidth
type="submit"
disabled={formik.isSubmitting}
sx={{
py: "12px",
"&:hover": {
backgroundColor: "#581CA7",
},
"&:active": {
color: "white",
backgroundColor: "black",
},
}}
data-cy="signup"
>
Восстановить
</Button>
</Box>
</Dialog>
); );
}; };

@ -92,16 +92,6 @@ export default function Header() {
gap: "15px", gap: "15px",
}} }}
> >
<Button
variant="contained"
sx={{
fontSize: "14px",
lineHeight: "18px",
height: "34px",
}}
>
Опубликовать
</Button>
<CustomAvatar <CustomAvatar
sx={{ ml: "11px", backgroundColor: theme.palette.orange.main, height: "36px", width: "36px" }} sx={{ ml: "11px", backgroundColor: theme.palette.orange.main, height: "36px", width: "36px" }}
/> />

@ -1,6 +1,6 @@
import { Box, Container, IconButton, Typography, useTheme, useMediaQuery } from "@mui/material"; import { Box, Container, IconButton, Typography, useTheme, useMediaQuery } from "@mui/material";
import NavMenuItem from "./NavMenuItem"; import NavMenuItem from "./NavMenuItem";
import PenaLogo from "../PenaLogo"; import Logotip from "../../pages/Landing/images/icons/QuizLogo";
import WalletIcon from "@icons/WalletIcon"; import WalletIcon from "@icons/WalletIcon";
import CustomAvatar from "./Avatar"; import CustomAvatar from "./Avatar";
import { Burger } from "@icons/Burger"; import { Burger } from "@icons/Burger";
@ -53,7 +53,7 @@ export default function HeaderFull() {
/> />
)} )}
<Link to="/"> <Link to="/">
<PenaLogo width={124} /> <Logotip width={124} />
</Link> </Link>
{!isTablet && ( {!isTablet && (
<Box <Box

@ -5,11 +5,12 @@ interface Props {
icon: any; icon: any;
text: string; text: string;
isActive?: boolean; isActive?: boolean;
disabled?: boolean;
isCollapsed: boolean; isCollapsed: boolean;
onClick: () => void; onClick: () => void;
} }
export default function MenuItem({ icon, text, isActive = false, isCollapsed, onClick }: Props) { export default function MenuItem({ icon, text, isActive = false, isCollapsed, onClick, disabled = false }: Props) {
const theme = useTheme(); const theme = useTheme();
return ( return (
@ -22,6 +23,7 @@ export default function MenuItem({ icon, text, isActive = false, isCollapsed, on
> >
<ListItemButton <ListItemButton
onClick={onClick} onClick={onClick}
disabled={disabled}
sx={{ sx={{
py: "4px", py: "4px",
gap: "14px", gap: "14px",

@ -40,8 +40,8 @@ const styleSlider: SxProps<Theme> = {
"&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": { "&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": {
boxShadow: `0px 0px 0px 3px white, boxShadow: `0px 0px 0px 3px white,
0px 4px 4px 3px #C3C8DD`, 0px 4px 4px 3px #C3C8DD`,
},
}, },
},
}; };
interface Props { interface Props {
@ -249,20 +249,9 @@ export const CropModal: FC<Props> = ({ isOpen, imageBlob, originalImageUrl, setC
marginTop: "40px", marginTop: "40px",
width: "100%", width: "100%",
display: "flex", display: "flex",
}}> gap: "10px",
<Button }}
onClick={handleSaveClick} >
disableRipple
data-cy="crop-modal-save-button"
sx={{
height: "48px",
color: "#7E2AEA",
borderRadius: "8px",
border: "1px solid #7E2AEA",
marginRight: "10px",
px: "20px",
}}
>Сохранить</Button>
<Button <Button
onClick={handleLoadOriginalImage} onClick={handleLoadOriginalImage}
disableRipple disableRipple
@ -273,8 +262,6 @@ export const CropModal: FC<Props> = ({ isOpen, imageBlob, originalImageUrl, setC
color: "#7E2AEA", color: "#7E2AEA",
borderRadius: "8px", borderRadius: "8px",
border: "1px solid #7E2AEA", border: "1px solid #7E2AEA",
marginRight: "10px",
ml: "auto",
}} }}
> >
Загрузить оригинал Загрузить оригинал
@ -282,18 +269,38 @@ export const CropModal: FC<Props> = ({ isOpen, imageBlob, originalImageUrl, setC
<Button <Button
onClick={handleCropClick} onClick={handleCropClick}
disableRipple disableRipple
variant="contained" disabled={!completedCrop}
disabled={!completedCrop?.width || !completedCrop?.height}
sx={{ sx={{
padding: "10px 20px", padding: "10px 20px",
borderRadius: "8px", borderRadius: "8px",
background: theme.palette.brightPurple.main, background: theme.palette.brightPurple.main,
fontSize: "18px", fontSize: "18px",
color: "#7E2AEA",
border: `1px solid ${!completedCrop ? "rgba(0, 0, 0, 0.26)" : "#7E2AEA"}`,
backgroundColor: "transparent",
}} }}
> >
<CropIcon /> <CropIcon color={!completedCrop ? "rgba(0, 0, 0, 0.26)" : "#7E2AEA"} />
Обрезать Обрезать
</Button> </Button>
<Button
onClick={handleSaveClick}
disableRipple
variant="contained"
data-cy="crop-modal-save-button"
sx={{
height: "48px",
borderRadius: "8px",
border: "1px solid #7E2AEA",
marginRight: "10px",
px: "20px",
ml: "auto",
}}
>
Сохранить
</Button>
</Box> </Box>
</Box> </Box>
</Modal> </Modal>

@ -15,6 +15,7 @@ import { setCurrentStep } from "@root/quizes/actions";
import { useQuizStore } from "@root/quizes/store"; import { useQuizStore } from "@root/quizes/store";
import { useState } from "react"; import { useState } from "react";
import MenuItem from "./MenuItem"; import MenuItem from "./MenuItem";
import {useCurrentQuiz} from "@root/quizes/hooks";
const quizSettingsMenuItems = [ const quizSettingsMenuItems = [
@ -28,6 +29,8 @@ export default function Sidebar() {
const theme = useTheme(); const theme = useTheme();
const [isMenuCollapsed, setIsMenuCollapsed] = useState(false); const [isMenuCollapsed, setIsMenuCollapsed] = useState(false);
const currentStep = useQuizStore(state => state.currentStep); const currentStep = useQuizStore(state => state.currentStep);
const quiz = useCurrentQuiz();
const handleMenuCollapseToggle = () => setIsMenuCollapsed((prev) => !prev); const handleMenuCollapseToggle = () => setIsMenuCollapsed((prev) => !prev);
@ -94,6 +97,7 @@ export default function Sidebar() {
text={menuItem.sidebarText} text={menuItem.sidebarText}
isCollapsed={isMenuCollapsed} isCollapsed={isMenuCollapsed}
isActive={currentStep === index} isActive={currentStep === index}
disabled={index===0 ? false : quiz===undefined ? true : (quiz?.config.type === null)}
icon={ icon={
<Icon <Icon
color={ color={