mirror of
https://github.com/sailor-sh/CK-X.git
synced 2026-07-12 17:19:18 +00:00
218 lines
6.3 KiB
JavaScript
218 lines
6.3 KiB
JavaScript
/**
|
|
* Timer Service
|
|
* Handles timer functionality for the exam
|
|
*/
|
|
|
|
let timerDuration = 120; // Default timer duration in minutes
|
|
let timerInterval = null;
|
|
let timerElement = null;
|
|
let onTimerEndCallback = null;
|
|
let isTimerRunning = false;
|
|
const timeThresholds = [30, 10, 0]; // Time thresholds in minutes
|
|
let timeThresholdCallbacks = {}; // Callbacks for time thresholds
|
|
let processedThresholds = new Set(); // Track which thresholds have been processed
|
|
|
|
/**
|
|
* Set timer duration
|
|
* @param {number} duration - Duration in minutes
|
|
*/
|
|
function setTimerDuration(duration) {
|
|
timerDuration = duration;
|
|
// Reset processed thresholds when timer duration changes
|
|
processedThresholds.clear();
|
|
}
|
|
|
|
/**
|
|
* Register callbacks for specific time thresholds
|
|
* @param {Object} callbacks - Object with threshold minutes as keys and callback functions as values
|
|
*/
|
|
function registerTimeThresholdCallbacks(callbacks) {
|
|
timeThresholdCallbacks = { ...timeThresholdCallbacks, ...callbacks };
|
|
}
|
|
|
|
/**
|
|
* Get remaining time
|
|
* @returns {number} Remaining time in minutes
|
|
*/
|
|
function getRemainingTime() {
|
|
return timerDuration;
|
|
}
|
|
|
|
/**
|
|
* Calculate remaining exam time based on exam info
|
|
* @param {Object} examInfo - The exam information object
|
|
* @returns {number} Remaining time in minutes
|
|
*/
|
|
function calculateRemainingTime(examInfo) {
|
|
// If exam hasn't started yet or no duration set, return default
|
|
if (!examInfo.info?.examDurationInMinutes) {
|
|
return getRemainingTime();
|
|
}
|
|
|
|
// Check if exam has ended
|
|
if (examInfo.info?.events?.examEndTime) {
|
|
return 0; // No time remaining if exam is finished
|
|
}
|
|
|
|
// If exam has started, calculate remaining time
|
|
if (examInfo.info?.events?.examStartTime) {
|
|
// Make sure we have a proper number value for startTime
|
|
let startTime = examInfo.info.events.examStartTime;
|
|
|
|
// Parse the timestamp to ensure it's a number (could be stored as string)
|
|
if (typeof startTime === 'string') {
|
|
startTime = parseInt(startTime, 10);
|
|
}
|
|
|
|
// Debug log to identify the issue
|
|
console.log('Start time (epoch):', startTime);
|
|
console.log('Current time (epoch):', Date.now());
|
|
console.log('Exam duration (minutes):', examInfo.info.examDurationInMinutes);
|
|
|
|
const durationMs = examInfo.info.examDurationInMinutes * 60 * 1000;
|
|
const elapsedMs = Date.now() - startTime;
|
|
const remainingMs = Math.max(0, durationMs - elapsedMs);
|
|
|
|
// Debug log for troubleshooting
|
|
console.log('Duration (ms):', durationMs);
|
|
console.log('Elapsed (ms):', elapsedMs);
|
|
console.log('Remaining (ms):', remainingMs);
|
|
console.log('Remaining (minutes):', Math.ceil(remainingMs / (60 * 1000)));
|
|
|
|
// Convert ms to minutes
|
|
return Math.ceil(remainingMs / (60 * 1000));
|
|
}
|
|
|
|
// Default: return full duration if exam hasn't started
|
|
return examInfo.info.examDurationInMinutes;
|
|
}
|
|
|
|
/**
|
|
* Initialize the timer
|
|
* @param {HTMLElement} element - DOM element to display the timer
|
|
* @param {number} minutes - Timer duration in minutes
|
|
* @param {Object} options - Optional configuration
|
|
* @param {Function} options.onTimerEnd - Callback function when timer ends
|
|
*/
|
|
function initTimer(element, minutes, options = {}) {
|
|
timerElement = element;
|
|
timerDuration = minutes;
|
|
onTimerEndCallback = options.onTimerEnd;
|
|
|
|
// Reset processed thresholds when initializing new timer
|
|
processedThresholds.clear();
|
|
|
|
updateTimerDisplay(minutes);
|
|
}
|
|
|
|
/**
|
|
* Check if a time threshold has been reached and trigger callback
|
|
* @param {number} remainingMinutes - Remaining time in minutes
|
|
* @param {number} remainingSeconds - Remaining time in seconds
|
|
*/
|
|
function checkTimeThresholds(remainingMinutes, remainingSeconds) {
|
|
// Check each threshold
|
|
timeThresholds.forEach(threshold => {
|
|
// If we just crossed this threshold and haven't processed it yet
|
|
if (remainingMinutes === threshold &&
|
|
remainingSeconds === 0 &&
|
|
!processedThresholds.has(threshold)) {
|
|
|
|
// Mark as processed
|
|
processedThresholds.add(threshold);
|
|
|
|
// Call the registered callback if exists
|
|
if (timeThresholdCallbacks[threshold]) {
|
|
timeThresholdCallbacks[threshold](threshold);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Start the timer
|
|
*/
|
|
function startTimer() {
|
|
if (isTimerRunning) return;
|
|
isTimerRunning = true;
|
|
|
|
let remainingSeconds = timerDuration * 60;
|
|
|
|
timerInterval = setInterval(() => {
|
|
remainingSeconds--;
|
|
|
|
if (remainingSeconds <= 0) {
|
|
stopTimer();
|
|
updateTimerDisplay(0);
|
|
|
|
if (onTimerEndCallback) {
|
|
onTimerEndCallback();
|
|
}
|
|
return;
|
|
}
|
|
|
|
const minutes = Math.floor(remainingSeconds / 60);
|
|
const seconds = remainingSeconds % 60;
|
|
|
|
// Check if we've hit any time thresholds
|
|
checkTimeThresholds(minutes, seconds);
|
|
|
|
updateTimerDisplay(minutes, seconds);
|
|
}, 1000);
|
|
}
|
|
|
|
/**
|
|
* Stop the timer
|
|
*/
|
|
function stopTimer() {
|
|
if (timerInterval) {
|
|
clearInterval(timerInterval);
|
|
timerInterval = null;
|
|
isTimerRunning = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset the timer
|
|
*/
|
|
function resetTimer() {
|
|
stopTimer();
|
|
timerDuration = 120; // Reset to default
|
|
processedThresholds.clear();
|
|
if (timerElement) {
|
|
updateTimerDisplay(timerDuration);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update the timer display
|
|
* @param {number} minutes - Minutes remaining
|
|
* @param {number} seconds - Seconds remaining
|
|
*/
|
|
function updateTimerDisplay(minutes, seconds = 0) {
|
|
if (!timerElement) return;
|
|
|
|
const formattedMinutes = String(minutes).padStart(2, '0');
|
|
const formattedSeconds = String(seconds).padStart(2, '0');
|
|
|
|
timerElement.textContent = `${formattedMinutes}:${formattedSeconds}`;
|
|
|
|
// Add visual warning when less than 5 minutes remaining
|
|
if (minutes < 5) {
|
|
timerElement.classList.add('timer-warning');
|
|
} else {
|
|
timerElement.classList.remove('timer-warning');
|
|
}
|
|
}
|
|
|
|
// Export the timer service
|
|
export {
|
|
setTimerDuration,
|
|
getRemainingTime,
|
|
calculateRemainingTime,
|
|
initTimer,
|
|
startTimer,
|
|
stopTimer,
|
|
resetTimer,
|
|
registerTimeThresholdCallbacks
|
|
};
|