diff --git a/frontend/src/components/TrainingUnitSectionsEditor.jsx b/frontend/src/components/TrainingUnitSectionsEditor.jsx
index 4a4cb10..960932a 100644
--- a/frontend/src/components/TrainingUnitSectionsEditor.jsx
+++ b/frontend/src/components/TrainingUnitSectionsEditor.jsx
@@ -46,6 +46,7 @@ export default function TrainingUnitSectionsEditor({
showExecutionExtras = false,
heading = 'Abschnitte & Übungen',
hideHeading = false,
+ headingAccessory = null,
wideExerciseGrid = false,
enableItemDragReorder = true,
enableSectionDragReorder = true,
@@ -353,8 +354,39 @@ export default function TrainingUnitSectionsEditor({
(wideExerciseGrid ? ' training-unit-sections-editor--wide' : '')
}
>
- {!hideHeading ? (
-
{heading}
+ {(!hideHeading || headingAccessory) ? (
+
+ {!hideHeading ? (
+
+ {heading}
+
+ ) : headingAccessory ? (
+
+ ) : null}
+ {headingAccessory ? (
+
+ {headingAccessory}
+
+ ) : null}
+
) : null}
{list.map((sec, sIdx) => {
const planMin = sectionPlannedMinutes(sec)
diff --git a/frontend/src/pages/TrainingFrameworkProgramEditPage.jsx b/frontend/src/pages/TrainingFrameworkProgramEditPage.jsx
index 72f9446..bced89d 100644
--- a/frontend/src/pages/TrainingFrameworkProgramEditPage.jsx
+++ b/frontend/src/pages/TrainingFrameworkProgramEditPage.jsx
@@ -6,10 +6,10 @@ import ExercisePeekModal from '../components/ExercisePeekModal'
import TrainingUnitSectionsEditor from '../components/TrainingUnitSectionsEditor'
import {
defaultSection,
- exerciseRow,
normalizeUnitToForm,
enrichSectionsWithVariants,
buildSectionsPayload,
+ hydrateExercisePlanningRow,
} from '../utils/trainingUnitSectionsForm'
const DND_FW_SLOT = 'application/x-shinkan-framework-slot'
@@ -52,27 +52,6 @@ async function enrichFrameworkSlotSections(slots) {
return out
}
-async function hydrateExerciseForSlotRow(exercise) {
- let variants = Array.isArray(exercise?.variants) ? exercise.variants : []
- let title = exercise?.title || ''
- const id = exercise?.id
- if (!id) return null
- if (!variants.length) {
- try {
- const full = await api.getExercise(id)
- variants = Array.isArray(full?.variants) ? full.variants : []
- title = full?.title || title
- } catch {
- variants = []
- }
- }
- const row = exerciseRow()
- row.exercise_id = id
- row.exercise_variant_id = ''
- row.exercise_title = title
- row.variants = variants
- return row
-}
function goalHoverText(g) {
const t = (g.title || '').trim() || 'Ohne Titel'
const n = (g.notes || '').trim()
@@ -1138,7 +1117,7 @@ export default function TrainingFrameworkProgramEditPage() {
const { slotIdx, sectionIndex: sIdx } = sectionPickerCtx
const rows = []
for (const ex of picked) {
- const row = await hydrateExerciseForSlotRow(ex)
+ const row = await hydrateExercisePlanningRow(ex)
if (row) rows.push(row)
}
if (!rows.length) return
@@ -1166,7 +1145,7 @@ export default function TrainingFrameworkProgramEditPage() {
if (sectionPickerCtx.multi) return
if (typeof sectionPickerCtx.itemIndex !== 'number') return
const { slotIdx, sectionIndex: sIdx, itemIndex: iIdx } = sectionPickerCtx
- const row = await hydrateExerciseForSlotRow(exercise)
+ const row = await hydrateExercisePlanningRow(exercise)
if (!row) return
setForm((prev) => ({
...prev,
diff --git a/frontend/src/pages/TrainingPlanningPage.jsx b/frontend/src/pages/TrainingPlanningPage.jsx
index fac61ad..6363bbe 100644
--- a/frontend/src/pages/TrainingPlanningPage.jsx
+++ b/frontend/src/pages/TrainingPlanningPage.jsx
@@ -7,34 +7,12 @@ import ExercisePeekModal from '../components/ExercisePeekModal'
import TrainingUnitSectionsEditor from '../components/TrainingUnitSectionsEditor'
import {
defaultSection,
- exerciseRow,
normalizeUnitToForm,
enrichSectionsWithVariants,
buildSectionsPayload,
+ hydrateExercisePlanningRow,
} from '../utils/trainingUnitSectionsForm'
-async function hydrateExerciseForPickerRow(exercise) {
- let variants = Array.isArray(exercise?.variants) ? exercise.variants : []
- let title = exercise?.title || ''
- const id = exercise?.id
- if (!id) return null
- if (!variants.length) {
- try {
- const full = await api.getExercise(id)
- variants = Array.isArray(full?.variants) ? full.variants : []
- title = full?.title || title
- } catch {
- variants = []
- }
- }
- const row = exerciseRow()
- row.exercise_id = id
- row.exercise_variant_id = ''
- row.exercise_title = title
- row.variants = variants
- return row
-}
-
function TrainingPlanningPage() {
const { user } = useAuth()
const [groups, setGroups] = useState([])
@@ -634,7 +612,7 @@ function TrainingPlanningPage() {
background: 'var(--surface)',
borderRadius: '12px',
padding: 'clamp(12px, 3vw, 2rem)',
- maxWidth: 'min(960px, 100%)',
+ maxWidth: 'min(1100px, 100%)',
width: '100%',
maxHeight: '92vh',
overflowY: 'auto',
@@ -715,26 +693,16 @@ function TrainingPlanningPage() {
/>
-
-
Abschnitte & Übungen
-
-
-
+
+ Vorlage aus Aufbau speichern
+
+ }
sections={formData.sections}
+ wideExerciseGrid
onSectionsChange={(updater) =>
setFormData((prev) => ({
...prev,
@@ -754,6 +722,7 @@ function TrainingPlanningPage() {
}
showExecutionExtras={!!editingUnit}
/>
+
@@ -867,7 +836,7 @@ function TrainingPlanningPage() {
const { sIdx } = exercisePickerTarget
const rows = []
for (const ex of picked) {
- const row = await hydrateExerciseForPickerRow(ex)
+ const row = await hydrateExercisePlanningRow(ex)
if (row) rows.push(row)
}
if (!rows.length) return
@@ -884,7 +853,7 @@ function TrainingPlanningPage() {
}
onSelectExercise={async (ex) => {
if (!exercisePickerTarget || exercisePickerTarget.multi) return
- const row = await hydrateExerciseForPickerRow(ex)
+ const row = await hydrateExercisePlanningRow(ex)
if (!row) return
const { sIdx, iIdx } = exercisePickerTarget
if (typeof iIdx !== 'number') return
diff --git a/frontend/src/utils/trainingUnitSectionsForm.js b/frontend/src/utils/trainingUnitSectionsForm.js
index e41ef40..01c9b4e 100644
--- a/frontend/src/utils/trainingUnitSectionsForm.js
+++ b/frontend/src/utils/trainingUnitSectionsForm.js
@@ -18,6 +18,28 @@ export function exerciseRow() {
}
}
+export async function hydrateExercisePlanningRow(exercise) {
+ let variants = Array.isArray(exercise?.variants) ? exercise.variants : []
+ let title = exercise?.title || ''
+ const id = exercise?.id
+ if (!id) return null
+ if (!variants.length) {
+ try {
+ const full = await api.getExercise(id)
+ variants = Array.isArray(full?.variants) ? full.variants : []
+ title = full?.title || title
+ } catch {
+ variants = []
+ }
+ }
+ const row = exerciseRow()
+ row.exercise_id = id
+ row.exercise_variant_id = ''
+ row.exercise_title = title
+ row.variants = variants
+ return row
+}
+
export function noteRow() {
return { item_type: 'note', note_body: '' }
}