chat general broadcast done with now notifications system separated in different space on the chat windo

This commit is contained in:
NigeParis 2025-12-02 16:52:41 +01:00 committed by apetitco
parent 26c9bd6421
commit 8a151cfb5e
6 changed files with 81 additions and 78 deletions

View file

@ -9,4 +9,6 @@ declare global {
dispatchEvent<K extends keyof CustomEventMap>(ev: CustomEventMap[K]): void;
}
}
export { }; //keep that for TS compiler.

View file

@ -40,7 +40,6 @@
active:shadow-[0_2px_0_0_black];;
}
.chatbox-style {
@apply
w-[650px]
@ -60,12 +59,37 @@
mx-auto;
}
.system-info {
@apply
h-[40px]
bg-gray-200
text-gray-700
p-3
rounded-3xl
mb-2 border
border-gray-200
text-center
shadow
overflow-y-auto
justify-end /* 👈 forces text to bottom */
relative; /* needed for overlay */
}
.text-info {
@apply
text-blue-800
}
.chat-window-style {
@apply
w-[400px]
h-[50px]
p-[10px]
border-1 border-black
border-1
border-black
shadow-sm
flex-1
rounded-3xl

View file

@ -7,9 +7,10 @@
<button id="b-clear" class="btn-style absolute top-4 right-6">Clear Text</button>
<button id="b-quit" class="btn-style absolute top-14 right-6">Quit Chat</button>
<button id="b-help" class="btn-style absolute top-14 left-6">Connected</button>
<!-- Center wrapper for chat + vertical box -->
<!-- Horizontal Message Box -->
<div id="system-box" class="system-info">System: connecting ... </div>
<div class="flex justify-center mt-2">
<!-- Center wrapper for chat + vertical box -->
<!-- Groupe Chat + vertical box container -->
<div id = "g-boxes" class="flex gap-2">
<!-- Text Chat box panel + send -->
@ -20,7 +21,6 @@
<button id="b-send" class="send-btn-style">Send</button>
</div>
</div>
<!-- Vertical Ping Buddies box panel-->
<div id="ping-box" class="ping-box">
<p id="ping-title" class="ping-title">Ping Buddies</p>
@ -34,7 +34,9 @@
</div>
</div>
</div>
<p class="text-gray-400 mt-2">From this Chat Box you can send messages to other players</p>
</div>
</div>

View file

@ -4,17 +4,22 @@ import authHtml from './chat.html?raw';
import client from '@app/api'
import { getUser, updateUser } from "@app/auth";
import io, { Socket } from 'socket.io-client';
// import type { ClientMessage } from "@app/@types/dom";
const color = {
red: 'color: red; font-weight: bold;',
green: 'color: green; font-weight: bold;',
yellow: 'color: orange; font-weight: bold;',
blue: 'color: blue; font-weight: bold;',
red: 'color: red;',
green: 'color: green;',
yellow: 'color: orange;',
blue: 'color: blue;',
reset: '',
};
export type ClientMessage = {
destination: string;
user: string;
text: string;
SenderWindowID: string;
};
// get the name of the machine used to connect
@ -143,26 +148,39 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
});
// Listen for messages from the server "MsgObjectServer"
socket.on("MsgObjectServer", (data: any) => {
console.log("Message Obj Recieved:", data.message);
console.log("Recieved data.message.text: ", data.message.text);
console.log("Recieved data.message.user: ", data.message.user);
console.log("Recieved data.message.type: ", data.message.type);
console.log("Recieved data.message.token: ", data.message.token);
console.log("Recieved data.message.timestamp: ", data.message.timestamp);
socket.on("MsgObjectServer", (data: { message: ClientMessage}) => {
console.log("Message Obj Recieved:", data);
console.log("%cRecieved data.message.text: ", color.blue, data.message.text);
console.log("%cRecieved data.message.user: ", color.blue, data.message.user);
// Display the message in the chat window
const systemWindow = document.getElementById('system-box') as HTMLDivElement;
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
const bconnected = document.getElementById('b-help') as HTMLButtonElement;
if (bconnected) {
bconnected.click();
}
if (chatWindow) {
if (chatWindow && data.message.destination === "") {
const messageElement = document.createElement("div");
messageElement.textContent = `${data.message.user}: ${data.message.text}`;
chatWindow.appendChild(messageElement);
chatWindow.scrollTop = chatWindow.scrollHeight;
}
const MAX_SYSTEM_MESSAGES = 10;
if (systemWindow && data.message.destination === "system-info") {
const messageElement = document.createElement("div");
messageElement.textContent = `${data.message.user}: ${data.message.text}`;
systemWindow.appendChild(messageElement);
// keep only last 10
while (systemWindow.children.length > MAX_SYSTEM_MESSAGES) {
systemWindow.removeChild(systemWindow.firstChild!);
}
systemWindow.scrollTop = systemWindow.scrollHeight;
}
console.log("Getuser():", getUser());
});
@ -261,6 +279,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
const user = getUser();
if (user && socket?.connected) {
const message = {
destination: "",
type: "chat",
user: user.name,
token: document.cookie,
@ -298,7 +317,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
setInterval(async () => {
bconnected.click();
//bconnected.click();
}, 10000); // every 10 second
// Help Text button
@ -312,7 +331,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
oldUser = loggedIn.name || "undefined";
const res = await client.guestLogin();
let user = await updateUser();
console.log('%User?name:',color.yellow, user?.name);
console.log('%cUser?name:',color.yellow, user?.name);
localStorage.setItem("oldName", oldUser);
buddies.textContent = "";
// if (chatWindow) {
@ -347,8 +366,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
switch (res.kind) {
case 'success': {
let user = await updateUser();
console.log('%cUSER_NAME ',color.yellow, user?.name);
console.log('%cGET_user ',color.yellow, getUser()?.name || null);
if (chatWindow) {
socket.emit('updateClientName', {
oldUser: '',

View file

@ -32,6 +32,13 @@ interface ClientInfo {
lastSeen: number;
}
export type ClientMessage = {
destination: string;
user: string;
text: string;
SenderWindowID: string;
};
const clientChat = new Map<string, ClientInfo>();
// @ts-expect-error: import.meta.glob is a vite thing. Typescript doesn't know this...
@ -69,18 +76,13 @@ export default app;
export { app };
type ClientMessage = {
user: string;
text: string;
SenderWindowID: string;
};
// When using .decorate you have to specify added properties for Typescript
declare module 'fastify' {
interface FastifyInstance {
io: Server<{
hello: (message: string) => string;
MsgObjectServer: (data: { message: ClientMessage }) => void;
MsgObjectServer: (data: { message: ClientMessage } ) => void;
message: (msg: string) => void;
listBud: (msg: string) => void;
testend: (sock_id_client: string) => void;
@ -273,6 +275,7 @@ function broadcast(data: ClientMessage, sender?: string) {
if (!clientName) return;
console.log(color.green, `Client logging out: ${clientName} (${socket.id})`);
const obj = {
destination: "system-info",
type: "chat" as const,
user: clientName,
token: "",
@ -300,6 +303,7 @@ function broadcast(data: ClientMessage, sender?: string) {
if (clientName !== null) {
const obj = {
destination: "system-info",
type: 'chat',
user: clientName,
token: '',
@ -323,6 +327,7 @@ function broadcast(data: ClientMessage, sender?: string) {
if (clientName !== null) {
const obj = {
destination: "system-info",
type: 'chat',
user: clientName,
token: '',
@ -367,6 +372,7 @@ function broadcast(data: ClientMessage, sender?: string) {
);
if (clientName !== null) {
const obj = {
destination: "system-info",
type: 'chat',
user: clientName,
frontendUserName: userNameFromFrontend,

View file

@ -34,54 +34,6 @@ export const ChatRes = {
export type ChatResType = MakeStaticResponse<typeof ChatRes>;
function connectedUser(io: Server | undefined, targetSocketId?: string): number {
let count = 0;
// Track unique usernames (avoid duplicates)
const seenUsers = new Set<string>();
for (const [socketId, info] of clientChat) {
// Validate entry
if (!info || typeof info.user !== "string" || info.user.trim() === "") {
clientChat.delete(socketId);
continue;
}
const username = info.user;
// Validate socket exists if io is passed
if (io) {
const socket = io.sockets.sockets.get(socketId);
// Remove disconnected sockets
if (!socket || socket.disconnected) {
clientChat.delete(socketId);
continue;
}
}
// Skip duplicates
if (seenUsers.has(username))
continue;
seenUsers.add(username);
count++;
// Send to target only
if (io && targetSocketId) {
io.to(targetSocketId).emit("listBud", username);
}
console.log(color.yellow, "Client:", color.reset, username);
console.log(color.yellow, "Socket ID:", color.reset, socketId);
}
return count;
}
const route: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.get(