fix(tasks): keep a task whole through import and edit, and fix two counts
Review found that import and edit rebuilt a task from this build's parse. That stripped any field it didn't know, and import dropped a newer version's task entirely. Both now keep the record as stored and validate only to display it. An event whose goal is points can't be ticked, so it no longer counts as waiting today: it counts with its week. The month-day field reset itself to 1 when emptied; it now keeps a draft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
54d8424d1e
commit
5a4c746a44
7 files changed
+110
-28
No files matched your search
+10
-1
@@ -10,7 +10,7 @@ import {
|
||||
strandedNotice,
|
||||
} from "../src/client/components/CustomForms.tsx";
|
||||
import { eventCaption, YourOwn } from "../src/client/components/YourOwn.tsx";
|
||||
import { TaskForm, taskDraftFrom } from "../src/client/components/TaskForm.tsx";
|
||||
import { parseMonthDay, TaskForm, taskDraftFrom } from "../src/client/components/TaskForm.tsx";
|
||||
import { EventRow } from "../src/client/components/EventRow.tsx";
|
||||
import { EventDetail } from "../src/client/components/EventDetail.tsx";
|
||||
import { AUTHOR, Colophon, REPO_URL, RESET_CLOCK_CREDIT } from "../src/client/components/Colophon.tsx";
|
||||
@@ -1311,3 +1311,12 @@ describe("the reader's weekly and monthly tasks in settings", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("review fixes: the month-day field", () => {
|
||||
test("an emptied field is mid-edit, not day 1", () => {
|
||||
expect(parseMonthDay("")).toBeNull();
|
||||
expect(parseMonthDay("5")).toBe(5);
|
||||
expect(parseMonthDay("40")).toBe(31);
|
||||
expect(parseMonthDay("0")).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { mergeAmounts, readableAmounts } from "../src/client/state/useAmounts.ts";
|
||||
import { mergeTasks, visibleTasks } from "../src/client/state/useTasks.ts";
|
||||
import { editedTask, mergeTasks, visibleTasks } from "../src/client/state/useTasks.ts";
|
||||
|
||||
/**
|
||||
* The two stores weekly and monthly tasks add. Both are the only copy of what
|
||||
@@ -91,3 +91,28 @@ describe("amounts", () => {
|
||||
expect(merged).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe("review fixes: a task's data outlives this build", () => {
|
||||
test("merge keeps fields this build does not know", () => {
|
||||
const withExtra = { ...task(A, "Weekly", "2026-10-05T00:00:00.000Z"), notes: "keep me" };
|
||||
expect(mergeTasks({}, { [A]: withExtra })[A]).toEqual(withExtra);
|
||||
});
|
||||
|
||||
test("a newer version's task in a backup reaches a fresh device", () => {
|
||||
expect(mergeTasks({}, { [FUTURE.id]: FUTURE })[FUTURE.id]).toEqual(FUTURE);
|
||||
});
|
||||
|
||||
test("but junk without a task id or a timestamp still stays out", () => {
|
||||
expect(mergeTasks({}, { x: { id: "myevent:abcdef1234", updatedAt: "2026" } })).toEqual({});
|
||||
expect(mergeTasks({}, { x: { id: "mytask:abcdef1234" } })).toEqual({});
|
||||
});
|
||||
|
||||
test("editing keeps fields this build does not know", () => {
|
||||
const stored = { ...task(A, "Weekly", "2026-10-05T00:00:00.000Z"), notes: "keep me" };
|
||||
const next = editedTask(stored, {
|
||||
game: "zzz", title: "Renamed", period: { unit: "week", startsOn: 1 },
|
||||
measure: { kind: "days", required: 1 },
|
||||
}, "2026-10-06T00:00:00.000Z");
|
||||
expect(next).toMatchObject({ title: "Renamed", notes: "keep me", updatedAt: "2026-10-06T00:00:00.000Z" });
|
||||
});
|
||||
});
|
||||
@@ -1457,3 +1457,27 @@ describe("GoalControl with points", () => {
|
||||
expect(html).toContain("points each week, weeks start");
|
||||
});
|
||||
});
|
||||
|
||||
describe("review fixes: an event's points goal is not a daily", () => {
|
||||
test("it is counted with the week, not as waiting today", () => {
|
||||
const NOW = Date.parse("2026-10-15T12:00:00.000Z");
|
||||
const ev = {
|
||||
id: "p1", game: "zzz", title: "Points event", type: "other", summary: null,
|
||||
startsAt: "2026-10-01T00:00:00.000Z", startPrecision: "day", endsAt: null,
|
||||
endPrecision: "unknown", regionScoped: false, regionEnds: null,
|
||||
sourceUrl: "https://example.test",
|
||||
} as never;
|
||||
const week: GoalStatus = {
|
||||
scope: "week", measure: "amount", periodStart: "2026-10-12", required: 2100, count: 100,
|
||||
met: false, needed: 2000, open: 4, shortfall: false,
|
||||
};
|
||||
const total: GoalStatus = { ...week, scope: "event", periodStart: "2026-10-01" };
|
||||
const tally = (goal: GoalStatus) => {
|
||||
const [group] = dailyGroups(["zzz"], [ev], NOW, "europe", (id) => metaFor(id, {}),
|
||||
(e) => Date.parse(e.startsAt), false, () => goal);
|
||||
return dailyTally(group!.items, () => []);
|
||||
};
|
||||
expect(tally(week)).toMatchObject({ total: 0, week: { total: 1, complete: 0 } });
|
||||
expect(tally(total)).toMatchObject({ total: 0, week: { total: 0 }, month: { total: 0 } });
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user