diff --git a/src/api.ts b/src/api.ts index 8beb9ac..0745a84 100644 --- a/src/api.ts +++ b/src/api.ts @@ -96,7 +96,11 @@ api.interceptors.response.use( error.config?.url?.includes('/api/local/login') || error.config?.url?.includes('/api/msft/login'); - if (!isLoginEndpoint) { + // Don't redirect if we're already on the login page (prevents redirect loops) + const isOnLoginPage = window.location.pathname === '/login' || + window.location.pathname.startsWith('/login'); + + if (!isLoginEndpoint && !isOnLoginPage) { // Clear local auth data (httpOnly cookies are cleared by backend) sessionStorage.removeItem('auth_authority'); clearUserDataCache(); @@ -104,6 +108,13 @@ api.interceptors.response.use( window.location.href = '/login'; } } + + // Handle rate limiting (429) - don't throw, just log and return error + if (error.response?.status === 429) { + console.warn('Rate limit exceeded (429). Please wait before making more requests.'); + // Don't cause cascading errors by throwing here + } + return Promise.reject(error); } ); diff --git a/src/hooks/useUsers.ts b/src/hooks/useUsers.ts index 96a78fb..f6e78d6 100644 --- a/src/hooks/useUsers.ts +++ b/src/hooks/useUsers.ts @@ -314,7 +314,13 @@ export function useOrgUsers() { setAttributes(attrs); return attrs; } catch (error: any) { - console.error('Error fetching attributes:', error); + // Don't log 429 errors as errors (they're rate limit warnings) + if (error.response?.status === 429) { + console.warn('Rate limit exceeded while fetching user attributes. Please wait.'); + } else if (error.response?.status !== 401) { + // Only log non-auth errors (401 is expected when not logged in) + console.error('Error fetching attributes:', error); + } setAttributes([]); return []; } @@ -551,19 +557,26 @@ export function useOrgUsers() { // Ensure attributes are loaded - can be called by EditActionButton const ensureAttributesLoaded = useCallback(async () => { + // Don't fetch attributes if user is not authenticated (prevents 401 errors) + if (!user) { + return []; + } + if (attributes && attributes.length > 0) { return attributes; } const fetchedAttributes = await fetchAttributes(); return fetchedAttributes; - }, [attributes, fetchAttributes]); + }, [attributes, fetchAttributes, user]); - // Fetch attributes and permissions on mount + // Fetch attributes and permissions on mount (only if user is authenticated) useEffect(() => { - fetchAttributes(); - fetchPermissions(); - }, [fetchAttributes, fetchPermissions]); + if (user) { + fetchAttributes(); + fetchPermissions(); + } + }, [fetchAttributes, fetchPermissions, user]); // Initial fetch useEffect(() => {