init commit

This commit is contained in:
David Melendez
2026-01-14 22:32:13 +01:00
parent 29b2e1438c
commit 00cb087b68
84 changed files with 29665 additions and 1 deletions

View File

@@ -0,0 +1,282 @@
/**
* Professional Navigation Service
* Enterprise-grade navigation handling with error management and user feedback
*
* @author David Valera Melendez <david@valera-melendez.de>
* @created 2025-08-08
* @location Made in Germany 🇩🇪
*/
import { Injectable } from '@angular/core';
import { Router, NavigationEnd, NavigationError, NavigationCancel } from '@angular/router';
import { Location } from '@angular/common';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Observable, BehaviorSubject } from 'rxjs';
import { filter } from 'rxjs/operators';
export interface NavigationState {
isNavigating: boolean;
currentUrl: string;
previousUrl: string | null;
error: string | null;
}
@Injectable({
providedIn: 'root'
})
export class NavigationService {
private navigationStateSubject = new BehaviorSubject<NavigationState>({
isNavigating: false,
currentUrl: '/',
previousUrl: null,
error: null
});
public readonly navigationState$: Observable<NavigationState> = this.navigationStateSubject.asObservable();
constructor(
private router: Router,
private location: Location,
private snackBar: MatSnackBar
) {
this.initializeNavigationTracking();
}
/**
* Initialize navigation event tracking
*/
private initializeNavigationTracking(): void {
// Track navigation start
this.router.events.subscribe(event => {
if (event.constructor.name === 'NavigationStart') {
this.updateNavigationState({
...this.navigationStateSubject.value,
isNavigating: true,
error: null
});
}
});
// Track successful navigation
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.updateNavigationState({
previousUrl: this.navigationStateSubject.value.currentUrl,
currentUrl: event.url,
isNavigating: false,
error: null
});
}
});
// Track navigation errors
this.router.events.subscribe(event => {
if (event instanceof NavigationError) {
console.error('Navigation error:', event.error);
this.updateNavigationState({
...this.navigationStateSubject.value,
isNavigating: false,
error: event.error?.message || 'Navigation failed'
});
this.showErrorMessage('Navigation failed. Please try again.');
}
});
// Track navigation cancellations
this.router.events.subscribe(event => {
if (event instanceof NavigationCancel) {
console.warn('Navigation cancelled:', event.reason);
this.updateNavigationState({
...this.navigationStateSubject.value,
isNavigating: false,
error: null
});
}
});
}
/**
* Update navigation state
*/
private updateNavigationState(state: NavigationState): void {
this.navigationStateSubject.next(state);
}
/**
* Navigate to a route with comprehensive error handling
*/
async navigateToRoute(route: string | string[], options?: {
replaceUrl?: boolean;
queryParams?: any;
fragment?: string;
state?: any;
skipLocationChange?: boolean;
preserveFragment?: boolean;
preserveQueryParams?: boolean;
}): Promise<boolean> {
try {
const navigationResult = await this.router.navigate(
Array.isArray(route) ? route : [route],
{
replaceUrl: options?.replaceUrl || false,
queryParams: options?.queryParams,
fragment: options?.fragment,
state: options?.state,
skipLocationChange: options?.skipLocationChange || false,
preserveFragment: options?.preserveFragment || false,
queryParamsHandling: options?.preserveQueryParams ? 'merge' : undefined
}
);
if (!navigationResult) {
console.error('Navigation failed for route:', route);
this.showErrorMessage('Unable to navigate to the requested page.');
return false;
}
return true;
} catch (error) {
console.error('Navigation exception:', error);
this.showErrorMessage('An unexpected error occurred during navigation.');
return false;
}
}
/**
* Navigate to login page with return URL
*/
async navigateToLogin(returnUrl?: string): Promise<boolean> {
const queryParams = returnUrl ? { returnUrl } : undefined;
return await this.navigateToRoute('/auth/login', { queryParams });
}
/**
* Navigate to dashboard
*/
async navigateToDashboard(): Promise<boolean> {
return await this.navigateToRoute('/dashboard');
}
/**
* Navigate to resume builder
*/
async navigateToBuilder(): Promise<boolean> {
return await this.navigateToRoute('/builder');
}
/**
* Navigate to user profile
*/
async navigateToProfile(): Promise<boolean> {
return await this.navigateToRoute('/profile');
}
/**
* Navigate to settings
*/
async navigateToSettings(): Promise<boolean> {
return await this.navigateToRoute('/settings');
}
/**
* Navigate to home page
*/
async navigateToHome(): Promise<boolean> {
return await this.navigateToRoute('/home', { replaceUrl: true });
}
/**
* Navigate back to previous page
*/
navigateBack(): void {
const previousUrl = this.navigationStateSubject.value.previousUrl;
if (previousUrl && previousUrl !== this.navigationStateSubject.value.currentUrl) {
this.location.back();
} else {
this.navigateToHome();
}
}
/**
* Navigate forward in browser history
*/
navigateForward(): void {
this.location.forward();
}
/**
* Get current URL
*/
getCurrentUrl(): string {
return this.router.url;
}
/**
* Check if currently on a specific route
*/
isCurrentRoute(route: string): boolean {
return this.router.url === route || this.router.url.startsWith(route + '/');
}
/**
* Check if route is public (doesn't require authentication)
*/
isPublicRoute(url?: string): boolean {
const currentUrl = url || this.router.url;
const publicRoutes = ['/home', '/login', '/register', '/forgot-password', '/auth', '/404', '/403', '/500'];
return publicRoutes.some(route => currentUrl.startsWith(route)) || currentUrl === '/';
}
/**
* Force reload current page
*/
reloadCurrentPage(): void {
const currentUrl = this.router.url;
this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => {
this.router.navigate([currentUrl]);
});
}
/**
* Open external URL in new tab
*/
openExternalUrl(url: string): void {
window.open(url, '_blank', 'noopener,noreferrer');
}
/**
* Show success message to user
*/
private showSuccessMessage(message: string): void {
this.snackBar.open(message, 'Close', {
duration: 4000,
panelClass: ['success-snackbar'],
horizontalPosition: 'end',
verticalPosition: 'top'
});
}
/**
* Show error message to user
*/
private showErrorMessage(message: string): void {
this.snackBar.open(message, 'Close', {
duration: 6000,
panelClass: ['error-snackbar'],
horizontalPosition: 'end',
verticalPosition: 'top'
});
}
/**
* Show info message to user
*/
private showInfoMessage(message: string): void {
this.snackBar.open(message, 'Close', {
duration: 3000,
panelClass: ['info-snackbar'],
horizontalPosition: 'end',
verticalPosition: 'top'
});
}
}