feat: stats

This commit is contained in:
2026-05-16 17:11:07 +02:00
parent d9e80f7603
commit 7b8ede2a1a
18 changed files with 254 additions and 53 deletions
+1 -3
View File
@@ -61,11 +61,10 @@ class AuthController extends Controller
$request->user()->currentAccessToken()->delete();
return response()->json([
'message' => 'Déconnecté avec succès'
'message' => 'Déconnecté avec succès',
])->withoutCookie('token');
}
public function me(): JsonResponse
{
$user = auth()->user();
@@ -99,5 +98,4 @@ class AuthController extends Controller
return response()->json(new UserResource($user->fresh()));
}
}
@@ -34,11 +34,13 @@ class DeviceTokenController extends Controller
],
], $deviceToken->wasRecentlyCreated ? 201 : 200);
}
public function notifs(): JsonResponse
{
auth()->user()->notify(new TestNotification());
auth()->user()->notify(new TestNotification);
return response()->json([
'message' => 'Notification envoyée'
'message' => 'Notification envoyée',
]);
}
@@ -3,12 +3,16 @@
namespace App\Http\Controllers;
use App\Http\Requests\MealPostsRequest;
use App\Http\Requests\MealPostStatsRequest;
use App\Http\Resources\MealPostsResource;
use App\Models\MealPosts;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Response;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
class MealPostController extends Controller
@@ -27,6 +31,40 @@ class MealPostController extends Controller
return MealPostsResource::collection($mealPosts);
}
public function stats(MealPostStatsRequest $request): JsonResponse
{
$validated = $request->validated();
$period = $validated['period'] ?? 'day';
$referenceDate = CarbonImmutable::createFromFormat('!Y-m-d', $validated['date'] ?? now()->toDateString());
[$startDate, $endDate] = match ($period) {
'week' => [
$referenceDate->startOfWeek(CarbonInterface::MONDAY),
$referenceDate->endOfWeek(CarbonInterface::SUNDAY),
],
default => [
$referenceDate->startOfDay(),
$referenceDate->endOfDay(),
],
};
$mealPosts = MealPosts::query()
->where('user_id', $request->user()->getKey())
->whereBetween('eaten_at', [$startDate, $endDate])
->get(['calories', 'proteins', 'carbs', 'fats', 'eaten_at']);
return response()->json([
'data' => [
'period' => $period,
'date' => $referenceDate->toDateString(),
'startDate' => $startDate->toDateString(),
'endDate' => $endDate->toDateString(),
'totals' => $this->getNutritionTotals($mealPosts),
'days' => $this->getDailyNutritionTotals($mealPosts, $startDate, $endDate),
],
]);
}
public function store(MealPostsRequest $request): JsonResponse
{
$mealPost = MealPosts::create([
@@ -85,4 +123,34 @@ class MealPostController extends Controller
return $data;
}
private function getDailyNutritionTotals(Collection $mealPosts, CarbonImmutable $startDate, CarbonImmutable $endDate): array
{
$days = [];
for ($date = $startDate; $date->lte($endDate); $date = $date->addDay()) {
$day = $date->toDateString();
$dayMealPosts = $mealPosts->filter(
fn (MealPosts $mealPost): bool => $mealPost->eaten_at->toDateString() === $day
);
$days[] = [
'date' => $day,
'totals' => $this->getNutritionTotals($dayMealPosts),
];
}
return $days;
}
private function getNutritionTotals(Collection $mealPosts): array
{
return [
'calories' => (int) $mealPosts->sum(fn (MealPosts $mealPost): int => (int) ($mealPost->calories ?? 0)),
'proteins' => round((float) $mealPosts->sum(fn (MealPosts $mealPost): float => (float) ($mealPost->proteins ?? 0)), 2),
'carbs' => round((float) $mealPosts->sum(fn (MealPosts $mealPost): float => (float) ($mealPost->carbs ?? 0)), 2),
'fats' => round((float) $mealPosts->sum(fn (MealPosts $mealPost): float => (float) ($mealPost->fats ?? 0)), 2),
'mealsCount' => $mealPosts->count(),
];
}
}
@@ -16,7 +16,7 @@ class AuthenticateWithCookie
public function handle(Request $request, Closure $next): Response
{
if ($request->hasCookie('token')) {
$request->headers->set('Authorization', 'Bearer ' . $request->cookie('token'));
$request->headers->set('Authorization', 'Bearer '.$request->cookie('token'));
}
return $next($request);
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class MealPostStatsRequest extends FormRequest
{
public function rules(): array
{
return [
'period' => ['sometimes', 'string', Rule::in(['day', 'week'])],
'date' => ['sometimes', 'date_format:Y-m-d'],
];
}
public function authorize(): bool
{
return true;
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ class MealPostsRequest extends FormRequest
{
return [
'image.max' => "L'image ne doit pas dépasser 4 Mo.",
'image_url.required_without' => "Ajoute une image au repas.",
'image_url.required_without' => 'Ajoute une image au repas.',
];
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ class RegisterRequest extends FormRequest
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8'],
'avatar' => ['sometimes', 'nullable', 'image', 'max:2048'],
'bio' => [ 'nullable', 'string']
'bio' => ['nullable', 'string'],
];
}
+1 -1
View File
@@ -19,7 +19,7 @@ class UserResource extends JsonResource
'name' => $this->name,
'email' => $this->email,
'avatarUrl' => $this->avatar_url ? asset(Storage::url($this->avatar_url)) : null,
'bio' => $this->bio
'bio' => $this->bio,
];
}
}