feat: let a day already gone be ticked
People play at midnight and tick at breakfast, or forget for a week and come back. A log that only accepts today goes wrong on its first bad evening and is never trusted again. An event whose end was published already allowed this — its checklist draws the whole run and past pips are clickable. `catchUpDays` answers the two cases `dailyDays` cannot: a standing chore, which has no start or end because it is a routine rather than an event, and an event with `endsAt: null`, where the checklist could draw no run at all and so offered only today. That second one is the worse of the two, because it looks like a working checklist. Never a day past today. A tick claims you did it, and nobody can have done tomorrow, so a future day is absent rather than rendered and disabled — a control for a claim that cannot be true. An event's strip starts when the event did, capped at the same fortnight so a login campaign that opened in March does not become a wall of pips. The window bounds display and never data: a tick older than it stays logged and keeps counting toward the streak. `DayPip` moves to its own module rather than being copied, so there is one answer to what a missed day looks like. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
88d5ea2e43
commit
bf7959c916
4 files changed
+225
-55
No files matched your search
@@ -161,6 +161,59 @@ export function dailyDays(
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* How far back a catch-up strip reaches.
|
||||
*
|
||||
* A fortnight: long enough to repair a holiday or a bad week, short enough that
|
||||
* it is still recording what you did rather than reconstructing a month from
|
||||
* memory. It bounds *display* only — see `catchUpDays`.
|
||||
*/
|
||||
export const CATCH_UP_DAYS = 14;
|
||||
|
||||
/**
|
||||
* The days a reader can still say they did, oldest first.
|
||||
*
|
||||
* `dailyDays` answers this for an event whose end was announced, because there
|
||||
* the whole run is known. Two things it cannot answer: a game's standing chore,
|
||||
* which has no start and no end because it is a routine rather than an event,
|
||||
* and an event with `endsAt: null`, where `dailyDays` returns null and the
|
||||
* checklist has nothing to draw. Both leave the reader with today and no way to
|
||||
* record yesterday, which is the day they actually did and forgot to tick.
|
||||
*
|
||||
* `notBefore` is an instant to clip at — an event's start — or null when there
|
||||
* is nothing to clip at, which is the chore case. Never returns a day past
|
||||
* today: a tick is a claim you did it, and tomorrow is not something anyone can
|
||||
* have done, so it is absent rather than present-and-disabled.
|
||||
*
|
||||
* **This bounds what is shown and never what is stored.** A tick older than the
|
||||
* window stays in the log, keeps counting toward `streakOf` and toward
|
||||
* `dailySummary`'s totals, and is simply off-screen — nothing here removes a day
|
||||
* the reader did not remove themselves.
|
||||
*/
|
||||
export function catchUpDays(
|
||||
now: number,
|
||||
region: Region,
|
||||
game: LaneId | undefined,
|
||||
notBefore: number | null,
|
||||
span = CATCH_UP_DAYS,
|
||||
): string[] {
|
||||
const today = dayKey(now, region, game);
|
||||
const floor = notBefore === null ? null : dayKey(notBefore, region, game);
|
||||
|
||||
const out: string[] = [];
|
||||
// Walked in day-key space rather than in instants, like `streakOf`: these are
|
||||
// keys cut on a game's reset clock, and stepping a calendar day back is the
|
||||
// only operation that keeps them lined up with what was written.
|
||||
let cursor = Date.parse(`${today}T00:00:00Z`);
|
||||
while (out.length < span) {
|
||||
const key = keyOf(cursor);
|
||||
if (floor !== null && key < floor) break;
|
||||
out.push(key);
|
||||
cursor -= DAY;
|
||||
}
|
||||
return out.reverse();
|
||||
}
|
||||
|
||||
export interface DailySummary {
|
||||
/** Every claimable day, oldest first. Null when the end is unannounced. */
|
||||
days: string[] | null;
|
||||
|
||||
Reference in new issue
Block a user