Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 55 additions & 40 deletions src/components/Timer/Timer.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
/* eslint-disable jsx-a11y/media-has-caption */
import cs from 'classnames';
import moment from 'moment';
import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody, ModalFooter, Button, Progress } from 'reactstrap';
import useWebSocket, { ReadyState } from 'react-use-websocket';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { BsAlarmFill, BsArrowClockwise } from 'react-icons/bs';
import {
FaPlusCircle,
FaMinusCircle,
FaPlayCircle,
FaPauseCircle,
FaPlayCircle,
FaPlusCircle,
FaStopCircle,
FaUndoAlt,
} from 'react-icons/fa';
import { toast } from 'react-toastify';
import cs from 'classnames';
import { connect, useDispatch } from 'react-redux';
import css from './Timer.module.css';
import '../Header/index.css';
import { toast } from 'react-toastify';
import useWebSocket, { ReadyState } from 'react-use-websocket';
import { Button, Modal, ModalBody, ModalFooter, ModalHeader, Progress } from 'reactstrap';
import { ENDPOINTS } from '~/utils/URL';
import config from '../../config.json';
import '../Header/index.css';
import TimeEntryForm from '../Timelog/TimeEntryForm';
import Countdown from './Countdown';
import TimerStatus from './TimerStatus';
import css from './Timer.module.css';
import TimerPopout from './TimerPopout';
import { postTimeEntry, editTimeEntry } from '../../actions/timeEntries';
import TimerStatus from './TimerStatus';

function Timer({ authUser, darkMode, isPopout }) {
const dispatch = useDispatch();
Expand Down Expand Up @@ -118,6 +117,7 @@
const isWSOpenRef = useRef(0);
const timeIsOverAudioRef = useRef(null);
const forcedPausedAudioRef = useRef(null);
const audioUnlockedRef = useRef(false);

const timeToLog = moment.duration(goal - remaining);
const logHours = timeToLog.hours();
Expand All @@ -127,7 +127,6 @@

// Enhanced function to clear submitted time with better logging
const clearSubmittedTime = useCallback(() => {
console.log(' Clearing submitted time - Timer reset or user change detected');
setLastSubmittedTime(null);
setLogTimer({ hours: 0, minutes: 0 });
setTimerState('idle');
Expand All @@ -147,8 +146,6 @@
remaining,
};

console.log('✅ Time submitted successfully:', submissionRecord);

setLastSubmittedTime(timeKey);
setSubmissionHistory(prev => [...prev, submissionRecord]);
setLogTimer({ hours: 0, minutes: 0 });
Expand All @@ -159,8 +156,9 @@
const existingHistory = JSON.parse(localStorage.getItem('timerSubmissionHistory') || '[]');
const updatedHistory = [...existingHistory, submissionRecord].slice(-10); // Keep last 10 entries
localStorage.setItem('timerSubmissionHistory', JSON.stringify(updatedHistory));
} catch (error) {
console.warn('Could not save submission history to localStorage:', error);
} catch (_error) {
// localStorage unavailable - non-critical, safe to ignore
void _error;

Check failure on line 161 in src/components/Timer/Timer.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this use of the "void" operator.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ4zVwHaGVej_5Gp8DSK&open=AZ4zVwHaGVej_5Gp8DSK&pullRequest=5279
}
},
[goal, remaining, sessionId, viewingUserId, authUser?.userid],
Expand Down Expand Up @@ -221,7 +219,6 @@
// Enhanced function to handle timer state changes
const updateTimerState = useCallback(
newState => {
console.log(`🔄 Timer state changed: ${timerState} → ${newState}`);
setTimerState(newState);
},
[timerState],
Expand Down Expand Up @@ -252,7 +249,6 @@
}
const newSessionId = `session_${Date.now()}_${randomPart}`;
setSessionId(newSessionId);
console.log('🚀 Timer session initialized:', newSessionId);
}, []);

// Enhanced useEffect for timer state management
Expand All @@ -266,6 +262,29 @@
}
}, [running, paused, started, updateTimerState]);

const pauseAudioRef = ref => {
if (!ref.current) return;
ref.current.pause();
ref.current.currentTime = 0;
};

useEffect(() => {
const unlockAudio = () => {
if (audioUnlockedRef.current) return;
if (timeIsOverAudioRef.current) {
timeIsOverAudioRef.current.play().catch(() => {});
pauseAudioRef(timeIsOverAudioRef);
}
if (forcedPausedAudioRef.current) {
forcedPausedAudioRef.current.play().catch(() => {});
pauseAudioRef(forcedPausedAudioRef);
}
audioUnlockedRef.current = true;
};
document.addEventListener('click', unlockAudio, { once: true });
return () => document.removeEventListener('click', unlockAudio);
}, []);

useEffect(() => {
const handleStorageEvent = () => {
const sessionStorageData = JSON.parse(window.sessionStorage.getItem('viewingUser'));
Expand Down Expand Up @@ -474,7 +493,6 @@
return;
}

console.log('🛑 Stop button clicked - preparing to log time:', timeToSubmit);
toggleLogTimeModal();
}, [logHours, logMinutes, validateTimeForSubmission, toggleLogTimeModal]);

Expand Down Expand Up @@ -567,22 +585,14 @@
}, [running]);

useEffect(() => {
/**
* This useEffect will run upon message change,
* and message is a state as a copy of the lastJsonMessage,
* here message works as a buffer, for details see above
*/
let interval;
if (running) {
updateRemaining();
interval = setInterval(() => {
updateRemaining();
}, 1000);
} else {
if (!running) {
setRemaining(time);
clearInterval(interval);
return undefined;
}

updateRemaining();
const interval = setInterval(() => {
updateRemaining();
}, 1000);
return () => clearInterval(interval);
}, [running, message]);

Expand All @@ -597,7 +607,6 @@
if (lastSubmittedTime !== timeKey && (logHours > 0 || logMinutes > 0)) {
if (validateTimeForSubmission(currentTimeToLog)) {
setLogTimer(currentTimeToLog);
console.log('⏱️ Time to log updated:', currentTimeToLog);
}
}
}, [remaining, logHours, logMinutes, goal, lastSubmittedTime, validateTimeForSubmission]);
Expand All @@ -606,14 +615,16 @@
useEffect(() => {
if (!started || goal !== lastSubmittedTime?.goal) {
clearSubmittedTime();
console.log('🔄 Timer reset detected - clearing submitted time');
}
}, [started, goal, clearSubmittedTime]);

useEffect(() => {
if (timeIsOverModalOpen) {
window.focus();
timeIsOverAudioRef.current.play();
const playPromise = timeIsOverAudioRef.current.play();
if (playPromise !== undefined) {
playPromise.catch(() => {});
}
} else {
window.focus();
timeIsOverAudioRef.current.pause();
Expand All @@ -631,7 +642,10 @@
useEffect(() => {
if (inacModal) {
window.focus();
forcedPausedAudioRef.current.play();
const playPromise = forcedPausedAudioRef.current.play();
if (playPromise !== undefined) {
playPromise.catch(() => {});
}
} else {
window.focus();
forcedPausedAudioRef.current.pause();
Expand All @@ -642,7 +656,10 @@
useEffect(() => {
if (weekEndModal) {
window.focus();
timeIsOverAudioRef.current.play();
const playPromise = timeIsOverAudioRef.current.play();
if (playPromise !== undefined) {
playPromise.catch(() => {});
}
} else {
window.focus();
timeIsOverAudioRef.current.pause();
Expand All @@ -659,14 +676,12 @@
// Enhanced cleanup when viewing user changes
useEffect(() => {
clearSubmittedTime();
console.log('👤 User changed - clearing timer state');
}, [viewingUserId, clearSubmittedTime]);

// Enhanced cleanup on component unmount
useEffect(() => {
return () => {
clearSubmittedTime();
console.log('🔚 Timer component unmounting - cleanup complete');
};
}, [clearSubmittedTime]);

Expand Down
Loading