diff --git a/public/src/js/leaderboard.js b/public/src/js/leaderboard.js index a28199f..2969a40 100644 --- a/public/src/js/leaderboard.js +++ b/public/src/js/leaderboard.js @@ -77,9 +77,16 @@ class Leaderboard { } async fetchLeaderboard() { + // Validate songId is a valid number + if (!this.songId || isNaN(parseInt(this.songId))) { + console.error("Invalid song ID for leaderboard:", this.songId) + this.leaderboardData = [] + return + } + try { var response = await loader.ajax( - `${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${this.songId}&difficulty=${this.difficulty}` + `${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${parseInt(this.songId)}&difficulty=${this.difficulty}` ) var data = JSON.parse(response) if (data.status === "ok") { @@ -94,6 +101,7 @@ class Leaderboard { } } + changeDifficulty(direction) { var difficulties = ["easy", "normal", "hard", "oni", "ura"] var currentIndex = difficulties.indexOf(this.difficulty) diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index e2affbf..af64b78 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -958,27 +958,92 @@ class Scoresheet { } submitToLeaderboard(songId, difficulty, scoreObj) { - // Only submit if user is logged in and song has valid ID - if (!account.loggedIn || !songId) { + // Only submit if user is logged in and song has valid numeric ID + if (!account.loggedIn || !songId || isNaN(parseInt(songId))) { return } + var self = this loader.getCsrfToken().then(token => { var request = new XMLHttpRequest() request.open("POST", "api/leaderboard/submit") request.setRequestHeader("Content-Type", "application/json;charset=UTF-8") request.setRequestHeader("X-CSRFToken", token) + + request.onload = function () { + if (request.status === 200) { + try { + var response = JSON.parse(request.responseText) + if (response.status === "ok") { + self.showLeaderboardNotification(response.message) + } + } catch (e) { + console.error("Failed to parse leaderboard response:", e) + } + } + } + request.send(JSON.stringify({ - song_id: songId, + song_id: parseInt(songId), difficulty: difficulty, score: scoreObj })) }).catch(() => { - // Silently fail - leaderboard submission is optional console.log("Leaderboard submission failed") }) } + showLeaderboardNotification(message) { + var notification = document.createElement("div") + notification.className = "leaderboard-notification" + notification.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + padding: 15px 25px; + background: linear-gradient(135deg, #4a90e2, #7b68ee); + color: white; + border-radius: 10px; + font-size: 16px; + font-family: ${strings.font || "sans-serif"}; + z-index: 10000; + box-shadow: 0 4px 15px rgba(0,0,0,0.3); + opacity: 0; + transform: translateX(100px); + transition: all 0.3s ease-out; + ` + + var text = "" + switch (message) { + case "score_submitted": text = "πŸ† ζˆη»©ε·²ζδΊ€εˆ°ζŽ’θ‘Œζ¦œοΌ"; break + case "score_updated": text = "πŸŽ‰ ζŽ’θ‘Œζ¦œζˆη»©ε·²ζ›΄ζ–°οΌ"; break + case "score_not_higher": text = "πŸ“Š ε·²ζœ‰ζ›΄ι«˜ζˆη»©"; break + case "score_too_low": text = "ζœͺθΏ›ε…₯ζŽ’θ‘Œζ¦œε‰50"; break + default: text = "ζŽ’θ‘Œζ¦œε·²ζ›΄ζ–°" + } + notification.innerText = text + + document.body.appendChild(notification) + + // Trigger animation + setTimeout(() => { + notification.style.opacity = "1" + notification.style.transform = "translateX(0)" + }, 10) + + // Remove after 3 seconds + setTimeout(() => { + notification.style.opacity = "0" + notification.style.transform = "translateX(100px)" + setTimeout(() => { + if (notification.parentNode) { + notification.parentNode.removeChild(notification) + } + }, 300) + }, 3000) + } + + clean() { this.keyboard.clean() this.gamepad.clean()