mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 06:32:03 +00:00
feat(workouts): save an edited resubmit of a hand-entered workout
The manual form sends one manual: id per opening and resends it after an edit. The batch route now treats a MANUAL entry with a manual: id as an overwrite, the way stats: measurements are: the stored row takes the new values and the entry reports "updated", or "duplicate" when nothing changed. Records keyed on the workout are removed under the personal-records lock and re-derived. Every other id stays first-write-wins. The status enum gains "updated".
This commit is contained in:
1 parent
6bb65824bf
commit
916f918674
6 files changed
+271
-19
No files matched your search
@@ -138,6 +138,18 @@ describe("saveManualWorkout — the wire", () => {
|
||||
).resolves.toBe("duplicate");
|
||||
});
|
||||
|
||||
it("treats an edited resubmit (`updated`) as saved and refreshes", async () => {
|
||||
fetchSpy.mockResolvedValue(
|
||||
envelope({ entries: [{ index: 0, status: "updated" }] }),
|
||||
);
|
||||
const client = fakeClient();
|
||||
|
||||
await expect(
|
||||
saveManualWorkout(ENTRY, client as unknown as QueryClient),
|
||||
).resolves.toBe("updated");
|
||||
expect(client.invalidateQueries).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws when the route skipped the entry, and refreshes nothing", async () => {
|
||||
fetchSpy.mockResolvedValue(
|
||||
envelope({ entries: [{ index: 0, status: "skipped" }] }),
|
||||
|
||||
@@ -59,7 +59,7 @@ interface BatchResult {
|
||||
entries?: Array<{ status: string }>;
|
||||
}
|
||||
|
||||
export type ManualWorkoutSaveOutcome = "inserted" | "duplicate";
|
||||
export type ManualWorkoutSaveOutcome = "inserted" | "duplicate" | "updated";
|
||||
|
||||
/**
|
||||
* Post the entry and refresh what shows workouts. A `duplicate` is a success:
|
||||
@@ -74,7 +74,7 @@ export async function saveManualWorkout(
|
||||
workouts: [entry],
|
||||
});
|
||||
const status = result?.entries?.[0]?.status;
|
||||
if (status !== "inserted" && status !== "duplicate") {
|
||||
if (status !== "inserted" && status !== "duplicate" && status !== "updated") {
|
||||
throw new Error(`workout entry not stored: ${status ?? "unknown"}`);
|
||||
}
|
||||
// The list, the dashboard tile and every detail read sit under this
|
||||
@@ -112,7 +112,8 @@ export function ManualWorkoutForm({
|
||||
const timezone = user?.timezone || DEFAULT_TIMEZONE;
|
||||
|
||||
// Minted once per opened form and sent with every submit, so a second tap
|
||||
// or a retried request lands as a duplicate rather than a second row.
|
||||
// or a retried request lands as a duplicate rather than a second row, and
|
||||
// a submit after an edit updates the row the first submit stored.
|
||||
const [externalId] = useState(newManualWorkoutExternalId);
|
||||
const [draft, setDraft] = useState<ManualWorkoutDraft>(() =>
|
||||
emptyManualWorkoutDraft(new Date(), timezone),
|
||||
|
||||
Reference in new issue
Block a user