diff --git a/frontend/src/pages/ActivityPage.jsx b/frontend/src/pages/ActivityPage.jsx index ea8284e..163857c 100644 --- a/frontend/src/pages/ActivityPage.jsx +++ b/frontend/src/pages/ActivityPage.jsx @@ -123,6 +123,50 @@ function activitySchemaHeadlineBinding(s) { return null } +/** training_parameters.category (siehe Migration 013); feste Reihenfolge der Wertegruppen */ +const TRAINING_PARAM_CATEGORY_ORDER = [ + 'physical', + 'physiological', + 'performance', + 'subjective', + 'environmental', +] + +const TRAINING_PARAM_CATEGORY_LABEL_DE = { + physical: 'Physisch / Bewegung', + physiological: 'Physiologie', + performance: 'Leistung', + subjective: 'Subjektiv und Wahrnehmung', + environmental: 'Umwelt', +} + +function compareActivityProfileSchemaRows(a, b) { + const ca = (a.param_category && String(a.param_category).trim().toLowerCase()) || '' + const cb = (b.param_category && String(b.param_category).trim().toLowerCase()) || '' + const ia = TRAINING_PARAM_CATEGORY_ORDER.indexOf(ca) + const ib = TRAINING_PARAM_CATEGORY_ORDER.indexOf(cb) + const ra = ia === -1 ? 1000 : ia + const rb = ib === -1 ? 1000 : ib + if (ra !== rb) return ra - rb + if (ca !== cb) return ca.localeCompare(cb, 'de') + + const ga = (a.ui_group && String(a.ui_group).trim()) || '' + const gb = (b.ui_group && String(b.ui_group).trim()) || '' + if (ga !== gb) { + if (!ga) return -1 + if (!gb) return 1 + return ga.localeCompare(gb, 'de') + } + const sa = Number(a.sort_order) || 0 + const sb = Number(b.sort_order) || 0 + if (sa !== sb) return sa - sb + return String(a.key).localeCompare(String(b.key), 'de') +} + +function sortActivityProfileSchemaRows(rows) { + return [...rows].sort(compareActivityProfileSchemaRows) +} + function empty() { return { date: dayjs().format('YYYY-MM-DD'), @@ -189,42 +233,94 @@ function SessionMetricsFields({ schema, values, setValues, metrics }) { if (schemaForDisplay.length === 0 && orphanMetrics.length === 0) return null const set = (k, v) => setValues((prev) => ({ ...prev, [k]: v })) + + const sortedForDisplay = sortActivityProfileSchemaRows(schemaForDisplay) + const profileFieldNodes = [] + let lastCategoryKey = null + let lastUiGroup = null + for (const s of sortedForDisplay) { + const catRaw = (s.param_category && String(s.param_category).trim().toLowerCase()) || '' + const catKey = catRaw || '_other' + if (catKey !== lastCategoryKey) { + lastCategoryKey = catKey + lastUiGroup = null + const catTitle = + (catRaw && TRAINING_PARAM_CATEGORY_LABEL_DE[catRaw]) || s.param_category || 'Sonstige' + profileFieldNodes.push( +