This commit is contained in:
2026-01-10 09:22:28 +07:00
parent 5c452c5c74
commit cf0df928b1

View File

@@ -75,24 +75,26 @@ export function DashboardPage() {
// Check if we should track time: any tracked game is running + active assignment exists
const isTrackingAssignment = !!(currentGame && currentAssignment && currentAssignment.status === 'active')
// Sync time to server
// Track base minutes at session start to avoid re-adding on each sync
const baseMinutesRef = useRef<number>(0)
// Sync time to server - use refs to avoid dependency issues
const doSyncTime = useCallback(async () => {
if (!currentAssignment || !isTrackingAssignment) {
const assignment = useMarathonStore.getState().currentAssignment
if (!assignment || assignment.status !== 'active' || !sessionStartRef.current) {
return
}
// Calculate total minutes: previous tracked + current session
const sessionDuration = sessionStartRef.current
? Math.floor((Date.now() - sessionStartRef.current) / 60000)
: 0
const totalMinutes = currentAssignment.tracked_time_minutes + sessionDuration
// Calculate session duration only
const sessionMinutes = Math.floor((Date.now() - sessionStartRef.current) / 60000)
const totalMinutes = baseMinutesRef.current + sessionMinutes
if (totalMinutes !== lastSyncedMinutesRef.current && totalMinutes > 0) {
console.log(`[Sync] Syncing ${totalMinutes} minutes for assignment ${currentAssignment.id}`)
console.log(`[Sync] Syncing ${totalMinutes} minutes for assignment ${assignment.id} (base: ${baseMinutesRef.current}, session: ${sessionMinutes})`)
await syncTime(totalMinutes)
lastSyncedMinutesRef.current = totalMinutes
}
}, [currentAssignment, isTrackingAssignment, syncTime])
}, [syncTime])
useEffect(() => {
loadTrackedGames()
@@ -134,16 +136,17 @@ export function DashboardPage() {
useEffect(() => {
let localTimerInterval: NodeJS.Timeout | null = null
if (isTrackingAssignment) {
if (isTrackingAssignment && currentAssignment) {
// Start session if not already started
if (!sessionStartRef.current) {
sessionStartRef.current = Date.now()
// Store base minutes at session start
baseMinutesRef.current = currentAssignment.tracked_time_minutes || 0
lastSyncedMinutesRef.current = baseMinutesRef.current
console.log(`[Sync] Session started, base minutes: ${baseMinutesRef.current}`)
}
// Sync immediately when game starts
doSyncTime()
// Setup periodic sync every 60 seconds
// Setup periodic sync every 60 seconds (don't sync immediately to avoid loops)
syncIntervalRef.current = setInterval(() => {
doSyncTime()
}, 60000)
@@ -157,12 +160,15 @@ export function DashboardPage() {
} else {
// Do final sync when game stops
if (syncIntervalRef.current) {
if (sessionStartRef.current) {
doSyncTime()
}
if (syncIntervalRef.current) {
clearInterval(syncIntervalRef.current)
syncIntervalRef.current = null
sessionStartRef.current = null
}
sessionStartRef.current = null
baseMinutesRef.current = 0
setLocalSessionSeconds(0)
}
@@ -175,7 +181,9 @@ export function DashboardPage() {
clearInterval(localTimerInterval)
}
}
}, [isTrackingAssignment, doSyncTime])
// Note: doSyncTime is intentionally excluded to avoid infinite loops
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isTrackingAssignment])
// Toggle monitoring
const toggleMonitoring = async () => {
@@ -222,9 +230,11 @@ export function DashboardPage() {
// Playthrough assignment
if (assignment.is_playthrough && assignment.playthrough_info) {
// Use localSessionSeconds for live display (updates every second)
// When actively tracking: use baseMinutesRef (set at session start) + current session
// Otherwise: use tracked_time_minutes from assignment
const baseMinutes = isTrackingAssignment ? baseMinutesRef.current : assignment.tracked_time_minutes
const sessionSeconds = isTrackingAssignment ? localSessionSeconds : 0
const totalSeconds = (assignment.tracked_time_minutes * 60) + sessionSeconds
const totalSeconds = (baseMinutes * 60) + sessionSeconds
const totalMinutes = Math.floor(totalSeconds / 60)
const trackedHours = totalMinutes / 60
const estimatedPoints = Math.floor(trackedHours * 30)