From 9e9417f937d926ac262b1436d8da5fbeff9f6921 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Thu, 27 Aug 2026 11:48:42 +0300 Subject: [PATCH] fix: Rewrite getConversations query to guarantee all students appear for teacher without complex join dependencies --- backend/app/Controllers/ChatController.php | 109 +++++++++------------ backend/app/Views/TeacherPortal.php | 10 ++ 2 files changed, 59 insertions(+), 60 deletions(-) diff --git a/backend/app/Controllers/ChatController.php b/backend/app/Controllers/ChatController.php index 91f116e..3010a6a 100644 --- a/backend/app/Controllers/ChatController.php +++ b/backend/app/Controllers/ChatController.php @@ -69,84 +69,73 @@ class ChatController self::ensureSeedUsers(); $userId = (int)$request->user_id; - $userRole = (string)($request->role ?? 'student'); - // 1. Fetch users with conversation history - $activeConvs = []; + // 1. Fetch all other users in the system + $users = []; try { - $rows = Database::select(" - SELECT - u.id as user_id, - u.uuid as user_uuid, - u.full_name as encrypted_name, - u.role as user_role, - tp.specialization, - m.message as last_message, - m.message_type as last_message_type, - m.created_at as last_message_at, - (SELECT COUNT(*) FROM chat_messages WHERE sender_id = u.id AND receiver_id = ? AND is_read = 0) as unread_count + $users = Database::select(" + SELECT u.id as user_id, u.uuid as user_uuid, u.full_name as encrypted_name, u.role as user_role, tp.specialization FROM users u LEFT JOIN teacher_profiles tp ON tp.user_id = u.id - JOIN chat_messages m ON m.id = ( - SELECT MAX(id) FROM chat_messages - WHERE (sender_id = ? AND receiver_id = u.id) OR (sender_id = u.id AND receiver_id = ?) - ) WHERE u.id != ? - ORDER BY m.created_at DESC - ", [$userId, $userId, $userId, $userId]); - $activeConvs = $rows ?: []; - } catch (\Exception $e) { - error_log("Active convs query note: " . $e->getMessage()); - } - - $existingUserIds = array_column($activeConvs, 'user_id'); - $existingUserIds[] = $userId; - - // 2. Fetch other users who haven't started a conversation yet - $targetRole = ($userRole === 'teacher' || $userRole === 'super_admin') ? 'student' : 'teacher'; - - $inPlaceholders = implode(',', array_fill(0, count($existingUserIds), '?')); - $otherUsers = []; - try { - $otherUsers = Database::select(" - SELECT - u.id as user_id, - u.uuid as user_uuid, - u.full_name as encrypted_name, - u.role as user_role, - tp.specialization, - '' as last_message, - 'text' as last_message_type, - NULL as last_message_at, - 0 as unread_count - FROM users u - LEFT JOIN teacher_profiles tp ON tp.user_id = u.id - WHERE u.role = ? AND u.id NOT IN ({$inPlaceholders}) ORDER BY u.id DESC - LIMIT 50 - ", array_merge([$targetRole], $existingUserIds)); + LIMIT 100 + ", [$userId]); } catch (\Exception $e) { - error_log("Other users query note: " . $e->getMessage()); + error_log("Users select in getConversations error: " . $e->getMessage()); } - $allRows = array_merge($activeConvs, $otherUsers ?: []); + $conversations = []; + foreach ($users as $row) { + $otherId = (int)$row['user_id']; + + // Get latest message between $userId and $otherId + $lastMsg = null; + $unreadCount = 0; + try { + $lastMsg = Database::selectOne(" + SELECT message, message_type, created_at + FROM chat_messages + WHERE (sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?) + ORDER BY id DESC + LIMIT 1 + ", [$userId, $otherId, $otherId, $userId]); + + $unreadRow = Database::selectOne(" + SELECT COUNT(*) as cnt + FROM chat_messages + WHERE sender_id = ? AND receiver_id = ? AND is_read = 0 + ", [$otherId, $userId]); + $unreadCount = (int)($unreadRow['cnt'] ?? 0); + } catch (\Exception $e) { + // Ignore per-user message query issue if any + } - $conversations = array_map(function ($row) { $rawName = (string)($row['encrypted_name'] ?? ''); $decryptedName = Security::decrypt($rawName) ?: $rawName; - return [ - 'user_id' => (int)$row['user_id'], + $conversations[] = [ + 'user_id' => $otherId, 'user_uuid' => $row['user_uuid'] ?? '', 'full_name' => $decryptedName ?: ($row['user_role'] === 'teacher' ? 'الأستاذ حمزة الغويري' : 'طالب صَقِل'), 'role' => $row['user_role'] ?? 'student', 'specialization' => $row['specialization'] ?? ($row['user_role'] === 'teacher' ? 'الرياضيات العلمي' : null), - 'last_message' => $row['last_message'] ?: ($row['user_role'] === 'teacher' ? 'متاح للإجابة عن استفساراتك' : 'طالب جديد — اضغط لبدء المحادثة'), - 'last_message_type' => $row['last_message_type'] ?? 'text', - 'last_message_at' => $row['last_message_at'] ?? null, - 'unread_count' => (int)($row['unread_count'] ?? 0), + 'last_message' => $lastMsg['message'] ?? ($row['user_role'] === 'teacher' ? 'متاح للإجابة عن استفساراتك' : 'طالب جديد — اضغط لبدء المحادثة'), + 'last_message_type' => $lastMsg['message_type'] ?? 'text', + 'last_message_at' => $lastMsg['created_at'] ?? null, + 'unread_count' => $unreadCount, ]; - }, $allRows); + } + + // Sort: users with active messages first, then by last_message_at DESC + usort($conversations, function ($a, $b) { + if ($a['last_message_at'] && !$b['last_message_at']) return -1; + if (!$a['last_message_at'] && $b['last_message_at']) return 1; + if ($a['last_message_at'] && $b['last_message_at']) { + return strcmp($b['last_message_at'], $a['last_message_at']); + } + return $b['user_id'] <=> $a['user_id']; + }); $response->json([ 'status' => 'success', diff --git a/backend/app/Views/TeacherPortal.php b/backend/app/Views/TeacherPortal.php index 916fe93..bf49d7b 100644 --- a/backend/app/Views/TeacherPortal.php +++ b/backend/app/Views/TeacherPortal.php @@ -671,9 +671,19 @@ class TeacherPortal const data = await res.json(); if (res.ok && data.status === 'success') { renderConversations(data.data); + } else { + console.warn('Load convs returned:', data); + const container = document.getElementById('conv_list_container'); + if (container) { + container.innerHTML = '
' + (data.message || 'لا توجد محادثات نشطة') + '
'; + } } } catch (e) { console.error('Load convs error:', e); + const container = document.getElementById('conv_list_container'); + if (container) { + container.innerHTML = '
تعذر تحميل المحادثات (خطأ في الاتصال)
'; + } } }