diff --git a/web/src/routes/SessionsPage.test.tsx b/web/src/routes/SessionsPage.test.tsx index d6aed45..7f15513 100644 --- a/web/src/routes/SessionsPage.test.tsx +++ b/web/src/routes/SessionsPage.test.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { describe, expect, it, vi } from 'vitest' -import { SessionsPage } from './SessionsPage' +import { commandOccurrence, SessionsPage } from './SessionsPage' function page(kind: string, items: unknown[]) { return { api_version: 1, kind, offset: 0, more: false, next_offset: items.length, items } @@ -11,6 +11,19 @@ function response(value: unknown) { } describe('Sessions page', () => { + it('removes presentation-only fields from a preparation command', () => { + const command = commandOccurrence({ + exercise_id: 'ex_one', exercise_name: 'Visible name', equipment_id: null, + recording_mode: 'sets', tracking_mode: 'reps', load_mode: 'external', rest_seconds: 90, + target_sets: 3, target_reps: 8, target_duration_seconds: null, target_weight_kg: 42, + notes: null, + }) + expect(command).not.toHaveProperty('exercise_name') + expect(command).not.toHaveProperty('recording_mode') + expect(command).not.toHaveProperty('tracking_mode') + expect(command).toMatchObject({ exercise_id: 'ex_one', target_sets: 3, rest_seconds: 90 }) + }) + it('keeps proposals distinct and opens a stable deep link', async () => { window.history.replaceState(null, '', '/seances') vi.stubGlobal('fetch', vi.fn((input: RequestInfo | URL) => { diff --git a/web/src/routes/SessionsPage.tsx b/web/src/routes/SessionsPage.tsx index 8e3fc06..3dd1091 100644 --- a/web/src/routes/SessionsPage.tsx +++ b/web/src/routes/SessionsPage.tsx @@ -31,6 +31,42 @@ function emptyInput(): PreparationInput { editing_state: 'draft', occurrences: [] } } +function editableOccurrence( + value: PreparationOccurrence, + preserveIdentity: boolean, +): PreparationOccurrence { + return { + ...(preserveIdentity ? { entry_id: value.entry_id } : {}), + exercise_id: value.exercise_id, + exercise_name: value.exercise_name, + equipment_id: value.equipment_id, + recording_mode: value.recording_mode, + tracking_mode: value.tracking_mode, + load_mode: value.load_mode, + rest_seconds: value.rest_seconds, + target_sets: value.target_sets, + target_reps: value.target_reps, + target_duration_seconds: value.target_duration_seconds, + target_weight_kg: value.target_weight_kg, + notes: value.notes, + } +} + +export function commandOccurrence(value: PreparationOccurrence): PreparationOccurrence { + return { + ...(value.entry_id ? { entry_id: value.entry_id } : {}), + exercise_id: value.exercise_id, + equipment_id: value.equipment_id, + load_mode: value.load_mode, + rest_seconds: value.rest_seconds, + target_sets: value.target_sets, + target_reps: value.target_reps, + target_duration_seconds: value.target_duration_seconds, + target_weight_kg: value.target_weight_kg, + notes: value.notes, + } +} + function Editor({ initial, onSaved, onCancel }: { initial?: SessionDetail onSaved: (identity: string) => void @@ -38,9 +74,8 @@ function Editor({ initial, onSaved, onCancel }: { }) { const [input, setInput] = useState(() => initial ? { title: initial.title, session_type: initial.session_type, planned_for: initial.planned_for, - notes: initial.notes, editing_state: 'draft', occurrences: initial.occurrences.map((value) => ({ - ...value, entry_id: initial.kind === 'proposal' ? undefined : value.entry_id, - })), + notes: initial.notes, editing_state: 'draft', occurrences: initial.occurrences.map((value) => + editableOccurrence(value, initial.kind === 'preparation')), ...(initial.kind === 'proposal' ? { source_proposal_id: initial.identity, source_payload_sha256: initial.source_fingerprint ?? undefined, @@ -78,7 +113,8 @@ function Editor({ initial, onSaved, onCancel }: { const submit = async (ready: boolean) => { setSaving(true); setError('') try { - const result = await savePreparation({ ...input, editing_state: ready ? 'ready' : 'draft' }, + const result = await savePreparation({ ...input, editing_state: ready ? 'ready' : 'draft', + occurrences: input.occurrences.map(commandOccurrence) }, initial?.kind === 'preparation' ? initial.identity : undefined, initial?.kind === 'preparation' ? initial.revision_id : undefined) if (ready) await prepareForAndroid(result.preparation_id, result.revision_id)