diff --git a/sql/init.sql b/sql/init.sql index d1c3fdc..6131d54 100644 --- a/sql/init.sql +++ b/sql/init.sql @@ -2,26 +2,21 @@ -- This file includes all the necessary SQL files to set up the database schema -- Enable UUID extension if not already enabled CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - -- Common utility functions \ i common / utility_functions.sql -- Authentication and user management \ i auth / user_roles.sql \ i auth / user_triggers.sql \ i auth / user_preferences.sql -- Problem-related tables and functions -\ i problems / problems.sql \ i problems / user_problem_feedback.sql \ i problems / user_solved_problems.sql \ i problems / problem_functions.sql -- Contest-related tables and functions +\ i problems / problems.sql \ i problems / user_problem_feedback.sql \ i problems / user_solved_problems.sql \ i problems / problem_functions.sql \ i problems / get_user_solved_problems.sql -- Contest-related tables and functions \ i contests / contests.sql \ i contests / user_contest_participation.sql \ i contests / user_contest_feedback.sql \ i contests / contest_functions.sql -- Leaderboard functions \ i leaderboard / leaderboard_functions.sql -- Grant necessary permissions - GRANT USAGE ON SCHEMA public TO anon, authenticated, service_role; - GRANT ALL ON ALL TABLES IN SCHEMA public TO anon, authenticated, service_role; - GRANT ALL ON ALL FUNCTIONS IN SCHEMA public TO anon, authenticated, service_role; - GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO anon, authenticated, service_role; \ No newline at end of file diff --git a/sql/problems/get_user_solved_problems.sql b/sql/problems/get_user_solved_problems.sql new file mode 100644 index 0000000..c1dfaf2 --- /dev/null +++ b/sql/problems/get_user_solved_problems.sql @@ -0,0 +1,16 @@ +-- Function to get solved problems for a specific user +CREATE OR REPLACE FUNCTION get_user_solved_problems(p_user_id UUID) +RETURNS TABLE (problem_id UUID) AS $$ +BEGIN + RETURN QUERY + SELECT usp.problem_id + FROM user_solved_problems usp + JOIN auth.users u ON usp.user_id = u.id + LEFT JOIN user_preferences up ON u.id = up.user_id + WHERE usp.user_id = p_user_id + AND COALESCE(up.hide_from_leaderboard, false) = false; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Grant permissions +GRANT EXECUTE ON FUNCTION get_user_solved_problems TO authenticated, anon; diff --git a/src/lib/components/LeaderboardTable.svelte b/src/lib/components/LeaderboardTable.svelte index a7695d5..43dacc5 100644 --- a/src/lib/components/LeaderboardTable.svelte +++ b/src/lib/components/LeaderboardTable.svelte @@ -111,15 +111,39 @@ function getRankTierName(rank: number): string { {entry.username.substring(0, 2).toUpperCase()} {/if} - - @{entry.username} - +
+ + @{entry.username} + + + + + + + + +
@@ -182,11 +206,11 @@ function getRankTierName(rank: number): string { } /* Ensure username is always purple */ -a[href*='github.com'] { +a[href^='/user/'] { color: var(--color-username) !important; } -a[href*='github.com']:hover { +a[href^='/user/']:hover { color: color-mix(in oklab, var(--color-username) 80%, white) !important; } diff --git a/src/lib/components/ProblemDisplay.svelte b/src/lib/components/ProblemDisplay.svelte new file mode 100644 index 0000000..acc9fb0 --- /dev/null +++ b/src/lib/components/ProblemDisplay.svelte @@ -0,0 +1,537 @@ + + + + {targetUser ? `${targetUser.username}'s Solved Problems` : pageTitle} + + + +
+ {#if loading} +
+
+ + + + +

Loading problems...

+
+
+ {:else if error} +
+

{error}

+
+ {:else} +
+ + + + +
+
+
+ +
+
+
+
+ {/if} +
+ + diff --git a/src/lib/services/problem.ts b/src/lib/services/problem.ts index 77e1579..38dffc5 100644 --- a/src/lib/services/problem.ts +++ b/src/lib/services/problem.ts @@ -260,6 +260,34 @@ export async function fetchUserSolvedProblems(): Promise> { } } +/** + * Fetches solved problems for a specific user + * @param userId - User ID to fetch solved problems for + * @returns Set of solved problem IDs + */ +export async function fetchUserSolvedProblemsByUserId(userId: string): Promise> { + if (!userId) { + return new Set(); + } + + try { + // Use the RPC function to get solved problems for a user who isn't hidden from the leaderboard + const { data, error } = await supabase.rpc('get_user_solved_problems', { + p_user_id: userId + }); + + if (error) { + console.error(`Error fetching solved problems for user ${userId}:`, error); + return new Set(); + } + + return new Set(data.map((item: { problem_id: string }) => item.problem_id)); + } catch (err) { + console.error(`Failed to fetch solved problems for user ${userId}:`, err); + return new Set(); + } +} + /** * Marks a problem as solved or unsolved by the current user * @param problemId - Problem ID diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index af81d1e..a441197 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,503 +1,5 @@ - - Problems - - - -
- {#if loading} -
-
- - - - -

Loading problems...

-
-
- {:else if error} -
-

{error}

- -
- {:else} -
- - - - -
-
-
- -
-
-
-
- {/if} -
- - + diff --git a/src/routes/user/[userId]/+page.svelte b/src/routes/user/[userId]/+page.svelte new file mode 100644 index 0000000..d72fe5f --- /dev/null +++ b/src/routes/user/[userId]/+page.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/routes/user/[userId]/+page.ts b/src/routes/user/[userId]/+page.ts new file mode 100644 index 0000000..4b82490 --- /dev/null +++ b/src/routes/user/[userId]/+page.ts @@ -0,0 +1,7 @@ +import type { PageLoad } from './$types'; + +export const load: PageLoad = ({ params }) => { + return { + userId: params.userId + }; +};