fix: stop the running-now header counting down to "ended"

The section header said "next after this ends in {live[1]}", which got the
question wrong in both of the ways lens.ts exists to prevent.

An event whose end was never announced has no time remaining, and the `?? 0`
that stood in for it made `formatRemaining` return its expiry string — so a
second row with `endsAt: null` had the header reading "next after this ends in
ended". That is the one rule this product is built on, inverted: an unknown end
announced as an expiry.

And `live[1]` is the second *row*, not the second deadline. The list is sorted
by whatever mode the reader picked, so under "doing first" the header named
whatever they were second-most partway through — the same mistake firstToExpire
was written to keep out of the headline, one row further down.

`followingDeadlineMs` asks the deadlines instead and returns null when there is
no second dated end, and the header then says nothing at all.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Lucas Winther
2026-08-20 06:12:38 +02:00
co-authored by Claude Opus 5
parent 447ea25632
commit 4fe563dcbb
3 changed files with 73 additions and 5 deletions
+13 -5
View File
@@ -24,6 +24,7 @@ import { compareRows, SORT_MODES, type Activity, type SortMode } from "./state/s
import {
advanceFocus,
countByGame,
followingDeadlineMs,
nextToExpire,
outstanding,
resolveFocus,
@@ -300,6 +301,15 @@ export function App() {
const live = visible.filter((r) => r.clock.live);
const upcoming = visible.filter((r) => r.clock.upcoming);
/**
* What falls due after the row at the top of "Running now".
*
* Read off the deadlines rather than off the list, because the list is in
* whichever order the reader chose — see `followingDeadlineMs`. Null when
* there is no second dated end, and the header then says nothing rather than
* counting down to a placeholder.
*/
const following = followingDeadlineMs(live);
/**
* The unstarted events the checklist actually lists.
*
@@ -512,11 +522,9 @@ export function App() {
legend
title="Running now"
hint={
live.length > 1
? `next after this ends in ${formatRemaining(
live[1]?.clock.msRemaining ?? 0,
)}`
: undefined
following === null
? undefined
: `next after this ends in ${formatRemaining(following)}`
}
action={
visible.length > 1 ? (