analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
850 lines (849 loc) • 32.6 kB
JavaScript
// src/components/Quiz/useQuizStore.ts
import { create } from "zustand";
import { devtools } from "zustand/middleware";
var QUESTION_DIFFICULTY = /* @__PURE__ */ ((QUESTION_DIFFICULTY2) => {
QUESTION_DIFFICULTY2["FACIL"] = "FACIL";
QUESTION_DIFFICULTY2["MEDIO"] = "MEDIO";
QUESTION_DIFFICULTY2["DIFICIL"] = "DIFICIL";
return QUESTION_DIFFICULTY2;
})(QUESTION_DIFFICULTY || {});
var QUIZ_TYPE = /* @__PURE__ */ ((QUIZ_TYPE2) => {
QUIZ_TYPE2["SIMULADO"] = "SIMULADO";
QUIZ_TYPE2["QUESTIONARIO"] = "QUESTIONARIO";
QUIZ_TYPE2["ATIVIDADE"] = "ATIVIDADE";
QUIZ_TYPE2["AULA_RECOMENDADA"] = "AULA_RECOMENDADA";
return QUIZ_TYPE2;
})(QUIZ_TYPE || {});
var QUESTION_TYPE = /* @__PURE__ */ ((QUESTION_TYPE2) => {
QUESTION_TYPE2["ALTERNATIVA"] = "ALTERNATIVA";
QUESTION_TYPE2["DISSERTATIVA"] = "DISSERTATIVA";
QUESTION_TYPE2["MULTIPLA_ESCOLHA"] = "MULTIPLA_ESCOLHA";
QUESTION_TYPE2["VERDADEIRO_FALSO"] = "VERDADEIRO_FALSO";
QUESTION_TYPE2["RELACIONAR"] = "RELACIONAR";
QUESTION_TYPE2["PREENCHER_LACUNAS"] = "PREENCHER_LACUNAS";
QUESTION_TYPE2["IMAGEM"] = "IMAGEM";
return QUESTION_TYPE2;
})(QUESTION_TYPE || {});
var hasMeaningfulAnswer = (answer) => {
if (!answer) return false;
if (answer.questionType === "MULTIPLA_ESCOLHA" /* MULTIPLA_ESCOLHA */) {
return Array.isArray(answer.selectedOptionIds) && answer.selectedOptionIds.length > 0 || Boolean(answer.optionId);
}
const freeTextTypes = [
"DISSERTATIVA" /* DISSERTATIVA */,
"RELACIONAR" /* RELACIONAR */,
"PREENCHER_LACUNAS" /* PREENCHER_LACUNAS */,
"IMAGEM" /* IMAGEM */,
"VERDADEIRO_FALSO" /* VERDADEIRO_FALSO */
];
if (freeTextTypes.includes(answer.questionType)) {
if (!answer.answer || answer.answer.trim() === "") return false;
if (answer.questionType === "RELACIONAR" /* RELACIONAR */ || answer.questionType === "PREENCHER_LACUNAS" /* PREENCHER_LACUNAS */ || answer.questionType === "VERDADEIRO_FALSO" /* VERDADEIRO_FALSO */) {
try {
const parsed = JSON.parse(answer.answer);
return typeof parsed === "object" && Object.keys(parsed).length > 0;
} catch {
return false;
}
}
return true;
}
return answer.optionId !== null && answer.optionId !== "";
};
var QUESTION_STATUS = /* @__PURE__ */ ((QUESTION_STATUS2) => {
QUESTION_STATUS2["PENDENTE_AVALIACAO"] = "PENDENTE_AVALIACAO";
QUESTION_STATUS2["RESPOSTA_CORRETA"] = "RESPOSTA_CORRETA";
QUESTION_STATUS2["RESPOSTA_INCORRETA"] = "RESPOSTA_INCORRETA";
QUESTION_STATUS2["NAO_RESPONDIDO"] = "NAO_RESPONDIDO";
return QUESTION_STATUS2;
})(QUESTION_STATUS || {});
var ANSWER_STATUS = /* @__PURE__ */ ((ANSWER_STATUS2) => {
ANSWER_STATUS2["RESPOSTA_CORRETA"] = "RESPOSTA_CORRETA";
ANSWER_STATUS2["RESPOSTA_INCORRETA"] = "RESPOSTA_INCORRETA";
ANSWER_STATUS2["PENDENTE_AVALIACAO"] = "PENDENTE_AVALIACAO";
ANSWER_STATUS2["NAO_RESPONDIDO"] = "NAO_RESPONDIDO";
return ANSWER_STATUS2;
})(ANSWER_STATUS || {});
var SUBTYPE_ENUM = /* @__PURE__ */ ((SUBTYPE_ENUM2) => {
SUBTYPE_ENUM2["PROVA"] = "PROVA";
SUBTYPE_ENUM2["ENEM_PROVA_1"] = "ENEM_PROVA_1";
SUBTYPE_ENUM2["ENEM_PROVA_2"] = "ENEM_PROVA_2";
SUBTYPE_ENUM2["VESTIBULAR"] = "VESTIBULAR";
SUBTYPE_ENUM2["SIMULADO"] = "SIMULADO";
SUBTYPE_ENUM2["SIMULADAO"] = "SIMULADAO";
return SUBTYPE_ENUM2;
})(SUBTYPE_ENUM || {});
var MINUTE_INTERVAL_MS = 6e4;
var useQuizStore = create()(
devtools(
(set, get) => {
let timerInterval = null;
let minuteCallbackInterval = null;
let timerStartedAt = null;
let timerBaseElapsed = 0;
const clampElapsed = (elapsed) => {
const { timeLimit } = get();
return timeLimit === null ? elapsed : Math.min(elapsed, timeLimit);
};
const handleVisibilityChange = () => {
if (document.visibilityState === "visible" && timerStartedAt !== null) {
const now = Date.now();
const elapsed = clampElapsed(
timerBaseElapsed + Math.floor((now - timerStartedAt) / 1e3)
);
set({ timeElapsed: elapsed });
checkTimeLimit(elapsed);
}
};
const checkTimeLimit = (elapsed) => {
const { timeLimit, isFinished, onTimeUp } = get();
if (timeLimit !== null && elapsed >= timeLimit && !isFinished) {
get().finishQuiz();
onTimeUp?.();
}
};
const startTimer = () => {
if (get().isFinished) {
return;
}
if (timerInterval) {
clearInterval(timerInterval);
}
timerStartedAt = Date.now();
timerBaseElapsed = get().timeElapsed;
document.addEventListener("visibilitychange", handleVisibilityChange);
timerInterval = setInterval(() => {
if (timerStartedAt === null) return;
const now = Date.now();
const elapsed = clampElapsed(
timerBaseElapsed + Math.floor((now - timerStartedAt) / 1e3)
);
set({ timeElapsed: elapsed });
checkTimeLimit(elapsed);
}, 1e3);
};
const stopTimer = () => {
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
timerStartedAt = null;
timerBaseElapsed = 0;
document.removeEventListener(
"visibilitychange",
handleVisibilityChange
);
};
const setMinuteCallback = (callback) => {
set({ minuteCallback: callback });
};
const startMinuteCallback = () => {
const { minuteCallback, isFinished } = get();
if (isFinished || !minuteCallback) {
return;
}
if (minuteCallbackInterval) {
clearInterval(minuteCallbackInterval);
}
minuteCallbackInterval = setInterval(() => {
const {
minuteCallback: currentCallback,
isFinished: currentIsFinished
} = get();
if (currentIsFinished || !currentCallback) {
stopMinuteCallback();
return;
}
currentCallback();
}, MINUTE_INTERVAL_MS);
};
const stopMinuteCallback = () => {
if (minuteCallbackInterval) {
clearInterval(minuteCallbackInterval);
minuteCallbackInterval = null;
}
};
return {
// Initial State
quiz: null,
currentQuestionIndex: 0,
selectedAnswers: {},
userAnswers: [],
timeElapsed: 0,
isStarted: false,
isFinished: false,
userId: "",
variant: "default" /* DEFAULT */,
minuteCallback: null,
dissertativeCharLimit: void 0,
timeLimit: null,
onTimeUp: null,
questionsResult: null,
currentQuestionResult: null,
draftApiClient: null,
lastSavedDraftPayload: "",
isSavingDraft: false,
activityFeedback: null,
// Setters
setQuiz: (quiz) => set({ quiz }),
setUserId: (userId) => set({ userId }),
setUserAnswers: (userAnswers) => set({ userAnswers }),
getUserId: () => get().userId,
setVariant: (variant) => set({ variant }),
setQuestionResult: (questionsResult) => set({ questionsResult }),
setDissertativeCharLimit: (limit) => set({ dissertativeCharLimit: limit }),
getDissertativeCharLimit: () => get().dissertativeCharLimit,
setDraftApiClient: (client) => set({ draftApiClient: client }),
// Draft save - called automatically on navigation
saveDraft: async () => {
const {
draftApiClient,
quiz,
hasDraftChanges,
prepareDraftPayload,
lastSavedDraftPayload,
isSavingDraft
} = get();
if (!draftApiClient || !quiz) return;
if (isSavingDraft) return;
if (!hasDraftChanges()) return;
const payload = prepareDraftPayload();
const payloadString = JSON.stringify(payload);
if (payloadString === lastSavedDraftPayload) return;
try {
set({ isSavingDraft: true });
await draftApiClient.saveDraft(quiz.id, payload);
set({ lastSavedDraftPayload: payloadString });
} catch (error) {
console.warn("Erro ao salvar rascunho:", error);
} finally {
set({ isSavingDraft: false });
}
},
// Load draft and apply to quiz, navigate to first unanswered question
loadAndApplyDraft: async () => {
const {
draftApiClient,
quiz,
applyDraftAnswers,
prepareDraftPayload
} = get();
if (!draftApiClient || !quiz) return;
try {
const draftData = await draftApiClient.loadDraft(quiz.id);
if (draftData?.hasDraft && draftData.answers?.length > 0) {
applyDraftAnswers(draftData.answers);
const payload = prepareDraftPayload();
set({ lastSavedDraftPayload: JSON.stringify(payload) });
const questions = get().quiz?.questions || [];
const updatedAnswers = get().userAnswers;
const firstUnansweredIndex = questions.findIndex((question) => {
const answer = updatedAnswers.find(
(a) => a.questionId === question.id
);
if (!answer) return true;
if (answer.optionId) return false;
if (answer.selectedOptionIds && answer.selectedOptionIds.length > 0)
return false;
if (answer.answer && answer.answer.trim() !== "") return false;
return true;
});
if (firstUnansweredIndex > 0) {
set({ currentQuestionIndex: firstUnansweredIndex });
}
}
} catch (error) {
console.warn("Erro ao carregar rascunho:", error);
}
},
// Navigation
goToNextQuestion: () => {
const { currentQuestionIndex, getTotalQuestions, saveDraft } = get();
const totalQuestions = getTotalQuestions();
if (currentQuestionIndex < totalQuestions - 1) {
saveDraft();
set({ currentQuestionIndex: currentQuestionIndex + 1 });
}
},
goToPreviousQuestion: () => {
const { currentQuestionIndex, saveDraft } = get();
if (currentQuestionIndex > 0) {
saveDraft();
set({ currentQuestionIndex: currentQuestionIndex - 1 });
}
},
goToQuestion: (index) => {
const { getTotalQuestions, currentQuestionIndex, saveDraft } = get();
const totalQuestions = getTotalQuestions();
if (index >= 0 && index < totalQuestions && index !== currentQuestionIndex) {
saveDraft();
set({ currentQuestionIndex: index });
}
},
selectAnswer: (questionId, answerId) => {
const { quiz, userAnswers } = get();
if (!quiz) return;
const activityId = quiz.id;
const userId = get().getUserId();
if (!userId || userId === "") {
return;
}
const question = quiz.questions.find((q) => q.id === questionId);
if (!question) return;
const existingAnswerIndex = userAnswers.findIndex(
(answer) => answer.questionId === questionId
);
const newUserAnswer = {
questionId,
activityId,
userId,
answer: question.questionType === "DISSERTATIVA" /* DISSERTATIVA */ ? answerId : null,
optionId: question.questionType === "DISSERTATIVA" /* DISSERTATIVA */ ? null : answerId,
questionType: question.questionType,
answerStatus: "PENDENTE_AVALIACAO" /* PENDENTE_AVALIACAO */
};
let updatedUserAnswers;
if (existingAnswerIndex !== -1) {
updatedUserAnswers = [...userAnswers];
updatedUserAnswers[existingAnswerIndex] = newUserAnswer;
} else {
updatedUserAnswers = [...userAnswers, newUserAnswer];
}
set({
userAnswers: updatedUserAnswers
});
},
selectMultipleAnswer: (questionId, answerIds) => {
const { quiz, userAnswers } = get();
if (!quiz) return;
const activityId = quiz.id;
const userId = get().getUserId();
if (!userId || userId === "") {
return;
}
const question = quiz.questions.find((q) => q.id === questionId);
if (!question) return;
const filteredUserAnswers = userAnswers.filter(
(answer) => answer.questionId !== questionId
);
if (answerIds.length === 0) {
set({
userAnswers: filteredUserAnswers
});
return;
}
const newUserAnswer = {
questionId,
activityId,
userId,
answer: null,
optionId: answerIds.length > 0 ? answerIds[0] : null,
selectedOptionIds: answerIds,
questionType: question.questionType,
answerStatus: "PENDENTE_AVALIACAO" /* PENDENTE_AVALIACAO */
};
const updatedUserAnswers = [...filteredUserAnswers, newUserAnswer];
set({
userAnswers: updatedUserAnswers
});
},
selectDissertativeAnswer: (questionId, answer) => {
const { quiz, userAnswers, dissertativeCharLimit } = get();
if (!quiz) return;
const activityId = quiz.id;
const userId = get().getUserId();
if (!userId || userId === "") {
return;
}
const question = quiz.questions.find((q) => q.id === questionId);
const allowedTypes = [
"DISSERTATIVA" /* DISSERTATIVA */,
"RELACIONAR" /* RELACIONAR */,
"PREENCHER_LACUNAS" /* PREENCHER_LACUNAS */,
"IMAGEM" /* IMAGEM */,
"VERDADEIRO_FALSO" /* VERDADEIRO_FALSO */
];
if (!question || !allowedTypes.includes(question.questionType)) {
return;
}
let validatedAnswer = answer;
if (question.questionType === "DISSERTATIVA" /* DISSERTATIVA */ && dissertativeCharLimit !== void 0 && answer.length > dissertativeCharLimit) {
validatedAnswer = answer.substring(0, dissertativeCharLimit);
}
const existingAnswerIndex = userAnswers.findIndex(
(answerItem) => answerItem.questionId === questionId
);
const newUserAnswer = {
questionId,
activityId,
userId,
answer: validatedAnswer,
optionId: null,
questionType: question.questionType,
answerStatus: "PENDENTE_AVALIACAO" /* PENDENTE_AVALIACAO */
};
let updatedUserAnswers;
if (existingAnswerIndex !== -1) {
updatedUserAnswers = [...userAnswers];
updatedUserAnswers[existingAnswerIndex] = newUserAnswer;
} else {
updatedUserAnswers = [...userAnswers, newUserAnswer];
}
set({
userAnswers: updatedUserAnswers
});
},
skipQuestion: () => {
const { getCurrentQuestion, userAnswers, quiz } = get();
const currentQuestion = getCurrentQuestion();
if (!quiz) return;
if (currentQuestion) {
const activityId = quiz.id;
const userId = get().getUserId();
if (!userId || userId === "") {
return;
}
const existingAnswerIndex = userAnswers.findIndex(
(answer) => answer.questionId === currentQuestion.id
);
const existingAnswer = existingAnswerIndex === -1 ? null : userAnswers[existingAnswerIndex];
if (hasMeaningfulAnswer(existingAnswer)) {
return;
}
const newUserAnswer = {
questionId: currentQuestion.id,
activityId,
userId,
answer: null,
optionId: null,
questionType: currentQuestion.questionType,
answerStatus: "PENDENTE_AVALIACAO" /* PENDENTE_AVALIACAO */
};
let updatedUserAnswers;
if (existingAnswerIndex !== -1) {
updatedUserAnswers = [...userAnswers];
updatedUserAnswers[existingAnswerIndex] = newUserAnswer;
} else {
updatedUserAnswers = [...userAnswers, newUserAnswer];
}
set({
userAnswers: updatedUserAnswers
});
}
},
skipCurrentQuestionIfUnanswered: () => {
const { getCurrentQuestion, getCurrentAnswer, skipQuestion } = get();
const currentQuestion = getCurrentQuestion();
const currentAnswer = getCurrentAnswer();
if (!currentQuestion) return;
if (!currentAnswer || currentAnswer.optionId === null && currentAnswer.answer === null && (!currentAnswer.selectedOptionIds || currentAnswer.selectedOptionIds.length === 0)) {
skipQuestion();
}
},
addUserAnswer: (questionId, answerId) => {
const { quiz, userAnswers } = get();
if (!quiz) return;
const activityId = quiz.id;
const userId = get().getUserId();
if (!userId || userId === "") {
return;
}
const question = quiz.questions.find((q) => q.id === questionId);
if (!question) return;
const existingAnswerIndex = userAnswers.findIndex(
(answer) => answer.questionId === questionId
);
const newUserAnswer = {
questionId,
activityId,
userId,
answer: question.questionType === "DISSERTATIVA" /* DISSERTATIVA */ ? answerId || null : null,
optionId: question.questionType !== "DISSERTATIVA" /* DISSERTATIVA */ ? answerId || null : null,
questionType: question.questionType,
answerStatus: "PENDENTE_AVALIACAO" /* PENDENTE_AVALIACAO */
};
if (existingAnswerIndex !== -1) {
const updatedUserAnswers = [...userAnswers];
updatedUserAnswers[existingAnswerIndex] = newUserAnswer;
set({ userAnswers: updatedUserAnswers });
} else {
set({ userAnswers: [...userAnswers, newUserAnswer] });
}
},
startQuiz: () => {
set({ isStarted: true, timeElapsed: 0 });
startTimer();
startMinuteCallback();
},
finishQuiz: () => {
set({ isFinished: true });
stopTimer();
stopMinuteCallback();
},
resetQuiz: () => {
stopTimer();
stopMinuteCallback();
set({
quiz: null,
currentQuestionIndex: 0,
selectedAnswers: {},
userAnswers: [],
timeElapsed: 0,
isStarted: false,
isFinished: false,
userId: "",
variant: "default" /* DEFAULT */,
minuteCallback: null,
dissertativeCharLimit: void 0,
timeLimit: null,
onTimeUp: null,
questionsResult: null,
currentQuestionResult: null,
// Note: draftApiClient is NOT reset here - it's managed by useDraftAutoSave hook
lastSavedDraftPayload: "",
isSavingDraft: false,
activityFeedback: null
});
},
// Timer
updateTime: (time) => {
timerBaseElapsed = time;
if (timerStartedAt !== null) {
timerStartedAt = Date.now();
}
set({ timeElapsed: time });
checkTimeLimit(time);
},
startTimer,
stopTimer,
setTimeLimit: (seconds) => set({ timeLimit: seconds }),
setOnTimeUp: (callback) => set({ onTimeUp: callback }),
getRemainingTime: () => {
const { timeLimit, timeElapsed } = get();
if (timeLimit === null) return null;
return Math.max(0, timeLimit - timeElapsed);
},
// Minute Callback
setMinuteCallback,
startMinuteCallback,
stopMinuteCallback,
// Getters
getCurrentQuestion: () => {
const { currentQuestionIndex, quiz } = get();
if (!quiz) {
return null;
}
return quiz.questions[currentQuestionIndex];
},
getTotalQuestions: () => {
const { quiz } = get();
return quiz?.questions?.length || 0;
},
getAnsweredQuestions: () => {
const { userAnswers } = get();
const answeredQuestionIds = new Set(
userAnswers.filter((answer) => hasMeaningfulAnswer(answer)).map((answer) => answer.questionId)
);
return answeredQuestionIds.size;
},
getUnansweredQuestions: () => {
const { quiz, userAnswers } = get();
if (!quiz) return [];
const unansweredQuestions = [];
quiz.questions.forEach((question, index) => {
const userAnswer = userAnswers.find(
(answer) => answer.questionId === question.id
);
const isAnswered = hasMeaningfulAnswer(userAnswer);
const isSkipped = userAnswer && !hasMeaningfulAnswer(userAnswer);
if (!isAnswered && !isSkipped) {
unansweredQuestions.push(index + 1);
}
});
return unansweredQuestions;
},
getSkippedQuestions: () => {
const { userAnswers } = get();
const skippedQuestionIds = new Set(
userAnswers.filter((answer) => !hasMeaningfulAnswer(answer)).map((answer) => answer.questionId)
);
return skippedQuestionIds.size;
},
getProgress: () => {
const { getTotalQuestions, getAnsweredQuestions } = get();
const total = getTotalQuestions();
const answered = getAnsweredQuestions();
return total > 0 ? answered / total * 100 : 0;
},
isQuestionAnswered: (questionId) => {
const { userAnswers } = get();
const userAnswer = userAnswers.find(
(answer) => answer.questionId === questionId
);
return hasMeaningfulAnswer(userAnswer);
},
isQuestionSkipped: (questionId) => {
const { userAnswers } = get();
const userAnswer = userAnswers.find(
(answer) => answer.questionId === questionId
);
return userAnswer ? !hasMeaningfulAnswer(userAnswer) : false;
},
getCurrentAnswer: () => {
const { getCurrentQuestion, userAnswers } = get();
const currentQuestion = getCurrentQuestion();
if (!currentQuestion) return void 0;
const userAnswer = userAnswers.find(
(answer) => answer.questionId === currentQuestion.id
);
if (!hasMeaningfulAnswer(userAnswer)) {
return void 0;
}
return userAnswer;
},
getAllCurrentAnswer: () => {
const { getCurrentQuestion, userAnswers } = get();
const currentQuestion = getCurrentQuestion();
if (!currentQuestion) return void 0;
const userAnswer = userAnswers.filter(
(answer) => answer.questionId === currentQuestion.id
);
return userAnswer;
},
getQuizTitle: () => {
const { quiz } = get();
return quiz?.title || "Quiz";
},
formatTime: (seconds) => {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return `${minutes.toString().padStart(2, "0")}:${remainingSeconds.toString().padStart(2, "0")}`;
},
getUserAnswers: () => {
const { userAnswers } = get();
return userAnswers;
},
getUnansweredQuestionsFromUserAnswers: () => {
const { quiz, userAnswers } = get();
if (!quiz) return [];
const unansweredQuestions = [];
quiz.questions.forEach((question, index) => {
const userAnswer = userAnswers.find(
(answer) => answer.questionId === question.id
);
const hasAnswer = hasMeaningfulAnswer(userAnswer);
const isSkipped = userAnswer && !hasMeaningfulAnswer(userAnswer);
if (!hasAnswer || isSkipped) {
unansweredQuestions.push(index + 1);
}
});
return unansweredQuestions;
},
getQuestionsGroupedBySubject: () => {
const { getQuestionResult, quiz, variant } = get();
const questions = variant == "result" ? getQuestionResult()?.answers : quiz?.questions;
if (!questions) return {};
const groupedQuestions = {};
questions.forEach((question) => {
const subjectId = question.knowledgeMatrix?.[0]?.subject?.id || "Sem mat\xE9ria";
if (!groupedQuestions[subjectId]) {
groupedQuestions[subjectId] = [];
}
groupedQuestions[subjectId].push(question);
});
return groupedQuestions;
},
// New methods for userAnswers
getUserAnswerByQuestionId: (questionId) => {
const { userAnswers } = get();
return userAnswers.find((answer) => answer.questionId === questionId) || null;
},
isQuestionAnsweredByUserAnswers: (questionId) => {
const { userAnswers } = get();
const answer = userAnswers.find(
(answer2) => answer2.questionId === questionId
);
return hasMeaningfulAnswer(answer);
},
getQuestionStatusFromUserAnswers: (questionId) => {
const { userAnswers } = get();
const answer = userAnswers.find(
(answer2) => answer2.questionId === questionId
);
if (!answer) return "unanswered";
if (hasMeaningfulAnswer(answer)) return "answered";
return "skipped";
},
getUserAnswersForActivity: () => {
const { userAnswers } = get();
return userAnswers;
},
setCurrentQuestion: (question) => {
const { quiz, variant, questionsResult } = get();
if (!quiz) return;
let questionIndex;
if (variant == "result") {
if (!questionsResult) return;
const questionResult = questionsResult.answers.find((q) => q.id === question.id) ?? questionsResult.answers.find((q) => q.questionId === question.id);
if (!questionResult) return;
questionIndex = quiz.questions.findIndex(
(q) => q.id === questionResult.questionId
);
} else {
questionIndex = quiz.questions.findIndex(
(q) => q.id === question.id
);
}
if (questionIndex === -1) {
return;
}
set({ currentQuestionIndex: questionIndex });
},
setAnswerStatus: (questionId, status) => {
const { userAnswers } = get();
const existingAnswerIndex = userAnswers.findIndex(
(answer) => answer.questionId === questionId
);
if (existingAnswerIndex !== -1) {
const updatedUserAnswers = [...userAnswers];
updatedUserAnswers[existingAnswerIndex] = {
...updatedUserAnswers[existingAnswerIndex],
answerStatus: status
};
set({ userAnswers: updatedUserAnswers });
}
},
getAnswerStatus: (questionId) => {
const { userAnswers } = get();
const userAnswer = userAnswers.find(
(answer) => answer.questionId === questionId
);
return userAnswer ? userAnswer.answerStatus : null;
},
getQuestionIndex: (questionId) => {
const { questionsResult, variant, quiz } = get();
if (variant == "result") {
if (!questionsResult) return 0;
let idx = questionsResult.answers.findIndex(
(q) => q.questionId === questionId
);
if (idx === -1) {
idx = questionsResult.answers.findIndex(
(q) => q.id === questionId
);
}
return idx !== -1 ? idx + 1 : 0;
} else {
if (!quiz) return 0;
const idx = quiz.questions.findIndex((q) => q.id === questionId);
return idx !== -1 ? idx + 1 : 0;
}
},
// Question Result
getQuestionResultByQuestionId: (questionId) => {
const { questionsResult } = get();
const question = questionsResult?.answers.find(
(answer) => answer.questionId === questionId
);
return question || null;
},
getQuestionResultStatistics: () => {
const { questionsResult } = get();
return questionsResult?.statistics || null;
},
getQuestionResult: () => {
const { questionsResult } = get();
return questionsResult;
},
setQuestionsResult: (questionsResult) => {
set({ questionsResult });
},
setCurrentQuestionResult: (currentQuestionResult) => {
set({ currentQuestionResult });
},
getCurrentQuestionResult: () => {
const { currentQuestionResult } = get();
return currentQuestionResult;
},
// Draft management
applyDraftAnswers: (draftAnswers) => {
const { quiz, userId } = get();
if (!quiz || !draftAnswers || draftAnswers.length === 0) return;
const activityId = quiz.id;
const newUserAnswers = [];
for (const draft of draftAnswers) {
const question = quiz.questions.find(
(q) => q.id === draft.questionId
);
if (!question) continue;
let parsedAnswer = draft.answer;
let selectedOptionIds = draft.selectedOptionIds;
if (draft.answer && !draft.optionId) {
try {
const parsed = JSON.parse(draft.answer);
if (parsed.selectedOptionIds) {
selectedOptionIds = parsed.selectedOptionIds;
parsedAnswer = null;
}
} catch {
}
}
const userAnswer = {
questionId: draft.questionId,
activityId,
userId,
answer: parsedAnswer,
optionId: draft.optionId || null,
selectedOptionIds: selectedOptionIds || null,
questionType: question.questionType,
answerStatus: "PENDENTE_AVALIACAO" /* PENDENTE_AVALIACAO */
};
newUserAnswers.push(userAnswer);
}
set({ userAnswers: newUserAnswers });
},
prepareDraftPayload: () => {
const { userAnswers } = get();
const answers = userAnswers.filter((answer) => hasMeaningfulAnswer(answer)).map((answer) => {
const draftAnswer = {
questionId: answer.questionId
};
if (answer.optionId) {
draftAnswer.optionId = answer.optionId;
}
if (answer.answer) {
draftAnswer.answer = answer.answer;
}
if (answer.selectedOptionIds && answer.selectedOptionIds.length > 0) {
draftAnswer.selectedOptionIds = answer.selectedOptionIds;
}
return draftAnswer;
});
return { answers };
},
hasDraftChanges: () => {
const { userAnswers } = get();
return userAnswers.some((answer) => hasMeaningfulAnswer(answer));
},
// Activity Feedback
setActivityFeedback: (feedback) => set({ activityFeedback: feedback }),
getActivityFeedback: () => get().activityFeedback
};
},
{
name: "quiz-store"
}
)
);
export {
QUESTION_DIFFICULTY,
QUIZ_TYPE,
QUESTION_TYPE,
hasMeaningfulAnswer,
QUESTION_STATUS,
ANSWER_STATUS,
SUBTYPE_ENUM,
MINUTE_INTERVAL_MS,
useQuizStore
};
//# sourceMappingURL=chunk-G7IP4VLI.mjs.map