Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions driving_log/templates/dashboard.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{% extends "base.html" %}
{% block content %}
{% set rounded_percent = (totals.total_minutes / 36 + 0.5) | int %}
{% if totals.total_minutes < 3600 %}
{% set total_remaining = [0, 3600 - totals.total_minutes] | max %}
{% set night_remaining = [0, 600 - totals.night_minutes] | max %}
{% set required_remaining = [total_remaining, night_remaining] | max %}
{% set rounded_percent = ((3600 - required_remaining) / 36 + 0.5) | int %}
{% if required_remaining > 0 %}
{% set total_percent = [99, rounded_percent] | min %}
{% else %}
{% set total_percent = rounded_percent %}
Expand All @@ -26,14 +29,14 @@ <h1>Student progress</h1>
class="progress-visual"
style="--total-progress: {{ [100, totals.total_minutes / 36] | min }}; --night-progress: {{ [100, totals.night_minutes / 6] | min }}"
>
<svg viewBox="0 0 240 140" role="img" aria-label="{{ total_percent }} percent of required driving completed">
<svg viewBox="0 0 240 140" role="img" aria-label="{{ total_percent }} percent of driving requirements completed">
<path fill="none" class="progress-track progress-track-total" pathLength="100" d="M 20 120 A 100 100 0 0 1 220 120"></path>
<path fill="none" class="progress-arc progress-arc-total" pathLength="100" d="M 20 120 A 100 100 0 0 1 220 120"></path>
<path fill="none" class="progress-track progress-track-night" pathLength="100" d="M 48 120 A 72 72 0 0 1 192 120"></path>
<path fill="none" class="progress-arc progress-arc-night" pathLength="100" d="M 48 120 A 72 72 0 0 1 192 120"></path>
<g class="progress-label" aria-hidden="true">
<text class="progress-percent-value" x="120" y="112" text-anchor="middle" textLength="72" lengthAdjust="spacingAndGlyphs">{{ total_percent }}%</text>
<text class="progress-percent-caption" x="120" y="135" text-anchor="middle" textLength="72" lengthAdjust="spacingAndGlyphs">COMPLETE</text>
<text class="progress-percent-caption" x="120" y="135" text-anchor="middle" textLength="72" lengthAdjust="spacingAndGlyphs">{{ "REQUIREMENTS MET" if required_remaining == 0 else "TO COMPLETE" }}</text>
</g>
</svg>
</div>
Expand Down
40 changes: 20 additions & 20 deletions tests/test_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ async def scenario() -> None:
self.assertNotIn("0h 0m day", listing.text)
dashboard = await client.get("/")
self.assertIn(
'aria-label="2 percent of required driving completed"', dashboard.text
'aria-label="2 percent of driving requirements completed"', dashboard.text
)
self.assertIn(">2%</text>", dashboard.text)
self.assertNotIn("1.7%", dashboard.text)
Expand Down Expand Up @@ -1151,7 +1151,7 @@ async def scenario() -> None:

self.run_async(scenario)

def test_dashboard_progress_rounds_half_up_without_early_completion(self) -> None:
def test_dashboard_progress_accounts_for_total_and_night_requirements(self) -> None:
async def scenario() -> None:
async with (
self.app.router.lifespan_context(self.app),
Expand All @@ -1178,15 +1178,15 @@ async def add_drive(day: int, duration_minutes: int) -> None:
)
self.assertEqual(response.status_code, 303)

async def add_night_drive(day: int) -> None:
async def add_night_drive(day: int, duration_hours: float) -> None:
start = datetime(2026, 7, day, 22, tzinfo=ZoneInfo(DEFAULT_TIMEZONE))
response = await client.post(
"/drives",
data={
"request_id": str(uuid.uuid4()),
"driver_name": "Daniel Ahern",
"started_at_local": start.strftime("%Y-%m-%dT%H:%M"),
"ended_at_local": (start + timedelta(hours=8)).strftime(
"ended_at_local": (start + timedelta(hours=duration_hours)).strftime(
"%Y-%m-%dT%H:%M"
),
"road_type": "local",
Expand All @@ -1197,43 +1197,43 @@ async def add_night_drive(day: int) -> None:
await add_drive(1, 18)
dashboard = await client.get("/")
self.assertIn(
'aria-label="1 percent of required driving completed"', dashboard.text
'aria-label="1 percent of driving requirements completed"', dashboard.text
)
self.assertIn(">1%</text>", dashboard.text)

await add_drive(2, 72)
dashboard = await client.get("/")
self.assertIn(
'aria-label="3 percent of required driving completed"', dashboard.text
'aria-label="3 percent of driving requirements completed"', dashboard.text
)
self.assertIn(">3%</text>", dashboard.text)

for day in range(3, 13):
for day in range(3, 12):
await add_drive(day, 300)
await add_drive(13, 300)
await add_drive(14, 209)
await add_drive(12, 90)
await add_night_drive(13, 6.5)
dashboard = await client.get("/")
self.assertIn(
'aria-label="99 percent of required driving completed"', dashboard.text
'aria-label="91 percent of driving requirements completed"', dashboard.text
)
self.assertIn(">99%</text>", dashboard.text)
self.assertIn(">91%</text>", dashboard.text)
self.assertIn(">TO COMPLETE</text>", dashboard.text)

await add_drive(15, 1)
await add_drive(14, 330)
dashboard = await client.get("/")
self.assertIn(
'aria-label="100 percent of required driving completed"', dashboard.text
'aria-label="94 percent of driving requirements completed"', dashboard.text
)
self.assertIn(">100%</text>", dashboard.text)
self.assertIn(">94%</text>", dashboard.text)

await add_drive(16, 288)
await add_night_drive(20)
await add_night_drive(22)
await add_night_drive(24)
await add_night_drive(16, 3.5)
await add_drive(18, 288)
dashboard = await client.get("/")
self.assertIn(
'aria-label="148 percent of required driving completed"', dashboard.text
'aria-label="100 percent of driving requirements completed"', dashboard.text
)
self.assertIn(">148%</text>", dashboard.text)
self.assertIn(">100%</text>", dashboard.text)
self.assertIn(">REQUIREMENTS MET</text>", dashboard.text)
self.assertIn(
"<span>Total driving</span>\n <span>Remaining: 0h 00m</span>",
dashboard.text,
Expand Down
Loading