fix(cycle): log past dates as themselves, in any order (#1004)

The log sheet took its "Day N" header and its "period ended" button
from the verdict, which is the answer about today. A January date opened
in September read "Day 2", and a back-dated period could only be closed
on dates where today happened to be a bleeding day, so the button came
and went as unrelated months were filled in.

The calendar read now carries, per date, the cycle day of the logged
cycle that date belongs to (null before the first start, after today, or
past the verdict's ceiling for an open cycle) and whether a one-tap
period end can land there. The sheet reads both off the grid day for the
date it opened on.

Saving a new entry with nothing picked used to write an empty row: the
request succeeded, the sheet closed and the calendar had nothing to
draw, which read as a save that did nothing. Save now needs something to
store and says what, and an emptied existing entry still saves. The
sheet also stops writing until the opened date's own entry has loaded,
because until then it held the previous date's row id and a quick Save
patched the wrong day.

On the server, a start recorded a few days after an earlier one is the
same period entered in the other order: opening the earlier start now
folds the later one into it instead of leaving a one-day cycle in front
of it, and a bleed too far before the next start to be its first day and
too close to be a cycle of its own no longer infers a start. Opening or
removing a start re-attributes the day-logs whose cycle changed.
This commit is contained in:
Marc-André Bombeck committed 2026-09-24 08:02:00 +02:00
1 parent aa58495cbe
commit 7d25bb7352
24 files changed
+877 -33

No files matched your search

+15
View File
@@ -30687,6 +30687,19 @@ components:
isCycleStart:
type: boolean
description: Whether a logged cycle opens on this day. Deleting this day's log removes that cycle start with it.
cycleDay:
anyOf:
- type: integer
minimum: -9007199254740991
maximum: 9007199254740991
- type: "null"
description: The 1-based day of the logged cycle this date belongs to. Null before the first logged start, after today,
or once an open cycle has run past the point where the verdict stops counting. For today it equals
verdict.dayOfCycle.
periodEndable:
type: boolean
description: Whether a one-tap period end (POST /api/cycle/period, action end) on this date lands inside the first days
of a logged cycle. Resolved per date, independent of today's phase.
flow:
anyOf:
- $ref: "#/components/schemas/FlowLevel"
@@ -30738,6 +30751,8 @@ components:
- isPredictedOvulation
- isPeriodLogged
- isCycleStart
- cycleDay
- periodEndable
- flow
- hasSymptoms
- confidence