fix: skipping questions bug and overall UI and flow update
This commit is contained in:
+121
-48
@@ -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;
|
||||
}
|
||||
|
||||
+184
-512
@@ -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;
|
||||
};
|
||||
|
||||
+12
-60
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user