import { QuizQuestionResult } from "@model/questionTypes/result"; import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; import { setCurrentQuizStep, useQuizViewStore } from "@stores/quizView/store"; import { useCallback, useDebugValue, useMemo, useState } from "react"; import { isResultQuestionEmpty } from "../../pages/ViewPublicationPage/tools/checkEmptyData"; import { useQuizData } from "./useQuizData"; export function useQuestionFlowControl() { const { settings, questions } = useQuizData(); const [currentQuestion, setCurrentQuestion] = useState(getFirstQuestion); const answers = useQuizViewStore(state => state.answers); const linearQuestionIndex = questions.every(({ content }) => content.rule.parentId !== "root") // null when branching enabled ? questions.indexOf(currentQuestion) : null; function getFirstQuestion() { if (questions.length === 0) throw new Error("No questions found"); if (settings.cfg.haveRoot) { const nextQuestion = questions.find( question => question.id === settings.cfg.haveRoot || question.content.id === settings.cfg.haveRoot ); if (!nextQuestion) throw new Error("Root question not found"); return nextQuestion; } return questions[0]; } const nextQuestionId = useMemo(() => { console.log("Смотрим какой вопрос будет дальше. Что у нас сегодня вкусненького? Щя покажу от какого вопроса мы ищем следующий шаг"); console.log(currentQuestion); console.log("От вот этого /|"); //вопрос обязателен, анализируем ответ и условия ветвления if (answers.length) { let readyBeNextQuestion = ""; const answer = answers.find(({ questionId }) => questionId === currentQuestion.id); currentQuestion.content.rule.main.forEach(({ next, rules }) => { const longerArray = Math.max( rules[0].answers.length, answer?.answer && Array.isArray(answer?.answer) ? answer?.answer.length : [answer?.answer].length ); for (let i = 0; i < longerArray; i++) { if (Array.isArray(answer?.answer)) { if (answer?.answer.find((item) => String(item === rules[0].answers[i]))) { readyBeNextQuestion = next; // Ес­ли хоть один эле­мент от­ли­ча­ет­ся, мас­си­вы не рав­ны } return; } if (String(rules[0].answers[i]) === answer?.answer) { readyBeNextQuestion = next; // Ес­ли хоть один эле­мент от­ли­ча­ет­ся, мас­си­вы не рав­ны } } }); if (readyBeNextQuestion) return readyBeNextQuestion; } if (!currentQuestion.required) {//вопрос не обязателен и не нашли совпадений между ответами и условиями ветвления console.log("вопрос не обязателен ищем дальше"); const defaultNextQuestionId = currentQuestion.content.rule.default; if (defaultNextQuestionId.length > 1 && defaultNextQuestionId !== " ") return defaultNextQuestionId; //Вопросы типа страница, ползунок, своё поле для ввода и дата не могут иметь больше 1 ребёнка. Пользователь не может настроить там дефолт //Кинуть на ребёнка надо даже если там нет дефолта if ( ["date", "page", "text", "number"].includes(currentQuestion.type) && currentQuestion.content.rule.children.length === 1 ) return currentQuestion.content.rule.children[0]; } //ничё не нашли, ищем резулт console.log("ничё не нашли, ищем резулт "); return questions.find(q => { return q.type === "result" && q.content.rule.parentId === currentQuestion.content.id; })?.id; }, [answers, currentQuestion, questions]); const prevQuestion = linearQuestionIndex !== null ? questions[linearQuestionIndex - 1] : questions.find(q => q.id === currentQuestion.content.rule.parentId || q.content.id === currentQuestion.content.rule.parentId ); const nextQuestion = linearQuestionIndex !== null ? questions[linearQuestionIndex + 1] : questions.find(q => q.id === nextQuestionId || q.content.id === nextQuestionId); const resultQuestion = useMemo(() => { let resultQuestion: QuizQuestionResult | undefined; if (currentQuestion.type === "result") resultQuestion = currentQuestion; if (settings.cfg.haveRoot) { resultQuestion = questions.find((question): question is QuizQuestionResult => { return question.type === "result" && question.content.rule.parentId === currentQuestion.content.id; }); } else { resultQuestion = questions.find((question): question is QuizQuestionResult => { return question.type === "result" && question.content.rule.parentId === "line"; }); } if (resultQuestion && !isResultQuestionEmpty(resultQuestion)) return resultQuestion; }, [currentQuestion, questions, settings.cfg.haveRoot]); const showResult = useCallback(() => { if (!resultQuestion) throw new Error("Result question not found"); setCurrentQuestion(resultQuestion); if (settings.cfg.resultInfo.showResultForm === "after") { setCurrentQuizStep("contactform"); } }, [resultQuestion, settings.cfg.resultInfo.showResultForm]); const showResultAfterContactForm = useCallback(() => { if (!resultQuestion) throw new Error("Result question not found"); if (resultQuestion.type !== "result") throw new Error("Current question is not a result question"); setCurrentQuizStep("question"); }, [resultQuestion]); const moveToPrevQuestion = useCallback(() => { if (!prevQuestion) throw new Error("Previous question not found"); setCurrentQuestion(prevQuestion); }, [prevQuestion]); const moveToNextQuestion = useCallback(() => { if (!nextQuestion) throw new Error("Next question not found"); if (nextQuestion.type === "result") return showResult(); setCurrentQuestion(nextQuestion); }, [nextQuestion, showResult]); const isPreviousButtonEnabled = Boolean(prevQuestion); const isNextButtonEnabled = useMemo(() => { const hasAnswer = answers.some(({ questionId }) => questionId === currentQuestion.id); if ("required" in currentQuestion.content && currentQuestion.content.required) { return hasAnswer; } return Boolean(nextQuestion); }, [answers, currentQuestion.content, currentQuestion.id, nextQuestion]); useDebugValue({ linearQuestionIndex, currentQuestion, prevQuestion, nextQuestion, resultQuestion, }); return { currentQuestion, currentQuestionStepNumber: linearQuestionIndex && linearQuestionIndex + 1, isNextButtonEnabled, isPreviousButtonEnabled, moveToPrevQuestion, moveToNextQuestion, showResultAfterContactForm, }; }