Add time-based day progress bar to dashboards

Replaces block-count progress with a wall-clock progress bar driven by
configurable day start/end hours on each schedule template.

- ScheduleTemplate: add day_start_time / day_end_time (TIME, nullable)
- Startup migration: idempotent ALTER TABLE for existing DBs
- Dashboard snapshot: includes day_start_time / day_end_time from template
- Admin → Schedules: time pickers in block editor to set day hours
- Dashboard view: time-based progress bar with start/current/end labels
- TV view: full-width day progress strip between header and main content

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 10:08:07 -08:00
parent 462205cdc1
commit 3e7ff2a50b
10 changed files with 213 additions and 38 deletions

View File

@@ -11,7 +11,7 @@ from sqlalchemy.orm import selectinload
from app.dependencies import get_db
from app.models.child import Child
from app.models.schedule import ScheduleBlock
from app.models.schedule import ScheduleBlock, ScheduleTemplate
from app.models.session import DailySession, TimerEvent
from app.schemas.session import DashboardSnapshot
@@ -41,6 +41,8 @@ async def get_dashboard(child_id: int, db: AsyncSession = Depends(get_db)):
blocks = []
completed_ids = []
block_elapsed_seconds = 0
day_start_time = None
day_end_time = None
if session and session.template_id:
blocks_result = await db.execute(
@@ -50,6 +52,14 @@ async def get_dashboard(child_id: int, db: AsyncSession = Depends(get_db)):
)
blocks = blocks_result.scalars().all()
template_result = await db.execute(
select(ScheduleTemplate).where(ScheduleTemplate.id == session.template_id)
)
template = template_result.scalar_one_or_none()
if template:
day_start_time = template.day_start_time
day_end_time = template.day_end_time
events_result = await db.execute(
select(TimerEvent).where(
TimerEvent.session_id == session.id,
@@ -88,4 +98,6 @@ async def get_dashboard(child_id: int, db: AsyncSession = Depends(get_db)):
blocks=blocks,
completed_block_ids=completed_ids,
block_elapsed_seconds=block_elapsed_seconds,
day_start_time=day_start_time,
day_end_time=day_end_time,
)