From 5e5350d5ac1a7a2fb62776fff23c3f761abb4643 Mon Sep 17 00:00:00 2001 From: Lars Date: Fri, 15 May 2026 17:01:00 +0200 Subject: [PATCH] Enhance TrainingCoachPage and trainingPlanUtils with session storage management and phase handling improvements - Introduced a new function in TrainingCoachPage to clear session storage for coach steps, improving state management during training sessions. - Updated the sectionsWithPlanLocForDisplay function in trainingPlanUtils to include logic for determining the maximum phase order index, enhancing phase handling. - Enhanced the mapping of sections to include default plan locations for parallel phases, optimizing data representation and user experience. --- frontend/src/pages/TrainingCoachPage.jsx | 15 ++++++++++++ frontend/src/utils/trainingPlanUtils.js | 31 +++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/TrainingCoachPage.jsx b/frontend/src/pages/TrainingCoachPage.jsx index 48b3084..abdf806 100644 --- a/frontend/src/pages/TrainingCoachPage.jsx +++ b/frontend/src/pages/TrainingCoachPage.jsx @@ -27,6 +27,18 @@ function storageStepKey(unitId, mergedPicks) { return `sj_coach_step_${unitId}_${coachBranchPicksStepStorageSuffix(mergedPicks)}` } +function clearCoachStepStorageForUnit(unitId) { + const pref = `sj_coach_step_${unitId}_` + try { + for (let i = sessionStorage.length - 1; i >= 0; i -= 1) { + const k = sessionStorage.key(i) + if (k && k.startsWith(pref)) sessionStorage.removeItem(k) + } + } catch { + /* ignore */ + } +} + function storageDeltasKey(unitId) { return `sj_coach_deltas_${unitId}` } @@ -614,9 +626,12 @@ export default function TrainingCoachPage() { sessionStorage.removeItem(storageDeltasKey(idNum)) sessionStorage.removeItem(storageDebriefKey(idNum)) sessionStorage.removeItem(coachBranchPicksStorageKey(idNum)) + clearCoachStepStorageForUnit(idNum) } catch { /* ignore */ } + setSearchParams({}, { replace: true }) + setStep(0) setDeltas({}) setBranchPicks({}) setStreamChoiceHint(null) diff --git a/frontend/src/utils/trainingPlanUtils.js b/frontend/src/utils/trainingPlanUtils.js index ebcc365..616de23 100644 --- a/frontend/src/utils/trainingPlanUtils.js +++ b/frontend/src/utils/trainingPlanUtils.js @@ -5,6 +5,7 @@ import { buildPlanPayloadForSave, cloneJsonSerializablePlanningProfile, + defaultPlanLocWholeGroup, inheritPlanLocForPhasedSave, phaseRunsFromSections, sectionIndicesForParallelStream, @@ -94,6 +95,16 @@ function planLocBySectionIdFromPhases(phases) { return byId } +function maxPhaseOrderIndexFromNestedPhases(phases) { + let m = -1 + if (!Array.isArray(phases)) return m + for (const ph of phases) { + const po = Number(ph.order_index ?? ph.orderIndex ?? 0) + if (Number.isFinite(po)) m = Math.max(m, po) + } + return m +} + export function sectionsWithPlanLocForDisplay(unit) { const sorted = sortedSections(unit) const byId = planLocBySectionIdFromPhases(unit?.phases) @@ -105,7 +116,25 @@ export function sectionsWithPlanLocForDisplay(unit) { if (s.planLoc && s.planLoc.phaseKind) return s return { ...s } }) - return inheritPlanLocForPhasedSave(merged) + const inherited = inheritPlanLocForPhasedSave(merged) + const maxPhPo = maxPhaseOrderIndexFromNestedPhases(unit?.phases) + return inherited.map((s) => { + const sid = s.id != null ? Number(s.id) : NaN + if (!Number.isFinite(sid) || byId.has(sid)) return s + const pl = s.planLoc + if (pl?.phaseKind === 'parallel') { + const po = maxPhPo >= 0 ? maxPhPo + 1 : 0 + return { + ...s, + planLoc: { + ...defaultPlanLocWholeGroup(po), + phaseTitle: pl.phaseTitle ?? null, + phaseGuidanceNotes: pl.phaseGuidanceNotes ?? null, + }, + } + } + return s + }) } /**