diff --git a/frontend/src/chat/chat.css b/frontend/src/chat/chat.css index d98a4fb..5e9b65e 100644 --- a/frontend/src/chat/chat.css +++ b/frontend/src/chat/chat.css @@ -216,6 +216,13 @@ div-private { items-center; } +.popup-b-clear { + @apply + absolute + bottom-42 + right-12 +} + .hidden{ display: none; } \ No newline at end of file diff --git a/frontend/src/pages/chat/chat.ts b/frontend/src/pages/chat/chat.ts index ac7ec31..4b8bd2f 100644 --- a/frontend/src/pages/chat/chat.ts +++ b/frontend/src/pages/chat/chat.ts @@ -68,8 +68,30 @@ function isLoggedIn() { return getUser() || null; }; -function getProfil(user: string): string { - return `Profil: ${user}
` +function actionBtnPopUp() { + setTimeout(() => { + const clearTextBtn = document.querySelector("#popup-b-clear"); + clearTextBtn?.addEventListener("click", () => { + clearText(); + }); + }, 0) +} + +// getProfil get the profil of user +function getProfil(socket: Socket, user: string) { + if (!socket.connected) return; + const profil = { + command: '@profil', + destination: 'profilMessage', + type: "chat", + user: user, + token: document.cookie ?? "", + text: user, + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + // addMessage(JSON.stringify(profil)); + socket.emit('profilMessage', JSON.stringify(profil)); } async function windowStateHidden() { @@ -149,7 +171,7 @@ function parseCmdMsg(msgText: string): string[] | undefined { return command; } -async function listBuddies(buddies: HTMLDivElement, listBuddies: string) { +async function listBuddies(socket: Socket, buddies: HTMLDivElement, listBuddies: string) { if (!buddies) return; const sendtextbox = document.getElementById('t-chat-window') as HTMLButtonElement; @@ -169,14 +191,15 @@ async function listBuddies(buddies: HTMLDivElement, listBuddies: string) { buddiesElement.addEventListener("dblclick", () => { console.log("Open profile:", listBuddies); - const profile: string = getProfil(listBuddies); - openProfilePopup(`${profile}`); - setTimeout(() => { - const clearTextBtn = document.querySelector("#popup-b-clear"); - clearTextBtn?.addEventListener("click", () => { - clearText(); - }); - }, 0) + getProfil(socket, listBuddies); + // openProfilePopup(`${profile}`); + // setTimeout(() => { + // const clearTextBtn = document.querySelector("#popup-b-clear"); + // clearTextBtn?.addEventListener("click", () => { + // clearText(); + // }); + // }, 0) + // actionBtnPopUp(); }); buddies.appendChild(buddiesElement); @@ -313,7 +336,6 @@ async function openProfilePopup(profil: string) { if (profilList) profilList.classList.remove("hidden"); // The popup now exists → attach the event - } @@ -394,7 +416,12 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn console.log("Getuser():", getUser()); }); + socket.on('profilMessage', (profil) => { + openProfilePopup(profil); + actionBtnPopUp(); + }); + socket.on('logout', () => { quitChat(socket); }); @@ -437,7 +464,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn socket.on('listBud', async (myBuddies: string) => { const buddies = document.getElementById('div-buddies') as HTMLDivElement; console.log('List buddies connected ', myBuddies); - listBuddies(buddies,myBuddies); + listBuddies(socket, buddies, myBuddies); }); socket.once('welcome', (data) => { @@ -507,8 +534,22 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn whoami(socket); break; case '@profil': - if (`${msgCommand[1]}`) - openProfilePopup(`Profil: ${msgCommand[1]}`); + getProfil(socket, msgCommand[1]); + // Ensure we have a user AND socket is connected + // if (!socket.connected) return; + // const profil = { + // command: msgCommand[0], + // destination: 'profil', + // type: "chat", + // user: msgCommand[1], + // token: document.cookie ?? "", + // text: msgCommand[1], + // timestamp: Date.now(), + // SenderWindowID: socket.id, + // }; + // //socket.emit('MsgObjectServer', message); + // addMessage(JSON.stringify(profil)); + // socket.emit('profilMessage', JSON.stringify(profil)); break; case '@cls': chatWindow.innerHTML = ''; @@ -524,7 +565,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn command: msgCommand[0], destination: '', type: "chat", - user, + user: user, token: document.cookie ?? "", text: msgCommand[1], timestamp: Date.now(), diff --git a/src/chat/src/app.ts b/src/chat/src/app.ts index d2a7cae..a02fac9 100644 --- a/src/chat/src/app.ts +++ b/src/chat/src/app.ts @@ -6,6 +6,7 @@ import * as auth from '@shared/auth'; import * as swagger from '@shared/swagger'; import * as utils from '@shared/utils'; import { Server, Socket } from 'socket.io'; +import type { User } from '@shared/database/mixin/user'; // colors for console.log export const color = { @@ -84,6 +85,7 @@ declare module 'fastify' { hello: (message: string) => string; MsgObjectServer: (data: { message: ClientMessage }) => void; privMessage: (data: string) => void; + profilMessage: (data: string) => void; privMessageCopy: (msg: string) => void; message: (msg: string) => void; listBud: (msg: string) => void; @@ -146,7 +148,7 @@ async function onReady(fastify: FastifyInstance) { } // If no io provided, assume entries in the map are valid and count them. count++; - console.log(color.red, 'DEBUG LOG: - Client (unverified):', color.reset, username ); + console.log(color.red, 'DEBUG LOG: - Client (unverified):', color.reset, username); console.log(color.red, 'DEBUG LOG: - Chat Socket ID (unverified):', color.reset, socketId); } return count; @@ -174,7 +176,58 @@ async function onReady(fastify: FastifyInstance) { }); } + function formatTimestamp(ms: number) { + const d = new Date(ms); + return d.toLocaleString('fr-FR', { timeZone: 'Europe/Paris' }); + } + function getUserByName(users: User[], name: string) { + return users.find(u => u.name === name) || null; + } + + + // this function returns html the profil pop up in CHAT of a user 'nickname unique' TODO .... + async function getProfil(user: string): Promise { + let profilHtmlPopup = '404: Error: Profil not found'; + const sockets = await fastify.io.fetchSockets(); + const users: User[] = fastify.db.getAllUsers() ?? []; + + // const senderSocket = sockets.find(socket => socket.id === user); + for (const socket of sockets) { + const clientInfo = clientChat?.get(socket.id); + const allUsers: User | null = getUserByName(users, user); + if (clientInfo?.user === allUsers?.name) { + const lastSeen = formatTimestamp(clientInfo?.lastSeen ?? 0); + console.log(color.yellow, `'Clientinfo.user: '${lastSeen}' user: '${user}'`); + profilHtmlPopup = `
+ Profil of ${clientInfo?.user}
+ Login Name: '${allUsers?.login ?? 'Guest'}' +
+ +
Joined: xx/xx/xx
+
Last connection: ${lastSeen}
+
About: No description
+ `; + break; + } + }; + return profilHtmlPopup; + }; + + function sendProfil(data: ClientMessage, clientProfil?: string) { + + fastify.io.fetchSockets().then((sockets) => { + const senderSocket = sockets.find(socket => socket.id === clientProfil); + for (const socket of sockets) { + const clientInfo = clientChat.get(socket.id); + if (clientInfo?.user === data.user) { + if (senderSocket) { + socket.emit('profilMessage', `${data.text}`); + } + } + } + }); + } function sendPrivMessage(data: ClientMessage, sender?: string) { fastify.io.fetchSockets().then((sockets) => { @@ -186,20 +239,20 @@ async function onReady(fastify: FastifyInstance) { console.log(color.yellow, `Skipping socket ${s.id} (no user found)`); continue; } - let user: string = clientChat.get(s.id)?.user ?? ""; + const user: string = clientChat.get(s.id)?.user ?? ''; const atUser = `@${user}`; - if (atUser !== data.command || atUser === "") { + if (atUser !== data.command || atUser === '') { console.log(color.yellow, `DEBUG LOG: User: '${atUser}' command NOT FOUND: '${data.command[0]}' `); continue; } - if (data.text !== "") { + if (data.text !== '') { s.emit('MsgObjectServer', { message: data }); console.log(color.yellow, `DEBUG LOG: User: '${atUser}' command FOUND: '${data.command}' `); - if (senderSocket) - senderSocket.emit('privMessageCopy',`${data.command}: ${data.text}🔒`); - // Debug logs + if (senderSocket) { + senderSocket.emit('privMessageCopy', `${data.command}: ${data.text}🔒`); + } } - console.log(color.green, `'Priv to:', ${data.command} message: ${data.text}`); + console.log(color.green, `DEBUG LOG: 'Priv to:', ${data.command} message: ${data.text}`); } }); } @@ -355,12 +408,12 @@ async function onReady(fastify: FastifyInstance) { socket.on('privMessage', (data) => { - const clientName: string = clientChat.get(socket.id)?.user || ""; - const prvMessage: ClientMessage = JSON.parse(data) || ""; + const clientName: string = clientChat.get(socket.id)?.user || ''; + const prvMessage: ClientMessage = JSON.parse(data) || ''; console.log( color.blue, `DEBUG LOG: ClientName: '${clientName}' id Socket: '${socket.id}' target Name:`, - prvMessage.command + prvMessage.command, ); if (clientName !== null) { @@ -374,12 +427,42 @@ async function onReady(fastify: FastifyInstance) { timestamp: Date.now(), SenderWindowID: socket.id, }; - console.log(color.blue, 'PRIV MESSAGE OUT :', obj.SenderWindowID); + console.log(color.blue, 'DEBUG LOG: PRIV MESSAGE OUT :', obj.SenderWindowID); sendPrivMessage(obj, obj.SenderWindowID); // clientChat.delete(obj.user); } }); + socket.on('profilMessage', async (data) => { + const clientName: string = clientChat.get(socket.id)?.user || ''; + const profilMessage: ClientMessage = JSON.parse(data) || ''; + const users: User[] = fastify.db.getAllUsers() ?? []; + console.log(color.yellow, 'DEBUG LOG: ALL USERS EVER CONNECTED:', users); + console.log( + color.blue, + `DEBUG LOG: ClientName: '${clientName}' id Socket: '${socket.id}' target profil:`, + profilMessage.user, + ); + const profileHtml: string = await getProfil(profilMessage.user); + if (clientName !== null) { + const testuser: User | null = getUserByName(users, profilMessage.user); + console.log(color.yellow, 'user:', testuser?.login ?? 'Guest'); + const obj = { + command: profilMessage.command, + destination: 'profilMsg', + type: 'chat', + user: clientName, + token: '', + text: profileHtml, + timestamp: Date.now(), + SenderWindowID: socket.id, + }; + console.log(color.blue, 'DEBUG - profil message MESSAGE OUT :', obj.SenderWindowID); + sendProfil(obj, obj.SenderWindowID); + // clientChat.delete(obj.user); + } + }); + socket.on('client_entered', (data) => { // data may be undefined (when frontend calls emit with no payload)