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"; import { devlog } from "@frontend/kitui"; export function useQuestionFlowControl() { const { settings, questions } = useQuizData(); const isLinear = questions.every(({ content }) => content.rule.parentId !== "root"); const [currentQuestion, setCurrentQuestion] = useState(getFirstQuestion); const answers = useQuizViewStore(state => state.answers); const questionIndex = isLinear ? questions.indexOf(currentQuestion) : null; const currentQuestionStepNumber = questionIndex && questionIndex + 1; 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("От вот этого /|"); let readyBeNextQuestion = ""; //вопрос обязателен, анализируем ответ и условия ветвления if (answers.length) { 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 defaultNextQuestion = currentQuestion.content.rule.default; if (defaultNextQuestion.length > 1 && defaultNextQuestion !== " ") return defaultNextQuestion; //Вопросы типа страница, ползунок, своё поле для ввода и дата не могут иметь больше 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 nextQuestion = questions.find(q => q.id === nextQuestionId || q.content.id === nextQuestionId); const resultQuestion = useMemo(() => { if (currentQuestion.type === "result") return currentQuestion; if (settings.cfg.haveRoot) return questions.find((question): question is QuizQuestionResult => { return question.type === "result" && question.content.rule.parentId === currentQuestion.content.id; }); return questions.find((question): question is QuizQuestionResult => { return question.type === "result" && question.content.rule.parentId === "line"; }); }, [currentQuestion, questions, settings.cfg.haveRoot]); const showResult = useCallback((resultQuestion: QuizQuestionResult) => { if (settings.cfg.resultInfo.showResultForm === "before" && !isResultQuestionEmpty(resultQuestion)) { return setCurrentQuestion(resultQuestion); } setCurrentQuizStep("contactform"); }, [settings.cfg.resultInfo.showResultForm]); const showResultAfterContactForm = useCallback(() => { if (settings.cfg.resultInfo.showResultForm === "before") return; if (!resultQuestion) throw new Error("Result question not found"); if (isResultQuestionEmpty(resultQuestion)) { devlog("Result question is empty"); return; } setCurrentQuizStep("question"); setCurrentQuestion(resultQuestion); }, [resultQuestion, settings.cfg.resultInfo.showResultForm]); const moveToPrevQuestionLinear = useCallback(() => { if (questionIndex === null) return; const question = questions[questionIndex - 1]; if (question && question.type !== "result") { setCurrentQuestion(question); } }, [questionIndex, questions]); const moveToNextQuestionLinear = useCallback(() => { if (questionIndex === null) return; const question = questions[questionIndex + 1]; if (question && question.type !== "result") { return setCurrentQuestion(question); } if (!resultQuestion) throw new Error("Result question not found"); showResult(resultQuestion); }, [questionIndex, questions, resultQuestion, showResult]); const moveToPrevQuestionBranching = useCallback(() => { if (currentQuestion.content.rule.parentId === "root") throw new Error("No question to go back to"); const questionId = currentQuestion.content.rule.parentId; const parent = questions.find(q => q.id === questionId || q.content.id === questionId) || null; if (!parent || parent.type === "result") throw new Error("Parent question not found"); setCurrentQuestion(parent); }, [currentQuestion.content.rule.parentId, questions]); const moveToNextQuestionBranching = useCallback(() => { if (!nextQuestion) throw new Error("Next question not found"); if (nextQuestion.type === "result") { showResult(nextQuestion); } else { setCurrentQuestion(nextQuestion); } }, [nextQuestion, showResult]); const isPreviousButtonDisabled = useMemo(() => { if (isLinear) { const questionIndex = questions.findIndex(({ id }) => id === currentQuestion.id); const previousQuestion = questions[questionIndex - 1]; return previousQuestion ? false : true; } else { return currentQuestion.content.rule.parentId === "root" ? true : false; } }, [questions, isLinear, currentQuestion.content.rule.parentId, currentQuestion.id]); const isNextButtonDisabled = useMemo(() => { const answer = answers.find(({ questionId }) => questionId === currentQuestion.id); if ("required" in currentQuestion.content && currentQuestion.content.required) { return !answer; } if (isLinear) return false; if (nextQuestion) { return false; } else { const questionId = currentQuestion.content.rule.default; const nextQuestion = questions.find(q => q.id === questionId || q.content.id === questionId) || null; if (nextQuestion?.type) return false; } return true; }, [answers, currentQuestion.content, currentQuestion.id, isLinear, nextQuestion, questions]); useDebugValue({ isLinear, currentQuestion, nextQuestion: questions.find(q => q.content.id === nextQuestionId), resultQuestion, }); return { currentQuestion, currentQuestionStepNumber, isNextButtonDisabled, isPreviousButtonDisabled, moveToPrevQuestion: isLinear ? moveToPrevQuestionLinear : moveToPrevQuestionBranching, moveToNextQuestion: isLinear ? moveToNextQuestionLinear : moveToNextQuestionBranching, showResultAfterContactForm, }; }