fix: skipping questions bug and overall UI and flow update

This commit is contained in:
Ayobami
2025-07-25 20:57:49 +01:00
parent 6a137285e6
commit 1e7808fb4a
3 changed files with 317 additions and 620 deletions
+184 -512
View File
@@ -64,7 +64,6 @@ let nextQuestionTimeoutCounter = 3000;
let selectionQuestionTimeoutCounter = 6000;
let closeResponseTimeoutCounter = 5000;
let timeout;
let responseCountdownInterval;
const mainImage = $(".main-image-container img");
fetch(url_preset + "/configurations")
@@ -76,7 +75,23 @@ fetch(url_preset + "/configurations")
}
});
$(document).on("click", ".beginButton", async function () {
$(document).ready(function () {
// Show Resume button if there is saved progress
if (localStorage.getItem("answers")) {
$("#resumeButton").show();
} else {
$("#resumeButton").hide();
}
});
$(document).on("click", "#beginButton", async function () {
// Clear progress and start fresh
localStorage.removeItem("answers");
dataToReturn = [];
uniqueQuestionsShowed = [];
currentQuizIndex = 0;
currentQuestionCounter = 0;
isExecuted = false;
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
@@ -89,6 +104,56 @@ $(document).on("click", ".beginButton", async function () {
return nextQuestion();
});
$(document).on("click", "#resumeButton", async function () {
// Resume from last progress
dataToReturn = localStorage.getItem("answers")
? JSON.parse(localStorage.getItem("answers"))
: [];
uniqueQuestionsShowed = [];
currentQuizIndex = 0;
currentQuestionCounter = 0;
isExecuted = false;
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
$("#page4").css("display", "none");
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
await getQuizzesApi();
showQuizTitle();
// Find last answered question
let lastQ = null;
let lastQuizIdx = 0;
let lastQCounter = 0;
if (dataToReturn.length > 0) {
for (let i = 0; i < allItems.length; i++) {
const quiz = allItems[i];
for (let j = 0; j < quiz.questions.length; j++) {
const q = quiz.questions[j];
if (dataToReturn.find((a) => a.question && a.question.id === q.id)) {
lastQuizIdx = i;
lastQCounter = j + 1;
}
}
}
currentQuizIndex = lastQuizIdx;
currentQuestionCounter = lastQCounter;
}
// Go to the next unanswered question
setTimeout(() => {
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "block");
$("#page4").css("display", "none");
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
$("#progressBarSection").css("display", "block");
nextQuestion();
}, nextQuestionTimeoutCounter);
});
$(document).on("click", ".goBottom", function () {
$("html, body").animate({ scrollTop: $(document).height() }, "slow");
});
@@ -1023,22 +1088,26 @@ function showResponse(responseHead, responseBody, weatherQuestion) {
if (weatherQuestion) {
$("#page5 #weatherApi").css("display", "block");
}
// Countdown timer logic for Quiz 2
clearInterval(responseCountdownInterval);
let countdown = Math.ceil(closeResponseTimeoutCounter / 1000);
$("#responseCountdown").show().text(`Closing in ${countdown} seconds...`);
responseCountdownInterval = setInterval(function () {
countdown--;
if (countdown > 0) {
$("#responseCountdown").text(`Closing in ${countdown} seconds...`);
// Countdown timer logic
if (window.responseCountdownInterval) {
clearInterval(window.responseCountdownInterval);
}
const timerDiv = $("#response-timer");
let secondsLeft = Math.ceil(closeResponseTimeoutCounter / 1000);
timerDiv.text(secondsLeft);
timerDiv.show();
window.responseCountdownInterval = setInterval(() => {
secondsLeft--;
if (secondsLeft > 0) {
timerDiv.text(secondsLeft);
} else {
clearInterval(responseCountdownInterval);
$("#responseCountdown").hide();
timerDiv.text(0);
clearInterval(window.responseCountdownInterval);
}
}, 1000);
closeResponseTimeout = setTimeout(() => {
clearInterval(responseCountdownInterval);
$("#responseCountdown").hide();
closeResponse();
}, closeResponseTimeoutCounter);
}
@@ -1047,11 +1116,15 @@ function showResponse(responseHead, responseBody, weatherQuestion) {
function closeResponse() {
responseOnGoing = false;
hasNoResponse = true;
clearInterval(responseCountdownInterval);
$("#responseCountdown").hide();
$("#page5").css("display", "none");
$("#page4").css("display", "none");
$("#page3").css("display", "block");
// Clear the countdown timer
if (window.responseCountdownInterval) {
clearInterval(window.responseCountdownInterval);
window.responseCountdownInterval = null;
}
$("#response-timer").hide();
if (currentQuestionCounter < totalQuizQuestions.length) {
return askQuestion(totalQuizQuestions, currentQuestionCounter);
} else {
@@ -1068,8 +1141,6 @@ function closeResponse() {
} // function closeResponse ends here
async function askQuestion(totalQuizQuestions, counter, fromBack) {
// Always hide all answer rows before showing the current one
$(".answerRow").hide();
clearTimeout(timeout);
clearTimeout(closeResponseTimeout);
@@ -1420,10 +1491,10 @@ async function askQuestion(totalQuizQuestions, counter, fromBack) {
`);
}
});
// Add 'None of the above' button
// Add 'None of the above' option at the end
$("#typeSelection .answerInner").append(`
<div class="selectionOptions">
<button class="selectionBtns selectionBtn noneOfTheAboveBtn" onclick="handleNoneOfTheAbove()">None of the above</button>
<button class="selectionBtns selectionBtn none-of-the-above" onclick="handleNoneOfTheAbove()">None of the above</button>
</div>
`);
@@ -1483,8 +1554,6 @@ async function askQuestion(totalQuizQuestions, counter, fromBack) {
$("#questionRow h1").html(ques.question);
}
currentQuestionCounter++;
// At the end of askQuestion, always update the nav bar
renderQuestionNavBar();
}
async function storeAnswer(currentQuestion, currentActiveAnswerType) {
@@ -1798,20 +1867,6 @@ async function storeAnswer(currentQuestion, currentActiveAnswerType) {
}
}
localStorage.setItem("answers", JSON.stringify(dataToReturn));
if (
typeof customerEmail !== "undefined" &&
customerEmail &&
customerEmail.innerText
) {
localStorage.setItem(
"answers_" + customerEmail.innerText,
JSON.stringify(dataToReturn)
);
}
let userKey = getUserProgressKey();
localStorage.setItem(userKey, JSON.stringify(dataToReturn));
checkResumeButtonVisibility();
renderQuestionNavBar();
}
let currentSuggestIndex;
@@ -2115,508 +2170,125 @@ function handleImageMissing(self) {
$(self).addClass("image-missing");
}
// 1. Add checkAllergie function near the top (after variable declarations)
function checkAllergie(btn) {
clearTimeout(timeout);
var val = $(btn).attr("data-val");
// Quiz 4: Terminate if Banana, Olive, or Sunflowers is selected
if (["Banana", "Olive", "Sunflowers"].includes(val)) {
showTerminationScreen();
// Implement checkAllergie for Quiz 4
function checkAllergie(self) {
const value = self.dataset.val || $(self).data("val");
if (["Banana", "Olive", "Sunflowers"].includes(value)) {
// Simulate API fetch for message and counter
const terminationMessage =
"You have an allergy to one of the main ingredients in our system. Our current system will not suit you.";
const terminationTitle = "Quiz will now be terminated";
let counter = 10; // seconds (simulate API value)
$("#termination-overlay .termination-message").text(terminationMessage);
$("#termination-overlay .termination-title").text(terminationTitle);
$("#termination-overlay .termination-counter").text(counter);
$("#termination-overlay").css("display", "flex");
let interval = setInterval(() => {
counter--;
$("#termination-overlay .termination-counter").text(counter);
if (counter <= 0) {
clearInterval(interval);
window.location.href = "/";
}
}, 1000);
// Block all interaction
$("body > *:not(#termination-overlay)").css("pointer-events", "none");
return;
}
if ($(btn).hasClass("active")) {
tempSelectionAns.splice(tempSelectionAns.indexOf(val), 1);
$(btn).removeClass("active");
$(btn).removeClass("highlight");
} else {
tempSelectionAns.push(val);
if (!$(btn).hasClass("active")) $(btn).addClass("active");
if (!$(btn).hasClass("highlight")) $(btn).addClass("highlight");
}
timeout = setTimeout(function () {
nextQuestion();
}, selectionQuestionTimeoutCounter);
// If not terminating, proceed as normal (select/deselect logic)
// (existing selection logic is handled by the .selectionBtn click handler)
}
// Quiz 4: Show termination overlay and handle countdown/redirect
function showTerminationScreen() {
// Get message and counter from mainConfigurations (from /configurations API)
var message =
mainConfigurations && mainConfigurations.termination_message
? mainConfigurations.termination_message
: "You have selected an allergen. The quiz will now end.";
var counter =
mainConfigurations && mainConfigurations.termination_counter
? parseInt(mainConfigurations.termination_counter)
: 5;
$("#terminationMessage").text(message);
$("#terminationCountdown").text(counter);
$("#terminationOverlay").css({ display: "flex" });
var countdown = counter;
var interval = setInterval(function () {
countdown--;
if (countdown > 0) {
$("#terminationCountdown").text(countdown);
} else {
clearInterval(interval);
window.location.href = "/";
}
}, 1000);
}
// Quiz 5: Show Resume Quiz button if progress exists, and handle resume logic
$(document).ready(function () {
// Use email as key if available, otherwise fallback to local
let userKey = null;
if (
typeof customerEmail !== "undefined" &&
customerEmail &&
customerEmail.innerText
) {
userKey = "answers_" + customerEmail.innerText;
}
let savedAnswers = userKey
? localStorage.getItem(userKey)
: localStorage.getItem("answers");
if (savedAnswers && JSON.parse(savedAnswers).length > 0) {
$("#resumeButton").show();
}
$("#resumeButton").on("click", async function () {
// Load saved progress
let answers = userKey
? localStorage.getItem(userKey)
: localStorage.getItem("answers");
if (answers) {
dataToReturn = JSON.parse(answers);
// Find last answered question
let lastQ = dataToReturn[dataToReturn.length - 1];
// Set quiz and question index
let found = false;
for (let i = 0; i < allItems.length; i++) {
let idx = allItems[i].questions.findIndex(
(q) => q.id === lastQ.question.id
);
if (idx !== -1) {
currentQuizIndex = i;
currentQuestionCounter = idx + 1;
found = true;
break;
}
}
if (!found) {
currentQuizIndex = 0;
currentQuestionCounter = 0;
}
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
$("#page4").css("display", "none");
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
await getQuizzesApi();
showQuizTitle();
// Resume from next unanswered question
return askQuestion(
allItems[currentQuizIndex].questions,
currentQuestionCounter
);
}
});
});
// Utility for user-specific progress key
function getUserProgressKey() {
if (
typeof customerEmail !== "undefined" &&
customerEmail &&
customerEmail.innerText
) {
return "answers_" + customerEmail.innerText;
}
return "answers";
}
function clearAllProgress() {
localStorage.removeItem("answers");
if (
typeof customerEmail !== "undefined" &&
customerEmail &&
customerEmail.innerText
) {
localStorage.removeItem("answers_" + customerEmail.innerText);
}
}
// Overwrite reset logic
$(document).on("click", "#resetQuizButton", function () {
$(document).on("click", "#resetQuizButton", async function () {
if (
confirm(
"Are you sure you want to reset the quiz? All progress will be lost."
)
) {
clearAllProgress();
// Reload the page for a true fresh start (clears all in-memory state/UI)
window.location.reload();
localStorage.removeItem("answers");
dataToReturn = [];
uniqueQuestionsShowed = [];
currentQuizIndex = 0;
currentQuestionCounter = 0;
isExecuted = false;
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
$("#page4").css("display", "none");
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
await getQuizzesApi();
showQuizTitle();
return nextQuestion();
}
});
// Overwrite resume logic
$(document).ready(function () {
let userKey = getUserProgressKey();
let savedAnswers = localStorage.getItem(userKey);
if (savedAnswers && JSON.parse(savedAnswers).length > 0) {
$("#resumeButton").show();
}
$("#resumeButton")
.off("click")
.on("click", async function () {
let userKey = getUserProgressKey();
let answers = localStorage.getItem(userKey);
let navState = localStorage.getItem("quiz_nav_state");
await getQuizzesApi(); // Always load quizzes first
let startFromBeginning = false;
let found = false;
if (answers) {
try {
dataToReturn = JSON.parse(answers);
} catch (e) {
dataToReturn = [];
}
if (Array.isArray(dataToReturn) && dataToReturn.length > 0) {
let lastQ = dataToReturn[dataToReturn.length - 1];
if (
lastQ &&
lastQ.question &&
typeof lastQ.question.id !== "undefined"
) {
for (let i = 0; i < allItems.length; i++) {
let idx = allItems[i].questions.findIndex(
(q) => q.id === lastQ.question.id
);
if (idx !== -1) {
currentQuizIndex = i;
currentQuestionCounter = idx + 1;
found = true;
break;
}
}
}
}
}
// If not found by answers, try nav state
if (!found && navState) {
try {
const { quizIndex, questionCounter } = JSON.parse(navState);
if (
typeof quizIndex === "number" &&
typeof questionCounter === "number"
) {
currentQuizIndex = quizIndex;
currentQuestionCounter = questionCounter;
found = true;
}
} catch (e) {}
}
// If still not found, start from beginning
if (!found) {
currentQuizIndex = 0;
currentQuestionCounter = 0;
}
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
$("#page4").css("display", "none");
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
showQuizTitle();
askQuestion(allItems[currentQuizIndex].questions, currentQuestionCounter);
});
});
// In storeAnswer, always save to the correct user key
async function storeAnswer(currentQuestion, currentActiveAnswerType) {
// ... existing code ...
let userKey = getUserProgressKey();
localStorage.setItem(userKey, JSON.stringify(dataToReturn));
checkResumeButtonVisibility();
renderQuestionNavBar();
}
function renderQuestionNavBar() {
if (!allItems || allItems.length === 0 || !$("#page3").is(":visible")) {
$("#questionNavBar").hide();
// Hide on landing and final result pages
if ($("#page1").is(":visible") || $("#page7").is(":visible")) {
$("#question-nav-bar").hide();
return;
}
let questions = [];
allItems.forEach((quiz) => {
quiz.questions.forEach((q) => {
questions.push({ id: q.id, text: q.question });
});
});
let answeredIds = (dataToReturn || [])
.map((a) => a.question && a.question.id)
.filter(Boolean);
// Determine the current question id
let currentId = null;
$("#question-nav-bar").show();
$("#question-nav-bar").html("");
if (
allItems[currentQuizIndex] &&
allItems[currentQuizIndex].questions[currentQuestionCounter] // currentQuestionCounter points to the next question, so use currentQuestionCounter-1 if >0
) {
currentId =
allItems[currentQuizIndex].questions[currentQuestionCounter]?.id;
// If currentId is undefined (e.g., at end), fallback to previous
if (!currentId && currentQuestionCounter > 0) {
currentId =
allItems[currentQuizIndex].questions[currentQuestionCounter - 1]?.id;
}
} else if (
allItems[currentQuizIndex] &&
allItems[currentQuizIndex].questions[currentQuestionCounter - 1]
) {
currentId =
allItems[currentQuizIndex].questions[currentQuestionCounter - 1].id;
}
let html = "";
questions.forEach((q, idx) => {
let btnClass = "nav-btn";
const isAnswered = answeredIds.includes(q.id);
const isCurrent = q.id === currentId;
if (isAnswered) btnClass += " answered";
!allItems ||
!allItems[currentQuizIndex] ||
!allItems[currentQuizIndex].questions
)
return;
const questions = allItems[currentQuizIndex].questions;
let navHtml = '<div class="question-nav-inner">';
for (let i = 0; i < questions.length; i++) {
const q = questions[i];
let answered = dataToReturn.find(
(a) => a.question && a.question.id === q.id
);
let isCurrent = i === currentQuestionCounter - 1;
let btnClass = "question-nav-btn";
if (isCurrent) btnClass += " current";
if (!isAnswered) btnClass += " unanswered";
html += `<button class="${btnClass}" data-qid="${
q.id
}" style="margin:0 4px; min-width:32px; min-height:32px; border-radius:4px; border:none; font-weight:bold; cursor:pointer;">${
idx + 1
}</button>`;
});
$("#questionNavBar").html(html).show();
else if (answered) btnClass += " answered";
else btnClass += " unanswered";
navHtml += `<button class="${btnClass}" data-qidx="${i}">${i + 1}</button>`;
}
navHtml += "</div>";
$("#question-nav-bar").html(navHtml);
}
// Handle nav bar button click
$(document).on("click", "#questionNavBar .nav-btn", function () {
let qid = parseInt($(this).attr("data-qid"));
let found = false;
for (let i = 0; i < allItems.length; i++) {
let idx = allItems[i].questions.findIndex((q) => q.id === qid);
if (idx !== -1) {
currentQuizIndex = i;
currentQuestionCounter = idx;
found = true;
break;
}
// Helper to jump to a specific question index in the current quiz
function jumpToQuestion(index) {
// Hide all answer rows and question row
var divsToHide = document.getElementsByClassName("answerRow");
for (let i = 0; i < divsToHide.length; i++) {
divsToHide[i].style.display = "none";
}
if (found) {
askQuestion(allItems[currentQuizIndex].questions, currentQuestionCounter);
$("#questionRow").css("display", "none");
// Set the counter and show the question
currentQuestionCounter = index;
askQuestion(allItems[currentQuizIndex].questions, index);
}
// Handle nav bar click
$(document).on("click", ".question-nav-btn", async function () {
const idx = parseInt($(this).attr("data-qidx"));
if (!isNaN(idx)) {
jumpToQuestion(idx);
}
});
// Update nav bar on question change
let origAskQuestion = askQuestion;
const origAskQuestion = askQuestion;
askQuestion = async function (...args) {
let result = await origAskQuestion.apply(this, args);
const result = await origAskQuestion.apply(this, args);
renderQuestionNavBar();
return result;
};
// Show/hide nav bar on page changes
function updateNavBarVisibility() {
if (
typeof renderQuestionNavBar === "function" &&
$("#page3").is(":visible")
) {
renderQuestionNavBar();
$("#questionNavBar").show();
} else {
$("#questionNavBar").hide();
}
}
// Ensure nav bar is shown after every askQuestion
if (!window._quizNavWrapped) {
window._quizNavWrapped = true;
const origAskQuestion = askQuestion;
askQuestion = async function (...args) {
let result = await origAskQuestion.apply(this, args);
updateNavBarVisibility();
saveNavState();
return result;
};
}
// On page load or resume, restore nav state and show nav bar if on question page
$(document).ready(function () {
loadNavState();
updateNavBarVisibility();
});
// Add minimal CSS for nav bar button states
$(
"<style>\
#questionNavBar { display: flex !important; overflow-x: auto; }\
#questionNavBar .nav-btn { background: #eee; color: #333; transition: background 0.2s; }\
#questionNavBar .nav-btn.answered { background: #4caf50; color: #fff; }\
#questionNavBar .nav-btn.current { background: #2196f3; color: #fff; border: 2px solid #1976d2; }\
#questionNavBar .nav-btn.unanswered { background: #ccc; color: #888; }\
</style>"
).appendTo("head");
// Utility for nav state persistence
function saveNavState() {
localStorage.setItem(
"quiz_nav_state",
JSON.stringify({
quizIndex: currentQuizIndex,
questionCounter: currentQuestionCounter,
})
);
}
function loadNavState() {
const state = localStorage.getItem("quiz_nav_state");
if (state) {
try {
const { quizIndex, questionCounter } = JSON.parse(state);
if (
typeof quizIndex === "number" &&
typeof questionCounter === "number"
) {
currentQuizIndex = quizIndex;
currentQuestionCounter = questionCounter;
}
} catch (e) {}
}
}
// On reset, clear nav state
function clearAllProgress() {
localStorage.removeItem("answers");
localStorage.removeItem("quiz_nav_state");
if (
typeof customerEmail !== "undefined" &&
customerEmail &&
customerEmail.innerText
) {
localStorage.removeItem("answers_" + customerEmail.innerText);
}
$("#resumeButton").hide();
}
// BEGIN button: always start fresh and clear progress
$(document).on("click", "#beginButton", async function () {
clearAllProgress();
$("#resumeButton").hide();
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
$("#page4").css("display", "none");
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
dataToReturn = [];
uniqueQuestionsShowed = [];
lastQuizResponseShown = null;
lastShowedQuestionId = null;
currentQuizIndex = 0;
currentQuestionCounter = 0;
isExecuted = false;
await getQuizzesApi();
showQuizTitle();
askQuestion(allItems[currentQuizIndex].questions, 0);
});
// Resume button logic: only show if there is progress
function checkResumeButtonVisibility() {
let userKey = getUserProgressKey();
let savedAnswers = localStorage.getItem(userKey);
let navState = localStorage.getItem("quiz_nav_state");
if ((savedAnswers && JSON.parse(savedAnswers).length > 0) || navState) {
$("#resumeButton").show();
} else {
$("#resumeButton").hide();
}
}
$(document).ready(function () {
loadNavState();
updateNavBarVisibility();
checkResumeButtonVisibility();
$("#resumeButton")
.off("click")
.on("click", async function () {
let userKey = getUserProgressKey();
let answers = localStorage.getItem(userKey);
let navState = localStorage.getItem("quiz_nav_state");
await getQuizzesApi(); // Always load quizzes first
let startFromBeginning = false;
let found = false;
if (answers) {
try {
dataToReturn = JSON.parse(answers);
} catch (e) {
dataToReturn = [];
}
if (Array.isArray(dataToReturn) && dataToReturn.length > 0) {
let lastQ = dataToReturn[dataToReturn.length - 1];
if (
lastQ &&
lastQ.question &&
typeof lastQ.question.id !== "undefined"
) {
for (let i = 0; i < allItems.length; i++) {
let idx = allItems[i].questions.findIndex(
(q) => q.id === lastQ.question.id
);
if (idx !== -1) {
currentQuizIndex = i;
currentQuestionCounter = idx + 1;
found = true;
break;
}
}
}
}
}
// If not found by answers, try nav state
if (!found && navState) {
try {
const { quizIndex, questionCounter } = JSON.parse(navState);
if (
typeof quizIndex === "number" &&
typeof questionCounter === "number"
) {
currentQuizIndex = quizIndex;
currentQuestionCounter = questionCounter;
found = true;
}
} catch (e) {}
}
// If still not found, start from beginning
if (!found) {
currentQuizIndex = 0;
currentQuestionCounter = 0;
}
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
$("#page4").css("display", "none");
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
showQuizTitle();
askQuestion(allItems[currentQuizIndex].questions, currentQuestionCounter);
});
});
// After reset, hide resume button until new progress is made
function clearAllProgress() {
localStorage.removeItem("answers");
localStorage.removeItem("quiz_nav_state");
if (
typeof customerEmail !== "undefined" &&
customerEmail &&
customerEmail.innerText
) {
localStorage.removeItem("answers_" + customerEmail.innerText);
}
$("#resumeButton").hide();
}
// Also update nav bar on nextQuestion
const origNextQuestion = nextQuestion;
nextQuestion = async function (...args) {
const result = await origNextQuestion.apply(this, args);
renderQuestionNavBar();
return result;
};