From 4cd449c0cf1e7101b351920bc4577be81594da62 Mon Sep 17 00:00:00 2001 From: mudabbir-ahmad Date: Tue, 18 Mar 2025 22:35:04 +0000 Subject: [PATCH] fixed stats page to show correct number of skipped clues. reflected this change accurately in leaderboards for users and admins as to not create a bug where a skipped clue would contribute to progress --- app/(main)/clue/[clueId]/page.js | 2 +- app/(main)/map/page.js | 6 ++-- app/(main)/stats/page.js | 30 +++++++++++------- app/api/admin/leaderboard/route.js | 3 +- .../teams/[teamId]/reset-progress/route.js | 7 ++-- app/api/leaderboard/route.js | 8 +++-- app/api/team-stats/route.js | 29 +++++++---------- clue_hunt.db | Bin 176128 -> 180224 bytes 8 files changed, 46 insertions(+), 39 deletions(-) diff --git a/app/(main)/clue/[clueId]/page.js b/app/(main)/clue/[clueId]/page.js index efb8ccf..0870169 100644 --- a/app/(main)/clue/[clueId]/page.js +++ b/app/(main)/clue/[clueId]/page.js @@ -588,7 +588,7 @@ export default function CluePage({ params }) { )} - + {clueSkipped && !clueFound && (
↷
diff --git a/app/(main)/map/page.js b/app/(main)/map/page.js index 97f4929..af8e670 100644 --- a/app/(main)/map/page.js +++ b/app/(main)/map/page.js @@ -338,8 +338,10 @@ export default function MapPage() { // Function to determine clue button class based on status const getClueButtonClass = (clue) => { if (clue.found) return `${styles["clue-button"]} ${styles["clue-found"]}`; - if (clue.skipped) return `${styles["clue-button"]} ${styles["clue-skipped"]}`; - if (clue.available) return `${styles["clue-button"]} ${styles["clue-available"]}`; + if (clue.skipped) + return `${styles["clue-button"]} ${styles["clue-skipped"]}`; + if (clue.available) + return `${styles["clue-button"]} ${styles["clue-available"]}`; return `${styles["clue-button"]} ${styles["clue-locked"]}`; }; diff --git a/app/(main)/stats/page.js b/app/(main)/stats/page.js index 4b95b3e..01f2363 100644 --- a/app/(main)/stats/page.js +++ b/app/(main)/stats/page.js @@ -86,14 +86,18 @@ export default function StatsPage() { return (
-

Found Clues ({foundClues?.length || 0})

+

+ Found Clues ({foundClues?.length || 0}) +

    {foundClues?.length > 0 ? ( - foundClues.map(clue => ( + foundClues.map((clue) => (
  • ✓
    -
    {clue.title || `Clue #${clue.id}`}
    +
    + {clue.title || `Clue #${clue.id}`} +
    {new Date(clue.found_at).toLocaleTimeString()}
    @@ -105,14 +109,18 @@ export default function StatsPage() { )}
-

Skipped Clues ({skippedClues?.length || 0})

+

+ Skipped Clues ({skippedClues?.length || 0}) +

    {skippedClues?.length > 0 ? ( - skippedClues.map(clue => ( + skippedClues.map((clue) => (
  • ↷
    -
    {clue.title || `Clue #${clue.id}`}
    +
    + {clue.title || `Clue #${clue.id}`} +
    Skipped at {new Date(clue.found_at).toLocaleTimeString()}
    @@ -182,7 +190,7 @@ export default function StatsPage() {
    Clues Found: - {teamStats.foundClues.length} + {teamStats.foundClues.length} of {teamStats.totalClues}
    @@ -191,7 +199,9 @@ export default function StatsPage() {
    Clues Skipped: - {teamStats.skippedClues} + + {teamStats.skippedCluesCount} +
    Current Rank: @@ -214,9 +224,7 @@ export default function StatsPage() { {expanded && ( -
    - {renderCluesList()} -
    +
    {renderCluesList()}
    )}
    diff --git a/app/api/admin/leaderboard/route.js b/app/api/admin/leaderboard/route.js index 371ede0..07e583e 100644 --- a/app/api/admin/leaderboard/route.js +++ b/app/api/admin/leaderboard/route.js @@ -38,13 +38,14 @@ export async function GET(request) { const totalClues = clueCountResult?.total || 0; // Get all teams with member count and clues found + // Modified to exclude skipped clues from cluesFound count const teams = await query(` SELECT t.id, t.name, t.code, COUNT(DISTINCT u.id) as memberCount, - COUNT(DISTINCT tc.clue_id) as cluesFound, + COUNT(DISTINCT CASE WHEN tc.skipped = 0 OR tc.skipped IS NULL THEN tc.clue_id END) as cluesFound, MAX(tc.found_at) as lastActivity FROM teams t diff --git a/app/api/admin/teams/[teamId]/reset-progress/route.js b/app/api/admin/teams/[teamId]/reset-progress/route.js index 2dceff1..6f27894 100644 --- a/app/api/admin/teams/[teamId]/reset-progress/route.js +++ b/app/api/admin/teams/[teamId]/reset-progress/route.js @@ -23,7 +23,8 @@ async function verifyAdmin(request) { return { authorized: true, token }; } -export async function POST(request, context) { +// Make sure the reset progress API also handles the skipped flag +export async function POST(request, { params }) { try { // Verify admin access const { authorized, error, status } = await verifyAdmin(request); @@ -31,7 +32,7 @@ export async function POST(request, context) { return Response.json({ error }, { status }); } - const { teamId } = context.params; + const { teamId } = params; // Validate teamId is a number if (isNaN(parseInt(teamId))) { @@ -44,7 +45,7 @@ export async function POST(request, context) { return Response.json({ error: "Team not found" }, { status: 404 }); } - // Delete all clue progress for the team + // When resetting progress, make sure to reset skipped status too await run("DELETE FROM team_clues WHERE team_id = ?", [teamId]); return Response.json({ diff --git a/app/api/leaderboard/route.js b/app/api/leaderboard/route.js index 7f6948b..d6205c4 100644 --- a/app/api/leaderboard/route.js +++ b/app/api/leaderboard/route.js @@ -25,12 +25,13 @@ export async function GET(request) { // Get all teams with progress info and member count // Only include teams that have at least one member + // Modify the SQL query to exclude skipped clues from the count const teams = await query(` SELECT - t.id, - t.name, + t.id, + t.name, t.code, - COUNT(DISTINCT tc.clue_id) as cluesFound, + COUNT(DISTINCT CASE WHEN tc.skipped = 0 OR tc.skipped IS NULL THEN tc.clue_id END) as cluesFound, MAX(tc.found_at) as lastActivity, COUNT(DISTINCT u.id) as memberCount FROM @@ -49,6 +50,7 @@ export async function GET(request) { `); // Add progress percentage and total clues to each team + // Make sure the progress calculation is consistent const teamsWithProgress = teams.map((team) => ({ ...team, totalClues, diff --git a/app/api/team-stats/route.js b/app/api/team-stats/route.js index a07f67a..4685277 100644 --- a/app/api/team-stats/route.js +++ b/app/api/team-stats/route.js @@ -66,29 +66,16 @@ export async function GET(request) { [token.teamId] ); - // We need to calculate skipped clues - these are clues that have higher IDs than the user's lowest unfound clue - // First, get all clue IDs + // Get all clue IDs - this part is still useful for other calculations const allClueIds = await query("SELECT id FROM clues ORDER BY id ASC"); - - // Convert to a simple array of IDs const allClueIdArray = allClueIds.map((c) => c.id); - - // Create a set of found clue IDs for easy lookup const foundClueIdSet = new Set(foundClues.map((c) => c.id)); - - // Find all unfound clue IDs const unfoundClueIds = allClueIdArray.filter( (id) => !foundClueIdSet.has(id) ); - // If there are unfound clues, the ones after the first unfound are "skipped" - let skippedCluesCount = 0; - if (unfoundClueIds.length > 0) { - const lowestUnfoundId = Math.min(...unfoundClueIds); - - // Skipped clues are found clues with IDs higher than the lowest unfound - skippedCluesCount = foundClues.filter((c) => c.id > lowestUnfoundId).length; - } + // Replace the old skipped clues calculation with this simple count + let skippedCluesCount = skippedClues.length; // Get current team rank const teamRankings = await query(` @@ -114,16 +101,22 @@ export async function GET(request) { let currentRank = teamRankings.findIndex((t) => t.id === team.id) + 1; if (currentRank === 0) currentRank = teamRankings.length + 1; // If not found (shouldn't happen) + // Update progress calculation - don't subtract skippedCluesCount since foundClues query already excludes skipped clues + const correctlyFoundCount = foundClues.length; // <-- Fixed: don't subtract again + // Construct response object const teamStats = { team, totalClues, foundClues, - remainingClues: totalClues - foundClues.length, + skippedClues, + remainingClues: totalClues - correctlyFoundCount, skippedCluesCount, currentRank, progress: - totalClues > 0 ? Math.round((foundClues.length / totalClues) * 100) : 0, + totalClues > 0 + ? Math.round((correctlyFoundCount / totalClues) * 100) + : 0, }; // Return only the teamStats object instead of trying to include undefined variables diff --git a/clue_hunt.db b/clue_hunt.db index 371a853bb737fc836604448c794feade926de7b8..de55ce0f632d81169f99cff1dcedbc5939395f85 100644 GIT binary patch delta 386 zcmZp8z}3*eJwcjv9s>h|&O`-!#(5hPob4H}ZeC)apuokKYj98d@kA8Ce+{SQ%PwK9z43z#+{a4>XBEXEM(L6DI!n%}xho z`PqO1+WoR>9Bl>wj_6v| delta 170 zcmV;b09F5hfD3@&3XmHGnE(I)E0G{S0hzI2Lq7r0v!p*@APNEx$^Z}L56Ta(vkqXO z4;(NW0|fyAGYJm^GB7eVEif}JF*qPHF*-FgIyAG&Z#qy28V_Xv0000hlMKK#vq0b_ z53^;@pKuBS5Ay&I`VaFD>a!8B+z$x{1OWj74+8@Lhx1PXxARW|5l{n30W6aTkd%>< YkpnT0QJ4Rr0u`5dp#mPaVxa<_4p)0Ke*gdg