PageSourceSearch

https://powercoach.ai/assets/utils/capture_progress_rank-9151a59c.js

js powercoach.ai collected 2026-10-05 14:01:32 UTC 3,663 bytes, 86 lines download raw bytes

1// Monotonic ordering for game `progress` tokens, used to decide whether a
2// freshly-served bootstrap payload is AHEAD of the state the capture
3// controller already holds in memory.
4//
5// Why this exists: Turbo keeps the JS context alive across visits, so
6// `window.gameData` survives navigating away from the capture page and back.
7// The bootstrap used to return early whenever `window.gameData` was defined,
8// which meant the fresh server payload was ignored on re-entry and the page
9// could render (and then persist) a period that had already ended. See
10// docs — Trello Y8W2foZE.
11//
12// The comparison has to be DIRECTIONAL. Adopting the server payload whenever
13// it merely differs would be its own bug: if a coach taps "End Quarter" and
14// navigates away before the debounced persist lands, the server is briefly
15// BEHIND the client, and blindly adopting it would revert the quarter end —
16// exactly the symptom we're fixing. So we only ever move forward.
17//
18// Ranking is structural rather than a per-sport sequence table. A single game
19// only ever uses one regulation family (q… for AFL / American football /
20// netball, h… for football / rugby league / flag football), so those share a
21// base and never compete with each other. Extra periods always follow
22// regulation, whichever form they take (et…, gp…, ot, gg).
23
24const PREGAME = new Set(['pregame', 'pre-game']);
25
26// Base offsets keep the families ordered: regulation < extra < shootout < done.
27const REGULATION_BASE = 10;
28const EXTRA_BASE = 100;
29const SHOOTOUT_RANK = 200;
30const COMPLETED_RANK = 300;
31
32const REGULATION_PREFIXES = ['q', 'h'];
33// `ot` (gridiron overtime) and `gg` (netball golden goal) carry no number.
34const EXTRA_PREFIXES = ['et', 'gp', 'ot', 'gg'];
35
36// Two ranks per period so the "-ended" break always sorts immediately after
37// the live period it closes, and before the next period starts.
38function periodRank(base, periodNumber, ended) {
39  return base + periodNumber * 2 + (ended ? 1 : 0);
40}
41
42// Returns a comparable integer, or null for anything we don't recognise.
43// Null is the fail-safe: an unknown token must never be treated as "ahead".
44export function progressRank(progress) {
45  if (typeof progress !== 'string') return null;
46
47  const token = progress.trim().toLowerCase();
48  if (token === '') return null;
49
50  if (PREGAME.has(token)) return 0;
51  if (token === 'completed') return COMPLETED_RANK;
52  if (token === 'penalty_shootout') return SHOOTOUT_RANK;
53
54  const match = token.match(/^([a-z]+)(\d*)(-ended)?$/);
55  if (!match) return null;
56
57  const [, prefix, digits, endedSuffix] = match;
58  const ended = Boolean(endedSuffix);
59
60  if (REGULATION_PREFIXES.includes(prefix)) {
61    // Regulation periods are always numbered ("q2", "h1") — a bare "q" is junk.
62    if (digits === '') return null;
63    return periodRank(REGULATION_BASE, Number(digits), ended);
64  }
65
66  if (EXTRA_PREFIXES.includes(prefix)) {
67    // "ot" / "gg" are single unnumbered periods; treat them as period 1 so they
68    // sort alongside "et1" / "gp1".
69    const periodNumber = digits === '' ? 1 : Number(digits);
70    return periodRank(EXTRA_BASE, periodNumber, ended);
71  }
72
73  return null;
74}
75
76// True only when the server payload represents a strictly later point in the
77// game than what the client holds. Unknown tokens on either side return false
78// so we leave the in-memory state alone rather than guess.
79export function serverStateIsAhead(clientProgress, serverProgress) {
80  const clientRank = progressRank(clientProgress);
81  const serverRank = progressRank(serverProgress);
82
83  if (clientRank === null || serverRank === null) return false;
84
85  return serverRank > clientRank;
86}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.