From 6b3d770182f43d01fb228eb54c48f241159f8bcd Mon Sep 17 00:00:00 2001 From: Valknar XXX Date: Tue, 28 Oct 2025 13:36:32 +0100 Subject: [PATCH] feat: display gamification stats on user profile page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add gamification card to user profile showing: - Total weighted points and rank - Recordings and playbacks count - Unlocked achievements with icons and dates - Link to leaderboard Updates user profile page server load to fetch gamification data from /api/sexy/gamification/user/:id endpoint. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../src/routes/users/[id]/+page.server.ts | 8 ++ .../src/routes/users/[id]/+page.svelte | 88 +++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/packages/frontend/src/routes/users/[id]/+page.server.ts b/packages/frontend/src/routes/users/[id]/+page.server.ts index a63eb23..77020cf 100644 --- a/packages/frontend/src/routes/users/[id]/+page.server.ts +++ b/packages/frontend/src/routes/users/[id]/+page.server.ts @@ -30,12 +30,20 @@ export const load: PageServerLoad = async ({ params, locals, fetch }) => { const likesData = await likesResponse.json(); const likesCount = likesData.data?.[0]?.count || 0; + // Fetch gamification data + const gamificationResponse = await fetch(`/api/sexy/gamification/user/${id}`); + let gamification = null; + if (gamificationResponse.ok) { + gamification = await gamificationResponse.json(); + } + return { user, stats: { comments_count: commentsCount, likes_count: likesCount, }, + gamification, isOwnProfile: locals.authStatus.user?.id === id, }; } catch (error) { diff --git a/packages/frontend/src/routes/users/[id]/+page.svelte b/packages/frontend/src/routes/users/[id]/+page.svelte index d3476dd..b76c3df 100644 --- a/packages/frontend/src/routes/users/[id]/+page.svelte +++ b/packages/frontend/src/routes/users/[id]/+page.svelte @@ -137,5 +137,93 @@ let joinDate = $derived( + + + {#if data.gamification?.stats} + + + +
+

+ + {$_("gamification.stats")} +

+ +
+ + +
+
+
+ {Math.round(data.gamification.stats.total_weighted_points)} +
+
+ {$_("gamification.points")} +
+
+
+
+ #{data.gamification.stats.rank} +
+
+ {$_("gamification.rank")} +
+
+
+
+ {data.gamification.stats.recordings_count} +
+
+ {$_("gamification.recordings")} +
+
+
+
+ {data.gamification.stats.playbacks_count} +
+
+ {$_("gamification.plays")} +
+
+
+ + + {#if data.gamification.achievements?.length > 0} +
+

+ + {$_("gamification.achievements")} ({data.gamification.achievements.length}) +

+
+ {#each data.gamification.achievements as achievement (achievement.id)} +
+ {achievement.icon || "🏆"} + + {achievement.name} + + {#if achievement.date_unlocked} + + {new Date(achievement.date_unlocked).toLocaleDateString($locale)} + + {/if} +
+ {/each} +
+
+ {:else} +
+ +

No achievements unlocked yet

+
+ {/if} +
+
+ {/if}