import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, Observable, of, throwError } from 'rxjs'; import { tap, catchError } from 'rxjs/operators'; import { Router } from '@angular/router'; @Injectable({ providedIn: 'root' }) export class AuthService { private apiUrl = location.hostname.endsWith('hf.space') ? 'https://pykara-py-learn-backend.hf.space' : 'http://localhost:5000'; // Your Flask API base URL private loggedInSubject = new BehaviorSubject(false); // Shared state public isLoggedIn$ = this.loggedInSubject.asObservable(); private refreshIntervalId: any; constructor(private http: HttpClient, private router: Router) { } // ✅ Called to check current status isLoggedIn(): boolean { return this.loggedInSubject.value; } // ✅ Set login status manually setLoggedIn(status: boolean): void { this.loggedInSubject.next(status); } // ✅ Login Method login(username: string, password: string): Observable { return this.http.post(`${this.apiUrl}/login`, { username, password }, { withCredentials: true }); } startAutoRefresh(): void { if (this.refreshIntervalId) return; this.refreshIntervalId = setInterval(() => { this.refreshAccessToken(); }, 12 * 60 * 1000); } clearAutoRefresh(): void { clearInterval(this.refreshIntervalId); this.refreshIntervalId = null; } refreshAccessToken(): void { this.http.post(`${this.apiUrl}/refresh`, {}, { withCredentials: true }).subscribe( (response: any) => { console.log("✅ Access token refreshed:", response.access_token); //alert("🔄 Access token has been refreshed!"); }, (error) => { console.error("❌ Refresh failed:", error); if ( error.status === 401 && error.error && (error.error.message === 'Refresh token has expired' || error.error.message === 'Invalid refresh token') ) { //alert("⚠️ Your session has expired. Please log in again."); // Clear cookies manually (if needed) this.clearTokens(); // Redirect to login this.router.navigate(['/auth']); } } ); } logout(): Observable { console.log("🔧 Sending logout request with credentials"); return this.http.post(`${this.apiUrl}/logout`, {}, { withCredentials: true }).pipe( tap(response => { console.log('🔙 Response from backend:', response); this.clearTokens(); this.clearAutoRefresh(); // ✅ Stop auto-refresh this.setLoggedIn(false); // ✅ Reflect logout in UI }), catchError(error => { console.error('❌ Error from backend:', error); // Still ensure local state reflects logout this.clearTokens(); this.clearAutoRefresh(); this.setLoggedIn(false); return throwError(() => error); }) ); } clearTokens(): void { document.cookie = 'access_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; document.cookie = 'refresh_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; this.clearAutoRefresh(); // ✅ } //// ✅ Check if user is logged in (check for presence of cookies) //isLoggedIn(): boolean { // // Check cookies directly (this will happen automatically when the browser sends cookies) // // Check if the cookies are present (you can do it manually using a service or via backend) // return document.cookie.includes('access_token'); //} // ✅ Get access token (using cookies) getAccessToken(): string | null { const cookies = document.cookie.split('; '); for (let cookie of cookies) { if (cookie.startsWith('access_token=')) { return cookie.split('=')[1]; } } return null; } // ✅ Save tokens (Not necessary, as tokens are managed via cookies) saveTokens(accessToken: string, refreshToken: string): void { // No need for this if you're using cookies, but if you want to persist in localStorage, use: localStorage.setItem('access_token', accessToken); localStorage.setItem('refresh_token', refreshToken); } //checkSession(): Observable { // return this.http.get(`${this.apiUrl}/check-auth`, { withCredentials: true }).pipe( // tap((res: any) => { // console.log('✅ Session valid:', res); // this.setLoggedIn(true); // }), // catchError((err) => { // console.warn('❌ Session check failed:', err); // this.setLoggedIn(false); // return [false]; // Return false on error // }) // ); //} checkSession(): Observable { return this.http.get(`${this.apiUrl}/check-auth`, { withCredentials: true }).pipe( tap((res: any) => { console.log('✅ Session valid:', res); this.setLoggedIn(true); this.startAutoRefresh(); return true; // ✅ Important! }), catchError((err) => { if (err.status === 401) { // Access token may be expired. Try refresh console.warn('🔄 Access token expired. Trying to refresh...'); return this.http.post(`${this.apiUrl}/refresh`, {}, { withCredentials: true }).pipe( tap((refreshRes: any) => { console.log("✅ Token refreshed during checkSession."); //alert("✅ Token refreshed during checkSession."); this.setLoggedIn(true); this.startAutoRefresh(); }), catchError((refreshErr) => { console.error("❌ Refresh token failed during checkSession.", refreshErr); this.setLoggedIn(false); return of(false); }) ); } else { console.error("❌ Unknown error during checkSession", err); this.setLoggedIn(false); return of(false); } }) ); } }