diff --git a/srcs/backend/services/friends.js b/srcs/backend/services/friends.js
index ad2f66b..a9de380 100644
--- a/srcs/backend/services/friends.js
+++ b/srcs/backend/services/friends.js
@@ -178,6 +178,29 @@ async function declineFriendRequest(userId, fromUserId) {
}
}
+/**
+ * Get list of friend IDs for a user (for quick lookup)
+ */
+async function getFriendIds(userId) {
+ try {
+ const result = await query(
+ `SELECT
+ CASE
+ WHEN f.id_user1 = $1 THEN f.id_user2
+ ELSE f.id_user1
+ END as friend_id
+ FROM friendship f
+ WHERE (f.id_user1 = $1 OR f.id_user2 = $1)
+ AND f.status = 'accepted'`,
+ [userId]
+ );
+ return result.rows.map(row => row.friend_id);
+ } catch (err) {
+ console.error('Get friend IDs error:', err);
+ return [];
+ }
+}
+
/**
* Remove a friend
*/
@@ -207,6 +230,7 @@ async function removeFriend(userId, friendId) {
export default {
getFriends,
+ getFriendIds,
getPendingRequests,
searchUsers,
sendFriendRequest,
diff --git a/srcs/backend/services/socket.js b/srcs/backend/services/socket.js
index d1b5229..6f5cea1 100644
--- a/srcs/backend/services/socket.js
+++ b/srcs/backend/services/socket.js
@@ -1,5 +1,6 @@
import jwt from 'jsonwebtoken';
import chatService from './global_chat.js';
+import friendsService from './friends.js';
function setupSocketIO(io)
{
@@ -21,11 +22,27 @@ function setupSocketIO(io)
}
});
- io.on('connection', (socket) =>
+ io.on('connection', async (socket) =>
{
console.log(`User connected: ${socket.user.username}`);
socket.join('general-chat');
+
+ // Send recent messages and friend IDs on connection
+ try {
+ const [recentMessages, friendIds] = await Promise.all([
+ chatService.getRecentMessages(50),
+ friendsService.getFriendIds(socket.user.userId)
+ ]);
+
+ socket.emit('chat-init', {
+ messages: recentMessages,
+ friendIds: friendIds
+ });
+ } catch (err) {
+ console.error('Error fetching initial data:', err);
+ }
+
socket.on('chat-message', async(data) =>
{
try
@@ -33,7 +50,8 @@ function setupSocketIO(io)
const message = await chatService.saveMessage(socket.user.userId, data.content);
socket.broadcast.to('general-chat').emit('chat-message',
{
- id:message.id,
+ id: message.id,
+ sender_id: socket.user.userId,
username: socket.user.username,
content: message.content,
created_at: message.created_at
diff --git a/srcs/frontend/src/global_chat.js b/srcs/frontend/src/global_chat.js
index 7983b12..b2b121b 100644
--- a/srcs/frontend/src/global_chat.js
+++ b/srcs/frontend/src/global_chat.js
@@ -16,6 +16,7 @@ export class GlobalChat extends Window {
this.socket = null;
this.connected = false;
+ this.friendIds = new Set();
this.buildUI();
this.bindEvents();
@@ -100,15 +101,17 @@ export class GlobalChat extends Window {
* @param {string} username - User name
* @param {string} content - Message content
* @param {boolean} isOwn - Is this the current user's message
+ * @param {boolean} isFriend - Is this user a friend
*/
- addChatMessage(username, content, isOwn = false) {
+ addChatMessage(username, content, isOwn = false, isFriend = false) {
const msg = this.createElement('div', CSS.CHAT_MESSAGE);
if (isOwn) {
msg.classList.add('chat__message--own');
}
- msg.innerHTML = `${this.escapeHtml(username)}: ${this.escapeHtml(content)}`;
+ const friendIndicator = isFriend ? '' : '';
+ msg.innerHTML = `${friendIndicator}${this.escapeHtml(username)}: ${this.escapeHtml(content)}`;
this.output.appendChild(msg);
this.scrollToBottom();
}
@@ -252,8 +255,21 @@ export class GlobalChat extends Window {
eventBus.emit(Events.CHAT_DISCONNECTED, { reason });
});
+ // Handle initial data (recent messages + friend IDs)
+ this.socket.on('chat-init', (data) => {
+ console.log('Received chat init data:', data.messages.length, 'messages');
+ this.friendIds = new Set(data.friendIds || []);
+
+ // Display recent messages
+ data.messages.forEach(msg => {
+ const isFriend = this.friendIds.has(msg.sender_id);
+ this.addChatMessage(msg.username, msg.content, false, isFriend);
+ });
+ });
+
this.socket.on('chat-message', (msg) => {
- this.addChatMessage(msg.username, msg.content);
+ const isFriend = this.friendIds.has(msg.sender_id);
+ this.addChatMessage(msg.username, msg.content, false, isFriend);
eventBus.emit(Events.CHAT_MESSAGE_RECEIVED, msg);
});
}
diff --git a/srcs/frontend/src/style.css b/srcs/frontend/src/style.css
index f24acab..4714622 100644
--- a/srcs/frontend/src/style.css
+++ b/srcs/frontend/src/style.css
@@ -382,6 +382,16 @@ body {
align-self: flex-end;
}
+.chat__friend-indicator {
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ background-color: var(--color-success);
+ border-radius: 50%;
+ margin-right: var(--spacing-xs);
+ vertical-align: middle;
+}
+
.chat__system {
color: var(--color-text-muted);
font-size: var(--font-size-sm);