conversations() ->with(['participants', 'lastMessage.user']) ->orderByDesc('conversations.updated_at') ->limit(50) ->get() ->map(function ($conv) use ($user) { $other = $conv->participants->firstWhere('id', '!=', $user->id); $last = $conv->lastMessage; $unread = $conv->unreadCountFor($user->id); $preview = null; if ($last) { if (str_starts_with($last->body, 'IMAGE::')) $preview = '📷 Fotoğraf'; elseif (str_starts_with($last->body, 'GIF::')) $preview = '🎞 GIF'; elseif (str_starts_with($last->body, 'ANIMESHARE::')) { try { $sd = json_decode(substr($last->body, 12), true); $preview = '🎬 ' . ($sd['title'] ?? 'Anime'); } catch (\Throwable) {} } else { $isMine = $last->user_id === $user->id; $preview = ($isMine ? 'Sen: ' : '') . \Illuminate\Support\Str::limit($last->body, 60); } } return [ 'id' => $conv->id, 'other_user' => $other ? [ 'id' => $other->id, 'name' => $other->name, 'username' => $other->username, 'avatar' => $other->avatar ? \App\Support\MediaUrl::fromStoragePath($other->avatar) : null, ] : null, 'last_message' => $last ? [ 'body' => $preview ?? '', 'user_id' => $last->user_id, 'created_at' => $last->created_at?->toISOString(), ] : null, 'unread_count' => $unread, 'updated_at' => $conv->updated_at?->toISOString(), ]; }); return response()->json(['conversations' => $convs]); } // GET /api/messages/{conversation} — messages in a conversation public function show(Conversation $conversation) { $user = Auth::user(); abort_unless($conversation->participants()->where('user_id', $user->id)->exists(), 403); $other = $conversation->participants()->where('user_id', '!=', $user->id)->first(); $messages = $conversation->messages() ->with('user') ->orderBy('created_at') ->get() ->map(fn($m) => [ 'id' => $m->id, 'user_id' => $m->user_id, 'body' => $m->body, 'created_at' => $m->created_at?->toISOString(), 'author' => [ 'id' => $m->user?->id, 'name' => $m->user?->name, 'avatar' => $m->user?->avatar ? \App\Support\MediaUrl::fromStoragePath($m->user->avatar) : null, ], ]); // Mark as read $conversation->participants()->updateExistingPivot($user->id, ['last_read_at' => now()]); return response()->json([ 'messages' => $messages, 'other_user' => $other ? [ 'id' => $other->id, 'name' => $other->name, 'username' => $other->username, 'avatar' => $other->avatar ? \App\Support\MediaUrl::fromStoragePath($other->avatar) : null, ] : null, ]); } // POST /api/messages/{conversation} — send a message public function send(Request $request, Conversation $conversation) { $user = Auth::user(); abort_unless($conversation->participants()->where('user_id', $user->id)->exists(), 403); $request->validate(['body' => 'required|string|max:5000']); $message = Message::create([ 'conversation_id' => $conversation->id, 'user_id' => $user->id, 'body' => $request->body, ]); $conversation->touch(); $conversation->participants()->updateExistingPivot($user->id, ['last_read_at' => now()]); return response()->json([ 'id' => $message->id, 'user_id' => $user->id, 'body' => $message->body, 'created_at' => $message->created_at->toISOString(), 'author' => [ 'id' => $user->id, 'name' => $user->name, 'avatar' => $user->avatar ? \App\Support\MediaUrl::fromStoragePath($user->avatar) : null, ], ]); } // POST /api/messages/start/{user} — start or open conversation public function startConversation(User $user) { $me = Auth::user(); if ($me->id === $user->id) abort(422, 'Kendinize mesaj gönderemezsiniz.'); $conv = Conversation::whereHas('participants', fn($q) => $q->where('user_id', $me->id)) ->whereHas('participants', fn($q) => $q->where('user_id', $user->id)) ->first(); if (!$conv) { $conv = DB::transaction(function () use ($me, $user) { $c = Conversation::create(); $c->participants()->attach([$me->id, $user->id]); return $c; }); } return response()->json(['conversation_id' => $conv->id]); } // GET /api/messages/{conv}/poll?after={id} — poll for new messages (mobile) public function poll(Request $request, Conversation $conversation) { $user = Auth::user(); abort_unless($conversation->participants()->where('user_id', $user->id)->exists(), 403); $after = (int) $request->query('after', 0); $messages = $conversation->messages() ->with('user') ->where('id', '>', $after) ->orderBy('created_at') ->get() ->map(fn($m) => [ 'id' => $m->id, 'user_id' => $m->user_id, 'body' => $m->body, 'created_at' => $m->created_at?->toISOString(), 'author' => [ 'id' => $m->user?->id, 'name' => $m->user?->name, 'avatar' => $m->user?->avatar ? \App\Support\MediaUrl::fromStoragePath($m->user->avatar) : null, ], ]); $conversation->participants()->updateExistingPivot($user->id, ['last_read_at' => now()]); return response()->json(['messages' => $messages]); } }