From d97925d5a1f8e587aeaec99dce1f24fe1ee41acf Mon Sep 17 00:00:00 2001 From: Lars Date: Fri, 27 Mar 2026 10:36:42 +0100 Subject: [PATCH] feat: Focus Areas Slider UI (Goal System v2.0 complete) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces single goal mode cards with weighted multi-focus system UI Features: - 6 sliders for focus dimensions (5% increments) - Live sum calculation with visual feedback - Validation: Sum must equal 100% - Color-coded sliders per dimension - Edit/Display mode toggle - Shows derived values if not customized UX Flow: 1. Default: Shows focus distribution (bars) 2. Click 'Anpassen': Shows sliders 3. Adjust percentages (sum = 100%) 4. Save → Updates backend + reloads Visual: - Active dimensions shown as colored cards (display mode) - Gradient sliders with percentage labels (edit mode) - Green box when sum = 100%, red when != 100% - Info message if derived from old goal_mode Complete v2.0: ✅ Backend (Migration 027, API, get_focus_weights V2) ✅ Frontend (Slider UI, state management, validation) ✅ Auto-migration (goal_mode → focus_areas) Ready for: KI-Integration with weighted scoring --- frontend/src/pages/GoalsPage.jsx | 227 ++++++++++++++++++++++++++----- 1 file changed, 193 insertions(+), 34 deletions(-) diff --git a/frontend/src/pages/GoalsPage.jsx b/frontend/src/pages/GoalsPage.jsx index 5ba8e00..ca998c4 100644 --- a/frontend/src/pages/GoalsPage.jsx +++ b/frontend/src/pages/GoalsPage.jsx @@ -46,6 +46,16 @@ const GOAL_MODES = [ export default function GoalsPage() { const [goalMode, setGoalMode] = useState(null) + const [focusAreas, setFocusAreas] = useState(null) + const [focusEditing, setFocusEditing] = useState(false) + const [focusTemp, setFocusTemp] = useState({ + weight_loss_pct: 0, + muscle_gain_pct: 0, + strength_pct: 0, + endurance_pct: 0, + flexibility_pct: 0, + health_pct: 0 + }) const [goals, setGoals] = useState([]) const [goalTypes, setGoalTypes] = useState([]) // Dynamic from DB (Phase 1.5) const [goalTypesMap, setGoalTypesMap] = useState({}) // For quick lookup @@ -74,13 +84,16 @@ export default function GoalsPage() { setLoading(true) setError(null) try { - const [modeData, goalsData, typesData] = await Promise.all([ + const [modeData, goalsData, typesData, focusData] = await Promise.all([ api.getGoalMode(), api.listGoals(), - api.listGoalTypeDefinitions() // Phase 1.5: Load from DB + api.listGoalTypeDefinitions(), // Phase 1.5: Load from DB + api.getFocusAreas() // v2.0: Load focus areas ]) setGoalMode(modeData.goal_mode) setGoals(goalsData) + setFocusAreas(focusData) + setFocusTemp(focusData) // Initialize temp state // Convert types array to map for quick lookup const typesMap = {} @@ -258,43 +271,189 @@ export default function GoalsPage() { )} - {/* Strategic Goal Mode Selection */} + {/* Focus Areas (v2.0) */}
-

🎯 Trainingsmodus

+
+

🎯 Fokus-Bereiche

+ {!focusEditing && focusAreas && ( + + )} +

- Wähle deine grundlegende Trainingsausrichtung. Dies beeinflusst die Gewichtung - und Interpretation aller Analysen. + Gewichte deine Trainingsziele individuell. Die Summe muss 100% ergeben. + {focusAreas && !focusAreas.custom && ( + + ℹ️ Aktuell abgeleitet aus Trainingsmodus "{goalMode}" - klicke "Anpassen" für individuelle Gewichtung + + )}

-
- {GOAL_MODES.map(mode => ( - - ))} -
+ {Object.values(focusTemp).reduce((a, b) => a + b, 0) !== 100 && ( +
+ ⚠️ Summe muss 100% ergeben +
+ )} +
+ + {/* Action Buttons */} +
+ + +
+ + ) : focusAreas && ( + /* Display Mode */ +
+ {[ + { key: 'weight_loss_pct', label: 'Fettabbau', icon: '📉', color: '#D85A30' }, + { key: 'muscle_gain_pct', label: 'Muskelaufbau', icon: '💪', color: '#378ADD' }, + { key: 'strength_pct', label: 'Kraftsteigerung', icon: '🏋️', color: '#7B68EE' }, + { key: 'endurance_pct', label: 'Ausdauer', icon: '🏃', color: '#1D9E75' }, + { key: 'flexibility_pct', label: 'Beweglichkeit', icon: '🤸', color: '#E67E22' }, + { key: 'health_pct', label: 'Gesundheit', icon: '❤️', color: '#F59E0B' } + ].filter(area => focusAreas[area.key] > 0).map(area => ( +
+
{area.icon}
+
{area.label}
+
{focusAreas[area.key]}%
+
+ ))} +
+ )} {/* Tactical Goals List */}