Fix timer reset on refresh and sync between dashboard and TV view

- Backend computes block_elapsed_seconds server-side from timer_events
- Store tracks blockStartedAt (ms) + blockElapsedOffset (seconds) instead
  of a client-side counter; updated correctly on start/pause/resume/end
- TimerDisplay derives elapsed from store props so both views always agree
- Add compact timer display to dashboard session card
- Add isPaused/pause-resume logic to dashboard Pause/Resume buttons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 00:16:29 -08:00
parent 3f9d599998
commit d43791f965
6 changed files with 129 additions and 18 deletions

View File

@@ -7,6 +7,9 @@ export const useScheduleStore = defineStore('schedule', () => {
const blocks = ref([])
const completedBlockIds = ref([])
const child = ref(null)
const isPaused = ref(false)
const blockStartedAt = ref(null) // Date.now() ms when current counting period started
const blockElapsedOffset = ref(0) // seconds already elapsed before blockStartedAt
const currentBlock = computed(() =>
session.value?.current_block_id
@@ -23,7 +26,17 @@ export const useScheduleStore = defineStore('schedule', () => {
session.value = snapshot.session
blocks.value = snapshot.blocks || []
completedBlockIds.value = snapshot.completed_block_ids || []
isPaused.value = false
if (snapshot.child) child.value = snapshot.child
// Restore elapsed time from server-computed value
const serverElapsed = snapshot.block_elapsed_seconds || 0
if (snapshot.session?.current_block_id && serverElapsed > 0) {
blockElapsedOffset.value = serverElapsed
blockStartedAt.value = Date.now()
} else {
blockElapsedOffset.value = 0
blockStartedAt.value = null
}
}
function applyWsEvent(event) {
@@ -34,8 +47,30 @@ export const useScheduleStore = defineStore('schedule', () => {
// Session ended
if (event.is_active === false) {
session.value = null
isPaused.value = false
blockStartedAt.value = null
blockElapsedOffset.value = 0
return
}
// Pause — accumulate elapsed, stop counting
if (event.event === 'pause') {
if (blockStartedAt.value) {
blockElapsedOffset.value += Math.floor((Date.now() - blockStartedAt.value) / 1000)
}
blockStartedAt.value = null
isPaused.value = true
}
// Start (new block) — reset elapsed, begin counting
if (event.event === 'start') {
blockElapsedOffset.value = 0
blockStartedAt.value = Date.now()
isPaused.value = false
}
// Resume — continue from where we left off
if (event.event === 'resume') {
blockStartedAt.value = Date.now()
isPaused.value = false
}
// Timer events update session state
if (event.current_block_id !== undefined && session.value) {
session.value.current_block_id = event.current_block_id
@@ -73,6 +108,9 @@ export const useScheduleStore = defineStore('schedule', () => {
blocks,
completedBlockIds,
child,
isPaused,
blockStartedAt,
blockElapsedOffset,
currentBlock,
progressPercent,
applySnapshot,