$u->id, 'username' => $u->username, 'name' => $u->name, 'avatar' => $u->avatar, 'avatar_url' => $u->avatar_url, ]; } private function formatMessage(DirectMessage $m): array { return [ 'id' => $m->id, 'message' => $m->is_deleted ? null : $m->message, 'sender_id' => $m->sender_id, 'is_deleted' => $m->is_deleted, 'is_read' => $m->is_read, 'created_at' => $m->created_at, 'user' => $m->sender ? $this->formatUser($m->sender) : null, 'reply_to' => $m->replyTo ? [ 'id' => $m->replyTo->id, 'message' => $m->replyTo->is_deleted ? null : $m->replyTo->message, 'sender_id' => $m->replyTo->sender_id, ] : null, ]; } // GET /api/dm/conversations public function conversations() { $me = Auth::id(); $sent = DirectMessage::where('sender_id', $me)->select('receiver_id as partner_id'); $received = DirectMessage::where('receiver_id', $me)->select('sender_id as partner_id'); $partnerIds = $sent->union($received)->pluck('partner_id')->unique()->values(); $conversations = $partnerIds->map(function ($pid) use ($me) { $partner = User::select('id', 'username', 'name', 'avatar', 'avatar_url')->find($pid); if (!$partner) return null; $lastMsg = DirectMessage::where(function ($q) use ($me, $pid) { $q->where('sender_id', $me)->where('receiver_id', $pid); })->orWhere(function ($q) use ($me, $pid) { $q->where('sender_id', $pid)->where('receiver_id', $me); })->orderByDesc('created_at')->first(); $unread = DirectMessage::where('sender_id', $pid) ->where('receiver_id', $me) ->where('is_read', false) ->count(); return [ 'partner' => $this->formatUser($partner), 'last_message' => $lastMsg ? [ 'id' => $lastMsg->id, 'message' => $lastMsg->is_deleted ? null : $lastMsg->message, 'sender_id' => $lastMsg->sender_id, 'created_at' => $lastMsg->created_at, ] : null, 'unread_count' => $unread, ]; })->filter()->sortByDesc(fn ($c) => optional($c['last_message'])['created_at'])->values(); return response()->json(['data' => $conversations]); } // GET /api/dm/{userId} public function messages($userId) { $me = Auth::id(); $msgs = DirectMessage::where(function ($q) use ($me, $userId) { $q->where('sender_id', $me)->where('receiver_id', $userId); })->orWhere(function ($q) use ($me, $userId) { $q->where('sender_id', $userId)->where('receiver_id', $me); }) ->with(['sender:id,username,name,avatar,avatar_url', 'replyTo']) ->orderBy('created_at') ->limit(100) ->get() ->map(fn ($m) => $this->formatMessage($m)); // Mark as read DirectMessage::where('sender_id', $userId) ->where('receiver_id', $me) ->where('is_read', false) ->update(['is_read' => true]); return response()->json(['data' => $msgs]); } // POST /api/dm/{userId} public function send(Request $request, $userId) { $me = Auth::id(); $request->validate([ 'message' => 'required|string|max:1000', 'reply_to_id' => 'nullable|integer|exists:direct_messages,id', ]); User::findOrFail($userId); $areFriends = Friend::where(function ($q) use ($me, $userId) { $q->where('user_id', $me)->where('friend_id', $userId); })->orWhere(function ($q) use ($me, $userId) { $q->where('user_id', $userId)->where('friend_id', $me); })->where('status', 'accepted')->exists(); if (!$areFriends) { return response()->json(['error' => 'You must be friends to send messages.'], 403); } $msg = DirectMessage::create([ 'sender_id' => $me, 'receiver_id' => $userId, 'message' => $request->message, 'reply_to_id' => $request->reply_to_id, ]); $msg->load(['sender:id,username,name,avatar,avatar_url', 'replyTo']); return response()->json(['data' => $this->formatMessage($msg)], 201); } // POST /api/dm/messages/{id}/report public function report(Request $request, $messageId) { $me = Auth::id(); $request->validate([ 'reason' => 'required|string|max:64', 'details' => 'nullable|string|max:500', ]); $msg = DirectMessage::where(function ($q) use ($me) { $q->where('sender_id', $me)->orWhere('receiver_id', $me); })->findOrFail($messageId); DirectMessageReport::firstOrCreate( ['reporter_id' => $me, 'message_id' => $msg->id], ['reason' => $request->reason, 'details' => $request->details] ); return response()->json(['ok' => true]); } // GET /api/friends public function friends() { $me = Auth::id(); $friends = Friend::where(function ($q) use ($me) { $q->where('user_id', $me)->orWhere('friend_id', $me); })->where('status', 'accepted') ->with(['user:id,username,name,avatar,avatar_url', 'friend:id,username,name,avatar,avatar_url']) ->get() ->map(function ($f) use ($me) { $partner = $f->user_id === $me ? $f->friend : $f->user; return $partner ? $this->formatUser($partner) : null; })->filter()->values(); return response()->json(['data' => $friends]); } // GET /api/friends/requests public function friendRequests() { $me = Auth::id(); $requests = Friend::where('friend_id', $me) ->where('status', 'pending') ->with('user:id,username,name,avatar,avatar_url') ->orderByDesc('created_at') ->get() ->map(fn ($f) => [ 'id' => $f->id, 'from' => $f->user ? $this->formatUser($f->user) : null, 'created_at' => $f->created_at, ])->filter(fn ($r) => $r['from'] !== null)->values(); return response()->json(['data' => $requests]); } }