authorize('view', $website); return view('annotations.index', [ 'website' => $website, 'annotations' => $website->annotations()->with('user')->orderByDesc('date')->paginate(25), ]); } public function store(Request $request, Website $website): RedirectResponse|JsonResponse { $this->authorize('view', $website); $validated = $request->validate([ 'date' => 'required|date', 'text' => 'required|string|max:500', 'category' => 'required|in:' . implode(',', array_keys(Annotation::$categories)), ]); $annotation = $website->annotations()->create([ ...$validated, 'user_id' => $request->user()->id, ]); if ($request->expectsJson()) { return response()->json($annotation->load('user'), 201); } return redirect() ->route('annotations.index', $website) ->with('success', 'Annotation added.'); } public function destroy(Request $request, Website $website, Annotation $annotation): RedirectResponse|JsonResponse { $this->authorize('view', $website); $annotation->delete(); if ($request->expectsJson()) { return response()->json(['ok' => true]); } return redirect() ->route('annotations.index', $website) ->with('success', 'Annotation deleted.'); } /** * JSON endpoint for chart overlays — returns annotations within a date range. */ public function forRange(Request $request, Website $website): JsonResponse { $this->authorize('view', $website); $request->validate([ 'from' => 'required|date', 'to' => 'required|date|after_or_equal:from', ]); $annotations = $website->annotations() ->with('user:id,name') ->whereBetween('date', [$request->from, $request->to]) ->orderBy('date') ->get() ->map(fn (Annotation $a) => [ 'id' => $a->id, 'date' => $a->date->toDateString(), 'text' => $a->text, 'category' => $a->category, 'user' => $a->user->name, ]); return response()->json($annotations); } }