diff --git a/Transcendence/srcs/backend/db.js b/Transcendence/srcs/backend/db.js index 28a95d5..bbb9c63 100644 --- a/Transcendence/srcs/backend/db.js +++ b/Transcendence/srcs/backend/db.js @@ -56,6 +56,17 @@ async function runMigrations() END IF; END $$; `); + // Create tetris_game_history table if not exists + await pool.query(` + CREATE TABLE IF NOT EXISTS tetris_game_history ( + id SERIAL PRIMARY KEY, + user_id INT REFERENCES users(id) ON DELETE CASCADE, + score INT NOT NULL DEFAULT 0, + game_type VARCHAR(10) NOT NULL DEFAULT 'solo', + result VARCHAR(10) DEFAULT NULL, + played_at TIMESTAMP DEFAULT NOW() + ); + `); console.log('Migrations completed!'); } catch (err) @@ -147,6 +158,15 @@ async function createTables() started_at TIMESTAMP DEFAULT NOW(), ended_at TIMESTAMP ); + + CREATE TABLE IF NOT EXISTS tetris_game_history ( + id SERIAL PRIMARY KEY, + user_id INT REFERENCES users(id) ON DELETE CASCADE, + score INT NOT NULL DEFAULT 0, + game_type VARCHAR(10) NOT NULL DEFAULT 'solo', + result VARCHAR(10) DEFAULT NULL, + played_at TIMESTAMP DEFAULT NOW() + ); `); console.log('Tables created!'); } diff --git a/Transcendence/srcs/backend/routes/player_stats.js b/Transcendence/srcs/backend/routes/player_stats.js index 9a7dfe6..fe78e01 100644 --- a/Transcendence/srcs/backend/routes/player_stats.js +++ b/Transcendence/srcs/backend/routes/player_stats.js @@ -43,7 +43,7 @@ router.get('/leaderboard', authenticateToken, async (req, res) => { } }); -// Save tetris score (solo or duel) — updates best score if higher +// Save tetris score (solo) — updates best score if higher + saves to history router.post('/tetris/score', authenticateToken, async (req, res) => { try { const { score } = req.body; @@ -52,6 +52,7 @@ router.post('/tetris/score', authenticateToken, async (req, res) => { } const bestScore = await playerStatsService.updateTetrisBestScore(req.user.userId, score); await playerStatsService.incrementTetrisGamesPlayed(req.user.userId); + await playerStatsService.addTetrisGameHistory(req.user.userId, score, 'solo', null); res.json({ bestScore }); } catch (err) { console.error('Error saving tetris score:', err); @@ -94,6 +95,17 @@ router.get('/tetris/rank/score', authenticateToken, async (req, res) => { } }); +// Get current user's tetris game history (last 15) +router.get('/tetris/history', authenticateToken, async (req, res) => { + try { + const history = await playerStatsService.getTetrisGameHistory(req.user.userId); + res.json(history); + } catch (err) { + console.error('Error getting tetris history:', err); + res.status(500).json({ error: 'Server error' }); + } +}); + // Current user's rank by tetris duel wins router.get('/tetris/rank/wins', authenticateToken, async (req, res) => { try { diff --git a/Transcendence/srcs/backend/services/player_stats.js b/Transcendence/srcs/backend/services/player_stats.js index 4e3ed59..8663915 100644 --- a/Transcendence/srcs/backend/services/player_stats.js +++ b/Transcendence/srcs/backend/services/player_stats.js @@ -129,6 +129,38 @@ async function getTetrisDuelWinsLeaderboard(limit = 10) { return result.rows; } +// Add a game to tetris history (keep max 15 per user) +async function addTetrisGameHistory(userId, score, gameType = 'solo', result = null) { + await query( + `INSERT INTO tetris_game_history (user_id, score, game_type, result) VALUES ($1, $2, $3, $4)`, + [userId, score, gameType, result] + ); + // Keep only the 15 most recent entries + await query( + `DELETE FROM tetris_game_history + WHERE id IN ( + SELECT id FROM tetris_game_history + WHERE user_id = $1 + ORDER BY played_at DESC + OFFSET 15 + )`, + [userId] + ); +} + +// Get the last 15 games for a user +async function getTetrisGameHistory(userId) { + const result = await query( + `SELECT id, score, game_type, result, played_at + FROM tetris_game_history + WHERE user_id = $1 + ORDER BY played_at DESC + LIMIT 15`, + [userId] + ); + return result.rows; +} + // Rank of a user by tetris best score (1 = best) async function getTetrisScoreRank(userId) { const result = await query( @@ -166,5 +198,7 @@ export default { getTetrisBestScoreLeaderboard, getTetrisDuelWinsLeaderboard, getTetrisScoreRank, - getTetrisDuelWinsRank + getTetrisDuelWinsRank, + addTetrisGameHistory, + getTetrisGameHistory }; diff --git a/Transcendence/srcs/backend/services/socket.js b/Transcendence/srcs/backend/services/socket.js index 0feaa3d..6fe5e7c 100644 --- a/Transcendence/srcs/backend/services/socket.js +++ b/Transcendence/srcs/backend/services/socket.js @@ -721,6 +721,7 @@ function setupSocketIO(io) // Relay pur : grid-update → adversaire uniquement socket.on('tetris:grid-update', (data) => { + if (data.score !== undefined) socket.tetrisLastScore = data.score; _tetrisRelayToOpponent(socket, 'tetris:grid-update', data); }); @@ -779,6 +780,7 @@ function setupSocketIO(io) try { await playerStatsService.updateTetrisBestScore(loserId, data.score || 0); await playerStatsService.incrementTetrisGamesPlayed(loserId); + await playerStatsService.addTetrisGameHistory(loserId, data.score || 0, 'duel', 'loss'); } catch (err) { console.error('Error saving tetris loser stats:', err); } @@ -793,6 +795,8 @@ function setupSocketIO(io) try { await playerStatsService.incrementTetrisWins(s.user.userId); await playerStatsService.incrementTetrisGamesPlayed(s.user.userId); + const winnerScore = s.tetrisLastScore || 0; + await playerStatsService.addTetrisGameHistory(s.user.userId, winnerScore, 'duel', 'win'); } catch (err) { console.error('Error saving tetris winner stats:', err); } diff --git a/Transcendence/srcs/frontend/src/tetris.css b/Transcendence/srcs/frontend/src/tetris.css index 37ae90e..bc30260 100644 --- a/Transcendence/srcs/frontend/src/tetris.css +++ b/Transcendence/srcs/frontend/src/tetris.css @@ -524,4 +524,13 @@ button:disabled { opacity: 0.3; cursor: not-allowed; } width: 30px; } +.hist-win { + color: var(--accent); + font-weight: bold; +} + +.hist-loss { + color: var(--accent2); +} + body { overflow-y: auto; } diff --git a/Transcendence/srcs/frontend/src/tetris.html b/Transcendence/srcs/frontend/src/tetris.html index 9c4799c..ab546b7 100644 --- a/Transcendence/srcs/frontend/src/tetris.html +++ b/Transcendence/srcs/frontend/src/tetris.html @@ -127,6 +127,7 @@
| # | Date | Type | Score | Résultat |
|---|---|---|---|---|
| Chargement… | ||||