Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/context/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { createContext, useContext, useState, useEffect, useRef } from 'react';
import { supabase } from '../lib/supabaseClient';
import { supabase, onAuthStateChange } from '../lib/supabaseClient';
import { retryWithBackoff } from '../lib/supabaseClient';
import { toast } from 'react-hot-toast';
// Removed POSSettingsAPI import to avoid circular dependency
Expand Down Expand Up @@ -442,9 +442,12 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
}
};

// Set up auth state change listener
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
logInfo('AuthProvider', `Auth state change: ${event}`, session?.user?.email);
// Set up auth state change listener using centralized handler
const unsubscribe = onAuthStateChange((event, session) => {
// Only log significant events
if (event === 'SIGNED_IN' || event === 'SIGNED_OUT' || event === 'TOKEN_REFRESHED') {
logInfo('AuthProvider', `Auth state change: ${event}`, session?.user?.email);
}

if (event === 'SIGNED_IN' && session?.user) {
logInfo('AuthProvider', `User signed in: ${session.user.email}`);
Expand Down Expand Up @@ -473,7 +476,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
// Cleanup function
return () => {
logInfo('AuthProvider', 'Cleaning up AuthProvider');
subscription.unsubscribe();
unsubscribe();
authProviderMountCount.current--;
// Don't reset globalAuthProviderInitialized on cleanup to prevent re-initialization
};
Expand Down
13 changes: 8 additions & 5 deletions src/context/PaymentsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
import { supabase } from '../lib/supabaseClient';
import { supabase, onAuthStateChange } from '../lib/supabaseClient';
import { safeQuery, SupabaseErrorHandler } from '../utils/supabaseErrorHandler';

export interface PaymentRow {
Expand Down Expand Up @@ -257,10 +257,13 @@ export const PaymentsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
useEffect(() => {
fetchPayments();

// Listen for authentication state changes with debouncing
// Listen for authentication state changes with debouncing using centralized handler
let authTimeout: NodeJS.Timeout;
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
console.log('Auth state changed:', event, session?.user?.id);
const unsubscribe = onAuthStateChange((event, session) => {
// Only log significant events
if (event === 'SIGNED_IN' || event === 'SIGNED_OUT') {
console.log('Auth state changed:', event, session?.user?.id);
}

// Clear previous timeout to debounce rapid auth changes
if (authTimeout) {
Expand All @@ -282,7 +285,7 @@ export const PaymentsProvider: React.FC<{ children: React.ReactNode }> = ({ chil
if (authTimeout) {
clearTimeout(authTimeout);
}
subscription.unsubscribe();
unsubscribe();
};
}, []);

Expand Down
38 changes: 36 additions & 2 deletions src/lib/supabaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,20 @@ const isBrowser = typeof window !== 'undefined';
// Create single instance with enhanced configuration to fix 400/406 errors
export const supabase = createClient<Database>(config.url, config.key, {
auth: {
// Enable automatic session refresh
// Disable automatic session refresh when no session exists
autoRefreshToken: true,
// Persist session in localStorage
persistSession: true,
// Detect session in URL (for magic links, etc.)
detectSessionInUrl: true,
detectSessionInUrl: false, // Disable to prevent unnecessary checks
// Storage key for session - CHANGED to clear cache
storageKey: 'lats-app-auth-token',
// Storage interface (only use localStorage in browser)
storage: isBrowser ? window.localStorage : undefined,
// Add flow type to prevent auth errors
flowType: 'pkce',
// Disable debug mode to reduce console spam
debug: false,
},
// Enable real-time subscriptions with basic configuration
realtime: {
Expand Down Expand Up @@ -298,6 +300,38 @@ export const monitorConnection = (intervalMs: number = 30000) => {
return () => clearInterval(interval);
};

// Custom auth state manager to prevent excessive auth checks
let authStateInitialized = false;
let authStateCallbacks: Array<(event: string, session: any) => void> = [];

// Enhanced auth state change handler
export const onAuthStateChange = (callback: (event: string, session: any) => void) => {
authStateCallbacks.push(callback);

// Only initialize auth state once
if (!authStateInitialized) {
authStateInitialized = true;

supabase.auth.onAuthStateChange((event, session) => {
// Only log significant events, not every INITIAL_SESSION
if (event !== 'INITIAL_SESSION' || session) {
console.log(`🔐 Auth state changed: ${event}`, session ? 'authenticated' : 'not authenticated');
}

// Call all registered callbacks
authStateCallbacks.forEach(cb => cb(event, session));
});
}

// Return unsubscribe function
return () => {
const index = authStateCallbacks.indexOf(callback);
if (index > -1) {
authStateCallbacks.splice(index, 1);
}
};
};

// Auto-run tests when this module is imported
if (isBrowser) {
setTimeout(async () => {
Expand Down