From 341c551ea5286bb73882c41de27b21704ac5753d Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Mon, 23 Feb 2026 17:48:14 +0000 Subject: [PATCH] refactor: simplify UserContext and supabaseClient - Refactored UserContext.tsx (67 lines simplified) - Simplified supabaseClient.ts (82 lines reduced) - Updated .env.development for local dev --- .env.development | 2 +- src/contexts/UserContext.tsx | 67 +++++++++++------------------ src/supabaseClient.ts | 82 ++++++++++++------------------------ 3 files changed, 51 insertions(+), 100 deletions(-) diff --git a/.env.development b/.env.development index 7206e53..16607d6 100644 --- a/.env.development +++ b/.env.development @@ -1,3 +1,4 @@ +VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiaWF0IjoxNzcxODE3MjE5LCJpc3MiOiJzdXBhYmFzZSIsInN1YiI6IjAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMCIsImV4cCI6MzM0ODYxNzIxOSwicm9sZSI6ImFub24ifQ.JbmQOTOBAzpBJ9JttOrGlo_JTXDXhCjYMjKiFvRkaNQ PORT_FRONTEND=5173 PORT_FRONTEND_HMR=3002 PORT_API=8000 @@ -15,7 +16,6 @@ VITE_APP_HMR_URL=http://192.168.0.94:5173 # Supabase is on external container - use its IP VITE_SUPABASE_URL=http://192.168.0.155:8000 -VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiaWF0IjoxNzcxODE3MjE5LCJpc3MiOiJzdXBhYmFzZSIsInN1YiI6IjAwMDAwMDAwLTAwMDAtMDAwMC0wMDAwLTAwMDAwMDAwMDAwMCIsImV4cCI6MzM0ODYxNzIxOSwicm9sZSI6ImFub24ifQ.JbmQOTOBAzpBJ9JttOrGlo_JTXDXhCjYMjKiFvRkaNQ # API should use localhost for local development VITE_API_URL=http://192.168.0.94:8000 diff --git a/src/contexts/UserContext.tsx b/src/contexts/UserContext.tsx index e1791ca..1918a46 100644 --- a/src/contexts/UserContext.tsx +++ b/src/contexts/UserContext.tsx @@ -8,9 +8,6 @@ import { DatabaseNameService } from '../services/graph/databaseNameService'; import { provisionUser } from '../services/provisioningService'; import { storageService, StorageKeys } from '../services/auth/localStorageService'; -const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; -const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY; - export interface UserContextType { user: CCUser | null; loading: boolean; @@ -32,9 +29,9 @@ export const UserContext = createContext({ preferences: {}, isMobile: false, isInitialized: false, - updateProfile: async () => { }, - updatePreferences: async () => { }, - clearError: () => { } + updateProfile: async () => {}, + updatePreferences: async () => {}, + clearError: () => {} }); export const UserProvider = ({ children }: { children: React.ReactNode }) => { @@ -66,7 +63,7 @@ export const UserProvider = ({ children }: { children: React.ReactNode }) => { return; } } - + let userInfo: User | null = null; // Declare at function scope try { logger.debug('user-context', '🔄 Resolving user profile', { @@ -113,61 +110,45 @@ export const UserProvider = ({ children }: { children: React.ReactNode }) => { email: userInfo.email }); - let profileRow: Record | null = null; + let profileRow: Record | null = null; logger.debug('user-context', '🔧 Step 5: Querying profiles table...', { userId: userInfo.id }); - + // Set loading state when we start the actual database query setLoading(true); - + // Query profiles table without timeout to see actual error logger.debug('user-context', '🔧 Step 5b: Starting profiles query...', { userId: userInfo.id, clientType: 'authenticated' }); - - // Try direct fetch instead of Supabase client to bypass hanging issue - logger.debug('user-context', '🔧 Step 5b1: About to make profiles query with direct fetch...', { + + logger.debug('user-context', '🔧 Step 5b1: About to make profiles query...', { userId: userInfo.id, queryStarted: true }); - - const { data, error } = await fetch(`${supabaseUrl}/rest/v1/profiles?select=*&id=eq.${userInfo.id}`, { - headers: { - 'Authorization': `Bearer ${supabaseAnonKey}`, - 'Content-Type': 'application/json' - } - }) - .then(async (response) => { - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`); - } - const result = await response.json(); - return { data: result[0] || null, error: null }; - }) - .catch((err) => { - logger.debug('user-context', '🔧 Step 5b1: Direct fetch failed', { - userId: userInfo?.id, - error: err.message - }); - return { data: null, error: { message: err.message, code: 'FETCH_ERROR' } }; - }); - + + const { data, error } = await supabase + .from('profiles') + .select('*') + .eq('id', userInfo.id) + .single(); + logger.debug('user-context', '🔧 Step 5b2: Direct fetch completed...', { userId: userInfo.id, hasData: !!data, hasError: !!error }); - + logger.debug('user-context', '🔧 Step 5c: Profiles query completed', { hasData: !!data, hasError: !!error, errorCode: error?.code, errorMessage: error?.message }); - + logger.debug('user-context', '🔧 Step 5a: Profiles query result', { hasData: !!data, hasError: !!error, @@ -319,7 +300,7 @@ export const UserProvider = ({ children }: { children: React.ReactNode }) => { userId: userInfo?.id, email: userInfo?.email }); - + if (userInfo) { const metadata = userInfo.user_metadata as CCUserMetadata; const fallbackProfile: CCUser = { @@ -333,12 +314,12 @@ export const UserProvider = ({ children }: { children: React.ReactNode }) => { created_at: userInfo.created_at, updated_at: userInfo.updated_at }; - + DatabaseNameService.rememberDatabaseNames({ userDbName: fallbackProfile.user_db_name, schoolDbName: fallbackProfile.school_db_name }); - + setProfile(fallbackProfile); logger.debug('user-context', '✅ Fallback profile created', { userId: fallbackProfile.id, @@ -348,7 +329,7 @@ export const UserProvider = ({ children }: { children: React.ReactNode }) => { } else { setProfile(null); } - + setPreferences({}); setError(error instanceof Error ? error : new Error('Failed to load user profile')); setLoading(false); // Ensure loading is cleared on error @@ -356,12 +337,12 @@ export const UserProvider = ({ children }: { children: React.ReactNode }) => { logger.debug('user-context', '🔧 Finalizing user context initialization...', { isMounted: mountedRef.current }); - + if (mountedRef.current) { // Loading state is already managed above, just log completion logger.debug('user-context', '✅ User context initialization complete'); } - + logger.debug('user-context', '🔧 Step 10: Setting isInitialized to true'); setIsInitialized(true); logger.debug('user-context', '✅ User context initialized flag set - initialization complete!', { diff --git a/src/supabaseClient.ts b/src/supabaseClient.ts index 3ed9c43..aee3177 100644 --- a/src/supabaseClient.ts +++ b/src/supabaseClient.ts @@ -4,65 +4,35 @@ import { logger } from './debugConfig'; const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY; -logger.info('supabase-client', '🔄 Supabase configuration', { - url: supabaseUrl, - key: supabaseAnonKey, -}); - if (!supabaseUrl || !supabaseAnonKey) { - logger.error('supabase-client', '❌ Missing Supabase configuration', { - hasUrl: !!supabaseUrl, - hasKey: !!supabaseAnonKey, - }); throw new Error('Missing Supabase configuration'); } -// Lazy-loaded Supabase client instance for non-auth operations -let supabaseInstance: SupabaseClient | null = null; - -const getSupabaseClient = () => { - if (!supabaseInstance) { - logger.info('supabase-client', '🔄 Initializing Supabase client'); - supabaseInstance = createClient( - supabaseUrl, - supabaseAnonKey, - { - auth: { - flowType: 'pkce', - autoRefreshToken: true, - persistSession: true, - detectSessionInUrl: false, - storage: window.localStorage, - storageKey: 'supabase.auth.token', - debug: true - }, - global: { - headers: { - 'X-Client-Info': 'classroom-copilot', - }, - }, - // Allow JWT issuer mismatch for local development - db: { - schema: 'public' - } - } - ); - - // Log configuration in development - logger.info('supabase-client', '🔄 Supabase client configuration loaded', { - url: supabaseUrl, - hasKey: !!supabaseAnonKey, - storageKey: 'supabase.auth.token' - }); - } - return supabaseInstance; -}; - -// Export a proxy that will lazy load the client when needed -export const supabase = new Proxy({} as SupabaseClient, { - get: (target, prop) => { - const client = getSupabaseClient(); - return client[prop as keyof SupabaseClient]; - } +logger.info('supabase-client', '🔄 Initializing Supabase client', { + url: supabaseUrl, + hasKey: !!supabaseAnonKey, }); +export const supabase: SupabaseClient = createClient( + supabaseUrl, + supabaseAnonKey, + { + auth: { + flowType: 'pkce', + autoRefreshToken: true, + persistSession: true, + detectSessionInUrl: false, + storage: window.localStorage, + storageKey: 'supabase.auth.token', + debug: true + }, + global: { + headers: { + 'X-Client-Info': 'classroom-copilot', + }, + }, + db: { + schema: 'public' + } + } +); \ No newline at end of file