import { useAuth } from 'react-oidc-context'; import { useCallback } from 'react'; const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001'; export const useAuthenticatedFetch = () => { const auth = useAuth(); const isTokenExpired = useCallback(() => { if (!auth.user?.expires_at) return true; const expiresAt = auth.user.expires_at * 1000; const now = Date.now(); const bufferMs = 60 * 1000; return now >= expiresAt - bufferMs; }, [auth.user?.expires_at]); const ensureValidToken = useCallback(async (): Promise => { if (!auth.user?.access_token) { throw new Error('Not authenticated'); } if (isTokenExpired()) { try { const user = await auth.signinSilent(); if (user?.access_token) { return user.access_token; } } catch { auth.signinRedirect(); throw new Error('Session expired, redirecting to login'); } } return auth.user.access_token; }, [auth, isTokenExpired]); const authFetch = useCallback( async (path: string, options: RequestInit = {}): Promise => { if (!navigator.onLine) { throw new Error('You appear to be offline. Please check your connection.'); } const token = await ensureValidToken(); const url = path.startsWith('http') ? path : `${API_URL}${path}`; let response: Response; try { response = await fetch(url, { ...options, headers: { ...options.headers, Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, }); } catch (err) { if (!navigator.onLine) { throw new Error('You appear to be offline. Please check your connection.'); } throw new Error('Network error. Please try again.'); } if (response.status === 401) { try { const user = await auth.signinSilent(); if (user?.access_token) { return fetch(url, { ...options, headers: { ...options.headers, Authorization: `Bearer ${user.access_token}`, 'Content-Type': 'application/json', }, }); } } catch { auth.signinRedirect(); } throw new Error('Session expired, redirecting to login'); } if (response.status >= 500) { throw new Error('Server error. Please try again later.'); } return response; }, [auth, ensureValidToken] ); return { authFetch, isAuthenticated: auth.isAuthenticated, isLoading: auth.isLoading, user: auth.user, }; };