Bugfixes
This commit is contained in:
@@ -110,43 +110,34 @@ async def get_wake_sleep_times(
|
||||
except ValueError:
|
||||
return {"days": []}
|
||||
|
||||
sessions, _ = await get_sessions(session, from_date=from_date, to_date=to_date)
|
||||
# Fetch sessions starting from one day before to catch night sleep ending on from_date
|
||||
adj_from_date = from_date - timedelta(days=1)
|
||||
sessions, _ = await get_sessions(session, from_date=adj_from_date, to_date=to_date)
|
||||
days_data = []
|
||||
current_date = from_date.date()
|
||||
while current_date <= to_date.date():
|
||||
date_str = current_date.strftime("%Y-%m-%d")
|
||||
day_sessions = [
|
||||
s
|
||||
for s in sessions
|
||||
if s.start_time.date() == current_date
|
||||
or (s.end_time and s.end_time.date() == current_date)
|
||||
]
|
||||
|
||||
wakeup_min = None
|
||||
bedtime_min = None
|
||||
|
||||
if day_sessions:
|
||||
# Find first wakeup after wakeup_ref
|
||||
wakeups = []
|
||||
for s in day_sessions:
|
||||
if s.end_time and s.end_time.time() >= w_ref_time:
|
||||
diff = (
|
||||
s.end_time - datetime.combine(current_date, w_ref_time)
|
||||
).total_seconds() / 60.0
|
||||
wakeups.append(int(diff))
|
||||
if wakeups:
|
||||
wakeup_min = min(wakeups)
|
||||
|
||||
# Find last bedtime before bedtime_ref
|
||||
bedtimes = []
|
||||
for s in day_sessions:
|
||||
if s.start_time.time() <= b_ref_time:
|
||||
diff = (
|
||||
s.start_time - datetime.combine(current_date, b_ref_time)
|
||||
).total_seconds() / 60.0
|
||||
bedtimes.append(int(diff))
|
||||
if bedtimes:
|
||||
bedtime_min = max(bedtimes)
|
||||
midnight_today = datetime.combine(current_date, time(0, 0))
|
||||
|
||||
night_session = None
|
||||
for s in sessions:
|
||||
# A session that runs over midnight into current_date
|
||||
if s.start_time < midnight_today and s.end_time and s.end_time >= midnight_today:
|
||||
night_session = s
|
||||
break
|
||||
|
||||
if night_session:
|
||||
# Bedtime offset from b_ref_time on the day it started
|
||||
s_start_date = night_session.start_time.date()
|
||||
ref_datetime_bedtime = datetime.combine(s_start_date, b_ref_time)
|
||||
bedtime_min = int((night_session.start_time - ref_datetime_bedtime).total_seconds() / 60.0)
|
||||
|
||||
# Wakeup offset from w_ref_time on the current day
|
||||
ref_datetime_wakeup = datetime.combine(current_date, w_ref_time)
|
||||
wakeup_min = int((night_session.end_time - ref_datetime_wakeup).total_seconds() / 60.0)
|
||||
|
||||
days_data.append(
|
||||
{
|
||||
|
||||
@@ -18,8 +18,8 @@ interface WakeupBedtimeProps {
|
||||
bedtime_ref: string;
|
||||
}
|
||||
|
||||
const BedtimePlot: React.FC<WakeupBedtimeProps> = ({ from_date, to_date, bedtime_ref }) => {
|
||||
const { wakeupBedtime, isLoading } = useStats(from_date, to_date, '07:00', '20:00');
|
||||
const BedtimePlot: React.FC<WakeupBedtimeProps> = ({ from_date, to_date, wakeup_ref, bedtime_ref }) => {
|
||||
const { wakeupBedtime, isLoading } = useStats(from_date, to_date, '07:00', '20:00', wakeup_ref, bedtime_ref);
|
||||
const [chartData, setChartData] = useState<{ date: string; minutes: number; time: string }[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -40,9 +40,9 @@ const DailySummary: React.FC<DailySummaryProps> = ({ from_date, to_date, day_sta
|
||||
|
||||
const data = dailySummary.days.map((day) => ({
|
||||
date: day.date,
|
||||
daySleep: day.day_minutes,
|
||||
nightSleep: day.night_minutes,
|
||||
total: day.total_minutes,
|
||||
daySleep: day.day_minutes / 60,
|
||||
nightSleep: day.night_minutes / 60,
|
||||
total: day.total_minutes / 60,
|
||||
}));
|
||||
|
||||
setChartData(data.reverse());
|
||||
@@ -58,9 +58,9 @@ const DailySummary: React.FC<DailySummaryProps> = ({ from_date, to_date, day_sta
|
||||
);
|
||||
const count = data.length;
|
||||
setAvgStats({
|
||||
avgTotal: Math.round(totals.total / count),
|
||||
avgDay: Math.round(totals.day / count),
|
||||
avgNight: Math.round(totals.night / count),
|
||||
avgTotal: totals.total / count,
|
||||
avgDay: totals.day / count,
|
||||
avgNight: totals.night / count,
|
||||
count,
|
||||
});
|
||||
}
|
||||
@@ -81,7 +81,12 @@ const DailySummary: React.FC<DailySummaryProps> = ({ from_date, to_date, day_sta
|
||||
margin={{ top: 5, right: 30, left: 60, bottom: 5 }}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
|
||||
<XAxis type="number" tick={{ fontSize: 12 }} tickLine={false} />
|
||||
<XAxis
|
||||
type="number"
|
||||
tickFormatter={(value) => `${Math.round(value)}h`}
|
||||
tick={{ fontSize: 12 }}
|
||||
tickLine={false}
|
||||
/>
|
||||
<YAxis
|
||||
type="category"
|
||||
dataKey="date"
|
||||
@@ -91,7 +96,7 @@ const DailySummary: React.FC<DailySummaryProps> = ({ from_date, to_date, day_sta
|
||||
/>
|
||||
<Tooltip
|
||||
formatter={(value: number, name: string) => [
|
||||
formatMinutes(value),
|
||||
formatMinutes(Math.round(value * 60)),
|
||||
name === 'daySleep' ? 'Day' : 'Night',
|
||||
]}
|
||||
/>
|
||||
@@ -102,15 +107,15 @@ const DailySummary: React.FC<DailySummaryProps> = ({ from_date, to_date, day_sta
|
||||
<div className="mt-4 grid grid-cols-3 gap-4 text-center">
|
||||
<div className="p-3 bg-gray-50 rounded-lg">
|
||||
<div className="text-xs text-gray-500">Avg Total</div>
|
||||
<div className="text-lg font-semibold text-gray-800">{formatMinutes(avgStats.avgTotal)}</div>
|
||||
<div className="text-lg font-semibold text-gray-800">{formatMinutes(Math.round(avgStats.avgTotal * 60))}</div>
|
||||
</div>
|
||||
<div className="p-3 bg-gray-50 rounded-lg">
|
||||
<div className="text-xs text-gray-500">Avg Day</div>
|
||||
<div className="text-lg font-semibold text-gray-800">{formatMinutes(avgStats.avgDay)}</div>
|
||||
<div className="text-lg font-semibold text-gray-800">{formatMinutes(Math.round(avgStats.avgDay * 60))}</div>
|
||||
</div>
|
||||
<div className="p-3 bg-gray-50 rounded-lg">
|
||||
<div className="text-xs text-gray-500">Avg Night</div>
|
||||
<div className="text-lg font-semibold text-gray-800">{formatMinutes(avgStats.avgNight)}</div>
|
||||
<div className="text-lg font-semibold text-gray-800">{formatMinutes(Math.round(avgStats.avgNight * 60))}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,8 +18,8 @@ interface WakeupBedtimeProps {
|
||||
bedtime_ref: string;
|
||||
}
|
||||
|
||||
const WakeupPlot: React.FC<WakeupBedtimeProps> = ({ from_date, to_date, wakeup_ref }) => {
|
||||
const { wakeupBedtime, isLoading } = useStats(from_date, to_date, '07:00', '20:00');
|
||||
const WakeupPlot: React.FC<WakeupBedtimeProps> = ({ from_date, to_date, wakeup_ref, bedtime_ref }) => {
|
||||
const { wakeupBedtime, isLoading } = useStats(from_date, to_date, '07:00', '20:00', wakeup_ref, bedtime_ref);
|
||||
const [chartData, setChartData] = useState<{ date: string; minutes: number; time: string }[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Investigation Plan: Bedtime Graph Issue
|
||||
|
||||
## Objective
|
||||
Investigate why the "Bedtime" graph shows unexpected times when a specific `bedtime_ref` is set.
|
||||
|
||||
## Current Understanding
|
||||
- The `BedtimePlot.tsx` component displays a graph where the Y-axis (or values) are formatted using `formatMinutesAfter(value, bedtime_ref)`.
|
||||
- The data comes from the `/api/stats/wake-sleep-times` endpoint.
|
||||
- The backend calculates `bedtime_minutes` based on sessions that started on or before the `bedtime_ref`.
|
||||
|
||||
## Investigation Steps
|
||||
|
||||
### Step 1: Analyze Backend Logic
|
||||
- [ ] Examine `get_wake_sleep_times` in `backend/app/routers/stats.py` to understand how `bedtime_minutes` is calculated.
|
||||
- [ ] Verify if the logic correctly identifies "bedtime" for various sleep session scenarios (e.g., sessions crossing midnight).
|
||||
- [ ] Identify potential edge cases where the `s.start_time.time() <= b_ref_time` condition might be problematic.
|
||||
|
||||
### Step 2: Analyze Frontend Logic
|
||||
- [ ] Examine `BedtimePlot.tsx` and `useStats.ts` to see how the data is consumed and formatted.
|
||||
- [ ] Understand how `formatMinutesAfter` interacts with the values returned by the backend.
|
||||
|
||||
### Step 3: Data Simulation & Verification
|
||||
- [ ] Create a set of test cases (mocked data) representing different sleep scenarios.
|
||||
- [ ] Manually calculate the expected `bedtime_minutes` for these scenarios using the current logic.
|
||||
- [ ] Compare with what the user reported to confirm the bug's nature.
|
||||
|
||||
### Step 4: Propose and Implement Fixes
|
||||
- [ ] Refine the backend logic to better represent "bedtime" if current logic is insufficient.
|
||||
- [ ] Ensure the frontend correctly displays the intended time.
|
||||
- [ ] Verify that changes do not break other parts of the stats page (e.g., Wakeup times).
|
||||
|
||||
## Future Tasks
|
||||
- [ ] Run tests to ensure correctness after implementation.
|
||||
- [ ] Finalize documentation/explanation of the fix.
|
||||
Reference in New Issue
Block a user