95f2b1d4a1
Introduces a `useTimer` hook to manage starting and stopping timers for tasks, updating their `timeTracked` property, and displaying tracking status. This involves changes in `App.tsx`, `KanbanBoard.tsx`, `TaskCard.tsx`, and `TasksWithCalendar.tsx` to integrate the timer start/stop actions and display. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/P2PZNJ9
113 lines
3.7 KiB
TypeScript
113 lines
3.7 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { Task } from '@shared/schema';
|
|
|
|
interface UseTimerProps {
|
|
tasks: Task[];
|
|
onTaskUpdate: (taskId: string, updates: Partial<Task>) => void;
|
|
}
|
|
|
|
export function useTimer({ tasks, onTaskUpdate }: UseTimerProps) {
|
|
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
|
const lastUpdateRef = useRef<{ [taskId: string]: number }>({});
|
|
|
|
useEffect(() => {
|
|
// Find tasks that are currently being tracked
|
|
const trackingTasks = tasks.filter(task => task.isTracking);
|
|
|
|
if (trackingTasks.length > 0) {
|
|
// Start the timer
|
|
intervalRef.current = setInterval(() => {
|
|
const now = Date.now();
|
|
|
|
trackingTasks.forEach(task => {
|
|
// Initialize last update time if not set
|
|
if (!lastUpdateRef.current[task.id]) {
|
|
lastUpdateRef.current[task.id] = now;
|
|
return;
|
|
}
|
|
|
|
// Calculate elapsed time since last update (in minutes)
|
|
const elapsed = (now - lastUpdateRef.current[task.id]) / 1000 / 60;
|
|
|
|
// Only update if at least 1 minute has passed (to avoid too frequent updates)
|
|
if (elapsed >= 1) {
|
|
const currentTime = task.timeTracked || 0;
|
|
const newTime = currentTime + Math.floor(elapsed);
|
|
|
|
onTaskUpdate(task.id, { timeTracked: newTime });
|
|
lastUpdateRef.current[task.id] = now;
|
|
|
|
console.log(`Timer updated for "${task.title}": +${Math.floor(elapsed)}min (total: ${newTime}min)`);
|
|
}
|
|
});
|
|
}, 60000); // Update every minute
|
|
} else {
|
|
// No tasks are being tracked, clear the timer
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
// Clear last update times for stopped tasks
|
|
lastUpdateRef.current = {};
|
|
}
|
|
|
|
// Cleanup on unmount or when tracking tasks change
|
|
return () => {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
};
|
|
}, [tasks.map(t => `${t.id}:${t.isTracking}`).join(','), onTaskUpdate]);
|
|
|
|
// Initialize last update times for currently tracking tasks
|
|
useEffect(() => {
|
|
const now = Date.now();
|
|
tasks.forEach(task => {
|
|
if (task.isTracking && !lastUpdateRef.current[task.id]) {
|
|
lastUpdateRef.current[task.id] = now;
|
|
} else if (!task.isTracking && lastUpdateRef.current[task.id]) {
|
|
delete lastUpdateRef.current[task.id];
|
|
}
|
|
});
|
|
}, [tasks]);
|
|
|
|
const startTimer = (taskId: string) => {
|
|
const now = Date.now();
|
|
lastUpdateRef.current[taskId] = now;
|
|
onTaskUpdate(taskId, { isTracking: true });
|
|
console.log(`Timer started for task: ${taskId}`);
|
|
};
|
|
|
|
const stopTimer = (taskId: string) => {
|
|
const task = tasks.find(t => t.id === taskId);
|
|
if (task && lastUpdateRef.current[taskId]) {
|
|
const now = Date.now();
|
|
const elapsed = (now - lastUpdateRef.current[taskId]) / 1000 / 60;
|
|
|
|
if (elapsed >= 0.1) { // Add time if at least 6 seconds have passed
|
|
const currentTime = task.timeTracked || 0;
|
|
const additionalTime = Math.max(1, Math.round(elapsed)); // At least 1 minute
|
|
const newTime = currentTime + additionalTime;
|
|
|
|
onTaskUpdate(taskId, {
|
|
isTracking: false,
|
|
timeTracked: newTime
|
|
});
|
|
|
|
console.log(`Timer stopped for "${task.title}": +${additionalTime}min (total: ${newTime}min)`);
|
|
} else {
|
|
onTaskUpdate(taskId, { isTracking: false });
|
|
}
|
|
|
|
delete lastUpdateRef.current[taskId];
|
|
} else {
|
|
onTaskUpdate(taskId, { isTracking: false });
|
|
}
|
|
};
|
|
|
|
return {
|
|
startTimer,
|
|
stopTimer
|
|
};
|
|
} |