|
|
@@ -26,6 +26,77 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
|
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
|
const [authStep, setAuthStep] = useState<string>("Initializing");
|
|
|
const navigate = useNavigate();
|
|
|
+
|
|
|
+ // Monitor session expiration periodically
|
|
|
+ useEffect(() => {
|
|
|
+ let sessionCheckInterval: NodeJS.Timeout;
|
|
|
+
|
|
|
+ const checkSessionValidity = async () => {
|
|
|
+ // Only check if user is authenticated
|
|
|
+ if (!isAuthenticated) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const session_data = localStorage.getItem("session_data");
|
|
|
+
|
|
|
+ if (!session_data) {
|
|
|
+ // Session data missing, force logout
|
|
|
+ handleSessionExpired();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const readable_session_data = JSON.parse(session_data);
|
|
|
+
|
|
|
+ if (!readable_session_data.success || !readable_session_data.session?.access_token) {
|
|
|
+ handleSessionExpired();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate token with backend
|
|
|
+ const check_auth_response = await fetch(`${API_URL}/auth/check`, {
|
|
|
+ method: "GET",
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ "Authorization": `Bearer ${readable_session_data.session.access_token}`,
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const check_auth_response_json = await check_auth_response.json();
|
|
|
+
|
|
|
+ if (!check_auth_response_json.success) {
|
|
|
+ // Session expired or invalid
|
|
|
+ handleSessionExpired();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Session validation failed:", error);
|
|
|
+ // Network error or server error - don't logout immediately
|
|
|
+ // Let the user continue and handle on next navigation attempt
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSessionExpired = () => {
|
|
|
+ // Clear all authentication data
|
|
|
+ localStorage.removeItem("session_data");
|
|
|
+ localStorage.setItem('IsAuthenticated', 'false');
|
|
|
+ setIsAuthenticated(false);
|
|
|
+ setAuthStep("Session expired");
|
|
|
+
|
|
|
+ // Refresh the page to reset app state and redirect to landing
|
|
|
+ window.location.href = '/';
|
|
|
+ };
|
|
|
+
|
|
|
+ // Start periodic session check (every 5 minutes)
|
|
|
+ if (isAuthenticated) {
|
|
|
+ sessionCheckInterval = setInterval(checkSessionValidity, 5 * 60 * 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ if (sessionCheckInterval) {
|
|
|
+ clearInterval(sessionCheckInterval);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }, [isAuthenticated]);
|
|
|
|
|
|
const check_auth = async(target_path: string) => {
|
|
|
setLoading(true);
|
|
|
@@ -55,23 +126,27 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
|
|
|
navigate(target_path);
|
|
|
}
|
|
|
} else {
|
|
|
+ // Session expired - clear state and redirect to landing page with full refresh
|
|
|
setAuthStep("Session expired");
|
|
|
- setIsAuthenticated(false);
|
|
|
+ localStorage.removeItem("session_data");
|
|
|
localStorage.setItem('IsAuthenticated', 'false');
|
|
|
- navigate("/login");
|
|
|
+ setIsAuthenticated(false);
|
|
|
+ window.location.href = '/';
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("Auth check failed:", error);
|
|
|
setAuthStep("Connection failed");
|
|
|
- setIsAuthenticated(false);
|
|
|
+ localStorage.removeItem("session_data");
|
|
|
localStorage.setItem('IsAuthenticated', 'false');
|
|
|
- navigate("/login");
|
|
|
+ setIsAuthenticated(false);
|
|
|
+ window.location.href = '/';
|
|
|
}
|
|
|
} else {
|
|
|
setAuthStep("Invalid session");
|
|
|
- setIsAuthenticated(false);
|
|
|
+ localStorage.removeItem("session_data");
|
|
|
localStorage.setItem('IsAuthenticated', 'false');
|
|
|
- navigate("/login");
|
|
|
+ setIsAuthenticated(false);
|
|
|
+ window.location.href = '/';
|
|
|
}
|
|
|
} else {
|
|
|
setAuthStep("No session found");
|