fix: apply game order to dailies and routines

Account creation order leaked into daily rows and routine groups even when the reader had arranged their games. Apply the shared display rule while preserving each game's server and task order.
This commit is contained in:
Lucas Winther committed 2026-11-02 03:35:32 +01:00
1 parent 2056630f67
commit dd5d374422
8 files changed
+74 -8

No files matched your search

+15 -1
View File
@@ -1,8 +1,22 @@
import { describe, expect, test } from "bun:test";
import { moveGame, orderGames } from "../src/client/state/gameOrder.ts";
import { moveGame, orderGames, orderGameItems } from "../src/client/state/gameOrder.ts";
import { metaFor } from "../src/shared/games.ts";
import type { LaneId } from "../src/shared/custom.ts";
test("ordering tasks keeps a game's servers and tasks stable without changing its input", () => {
const items = [
{ game: "hsr", id: "first" },
{ game: "genshin", id: "asia-daily" },
{ game: "hsr", id: "second" },
{ game: "genshin", id: "asia-weekly" },
{ game: "genshin", id: "europe-daily" },
];
const original = items.slice();
expect(orderGameItems(items, ["genshin", "hsr"], (g) => metaFor(g, {}).name).map((r) => r.id))
.toEqual(["asia-daily", "asia-weekly", "europe-daily", "first", "second"]);
expect(items).toEqual(original);
});
/**
* The reader's game order.
*
+20
View File
@@ -7,6 +7,26 @@ import { readerDayKey } from "../src/shared/readerClock.ts";
const at = "2026-10-16T12:00:00.000Z";
const now = Date.parse(at);
test.each([
{ order: ["zzz", "genshin", "hsr"], expected: ["ZZZ", "Genshin", "Star Rail"] },
{ order: undefined, expected: ["Genshin", "Star Rail", "ZZZ"] },
{ order: ["zzz"], expected: ["ZZZ", "Genshin", "Star Rail"] },
])("dailies and progress pips follow game order $order", ({ order, expected }) => {
let id = 0;
const state = migrateLegacy({}, ["hsr", "genshin", "zzz"], at, () => `account:${++id}`);
state.prefs.gameOrder = order;
const rows = Object.values(state.accounts).flatMap((account) =>
routineRows(state, account.id, now).filter((r) => r.id === `dailies:${account.game}`),
);
const html = render(<DailyPanel rows={rows} state={state} now={now} onAction={async () => ({ ok: true })} />);
expect([...html.matchAll(/<strong>(.*?)<\/strong>/g)].map((m) => m[1])).toEqual([...expected]);
const pips = [...html.matchAll(/<i[^>]*style="([^"]*)"/g)].map((m) => m[1]);
const rowHues = [...html.matchAll(/class="daily-row daily-hit"[^>]*style="([^"]*)"/g)].map((m) => m[1]);
expect(pips).toHaveLength(3);
expect(pips).toEqual(rowHues);
});
function setup() {
const state = migrateLegacy({}, ["genshin"], at, () => "account:daily");
state.accounts["account:daily"]!.routines["dailies:genshin"] = {
+11
View File
@@ -45,6 +45,17 @@ test("bulk pins combine changes per account and preserve the other placement", (
});
import { RoutinesPage } from "../src/client/components/redesign/RoutinesPage.tsx";
test.each(["game", "reset"])("routines follow Game order when grouped by %s", (group) => {
const at = "2026-10-16T12:00:00.000Z";
let id = 0;
const state = migrateLegacy({}, ["hsr", "genshin", "zzz"], at, () => `account:${++id}`);
state.prefs.gameOrder = ["zzz", "genshin", "hsr"];
state.prefs.routineGroup = group;
const html = render(<RoutinesPage state={state} now={Date.parse(at)} onAction={async () => ({ ok: true })} />);
const cells = [...html.matchAll(/class="gcell"><span>([^<]*)/g)].map((m) => m[1]);
expect(cells).toEqual(["ZZZ", "Genshin", "Star Rail"]);
});
test("the routines table shows progress as text with an edit affordance, not inputs", () => {
const at = "2026-10-16T12:00:00.000Z";
const state = migrateLegacy({}, ["genshin"], at, () => "account:table");