reorganize files

This commit is contained in:
2025-01-30 16:28:56 +02:00
parent 594a5fc0d5
commit f8bb71a184
94 changed files with 2 additions and 25 deletions

55
public/js/app.js Normal file
View File

@@ -0,0 +1,55 @@
// src/js/app.js
document.addEventListener('DOMContentLoaded', function() {
const currentPage = window.location.pathname.split('/').pop();
if (currentPage === 'consent.html') {
initConsentPage();
} else if (currentPage === 'quiz.html') {
initQuizPage();
} else if (currentPage === 'questionnaire.html') {
initQuestionnairePage();
} else if (currentPage === 'results.html') {
initResultsPage();
}
});
function initConsentPage() {
const consentButton = document.getElementById('consent-button');
consentButton.addEventListener('click', function() {
fetch('../data/questions.json')
.then(response => response.json())
.then(data => {
const quizVersions = Object.keys(data.quizzes);
const randomVersion = quizVersions[Math.floor(Math.random() * quizVersions.length)];
localStorage.setItem('quizVersion', randomVersion);
window.location.href = 'quiz.html';
});
});
}
function initQuizPage() {
const version = localStorage.getItem('quizVersion');
loadQuestions(version);
}
function initQuestionnairePage() {
// Logic for initializing the questionnaire page
}
function initResultsPage() {
// Logic for displaying results
}
function loadQuestions(version) {
fetch('../data/questions.json')
.then(response => response.json())
.then(data => {
const questions = data.quizzes[version];
displayQuestions(questions);
});
}
function displayQuestions(questions) {
// Logic to display questions on the quiz page
}

14
public/js/consent.js Normal file
View File

@@ -0,0 +1,14 @@
document.addEventListener('DOMContentLoaded', function() {
const consentButton = document.getElementById('consentButton');
consentButton.addEventListener('click', function() {
fetch('../data/questions.json')
.then(response => response.json())
.then(data => {
const quizVersions = Object.keys(data.quizzes);
const randomVersion = quizVersions[Math.floor(Math.random() * quizVersions.length)];
localStorage.setItem('quizVersion', randomVersion);
window.location.href = 'quiz.html';
});
});
});

View File

@@ -0,0 +1,80 @@
// This file handles the logic for the questionnaire, including collecting additional participant information after the quiz.
document.addEventListener('DOMContentLoaded', function() {
const questionnaireForm = document.getElementById('questionnaire-form');
questionnaireForm.addEventListener('submit', function(event) {
event.preventDefault();
// Form validation
const age = document.getElementById('age').value;
if (age < 0 || age > 120) {
showError('Please enter a valid age between 0 and 120');
return;
}
const participantData = {
age: age,
gender: document.getElementById('gender').value,
education: document.getElementById('education').value,
colorBlind: document.getElementById('color-blind').value,
familiarity: document.getElementById('familiarity').value,
englishLevel: document.getElementById('english-level').value,
ukrainianLevel: document.getElementById('ukrainian-level').value,
visualizationDifficulty: document.getElementById('visualization-difficulty').value,
quizDifficulty: document.getElementById('quiz-difficulty').value,
kseAffiliation: document.getElementById('kse-affiliation').value,
comments: document.getElementById('comments').value
};
// Disable form while submitting
const submitButton = document.querySelector('button[type="submit"]');
submitButton.disabled = true;
// Store participant data in local storage
localStorage.setItem('participantData', JSON.stringify(participantData));
// Retrieve existing quiz data
const allQuizzes = JSON.parse(localStorage.getItem('allQuizzes') || '{}');
const quizId = 'quiz';
if (allQuizzes[quizId]) {
allQuizzes[quizId].participantData = participantData;
allQuizzes[quizId].iterationVersion = 'v1.0.0'; // Add semantic versioning
localStorage.setItem('allQuizzes', JSON.stringify(allQuizzes));
}
// Send data to the backend
fetch('/api/responses', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(allQuizzes)
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data.success) {
console.log('Success:', data);
window.location.href = 'results.html';
} else {
throw new Error(data.message || 'Failed to submit the form');
}
})
.catch((error) => {
console.error('Error:', error);
showError('Failed to submit the form. Please try again.');
submitButton.disabled = false;
});
});
function showError(message) {
const errorDiv = document.getElementById('error-message');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
}
});

201
public/js/quiz.js Normal file
View File

@@ -0,0 +1,201 @@
// This file manages the quiz functionality, including loading questions from the JSON file, displaying them to the user, and collecting answers.
document.addEventListener('DOMContentLoaded', function () {
const quizContainer = document.getElementById('quiz');
const resultsContainer = document.getElementById('results');
const timerDisplay = document.getElementById('time');
const timerLabel = document.getElementById('timer-label'); // Add a label for the timer
const version = localStorage.getItem('quizVersion');
const quizId = 'quiz';
let questions = [];
let currentQuestionIndex = 0;
let score = 0;
let quizResults = [];
const initialTimeLeft = 25000; // 25 seconds in milliseconds
let timeLeft = initialTimeLeft;
let timer;
let startTime = new Date().toISOString();
// Set timer label based on version
if (version === 'ukrainian') {
timerLabel.textContent = 'Час, що залишився:';
} else {
timerLabel.textContent = 'Time remaining:';
}
// Generate and store browser ID
function generateBrowserId() {
return 'xxxx-xxxx-4xxx-yxxx-xxxx-xxxx-xxxx-xxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
const browserId = localStorage.getItem('browserId') || generateBrowserId();
localStorage.setItem('browserId', browserId);
const browserInfo = {
userAgent: navigator.userAgent,
screenResolution: `${window.screen.width}x${window.screen.height}`,
operatingSystem: navigator.platform,
hostname: window.location.hostname // Store hostname
};
// Check if there is a completed quiz
const allQuizzes = JSON.parse(localStorage.getItem('allQuizzes') || '{}');
if (allQuizzes[quizId] && allQuizzes[quizId].completed) {
alert("Ви вже пройшли дослідження. Дякуємо! Перенаправлення на головну сторінку тесту.");
window.location.href = 'index.html';
return;
}
fetch('data/questions.json')
.then(response => response.json())
.then(data => {
if (!data.quizzes || !data.quizzes[version] || !data.quizzes[version].questions) {
throw new Error('Invalid quiz data or version');
}
questions = data.quizzes[version].questions;
questions = shuffleArray(questions); // Randomize the order of questions
displayQuestion();
})
.catch(error => {
console.error('Error loading quiz:', error);
quizContainer.innerHTML = '<p>Error loading quiz. Please try again later.</p>';
});
// Function to shuffle an array
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
function displayQuestion() {
if (!questions || currentQuestionIndex >= questions.length) {
showResults();
return;
}
// Complete timer reset
stopTimer();
timeLeft = initialTimeLeft; // Reset to initial time
timerDisplay.textContent = Math.ceil(timeLeft / 1000); // Display in whole seconds
const question = questions[currentQuestionIndex];
const imageVersion = version === 'translated' ? 'original' : version;
const imagePath = `/images/${question.chart}-${imageVersion}.${question.image}`;
document.getElementById('chart').innerHTML = `<img src="${imagePath}" alt="${question.chart_uk}">`;
// Update question and options
document.getElementById('question-text').innerHTML = question.question;
document.getElementById('options').innerHTML = question.options.map((option, index) => `
<button class="option-button" data-value="${option}">${option}</button>
`).join('');
// Start fresh timer
startTimer();
// Add event listeners to option buttons
document.querySelectorAll('.option-button').forEach(button => {
button.addEventListener('click', () => submitAnswer(button.dataset.value));
});
}
function stopTimer() {
if (timer) {
clearInterval(timer);
timer = null;
}
}
function startTimer() {
// Clear any existing timer
stopTimer();
// Ensure display shows starting value
timerDisplay.textContent = Math.ceil(timeLeft / 1000); // Display in whole seconds
timer = setInterval(() => {
timeLeft -= 100; // Decrease by 100 milliseconds
timerDisplay.textContent = Math.ceil(timeLeft / 1000); // Display in whole seconds
if (timeLeft <= 0) {
stopTimer();
alert("Time's up! Moving to the next question.");
submitAnswer(true);
}
}, 100);
}
function storeQuizProgress() {
const currentProgress = {
quizId: quizId,
version: version,
score: score,
currentQuestionIndex: currentQuestionIndex,
totalQuestions: questions.length,
answers: quizResults,
lastUpdated: new Date().toISOString(),
participantData: JSON.parse(localStorage.getItem('participantData') || '{}'),
startTime: startTime, // Store start time
browserId: browserId, // Store browser ID
browserInfo: browserInfo // Store browser info including hostname
};
const allQuizzes = JSON.parse(localStorage.getItem('allQuizzes') || '{}');
allQuizzes[quizId] = currentProgress;
localStorage.setItem('allQuizzes', JSON.stringify(allQuizzes));
}
function submitAnswer(selectedAnswer = null) {
// Stop the timer first
stopTimer();
if (!selectedAnswer) {
alert('Please select an answer before proceeding.');
startTimer(); // Restart timer if no answer selected
return;
}
const currentQuestion = questions[currentQuestionIndex];
const isCorrect = selectedAnswer === currentQuestion.answer;
if (isCorrect) {
score++;
}
// Store the question result
quizResults.push({
question: currentQuestion.question,
selectedAnswer: selectedAnswer,
correctAnswer: currentQuestion.answer,
isCorrect: isCorrect,
questionIndex: currentQuestionIndex,
ordinalNumber: currentQuestionIndex + 1, // Store the ordinal number of the question
timestamp: new Date().toISOString(),
timeSpent: 25000 - timeLeft, // Time spent in milliseconds
chartType: currentQuestion.chart,
chartTypeUk: currentQuestion.chart_uk // Include chart_uk type
});
// Store progress after each answer
storeQuizProgress();
currentQuestionIndex++;
// Reset timer state before showing next question
timeLeft = initialTimeLeft; // Reset to initial time
displayQuestion();
}
function showResults() {
// Mark quiz as completed
const allQuizzes = JSON.parse(localStorage.getItem('allQuizzes') || '{}');
allQuizzes[quizId].completed = true;
allQuizzes[quizId].completedAt = new Date().toISOString();
localStorage.setItem('allQuizzes', JSON.stringify(allQuizzes));
// Redirect to the questionnaire page
window.location.href = 'questionnaire.html';
}
});

30
public/js/results.js Normal file
View File

@@ -0,0 +1,30 @@
const resultsContainer = document.getElementById('results');
const resultsHeader = document.getElementById('results-header');
const resultsTableBody = document.getElementById('results-table-body');
const allQuizzes = JSON.parse(localStorage.getItem('allQuizzes') || '{}');
const quizData = allQuizzes['quiz'];
function displayResults() {
const totalQuestions = quizData.totalQuestions;
const correctAnswers = quizData.score;
const percentage = ((correctAnswers / totalQuestions) * 100).toFixed(2);
resultsHeader.textContent = `Результати тесту: ${correctAnswers}/${totalQuestions}, ${percentage}%`;
let resultsHTML = '';
quizData.answers.forEach(answer => {
resultsHTML += `
<tr>
<td>${answer.question}</td>
<td>${answer.chartTypeUk}</td>
<td>${answer.isCorrect ? '✅' : '❌'}</td>
</tr>
`;
});
resultsTableBody.innerHTML = resultsHTML;
}
window.onload = displayResults;