публикация ветвится в вопросах - вариантах
This commit is contained in:
parent
ab4d99c3ba
commit
e1b9ada5af
@ -62,7 +62,7 @@ export default function App() {
|
||||
<Route path="/" element={<Landing />} />
|
||||
<Route path="/signin" element={<SigninDialog />} />
|
||||
<Route path="/signup" element={<SignupDialog />} />
|
||||
<Route path="view/:quizId" element={<ViewPage />} />
|
||||
<Route path="/view" element={<ViewPage />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</>
|
||||
|
||||
@ -17,7 +17,7 @@ export interface QuestionBranchingRuleMain {
|
||||
or: boolean;
|
||||
rules: {
|
||||
question: string; //id родителя (пока что)
|
||||
answers: string[]
|
||||
answers: string[]
|
||||
}[]
|
||||
}
|
||||
export interface QuestionBranchingRule {
|
||||
|
||||
@ -33,7 +33,7 @@ export interface QuizConfig {
|
||||
noStartPage: boolean;
|
||||
startpageType: QuizStartpageType;
|
||||
results: QuizResultsType;
|
||||
haveRoot: boolean;
|
||||
haveRoot: string | null;
|
||||
startpage: {
|
||||
description: string;
|
||||
button: string;
|
||||
@ -62,7 +62,7 @@ export const defaultQuizConfig: QuizConfig = {
|
||||
noStartPage: false,
|
||||
startpageType: null,
|
||||
results: null,
|
||||
haveRoot: false,
|
||||
haveRoot: null,
|
||||
startpage: {
|
||||
description: "",
|
||||
button: "",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { MessageIcon } from "@icons/messagIcon";
|
||||
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||
import { TextareaAutosize } from "@mui/base/TextareaAutosize";
|
||||
import TextareaAutosize from "@mui/base/TextareaAutosize";
|
||||
import {
|
||||
Box,
|
||||
FormControl,
|
||||
|
||||
@ -3,7 +3,7 @@ import Cytoscape from "cytoscape";
|
||||
import CytoscapeComponent from "react-cytoscapejs";
|
||||
import popper from "cytoscape-popper";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { updateRootInfo } from "@root/quizes/actions"
|
||||
import { updateRootContentId } from "@root/quizes/actions"
|
||||
import { AnyQuizQuestion } from "@model/questionTypes/shared"
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
import { cleardragQuestionContentId, updateQuestion, updateOpenedModalSettingsId, getQuestionByContentId } from "@root/questions/actions";
|
||||
@ -211,7 +211,7 @@ export const CsComponent = ({
|
||||
question.content.rule.main = []
|
||||
question.content.rule.default = ""
|
||||
})
|
||||
updateRootInfo(quiz?.id, false)
|
||||
updateRootContentId(quiz?.id, false)
|
||||
} else {
|
||||
console.log("click not ROOT")
|
||||
const parentQuestionContentId = cy?.$('edge[target = "' + targetNodeContentId + '"]')?.toArray()?.[0]?.data()?.source
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Box } from "@mui/material"
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { updateDragQuestionContentId, updateQuestion } from "@root/questions/actions"
|
||||
import { updateRootInfo } from "@root/quizes/actions"
|
||||
import { updateRootContentId } from "@root/quizes/actions"
|
||||
import { useQuestionsStore } from "@root/questions/store"
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
@ -23,7 +23,7 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
|
||||
console.log(dragQuestionContentId)
|
||||
|
||||
if (dragQuestionContentId) {
|
||||
updateRootInfo(quiz?.id, true)
|
||||
updateRootContentId(quiz?.id, dragQuestionContentId)
|
||||
updateQuestion(dragQuestionContentId, (question) => question.content.rule.parentId = "root")
|
||||
}
|
||||
} else {
|
||||
@ -44,7 +44,7 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
|
||||
if (quiz) {
|
||||
|
||||
if (modalQuestionTargetContentId) {
|
||||
updateRootInfo(quiz?.id, true)
|
||||
updateRootContentId(quiz?.id, modalQuestionTargetContentId)
|
||||
updateQuestion(modalQuestionTargetContentId, (question) => question.content.rule.parentId = "root")
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Box, Typography, Button, useTheme } from "@mui/material";
|
||||
|
||||
import { useQuizViewStore } from "@root/quizView";
|
||||
import { useQuizViewStore, getAnswersByQuestionId } from "@root/quizView";
|
||||
|
||||
import type { QuizQuestionBase } from "../../model/questionTypes/shared";
|
||||
import type { AnyTypedQuizQuestion, QuizQuestionBase } from "../../model/questionTypes/shared";
|
||||
import { getQuestionByContentId } from "@root/questions/actions";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
|
||||
type FooterProps = {
|
||||
stepNumber: number;
|
||||
setStepNumber: (step: number) => void;
|
||||
questions: QuizQuestionBase[];
|
||||
setCurrentQuestion: (step: AnyTypedQuizQuestion) => void;
|
||||
question: QuizQuestionBase;
|
||||
};
|
||||
|
||||
export const Footer = ({
|
||||
stepNumber,
|
||||
setStepNumber,
|
||||
questions,
|
||||
setCurrentQuestion,
|
||||
question,
|
||||
}: FooterProps) => {
|
||||
const [disabledQuestionsId, setDisabledQuestionsId] = useState<Set<string>>(
|
||||
new Set()
|
||||
@ -22,37 +22,62 @@ export const Footer = ({
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
clearDisabledQuestions();
|
||||
|
||||
const disabledIds = [] as string[];
|
||||
|
||||
const newDisabledIds = new Set([...disabledQuestionsId, ...disabledIds]);
|
||||
setDisabledQuestionsId(newDisabledIds);
|
||||
}, [answers]);
|
||||
|
||||
const clearDisabledQuestions = () => {
|
||||
const cleanDisabledQuestions = new Set<string>();
|
||||
|
||||
answers.forEach(({ step, answer }) => {
|
||||
questions[step - 1].content.rule.main.forEach(({ next, rules }) => {
|
||||
rules.forEach(({ answers }) => {
|
||||
if (answer !== answers[0]) {
|
||||
cleanDisabledQuestions.add(next);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
setDisabledQuestionsId(cleanDisabledQuestions);
|
||||
};
|
||||
|
||||
const followPreviousStep = () => {
|
||||
setStepNumber(stepNumber - 1);
|
||||
if (question?.content.rule.parentId !== "root") {
|
||||
const parent = getQuestionByContentId(question?.content.rule.parentId)
|
||||
if (parent) {
|
||||
setCurrentQuestion(parent)
|
||||
} else {
|
||||
enqueueSnackbar("не могу получить предыдущий вопрос")
|
||||
}
|
||||
} else {
|
||||
enqueueSnackbar("вы находитесь на первом вопросе")
|
||||
}
|
||||
};
|
||||
|
||||
const followNextStep = () => {
|
||||
setStepNumber(stepNumber + 1);
|
||||
const answers = getAnswersByQuestionId(question.content.id) || []
|
||||
console.log(answers)
|
||||
if (answers) {
|
||||
|
||||
let readyBeNextQuestion = ""
|
||||
question.content.rule.main.forEach(({ next, rules }) => {
|
||||
console.log({ next, rules })
|
||||
|
||||
console.log("[storeAnswers] ", rules[0].answers)
|
||||
console.log("[answers.answer] ", [answers.answer])
|
||||
|
||||
let longerArray = Math.max(rules[0].answers.length, [answers.answer].length)
|
||||
|
||||
for (var i = 0; i < longerArray; i++) // Цикл по всем элементам бОльшего массива
|
||||
if (rules[0].answers[i] !== [answers.answer][i]) readyBeNextQuestion = next; // Если хоть один элемент отличается, массивы не равны
|
||||
|
||||
|
||||
})
|
||||
if (readyBeNextQuestion) {
|
||||
console.log("мы нашли совпадение в " + readyBeNextQuestion)
|
||||
|
||||
const nextQuestion = getQuestionByContentId(readyBeNextQuestion)
|
||||
console.log("next question ", nextQuestion)
|
||||
if (nextQuestion) {
|
||||
console.log("я устанавливаю следующий вопрос " + question.title)
|
||||
setCurrentQuestion(nextQuestion)
|
||||
return
|
||||
} else {
|
||||
enqueueSnackbar("не могу получить последующий вопрос")
|
||||
}
|
||||
} else {
|
||||
const nextQuestion = getQuestionByContentId(question.content.rule.default)
|
||||
console.log("я устанавливаю дефолтный вопрос")
|
||||
if (nextQuestion) {
|
||||
setCurrentQuestion(nextQuestion)
|
||||
} else {
|
||||
enqueueSnackbar("не могу получить последующий вопрос (дефолтный)")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
@ -82,7 +107,7 @@ export const Footer = ({
|
||||
color: theme.palette.grey1.main,
|
||||
}}
|
||||
>
|
||||
<Typography>Шаг</Typography>
|
||||
{/* <Typography>Шаг</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -96,16 +121,15 @@ export const Footer = ({
|
||||
background: theme.palette.brightPurple.main,
|
||||
}}
|
||||
>
|
||||
{stepNumber}
|
||||
</Typography>
|
||||
<Typography>Из</Typography>
|
||||
{stepNumber} */}
|
||||
{/* </Typography> */}
|
||||
{/* <Typography>Из</Typography>
|
||||
<Typography sx={{ fontWeight: "bold" }}>
|
||||
{questions.length}
|
||||
</Typography>
|
||||
</Typography> */}
|
||||
</Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={stepNumber <= 1}
|
||||
sx={{ fontSize: "16px", padding: "10px 15px" }}
|
||||
onClick={followPreviousStep}
|
||||
>
|
||||
@ -113,7 +137,6 @@ export const Footer = ({
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={questions.length <= stepNumber}
|
||||
sx={{ fontSize: "16px", padding: "10px 15px" }}
|
||||
onClick={followNextStep}
|
||||
>
|
||||
|
||||
@ -13,9 +13,11 @@ import { Page } from "./questions/Page";
|
||||
import { Rating } from "./questions/Rating";
|
||||
import { Footer } from "./Footer";
|
||||
|
||||
import type { FC } from "react";
|
||||
import { useState, type FC } from "react";
|
||||
import type { QuestionType } from "../../model/question/question";
|
||||
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { getQuestionByContentId } from "@root/questions/actions";
|
||||
|
||||
type QuestionProps = {
|
||||
stepNumber: number;
|
||||
@ -23,10 +25,7 @@ type QuestionProps = {
|
||||
questions: AnyTypedQuizQuestion[];
|
||||
};
|
||||
|
||||
const QUESTIONS_MAP: Record<
|
||||
Exclude<QuestionType, "nonselected">,
|
||||
FC<{ stepNumber: number; question: any }>
|
||||
> = {
|
||||
const QUESTIONS_MAP: any = {
|
||||
variant: Variant,
|
||||
images: Images,
|
||||
varimg: Varimg,
|
||||
@ -41,13 +40,15 @@ const QUESTIONS_MAP: Record<
|
||||
};
|
||||
|
||||
export const Question = ({
|
||||
stepNumber,
|
||||
setStepNumber,
|
||||
questions,
|
||||
}: QuestionProps) => {
|
||||
const question = questions[stepNumber - 1] as AnyTypedQuizQuestion;
|
||||
const quiz = useCurrentQuiz();
|
||||
const [currentQuestion, setCurrentQuestion] = useState(getQuestionByContentId(quiz?.config.haveRoot || ""))
|
||||
console.log("root " + quiz?.config.haveRoot)
|
||||
if (!currentQuestion) return <>не смог отобразить вопрос</>
|
||||
|
||||
const QuestionComponent =
|
||||
QUESTIONS_MAP[question.type as Exclude<QuestionType, "nonselected">];
|
||||
QUESTIONS_MAP[currentQuestion.type as Exclude<QuestionType, "nonselected">];
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@ -60,12 +61,11 @@ export const Question = ({
|
||||
margin: "0 auto",
|
||||
}}
|
||||
>
|
||||
<QuestionComponent question={question} stepNumber={stepNumber} />
|
||||
<QuestionComponent currentQuestion={currentQuestion}/>
|
||||
</Box>
|
||||
<Footer
|
||||
stepNumber={stepNumber}
|
||||
setStepNumber={setStepNumber}
|
||||
questions={questions}
|
||||
question={currentQuestion}
|
||||
setCurrentQuestion={setCurrentQuestion}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@ -18,13 +18,13 @@ import { useQuestions } from "@root/questions/hooks";
|
||||
import { setQuizes } from "@root/quizes/actions";
|
||||
|
||||
type StartPageViewPublicationProps = {
|
||||
setStepNumber: (step: number) => void;
|
||||
showNextButton: boolean;
|
||||
setVisualStartPage: (bool: boolean) => void;
|
||||
showNextButton:boolean
|
||||
};
|
||||
|
||||
export const StartPageViewPublication = ({
|
||||
setStepNumber,
|
||||
showNextButton,
|
||||
setVisualStartPage,
|
||||
showNextButton
|
||||
}: StartPageViewPublicationProps) => {
|
||||
const quizId = Number(useParams().quizId);
|
||||
const { quizes } = useQuizStore();
|
||||
@ -109,8 +109,8 @@ export const StartPageViewPublication = ({
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{ fontSize: "16px", padding: "10px 15px" }}
|
||||
disabled={!questions.length}
|
||||
onClick={() => setStepNumber(1)}
|
||||
// disabled={!questions.length}
|
||||
onClick={() => setVisualStartPage(false)}
|
||||
>
|
||||
{quiz?.config.startpage.button
|
||||
? quiz?.config.startpage.button
|
||||
|
||||
@ -9,15 +9,12 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
||||
|
||||
export const ViewPage = () => {
|
||||
const [stepNumber, setStepNumber] = useState<number>(0);
|
||||
const quiz = useCurrentQuiz();
|
||||
const { questions } = useQuestions();
|
||||
console.log(questions)
|
||||
|
||||
const [visualStartPage, setVisualStartPage] = useState<boolean>(!quiz?.config.noStartPage);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (stepNumber === 0 && quiz?.config.noStartPage) {
|
||||
setStepNumber(1);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const filteredQuestions = questions.filter(
|
||||
({ type }) => type
|
||||
@ -25,16 +22,14 @@ export const ViewPage = () => {
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{stepNumber ? (
|
||||
<Question
|
||||
stepNumber={stepNumber}
|
||||
setStepNumber={setStepNumber}
|
||||
questions={filteredQuestions}
|
||||
{visualStartPage ? (
|
||||
<StartPageViewPublication
|
||||
setVisualStartPage={setVisualStartPage}
|
||||
showNextButton={!!filteredQuestions.length}
|
||||
/>
|
||||
) : (
|
||||
<StartPageViewPublication
|
||||
setStepNumber={setStepNumber}
|
||||
showNextButton={!!filteredQuestions.length}
|
||||
<Question
|
||||
questions={filteredQuestions}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
@ -8,17 +8,16 @@ import "react-datepicker/dist/react-datepicker.css";
|
||||
import type { QuizQuestionDate } from "../../../model/questionTypes/date";
|
||||
|
||||
type DateProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionDate;
|
||||
currentQuestion: QuizQuestionDate;
|
||||
};
|
||||
|
||||
export const Date = ({ stepNumber, question }: DateProps) => {
|
||||
export const Date = ({ currentQuestion }: DateProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -29,7 +28,7 @@ export const Date = ({ stepNumber, question }: DateProps) => {
|
||||
>
|
||||
<DatePicker
|
||||
selected={answer ? new window.Date(answer) : new window.Date()}
|
||||
onChange={(date) => updateAnswer(stepNumber, String(date))}
|
||||
onChange={(date) => updateAnswer(currentQuestion.content.id, String(date))}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@ -16,31 +16,30 @@ import RadioIcon from "@ui_kit/RadioIcon";
|
||||
import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji";
|
||||
|
||||
type EmojiProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionEmoji;
|
||||
currentQuestion: QuizQuestionEmoji;
|
||||
};
|
||||
|
||||
export const Emoji = ({ stepNumber, question }: EmojiProps) => {
|
||||
export const Emoji = ({ currentQuestion }: EmojiProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
useEffect(() => {
|
||||
if (!answer) {
|
||||
updateAnswer(stepNumber, question.content.variants[0].id);
|
||||
updateAnswer(currentQuestion.content.id, currentQuestion.content.variants[0].id);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<RadioGroup
|
||||
name={question.id}
|
||||
value={question.content.variants.findIndex(({ id }) => answer === id)}
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(({ id }) => answer === id)}
|
||||
onChange={({ target }) =>
|
||||
updateAnswer(
|
||||
stepNumber,
|
||||
question.content.variants[Number(target.value)].id
|
||||
currentQuestion.content.id,
|
||||
currentQuestion.content.variants[Number(target.value)].id
|
||||
)
|
||||
}
|
||||
sx={{
|
||||
@ -52,7 +51,7 @@ export const Emoji = ({ stepNumber, question }: EmojiProps) => {
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
||||
{question.content.variants.map(
|
||||
{currentQuestion.content.variants.map(
|
||||
({ id, answer, extendedText }, index) => (
|
||||
<FormControlLabel
|
||||
key={id}
|
||||
|
||||
@ -11,25 +11,24 @@ import type { ChangeEvent } from "react";
|
||||
import type { QuizQuestionFile } from "../../../model/questionTypes/file";
|
||||
|
||||
type FileProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionFile;
|
||||
currentQuestion: QuizQuestionFile;
|
||||
};
|
||||
|
||||
export const File = ({ stepNumber, question }: FileProps) => {
|
||||
export const File = ({ currentQuestion }: FileProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
const uploadFile = ({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||
const file = target.files?.[0];
|
||||
|
||||
if (file) {
|
||||
updateAnswer(stepNumber, `${file.name}|${URL.createObjectURL(file)}`);
|
||||
updateAnswer(currentQuestion.content.id, `${file.name}|${URL.createObjectURL(file)}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -42,7 +41,7 @@ export const File = ({ stepNumber, question }: FileProps) => {
|
||||
<input
|
||||
onChange={uploadFile}
|
||||
hidden
|
||||
accept={UPLOAD_FILE_TYPES_MAP[question.content.type]}
|
||||
accept={UPLOAD_FILE_TYPES_MAP[currentQuestion.content.type]}
|
||||
multiple
|
||||
type="file"
|
||||
/>
|
||||
|
||||
@ -17,33 +17,32 @@ import RadioIcon from "@ui_kit/RadioIcon";
|
||||
import type { QuizQuestionImages } from "../../../model/questionTypes/images";
|
||||
|
||||
type ImagesProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionImages;
|
||||
currentQuestion: QuizQuestionImages;
|
||||
};
|
||||
|
||||
export const Images = ({ stepNumber, question }: ImagesProps) => {
|
||||
export const Images = ({ currentQuestion }: ImagesProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(500));
|
||||
|
||||
useEffect(() => {
|
||||
if (!answer) {
|
||||
updateAnswer(stepNumber, question.content.variants[0].id);
|
||||
updateAnswer(currentQuestion.content.id, currentQuestion.content.variants[0].id);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<RadioGroup
|
||||
name={question.id}
|
||||
value={question.content.variants.findIndex(({ id }) => answer === id)}
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(({ id }) => answer === id)}
|
||||
onChange={({ target }) =>
|
||||
updateAnswer(
|
||||
stepNumber,
|
||||
question.content.variants[Number(target.value)].id
|
||||
currentQuestion.content.id,
|
||||
currentQuestion.content.variants[Number(target.value)].id
|
||||
)
|
||||
}
|
||||
sx={{
|
||||
@ -66,7 +65,7 @@ export const Images = ({ stepNumber, question }: ImagesProps) => {
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{question.content.variants.map(
|
||||
{currentQuestion.content.variants.map(
|
||||
({ id, answer, extendedText }, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
|
||||
@ -8,27 +8,26 @@ import { useQuizViewStore, updateAnswer } from "@root/quizView";
|
||||
import type { QuizQuestionNumber } from "../../../model/questionTypes/number";
|
||||
|
||||
type NumberProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionNumber;
|
||||
currentQuestion: QuizQuestionNumber;
|
||||
};
|
||||
|
||||
export const Number = ({ stepNumber, question }: NumberProps) => {
|
||||
export const Number = ({ currentQuestion }: NumberProps) => {
|
||||
const theme = useTheme();
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
const min = window.Number(question.content.range.split("—")[0]);
|
||||
const max = window.Number(question.content.range.split("—")[1]);
|
||||
const min = window.Number(currentQuestion.content.range.split("—")[0]);
|
||||
const max = window.Number(currentQuestion.content.range.split("—")[1]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!answer) {
|
||||
updateAnswer(stepNumber, "1");
|
||||
updateAnswer(currentQuestion.content.id, "1");
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -42,7 +41,7 @@ export const Number = ({ stepNumber, question }: NumberProps) => {
|
||||
value={answer || ""}
|
||||
onChange={({ target }) => {
|
||||
updateAnswer(
|
||||
stepNumber,
|
||||
currentQuestion.content.id,
|
||||
window.Number(target.value) > max
|
||||
? String(max)
|
||||
: window.Number(target.value) < min
|
||||
@ -59,14 +58,14 @@ export const Number = ({ stepNumber, question }: NumberProps) => {
|
||||
value={window.Number(answer || 1)}
|
||||
min={min}
|
||||
max={max}
|
||||
step={question.content.step || 1}
|
||||
step={currentQuestion.content.step || 1}
|
||||
sx={{
|
||||
color: theme.palette.brightPurple.main,
|
||||
padding: "0",
|
||||
marginTop: "25px",
|
||||
}}
|
||||
onChange={(_, value) => {
|
||||
updateAnswer(stepNumber, String(value));
|
||||
updateAnswer(currentQuestion.content.id, String(value));
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@ -5,17 +5,16 @@ import { useQuizViewStore, updateAnswer } from "@root/quizView";
|
||||
import type { QuizQuestionPage } from "../../../model/questionTypes/page";
|
||||
|
||||
type PageProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionPage;
|
||||
currentQuestion: QuizQuestionPage;
|
||||
};
|
||||
|
||||
export const Page = ({ stepNumber, question }: PageProps) => {
|
||||
export const Page = ({ currentQuestion }: PageProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -24,9 +23,9 @@ export const Page = ({ stepNumber, question }: PageProps) => {
|
||||
marginTop: "20px",
|
||||
}}
|
||||
>
|
||||
{question.content.picture && (
|
||||
{currentQuestion.content.picture && (
|
||||
<img
|
||||
src={question.content.picture}
|
||||
src={currentQuestion.content.picture}
|
||||
alt=""
|
||||
style={{
|
||||
display: "block",
|
||||
@ -37,9 +36,9 @@ export const Page = ({ stepNumber, question }: PageProps) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{question.content.video && (
|
||||
{currentQuestion.content.video && (
|
||||
<video
|
||||
src={question.content.video}
|
||||
src={currentQuestion.content.video}
|
||||
controls
|
||||
style={{
|
||||
width: "100%",
|
||||
|
||||
@ -12,18 +12,17 @@ import StarIconMini from "@icons/questionsPage/StarIconMini";
|
||||
import type { QuizQuestionRating } from "../../../model/questionTypes/rating";
|
||||
|
||||
type RatingProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionRating;
|
||||
currentQuestion: QuizQuestionRating;
|
||||
};
|
||||
|
||||
export const Rating = ({ stepNumber, question }: RatingProps) => {
|
||||
export const Rating = ({ currentQuestion }: RatingProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -34,9 +33,9 @@ export const Rating = ({ stepNumber, question }: RatingProps) => {
|
||||
>
|
||||
<RatingComponent
|
||||
value={Number(answer || 0)}
|
||||
onChange={(_, value) => updateAnswer(stepNumber, String(value))}
|
||||
onChange={(_, value) => updateAnswer(currentQuestion.content.id, String(value))}
|
||||
sx={{ height: "50px" }}
|
||||
max={question.content.steps}
|
||||
max={currentQuestion.content.steps}
|
||||
icon={
|
||||
<StarIconMini
|
||||
color={theme.palette.brightPurple.main}
|
||||
@ -56,12 +55,12 @@ export const Rating = ({ stepNumber, question }: RatingProps) => {
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
maxWidth: `${question.content.steps * 50}px`,
|
||||
maxWidth: `${currentQuestion.content.steps * 50}px`,
|
||||
color: theme.palette.grey2.main,
|
||||
}}
|
||||
>
|
||||
<Typography>{question.content.ratingNegativeDescription}</Typography>
|
||||
<Typography>{question.content.ratingPositiveDescription}</Typography>
|
||||
<Typography>{currentQuestion.content.ratingNegativeDescription}</Typography>
|
||||
<Typography>{currentQuestion.content.ratingPositiveDescription}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@ -7,17 +7,16 @@ import { useQuizViewStore, updateAnswer } from "@root/quizView";
|
||||
import type { QuizQuestionSelect } from "../../../model/questionTypes/select";
|
||||
|
||||
type SelectProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionSelect;
|
||||
currentQuestion: QuizQuestionSelect;
|
||||
};
|
||||
|
||||
export const Select = ({ stepNumber, question }: SelectProps) => {
|
||||
export const Select = ({ currentQuestion }: SelectProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -28,9 +27,9 @@ export const Select = ({ stepNumber, question }: SelectProps) => {
|
||||
>
|
||||
<SelectComponent
|
||||
activeItemIndex={Number(answer) || 0}
|
||||
items={question.content.variants.map(({ answer }) => answer)}
|
||||
items={currentQuestion.content.variants.map(({ answer }) => answer)}
|
||||
onChange={(_, value) => {
|
||||
updateAnswer(stepNumber, String(value));
|
||||
updateAnswer(currentQuestion.content.id, String(value));
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@ -7,17 +7,16 @@ import { useQuizViewStore, updateAnswer } from "@root/quizView";
|
||||
import type { QuizQuestionText } from "../../../model/questionTypes/text";
|
||||
|
||||
type TextProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionText;
|
||||
currentQuestion: QuizQuestionText;
|
||||
};
|
||||
|
||||
export const Text = ({ stepNumber, question }: TextProps) => {
|
||||
export const Text = ({ currentQuestion }: TextProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -27,9 +26,9 @@ export const Text = ({ stepNumber, question }: TextProps) => {
|
||||
}}
|
||||
>
|
||||
<CustomTextField
|
||||
placeholder={question.content.placeholder}
|
||||
placeholder={currentQuestion.content.placeholder}
|
||||
value={answer || ""}
|
||||
onChange={({ target }) => updateAnswer(stepNumber, target.value)}
|
||||
onChange={({ target }) => updateAnswer(currentQuestion.content.id, target.value)}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@ -17,31 +17,31 @@ import type { QuizQuestionVariant } from "../../../model/questionTypes/variant";
|
||||
|
||||
type VariantProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionVariant;
|
||||
currentQuestion: QuizQuestionVariant;
|
||||
};
|
||||
|
||||
export const Variant = ({ stepNumber, question }: VariantProps) => {
|
||||
export const Variant = ({ currentQuestion }: VariantProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
|
||||
useEffect(() => {
|
||||
if (!answer) {
|
||||
updateAnswer(stepNumber, question.content.variants[0].id);
|
||||
updateAnswer(currentQuestion.content.id, currentQuestion.content.variants[0].id);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box sx={{ display: "flex" }}>
|
||||
<RadioGroup
|
||||
name={question.id}
|
||||
value={question.content.variants.findIndex(({ id }) => answer === id)}
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(({ id }) => answer === id)}
|
||||
onChange={({ target }) =>
|
||||
updateAnswer(
|
||||
stepNumber,
|
||||
question.content.variants[Number(target.value)].id
|
||||
currentQuestion.content.id,
|
||||
currentQuestion.content.variants[Number(target.value)].id
|
||||
)
|
||||
}
|
||||
sx={{
|
||||
@ -54,7 +54,7 @@ export const Variant = ({ stepNumber, question }: VariantProps) => {
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
||||
{question.content.variants.map(({ id, answer }, index) => (
|
||||
{currentQuestion.content.variants.map(({ id, answer }, index) => (
|
||||
<FormControlLabel
|
||||
key={id}
|
||||
sx={{
|
||||
@ -75,10 +75,10 @@ export const Variant = ({ stepNumber, question }: VariantProps) => {
|
||||
))}
|
||||
</Box>
|
||||
</RadioGroup>
|
||||
{question.content.back && (
|
||||
{currentQuestion.content.back && (
|
||||
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}>
|
||||
<img
|
||||
src={question.content.back}
|
||||
src={currentQuestion.content.back}
|
||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||||
alt=""
|
||||
/>
|
||||
|
||||
@ -16,33 +16,32 @@ import RadioIcon from "@ui_kit/RadioIcon";
|
||||
import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
|
||||
|
||||
type VarimgProps = {
|
||||
stepNumber: number;
|
||||
question: QuizQuestionVarImg;
|
||||
currentQuestion: QuizQuestionVarImg;
|
||||
};
|
||||
|
||||
export const Varimg = ({ stepNumber, question }: VarimgProps) => {
|
||||
export const Varimg = ({ currentQuestion }: VarimgProps) => {
|
||||
const { answers } = useQuizViewStore();
|
||||
const theme = useTheme();
|
||||
const { answer } = answers.find(({ step }) => step === stepNumber) ?? {};
|
||||
const variant = question.content.variants.find(({ id }) => answer === id);
|
||||
const { answer } = answers.find(({ questionId }) => questionId === currentQuestion.content.id) ?? {};
|
||||
const variant = currentQuestion.content.variants.find(({ id }) => answer === id);
|
||||
|
||||
useEffect(() => {
|
||||
if (!answer) {
|
||||
updateAnswer(stepNumber, question.content.variants[0].id);
|
||||
updateAnswer(currentQuestion.content.id, currentQuestion.content.variants[0].id);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h5">{question.title}</Typography>
|
||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||
<Box sx={{ display: "flex" }}>
|
||||
<RadioGroup
|
||||
name={question.id}
|
||||
value={question.content.variants.findIndex(({ id }) => answer === id)}
|
||||
name={currentQuestion.id}
|
||||
value={currentQuestion.content.variants.findIndex(({ id }) => answer === id)}
|
||||
onChange={({ target }) =>
|
||||
updateAnswer(
|
||||
stepNumber,
|
||||
question.content.variants[Number(target.value)].id
|
||||
currentQuestion.content.id,
|
||||
currentQuestion.content.variants[Number(target.value)].id
|
||||
)
|
||||
}
|
||||
sx={{
|
||||
@ -55,7 +54,7 @@ export const Varimg = ({ stepNumber, question }: VarimgProps) => {
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
||||
{question.content.variants.map(({ id, answer }, index) => (
|
||||
{currentQuestion.content.variants.map(({ id, answer }, index) => (
|
||||
<FormControlLabel
|
||||
key={id}
|
||||
sx={{
|
||||
@ -75,10 +74,10 @@ export const Varimg = ({ stepNumber, question }: VarimgProps) => {
|
||||
))}
|
||||
</Box>
|
||||
</RadioGroup>
|
||||
{(variant?.extendedText || question.content.back) && (
|
||||
{(variant?.extendedText || currentQuestion.content.back) && (
|
||||
<Box sx={{ maxWidth: "400px", width: "100%", height: "300px" }}>
|
||||
<img
|
||||
src={answer ? variant?.extendedText : question.content.back}
|
||||
src={answer ? variant?.extendedText : currentQuestion.content.back}
|
||||
style={{ width: "100%", height: "100%", objectFit: "cover" }}
|
||||
alt=""
|
||||
/>
|
||||
|
||||
@ -171,7 +171,7 @@ export default function StartPage() {
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<a href={`/view/${quiz?.backendId}`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
|
||||
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{
|
||||
|
||||
@ -2,7 +2,7 @@ import { create } from "zustand";
|
||||
import { devtools } from "zustand/middleware";
|
||||
|
||||
type Answer = {
|
||||
step: number;
|
||||
questionId: string;
|
||||
answer: string;
|
||||
};
|
||||
|
||||
@ -21,15 +21,21 @@ export const useQuizViewStore = create<QuizViewStore>()(
|
||||
)
|
||||
);
|
||||
|
||||
export const updateAnswer = (step: number, answer: string) => {
|
||||
export const updateAnswer = (questionId: string, answer: string) => {
|
||||
const answers = [...useQuizViewStore.getState().answers];
|
||||
const answerIndex = answers.findIndex((answer) => step === answer.step);
|
||||
const answerIndex = answers.findIndex((answer) => questionId === answer.questionId);
|
||||
|
||||
if (answerIndex < 0) {
|
||||
answers.push({ step, answer });
|
||||
answers.push({ questionId, answer });
|
||||
} else {
|
||||
answers[answerIndex] = { step, answer };
|
||||
answers[answerIndex] = { questionId, answer };
|
||||
}
|
||||
|
||||
useQuizViewStore.setState({ answers });
|
||||
};
|
||||
|
||||
export const getAnswersByQuestionId = (questionId: string) => {
|
||||
if (questionId === null) return null;
|
||||
const answers = [...useQuizViewStore.getState().answers];
|
||||
return answers.find(a => a.questionId === questionId) || null;
|
||||
}
|
||||
@ -175,10 +175,10 @@ export const deleteQuiz = async (quizId: string) => requestQueue.enqueue(async (
|
||||
enqueueSnackbar(`Не удалось удалить квиз. ${message}`);
|
||||
}
|
||||
});
|
||||
export const updateRootInfo = (quizId: string, have:boolean) => updateQuiz(
|
||||
export const updateRootContentId = (quizId: string, id:string) => updateQuiz(
|
||||
quizId,
|
||||
quiz => {
|
||||
quiz.config.haveRoot = have;
|
||||
quiz.config.haveRoot = id;
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user