mirror of
https://github.com/a-mayb3/KanbanCloneAngular.git
synced 2026-03-21 09:55:37 +01:00
Adapted some config for the api
This commit is contained in:
parent
773fa7ad6d
commit
d1e016b7df
9 changed files with 74 additions and 54 deletions
|
|
@ -1,7 +1,11 @@
|
|||
import { ApplicationConfig, provideBrowserGlobalErrorListeners, APP_INITIALIZER } from '@angular/core';
|
||||
import {
|
||||
ApplicationConfig,
|
||||
provideBrowserGlobalErrorListeners,
|
||||
APP_INITIALIZER,
|
||||
} from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { catchError, of } from 'rxjs';
|
||||
import { catchError, of, throwError } from 'rxjs';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import { httpInterceptor } from './interceptors/http.interceptor';
|
||||
|
|
@ -11,28 +15,30 @@ import { AuthService } from './services/auth.service';
|
|||
* Initialize auth state on app startup by checking for existing session
|
||||
*/
|
||||
function initializeAuth(authService: AuthService) {
|
||||
return () => authService.checkSession().pipe(
|
||||
catchError((error) => {
|
||||
// Session check failed - user is not logged in or session expired
|
||||
console.log('No active session or session expired');
|
||||
authService.clearAuthState();
|
||||
return of(null);
|
||||
})
|
||||
);
|
||||
return () =>
|
||||
authService.checkSession().pipe(
|
||||
catchError((error) => {
|
||||
console.error('Session check failed:', error);
|
||||
if (error?.status === 401 || error?.status === 422) {
|
||||
authService.clearAuthState();
|
||||
return of(null);
|
||||
}
|
||||
authService.clearAuthState();
|
||||
return throwError(() => error);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
provideRouter(routes),
|
||||
provideHttpClient(
|
||||
withInterceptors([httpInterceptor])
|
||||
),
|
||||
provideHttpClient(withInterceptors([httpInterceptor])),
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: initializeAuth,
|
||||
deps: [AuthService],
|
||||
multi: true
|
||||
}
|
||||
]
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
<app-navbar />
|
||||
<main class="main"></main>
|
||||
|
||||
|
||||
<main class="main">
|
||||
<router-outlet />
|
||||
</main>
|
||||
<app-footer />
|
||||
|
||||
<router-outlet />
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,28 @@ import { LoginComponent } from './pages/login/login.component';
|
|||
|
||||
export const routes: Routes = [
|
||||
// Public routes
|
||||
{
|
||||
path: 'login',
|
||||
component: LoginComponent
|
||||
{
|
||||
path: 'login',
|
||||
component: LoginComponent
|
||||
},
|
||||
|
||||
// Protected routes - require authentication
|
||||
{
|
||||
path: '',
|
||||
{
|
||||
path: '',
|
||||
canActivate: [authGuard],
|
||||
loadComponent: () => import('./pages/home/home.component').then(m => m.HomeComponent)
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./pages/home/home.component').then(m => m.HomeComponent)
|
||||
},
|
||||
{
|
||||
path: 'projects/new',
|
||||
loadComponent: () => import('./pages/project-create/project-create.component').then(m => m.ProjectCreateComponent)
|
||||
},
|
||||
{
|
||||
path: 'projects/:id',
|
||||
loadComponent: () => import('./pages/project-details/project-details.component').then(m => m.ProjectDetailsComponent)
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import { Component, signal, inject } from '@angular/core';
|
|||
import { RouterOutlet } from '@angular/router';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Navbar } from './navbar/navbar';
|
||||
import { NavbarComponent } from './components/navbar/navbar.component';
|
||||
import { FooterComponent } from './components/footer/footer.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet, CommonModule, Navbar],
|
||||
imports: [RouterOutlet, CommonModule, NavbarComponent, FooterComponent],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.css'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,33 +15,24 @@ export const httpInterceptor: HttpInterceptorFn = (req, next) => {
|
|||
// Clone the request to add withCredentials flag
|
||||
// This ensures cookies are sent with every request
|
||||
const reqWithCredentials = req.clone({
|
||||
withCredentials: true
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
// Pass the cloned request to the next handler
|
||||
return next(reqWithCredentials).pipe(
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
// Handle different HTTP error codes
|
||||
if (error.status === 401) {
|
||||
// Unauthorized - redirect to login (but not for session check endpoint)
|
||||
// Skip redirect for /me endpoint to avoid issues during app initialization
|
||||
if (!req.url.endsWith('/me')) {
|
||||
console.error('Unauthorized access - redirecting to login');
|
||||
if (router.url !== '/login') {
|
||||
router.navigate(['/login']);
|
||||
}
|
||||
} else if (error.status === 403) {
|
||||
// Forbidden
|
||||
console.error('Access forbidden:', error.message);
|
||||
} else if (error.status === 0) {
|
||||
// Network error
|
||||
console.error('Network error - check if the server is running');
|
||||
} else {
|
||||
// Other errors
|
||||
console.error(`HTTP Error ${error.status}:`, error.message);
|
||||
}
|
||||
|
||||
// Re-throw the error so components can handle it if needed
|
||||
return throwError(() => error);
|
||||
})
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export interface ProjectFull {
|
|||
|
||||
export interface CreateProjectRequest {
|
||||
name: string;
|
||||
description?: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface UpdateProjectRequest {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
name="description"
|
||||
[(ngModel)]="description"
|
||||
rows="4"
|
||||
placeholder="Optional description"
|
||||
placeholder="Enter a project description"
|
||||
required
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { CreateProjectRequest, Project } from '../../models/projects.models';
|
|||
standalone: true,
|
||||
imports: [CommonModule, FormsModule],
|
||||
templateUrl: './project-create.component.html',
|
||||
styleUrl: './project-create.component.css'
|
||||
styleUrl: './project-create.component.css',
|
||||
})
|
||||
export class ProjectCreateComponent {
|
||||
private apiService = inject(ApiService);
|
||||
|
|
@ -27,9 +27,14 @@ export class ProjectCreateComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.description.trim()) {
|
||||
this.errorMessage.set('Project description is required.');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload: CreateProjectRequest = {
|
||||
name: this.name.trim(),
|
||||
description: this.description.trim() || undefined
|
||||
description: this.description.trim(),
|
||||
};
|
||||
|
||||
this.isSaving.set(true);
|
||||
|
|
@ -39,7 +44,7 @@ export class ProjectCreateComponent {
|
|||
next: (project) => {
|
||||
this.isSaving.set(false);
|
||||
if (project?.id != null) {
|
||||
this.router.navigate(['/projects', project.id]);
|
||||
this.router.navigate(['/projects/', project.id]);
|
||||
} else {
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
|
@ -47,9 +52,9 @@ export class ProjectCreateComponent {
|
|||
error: (error) => {
|
||||
this.isSaving.set(false);
|
||||
this.errorMessage.set(
|
||||
error?.error?.message || 'Failed to create project. Please try again.'
|
||||
error?.error?.message || 'Failed to create project. Please try again.',
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable, inject, signal, computed } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
import { Observable, tap, catchError, throwError } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
import { LoginRequest, LoginResponse, User, AuthState } from '../models/auth.models';
|
||||
import { environment } from '../config/environment';
|
||||
|
|
@ -36,11 +36,11 @@ export class AuthService {
|
|||
credentials
|
||||
).pipe(
|
||||
tap(response => {
|
||||
if (response.success && response.user) {
|
||||
// Update auth state
|
||||
if (response.success || response.user) {
|
||||
// Update auth state even if the backend only sets a cookie
|
||||
this.authState.set({
|
||||
isAuthenticated: true,
|
||||
user: response.user
|
||||
user: response.user ?? null
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
@ -52,7 +52,7 @@ export class AuthService {
|
|||
* Clears the session cookie on the backend
|
||||
*/
|
||||
logout(): Observable<any> {
|
||||
return this.http.post(`${environment.apiBaseUrl}/me/logout`, {}).pipe(
|
||||
return this.http.get(`${environment.apiBaseUrl}/me/logout`).pipe(
|
||||
tap(() => {
|
||||
// Clear auth state
|
||||
this.authState.set({
|
||||
|
|
@ -61,6 +61,11 @@ export class AuthService {
|
|||
});
|
||||
// Redirect to login
|
||||
this.router.navigate(['/login']);
|
||||
}),
|
||||
catchError((error) => {
|
||||
// Even if logout fails on backend, clear local state
|
||||
this.clearAuthState();
|
||||
return throwError(() => error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
@ -88,5 +93,6 @@ export class AuthService {
|
|||
isAuthenticated: false,
|
||||
user: null
|
||||
});
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue