mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
Merge branch 'main' into feat/mood-level-b
This commit is contained in:
commit
b4051e6db3
12 files changed
+73
-57
No files matched your search
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
applyOptimisticSlotMark,
|
||||
slotMarkRequestBody,
|
||||
complianceFromLedger,
|
||||
formatSlotDelta,
|
||||
groupLedgerByDay,
|
||||
@@ -195,3 +196,23 @@ describe("applyOptimisticSlotMark", () => {
|
||||
expect(next.rows[0].status).toBe("taken_late");
|
||||
});
|
||||
});
|
||||
|
||||
describe("slotMarkRequestBody", () => {
|
||||
const row = { at: "2026-08-04T07:00:00.000Z" };
|
||||
|
||||
it("anchors takenAt on the slot instant, not on now", () => {
|
||||
const body = slotMarkRequestBody(row, "taken");
|
||||
expect(body).toEqual({
|
||||
skipped: false,
|
||||
scheduledFor: "2026-08-04T07:00:00.000Z",
|
||||
takenAt: "2026-08-04T07:00:00.000Z",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the skipped arm free of takenAt", () => {
|
||||
expect(slotMarkRequestBody(row, "skipped")).toEqual({
|
||||
skipped: true,
|
||||
scheduledFor: "2026-08-04T07:00:00.000Z",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -204,3 +204,18 @@ export function applyOptimisticSlotMark(
|
||||
});
|
||||
return { ...payload, rows };
|
||||
}
|
||||
|
||||
/**
|
||||
* Request body for marking a ledger slot from the Verlauf. The taken arm
|
||||
* anchors `takenAt` on the slot instant: marking Tuesday 09:00 from a
|
||||
* Thursday evening records a dose taken Tuesday 09:00, which is the claim
|
||||
* the person is making. The optimistic paint above already promised this.
|
||||
*/
|
||||
export function slotMarkRequestBody(
|
||||
row: Pick<LedgerRow, "at">,
|
||||
action: "taken" | "skipped",
|
||||
): Record<string, unknown> {
|
||||
return action === "skipped"
|
||||
? { skipped: true, scheduledFor: row.at }
|
||||
: { skipped: false, scheduledFor: row.at, takenAt: row.at };
|
||||
}
|
||||
@@ -106,6 +106,7 @@ import {
|
||||
formatSlotDelta,
|
||||
groupLedgerByDay,
|
||||
isSlotActionable,
|
||||
slotMarkRequestBody,
|
||||
type LedgerPayload,
|
||||
type LedgerRow,
|
||||
} from "@/components/medications/dose-history-ledger-compute";
|
||||
@@ -273,18 +274,13 @@ export function DoseHistoryLedger({
|
||||
|
||||
try {
|
||||
// Pin the displayed slot so the server marks THAT dose (the canonical
|
||||
// slot upsert), not a now-snap to the nearest one. The POST returns
|
||||
// the created event; its id drives the Undo affordance (the same
|
||||
// soft-delete route the cards use).
|
||||
// slot upsert), not a now-snap to the nearest one — and anchor
|
||||
// `takenAt` on the same instant, matching the optimistic paint. The
|
||||
// POST returns the created event; its id drives the Undo affordance
|
||||
// (the same soft-delete route the cards use).
|
||||
const created = await apiPost<{ id?: string } | undefined>(
|
||||
`/api/medications/${medicationId}/intake`,
|
||||
action === "skipped"
|
||||
? { skipped: true, scheduledFor: row.at }
|
||||
: {
|
||||
skipped: false,
|
||||
scheduledFor: row.at,
|
||||
takenAt: new Date().toISOString(),
|
||||
},
|
||||
slotMarkRequestBody(row, action),
|
||||
);
|
||||
const eventId: string | undefined = created?.id;
|
||||
toast.success(
|
||||
|
||||
Reference in new issue
Block a user