WP 9c Phase 1 #12
|
|
@ -171,14 +171,15 @@ def create_sleep(
|
||||||
bedtime = data.bedtime if data.bedtime else None
|
bedtime = data.bedtime if data.bedtime else None
|
||||||
wake_time = data.wake_time if data.wake_time else None
|
wake_time = data.wake_time if data.wake_time else None
|
||||||
|
|
||||||
# Plausibility check: phases should sum to duration (tolerance: 5 min)
|
# Plausibility check: sleep phases (deep+rem+light) should sum to duration
|
||||||
if any([data.deep_minutes, data.rem_minutes, data.light_minutes, data.awake_minutes]):
|
# Note: awake_minutes is NOT part of sleep duration (tracked separately)
|
||||||
phase_sum = (data.deep_minutes or 0) + (data.rem_minutes or 0) + (data.light_minutes or 0) + (data.awake_minutes or 0)
|
if any([data.deep_minutes, data.rem_minutes, data.light_minutes]):
|
||||||
diff = abs(data.duration_minutes - phase_sum)
|
sleep_phase_sum = (data.deep_minutes or 0) + (data.rem_minutes or 0) + (data.light_minutes or 0)
|
||||||
|
diff = abs(data.duration_minutes - sleep_phase_sum)
|
||||||
if diff > 5:
|
if diff > 5:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
400,
|
400,
|
||||||
f"Plausibilitätsprüfung fehlgeschlagen: Phasen-Summe ({phase_sum} min) weicht um {diff} min von Gesamtdauer ({data.duration_minutes} min) ab. Max. Toleranz: 5 min."
|
f"Plausibilitätsprüfung fehlgeschlagen: Schlafphasen-Summe ({sleep_phase_sum} min) weicht um {diff} min von Schlafdauer ({data.duration_minutes} min) ab. Max. Toleranz: 5 min. Hinweis: Wachphasen werden nicht zur Schlafdauer gezählt."
|
||||||
)
|
)
|
||||||
|
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
|
|
@ -231,14 +232,15 @@ def update_sleep(
|
||||||
bedtime = data.bedtime if data.bedtime else None
|
bedtime = data.bedtime if data.bedtime else None
|
||||||
wake_time = data.wake_time if data.wake_time else None
|
wake_time = data.wake_time if data.wake_time else None
|
||||||
|
|
||||||
# Plausibility check: phases should sum to duration (tolerance: 5 min)
|
# Plausibility check: sleep phases (deep+rem+light) should sum to duration
|
||||||
if any([data.deep_minutes, data.rem_minutes, data.light_minutes, data.awake_minutes]):
|
# Note: awake_minutes is NOT part of sleep duration (tracked separately)
|
||||||
phase_sum = (data.deep_minutes or 0) + (data.rem_minutes or 0) + (data.light_minutes or 0) + (data.awake_minutes or 0)
|
if any([data.deep_minutes, data.rem_minutes, data.light_minutes]):
|
||||||
diff = abs(data.duration_minutes - phase_sum)
|
sleep_phase_sum = (data.deep_minutes or 0) + (data.rem_minutes or 0) + (data.light_minutes or 0)
|
||||||
|
diff = abs(data.duration_minutes - sleep_phase_sum)
|
||||||
if diff > 5:
|
if diff > 5:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
400,
|
400,
|
||||||
f"Plausibilitätsprüfung fehlgeschlagen: Phasen-Summe ({phase_sum} min) weicht um {diff} min von Gesamtdauer ({data.duration_minutes} min) ab. Max. Toleranz: 5 min."
|
f"Plausibilitätsprüfung fehlgeschlagen: Schlafphasen-Summe ({sleep_phase_sum} min) weicht um {diff} min von Schlafdauer ({data.duration_minutes} min) ab. Max. Toleranz: 5 min. Hinweis: Wachphasen werden nicht zur Schlafdauer gezählt."
|
||||||
)
|
)
|
||||||
|
|
||||||
with get_db() as conn:
|
with get_db() as conn:
|
||||||
|
|
@ -557,12 +559,12 @@ async def import_apple_health_sleep(
|
||||||
cur = get_cursor(conn)
|
cur = get_cursor(conn)
|
||||||
|
|
||||||
for date, night in nights_dict.items():
|
for date, night in nights_dict.items():
|
||||||
# Calculate total duration (sum of all phases)
|
# Calculate sleep duration (deep + rem + light, WITHOUT awake)
|
||||||
|
# Note: awake_minutes tracked separately, not part of sleep duration
|
||||||
duration_minutes = (
|
duration_minutes = (
|
||||||
night['deep_minutes'] +
|
night['deep_minutes'] +
|
||||||
night['rem_minutes'] +
|
night['rem_minutes'] +
|
||||||
night['light_minutes'] +
|
night['light_minutes']
|
||||||
night['awake_minutes']
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate wake_count (number of awake segments)
|
# Calculate wake_count (number of awake segments)
|
||||||
|
|
|
||||||
|
|
@ -336,7 +336,7 @@ function SleepEntry({ entry, expanded, editing, onToggleExpand, onEdit, onCancel
|
||||||
const [plausibilityError, setPlausibilityError] = useState(null)
|
const [plausibilityError, setPlausibilityError] = useState(null)
|
||||||
const [suggestedDuration, setSuggestedDuration] = useState(null)
|
const [suggestedDuration, setSuggestedDuration] = useState(null)
|
||||||
|
|
||||||
// Auto-calculate duration from bedtime + wake_time
|
// Auto-calculate duration from bedtime + wake_time (minus awake time)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editing && formData.bedtime && formData.wake_time) {
|
if (editing && formData.bedtime && formData.wake_time) {
|
||||||
const [bedH, bedM] = formData.bedtime.split(':').map(Number)
|
const [bedH, bedM] = formData.bedtime.split(':').map(Number)
|
||||||
|
|
@ -349,22 +349,29 @@ function SleepEntry({ entry, expanded, editing, onToggleExpand, onEdit, onCancel
|
||||||
wakeMinutes += 24 * 60
|
wakeMinutes += 24 * 60
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = wakeMinutes - bedMinutes
|
let duration = wakeMinutes - bedMinutes
|
||||||
|
|
||||||
|
// Subtract awake time to get actual sleep duration
|
||||||
|
const awake = parseInt(formData.awake_minutes) || 0
|
||||||
|
if (awake > 0) {
|
||||||
|
duration = Math.max(0, duration - awake)
|
||||||
|
}
|
||||||
|
|
||||||
setSuggestedDuration(duration)
|
setSuggestedDuration(duration)
|
||||||
} else {
|
} else {
|
||||||
setSuggestedDuration(null)
|
setSuggestedDuration(null)
|
||||||
}
|
}
|
||||||
}, [editing, formData.bedtime, formData.wake_time])
|
}, [editing, formData.bedtime, formData.wake_time, formData.awake_minutes])
|
||||||
|
|
||||||
// Live plausibility check
|
// Live plausibility check (sleep phases only, awake not counted)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editing) return
|
if (!editing) return
|
||||||
const phases = [formData.deep_minutes, formData.rem_minutes, formData.light_minutes, formData.awake_minutes]
|
const sleepPhases = [formData.deep_minutes, formData.rem_minutes, formData.light_minutes]
|
||||||
if (phases.some(p => p !== '' && p !== null)) {
|
if (sleepPhases.some(p => p !== '' && p !== null)) {
|
||||||
const sum = phases.reduce((a, b) => a + (parseInt(b) || 0), 0)
|
const sum = sleepPhases.reduce((a, b) => a + (parseInt(b) || 0), 0)
|
||||||
const diff = Math.abs(formData.duration_minutes - sum)
|
const diff = Math.abs(formData.duration_minutes - sum)
|
||||||
if (diff > 5) {
|
if (diff > 5) {
|
||||||
setPlausibilityError(`Phasen-Summe (${sum} min) weicht um ${diff} min ab (Toleranz: 5 min)`)
|
setPlausibilityError(`Schlafphasen-Summe (${sum} min) weicht um ${diff} min ab (Toleranz: 5 min). Wachphasen nicht mitgezählt.`)
|
||||||
} else {
|
} else {
|
||||||
setPlausibilityError(null)
|
setPlausibilityError(null)
|
||||||
}
|
}
|
||||||
|
|
@ -408,7 +415,7 @@ function SleepEntry({ entry, expanded, editing, onToggleExpand, onEdit, onCancel
|
||||||
|
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 10 }}>
|
<div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 10 }}>
|
||||||
<div>
|
<div>
|
||||||
<div className="form-label">Schlafdauer (Minuten)</div>
|
<div className="form-label">Schlafdauer (reine Schlafzeit, Minuten)</div>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="form-input"
|
className="form-input"
|
||||||
|
|
@ -731,7 +738,7 @@ function NewEntryForm({ onSave, onCancel, formatDuration }) {
|
||||||
const [showDetail, setShowDetail] = useState(false)
|
const [showDetail, setShowDetail] = useState(false)
|
||||||
const [suggestedDuration, setSuggestedDuration] = useState(null)
|
const [suggestedDuration, setSuggestedDuration] = useState(null)
|
||||||
|
|
||||||
// Auto-calculate duration from bedtime + wake_time
|
// Auto-calculate duration from bedtime + wake_time (minus awake time)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (formData.bedtime && formData.wake_time) {
|
if (formData.bedtime && formData.wake_time) {
|
||||||
const [bedH, bedM] = formData.bedtime.split(':').map(Number)
|
const [bedH, bedM] = formData.bedtime.split(':').map(Number)
|
||||||
|
|
@ -745,21 +752,28 @@ function NewEntryForm({ onSave, onCancel, formatDuration }) {
|
||||||
wakeMinutes += 24 * 60
|
wakeMinutes += 24 * 60
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = wakeMinutes - bedMinutes
|
let duration = wakeMinutes - bedMinutes
|
||||||
|
|
||||||
|
// Subtract awake time to get actual sleep duration
|
||||||
|
const awake = parseInt(formData.awake_minutes) || 0
|
||||||
|
if (awake > 0) {
|
||||||
|
duration = Math.max(0, duration - awake)
|
||||||
|
}
|
||||||
|
|
||||||
setSuggestedDuration(duration)
|
setSuggestedDuration(duration)
|
||||||
} else {
|
} else {
|
||||||
setSuggestedDuration(null)
|
setSuggestedDuration(null)
|
||||||
}
|
}
|
||||||
}, [formData.bedtime, formData.wake_time])
|
}, [formData.bedtime, formData.wake_time, formData.awake_minutes])
|
||||||
|
|
||||||
// Live plausibility check
|
// Live plausibility check (sleep phases only, awake not counted)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const phases = [formData.deep_minutes, formData.rem_minutes, formData.light_minutes, formData.awake_minutes]
|
const sleepPhases = [formData.deep_minutes, formData.rem_minutes, formData.light_minutes]
|
||||||
if (phases.some(p => p !== '' && p !== null)) {
|
if (sleepPhases.some(p => p !== '' && p !== null)) {
|
||||||
const sum = phases.reduce((a, b) => a + (parseInt(b) || 0), 0)
|
const sum = sleepPhases.reduce((a, b) => a + (parseInt(b) || 0), 0)
|
||||||
const diff = Math.abs(formData.duration_minutes - sum)
|
const diff = Math.abs(formData.duration_minutes - sum)
|
||||||
if (diff > 5) {
|
if (diff > 5) {
|
||||||
setPlausibilityError(`Phasen-Summe (${sum} min) weicht um ${diff} min ab (Toleranz: 5 min)`)
|
setPlausibilityError(`Schlafphasen-Summe (${sum} min) weicht um ${diff} min ab (Toleranz: 5 min). Wachphasen nicht mitgezählt.`)
|
||||||
} else {
|
} else {
|
||||||
setPlausibilityError(null)
|
setPlausibilityError(null)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user