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
+121 -48
View File
@@ -276,6 +276,10 @@ input[type="number"] {
background: #444242;
}
#resumeButton {
margin-left: 16px;
}
/*page 1 ends*/
/*page 2 starts*/
@@ -848,8 +852,8 @@ input::-ms-input-placeholder {
padding-bottom: 4px;
border-bottom: 1px solid black;
position: absolute;
bottom: 4px;
left: 50%;
bottom: 4px;
}
#page4 .customImgRow img {
width: 335px;
@@ -899,6 +903,14 @@ input::-ms-input-placeholder {
line-height: 30px;
margin: 0px;
}
#response-timer {
display: block;
text-align: center;
font-size: 2rem;
margin-top: 24px;
font-weight: bold;
color: #222;
}
/*page 5 ends here*/
/*page6 starts*/
@@ -1447,63 +1459,124 @@ img.image-missing {
border-left: none;
}
#resetQuizButton,
#resumeButton {
background: #737a73;
color: #fff;
font: 12px "Necto Mono";
border: none;
border-radius: 4px;
padding: 10px 32px;
margin-left: 8px;
cursor: pointer;
transition: all 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
outline: none;
#termination-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.95);
z-index: 9999;
justify-content: center;
align-items: center;
}
#resetQuizButton:hover,
#resumeButton:hover,
#resetQuizButton:focus,
#resumeButton:focus {
background: #444242;
#termination-overlay .termination-content {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#termination-overlay .termination-message {
color: #fff;
font-family: "Necto Mono", monospace;
font-size: 1.6rem;
text-align: center;
margin-bottom: 32px;
letter-spacing: 1px;
}
#termination-overlay .termination-title {
color: #fff;
font-family: "Bradford LL", serif;
font-size: 2.5rem;
font-style: italic;
text-align: center;
margin-bottom: 32px;
}
#termination-overlay .termination-counter {
color: #fff;
font-family: "Bradford LL", serif;
font-size: 3.5rem;
font-style: italic;
text-align: center;
margin-top: 16px;
}
#questionNavBar .nav-btn {
font: 12px "Necto Mono";
border-radius: 4px !important;
padding: 10px 16px !important;
margin: 0 4px;
min-width: 32px;
min-height: 32px;
border: none;
#resetQuizButton {
position: absolute;
top: 16px;
right: 24px;
background: #fff;
color: #222;
border: 2px solid #222;
border-radius: 6px;
padding: 8px 20px;
font-size: 1rem;
font-family: "Bradford LL", serif;
font-weight: bold;
cursor: pointer;
transition: background 0.2s, color 0.2s;
text-align: center;
vertical-align: middle;
display: inline-flex;
align-items: center;
z-index: 10;
}
#resetQuizButton:hover {
background: #222;
color: #fff;
}
#question-nav-bar {
width: 100%;
background: #f7f7f7;
border-bottom: 1px solid #ddd;
padding: 12px 0 8px 0;
position: sticky;
top: 0;
z-index: 20;
display: flex;
justify-content: center;
align-items: center;
min-height: 48px;
}
#questionNavBar .nav-btn.answered {
background: #43a047;
color: #fff;
border: 2px solid #388e3c;
.question-nav-inner {
display: flex;
gap: 8px;
overflow-x: auto;
padding: 0 16px;
}
#questionNavBar .nav-btn.current {
background: #1976d2;
color: #fff;
border: 3px solid #1565c0;
box-shadow: 0 0 8px 2px rgba(25, 118, 210, 0.15);
z-index: 2;
}
#questionNavBar .nav-btn.unanswered {
background: #ccc;
color: #888;
.question-nav-btn {
min-width: 36px;
height: 36px;
border-radius: 50%;
border: 2px solid #bbb;
}
#questionNavBar .nav-btn:hover,
#questionNavBar .nav-btn:focus {
filter: brightness(0.95);
background: #fff;
color: #bbb;
font-size: 1.1rem;
font-family: "Bradford LL", serif;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
outline: none;
}
.question-nav-btn.answered {
background: #e0ffe0;
color: #1a7f1a;
border-color: #1a7f1a;
}
.question-nav-btn.current {
background: #222;
color: #fff;
border-color: #222;
box-shadow: 0 0 0 2px #fff, 0 0 0 4px #222;
}
.question-nav-btn.unanswered {
background: #fff;
color: #bbb;
border-color: #bbb;
opacity: 0.6;
}
.question-nav-btn:hover {
background: #f0f0f0;
color: #222;
border-color: #222;
}
+170 -498
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,214 +2170,47 @@ 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();
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);
}
// 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 {
// 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 not terminating, proceed as normal (select/deselect logic)
// (existing selection logic is handled by the .selectionBtn click handler)
}
// 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();
}
});
// 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) {
localStorage.removeItem("answers");
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) {
uniqueQuestionsShowed = [];
currentQuizIndex = 0;
currentQuestionCounter = 0;
}
isExecuted = false;
$("#page1").css("display", "none");
$("#page2").css("display", "none");
$("#page3").css("display", "none");
@@ -2330,293 +2218,77 @@ $(document).ready(function () {
$("#page5").css("display", "none");
$("#page6").css("display", "none");
$("#page7").css("display", "none");
await getQuizzesApi();
showQuizTitle();
askQuestion(allItems[currentQuizIndex].questions, currentQuestionCounter);
});
return nextQuestion();
}
});
// 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")
) {
// Also update nav bar on nextQuestion
const origNextQuestion = nextQuestion;
nextQuestion = async function (...args) {
const result = await origNextQuestion.apply(this, args);
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();
}
};
+12 -60
View File
@@ -27,8 +27,8 @@
<button id="beginButton" class="beginButton">LET'S BEGIN!</button>
<button
id="resumeButton"
class="resumeButton"
style="display: none; margin-top: 1em"
class="beginButton"
style="display: none; margin-left: 16px"
>
RESUME QUIZ
</button>
@@ -74,29 +74,11 @@
><img src="/image/right-arrow.png"
/></span>
</div>
<button
id="resetQuizButton"
class="resetQuizButton"
style="margin-left: 1em"
>
<button id="resetQuizButton" class="resetQuizButton">
Reset Quiz
</button>
</div>
<div
id="questionNavBar"
class="question-nav-bar"
style="
position: static;
width: 100%;
background: #fff;
z-index: 1000;
display: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
padding: 0.5em 0;
justify-content: center;
align-items: center;
"
></div>
<div id="question-nav-bar"></div>
<div class="row questionRow mtb" id="questionRow">
<h1>
<!-- dynamic data here -->
@@ -261,6 +243,7 @@
/></span>
</div>
</div>
<div id="question-nav-bar"></div>
<div class="row responseRow">
<div class="responseInner">
<div class="responseHead">
@@ -269,17 +252,9 @@
<div class="responseBody">
<!-- dynamic data here -->
</div>
<div
id="responseCountdown"
style="
display: none;
text-align: center;
font-size: 1.5em;
margin-top: 1em;
"
></div>
</div>
</div>
<div id="response-timer"></div>
<div id="weatherApi" data-type="8">
<div class="header">Environmental Profile</div>
<div class="info">
@@ -397,35 +372,12 @@
<div></div>
<div></div>
</div>
<div
id="terminationOverlay"
style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.85);
z-index: 9999;
justify-content: center;
align-items: center;
flex-direction: column;
"
>
<div
id="terminationMessage"
style="
color: white;
font-size: 2em;
text-align: center;
margin-bottom: 1em;
"
></div>
<div
id="terminationCountdown"
style="color: white; font-size: 2em; text-align: center"
></div>
<div id="termination-overlay" style="display: none">
<div class="termination-content">
<div class="termination-message"></div>
<div class="termination-title"></div>
<div class="termination-counter"></div>
</div>
</div>
<script src="/frontend_js/jquery.min.js"></script>
<script src="/frontend_js/jquery-2.1.3.js"></script>