user(); $period = $request->string('period', 'week')->toString(); [$from, $bucket, $format] = match ($period) { 'day' => [Carbon::today(), 'hour', 'H\h'], 'month' => [Carbon::now()->subDays(30), 'day', 'D'], 'quarter' => [Carbon::now()->subDays(90), 'week', '\SW'], default => [Carbon::now()->subDays(7), 'day', 'ddd'], }; $rows = $user->measurements() ->where('measured_at', '>=', $from) ->orderBy('measured_at') ->get(); $points = $rows->groupBy(fn ($m) => match ($bucket) { 'hour' => $m->measured_at->format('H'), 'day' => $m->measured_at->format('Y-m-d'), 'week' => $m->measured_at->isoWeek(), })->map(function ($group) use ($format) { $first = $group->first(); return [ 'l' => $first->measured_at->locale('fr')->isoFormat($format === 'ddd' ? 'dd' : ($format === '\SW' ? '[S]W' : ($format === 'D' ? 'D' : 'HH'))), 'v' => (int) round($group->avg('value')), ]; })->values(); $inRange = $rows->filter(fn ($m) => $m->value >= $user->target_min && $m->value <= $user->target_max); $stats = [ 'avg' => $rows->count() ? (int) round($rows->avg('value')) : null, 'in_range_pct' => $rows->count() ? (int) round(($inRange->count() / $rows->count()) * 100) : 0, 'min' => $rows->min('value') !== null ? (int) $rows->min('value') : null, 'max' => $rows->max('value') !== null ? (int) $rows->max('value') : null, ]; $history = $user->measurements() ->orderByDesc('measured_at') ->limit(8) ->get() ->map(fn ($m) => [ 'id' => $m->id, 'time' => $m->measured_at->isoFormat('HH:mm'), 'value' => (int) $m->value, 'context' => match ($m->context) { 'fasting' => 'À jeun', 'before_meal' => 'Avant repas', 'after_meal' => 'Après repas', 'bedtime' => 'Coucher', default => 'Autre', }, 'in_range' => $m->isInRange($user->target_min, $user->target_max), ]); return Inertia::render('Diabetix/Stats', [ 'period' => $period, 'points' => $points, 'stats' => $stats, 'history' => $history, 'target' => ['min' => (int) $user->target_min, 'max' => (int) $user->target_max], ]); } }