Goalsystem V1 #50
|
|
@ -14,6 +14,7 @@ from pydantic import BaseModel
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
import traceback
|
||||||
|
|
||||||
from db import get_db, get_cursor, r2d
|
from db import get_db, get_cursor, r2d
|
||||||
from auth import require_auth
|
from auth import require_auth
|
||||||
|
|
@ -499,24 +500,51 @@ def list_goal_type_definitions(session: dict = Depends(require_auth)):
|
||||||
|
|
||||||
Public endpoint - returns all available goal types for dropdown.
|
Public endpoint - returns all available goal types for dropdown.
|
||||||
"""
|
"""
|
||||||
with get_db() as conn:
|
try:
|
||||||
cur = get_cursor(conn)
|
with get_db() as conn:
|
||||||
cur.execute("""
|
cur = get_cursor(conn)
|
||||||
SELECT id, type_key, label_de, label_en, unit, icon, category,
|
|
||||||
source_table, source_column, aggregation_method,
|
|
||||||
calculation_formula, description, is_system,
|
|
||||||
created_at, updated_at
|
|
||||||
FROM goal_type_definitions
|
|
||||||
WHERE is_active = true
|
|
||||||
ORDER BY
|
|
||||||
CASE
|
|
||||||
WHEN is_system = true THEN 0
|
|
||||||
ELSE 1
|
|
||||||
END,
|
|
||||||
label_de
|
|
||||||
""")
|
|
||||||
|
|
||||||
return [r2d(row) for row in cur.fetchall()]
|
# Check if table exists first
|
||||||
|
cur.execute("""
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT FROM information_schema.tables
|
||||||
|
WHERE table_name = 'goal_type_definitions'
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
table_exists = cur.fetchone()[0]
|
||||||
|
|
||||||
|
if not table_exists:
|
||||||
|
print("[ERROR] goal_type_definitions table does not exist!")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail="Goal Types Tabelle existiert nicht. Migration 024 muss ausgeführt werden."
|
||||||
|
)
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT id, type_key, label_de, label_en, unit, icon, category,
|
||||||
|
source_table, source_column, aggregation_method,
|
||||||
|
calculation_formula, description, is_system,
|
||||||
|
created_at, updated_at
|
||||||
|
FROM goal_type_definitions
|
||||||
|
WHERE is_active = true
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN is_system = true THEN 0
|
||||||
|
ELSE 1
|
||||||
|
END,
|
||||||
|
label_de
|
||||||
|
""")
|
||||||
|
|
||||||
|
return [r2d(row) for row in cur.fetchall()]
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] list_goal_type_definitions failed: {e}")
|
||||||
|
print(traceback.format_exc())
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=f"Fehler beim Laden der Goal Types: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
@router.post("/goal-types")
|
@router.post("/goal-types")
|
||||||
def create_goal_type_definition(
|
def create_goal_type_definition(
|
||||||
|
|
|
||||||
|
|
@ -84,21 +84,23 @@ export default function GoalsPage() {
|
||||||
|
|
||||||
// Convert types array to map for quick lookup
|
// Convert types array to map for quick lookup
|
||||||
const typesMap = {}
|
const typesMap = {}
|
||||||
typesData.forEach(type => {
|
if (typesData && Array.isArray(typesData)) {
|
||||||
typesMap[type.type_key] = {
|
typesData.forEach(type => {
|
||||||
label: type.label_de,
|
typesMap[type.type_key] = {
|
||||||
unit: type.unit,
|
label: type.label_de,
|
||||||
icon: type.icon || '📊',
|
unit: type.unit,
|
||||||
category: type.category,
|
icon: type.icon || '📊',
|
||||||
is_system: type.is_system
|
category: type.category,
|
||||||
}
|
is_system: type.is_system
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
setGoalTypes(typesData)
|
setGoalTypes(typesData || [])
|
||||||
setGoalTypesMap(typesMap)
|
setGoalTypesMap(typesMap)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to load goals:', err)
|
console.error('Failed to load goals:', err)
|
||||||
setError('Fehler beim Laden der Ziele')
|
setError(`Fehler beim Laden: ${err.message || err.toString()}`)
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
@ -121,8 +123,12 @@ export default function GoalsPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCreateGoal = () => {
|
const handleCreateGoal = () => {
|
||||||
|
if (goalTypes.length === 0) {
|
||||||
|
setError('Keine Goal Types verfügbar. Bitte Admin kontaktieren.')
|
||||||
|
return
|
||||||
|
}
|
||||||
setEditingGoal(null)
|
setEditingGoal(null)
|
||||||
const firstType = goalTypes.length > 0 ? goalTypes[0].type_key : 'weight'
|
const firstType = goalTypes[0].type_key
|
||||||
setFormData({
|
setFormData({
|
||||||
goal_type: firstType,
|
goal_type: firstType,
|
||||||
is_primary: goals.length === 0, // First goal is primary by default
|
is_primary: goals.length === 0, // First goal is primary by default
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user