diff --git a/srcs/backend/services/socket.js b/srcs/backend/services/socket.js index 9273bb5..e244769 100644 --- a/srcs/backend/services/socket.js +++ b/srcs/backend/services/socket.js @@ -28,14 +28,22 @@ function setupSocketIO(io) socket.join('general-chat'); socket.on('chat-message', async(data) => { - const message = await chatService.saveMessage(socket.user.userId, data.content); - io.to('general-chat').emit('chat-message', + try { - id:message.id, - username: socket.user.username, - content: message.content, - created_at: message.created_at - }); + const message = await chatService.saveMessage(socket.user.userId, data.content); + io.to('general-chat').emit('chat-message', + { + id:message.id, + username: socket.user.username, + content: message.content, + created_at: message.created_at + }); + } + catch (err) + { + console.error('Error saving message:', err); + socket.emit('error', {message: 'Failed to send message'}); + } }); socket.on('disconnect', () => { diff --git a/srcs/frontend/nginx.conf b/srcs/frontend/nginx.conf index f0635dc..97cc9d7 100644 --- a/srcs/frontend/nginx.conf +++ b/srcs/frontend/nginx.conf @@ -15,4 +15,16 @@ server { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } + + # Socket.IO WebSocket proxying + location /socket.io/ { + proxy_pass http://backend:3001; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } } diff --git a/srcs/frontend/src/app.js b/srcs/frontend/src/app.js index ec67df3..457716a 100644 --- a/srcs/frontend/src/app.js +++ b/srcs/frontend/src/app.js @@ -2,25 +2,36 @@ import {Element, MenuElement} from "./element.js"; import {Grid} from "./grid.js"; import {fenetre} from "./windows.js"; import {LoginWindow} from "./login.js"; +import { GlobalChat } from "./global_chat.js"; + function direBonjour() { - alert("clicked !"); + alert("clicked !"); } +// Définir les éléments du menu (structure logique) const menuElement = new Element("menu"); const loginElement = new MenuElement("login"); const registeredElement = new MenuElement("registered"); const explorerElement = new MenuElement("explorer"); const accueilElement = new MenuElement("accueil"); +const globalChatElement = new MenuElement("global_chat"); -// Lancement de la grille -const gridgreen = new Grid('#143a0fff', -1, 25, 0.12, "normal"); -const gridReverseRed = new Grid('#3a0f0f75', -1, 12.5, 0.09, "reverse"); +// Lancement de la grille (commentés si on ne l’utilise pas tout de suite) +// const gridgreen = new Grid('#143a0fff', -1, 25, 0.12, "normal"); +// const gridReverseRed = new Grid('#3a0f0f75', -1, 12.5, 0.09, "reverse"); -//Ajouter les fenetres +// Fenêtres et écrans const test = new fenetre(); const loginWindow = new LoginWindow(); +const global_chat = new GlobalChat(); +// Actions UI document.getElementById("login").addEventListener("click", () => { - loginWindow.show(); + loginWindow.show(); }); + +document.getElementById("global_chat").addEventListener("click", () => { + console.log("showing"); + global_chat.show(); +}); \ No newline at end of file diff --git a/srcs/frontend/src/element.js b/srcs/frontend/src/element.js index c4c7442..91f08da 100644 --- a/srcs/frontend/src/element.js +++ b/srcs/frontend/src/element.js @@ -1,31 +1,38 @@ export class Element { - constructor(id) { - this.element = document.getElementById(id); - this.element.addEventListener("mouseenter", () => { - console.log("La souris est sur le bouton " + id + " !"); - }); - this.element.addEventListener("mouseleave", () => { - console.log("La souris a quitté le bouton " + id + "."); - }); - } + constructor(id) { + this.element = document.getElementById(id); + // Debug: log hover events for the element with a minimal, clear message + this.element.addEventListener("mouseenter", () => { + console.log("Hover: " + id); + }); + this.element.addEventListener("mouseleave", () => { + console.log("Leave: " + id); + }); + } } export class MenuElement extends Element { - constructor(id) { - super(id); - this.element.addEventListener("click", () => { - console.log("Le bouton " + id + " a été cliqué !"); - }); - this.element.addEventListener("mouseenter", () => { - this.element.style.backgroundColor = "lightgrey"; - this.element.style.fontSize = "1.2em"; - this.element.style.cursor = "move"; - }); - this.element.addEventListener("mouseleave", () => { - this.element.style.backgroundColor = ""; - this.element.style.fontSize = ""; - this.element.style.cursor = ""; - this.element.getAnimations().forEach(animation => animation.cancel()); - }); - } -} \ No newline at end of file + constructor(id) { + super(id); + // Basic click feedback + this.element.addEventListener("click", () => { + console.log("Clicked: " + id); + }); + // Simple hover styling for menu items to improve clarity + this.element.addEventListener("mouseenter", () => { + this.element.style.backgroundColor = "lightgrey"; + this.element.style.fontSize = "1.2em"; + this.element.style.cursor = "pointer"; + }); + this.element.addEventListener("mouseleave", () => { + // Reset styles when not hovered + this.element.style.backgroundColor = ""; + this.element.style.fontSize = ""; + this.element.style.cursor = ""; + // Cancel any running animations for a crisp reset (defensive) + if (this.element.getAnimations) { + this.element.getAnimations().forEach(animation => animation.cancel()); + } + }); + } +} diff --git a/srcs/frontend/src/global_chat.js b/srcs/frontend/src/global_chat.js new file mode 100644 index 0000000..ab5cd6d --- /dev/null +++ b/srcs/frontend/src/global_chat.js @@ -0,0 +1,143 @@ +import {fenetre} from "./windows.js"; +export class GlobalChat extends fenetre { + constructor() { + super(320, 240, "Global Chat"); + + // Création des éléments + this.output = document.createElement("div"); + this.output.className = "chat-output"; + + this.input = document.createElement("input"); + this.input.type = "text"; + this.input.placeholder = "Tape ton message..."; + this.input.className = "chat-input"; + + this.sendButton = document.createElement("button"); + this.sendButton.textContent = "Envoyer"; + this.sendButton.className = "send-btn"; + + this.inputContainer = document.createElement("div"); + this.inputContainer.className = "input-container"; + this.inputContainer.append(this.input, this.sendButton); + + this.body.append(this.output, this.inputContainer); + + this.applyStyles(); + this.applyEvents(); + this.connect_sockio_global_chat(); + } + + applyStyles() { + // Conteneur principal en flex column + this.body.style.display = "flex"; + this.body.style.flexDirection = "column"; + this.body.style.height = "100%"; + this.body.style.padding = "10px"; + this.body.style.boxSizing = "border-box"; + this.body.style.gap = "10px"; + + // Zone des messages + this.output.style.flex = "1"; + this.output.style.overflowY = "auto"; + this.output.style.padding = "8px"; + this.output.style.background = "#f8f9fa"; + this.output.style.borderRadius = "6px"; + this.output.style.display = "flex"; + this.output.style.flexDirection = "column"; + this.output.style.gap = "10px"; + + // Conteneur input + bouton + this.inputContainer.style.display = "flex"; + this.inputContainer.style.gap = "8px"; + this.inputContainer.style.paddingTop = "8px"; + + // Input + this.input.style.flex = "1"; + this.input.style.padding = "8px 12px"; + this.input.style.border = "1px solid #ccc"; + this.input.style.borderRadius = "6px"; + this.input.style.fontSize = "14px"; + + // Bouton envoyer + this.sendButton.style.padding = "8px 16px"; + this.sendButton.style.background = "#0066cc"; + this.sendButton.style.color = "white"; + this.sendButton.style.border = "none"; + this.sendButton.style.borderRadius = "6px"; + this.sendButton.style.cursor = "pointer"; + this.sendButton.style.fontWeight = "500"; + } + + applyEvents() { + // Envoi avec le bouton + this.sendButton.addEventListener("click", () => this.sendMessage()); + + // Envoi avec Entrée + this.input.addEventListener("keypress", (e) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + this.sendMessage(); + } + }); + } + + async connect_sockio_global_chat() { + const token = localStorage.getItem("auth_token"); + + console.log("Tentative de connexion Socket.IO"); + console.log("→ Token trouvé ? ", !!token); + if (token) console.log("→ Token (début) : ", token.substring(0, 20) + "..."); + + if (!token) { + console.error("→ ERREUR : Aucun token dans localStorage → connexion impossible"); + this.output.innerHTML += '
Erreur : vous devez être connecté pour utiliser le chat global
'; + return; + } + + if (!window.io) { + const script = document.createElement("script"); + script.src = "/socket.io/socket.io.js"; + document.head.appendChild(script); + + await new Promise(resolve => { + script.onload = () => { + console.log("Script socket.io chargé depuis le backend"); + resolve(); + }; + script.onerror = () => console.error("Impossible de charger socket.io depuis le backend"); + }); + } + + this.socket = io({ + auth: { token }, + reconnection: true, + reconnectionAttempts: 5, + reconnectionDelay: 1000, + transports: ["websocket", "polling"] + }); + + this.socket.on("connect", () => { + console.log("→ SOCKET CONNECTÉ ! ID =", this.socket.id); + this.output.innerHTML += '
Connecté au chat global ✓
'; + }); + + this.socket.on("connect_error", (err) => { + console.error("→ Erreur de connexion socket :", err.message); + this.output.innerHTML += `
Erreur connexion chat : ${err.message}
`; + }); + + this.socket.on("disconnect", (reason) => { + console.log("→ Déconnecté :", reason); + this.output.innerHTML += `
Déconnecté du chat (${reason})
`; + }); + + // Réception des messages + this.socket.on("chat-message", (msg) => { + const div = document.createElement("div"); + div.className = "chat-message"; + div.innerHTML = `${msg.username}: ${msg.content}`; + this.output.appendChild(div); + this.output.scrollTop = this.output.scrollHeight; + }); + } +} \ No newline at end of file diff --git a/srcs/frontend/src/index.html b/srcs/frontend/src/index.html index ca0085d..a1387ae 100644 --- a/srcs/frontend/src/index.html +++ b/srcs/frontend/src/index.html @@ -1,23 +1,33 @@ - + + scribl.lidl_edition + - -

scribl.lidl_edition (GARE A VOS YEUX)

+

scribl.lidl_edition

- + + -
  • -
  • -
  • -
  • -
    - + + + - + + + + \ No newline at end of file