orderByDesc('created_at') ->limit(50) ->get(); $stats = [ 'total' => UserNotification::count(), 'unread' => UserNotification::whereNull('read_at')->count(), 'users' => User::count(), 'today' => UserNotification::whereDate('created_at', today())->count(), ]; return view('admin.notifications.index', compact('recent', 'stats')); } public function send(Request $request) { $data = $request->validate([ 'title' => 'required|string|max:100', 'body' => 'required|string|max:500', 'url' => 'nullable|url|max:300', 'target' => 'required|in:all,premium,free', 'icon' => 'nullable|string|max:50', ]); $query = User::query(); if ($data['target'] === 'premium') { $query->where('membership', 'premium') ->where(fn($q) => $q->whereNull('premium_expires_at')->orWhere('premium_expires_at', '>', now())); } elseif ($data['target'] === 'free') { $query->where(fn($q) => $q->where('membership', '!=', 'premium')->orWhere('premium_expires_at', '<=', now())); } $users = $query->select('id', 'fcm_token')->get(); if ($users->isEmpty()) { return back()->with('error', 'Hedef kullanıcı bulunamadı.'); } $notifData = json_encode([ 'title' => $data['title'], 'body' => $data['body'], 'url' => $data['url'] ?? null, 'icon' => $data['icon'] ?? 'bi-megaphone-fill', 'admin' => true, ]); $now = now(); $rows = $users->map(fn($u) => [ 'user_id' => $u->id, 'type' => 'admin', 'data' => $notifData, 'created_at' => $now, ])->toArray(); // In-app notifications foreach (array_chunk($rows, 500) as $chunk) { UserNotification::insert($chunk); } // FCM Push notifications $fcmTokens = $users->pluck('fcm_token')->filter()->values()->toArray(); if (!empty($fcmTokens)) { $fcm = new FcmService(); $fcm->sendToTokens($fcmTokens, $data['title'], $data['body'], [ 'type' => 'admin', 'url' => $data['url'] ?? '', ]); } return back()->with('success', count($rows) . ' kullanıcıya bildirim gönderildi' . (!empty($fcmTokens) ? ' (' . count($fcmTokens) . ' push)' : '') . '.'); } }