where('username', $username) ->first(); if (!$user) { abort(404, 'User not found'); } $auth = Auth::user(); $authId = $auth?->id; $likesCount = ProfileLike::where('profile_id', $user->id)->count(); $hasLiked = $authId ? ProfileLike::where('profile_id', $user->id)->where('user_id', $authId)->exists() : false; $comments = ProfileComment::with(['user:id,username,avatar']) ->where('profile_id', $user->id) ->latest() ->limit(20) ->get() ->map(function ($c) { return [ 'id' => $c->id, 'user' => [ 'id' => $c->user->id, 'username' => $c->user->username, 'avatar' => $c->user->avatar, ], 'content' => $c->content, 'created_at' => $c->created_at, ]; }); // Friendship flags $isFriend = false; $isPending = false; // I sent them a request (outgoing) $theyRequestedMe = false; // They sent me a request (incoming — I can accept/decline) $friendRowId = null; if ($authId) { $friendRow = Friend::where(function ($q) use ($authId, $user) { $q->where('user_id', $authId)->where('friend_id', $user->id); })->orWhere(function ($q) use ($authId, $user) { $q->where('user_id', $user->id)->where('friend_id', $authId); })->first(); if ($friendRow) { $isFriend = $friendRow->status === 'accepted'; $isPending = $friendRow->status === 'pending' && $friendRow->user_id == $authId; $theyRequestedMe = $friendRow->status === 'pending' && $friendRow->user_id == $user->id; $friendRowId = $friendRow->id; } } $profile = [ 'id' => $user->id, 'username' => $user->username, 'avatar' => $user->avatar ?? $user->avatar_url, 'banner' => $user->banner, 'bio' => $user->bio, 'vip_level' => (int) ($user->vip_level ?? 0), 'role' => $user->role ?? 'User', 'clan_tag' => $user->clan_tag, 'stats' => [ 'wagered' => (float) ($user->stats?->total_wagered ?? 0), 'wins' => (int) ($user->stats?->total_wins ?? 0), 'losses' => null, 'biggest_win' => (float) ($user->stats?->biggest_win ?? 0), 'biggest_win_game' => $user->stats?->biggest_win_game ?? null, 'join_date' => optional($user->created_at)->toDateString(), 'likes_count' => $likesCount, ], 'best_wins' => [], 'comments' => $comments, ]; return Inertia::render('Social/Profile', [ 'profile' => $profile, 'isOwnProfile' => $authId ? ((int)$authId === (int)$user->id) : false, 'isFriend' => $isFriend, 'isPending' => $isPending, 'theyRequestedMe' => $theyRequestedMe, 'friendRowId' => $friendRowId, 'hasLiked' => $hasLiked, ]); } // Update own profile public function update(Request $request) { $user = Auth::user(); abort_unless($user, 403); $data = $request->validate([ 'is_public' => 'boolean', 'bio' => 'nullable|string|max:160', 'avatar' => 'nullable|string', 'banner' => 'nullable|string', ]); $user->fill([ 'is_public' => (bool) ($data['is_public'] ?? $user->is_public), 'bio' => $data['bio'] ?? $user->bio, 'avatar' => $data['avatar'] ?? $user->avatar, 'banner' => $data['banner'] ?? $user->banner, ])->save(); return back()->with('success', 'Profile updated.'); } // Upload avatar or banner public function uploadImage(Request $request) { $user = Auth::user(); abort_unless($user, 403); $request->validate([ 'type' => 'required|in:avatar,banner', 'file' => 'required|file|mimes:jpeg,jpg,png,gif,webp,bmp|max:5120', ]); $file = $request->file('file'); $type = $request->input('type'); $path = $file->store("profile/{$type}s", 'public'); $url = Storage::disk('public')->url($path); if ($type === 'banner') { $user->banner = $url; } else { $user->avatar = $url; } $user->save(); return response()->json(['url' => $url], 200); } // Toggle like on a profile public function like($id) { $me = Auth::user(); abort_unless($me, 403); $target = User::findOrFail($id); if ($target->id === $me->id) { return back(); } $like = ProfileLike::where('user_id', $me->id)->where('profile_id', $target->id)->first(); if ($like) { $like->delete(); } else { ProfileLike::create(['user_id' => $me->id, 'profile_id' => $target->id]); } return back(); } // Add a comment to a profile public function comment(Request $request, $id) { $me = Auth::user(); abort_unless($me, 403); $data = $request->validate(['content' => 'required|string|max:500']); $target = User::findOrFail($id); ProfileComment::create([ 'user_id' => $me->id, 'profile_id' => $target->id, 'content' => $data['content'], ]); return back()->with('success', 'Comment posted.'); } // Report a profile public function report(Request $request, $id) { $me = Auth::user(); abort_unless($me, 403); $data = $request->validate([ 'reason' => 'required|string', 'details' => 'nullable|string', 'snapshot' => 'nullable|array', 'screenshot' => 'nullable|string', ]); $target = User::findOrFail($id); $screenshotPath = null; if (!empty($data['screenshot'])) { $base64 = $data['screenshot']; // Strip data URI prefix if present if (str_contains($base64, ',')) { $base64 = explode(',', $base64, 2)[1]; } $decoded = base64_decode($base64, true); if ($decoded !== false) { $filename = 'reports/profile-screenshots/' . $target->id . '_' . time() . '.png'; Storage::disk('public')->put($filename, $decoded); $screenshotPath = $filename; } } ProfileReport::create([ 'reporter_id' => $me->id, 'profile_id' => $target->id, 'reason' => $data['reason'], 'details' => $data['details'] ?? null, 'snapshot' => $data['snapshot'] ?? null, 'screenshot_path' => $screenshotPath, ]); if ($request->expectsJson()) { return response()->json(['success' => true]); } return back()->with('success', 'Profile reported.'); } // User search public function search(Request $request) { $q = (string) $request->input('q', ''); if (strlen($q) < 1) return response()->json([]); $users = User::query() ->where('username', 'like', "%" . str_replace(['%','_'], ['\\%','\\_'], $q) . "%") ->orWhere('id', '=', $q) ->orderBy('username') ->limit(10) ->get(['id', 'username', 'avatar', 'avatar_url', 'vip_level', 'balance']); $out = $users->map(function ($u) { return [ 'id' => $u->id, 'username' => $u->username, 'avatar' => $u->avatar ?? $u->avatar_url, 'avatar_url' => $u->avatar_url ?? $u->avatar, 'vip_level' => (int) ($u->vip_level ?? 0), 'stats' => [ 'wager' => 0, // Placeholder 'wins' => 0, // Placeholder 'balance' => $u->balance ] ]; }); return response()->json($out->all(), 200); } // Send a tip (balance transfer) and record it public function tip(Request $request, $id) { $sender = Auth::user(); abort_unless($sender, 403); $data = $request->validate([ 'currency' => 'required|string|max:10', 'amount' => 'required|numeric|min:0.00000001', 'note' => 'nullable|string|max:140', ]); if ((int)$id === (int)$sender->id) { return back()->withErrors(['amount' => 'You cannot tip yourself.']); } $receiver = User::findOrFail($id); $amount = (float) $data['amount']; if ($sender->balance < $amount) { return back()->withErrors(['amount' => 'Insufficient balance']); } DB::transaction(function () use ($sender, $receiver, $amount, $data) { // Simple balance transfer using users.balance $sender->balance = (float) $sender->balance - $amount; $receiver->balance = (float) $receiver->balance + $amount; $sender->save(); $receiver->save(); Tip::create([ 'from_user_id' => $sender->id, 'to_user_id' => $receiver->id, 'currency' => strtoupper($data['currency']), 'amount' => $amount, 'note' => $data['note'] ?? null, ]); }); return back()->with('success', 'Tip sent successfully.'); } // --- Friends --- public function requestFriend(Request $request) { $me = Auth::user(); abort_unless($me, 403); $data = $request->validate([ 'user_id' => 'required|integer', ]); $targetId = (int) $data['user_id']; if ($targetId === (int)$me->id) { return back()->withErrors(['friend' => 'You cannot add yourself.']); } $target = User::findOrFail($targetId); $existing = Friend::where('user_id', $me->id)->where('friend_id', $target->id)->first(); if ($existing) { if ($existing->status === 'pending') { return back()->with('success', 'Friend request already sent.'); } if ($existing->status === 'accepted') { return back()->with('success', 'You are already friends.'); } } Friend::updateOrCreate([ 'user_id' => $me->id, 'friend_id' => $target->id, ], [ 'status' => 'pending' ]); return back()->with('success', 'Friend request sent.'); } public function acceptFriend($id) { $me = Auth::user(); abort_unless($me, 403); $requestRow = Friend::where('user_id', $id)->where('friend_id', $me->id)->where('status', 'pending')->first(); if (!$requestRow) { return back()->withErrors(['friend' => 'Request not found.']); } DB::transaction(function () use ($requestRow, $me, $id) { $requestRow->status = 'accepted'; $requestRow->save(); // Ensure reciprocal row Friend::updateOrCreate([ 'user_id' => $me->id, 'friend_id' => (int) $id, ], [ 'status' => 'accepted' ]); }); return back()->with('success', 'Friend request accepted.'); } public function declineFriend($id) { $me = Auth::user(); abort_unless($me, 403); $requestRow = Friend::where('user_id', $id)->where('friend_id', $me->id)->where('status', 'pending')->first(); if (!$requestRow) { return back()->withErrors(['friend' => 'Request not found.']); } $requestRow->delete(); return back()->with('success', 'Friend request declined.'); } public function hub() { return Inertia::render('Social/Hub'); } public function me() { return Inertia::render('Social/Settings', [ 'user' => Auth::user(), ]); } }