публикация ветвится в вопросах - вариантах

This commit is contained in:
Nastya 2023-12-03 13:48:00 +03:00
parent ab4d99c3ba
commit e1b9ada5af
24 changed files with 212 additions and 198 deletions

@ -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;
},
);