From b779662245b42f37986a3d9f00e55feb0901bef8 Mon Sep 17 00:00:00 2001 From: zramsay Date: Wed, 12 Mar 2025 10:29:56 -0400 Subject: [PATCH] now --- src/app/api/auth/[...nextauth]/route.ts | 60 +++++++++++++++++ src/app/points/page.tsx | 22 ++++-- src/services/userPointsService.ts | 89 ++++++++++++++----------- 3 files changed, 125 insertions(+), 46 deletions(-) diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts index b2b133c..786a97e 100644 --- a/src/app/api/auth/[...nextauth]/route.ts +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -67,11 +67,47 @@ const authOptions = { console.log("Initial sign-in, storing profile data in token"); token.userId = token.sub; // Use sub as the primary userId token.email = profile.email; + + // Register user with Supabase immediately after successful authentication + try { + const { ensureUserExists } = require('../../../../services/userPointsService'); + console.log("Registering user in Supabase:", { userId: token.userId, email: token.email }); + + if (token.userId && token.email) { + const userUuid = await ensureUserExists( + token.userId, + token.email, + profile.name + ); + console.log("User registered in Supabase:", userUuid); + } else { + console.warn("Missing user data for Supabase registration"); + } + } catch (err) { + console.error("Error registering user in Supabase:", err); + // Continue with auth flow even if registration fails + } } else if (user) { // If we have user but no profile, make sure to keep the user data console.log("User data available, storing in token"); token.userId = token.sub || user.id; token.email = token.email || user.email; + + // Also ensure user exists in Supabase on non-initial sign-ins + try { + const { ensureUserExists } = require('../../../../services/userPointsService'); + console.log("Ensuring user exists in Supabase (non-initial sign-in)"); + + if (token.userId && token.email) { + await ensureUserExists( + token.userId, + token.email, + token.name + ); + } + } catch (err) { + console.error("Error ensuring user exists in Supabase:", err); + } } else { // Ensure email is always available for user identification console.log("No profile or user, using token defaults"); @@ -110,6 +146,30 @@ const authOptions = { session.user.email = token.email; console.log("Added missing email to session from token:", token.email); } + + // Also ensure user exists in Supabase when session is accessed + // This provides yet another safety check for user registration + try { + if (session.user.id && session.user.email) { + const { ensureUserExists } = require('../../../../services/userPointsService'); + console.log("Ensuring user exists in Supabase (from session callback)"); + + const userUuid = await ensureUserExists( + session.user.id, + session.user.email, + session.user.name + ); + + // If the ensured UUID is different from session user ID, update session + if (userUuid && userUuid !== session.user.id) { + console.log(`Session user ID (${session.user.id}) doesn't match Supabase user ID (${userUuid}), updating session`); + session.user.id = userUuid; + } + } + } catch (err) { + console.error("Error ensuring user exists during session callback:", err); + // Continue returning session even if this fails + } } // Detailed logging of the session we're returning diff --git a/src/app/points/page.tsx b/src/app/points/page.tsx index 0a99b6e..3d151e6 100644 --- a/src/app/points/page.tsx +++ b/src/app/points/page.tsx @@ -32,14 +32,22 @@ export default function PointsPage() { useEffect(() => { // Only load points if user is authenticated if (isAuthenticated && session?.user) { - // Use email as fallback if id is missing - const userId = session.user.id || session.user.email; - if (userId) { - console.log('Loading points for user:', userId); - loadUserPoints(userId); + // ALWAYS use email for consistent user identification + // This ensures we always get the same user regardless of session ID changes + const userIdentifier = session.user.email; + if (userIdentifier) { + console.log('Loading points using email identifier:', userIdentifier); + loadUserPoints(userIdentifier); } else { - setError('User ID or email not available'); - setLoading(false); + // Fallback to ID if somehow email is missing + const userId = session.user.id; + if (userId) { + console.log('No email available, falling back to user ID:', userId); + loadUserPoints(userId); + } else { + setError('User ID or email not available'); + setLoading(false); + } } } else if (status !== 'loading') { // If user is not authenticated and we've finished loading auth status diff --git a/src/services/userPointsService.ts b/src/services/userPointsService.ts index 5f59608..d370239 100644 --- a/src/services/userPointsService.ts +++ b/src/services/userPointsService.ts @@ -319,8 +319,9 @@ export async function findUserByEmail(email: string) { /** * Get a user's total points + * This function is email-aware and will find the correct user by email */ -export async function getUserPoints(userId: string) { +export async function getUserPoints(userIdOrEmail: string) { try { // Add safe mode to bypass database operations if needed const safeMode = process.env.POINTS_SAFE_MODE === 'true'; @@ -329,31 +330,33 @@ export async function getUserPoints(userId: string) { return 1; // Return 1 as a default so UI shows something } - if (!userId) { - console.warn('Cannot get points for undefined userId'); + if (!userIdOrEmail) { + console.warn('Cannot get points for undefined userId/email'); return 0; } - console.log('Fetching points for user:', userId); + console.log('Processing points request for:', userIdOrEmail); - // If the userId is not a UUID and looks like an email, try to find by email - if (!validateUuid(userId) && userId.includes('@')) { - const user = await findUserByEmail(userId); + // IMPORTANT: Always try to find by email first if it looks like an email + // This ensures consistent user identification regardless of the session ID + let userId = userIdOrEmail; + if (userIdOrEmail.includes('@')) { + console.log('Input looks like an email, finding consistent user ID'); + const user = await findUserByEmail(userIdOrEmail); if (user) { userId = user.id; - console.log('Found user by email, using ID:', userId); + console.log('Found user by email, using consistent ID:', userId); } else { console.log('No user found by email, returning 0 points'); return 0; } - } - - // Validate final user ID format - if (!validateUuid(userId)) { - console.warn('Invalid UUID format for user:', userId); + } else if (!validateUuid(userIdOrEmail)) { + // If not email and not valid UUID, we can't proceed + console.warn('Invalid user identifier format:', userIdOrEmail); return 0; } + // At this point, userId should be a valid UUID // Try getting total points using the RPC function try { const { data: totalPoints, error } = await supabaseAdmin.rpc('get_user_total_points', { @@ -394,8 +397,9 @@ export async function getUserPoints(userId: string) { /** * Get a user's point transaction history + * This function is email-aware and will find the correct user by email */ -export async function getUserTransactions(userId: string) { +export async function getUserTransactions(userIdOrEmail: string) { try { // Add safe mode to bypass database operations if needed const safeMode = process.env.POINTS_SAFE_MODE === 'true'; @@ -404,7 +408,7 @@ export async function getUserTransactions(userId: string) { // Return a sample transaction for UI display return [{ id: 1, - user_id: userId, + user_id: userIdOrEmail, points: 1, transaction_type: 'image_upload', image_hash: null, @@ -415,31 +419,33 @@ export async function getUserTransactions(userId: string) { }]; } - if (!userId) { - console.warn('Cannot get transactions for undefined userId'); + if (!userIdOrEmail) { + console.warn('Cannot get transactions for undefined userId/email'); return []; } - console.log('Fetching transactions for user:', userId); + console.log('Processing transactions request for:', userIdOrEmail); - // If the userId is not a UUID and looks like an email, try to find by email - if (!validateUuid(userId) && userId.includes('@')) { - const user = await findUserByEmail(userId); + // IMPORTANT: Always try to find by email first if it looks like an email + // This ensures consistent user identification regardless of the session ID + let userId = userIdOrEmail; + if (userIdOrEmail.includes('@')) { + console.log('Input looks like an email, finding consistent user ID'); + const user = await findUserByEmail(userIdOrEmail); if (user) { userId = user.id; - console.log('Found user by email, using ID:', userId); + console.log('Found user by email, using consistent ID:', userId); } else { console.log('No user found by email, returning empty transactions'); return []; } - } - - // Validate final user ID format - if (!validateUuid(userId)) { - console.warn('Invalid UUID format for user:', userId); + } else if (!validateUuid(userIdOrEmail)) { + // If not email and not valid UUID, we can't proceed + console.warn('Invalid user identifier format:', userIdOrEmail); return []; } + // At this point, userId should be a valid UUID // Try the RPC function first try { const { data: transactions, error: rpcError } = await supabaseAdmin.rpc('get_user_transactions', { @@ -480,32 +486,37 @@ export async function getUserTransactions(userId: string) { /** * Get full user stats + * This function is email-aware and will find the correct user by email */ -export async function getUserStats(userId: string) { +export async function getUserStats(userIdOrEmail: string) { try { - if (!userId) { - console.warn('Cannot get stats for undefined userId'); + if (!userIdOrEmail) { + console.warn('Cannot get stats for undefined userId/email'); return null; } - // If the userId is not a UUID and looks like an email, try to find by email - if (!validateUuid(userId) && userId.includes('@')) { - const user = await findUserByEmail(userId); + console.log('Processing stats request for:', userIdOrEmail); + + // IMPORTANT: Always try to find by email first if it looks like an email + // This ensures consistent user identification regardless of the session ID + let userId = userIdOrEmail; + if (userIdOrEmail.includes('@')) { + console.log('Input looks like an email, finding consistent user ID'); + const user = await findUserByEmail(userIdOrEmail); if (user) { userId = user.id; - console.log('Found user by email, using ID:', userId); + console.log('Found user by email, using consistent ID:', userId); } else { console.log('No user found by email, returning null stats'); return null; } - } - - // Validate final user ID format - if (!validateUuid(userId)) { - console.warn('Invalid UUID format for user:', userId); + } else if (!validateUuid(userIdOrEmail)) { + // If not email and not valid UUID, we can't proceed + console.warn('Invalid user identifier format:', userIdOrEmail); return null; } + // At this point, userId should be a valid UUID // Get user stats using the RPC function const { data, error } = await supabaseAdmin.rpc('get_user_stats', { user_id_param: userId