import { type FC } from 'react' import '@/assets/fonts/irancell/style.css' import 'swiper/swiper-bundle.css'; import 'react-loading-skeleton/dist/skeleton.css' import { BrowserRouter } from 'react-router-dom' import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query' import MainRouter from './router/MainRouter' import ToastContainer from './components/Toast' import { getRefreshToken, setRefreshToken, setToken } from './config/func'; import AuthRouter from './router/AuthRouter'; import CompleteProfileRouter from './router/CompleteProfileRouter'; import type { IApiErrorRepsonse } from './shared/types/Types'; import { Paths } from './config/Paths'; import { useSessionAuth } from './config/sessionAuth'; import { appNavigate, AppNavigation } from './config/navigation'; import { refreshToken } from './pages/auth/service/AuthService'; import { useGetMe } from './pages/user/hooks/useUserData'; import { needsProfileCompletion } from './pages/user/utils/profileUtils'; import MoonLoader from 'react-spinners/MoonLoader'; declare global { interface Window { isRefreshingToken?: boolean; isRefreshTokenExpired?: boolean; } } const queryClient = new QueryClient({ queryCache: new QueryCache({ onError: async (error: IApiErrorRepsonse) => { if (error?.response?.status === 401) { // اگر refresh token منقضی شده باشد، دیگر تلاش نکن if (window.isRefreshTokenExpired) { return; } // بررسی کن که آیا خطا از refresh endpoint است const isRefreshEndpoint = error?.config?.url?.includes('/public/auth/refresh'); // اگر خطا از refresh endpoint است، refresh token منقضی شده if (isRefreshEndpoint) { window.isRefreshTokenExpired = true; useSessionAuth.getState().clearSession(); queryClient.clear(); appNavigate(Paths.auth.login, { replace: true }); return; } try { // Use a flag to track if refresh is in progress if (window.isRefreshingToken) { // Wait for the refresh to complete await new Promise(resolve => { const checkComplete = setInterval(() => { if (!window.isRefreshingToken) { clearInterval(checkComplete); resolve(true); } }, 100); }); return; } // Set the flag to indicate refresh is in progress window.isRefreshingToken = true; try { const refreshTokenValue = await getRefreshToken(); if (!refreshTokenValue) { window.isRefreshTokenExpired = true; useSessionAuth.getState().clearSession(); queryClient.clear(); appNavigate(Paths.auth.login, { replace: true }); return; } const { data } = await refreshToken({ refreshToken: refreshTokenValue || '' }); if (data?.accessToken?.token) { // Save the new token await setToken(data?.accessToken?.token); // If refresh token also returned, update it if (data.refreshToken?.token) { await setRefreshToken(data.refreshToken?.token); } // Reset expired flag if refresh was successful window.isRefreshTokenExpired = false; // Retry the failed request queryClient.invalidateQueries(); return; } else { throw new Error('Invalid token response'); } } finally { window.isRefreshingToken = false; } } catch (refreshError: unknown) { console.error('Token refresh failed:', refreshError); // بررسی کن که آیا خطا از refresh endpoint است const errorWithConfig = refreshError as IApiErrorRepsonse; const isRefreshError = errorWithConfig?.config?.url?.includes('/admin/auth/refresh'); // اگر refresh token خودش 401 خورده، آن را منقضی شده علامت بزن if (isRefreshError || errorWithConfig?.response?.statusCode === 401) { window.isRefreshTokenExpired = true; } useSessionAuth.getState().clearSession(); queryClient.clear(); appNavigate(Paths.auth.login, { replace: true }); } } } }), defaultOptions: { queries: { refetchOnWindowFocus: false, retry: false // staleTime: 86400000 // 1 day in milliseconds } } }); const AppRoutes: FC = () => { const isLoggedIn = useSessionAuth((state) => state.isAuthenticated) const { data: user, isLoading } = useGetMe({ enabled: isLoggedIn }) const profileIncomplete = isLoggedIn && needsProfileCompletion(user) if (isLoggedIn && isLoading) { return (