mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
fix(cycle): reopen a re-tapped start that has nothing after it
The earlier rule could leave a one-day cycle in front of a real start when day two of a period was logged before day one. Tapping "My period started this day" on the real first day folds the later start in, but the re-tapped row kept the end date and length its vanished successor had given it, so the repaired cycle stayed closed after one day. A start with no cycle after it is open, so opening one now clears a stale end and length. The repair of such a history is covered end to end: the broken state is seeded as the old rule left it, the one tap is made through the period route, and the result is a single open cycle that owns every day of the period.
This commit is contained in:
1 parent
e0b547a430
commit
b77dbea6b1
2 files changed
+92
No files matched your search
@@ -183,6 +183,17 @@ export async function openCycleAt(
|
||||
syncVersion: { increment: 1 },
|
||||
},
|
||||
});
|
||||
} else if (cycle.endDate != null || cycle.lengthDays != null) {
|
||||
// With nothing after it the cycle is open. A re-tapped start whose row
|
||||
// still carries an end from a successor that no longer exists (the
|
||||
// one-day cycles an earlier rule left in front of a real start, once
|
||||
// that start is folded in) would otherwise stay closed on a stale date.
|
||||
moved.openedEndDateBefore = cycle.endDate;
|
||||
moved.openedEndDateAfter = null;
|
||||
await db.menstrualCycle.update({
|
||||
where: { id: cycle.id },
|
||||
data: { endDate: null, lengthDays: null, syncVersion: { increment: 1 } },
|
||||
});
|
||||
}
|
||||
|
||||
// The days between this start and the next one belong to this cycle now.
|
||||
|
||||
@@ -371,6 +371,87 @@ describe("a bleeding day opens a cycle", () => {
|
||||
expect(day.cycleId).toBe(may.id);
|
||||
});
|
||||
|
||||
it("repairs a one-day cycle the old rule left, with one tap on the real first day", async () => {
|
||||
// The state the previous rule produced when day two of a period was
|
||||
// logged before day one: a cycle one day long in front of the real one.
|
||||
// Seeded directly, because the current code no longer creates it.
|
||||
const prisma = getPrismaClient();
|
||||
const may = await prisma.menstrualCycle.create({
|
||||
data: {
|
||||
userId: USER_ID,
|
||||
startDate: "2026-05-04",
|
||||
endDate: "2026-05-31",
|
||||
lengthDays: 28,
|
||||
},
|
||||
});
|
||||
const stub = await prisma.menstrualCycle.create({
|
||||
data: {
|
||||
userId: USER_ID,
|
||||
startDate: "2026-06-01",
|
||||
endDate: "2026-06-01",
|
||||
lengthDays: 1,
|
||||
},
|
||||
});
|
||||
const real = await prisma.menstrualCycle.create({
|
||||
data: { userId: USER_ID, startDate: "2026-06-02" },
|
||||
});
|
||||
await prisma.cycleDayLog.createMany({
|
||||
data: [
|
||||
{
|
||||
userId: USER_ID,
|
||||
date: "2026-06-01",
|
||||
flow: "HEAVY",
|
||||
cycleId: stub.id,
|
||||
},
|
||||
{
|
||||
userId: USER_ID,
|
||||
date: "2026-06-02",
|
||||
flow: "MEDIUM",
|
||||
cycleId: real.id,
|
||||
},
|
||||
{
|
||||
userId: USER_ID,
|
||||
date: "2026-06-06",
|
||||
flow: "LIGHT",
|
||||
cycleId: real.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// What the release note tells the person to do.
|
||||
const { POST } = await import("@/app/api/cycle/period/route");
|
||||
const res = await POST(
|
||||
jsonRequest("/api/cycle/period", "POST", {
|
||||
action: "start",
|
||||
date: "2026-06-01",
|
||||
loggedAt: new Date().toISOString(),
|
||||
}),
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
const rows = await prisma.menstrualCycle.findMany({
|
||||
where: { userId: USER_ID, deletedAt: null },
|
||||
orderBy: { startDate: "asc" },
|
||||
select: { id: true, startDate: true, endDate: true, lengthDays: true },
|
||||
});
|
||||
expect(rows.map(({ id: _id, ...r }) => r)).toEqual([
|
||||
{ startDate: "2026-05-04", endDate: "2026-05-31", lengthDays: 28 },
|
||||
{ startDate: "2026-06-01", endDate: null, lengthDays: null },
|
||||
]);
|
||||
expect(rows[0].id).toBe(may.id);
|
||||
const june = rows[1].id;
|
||||
const days = await prisma.cycleDayLog.findMany({
|
||||
where: { userId: USER_ID, deletedAt: null },
|
||||
orderBy: { date: "asc" },
|
||||
select: { date: true, cycleId: true },
|
||||
});
|
||||
expect(days).toEqual([
|
||||
{ date: "2026-06-01", cycleId: june },
|
||||
{ date: "2026-06-02", cycleId: june },
|
||||
{ date: "2026-06-06", cycleId: june },
|
||||
]);
|
||||
});
|
||||
|
||||
it("gives the record a forecast and a cycle day it never had", async () => {
|
||||
// What the person actually sees. Four periods 28 days apart, logged as
|
||||
// flow and nothing else, and today inside the last one.
|
||||
|
||||
Reference in new issue
Block a user