diff --git a/src/App.tsx b/src/App.tsx
index a3b69afd..d717a830 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -5,7 +5,7 @@ import "dayjs/locale/ru";
import SigninDialog from "./pages/auth/Signin";
import SignupDialog from "./pages/auth/Signup";
import { ViewPage } from "./pages/ViewPublicationPage";
-import { BrowserRouter, Route, Routes, useLocation, useNavigate, Navigate } from "react-router-dom";
+import { Route, Routes, useLocation, useNavigate, Navigate } from "react-router-dom";
import "./index.css";
import ContactFormPage from "./pages/ContactFormPage/ContactFormPage";
import InstallQuiz from "./pages/InstallQuiz/InstallQuiz";
@@ -21,61 +21,65 @@ import { clearUserData, setUser, useUserStore } from "@root/user";
import { enqueueSnackbar } from "notistack";
import PrivateRoute from "@ui_kit/PrivateRoute";
+import { Restore } from "./pages/startPage/Restore";
dayjs.locale("ru");
const routeslink = [
- { path: "/list", page: , header: false, sidebar: false },
- { path: "/questions/:quizId", page: , header: true, sidebar: true, },
- { path: "/contacts", page: , header: true, sidebar: true },
- { path: "/result", page: , header: true, sidebar: true },
- { path: "/settings", page: , header: true, sidebar: true },
- { path: "/install", page: , header: true, sidebar: true },
+ { path: "/list", page: , header: false, sidebar: false },
+ { path: "/questions/:quizId", page: , header: true, sidebar: true },
+ { path: "/contacts", page: , header: true, sidebar: true },
+ { path: "/result", page: , header: true, sidebar: true },
+ { path: "/settings", page: , header: true, sidebar: true },
+ { path: "/install", page: , header: true, sidebar: true },
] as const;
export default function App() {
- const userId = useUserStore((state) => state.userId);
- const location = useLocation();
- const navigate = useNavigate();
+ const userId = useUserStore((state) => state.userId);
+ const location = useLocation();
+ const navigate = useNavigate();
- useUserFetcher({
- url: `https://hub.pena.digital/user/${userId}`,
- userId,
- onNewUser: setUser,
- onError: (error) => {
- const errorMessage = getMessageFromFetchError(error);
- if (errorMessage) {
- enqueueSnackbar(errorMessage);
- clearUserData();
- clearAuthToken();
- }
- },
- });
- if (location.state?.redirectTo)
- return ;
+ useUserFetcher({
+ url: `https://hub.pena.digital/user/${userId}`,
+ userId,
+ onNewUser: setUser,
+ onError: (error) => {
+ const errorMessage = getMessageFromFetchError(error);
+ if (errorMessage) {
+ enqueueSnackbar(errorMessage);
+ clearUserData();
+ clearAuthToken();
+ }
+ },
+ });
+ if (location.state?.redirectTo)
+ return ;
- return (
- <>
-
- {location.state?.backgroundLocation && (
-
- } />
- } />
-
- )}
-
- } />
- } />
- } />
- }>
- {routeslink.map((e, i) => (
- } />
- ))}
- } />
- } />
- } />
-
-
- >
- );
-}
\ No newline at end of file
+ return (
+ <>
+
+ {location.state?.backgroundLocation && (
+
+ } />
+ } />
+ } />
+
+ )}
+
+ } />
+ } />
+ } />
+ } />
+ }>
+ {routeslink.map((e, i) => (
+ } />
+ ))}
+
+ } />
+ } />
+ } />
+
+
+ >
+ );
+}
diff --git a/src/pages/Questions/BranchingMap/CsComponent.tsx b/src/pages/Questions/BranchingMap/CsComponent.tsx
index 3df6a30e..d07c5b35 100644
--- a/src/pages/Questions/BranchingMap/CsComponent.tsx
+++ b/src/pages/Questions/BranchingMap/CsComponent.tsx
@@ -51,7 +51,6 @@ type Popper = {
type NodeSingularWithPopper = NodeSingular & {
popper: (config: PopperConfig) => Popper;
};
- let counter = 0;
const stylesheet: Stylesheet[] = [
{
@@ -161,7 +160,6 @@ function CsComponent({
}, [modalQuestionTargetContentId])
const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => {
-console.log('AN', counter++, parentNodeContentId,targetNodeContentId)
//запрещаем работу родителя-ребенка если это один и тот же вопрос
if (parentNodeContentId === targetNodeContentId) return
@@ -171,7 +169,6 @@ console.log('AN', counter++, parentNodeContentId,targetNodeContentId)
const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length
//если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
const targetQuestion = { ...getQuestionByContentId(targetNodeContentId || dragQuestionContentId) } as AnyTypedQuizQuestion
-console.log('AN1', targetQuestion, parentNodeContentId,parentNodeChildren)
if (Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) {
clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren })
cy?.data('changed', true)
@@ -199,13 +196,13 @@ console.log('AN1', targetQuestion, parentNodeContentId,parentNodeChildren)
const clearDataAfterAddNode = ({ parentNodeContentId, targetQuestion, parentNodeChildren }: { parentNodeContentId: string, targetQuestion: AnyTypedQuizQuestion, parentNodeChildren: number }) => {
-console.log('AN2', parentNodeContentId,parentNodeChildren,targetQuestion)
const parentQuestion = { ...getQuestionByContentId(parentNodeContentId) } as AnyTypedQuizQuestion
//смотрим не добавлен ли родителю result. Если да - убираем его. Веточкам result не нужен
trashQuestions.forEach((targetQuestion) => {
if (targetQuestion.type === "result" && targetQuestion.content.rule.parentId === parentQuestion.content.id) {
+ console.log('deleteQ', targetQuestion.id)
deleteQuestion(targetQuestion.id);
}
})
diff --git a/src/pages/Questions/DraggableList/QuestionPageCard.tsx b/src/pages/Questions/DraggableList/QuestionPageCard.tsx
index d4ea5342..73c19b13 100644
--- a/src/pages/Questions/DraggableList/QuestionPageCard.tsx
+++ b/src/pages/Questions/DraggableList/QuestionPageCard.tsx
@@ -18,18 +18,28 @@ import RatingIcon from "@icons/questionsPage/rating";
import Slider from "@icons/questionsPage/slider";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import {
- Box,
- Checkbox,
- FormControl,
- FormControlLabel,
- IconButton,
- InputAdornment,
- Paper,
- TextField,
- useMediaQuery,
- useTheme,
+ Box,
+ Checkbox,
+ FormControl,
+ FormControlLabel,
+ IconButton,
+ InputAdornment,
+ Paper,
+ TextField,
+ useMediaQuery,
+ useTheme,
} from "@mui/material";
-import { copyQuestion, createUntypedQuestion, deleteQuestion, clearRuleForAll, toggleExpandQuestion, updateQuestion, updateUntypedQuestion, getQuestionByContentId, deleteQuestionWithTimeout } from "@root/questions/actions";
+import {
+ copyQuestion,
+ createUntypedQuestion,
+ deleteQuestion,
+ clearRuleForAll,
+ toggleExpandQuestion,
+ updateQuestion,
+ updateUntypedQuestion,
+ getQuestionByContentId,
+ deleteQuestionWithTimeout,
+} from "@root/questions/actions";
import { updateRootContentId } from "@root/quizes/actions";
import { useRef, useState } from "react";
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
@@ -44,445 +54,387 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuestionsStore } from "@root/questions/store";
interface Props {
- question: AnyTypedQuizQuestion | UntypedQuizQuestion;
- draggableProps: DraggableProvidedDragHandleProps | null | undefined;
- isDragging: boolean;
- index: number;
+ question: AnyTypedQuizQuestion | UntypedQuizQuestion;
+ draggableProps: DraggableProvidedDragHandleProps | null | undefined;
+ isDragging: boolean;
+ index: number;
}
export default function QuestionsPageCard({ question, draggableProps, isDragging, index }: Props) {
- const { questions } = useQuestionsStore();
- const [plusVisible, setPlusVisible] = useState(false);
- const [open, setOpen] = useState(false);
- const theme = useTheme();
- const isTablet = useMediaQuery(theme.breakpoints.down(1000));
- const isMobile = useMediaQuery(theme.breakpoints.down(790));
- const anchorRef = useRef(null);
- const quiz = useCurrentQuiz();
+ const { questions } = useQuestionsStore();
+ const [plusVisible, setPlusVisible] = useState(false);
+ const [open, setOpen] = useState(false);
+ const theme = useTheme();
+ const isTablet = useMediaQuery(theme.breakpoints.down(1000));
+ const isMobile = useMediaQuery(theme.breakpoints.down(790));
+ const anchorRef = useRef(null);
+ const quiz = useCurrentQuiz();
- const setTitle = useDebouncedCallback((title) => {
- const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
+ const setTitle = useDebouncedCallback((title) => {
+ const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
- updateQuestionFn(question.id, question => {
- question.title = title;
- });
- }, 200);
+ updateQuestionFn(question.id, (question) => {
+ question.title = title;
+ });
+ }, 200);
- return (
- <>
-
-
-
+
+
+
+ setTitle(target.value || " ")}
+ InputProps={{
+ startAdornment: (
+
+ setOpen((isOpened) => !isOpened)}
>
- setTitle(target.value || " ")}
- InputProps={{
- startAdornment: (
-
- setOpen((isOpened) => !isOpened)}
- >
- {IconAndrom(question.expanded, question.type)}
-
- setOpen(false)}
- anchorRef={anchorRef}
- question={question}
- questionType={question.type}
- />
-
- ),
- }}
- sx={{
- margin: isMobile ? "10px 0" : 0,
- "& .MuiInputBase-root": {
- color: "#000000",
- backgroundColor: question.expanded
- ? theme.palette.background.default
- : "transparent",
- height: "48px",
- borderRadius: "10px",
- ".MuiOutlinedInput-notchedOutline": {
- borderWidth: "1px !important",
- border: !question.expanded ? "none" : null,
- },
- "& .MuiInputBase-input::placeholder": {
- color: "#4D4D4D",
- opacity: 0.8,
- },
- },
- }}
- inputProps={{
- sx: {
- fontSize: "18px",
- lineHeight: "21px",
- py: 0,
- paddingLeft: question.type === null ? 0 : "18px",
- },
- "data-cy": "quiz-question-title",
- }}
- />
-
-
- toggleExpandQuestion(question.id)}
- >
- {question.expanded ? (
-
- ) : (
-
- )}
-
- {question.expanded ? (
- <>>
- ) : (
-
-
- }
- checkedIcon={}
- />
- }
- label={""}
- sx={{
- color: theme.palette.grey2.main,
- ml: "-9px",
- mr: 0,
- userSelect: "none",
- }}
- />
- copyQuestion(question.id, question.quizId)}
- >
-
-
- {
- const deleteFn = () => {
- if (question.type !== null) {
- if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
- updateRootContentId(quiz.id, "");
- clearRuleForAll();
- deleteQuestion(question.id);
- questions.forEach(q => {
- if (q.type === "result") {
- deleteQuestion(q.id);
- }
- });
- } else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
- const clearQuestions = [] as string[];
-
- //записываем потомков , а их результаты удаляем
- const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
- questions.forEach((targetQuestion) => {
- if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
- if (targetQuestion.type === "result") {
- deleteQuestion(targetQuestion.id);
- } else {
- if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id);
- getChildren(targetQuestion); //и ищем его потомков
- }
- }
- });
- };
- getChildren(question);
- //чистим потомков от инфы ветвления
- clearQuestions.forEach((id) => {
- updateQuestion(id, question => {
- question.content.rule.parentId = "";
- question.content.rule.main = [];
- question.content.rule.default = "";
- });
- });
-
- //чистим rule родителя
- const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
- const newRule = {};
- newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id); //удаляем условия перехода от родителя к этому вопросу
- newRule.parentId = parentQuestion.content.rule.parentId;
- newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId;
- newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
-
- updateQuestion(question.content.rule.parentId, (PQ) => {
- PQ.content.rule = newRule;
- });
- deleteQuestion(question.id);
- }
-
-
- deleteQuestion(question.id);
- } else {
- console.log("удаляю безтипогово");
- deleteQuestion(question.id);
- }
- };
-
- deleteQuestionWithTimeout(question.id, deleteFn);
- }}
- data-cy="delete-question"
- >
-
-
-
- )}
- {question.type !== null &&
-
- {question.page + 1}
-
- }
-
-
-
-
-
- {question.expanded && (
-
- {question.type === null ? (
-
- ) : (
-
- )}
-
- )}
-
- setPlusVisible(true)}
- onMouseLeave={() => setPlusVisible(false)}
- sx={{
- maxWidth: "825px",
- display: "flex",
- alignItems: "center",
- height: "40px",
- cursor: "pointer",
- }}
- >
- createUntypedQuestion(question.quizId, question.id)}
- sx={{
- display: plusVisible && !isDragging ? "flex" : "none",
- width: "100%",
- alignItems: "center",
- columnGap: "10px",
- }}
- data-cy="create-question"
- >
-
+ setOpen(false)}
+ anchorRef={anchorRef}
+ question={question}
+ questionType={question.type}
/>
-
-
-
- >
- );
+
+ ),
+ }}
+ sx={{
+ margin: isMobile ? "10px 0" : 0,
+ "& .MuiInputBase-root": {
+ color: "#000000",
+ backgroundColor: question.expanded ? theme.palette.background.default : "transparent",
+ height: "48px",
+ borderRadius: "10px",
+ ".MuiOutlinedInput-notchedOutline": {
+ borderWidth: "1px !important",
+ border: !question.expanded ? "none" : null,
+ },
+ "& .MuiInputBase-input::placeholder": {
+ color: "#4D4D4D",
+ opacity: 0.8,
+ },
+ },
+ }}
+ inputProps={{
+ sx: {
+ fontSize: "18px",
+ lineHeight: "21px",
+ py: 0,
+ paddingLeft: question.type === null ? 0 : "18px",
+ },
+ "data-cy": "quiz-question-title",
+ }}
+ />
+
+
+ toggleExpandQuestion(question.id)}
+ >
+ {question.expanded ? (
+
+ ) : (
+
+ )}
+
+ {question.expanded ? (
+ <>>
+ ) : (
+
+
+ }
+ checkedIcon={}
+ />
+ }
+ label={""}
+ sx={{
+ color: theme.palette.grey2.main,
+ ml: "-9px",
+ mr: 0,
+ userSelect: "none",
+ }}
+ />
+ copyQuestion(question.id, question.quizId)}>
+
+
+ {
+ const deleteFn = () => {
+ if (question.type !== null) {
+ if (question.content.rule.parentId === "root") {
+ //удалить из стора root и очистить rule всем вопросам
+ updateRootContentId(quiz.id, "");
+ clearRuleForAll();
+ deleteQuestion(question.id);
+ questions.forEach((q) => {
+ if (q.type === "result") {
+ deleteQuestion(q.id);
+ }
+ });
+ } else if (question.content.rule.parentId.length > 0) {
+ //удалить из стора вопрос из дерева и очистить его потомков
+ const clearQuestions = [] as string[];
+
+ //записываем потомков , а их результаты удаляем
+ const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
+ questions.forEach((targetQuestion) => {
+ if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {
+ //если у вопроса совпал родитель с родителем => он потомок, в кучу его
+ if (targetQuestion.type === "result") {
+ deleteQuestion(targetQuestion.id);
+ } else {
+ if (!clearQuestions.includes(targetQuestion.content.id))
+ clearQuestions.push(targetQuestion.content.id);
+ getChildren(targetQuestion); //и ищем его потомков
+ }
+ }
+ });
+ };
+ getChildren(question);
+ //чистим потомков от инфы ветвления
+ clearQuestions.forEach((id) => {
+ updateQuestion(id, (question) => {
+ question.content.rule.parentId = "";
+ question.content.rule.main = [];
+ question.content.rule.default = "";
+ });
+ });
+
+ //чистим rule родителя
+ const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
+ const newRule = {};
+ newRule.main = parentQuestion.content.rule.main.filter(
+ (data) => data.next !== question.content.id
+ ); //удаляем условия перехода от родителя к этому вопросу
+ newRule.parentId = parentQuestion.content.rule.parentId;
+ newRule.default =
+ parentQuestion.content.rule.parentId === question.content.id
+ ? ""
+ : parentQuestion.content.rule.parentId;
+ newRule.children = [...parentQuestion.content.rule.children].splice(
+ parentQuestion.content.rule.children.indexOf(question.content.id),
+ 1
+ );
+
+ updateQuestion(question.content.rule.parentId, (PQ) => {
+ PQ.content.rule = newRule;
+ });
+ deleteQuestion(question.id);
+ }
+
+ deleteQuestion(question.id);
+ } else {
+ console.log("удаляю безтипогово");
+ deleteQuestion(question.id);
+ }
+ };
+
+ deleteQuestionWithTimeout(question.id, deleteFn);
+ }}
+ data-cy="delete-question"
+ >
+
+
+
+ )}
+ {question.type !== null && (
+
+ {question.page + 1}
+
+ )}
+
+
+
+
+
+ {question.expanded && (
+
+ {question.type === null ? (
+
+ ) : (
+
+ )}
+
+ )}
+
+ setPlusVisible(true)}
+ onMouseLeave={() => setPlusVisible(false)}
+ sx={{
+ maxWidth: "825px",
+ display: "flex",
+ alignItems: "center",
+ height: "40px",
+ cursor: "pointer",
+ }}
+ >
+ createUntypedQuestion(question.quizId, question.id)}
+ sx={{
+ display: plusVisible && !isDragging ? "flex" : "none",
+ width: "100%",
+ alignItems: "center",
+ columnGap: "10px",
+ }}
+ data-cy="create-question"
+ >
+
+
+
+
+ >
+ );
}
const IconAndrom = (isExpanded: boolean, questionType: QuestionType | null) => {
- switch (questionType) {
- case "variant":
- return (
-
- );
- case "images":
- return (
-
- );
- case "varimg":
- return (
-
- );
- case "emoji":
- return (
-
- );
- case "text":
- return (
-
- );
- case "select":
- return (
-
- );
- case "date":
- return (
-
- );
- case "number":
- return (
-
- );
- case "file":
- return (
-
- );
- case "page":
- return (
-
- );
- case "rating":
- return (
-
- );
- default:
- return <>>;
- }
+ switch (questionType) {
+ case "variant":
+ return ;
+ case "images":
+ return ;
+ case "varimg":
+ return ;
+ case "emoji":
+ return ;
+ case "text":
+ return ;
+ case "select":
+ return ;
+ case "date":
+ return ;
+ case "number":
+ return ;
+ case "file":
+ return ;
+ case "page":
+ return ;
+ case "rating":
+ return ;
+ default:
+ return <>>;
+ }
};
diff --git a/src/pages/Questions/Form/FormDraggableList/FormDraggableListItem.tsx b/src/pages/Questions/Form/FormDraggableList/FormDraggableListItem.tsx
index 61b62039..d8e89df0 100644
--- a/src/pages/Questions/Form/FormDraggableList/FormDraggableListItem.tsx
+++ b/src/pages/Questions/Form/FormDraggableList/FormDraggableListItem.tsx
@@ -5,80 +5,77 @@ import { Draggable } from "react-beautiful-dnd";
import { AnyTypedQuizQuestion, UntypedQuizQuestion } from "../../../../model/questionTypes/shared";
import QuestionsPageCard from "./QuestionPageCard";
-
type FormDraggableListItemProps = {
- question: AnyTypedQuizQuestion | UntypedQuizQuestion;
- questionIndex: number;
+ question: AnyTypedQuizQuestion | UntypedQuizQuestion;
+ questionIndex: number;
};
-export default memo(
- ({ question, questionIndex }: FormDraggableListItemProps) => {
- const theme = useTheme();
+export default memo(({ question, questionIndex }: FormDraggableListItemProps) => {
+ const theme = useTheme();
- return (
-
- {(provided) => (
-
- {question.deleted ? (
-
-
- Вопрос удалён.
-
- {
- updateQuestion(question.id, question => {
- question.deleted = false;
- });
- }}
- sx={{
- cursor: "pointer",
- fontSize: "16px",
- textDecoration: "underline",
- color: theme.palette.brightPurple.main,
- textDecorationColor: theme.palette.brightPurple.main,
- }}
- >
- Восстановить?
-
-
- ) : (
-
-
-
- )}
-
- )}
-
- );
- }
-);
+ return (
+
+ {(provided) => (
+
+ {question.deleted ? (
+
+
+ Вопрос удалён.
+
+ {
+ updateQuestion(question.id, (question) => {
+ question.deleted = false;
+ });
+ }}
+ sx={{
+ cursor: "pointer",
+ fontSize: "16px",
+ textDecoration: "underline",
+ color: theme.palette.brightPurple.main,
+ textDecorationColor: theme.palette.brightPurple.main,
+ }}
+ >
+ Восстановить?
+
+
+ ) : (
+
+
+
+ )}
+
+ )}
+
+ );
+});
diff --git a/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx b/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx
index 89e8006e..d4f140f5 100644
--- a/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx
+++ b/src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx
@@ -11,8 +11,8 @@ import OptionsPict from "@icons/questionsPage/options_pict";
import Page from "@icons/questionsPage/page";
import RatingIcon from "@icons/questionsPage/rating";
import Slider from "@icons/questionsPage/slider";
-import { Box, InputAdornment, Paper } from "@mui/material";
-import { updateQuestion, updateUntypedQuestion } from "@root/questions/actions";
+import { Box, FormControlLabel, IconButton, InputAdornment, Paper, useMediaQuery, useTheme } from "@mui/material";
+import { toggleExpandQuestion, updateQuestion, updateUntypedQuestion } from "@root/questions/actions";
import CustomTextField from "@ui_kit/CustomTextField";
import { useRef, useState } from "react";
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
@@ -22,142 +22,206 @@ import SwitchQuestionsPage from "../../SwitchQuestionsPage";
import { ChooseAnswerModal } from "./ChooseAnswerModal";
import FormTypeQuestions from "../FormTypeQuestions";
import { QuestionType } from "@model/question/question";
-
+import { CrossedEyeIcon } from "@icons/CrossedEyeIcon";
+import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon";
+import { CopyIcon } from "@icons/questionsPage/CopyIcon";
+import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
+import { HideIcon } from "@icons/questionsPage/hideIcon";
+import ExpandLessIcon from "@mui/icons-material/ExpandLess";
+import { NoLuggageOutlined, SignalCellularNullOutlined } from "@mui/icons-material";
interface Props {
- question: AnyTypedQuizQuestion | UntypedQuizQuestion;
- questionIndex: number;
- draggableProps: DraggableProvidedDragHandleProps | null | undefined;
+ question: AnyTypedQuizQuestion | UntypedQuizQuestion;
+ questionIndex: number;
+ draggableProps: DraggableProvidedDragHandleProps | null | undefined;
}
-export default function QuestionsPageCard({
- question,
- questionIndex,
- draggableProps,
-}: Props) {
- const [open, setOpen] = useState(false);
- const anchorRef = useRef(null);
+export default function QuestionsPageCard({ question, questionIndex, draggableProps }: Props) {
+ const [open, setOpen] = useState(false);
+ const anchorRef = useRef(null);
+ const theme = useTheme();
+ const isTablet = useMediaQuery(theme.breakpoints.down(1000));
+ const isMobile = useMediaQuery(theme.breakpoints.down(790));
- const setTitle = useDebouncedCallback((title) => {
- const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
+ const setTitle = useDebouncedCallback((title) => {
+ const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
- updateQuestionFn(question.id, question => {
- question.title = title;
- });
- }, 200);
+ updateQuestionFn(question.id, (question) => {
+ question.title = title;
+ });
+ }, 200);
- return (
- <>
-
-
- setTitle(target.value)}
- sx={{ margin: "20px", width: "auto" }}
- InputProps={{
- startAdornment: (
-
- setOpen((isOpened) => !isOpened)}
- >
- {IconAndrom(question.type)}
-
- setOpen(false)}
- anchorRef={anchorRef}
- question={question}
- questionType={question.type}
- />
-
- ),
- endAdornment: (
-
- {questionIndex !== 0 && (
-
-
-
- )}
-
- ),
- }}
+ return (
+ <>
+
+
+
+ setTitle(target.value)}
+ sx={{ width: "100%" }}
+ InputProps={{
+ startAdornment: (
+
+ setOpen((isOpened) => !isOpened)}
+ >
+ {IconAndrom(question.type)}
+
+ setOpen(false)}
+ anchorRef={anchorRef}
+ question={question}
+ questionType={question.type}
/>
- {question.type === null ? (
-
- ) : (
-
- )}
+
+ ),
+ }}
+ />
+
+
+ toggleExpandQuestion(question.id)}
+ >
+ {question.expanded ? (
+
+ ) : (
+
+ )}
+
+
+
+ {questionIndex + 1}
-
- >
- );
+
+
+
+
+
+
+
+
+ {question.type === null ? (
+
+ ) : (
+
+ )}
+
+
+ >
+ );
}
const IconAndrom = (questionType: QuestionType | null) => {
- switch (questionType) {
- case "variant":
- return ;
- case "images":
- return (
-
- );
- case "varimg":
- return (
-
- );
- case "emoji":
- return ;
- case "text":
- return ;
- case "select":
- return (
-
- );
- case "date":
- return ;
- case "number":
- return ;
- case "file":
- return (
-
- );
- case "page":
- return ;
- case "rating":
- return (
-
- );
- default:
- return (
-
- );
- }
+ switch (questionType) {
+ case "variant":
+ return ;
+ case "images":
+ return ;
+ case "varimg":
+ return ;
+ case "emoji":
+ return ;
+ case "text":
+ return ;
+ case "select":
+ return ;
+ case "date":
+ return ;
+ case "number":
+ return ;
+ case "file":
+ return ;
+ case "page":
+ return ;
+ case "rating":
+ return ;
+ default:
+ return ;
+ }
};
diff --git a/src/pages/Questions/Form/FormDraggableList/index.tsx b/src/pages/Questions/Form/FormDraggableList/index.tsx
index 9eda5284..77c01d28 100644
--- a/src/pages/Questions/Form/FormDraggableList/index.tsx
+++ b/src/pages/Questions/Form/FormDraggableList/index.tsx
@@ -5,31 +5,25 @@ import { DragDropContext, Droppable } from "react-beautiful-dnd";
import FormDraggableListItem from "./FormDraggableListItem";
import { useQuestions } from "@root/questions/hooks";
-
export const FormDraggableList = () => {
+ const { questions } = useQuestions();
- const { questions } = useQuestions()
-
- const onDragEnd = ({ destination, source }: DropResult) => {
- if (destination) reorderQuestions(source.index, destination.index);
- };
+ const onDragEnd = ({ destination, source }: DropResult) => {
+ if (destination) reorderQuestions(source.index, destination.index);
+ };
- return (
-
-
- {(provided) => (
-
- {questions?.map((question, index) => (
-
- ))}
- {provided.placeholder}
-
- )}
-
-
- );
+ return (
+
+
+ {(provided) => (
+
+ {questions?.map((question, index) => (
+
+ ))}
+ {provided.placeholder}
+
+ )}
+
+
+ );
};
diff --git a/src/pages/Questions/Form/FormQuestionsPage.tsx b/src/pages/Questions/Form/FormQuestionsPage.tsx
index d4e138fe..baca3a95 100644
--- a/src/pages/Questions/Form/FormQuestionsPage.tsx
+++ b/src/pages/Questions/Form/FormQuestionsPage.tsx
@@ -8,106 +8,103 @@ import { FormDraggableList } from "./FormDraggableList";
import { collapseAllQuestions, createUntypedQuestion } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
-
export default function FormQuestionsPage() {
- const theme = useTheme();
- const quiz = useCurrentQuiz();
+ const theme = useTheme();
+ const quiz = useCurrentQuiz();
- if (!quiz) return null;
+ if (!quiz) return null;
- return (
- <>
-
- Заголовок анкеты
-
-
-
-
- {
- createUntypedQuestion(quiz.backendId);
- }}
- data-cy="create-question"
- >
-
-
- Добавить еще один вопрос
-
-
-
-
-
-
-
- {createPortal(, document.body)}
- >
- );
+ return (
+ <>
+
+ Заголовок анкеты
+
+
+
+
+ {
+ createUntypedQuestion(quiz.backendId);
+ }}
+ data-cy="create-question"
+ >
+
+ Добавить еще один вопрос
+
+
+
+
+
+
+ {createPortal(, document.body)}
+ >
+ );
}
diff --git a/src/pages/Questions/Form/FormTypeQuestions.tsx b/src/pages/Questions/Form/FormTypeQuestions.tsx
index a1bc3907..b0cd4fe7 100644
--- a/src/pages/Questions/Form/FormTypeQuestions.tsx
+++ b/src/pages/Questions/Form/FormTypeQuestions.tsx
@@ -12,80 +12,75 @@ import Slider from "../../../assets/icons/questionsPage/slider";
import { QuestionType } from "@model/question/question";
import { createTypedQuestion } from "@root/questions/actions";
-import type {
- UntypedQuizQuestion
-} from "../../../model/questionTypes/shared";
-
+import type { UntypedQuizQuestion } from "../../../model/questionTypes/shared";
type ButtonTypeQuestion = {
- icon: JSX.Element;
- title: string;
- value: QuestionType;
+ icon: JSX.Element;
+ title: string;
+ value: QuestionType;
};
const BUTTON_TYPE_SHORT_QUESTIONS: ButtonTypeQuestion[] = [
- {
- icon: ,
- title: "Варианты ответов",
- value: "variant",
- },
- {
- icon: ,
- title: "Своё поле для ввода",
- value: "text",
- },
- {
- icon: ,
- title: "Выпадающий список",
- value: "select",
- },
- {
- icon: ,
- title: "Дата",
- value: "date",
- },
- {
- icon: ,
- title: "Ползунок",
- value: "number",
- },
- {
- icon: ,
- title: "Загрузка файла",
- value: "file",
- },
+ {
+ icon: ,
+ title: "Варианты ответов",
+ value: "variant",
+ },
+ {
+ icon: ,
+ title: "Своё поле для ввода",
+ value: "text",
+ },
+ {
+ icon: ,
+ title: "Выпадающий список",
+ value: "select",
+ },
+ {
+ icon: ,
+ title: "Дата",
+ value: "date",
+ },
+ {
+ icon: ,
+ title: "Ползунок",
+ value: "number",
+ },
+ {
+ icon: ,
+ title: "Загрузка файла",
+ value: "file",
+ },
];
interface Props {
- question: UntypedQuizQuestion;
+ question: UntypedQuizQuestion;
}
export default function FormTypeQuestions({ question }: Props) {
-
- return (
-
-
- {(("page" in question) && question.page === 0
- ? BUTTON_TYPE_QUESTIONS
- : BUTTON_TYPE_SHORT_QUESTIONS
- ).map(({ icon, title, value: questionType }) => (
- {
- createTypedQuestion(question.id, questionType);
- }}
- icon={icon}
- text={title}
- />
- ))}
-
-
- );
+ return (
+
+
+ {("page" in question && question.page === 0 ? BUTTON_TYPE_QUESTIONS : BUTTON_TYPE_SHORT_QUESTIONS).map(
+ ({ icon, title, value: questionType }) => (
+ {
+ createTypedQuestion(question.id, questionType);
+ }}
+ icon={icon}
+ text={title}
+ />
+ )
+ )}
+
+
+ );
}
diff --git a/src/pages/Questions/QuestionsPage.tsx b/src/pages/Questions/QuestionsPage.tsx
index 20b72b5c..e1593a9f 100755
--- a/src/pages/Questions/QuestionsPage.tsx
+++ b/src/pages/Questions/QuestionsPage.tsx
@@ -1,12 +1,5 @@
-import { useState, useEffect, useLayoutEffect, useRef } from "react"
-import {
- Box,
- Button,
- IconButton,
- Typography,
- useMediaQuery,
- useTheme,
-} from "@mui/material";
+import { useState, useEffect, useLayoutEffect, useRef } from "react";
+import { Box, Button, IconButton, Typography, useMediaQuery, useTheme } from "@mui/material";
import { collapseAllQuestions, createUntypedQuestion } from "@root/questions/actions";
import { decrementCurrentStep, incrementCurrentStep } from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
@@ -14,105 +7,102 @@ import QuizPreview from "@ui_kit/QuizPreview/QuizPreview";
import { createPortal } from "react-dom";
import AddPlus from "../../assets/icons/questionsPage/addPlus";
import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft";
-import BranchingQuestions from "./BranchingModal/BranchingQuestionsModal"
+import BranchingQuestions from "./BranchingModal/BranchingQuestionsModal";
import { QuestionSwitchWindowTool } from "./QuestionSwitchWindowTool";
import { useQuestionsStore } from "@root/questions/store";
import { updateOpenBranchingPanel, updateEditSomeQuestion } from "@root/uiTools/actions";
import { useUiTools } from "@root/uiTools/store";
export default function QuestionsPage() {
- const theme = useTheme();
- const { openedModalSettingsId, openBranchingPanel } = useUiTools();
- const isMobile = useMediaQuery(theme.breakpoints.down(660));
- const quiz = useCurrentQuiz();
- useLayoutEffect(() => {
- updateOpenBranchingPanel(false)
- updateEditSomeQuestion()
- },[])
+ const theme = useTheme();
+ const { openedModalSettingsId, openBranchingPanel } = useUiTools();
+ const isMobile = useMediaQuery(theme.breakpoints.down(660));
+ const quiz = useCurrentQuiz();
+ useLayoutEffect(() => {
+ updateOpenBranchingPanel(false);
+ updateEditSomeQuestion();
+ }, []);
- const ref = useRef()
- if (!quiz) return null;
+ const ref = useRef();
+ if (!quiz) return null;
+ return (
+ <>
+
+ {quiz.name ? quiz.name : "Заголовок квиза"}
+
+
+
+
+ {
+ createUntypedQuestion(quiz.backendId);
+ }}
+ sx={{
+ position: "fixed",
+ left: isMobile ? "20px" : "250px",
+ bottom: isMobile ? "140px" : "20px",
+ }}
+ data-cy="create-question"
+ >
+
+
- return (
- <>
-
- {
- quiz.name ? quiz.name : "Заголовок квиза" }
-
-
-
-
- {
- createUntypedQuestion(quiz.backendId);
- }}
- sx={{
- position: "fixed",
- left: isMobile ? "20px" : "250px",
- bottom: isMobile ? "140px" : "20px",
- }}
- data-cy="create-question"
- >
-
-
-
-
-
-
-
-
-
- {createPortal(, document.body)}
- {openedModalSettingsId !== null && }
- >
- );
+
+
+
+
+
+ {createPortal(, document.body)}
+ {openedModalSettingsId !== null && }
+ >
+ );
}
diff --git a/src/pages/Questions/SwitchQuestionsPage.tsx b/src/pages/Questions/SwitchQuestionsPage.tsx
index 31e29c15..44911e35 100644
--- a/src/pages/Questions/SwitchQuestionsPage.tsx
+++ b/src/pages/Questions/SwitchQuestionsPage.tsx
@@ -12,48 +12,46 @@ import UploadFile from "./UploadFile/UploadFile";
import AnswerOptions from "./answerOptions/AnswerOptions";
import { notReachable } from "../../utils/notReachable";
-
interface Props {
- question: AnyTypedQuizQuestion;
+ question: AnyTypedQuizQuestion;
}
export default function SwitchQuestionsPage({ question }: Props) {
+ switch (question.type) {
+ case "variant":
+ return ;
- switch (question.type) {
- case "variant":
- return ;
+ case "images":
+ return ;
- case "images":
- return ;
+ case "varimg":
+ return ;
- case "varimg":
- return ;
+ case "emoji":
+ return ;
- case "emoji":
- return ;
+ case "text":
+ return ;
- case "text":
- return ;
+ case "select":
+ return ;
- case "select":
- return ;
+ case "date":
+ return ;
- case "date":
- return ;
+ case "number":
+ return ;
- case "number":
- return ;
+ case "file":
+ return ;
- case "file":
- return ;
+ case "page":
+ return ;
- case "page":
- return ;
+ case "rating":
+ return ;
- case "rating":
- return ;
-
- default:
- notReachable(question)
- }
+ default:
+ notReachable(question);
+ }
}
diff --git a/src/pages/Questions/UploadImage/UploadImageModal.tsx b/src/pages/Questions/UploadImage/UploadImageModal.tsx
index 39b63879..d722e81f 100644
--- a/src/pages/Questions/UploadImage/UploadImageModal.tsx
+++ b/src/pages/Questions/UploadImage/UploadImageModal.tsx
@@ -4,14 +4,23 @@ import SearchIcon from "../../../assets/icons/SearchIcon";
import UnsplashIcon from "../../../assets/icons/Unsplash.svg";
import { useRef, useState, type DragEvent } from "react";
+type ImageFormat = "jpg" | "jpeg" | "png" | "gif";
+
interface ModalkaProps {
isOpen: boolean;
onClose: () => void;
handleImageChange: (file: File) => void;
description?: string;
+ accept?: ImageFormat[];
}
-export const UploadImageModal: React.FC = ({ handleImageChange, isOpen, onClose, description }) => {
+export const UploadImageModal: React.FC = ({
+ handleImageChange,
+ isOpen,
+ onClose,
+ accept,
+ description,
+}) => {
const theme = useTheme();
const dropZone = useRef(null);
const [ready, setReady] = useState(false);
@@ -31,6 +40,10 @@ export const UploadImageModal: React.FC = ({ handleImageChange, is
handleImageChange(file);
};
+ const acceptedFormats = accept ? accept.map((format) => "." + format).join(", ") : "";
+
+ console.log(acceptedFormats);
+
return (
= ({ handleImageChange, is
event.target.files?.[0] && handleImageChange(event.target.files[0])}
hidden
- accept=".jpg, .jpeg, .png"
+ accept={acceptedFormats || ".jpg, .jpeg, .png , .gif"}
multiple
type="file"
data-cy="upload-image-input"
diff --git a/src/pages/auth/Signin.tsx b/src/pages/auth/Signin.tsx
index 41da4624..3fc929d5 100644
--- a/src/pages/auth/Signin.tsx
+++ b/src/pages/auth/Signin.tsx
@@ -1,18 +1,9 @@
import { login } from "@api/auth";
import CloseIcon from "@mui/icons-material/Close";
-import {
- Box,
- Button,
- Dialog,
- IconButton,
- Link,
- Typography,
- useMediaQuery,
- useTheme,
-} from "@mui/material";
+import { Box, Button, Dialog, IconButton, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
import { setUserId, useUserStore } from "@root/user";
import InputTextfield from "@ui_kit/InputTextfield";
-import PenaLogo2 from "@ui_kit/PenaLogo2";
+import Logotip from "../../pages/Landing/images/icons/QuizLogo";
import PasswordInput from "@ui_kit/passwordInput";
import { useFormik } from "formik";
import { enqueueSnackbar } from "notistack";
@@ -31,9 +22,7 @@ const initialValues: Values = {
};
const validationSchema = object({
- email: string()
- .required("Поле обязательно")
- .email("Введите корректный email"),
+ email: string().required("Поле обязательно").email("Введите корректный email"),
password: string().required("Поле обязательно").min(8, "Минимум 8 символов"),
});
@@ -49,10 +38,7 @@ export default function SigninDialog() {
initialValues,
validationSchema,
onSubmit: async (values, formikHelpers) => {
- const [loginResponse, loginError] = await login(
- values.email.trim(),
- values.password.trim()
- );
+ const [loginResponse, loginError] = await login(values.email.trim(), values.password.trim());
formikHelpers.setSubmitting(false);
@@ -111,8 +97,7 @@ export default function SigninDialog() {
gap: "15px",
borderRadius: "12px",
boxShadow: "0px 15px 80px rgb(210 208 225 / 70%)",
- "& .MuiFormHelperText-root.Mui-error, & .MuiFormHelperText-root.Mui-error.MuiFormHelperText-filled":
- {
+ "& .MuiFormHelperText-root.Mui-error, & .MuiFormHelperText-root.Mui-error.MuiFormHelperText-filled": {
position: "absolute",
top: "46px",
margin: "0",
@@ -130,7 +115,7 @@ export default function SigninDialog() {
-
+
-
- Вы еще не присоединились?
-
-
+ Вы еще не присоединились?
+
Регистрация
diff --git a/src/pages/auth/Signup.tsx b/src/pages/auth/Signup.tsx
index 636806e7..0359a97d 100644
--- a/src/pages/auth/Signup.tsx
+++ b/src/pages/auth/Signup.tsx
@@ -1,23 +1,14 @@
import { register } from "@api/auth";
import CloseIcon from "@mui/icons-material/Close";
-import {
- Box,
- Button,
- Dialog,
- IconButton,
- Link,
- Typography,
- useMediaQuery,
- useTheme,
-} from "@mui/material";
+import { Box, Button, Dialog, IconButton, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
import { setUserId, useUserStore } from "@root/user";
import InputTextfield from "@ui_kit/InputTextfield";
-import PenaLogo2 from "@ui_kit/PenaLogo2";
+import Logotip from "../../pages/Landing/images/icons/QuizLogo";
import PasswordInput from "@ui_kit/passwordInput";
import { useFormik } from "formik";
import { enqueueSnackbar } from "notistack";
import { useEffect, useState } from "react";
-import {Link as RouterLink, useLocation, useNavigate} from "react-router-dom";
+import { Link as RouterLink, useLocation, useNavigate } from "react-router-dom";
import { object, ref, string } from "yup";
interface Values {
@@ -33,9 +24,7 @@ const initialValues: Values = {
};
const validationSchema = object({
- email: string()
- .required("Поле обязательно")
- .email("Введите корректный email"),
+ email: string().required("Поле обязательно").email("Введите корректный email"),
password: string()
.min(8, "Минимум 8 символов")
.matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы")
@@ -50,18 +39,14 @@ export default function SignupDialog() {
const user = useUserStore((state) => state.user);
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
- const location = useLocation()
+ const location = useLocation();
const navigate = useNavigate();
const formik = useFormik({
initialValues,
validationSchema,
onSubmit: async (values, formikHelpers) => {
- const [registerResponse, registerError] = await register(
- values.email.trim(),
- values.password.trim(),
- "+7"
- );
+ const [registerResponse, registerError] = await register(values.email.trim(), values.password.trim(), "+7");
formikHelpers.setSubmitting(false);
@@ -120,12 +105,11 @@ export default function SignupDialog() {
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",
- },
+ "& .MuiFormHelperText-root.Mui-error, & .MuiFormHelperText-root.Mui-error.MuiFormHelperText-filled": {
+ position: "absolute",
+ top: "46px",
+ margin: "0",
+ },
}}
>
-
+
!imageUrl && setIsDropReady(true)}
diff --git a/src/pages/startPage/Restore.tsx b/src/pages/startPage/Restore.tsx
new file mode 100644
index 00000000..01f00a8f
--- /dev/null
+++ b/src/pages/startPage/Restore.tsx
@@ -0,0 +1,189 @@
+import { FC, useState } from "react";
+import CloseIcon from "@mui/icons-material/Close";
+import { Box, Button, Dialog, IconButton, Typography, useMediaQuery, useTheme } from "@mui/material";
+import InputTextfield from "@ui_kit/InputTextfield";
+import PasswordInput from "@ui_kit/passwordInput";
+import { useFormik } from "formik";
+import { object, ref, string } from "yup";
+import Logotip from "../Landing/images/icons/QuizLogo";
+import { useNavigate } from "react-router-dom";
+
+interface Values {
+ email: string;
+ password: string;
+ repeatPassword: string;
+}
+
+const initialValues: Values = {
+ email: "",
+ password: "",
+ repeatPassword: "",
+};
+
+const validationSchema = object({
+ email: string().required("Поле обязательно").email("Введите корректный email"),
+ password: string()
+ .min(8, "Минимум 8 символов")
+ .matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы")
+ .required("Поле обязательно"),
+ repeatPassword: string()
+ .oneOf([ref("password"), undefined], "Пароли не совпадают")
+ .required("Повторите пароль"),
+});
+
+export const Restore: FC = () => {
+ const [isDialogOpen, setIsDialogOpen] = useState(true);
+ const navigate = useNavigate();
+ const theme = useTheme();
+ const upMd = useMediaQuery(theme.breakpoints.up("md"));
+
+ const formik = useFormik({
+ initialValues,
+ validationSchema,
+ onSubmit: (values) => {
+ console.log(values);
+ },
+ });
+
+ function handleClose() {
+ setIsDialogOpen(false);
+ setTimeout(() => navigate("/"), theme.transitions.duration.leavingScreen);
+ }
+
+ return (
+
+
+
+
+ );
+};