Working avatar + english comments

This commit is contained in:
gprunet
2026-01-21 16:53:10 +01:00
parent 5bdf7f0442
commit 173d1a56f3
10 changed files with 43 additions and 111 deletions
+7 -1
View File
@@ -39,10 +39,16 @@ BACKEND
Aucun moyen de changer l'etat de la room de waiting a en cours ou finished Aucun moyen de changer l'etat de la room de waiting a en cours ou finished
ca attendra le systeme du jeu ca attendra le systeme du jeu
21/01 Ajout du service/route pour le systeme d'avatar
permet aux utilisateurs de changer ou supprimer leur avatar actuel
Ajout egalement d'une simple fonction pour recuperer l'avatar d'un utilisateur (pour le frontend)
DATABASE DATABASE
17/01 Ajout des tables game_rooms, game_players, game_rounds, words 17/01 Ajout des tables game_rooms, game_players, game_rounds, words
- nom, status et parametres de la game - nom, status et parametres de la game
- joueurs dans la game, leur scores et leur role actuel (dessinateur, devineur) - joueurs dans la game, leur scores et leur role actuel (dessinateur, devineur)
- historique de la game, qui a dessine quoi precedemment ainsi que les timers des rounds, sera aussi utile si on veut faire les stats de compte a l'avenir. - historique de la game, qui a dessine quoi precedemment ainsi que les timers des rounds, sera aussi utile si on veut faire les stats de compte a l'avenir.
- contient la liste des mots utilisable par les joueurs - contient la liste des mots utilisable par les joueurs
21/01 Ajout de avatar_url dans la table users
+2 -2
View File
@@ -28,8 +28,8 @@ services:
# - "3001:3001" # - "3001:3001"
depends_on: depends_on:
- database - database
# volumes: volumes:
# // - ./srcs/backend/avatar:/app/avatar
env_file: env_file:
- ../.env - ../.env
networks: networks:
+1
View File
@@ -38,6 +38,7 @@ async function createTables()
username VARCHAR(50) UNIQUE NOT NULL, username VARCHAR(50) UNIQUE NOT NULL,
password_hash TEXT NOT NULL, password_hash TEXT NOT NULL,
email VARCHAR(100), email VARCHAR(100),
avatar_url TEXT DEFAULT '/avatar/default.png',
created_at TIMESTAMP DEFAULT NOW() created_at TIMESTAMP DEFAULT NOW()
); );
+4 -4
View File
@@ -5,10 +5,10 @@ import {Server} from 'socket.io';
import authRouter from './routes/auth.js'; import authRouter from './routes/auth.js';
import chatRouter from './routes/global_chat.js'; import chatRouter from './routes/global_chat.js';
import gameRoomRouter from './routes/game_room.js'; import gameRoomRouter from './routes/game_room.js';
// import avatarRouter from './routes/avatar.js'; import avatarRouter from './routes/avatar.js';
import {waitForDb, createTables, ensureOauthClient} from './db.js'; import {waitForDb, createTables, ensureOauthClient} from './db.js';
import setupSocketIO from './services/socket.js'; import setupSocketIO from './services/socket.js';
// import avatarService from './services/avatar.js'; import avatarService from './services/avatar.js';
const app = express(); const app = express();
const server = http.createServer(app); const server = http.createServer(app);
@@ -38,11 +38,11 @@ async function startServer()
console.warn('OAuth client might already exist or failed to register:', e.message); console.warn('OAuth client might already exist or failed to register:', e.message);
} }
// app.use('/avatar', express.static(avatarService.AVATAR_DIR)); app.use('/avatar', express.static(avatarService.AVATAR_DIR));
app.use('/api/auth', authRouter); app.use('/api/auth', authRouter);
app.use('/api/global_chat', chatRouter); app.use('/api/global_chat', chatRouter);
app.use('/api/rooms', gameRoomRouter); app.use('/api/rooms', gameRoomRouter);
// app.use('/api/avatar', avatarRouter); app.use('/api/avatar', avatarRouter);
app.get('/api', (req, res) => res.send('Backend running')); app.get('/api', (req, res) => res.send('Backend running'));
server.listen(3001, () => server.listen(3001, () =>
+1 -1
View File
@@ -1,7 +1,7 @@
import express from 'express'; import express from 'express';
import multer from 'multer'; import multer from 'multer';
import avatarService from '../services/avatar.js'; import avatarService from '../services/avatar.js';
import {authenticateToken} from '../middleware/auth.js'; import authenticateToken from '../middleware/auth.js';
const router = express.Router(); const router = express.Router();
+3 -3
View File
@@ -9,7 +9,7 @@ function direBonjour() {
alert("clicked !"); alert("clicked !");
} }
// Définir les éléments du menu (structure logique) // Define the elements of the menu (logical structure)
const menuElement = new Element("menu"); const menuElement = new Element("menu");
const loginElement = new MenuElement("login"); const loginElement = new MenuElement("login");
const registeredElement = new MenuElement("registered"); const registeredElement = new MenuElement("registered");
@@ -17,11 +17,11 @@ const explorerElement = new MenuElement("explorer");
const accueilElement = new MenuElement("accueil"); const accueilElement = new MenuElement("accueil");
const globalChatElement = new MenuElement("global_chat"); const globalChatElement = new MenuElement("global_chat");
// Lancement de la grille (commentés si on ne lutilise pas tout de suite) // Start of the grid (commented if we dont use it yet)
// const gridgreen = new Grid('#143a0fff', -1, 25, 0.12, "normal"); // const gridgreen = new Grid('#143a0fff', -1, 25, 0.12, "normal");
// const gridReverseRed = new Grid('#3a0f0f75', -1, 12.5, 0.09, "reverse"); // const gridReverseRed = new Grid('#3a0f0f75', -1, 12.5, 0.09, "reverse");
// Fenêtres et écrans // Windows and screens
const test = new fenetre(); const test = new fenetre();
const loginWindow = new LoginWindow(); const loginWindow = new LoginWindow();
const global_chat = new GlobalChat(); const global_chat = new GlobalChat();
+15 -15
View File
@@ -3,7 +3,7 @@ export class GlobalChat extends fenetre {
constructor() { constructor() {
super(320, 240, "Global Chat"); super(320, 240, "Global Chat");
// Création des éléments // Creation of the elements
this.output = document.createElement("div"); this.output = document.createElement("div");
this.output.className = "chat-output"; this.output.className = "chat-output";
@@ -24,12 +24,12 @@ export class GlobalChat extends fenetre {
this.applyStyles(); this.applyStyles();
this.applyEvents(); this.applyEvents();
// Connexion au chat global est déclenchée via des contrôles dédiés // Connection to the global chat is started via dedicated controls
this.connected = false; this.connected = false;
this.createConnectControls(); this.createConnectControls();
} }
// Crée les contrôles Connect / Reconnect dans la fenêtre du chat // Create the controls (Connect / Reconnect) in the chat window
createConnectControls() { createConnectControls() {
this.controls = document.createElement("div"); this.controls = document.createElement("div");
this.controls.style.display = "flex"; this.controls.style.display = "flex";
@@ -62,7 +62,7 @@ export class GlobalChat extends fenetre {
} }
async reconnect_sockio_global_chat() { async reconnect_sockio_global_chat() {
// Déconnecte et reconnecte le socket si nécessaire // Disconnect and reconnect the socket if necessary
if (this.socket) { if (this.socket) {
try { try {
this.socket.close(); this.socket.close();
@@ -77,7 +77,7 @@ export class GlobalChat extends fenetre {
} }
applyStyles() { applyStyles() {
// Conteneur principal en flex column // Main container in flex collumn
this.body.style.display = "flex"; this.body.style.display = "flex";
this.body.style.flexDirection = "column"; this.body.style.flexDirection = "column";
this.body.style.height = "100%"; this.body.style.height = "100%";
@@ -85,7 +85,7 @@ export class GlobalChat extends fenetre {
this.body.style.boxSizing = "border-box"; this.body.style.boxSizing = "border-box";
this.body.style.gap = "10px"; this.body.style.gap = "10px";
// Zone des messages // Messages zone
this.output.style.flex = "1"; this.output.style.flex = "1";
this.output.style.overflowY = "auto"; this.output.style.overflowY = "auto";
this.output.style.padding = "8px"; this.output.style.padding = "8px";
@@ -95,7 +95,7 @@ export class GlobalChat extends fenetre {
this.output.style.flexDirection = "column"; this.output.style.flexDirection = "column";
this.output.style.gap = "10px"; this.output.style.gap = "10px";
// Conteneur input + bouton // Input container + button
this.inputContainer.style.display = "flex"; this.inputContainer.style.display = "flex";
this.inputContainer.style.gap = "8px"; this.inputContainer.style.gap = "8px";
this.inputContainer.style.paddingTop = "8px"; this.inputContainer.style.paddingTop = "8px";
@@ -107,7 +107,7 @@ export class GlobalChat extends fenetre {
this.input.style.borderRadius = "6px"; this.input.style.borderRadius = "6px";
this.input.style.fontSize = "14px"; this.input.style.fontSize = "14px";
// Bouton envoyer // Sender button
this.sendButton.style.padding = "8px 16px"; this.sendButton.style.padding = "8px 16px";
this.sendButton.style.background = "#0066cc"; this.sendButton.style.background = "#0066cc";
this.sendButton.style.color = "white"; this.sendButton.style.color = "white";
@@ -118,10 +118,10 @@ export class GlobalChat extends fenetre {
} }
applyEvents() { applyEvents() {
// Envoi avec le bouton // Send with the button
this.sendButton.addEventListener("click", () => this.sendMessage()); this.sendButton.addEventListener("click", () => this.sendMessage());
// Envoi avec Entrée // Send with Enter key
this.input.addEventListener("keypress", (e) => { this.input.addEventListener("keypress", (e) => {
if (e.key === "Enter" && !e.shiftKey) { if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault(); e.preventDefault();
@@ -130,7 +130,7 @@ export class GlobalChat extends fenetre {
}); });
} }
// Envoie le message courant via Socket.IO // Send current message via Socket.IO
sendMessage() { sendMessage() {
const content = this.input.value.trim(); const content = this.input.value.trim();
if (!content) return; if (!content) return;
@@ -143,7 +143,7 @@ export class GlobalChat extends fenetre {
return; return;
} }
// Affichage immédiat dans l'interface pour feedback utilisateur // Immediate display in the interface pour user feedback
const div = document.createElement("div"); const div = document.createElement("div");
div.className = "chat-message"; div.className = "chat-message";
div.innerHTML = `<strong>Moi:</strong> ${content}`; div.innerHTML = `<strong>Moi:</strong> ${content}`;
@@ -167,7 +167,7 @@ export class GlobalChat extends fenetre {
return; return;
} }
// Si déjà connecté, ne pas tenter de nouveau // If already connected, dont retry
if (this.socket && this.socket.connected) { if (this.socket && this.socket.connected) {
this.output.innerHTML += '<div class="system">Déjà connecté au chat global</div>'; this.output.innerHTML += '<div class="system">Déjà connecté au chat global</div>';
return; return;
@@ -194,7 +194,7 @@ export class GlobalChat extends fenetre {
reconnectionDelay: 1000, reconnectionDelay: 1000,
transports: ["websocket", "polling"] transports: ["websocket", "polling"]
}; };
// Optionnel: se connecter via un port alternatif si défini (ex: pour contourner le proxy) // Optional: connect from an alternative port (ex: to dodge the proxy)
const altPort = window.GLOBAL_CHAT_ALT_PORT; const altPort = window.GLOBAL_CHAT_ALT_PORT;
if (altPort) { if (altPort) {
const host = location.hostname || 'localhost'; const host = location.hostname || 'localhost';
@@ -218,7 +218,7 @@ export class GlobalChat extends fenetre {
this.output.innerHTML += `<div class="system">Déconnecté du chat (${reason})</div>`; this.output.innerHTML += `<div class="system">Déconnecté du chat (${reason})</div>`;
}); });
// Réception des messages // Messages reception
this.socket.on("chat-message", (msg) => { this.socket.on("chat-message", (msg) => {
const div = document.createElement("div"); const div = document.createElement("div");
div.className = "chat-message"; div.className = "chat-message";
-75
View File
@@ -1,75 +0,0 @@
export class Grid {
constructor(color = '#143a0fff', zIndex = 1, gridSize = 25, speed = 0.35, sens = "normal") {
// Initialisation des propriétés de l'instance
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.offset = 0;
this.gridSize = gridSize;
this.speed = speed;
this.color = color;
// Configuration du style
document.body.appendChild(this.canvas);
this.canvas.style.position = 'fixed';
this.canvas.style.top = '0';
this.canvas.style.left = '0';
this.canvas.style.zIndex = zIndex;
this.canvas.style.pointerEvents = 'none'; // Pour ne pas bloquer les clics sur les boutons
// Gestion du redimensionnement
window.addEventListener('resize', () => this.resize());
this.resize();
this.draw(sens);
}
resize() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
draw(sens = "normal") {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.strokeStyle = this.color;
this.ctx.lineWidth = 1;
// Mise à jour de l'offset
this.offset = (this.offset + this.speed) % this.gridSize;
if (sens === "normal") {
// Lignes verticales
for (let x = this.offset; x < this.canvas.width; x += this.gridSize) {
this.ctx.beginPath();
this.ctx.moveTo(x, 0);
this.ctx.lineTo(x, this.canvas.height);
this.ctx.stroke();
}
// Lignes horizontales
for (let y = this.offset; y < this.canvas.height; y += this.gridSize) {
this.ctx.beginPath();
this.ctx.moveTo(0, y);
this.ctx.lineTo(this.canvas.width, y);
this.ctx.stroke();
}
}
//pareillement pour le sens reverse
else if (sens === "reverse") {
// Lignes verticales
for (let x = this.gridSize - this.offset; x < this.canvas.width; x += this.gridSize) {
this.ctx.beginPath();
this.ctx.moveTo(x, 0);
this.ctx.lineTo(x, this.canvas.height);
this.ctx.stroke();
}
// Lignes horizontales
for (let y = this.gridSize - this.offset; y < this.canvas.height; y += this.gridSize) {
this.ctx.beginPath();
this.ctx.moveTo(0, y);
this.ctx.lineTo(this.canvas.width, y);
this.ctx.stroke();
}
}
// Appel récursif pour l'animation
requestAnimationFrame(() => this.draw(sens));
}
}
+3 -3
View File
@@ -4,13 +4,13 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>scribl.lidl_edition</title> <title>scribl.lidl_edition</title>
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
<script src="https://cdn.socket.io/4.8.1/socket.io.min.js"></script> <script src="https://cdn.socket.io/4.8.1/socket.io.min.js"></script>
</head> </head>
<body> <body>
<h1>scribl.lidl_edition</h1> <h1>scribl.lidl_edition</h1>
<!-- Menu principal --> <!-- Main menu -->
<nav id="menu" aria-label="Menu principal"> <nav id="menu" aria-label="Menu principal">
<button id="accueil" aria-label="Accueil">Accueil</button> <button id="accueil" aria-label="Accueil">Accueil</button>
<button id="explorer" aria-label="Explorer">Explorer</button> <button id="explorer" aria-label="Explorer">Explorer</button>
@@ -30,4 +30,4 @@
</html></script> </html></script>
</html> </html>
+7 -7
View File
@@ -33,14 +33,14 @@ export class LoginWindow extends fenetre {
this.applyStyles(); this.applyStyles();
this.bindEvents(); this.bindEvents();
// **** AJOUT FONCTION GITHUB **** // **** ADDED GITHUB FUNCTION ****
// Dans constructor() de LoginWindow // In constructor() of LoginWindow
this.githubBtn = document.createElement("button"); this.githubBtn = document.createElement("button");
this.githubBtn.innerText = "Se connecter avec GitHub"; this.githubBtn.innerText = "Se connecter avec GitHub";
this.githubBtn.style.backgroundColor = "#24292e"; this.githubBtn.style.backgroundColor = "#24292e";
this.githubBtn.style.color = "white"; this.githubBtn.style.color = "white";
this.githubBtn.onclick = () => { this.githubBtn.onclick = () => {
// Ouvre le OAuth GitHub dans une popup et reçoit le token via postMessage // Open the OAUTH Github in a popup and receive the token from postMessage
const w = 600; const w = 600;
const h = 700; const h = 700;
const left = (screen.width - w) / 2; const left = (screen.width - w) / 2;
@@ -59,7 +59,7 @@ export class LoginWindow extends fenetre {
}; };
this.body.appendChild(this.githubBtn); this.body.appendChild(this.githubBtn);
this.checkIfAlreadyLoggedIn(); //verifie si l'utilisateur est connecté au démarrage this.checkIfAlreadyLoggedIn(); // Verify if the user is connected on startup
} }
applyStyles() { applyStyles() {
@@ -93,13 +93,13 @@ export class LoginWindow extends fenetre {
if (response.ok) { if (response.ok) {
console.log("connexion ok", data); console.log("connexion ok", data);
// *** STOCKAGE DU TOKEN *** // *** TOKEN STORAGE ***
if (data.token) { if (data.token) {
localStorage.setItem("auth_token", data.token); localStorage.setItem("auth_token", data.token);
this.message.innerText = "Connexion réussie ! Bienvenue."; this.message.innerText = "Connexion réussie ! Bienvenue.";
this.message.style.color = "#3cff01"; this.message.style.color = "#3cff01";
// masquer la fenêtre après 1.5s // mask the window after 1.5s
setTimeout(() => this.hide(), 1500); setTimeout(() => this.hide(), 1500);
} }
@@ -109,7 +109,7 @@ export class LoginWindow extends fenetre {
} }
} }
else { else {
// Afficher une erreur utilisateur plus visible // Show a more visible user error
const errMsg = data && data.message ? data.message : "Échec de la connexion"; const errMsg = data && data.message ? data.message : "Échec de la connexion";
this.message.innerText = errMsg; this.message.innerText = errMsg;
this.message.style.color = "#ff4d4d"; this.message.style.color = "#ff4d4d";