diff --git a/src/model/questionTypes/result.ts b/src/model/questionTypes/result.ts index 44d0223..e2eeb33 100644 --- a/src/model/questionTypes/result.ts +++ b/src/model/questionTypes/result.ts @@ -4,6 +4,9 @@ import type { QuestionHint, } from "./shared"; +interface ResultQuestionBranchingRule extends QuestionBranchingRule { + minScore?: number +} export interface QuizQuestionResult extends QuizQuestionBase { type: "result"; content: { @@ -15,7 +18,7 @@ export interface QuizQuestionResult extends QuizQuestionBase { text: string; price: [number] | [number, number]; useImage: boolean; - rule: QuestionBranchingRule, + rule: ResultQuestionBranchingRule, hint: QuestionHint; autofill: boolean; redirect: string diff --git a/src/model/questionTypes/shared.ts b/src/model/questionTypes/shared.ts index a8fa5b2..b5384c6 100644 --- a/src/model/questionTypes/shared.ts +++ b/src/model/questionTypes/shared.ts @@ -46,6 +46,7 @@ export type QuestionVariant = { extendedText: string; /** Оригинал изображения (до кропа) */ originalImageUrl: string; + points?: number; }; export type QuestionType = diff --git a/src/model/settingsData.ts b/src/model/settingsData.ts index 06f1e18..849987f 100644 --- a/src/model/settingsData.ts +++ b/src/model/settingsData.ts @@ -51,6 +51,7 @@ export interface QuizConfig { type: QuizType; noStartPage: boolean; startpageType: QuizStartpageType; + score?: boolean; results: QuizResultsType; haveRoot: string; theme: QuizTheme; diff --git a/src/pages/ViewPublicationPage/Footer.tsx b/src/pages/ViewPublicationPage/Footer.tsx index 6706e08..b887308 100644 --- a/src/pages/ViewPublicationPage/Footer.tsx +++ b/src/pages/ViewPublicationPage/Footer.tsx @@ -12,6 +12,7 @@ type FooterProps = { export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => { const theme = useTheme(); const { questions } = useQuizData(); + console.log(questions) return ( { updateAnswer( currentQuestion.id, - date + date, + 0 ); } catch (e) { enqueueSnackbar("ответ не был засчитан"); diff --git a/src/pages/ViewPublicationPage/questions/Emoji.tsx b/src/pages/ViewPublicationPage/questions/Emoji.tsx index 27cc19d..7a06047 100644 --- a/src/pages/ViewPublicationPage/questions/Emoji.tsx +++ b/src/pages/ViewPublicationPage/questions/Emoji.tsx @@ -43,7 +43,8 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => { onChange={({ target }) => { updateAnswer( currentQuestion.id, - currentQuestion.content.variants[Number(target.value)].answer + currentQuestion.content.variants[Number(target.value)].answer, + currentQuestion.content.variants[Number(target.value)].points || 0 ); } } @@ -114,7 +115,8 @@ export const Emoji = ({ currentQuestion }: EmojiProps) => { updateAnswer( currentQuestion.id, - currentQuestion.content.variants[index].id + currentQuestion.content.variants[index].id, + currentQuestion.content.variants[index].points || 0 ); } catch (e) { diff --git a/src/pages/ViewPublicationPage/questions/File.tsx b/src/pages/ViewPublicationPage/questions/File.tsx index c5507f3..0ac79b4 100644 --- a/src/pages/ViewPublicationPage/questions/File.tsx +++ b/src/pages/ViewPublicationPage/questions/File.tsx @@ -159,7 +159,8 @@ export const File = ({ currentQuestion }: FileProps) => { updateAnswer( currentQuestion.id, - `${file.name}|${URL.createObjectURL(file)}` + `${file.name}|${URL.createObjectURL(file)}`, + 0 ); } catch (e) { @@ -219,7 +220,7 @@ export const File = ({ currentQuestion }: FileProps) => { { - updateAnswer(currentQuestion.id, ""); + updateAnswer(currentQuestion.id, "", 0); }} > diff --git a/src/pages/ViewPublicationPage/questions/Images.tsx b/src/pages/ViewPublicationPage/questions/Images.tsx index 3ef0993..0662a17 100644 --- a/src/pages/ViewPublicationPage/questions/Images.tsx +++ b/src/pages/ViewPublicationPage/questions/Images.tsx @@ -79,7 +79,8 @@ export const Images = ({ currentQuestion }: ImagesProps) => { updateAnswer( currentQuestion.id, - currentQuestion.content.variants[index].id + currentQuestion.content.variants[index].id, + currentQuestion.content.variants[index].points || 0 ); } catch (e) { diff --git a/src/pages/ViewPublicationPage/questions/Number.tsx b/src/pages/ViewPublicationPage/questions/Number.tsx index 5d6f340..5201e2c 100644 --- a/src/pages/ViewPublicationPage/questions/Number.tsx +++ b/src/pages/ViewPublicationPage/questions/Number.tsx @@ -41,7 +41,7 @@ export const Number = ({ currentQuestion }: NumberProps) => { qid, }); - updateAnswer(currentQuestion.id, value); + updateAnswer(currentQuestion.id, value, 0); } catch (e) { enqueueSnackbar("ответ не был засчитан"); } @@ -138,7 +138,7 @@ export const Number = ({ currentQuestion }: NumberProps) => { ? `${value[0]}—${value[1]}` : String(value); - updateAnswer(currentQuestion.id, range); + updateAnswer(currentQuestion.id, range, 0); }} onChangeCommitted={async (_, value) => { if (currentQuestion.content.chooseRange && Array.isArray(value)) { diff --git a/src/pages/ViewPublicationPage/questions/Rating.tsx b/src/pages/ViewPublicationPage/questions/Rating.tsx index cb75a05..bc753d4 100644 --- a/src/pages/ViewPublicationPage/questions/Rating.tsx +++ b/src/pages/ViewPublicationPage/questions/Rating.tsx @@ -101,7 +101,7 @@ export const Rating = ({ currentQuestion }: RatingProps) => { qid, }); - updateAnswer(currentQuestion.id, String(value)); + updateAnswer(currentQuestion.id, String(value), 0); } catch (e) { enqueueSnackbar("ответ не был засчитан"); diff --git a/src/pages/ViewPublicationPage/questions/Select.tsx b/src/pages/ViewPublicationPage/questions/Select.tsx index 4016752..12426b9 100644 --- a/src/pages/ViewPublicationPage/questions/Select.tsx +++ b/src/pages/ViewPublicationPage/questions/Select.tsx @@ -63,7 +63,7 @@ export const Select = ({ currentQuestion }: SelectProps) => { qid, }); - updateAnswer(currentQuestion.id, String(value)); + updateAnswer(currentQuestion.id, String(value), 0); } catch (e) { enqueueSnackbar("ответ не был засчитан"); diff --git a/src/pages/ViewPublicationPage/questions/Text.tsx b/src/pages/ViewPublicationPage/questions/Text.tsx index 30a6976..8459d04 100644 --- a/src/pages/ViewPublicationPage/questions/Text.tsx +++ b/src/pages/ViewPublicationPage/questions/Text.tsx @@ -50,7 +50,7 @@ export const Text = ({ currentQuestion }: TextProps) => { //@ts-ignore value={answer || ""} onChange={async ({ target }) => { - updateAnswer(currentQuestion.id, target.value); + updateAnswer(currentQuestion.id, target.value, 0); inputHC(target.value); } } diff --git a/src/pages/ViewPublicationPage/questions/Variant.tsx b/src/pages/ViewPublicationPage/questions/Variant.tsx index 64e8f51..4930050 100644 --- a/src/pages/ViewPublicationPage/questions/Variant.tsx +++ b/src/pages/ViewPublicationPage/questions/Variant.tsx @@ -185,6 +185,7 @@ const VariantItem = ({ onClick={async (event) => { event.preventDefault(); const variantId = currentQuestion.content.variants[index].id; + console.log(answer) if (currentQuestion.content.multi) { const currentAnswer = typeof answer !== "string" ? answer || [] : []; @@ -202,9 +203,11 @@ const VariantItem = ({ currentQuestion.id, currentAnswer.includes(variantId) ? currentAnswer?.filter((item) => item !== variantId) - : [...currentAnswer, variantId] + : [...currentAnswer, variantId], + currentQuestion.content.variants[index].points || 0 ); } catch (e) { + console.log(e) enqueueSnackbar("ответ не был засчитан"); } @@ -218,9 +221,14 @@ const VariantItem = ({ qid, }); - updateAnswer(currentQuestion.id, variantId); + updateAnswer(currentQuestion.id, variantId, + answer === variantId ? 0 + : + currentQuestion.content.variants[index].points || 0 + ); } catch (e) { + console.log(e) enqueueSnackbar("ответ не был засчитан"); } @@ -234,6 +242,7 @@ const VariantItem = ({ }); } catch (e) { + console.log(e) enqueueSnackbar("ответ не был засчитан"); } deleteAnswer(currentQuestion.id); diff --git a/src/pages/ViewPublicationPage/questions/Varimg.tsx b/src/pages/ViewPublicationPage/questions/Varimg.tsx index a3515fa..b85fb34 100644 --- a/src/pages/ViewPublicationPage/questions/Varimg.tsx +++ b/src/pages/ViewPublicationPage/questions/Varimg.tsx @@ -99,7 +99,8 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => { updateAnswer( currentQuestion.id, - currentQuestion.content.variants[index].id + currentQuestion.content.variants[index].id, + currentQuestion.content.variants[index].points || 0 ); } catch (e) { diff --git a/src/stores/quizView/store.ts b/src/stores/quizView/store.ts index ac92cf4..049ac58 100644 --- a/src/stores/quizView/store.ts +++ b/src/stores/quizView/store.ts @@ -19,6 +19,8 @@ type OwnVariant = { interface QuizViewStore { answers: QuestionAnswer[]; ownVariants: OwnVariant[]; + pointsSum: number; + points: Record; currentQuizStep: QuizStep; } @@ -27,6 +29,8 @@ export const useQuizViewStore = create()( (set, get) => ({ answers: [], ownVariants: [], + points: {}, + pointsSum: 0, currentQuizStep: "startpage", }), { @@ -39,27 +43,40 @@ export const useQuizViewStore = create()( function setProducedState( recipe: (state: QuizViewStore) => void, - action: A, + action?: A, ) { useQuizViewStore.setState(state => produce(state, recipe), false, action); } +const calcPoints = () => { + const storePoints = useQuizViewStore.getState().points; + let sum = Object.values(storePoints).reduce((accumulator, currentValue) => accumulator + currentValue) + console.log("сумма ", sum) + useQuizViewStore.setState({ pointsSum: sum }) +} + export const updateAnswer = ( questionId: string, - answer: string | string[] | Moment -) => setProducedState(state => { - const index = state.answers.findIndex(answer => questionId === answer.questionId); + answer: string | string[] | Moment, + points: number +) => { + setProducedState(state => { + const index = state.answers.findIndex(answer => questionId === answer.questionId); - if (index < 0) { - state.answers.push({ questionId, answer }); - } else { - state.answers[index] = { questionId, answer }; - } -}, { - type: "updateAnswer", - questionId, - answer -}); + if (index < 0) { + state.answers.push({ questionId, answer }); + } else { + state.answers[index] = { questionId, answer }; + } + }, { + type: "updateAnswer", + questionId, + answer + }) + const storePoints = useQuizViewStore.getState().points; + useQuizViewStore.setState({ points: { ...storePoints, ...{ [questionId]: points } } }) + calcPoints() +}; export const deleteAnswer = (questionId: string) => useQuizViewStore.setState(state => ({ answers: state.answers.filter(answer => questionId !== answer.questionId) diff --git a/src/utils/hooks/useQuestionFlowControl.ts b/src/utils/hooks/useQuestionFlowControl.ts index 7b59ecf..e3f2a8c 100644 --- a/src/utils/hooks/useQuestionFlowControl.ts +++ b/src/utils/hooks/useQuestionFlowControl.ts @@ -9,7 +9,8 @@ import moment from "moment"; export function useQuestionFlowControl() { const { settings, questions } = useQuizData(); const [currentQuestion, setCurrentQuestion] = useState(getFirstQuestion); - const answers = useQuizViewStore(state => state.answers); + const { answers, pointsSum } = useQuizViewStore(state => state); + const linearQuestionIndex = questions.every(({ content }) => content.rule.parentId !== "root") // null when branching enabled ? questions.indexOf(currentQuestion) @@ -30,12 +31,22 @@ export function useQuestionFlowControl() { return questions[0]; } - const nextQuestionId = useMemo(() => { + + const nextQuestionIdPointsLogic = () => { + return questions.find(question => + question.type === "result" && question.content.rule.parentId === "line" + ) + } + + const nextQuestionIdMainLogic = () => { const questionAnswer = answers.find(({ questionId }) => questionId === currentQuestion.id); + //Если ответ существует и не является объектом момента if (questionAnswer && !moment.isMoment(questionAnswer.answer)) { + //Ответы должны храниться в массиве const userAnswers = Array.isArray(questionAnswer.answer) ? questionAnswer.answer : [questionAnswer.answer]; + //Сравниваем список условий ветвления и выбираем подходящее for (const branchingRule of currentQuestion.content.rule.main) { if (userAnswers.some(answer => branchingRule.rules[0].answers.includes(answer))) { return branchingRule.next; @@ -58,7 +69,13 @@ export function useQuestionFlowControl() { return questions.find(q => { return q.type === "result" && q.content.rule.parentId === currentQuestion.content.id; })?.id; - }, [answers, currentQuestion, questions]); + }; + const calculateNextQuestionId = useMemo(() => { + if (Boolean(settings.cfg.score)) { + return nextQuestionIdPointsLogic() + } + return nextQuestionIdMainLogic() + }, [answers, currentQuestion, questions]) const prevQuestion = linearQuestionIndex !== null ? questions[linearQuestionIndex - 1] @@ -67,11 +84,51 @@ export function useQuestionFlowControl() { || q.content.id === currentQuestion.content.rule.parentId ); - const nextQuestion = linearQuestionIndex !== null - ? questions[linearQuestionIndex + 1] ?? questions.find(question => - question.type === "result" && question.content.rule.parentId === "line" - ) - : questions.find(q => q.id === nextQuestionId || q.content.id === nextQuestionId); + const findResultPointsLogic = () => { + const results = questions + .filter(e => e.type === "result" && e.content.rule.minScore !== undefined && e.content.rule.minScore <= pointsSum) + const numbers = results.map(e => e.content.rule.minScore) + const indexOfNext = Math.max(...numbers) + console.log(results) + console.log(numbers) + console.log(indexOfNext) + return results[numbers.indexOf(indexOfNext)] + } + + const nextQuestion = () => { + let next + //Искать можно двумя логиками. Основной и балловой + if (Boolean(settings.cfg.score)) { + //Балловая + + + //Ищем линейно + if (linearQuestionIndex !== null) { + + + next = questions[linearQuestionIndex + 1] + if (next.type === "result") next = findResultPointsLogic() + + + } + + + } else { + //Основная + if (linearQuestionIndex !== null) { + //Ищем линейно + next = questions[linearQuestionIndex + 1] ?? questions.find(question => + question.type === "result" && question.content.rule.parentId === "line" + ) + } else { + //Ищем ветвлением + next = questions.find(q => q.id === calculateNextQuestionId || q.content.id === calculateNextQuestionId); + } + } + if (!next) throw new Error("Не найден следующий вопрос") + console.log("next", next) + return next + } const showResult = useCallback(() => { if (nextQuestion?.type !== "result") throw new Error("Current question is not result");