get(); $grouped = $activeStories->groupBy('user_id')->map(function ($items) { $first = $items->first(); return [ 'username' => $first->username, 'profile_pic_url' => $first->profile_pic_url, 'is_unread' => $items->contains(fn ($item) => $item->viewed_at === null), 'muted' => $first->muted, 'soonest_expiring_at' => $items->min('expiring_at'), ]; }); $sorted = $grouped ->sortBy(fn ($s) => [$s['muted'] ? 1 : 0, $s['is_unread'] ? 0 : 1, $s['soonest_expiring_at']]) ->values() ->map(fn ($s) => [ 'username' => $s['username'], 'profile_pic_url' => $s['profile_pic_url'], 'is_unread' => $s['is_unread'], 'muted' => $s['muted'], ]); return response()->json($sorted); } public function show(string $username): JsonResponse { $items = Story::where('username', $username)->active()->orderBy('taken_at')->get(); if ($items->isEmpty()) { return response()->json(['message' => 'No active story found.'], 404); } $firstUnread = $items->first(fn ($item) => $item->viewed_at === null); $startIndex = $firstUnread ? $items->search(fn ($item) => $item->id === $firstUnread->id) : 0; return response()->json([ 'username' => $username, 'profile_pic_url' => $items->first()->profile_pic_url, 'start_index' => $startIndex, 'items' => $items->map(fn (Story $item) => [ 'id' => $item->id, 'code' => $item->code, 'is_video' => $item->is_video, 'image_url' => $item->image_url, 'video_url' => $item->video_url, 'accessibility_caption' => $item->accessibility_caption, 'taken_at' => $item->taken_at, ]), ]); } public function markViewed(string $id): JsonResponse { Story::where('id', $id)->update(['viewed_at' => now()]); return response()->json(['ok' => true]); } }