diff --git a/package.json b/package.json
index 46011cf8..be9d1334 100755
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-cytoscapejs": "^2.0.0",
+ "react-datepicker": "^4.24.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0",
@@ -79,6 +80,7 @@
"@emoji-mart/react": "^1.1.1",
"@types/react-beautiful-dnd": "^13.1.4",
"@types/react-cytoscapejs": "^1.2.4",
+ "@types/react-datepicker": "^4.19.3",
"craco-alias": "^3.0.1",
"cypress": "^13.4.0"
}
diff --git a/src/App.tsx b/src/App.tsx
index 56d797b3..a6f4ded1 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -4,6 +4,7 @@ import dayjs from "dayjs";
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 } from "react-router-dom";
import "./index.css";
import ContactFormPage from "./pages/ContactFormPage/ContactFormPage";
@@ -61,6 +62,7 @@ export default function App() {
} />
} />
} />
+ } />
>
diff --git a/src/assets/icons/questionsPage/StarIconMini.tsx b/src/assets/icons/questionsPage/StarIconMini.tsx
index 561c7413..96a7a2b1 100644
--- a/src/assets/icons/questionsPage/StarIconMini.tsx
+++ b/src/assets/icons/questionsPage/StarIconMini.tsx
@@ -1,19 +1,23 @@
import { Box } from "@mui/material";
+import type { SxProps } from "@mui/material";
+
interface Props {
color: string;
- width?: string;
+ width?: number;
+ sx?: SxProps;
}
-export default function StarIconMini({ color, width = "30px" }: Props) {
+export default function StarIconMini({ color, width = 30, sx }: Props) {
return (
+ */}
>
diff --git a/src/pages/ViewPublicationPage/Footer.tsx b/src/pages/ViewPublicationPage/Footer.tsx
new file mode 100644
index 00000000..975def78
--- /dev/null
+++ b/src/pages/ViewPublicationPage/Footer.tsx
@@ -0,0 +1,127 @@
+import { useState, useEffect } from "react";
+import { Box, Typography, Button, useTheme } from "@mui/material";
+
+import { useQuizViewStore } from "@root/quizView";
+
+import type { QuizQuestionBase } from "../../model/questionTypes/shared";
+
+type FooterProps = {
+ stepNumber: number;
+ setStepNumber: (step: number) => void;
+ questions: QuizQuestionBase[];
+};
+
+export const Footer = ({
+ stepNumber,
+ setStepNumber,
+ questions,
+}: FooterProps) => {
+ const [disabledQuestionsId, setDisabledQuestionsId] = useState>(
+ new Set()
+ );
+ const { answers } = useQuizViewStore();
+ const theme = useTheme();
+
+ useEffect(() => {
+ clearDisabledQuestions();
+
+ const nextStepId = questions[stepNumber + 1].id;
+
+ const disabledIds = [] as string[];
+
+ const newDisabledIds = new Set([...disabledQuestionsId, ...disabledIds]);
+ setDisabledQuestionsId(newDisabledIds);
+ }, [answers]);
+
+ const clearDisabledQuestions = () => {
+ const cleanDisabledQuestions = new Set();
+
+ answers.forEach(({ step, answer }) => {
+ questions[step].content.rule.main.forEach(({ next, rules }) => {
+ rules.forEach(({ answers }) => {
+ if (answer !== answers[0]) {
+ cleanDisabledQuestions.add(next);
+ }
+ });
+ });
+ });
+
+ setDisabledQuestionsId(cleanDisabledQuestions);
+ };
+
+ const followPreviousStep = () => {
+ setStepNumber(stepNumber - 1);
+ };
+
+ const followNextStep = () => {
+ setStepNumber(stepNumber + 1);
+ };
+
+ return (
+
+
+
+ Шаг
+
+ {stepNumber}
+
+ Из
+
+ {questions.length}
+
+
+
+
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/Question.tsx b/src/pages/ViewPublicationPage/Question.tsx
new file mode 100644
index 00000000..cef98135
--- /dev/null
+++ b/src/pages/ViewPublicationPage/Question.tsx
@@ -0,0 +1,72 @@
+import { Box } from "@mui/material";
+
+import { Variant } from "./questions/Variant";
+import { Images } from "./questions/Images";
+import { Varimg } from "./questions/Varimg";
+import { Emoji } from "./questions/Emoji";
+import { Text } from "./questions/Text";
+import { Select } from "./questions/Select";
+import { Date } from "./questions/Date";
+import { Number } from "./questions/Number";
+import { File } from "./questions/File";
+import { Page } from "./questions/Page";
+import { Rating } from "./questions/Rating";
+import { Footer } from "./Footer";
+
+import type { FC } from "react";
+import type { QuestionType } from "../../model/question/question";
+import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
+
+type QuestionProps = {
+ stepNumber: number;
+ setStepNumber: (step: number) => void;
+ questions: AnyTypedQuizQuestion[];
+};
+
+const QUESTIONS_MAP: Record<
+ Exclude,
+ FC<{ stepNumber: number; question: any }>
+> = {
+ variant: Variant,
+ images: Images,
+ varimg: Varimg,
+ emoji: Emoji,
+ text: Text,
+ select: Select,
+ date: Date,
+ number: Number,
+ file: File,
+ page: Page,
+ rating: Rating,
+};
+
+export const Question = ({
+ stepNumber,
+ setStepNumber,
+ questions,
+}: QuestionProps) => {
+ const question = questions[stepNumber - 1] as AnyTypedQuizQuestion;
+ const QuestionComponent =
+ QUESTIONS_MAP[question.type as Exclude];
+
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/StartPageViewPublication.tsx b/src/pages/ViewPublicationPage/StartPageViewPublication.tsx
new file mode 100644
index 00000000..3153015d
--- /dev/null
+++ b/src/pages/ViewPublicationPage/StartPageViewPublication.tsx
@@ -0,0 +1,159 @@
+import {
+ Box,
+ Button,
+ Typography,
+ useTheme,
+ useMediaQuery,
+} from "@mui/material";
+import useSWR from "swr";
+import { isAxiosError } from "axios";
+import { enqueueSnackbar } from "notistack";
+import { devlog } from "@frontend/kitui";
+
+import { quizApi } from "@api/quiz";
+
+import { useCurrentQuiz } from "@root/quizes/hooks";
+import { setQuizes } from "@root/quizes/actions";
+
+type StartPageViewPublicationProps = {
+ setStepNumber: (step: number) => void;
+ showNextButton: boolean;
+};
+
+export const StartPageViewPublication = ({
+ setStepNumber,
+ showNextButton,
+}: StartPageViewPublicationProps) => {
+ const theme = useTheme();
+ const isTablet = useMediaQuery(theme.breakpoints.down(630));
+ const quiz = useCurrentQuiz();
+ const isMediaFileExist =
+ quiz?.config.startpage.background.desktop ||
+ quiz?.config.startpage.background.video;
+
+ useSWR("quizes", () => quizApi.getList(), {
+ onSuccess: setQuizes,
+ onError: (error: unknown) => {
+ const message = isAxiosError(error)
+ ? error.response?.data ?? ""
+ : "";
+
+ devlog("Error getting quiz list", error);
+ enqueueSnackbar(`Не удалось получить квизы. ${message}`);
+ },
+ });
+
+ return (
+
+
+
+ {quiz?.config.startpage.background.mobile && (
+
+ )}
+
+ {quiz?.config.info.orgname}
+
+
+
+
+ {quiz?.name}
+
+
+ {quiz?.config.startpage.description}
+
+
+
+
+
+
+
+ {quiz?.config.info.phonenumber}
+
+
+ {quiz?.config.info.law}
+
+
+
+ {!isTablet && isMediaFileExist && (
+
+ {quiz?.config.startpage.background.mobile && (
+
+ )}
+ {quiz.config.startpage.background.type === "video" &&
+ quiz.config.startpage.background.video && (
+
+ )}
+
+ )}
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/index.tsx b/src/pages/ViewPublicationPage/index.tsx
new file mode 100644
index 00000000..ea1c2656
--- /dev/null
+++ b/src/pages/ViewPublicationPage/index.tsx
@@ -0,0 +1,42 @@
+import { useLayoutEffect, useState } from "react";
+import { Box } from "@mui/material";
+
+import { StartPageViewPublication } from "./StartPageViewPublication";
+import { Question } from "./Question";
+import { useQuestions } from "@root/questions/hooks";
+import { useCurrentQuiz } from "@root/quizes/hooks";
+
+import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
+
+export const ViewPage = () => {
+ const [stepNumber, setStepNumber] = useState(0);
+ const quiz = useCurrentQuiz();
+ const { questions } = useQuestions();
+
+ useLayoutEffect(() => {
+ if (stepNumber === 0 && quiz?.config.noStartPage) {
+ setStepNumber(1);
+ }
+ }, []);
+
+ const filteredQuestions = questions.filter(
+ ({ type }) => type
+ ) as AnyTypedQuizQuestion[];
+
+ return (
+
+ {stepNumber ? (
+
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Date.tsx b/src/pages/ViewPublicationPage/questions/Date.tsx
new file mode 100644
index 00000000..883a0f98
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Date.tsx
@@ -0,0 +1,42 @@
+import { useState } from "react";
+import { useParams } from "react-router-dom";
+import DatePicker from "react-datepicker";
+import { Box, Typography } from "@mui/material";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+
+import "react-datepicker/dist/react-datepicker.css";
+
+import type { QuizQuestionDate } from "../../../model/questionTypes/date";
+
+type DateProps = {
+ question: QuizQuestionDate;
+};
+
+export const Date = ({ question }: DateProps) => {
+ const [startDate, setStartDate] = useState(new window.Date());
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ return (
+
+ {question.title}
+
+ setStartDate(date)}
+ />
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Emoji.tsx b/src/pages/ViewPublicationPage/questions/Emoji.tsx
new file mode 100644
index 00000000..191c0ac8
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Emoji.tsx
@@ -0,0 +1,78 @@
+import { useState } from "react";
+import { useParams } from "react-router-dom";
+import {
+ Box,
+ Typography,
+ RadioGroup,
+ FormControlLabel,
+ Radio,
+ useTheme,
+} from "@mui/material";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+
+import RadioCheck from "@ui_kit/RadioCheck";
+import RadioIcon from "@ui_kit/RadioIcon";
+
+import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji";
+
+type EmojiProps = {
+ question: QuizQuestionEmoji;
+};
+
+export const Emoji = ({ question }: EmojiProps) => {
+ const [valueIndex, setValueIndex] = useState(0);
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const theme = useTheme();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ return (
+
+ {question.title}
+ setValueIndex(Number(target.value))}
+ sx={{
+ display: "flex",
+ flexWrap: "wrap",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ marginTop: "20px",
+ }}
+ >
+
+ {question.content.variants.map(
+ ({ id, answer, extendedText }, index) => (
+ } icon={} />
+ }
+ label={
+
+ {extendedText}
+ {answer}
+
+ }
+ />
+ )
+ )}
+
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/File.tsx b/src/pages/ViewPublicationPage/questions/File.tsx
new file mode 100644
index 00000000..e224d349
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/File.tsx
@@ -0,0 +1,64 @@
+import { useState } from "react";
+import { useParams } from "react-router-dom";
+import { Box, Typography, ButtonBase } from "@mui/material";
+
+import UploadBox from "@ui_kit/UploadBox";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+import { UPLOAD_FILE_TYPES_MAP } from "@ui_kit/QuizPreview/QuizPreviewQuestionTypes/File";
+
+import UploadIcon from "@icons/UploadIcon";
+
+import type { ChangeEvent } from "react";
+import type { QuizQuestionFile } from "../../../model/questionTypes/file";
+
+type FileProps = {
+ question: QuizQuestionFile;
+};
+
+export const File = ({ question }: FileProps) => {
+ const [fileName, setFileName] = useState("");
+ const [file, setFile] = useState();
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ const uploadFile = ({ target }: ChangeEvent) => {
+ const file = target.files?.[0];
+
+ if (file) {
+ setFileName(file.name);
+ setFile(URL.createObjectURL(file));
+ }
+ };
+
+ return (
+
+ {question.title}
+
+
+
+ } text="5 MB максимум" />
+
+ {fileName && (
+ {fileName}
+ )}
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Images.tsx b/src/pages/ViewPublicationPage/questions/Images.tsx
new file mode 100644
index 00000000..b7e8f03c
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Images.tsx
@@ -0,0 +1,110 @@
+import { useState } from "react";
+import { useParams } from "react-router-dom";
+import {
+ Box,
+ Typography,
+ RadioGroup,
+ FormControlLabel,
+ Radio,
+ useTheme,
+ useMediaQuery,
+} from "@mui/material";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+
+import RadioCheck from "@ui_kit/RadioCheck";
+import RadioIcon from "@ui_kit/RadioIcon";
+
+import type { QuizQuestionImages } from "../../../model/questionTypes/images";
+
+type ImagesProps = {
+ question: QuizQuestionImages;
+};
+
+export const Images = ({ question }: ImagesProps) => {
+ const [valueIndex, setValueIndex] = useState(0);
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const theme = useTheme();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+ const isTablet = useMediaQuery(theme.breakpoints.down(1000));
+ const isMobile = useMediaQuery(theme.breakpoints.down(500));
+
+ return (
+
+ {question.title}
+ setValueIndex(Number(target.value))}
+ sx={{
+ display: "flex",
+ flexWrap: "wrap",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ marginTop: "20px",
+ }}
+ >
+
+ {question.content.variants.map(
+ ({ id, answer, extendedText }, index) => (
+
+
+
+ {extendedText && (
+
+ )}
+
+
+ } icon={} />
+ }
+ label={answer}
+ />
+
+ )
+ )}
+
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Number.tsx b/src/pages/ViewPublicationPage/questions/Number.tsx
new file mode 100644
index 00000000..e6496bf5
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Number.tsx
@@ -0,0 +1,61 @@
+import { useState } from "react";
+import { useParams } from "react-router-dom";
+import { Box, Typography, Slider, useTheme } from "@mui/material";
+
+import CustomTextField from "@ui_kit/CustomTextField";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+
+import type { QuizQuestionNumber } from "../../../model/questionTypes/number";
+
+type NumberProps = {
+ question: QuizQuestionNumber;
+};
+
+export const Number = ({ question }: NumberProps) => {
+ const [value, setValue] = useState(0);
+ const quizId = window.Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const theme = useTheme();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ return (
+
+ {question.title}
+
+
+ {
+ setValue(value as number);
+ }}
+ />
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Page.tsx b/src/pages/ViewPublicationPage/questions/Page.tsx
new file mode 100644
index 00000000..773fc4b0
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Page.tsx
@@ -0,0 +1,57 @@
+import { useParams } from "react-router-dom";
+import { Box, Typography } from "@mui/material";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+import type { QuizQuestionPage } from "../../../model/questionTypes/page";
+
+type PageProps = {
+ question: QuizQuestionPage;
+};
+
+export const Page = ({ question }: PageProps) => {
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ return (
+
+ {question.title}
+
+ {question.content.picture && (
+
+ )}
+ {question.content.video && (
+
+ )}
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Rating.tsx b/src/pages/ViewPublicationPage/questions/Rating.tsx
new file mode 100644
index 00000000..1b7f416c
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Rating.tsx
@@ -0,0 +1,70 @@
+import { useParams } from "react-router-dom";
+import {
+ Box,
+ Typography,
+ Rating as RatingComponent,
+ useTheme,
+} from "@mui/material";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+
+import StarIconMini from "@icons/questionsPage/StarIconMini";
+
+import type { QuizQuestionRating } from "../../../model/questionTypes/rating";
+
+type RatingProps = {
+ question: QuizQuestionRating;
+};
+
+export const Rating = ({ question }: RatingProps) => {
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+ const theme = useTheme();
+
+ return (
+
+ {question.title}
+
+
+ }
+ emptyIcon={
+
+ }
+ />
+
+ {question.content.ratingNegativeDescription}
+ {question.content.ratingPositiveDescription}
+
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Select.tsx b/src/pages/ViewPublicationPage/questions/Select.tsx
new file mode 100644
index 00000000..b637f2b2
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Select.tsx
@@ -0,0 +1,40 @@
+import { Box, Typography } from "@mui/material";
+import { useParams } from "react-router-dom";
+
+import { Select as SelectComponent } from "../../../pages/Questions/Select";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+
+import type { QuizQuestionSelect } from "../../../model/questionTypes/select";
+
+type SelectProps = {
+ question: QuizQuestionSelect;
+};
+
+export const Select = ({ question }: SelectProps) => {
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ return (
+
+ {question.title}
+
+ answer)}
+ onChange={(action, num) => {
+ }}
+ />
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Text.tsx b/src/pages/ViewPublicationPage/questions/Text.tsx
new file mode 100644
index 00000000..06cc3803
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Text.tsx
@@ -0,0 +1,36 @@
+import { useParams } from "react-router-dom";
+import { Box, Typography } from "@mui/material";
+
+import CustomTextField from "@ui_kit/CustomTextField";
+
+import { questionStore, updateQuestionsList } from "@root/questions";
+
+import type { QuizQuestionText } from "../../../model/questionTypes/text";
+
+type TextProps = {
+ question: QuizQuestionText;
+};
+
+export const Text = ({ question }: TextProps) => {
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ return (
+
+ {question.title}
+
+
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Variant.tsx b/src/pages/ViewPublicationPage/questions/Variant.tsx
new file mode 100644
index 00000000..f746940b
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Variant.tsx
@@ -0,0 +1,91 @@
+import { useEffect } from "react";
+import {
+ Box,
+ Typography,
+ RadioGroup,
+ FormControlLabel,
+ Radio,
+ useTheme,
+} from "@mui/material";
+
+import { useQuizViewStore, updateAnswer } from "@root/quizView";
+
+import RadioCheck from "@ui_kit/RadioCheck";
+import RadioIcon from "@ui_kit/RadioIcon";
+
+import type { QuizQuestionVariant } from "../../../model/questionTypes/variant";
+
+type VariantProps = {
+ stepNumber: number;
+ question: QuizQuestionVariant;
+};
+
+export const Variant = ({ stepNumber, question }: VariantProps) => {
+ const { answers } = useQuizViewStore();
+ const theme = useTheme();
+ const answerIndex = answers.findIndex(({ step }) => step === stepNumber);
+ const answer = answers[answerIndex]?.answer;
+
+ useEffect(() => {
+ if (!answer) {
+ updateAnswer(stepNumber, question.content.variants[0].id);
+ }
+ }, []);
+
+ return (
+
+ {question.title}
+
+ answer === id)}
+ onChange={({ target }) =>
+ updateAnswer(
+ stepNumber,
+ question.content.variants[Number(target.value)].id
+ )
+ }
+ sx={{
+ display: "flex",
+ flexWrap: "wrap",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ flexBasis: "100%",
+ marginTop: "20px",
+ }}
+ >
+
+ {question.content.variants.map(({ id, answer }, index) => (
+ } icon={} />
+ }
+ label={answer}
+ />
+ ))}
+
+
+ {question.content.back && (
+
+
+
+ )}
+
+
+ );
+};
diff --git a/src/pages/ViewPublicationPage/questions/Varimg.tsx b/src/pages/ViewPublicationPage/questions/Varimg.tsx
new file mode 100644
index 00000000..f6faeab9
--- /dev/null
+++ b/src/pages/ViewPublicationPage/questions/Varimg.tsx
@@ -0,0 +1,87 @@
+import { useState } from "react";
+import { useParams } from "react-router-dom";
+import {
+ Box,
+ Typography,
+ RadioGroup,
+ FormControlLabel,
+ Radio,
+ useTheme,
+} from "@mui/material";
+
+import { questionStore } from "@root/questions";
+
+import RadioCheck from "@ui_kit/RadioCheck";
+import RadioIcon from "@ui_kit/RadioIcon";
+
+import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
+
+type VarimgProps = {
+ question: QuizQuestionVarImg;
+};
+
+export const Varimg = ({ question }: VarimgProps) => {
+ const [valueIndex, setValueIndex] = useState(-1);
+ const quizId = Number(useParams().quizId);
+ const { listQuestions } = questionStore();
+ const theme = useTheme();
+ const totalIndex = listQuestions[quizId].findIndex(
+ ({ id }) => question.id === id
+ );
+
+ return (
+
+ {question.title}
+
+ setValueIndex(Number(target.value))}
+ sx={{
+ display: "flex",
+ flexWrap: "wrap",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ flexBasis: "100%",
+ marginTop: "20px",
+ }}
+ >
+
+ {question.content.variants.map(({ id, answer }, index) => (
+ } icon={} />
+ }
+ label={answer}
+ />
+ ))}
+
+
+ {(question.content.variants[valueIndex]?.extendedText ||
+ question.content.back) && (
+
+
= 0
+ ? question.content.variants[valueIndex].extendedText
+ : question.content.back
+ }
+ style={{ width: "100%", height: "100%", objectFit: "cover" }}
+ alt=""
+ />
+
+ )}
+
+
+ );
+};
diff --git a/src/stores/quizView.ts b/src/stores/quizView.ts
new file mode 100644
index 00000000..00f54f11
--- /dev/null
+++ b/src/stores/quizView.ts
@@ -0,0 +1,35 @@
+import { create } from "zustand";
+import { devtools } from "zustand/middleware";
+
+type Answer = {
+ step: number;
+ answer: string;
+};
+
+interface QuizViewStore {
+ answers: Answer[];
+}
+
+export const useQuizViewStore = create()(
+ devtools(
+ (set, get) => ({
+ answers: [],
+ }),
+ {
+ name: "quizView",
+ }
+ )
+);
+
+export const updateAnswer = (step: number, answer: string) => {
+ const answers = [...useQuizViewStore.getState().answers];
+ const answerIndex = answers.findIndex((answer) => step === answer.step);
+
+ if (answerIndex < 0) {
+ answers.push({ step, answer });
+ } else {
+ answers[answerIndex] = { step, answer };
+ }
+
+ useQuizViewStore.setState({ answers });
+};
diff --git a/tsconfig.json b/tsconfig.json
index f6d247b8..cf78e18d 100755
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,7 @@
{
"extends": "./tsconfig.extend.json",
"compilerOptions": {
- "target": "es5",
+ "target": "es2015",
"lib": [
"dom",
"dom.iterable",
diff --git a/yarn.lock b/yarn.lock
index 4181f0c9..bb5e8393 100755
--- a/yarn.lock
+++ b/yarn.lock
@@ -1041,6 +1041,13 @@
dependencies:
regenerator-runtime "^0.14.0"
+"@babel/runtime@^7.21.0":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.5.tgz#11edb98f8aeec529b82b211028177679144242db"
+ integrity sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
"@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz"
@@ -1883,7 +1890,7 @@
schema-utils "^3.0.0"
source-map "^0.7.3"
-"@popperjs/core@^2.11.6", "@popperjs/core@^2.11.8":
+"@popperjs/core@^2.11.6", "@popperjs/core@^2.11.8", "@popperjs/core@^2.9.2":
version "2.11.8"
resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz"
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
@@ -2419,6 +2426,16 @@
"@types/cytoscape" "*"
"@types/react" "*"
+"@types/react-datepicker@^4.19.3":
+ version "4.19.3"
+ resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.19.3.tgz#0a58e42d820adf12337617bd72289766643775db"
+ integrity sha512-85F9eKWu9fGiD9r4KVVMPYAdkJJswR3Wci9PvqplmB6T+D+VbUqPeKtifg96NZ4nEhufjehW+SX4JLrEWVplWw==
+ dependencies:
+ "@popperjs/core" "^2.9.2"
+ "@types/react" "*"
+ date-fns "^2.0.1"
+ react-popper "^2.2.5"
+
"@types/react-dnd@^3.0.2":
version "3.0.2"
resolved "https://registry.npmjs.org/@types/react-dnd/-/react-dnd-3.0.2.tgz"
@@ -3607,6 +3624,11 @@ cjs-module-lexer@^1.0.0:
resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz"
integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
+classnames@^2.2.6:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
+ integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
+
clean-css@^5.2.2:
version "5.3.1"
resolved "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz"
@@ -4199,6 +4221,13 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
+date-fns@^2.0.1, date-fns@^2.30.0:
+ version "2.30.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
+ integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
+ dependencies:
+ "@babel/runtime" "^7.21.0"
+
dayjs@^1.10.4, dayjs@^1.11.10:
version "1.11.10"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz"
@@ -7093,7 +7122,7 @@ log-update@^4.0.0:
slice-ansi "^4.0.0"
wrap-ansi "^6.2.0"
-loose-envify@^1.1.0, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -8522,6 +8551,18 @@ react-cytoscapejs@^2.0.0:
dependencies:
prop-types "^15.8.1"
+react-datepicker@^4.24.0:
+ version "4.24.0"
+ resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.24.0.tgz#dfb12e277993f1ae2d350b7ba4dd6bba7d21bfb1"
+ integrity sha512-2QUC2pP+x4v3Jp06gnFllxKsJR0yoT/K6y86ItxEsveTXUpsx+NBkChWXjU0JsGx/PL8EQnsxN0wHl4zdA1m/g==
+ dependencies:
+ "@popperjs/core" "^2.11.8"
+ classnames "^2.2.6"
+ date-fns "^2.30.0"
+ prop-types "^15.7.2"
+ react-onclickoutside "^6.13.0"
+ react-popper "^2.3.0"
+
react-dev-utils@^12.0.1:
version "12.0.1"
resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz"
@@ -8604,6 +8645,11 @@ react-fast-compare@^2.0.1:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
+react-fast-compare@^3.0.1:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
+ integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
+
react-image-crop@^10.1.5:
version "10.1.8"
resolved "https://registry.npmjs.org/react-image-crop/-/react-image-crop-10.1.8.tgz"
@@ -8629,6 +8675,19 @@ react-is@^18.0.0, react-is@^18.2.0:
resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+react-onclickoutside@^6.13.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz#e165ea4e5157f3da94f4376a3ab3e22a565f4ffc"
+ integrity sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==
+
+react-popper@^2.2.5, react-popper@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba"
+ integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==
+ dependencies:
+ react-fast-compare "^3.0.1"
+ warning "^4.0.2"
+
react-redux@^7.2.0:
version "7.2.9"
resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz"
@@ -10201,6 +10260,13 @@ walker@^1.0.7:
dependencies:
makeerror "1.0.12"
+warning@^4.0.2:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
+ integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
+ dependencies:
+ loose-envify "^1.0.0"
+
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz"