diff --git a/next.config.mjs b/next.config.mjs index c9ddb84d..fdf681b1 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,5 +1,6 @@ /** @type {import("next").NextConfig} */ const nextConfig = { + transpilePackages: ["driver.js"], images: { remotePatterns: [ { diff --git a/package-lock.json b/package-lock.json index ce0b55ff..80555633 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@upstash/redis": "^1.38.0", "clsx": "^2.1.1", "date-fns": "^3.6.0", + "driver.js": "^1.4.0", "html-to-image": "^1.11.13", "jspdf": "^4.2.1", "jspdf-autotable": "^5.0.7", @@ -2289,6 +2290,12 @@ "@types/trusted-types": "^2.0.7" } }, + "node_modules/driver.js": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/driver.js/-/driver.js-1.4.0.tgz", + "integrity": "sha512-Gm64jm6PmcU+si21sQhBrTAM1JvUrR0QhNmjkprNLxohOBzul9+pNHXgQaT9lW84gwg9GMLB3NZGuGolsz5uew==", + "license": "MIT" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", diff --git a/package.json b/package.json index fd2359d8..0737870a 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "clsx": "^2.1.1", "date-fns": "^3.6.0", "html-to-image": "^1.11.13", + "driver.js": "^1.4.0", "jspdf": "^4.2.1", "jspdf-autotable": "^5.0.7", "next": "^14.2.35", diff --git a/src/app/api/user/settings/route.ts b/src/app/api/user/settings/route.ts index 04e60932..fbc0a229 100644 --- a/src/app/api/user/settings/route.ts +++ b/src/app/api/user/settings/route.ts @@ -24,12 +24,14 @@ export async function GET(req: NextRequest) { // Fetch user from Supabase const { data, error } = await supabaseAdmin .from("users") - .select("id, github_login, is_public, leaderboard_opt_in") + .select( + "id, github_login, is_public, leaderboard_opt_in, seen_onboarding" + ) .eq("id", user.id) .single(); - if (error) { console.error("Error fetching user:", error); + return NextResponse.json( { error: "Failed to fetch user settings" }, { status: 500 } @@ -46,18 +48,23 @@ export async function PATCH(req: NextRequest) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } - // Get user ID from Supabase - const user = await resolveAppUser(session.githubId, session.githubLogin); +const user = await resolveAppUser(session.githubId, session.githubLogin); - if (!user) { - return NextResponse.json( - { error: "User not found" }, - { status: 404 } - ); - } +if (!user) { + console.error("Error fetching user"); + + return NextResponse.json( + { error: "User not found" }, + { status: 404 } + ); +} + + let body: { + is_public?: boolean; + leaderboard_opt_in?: boolean; + seen_onboarding?: boolean; + }; - // Parse request body - let body: { is_public?: boolean; leaderboard_opt_in?: boolean }; try { body = await req.json(); } catch { @@ -67,49 +74,66 @@ export async function PATCH(req: NextRequest) { ); } - const { is_public, leaderboard_opt_in } = body; + const { + is_public, + leaderboard_opt_in, + seen_onboarding, + } = body; - if ( - typeof is_public !== "boolean" && - typeof leaderboard_opt_in !== "boolean" - ) { - return NextResponse.json( - { error: "At least one boolean setting is required" }, - { status: 400 } - ); - } + const updates: { + is_public?: boolean; + leaderboard_opt_in?: boolean; + seen_onboarding?: boolean; + } = {}; - const updates: { is_public?: boolean; leaderboard_opt_in?: boolean } = {}; if (typeof is_public === "boolean") { updates.is_public = is_public; } + if (typeof leaderboard_opt_in === "boolean") { updates.leaderboard_opt_in = leaderboard_opt_in; + + // If user opts into leaderboard, profile must be public if (leaderboard_opt_in) { updates.is_public = true; } } + if (typeof seen_onboarding === "boolean") { + updates.seen_onboarding = seen_onboarding; + } + + if (Object.keys(updates).length === 0) { + return NextResponse.json( + { error: "No valid fields to update" }, + { status: 400 } + ); + } + const { data: updated, error: updateError } = await supabaseAdmin .from("users") .update(updates) .eq("id", user.id) - .select("id, github_login, is_public, leaderboard_opt_in") + .select( + "id, github_login, is_public, leaderboard_opt_in, seen_onboarding" + ) .single(); if (updateError || !updated) { - console.error("Error updating settings:", updateError); + console.error("Failed to update settings:", updateError); + return NextResponse.json( { error: "Failed to update settings" }, { status: 500 } ); } - // Return updated user (only safe fields) return NextResponse.json({ id: updated.id, github_login: updated.github_login, is_public: updated.is_public, leaderboard_opt_in: updated.leaderboard_opt_in ?? false, + seen_onboarding: updated.seen_onboarding, }); } + diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 0a5de926..d4914bd6 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -51,7 +51,9 @@ export default async function DashboardPage() { {/* Row 1: Contribution graph + heatmap + Friend Comparison on left, Streak on right */}