feat(timer): add useTimerInitialization hook for managing running timers
- Introduced a new custom hook, useTimerInitialization, to fetch and initialize running timers from the backend when the project view loads. - Integrated the hook into the ProjectView component to update Redux state with active timers and their corresponding task details. - Enhanced error handling and logging for timer initialization to improve debugging and user experience.
This commit is contained in:
79
worklenz-frontend/src/hooks/useTimerInitialization.ts
Normal file
79
worklenz-frontend/src/hooks/useTimerInitialization.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useAppDispatch } from '@/hooks/useAppDispatch';
|
||||
import { updateTaskTimeTracking } from '@/features/tasks/tasks.slice';
|
||||
import { updateTask } from '@/features/task-management/task-management.slice';
|
||||
import { taskTimeLogsApiService } from '@/api/tasks/task-time-logs.api.service';
|
||||
import { store } from '@/app/store';
|
||||
import { Task } from '@/types/task-management.types';
|
||||
import logger from '@/utils/errorLogger';
|
||||
import moment from 'moment';
|
||||
|
||||
export const useTimerInitialization = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const hasInitialized = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const initializeTimers = async () => {
|
||||
// Prevent duplicate initialization
|
||||
if (hasInitialized.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
hasInitialized.current = true;
|
||||
|
||||
// Fetch running timers from backend
|
||||
const response = await taskTimeLogsApiService.getRunningTimers();
|
||||
|
||||
if (response && response.done && Array.isArray(response.body)) {
|
||||
const runningTimers = response.body;
|
||||
|
||||
// Update Redux state for each running timer
|
||||
runningTimers.forEach(timer => {
|
||||
if (timer.task_id && timer.start_time) {
|
||||
try {
|
||||
// Convert start_time to timestamp
|
||||
const startTime = moment(timer.start_time);
|
||||
if (startTime.isValid()) {
|
||||
const timestamp = startTime.valueOf();
|
||||
|
||||
// Update the tasks slice activeTimers
|
||||
dispatch(updateTaskTimeTracking({
|
||||
taskId: timer.task_id,
|
||||
timeTracking: timestamp
|
||||
}));
|
||||
|
||||
// Update the task-management slice if the task exists
|
||||
const currentTask = store.getState().taskManagement.entities[timer.task_id];
|
||||
if (currentTask) {
|
||||
const updatedTask: Task = {
|
||||
...currentTask,
|
||||
timeTracking: {
|
||||
...currentTask.timeTracking,
|
||||
activeTimer: timestamp,
|
||||
},
|
||||
updatedAt: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
};
|
||||
dispatch(updateTask(updatedTask));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error initializing timer for task ${timer.task_id}:`, error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (runningTimers.length > 0) {
|
||||
logger.info(`Initialized ${runningTimers.length} running timers from backend`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error initializing timers from backend:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize timers when the hook mounts
|
||||
initializeTimers();
|
||||
}, [dispatch]);
|
||||
};
|
||||
@@ -39,6 +39,7 @@ import { resetState as resetEnhancedKanbanState } from '@/features/enhanced-kanb
|
||||
import { setProjectId as setInsightsProjectId } from '@/features/projects/insights/project-insights.slice';
|
||||
import { SuspenseFallback } from '@/components/suspense-fallback/suspense-fallback';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTimerInitialization } from '@/hooks/useTimerInitialization';
|
||||
|
||||
|
||||
// Import critical components synchronously to avoid suspense interruptions
|
||||
@@ -89,6 +90,9 @@ const ProjectView = React.memo(() => {
|
||||
const [taskid, setTaskId] = useState<string>(urlParams.taskId);
|
||||
const [isInitialized, setIsInitialized] = useState(false);
|
||||
|
||||
// Initialize timer state from backend when project view loads
|
||||
useTimerInitialization();
|
||||
|
||||
// Update local state when URL params change
|
||||
useEffect(() => {
|
||||
setActiveTab(urlParams.tab);
|
||||
|
||||
Reference in New Issue
Block a user