diff --git a/frontend/src/pages/GoalsPage.jsx b/frontend/src/pages/GoalsPage.jsx index 8cd225b..848836e 100644 --- a/frontend/src/pages/GoalsPage.jsx +++ b/frontend/src/pages/GoalsPage.jsx @@ -71,6 +71,8 @@ export default function GoalsPage() { const [groupedGoals, setGroupedGoals] = useState({}) // Category-grouped goals const [goalTypes, setGoalTypes] = useState([]) // Dynamic from DB (Phase 1.5) const [goalTypesMap, setGoalTypesMap] = useState({}) // For quick lookup + const [focusAreas, setFocusAreas] = useState([]) // v2.0: Available focus areas + const [focusAreasGrouped, setFocusAreasGrouped] = useState({}) // Grouped by category const [showGoalForm, setShowGoalForm] = useState(false) const [editingGoal, setEditingGoal] = useState(null) const [showProgressModal, setShowProgressModal] = useState(false) @@ -95,7 +97,8 @@ export default function GoalsPage() { unit: 'kg', target_date: '', name: '', - description: '' + description: '', + focus_contributions: [] // v2.0: [{focus_area_id, contribution_weight}] }) useEffect(() => { @@ -106,12 +109,13 @@ export default function GoalsPage() { setLoading(true) setError(null) try { - const [modeData, goalsData, groupedData, typesData, focusData] = await Promise.all([ + const [modeData, goalsData, groupedData, typesData, focusData, focusAreasData] = await Promise.all([ api.getGoalMode(), api.listGoals(), api.listGoalsGrouped(), // v2.1: Load grouped by category api.listGoalTypeDefinitions(), // Phase 1.5: Load from DB - api.getFocusAreas() // v2.0: Load focus areas + api.getFocusAreas(), // v2.0: Load user focus preferences (legacy) + api.listFocusAreaDefinitions(false) // v2.0: Load available focus areas ]) setGoalMode(modeData.goal_mode) setGoals(goalsData) @@ -148,6 +152,12 @@ export default function GoalsPage() { setGoalTypes(typesData || []) setGoalTypesMap(typesMap) + + // v2.0: Set focus area definitions + if (focusAreasData) { + setFocusAreas(focusAreasData.areas || []) + setFocusAreasGrouped(focusAreasData.grouped || {}) + } } catch (err) { console.error('Failed to load goals:', err) setError(`Fehler beim Laden: ${err.message || err.toString()}`) @@ -188,7 +198,8 @@ export default function GoalsPage() { unit: goalTypesMap[firstType]?.unit || 'kg', target_date: '', name: '', - description: '' + description: '', + focus_contributions: [] // v2.0: Empty for new goal }) setShowGoalForm(true) } @@ -204,7 +215,8 @@ export default function GoalsPage() { unit: goal.unit, target_date: goal.target_date || '', name: goal.name || '', - description: goal.description || '' + description: goal.description || '', + focus_contributions: goal.focus_contributions || [] // v2.0: Load existing contributions }) setShowGoalForm(true) } @@ -652,6 +664,38 @@ export default function GoalsPage() { + {/* Focus Area Badges (v2.0) */} + {goal.focus_contributions && goal.focus_contributions.length > 0 && ( +
+ {goal.focus_contributions.map(fc => ( + + {fc.icon && {fc.icon}} + {fc.name_de} + ({fc.contribution_weight}%) + + ))} +
+ )} +
Start:{' '} @@ -848,6 +892,182 @@ export default function GoalsPage() { />
+ {/* Focus Areas (v2.0) */} +
+ +
+ Wähle die Bereiche aus, auf die dieses Ziel einzahlt. Mehrfachauswahl möglich. +
+ + {Object.keys(focusAreasGrouped).length === 0 ? ( +
+ Keine Focus Areas verfügbar +
+ ) : ( +
+ {Object.entries(focusAreasGrouped).map(([category, areas]) => ( +
+
+ {category} +
+
+ {areas.map(area => { + const isSelected = formData.focus_contributions?.some( + fc => fc.focus_area_id === area.id + ) + + return ( + + ) + })} +
+
+ ))} +
+ )} + + {/* Selected areas with weights */} + {formData.focus_contributions && formData.focus_contributions.length > 0 && ( +
+
+ Gewichtung ({formData.focus_contributions.length} ausgewählt) +
+
+ {formData.focus_contributions.map((fc, idx) => { + const area = focusAreas.find(a => a.id === fc.focus_area_id) + if (!area) return null + + return ( +
+
+ {area.icon} {area.name_de} +
+ { + const newWeight = parseFloat(e.target.value) || 0 + setFormData(f => ({ + ...f, + focus_contributions: f.focus_contributions.map((item, i) => + i === idx ? { ...item, contribution_weight: newWeight } : item + ) + })) + }} + style={{ + width: 70, + padding: '4px 8px', + fontSize: 13, + textAlign: 'center', + border: '1px solid var(--accent)', + borderRadius: 6 + }} + /> + % +
+ ) + })} +
+
+ )} +
+ {/* Zielwert */}
🎯 Zielwert