npm run serve:ssr funktioniert und Hamburger Menu bug fix

This commit is contained in:
2026-01-06 22:36:14 +01:00
parent 43027a54f7
commit 4f8fd77f7d
21 changed files with 371 additions and 111 deletions

View File

@@ -1,6 +1,7 @@
// auth.service.ts
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { HttpClient, HttpBackend, HttpHeaders, HttpParams } from '@angular/common/http';
import { Injectable, inject, PLATFORM_ID } from '@angular/core';
import { FirebaseApp } from '@angular/fire/app';
import { GoogleAuthProvider, UserCredential, createUserWithEmailAndPassword, getAuth, signInWithCustomToken, signInWithEmailAndPassword, signInWithPopup } from 'firebase/auth';
import { BehaviorSubject, Observable, catchError, firstValueFrom, map, of, shareReplay, take, tap } from 'rxjs';
@@ -14,8 +15,10 @@ export type UserRole = 'admin' | 'pro' | 'guest';
})
export class AuthService {
private app = inject(FirebaseApp);
private auth = getAuth(this.app);
private http = inject(HttpClient);
private platformId = inject(PLATFORM_ID);
private isBrowser = isPlatformBrowser(this.platformId);
private auth = this.isBrowser ? getAuth(this.app) : null;
private http = new HttpClient(inject(HttpBackend));
private mailService = inject(MailService);
// Add a BehaviorSubject to track the current user role
private userRoleSubject = new BehaviorSubject<UserRole | null>(null);
@@ -31,6 +34,26 @@ export class AuthService {
this.loadRoleFromToken();
}
// Helper methods for localStorage access (only in browser)
private setLocalStorageItem(key: string, value: string): void {
if (this.isBrowser) {
localStorage.setItem(key, value);
}
}
private getLocalStorageItem(key: string): string | null {
if (this.isBrowser) {
return localStorage.getItem(key);
}
return null;
}
private removeLocalStorageItem(key: string): void {
if (this.isBrowser) {
localStorage.removeItem(key);
}
}
private loadRoleFromToken(): void {
this.getToken().then(token => {
if (token) {
@@ -54,18 +77,24 @@ export class AuthService {
}
// Registrierung mit Email und Passwort
async registerWithEmail(email: string, password: string): Promise<UserCredential> {
if (!this.isBrowser || !this.auth) {
throw new Error('Auth is only available in browser context');
}
// Bestimmen der aktuellen Umgebung/Domain für die Verifizierungs-URL
let verificationUrl = '';
let verificationUrl = 'https://www.bizmatch.net/email-authorized';
// Prüfen der aktuellen Umgebung basierend auf dem Host
const currentHost = window.location.hostname;
// Prüfen der aktuellen Umgebung basierend auf dem Host (nur im Browser)
if (this.isBrowser) {
const currentHost = window.location.hostname;
if (currentHost.includes('localhost')) {
verificationUrl = 'http://localhost:4200/email-authorized';
} else if (currentHost.includes('dev.bizmatch.net')) {
verificationUrl = 'https://dev.bizmatch.net/email-authorized';
} else {
verificationUrl = 'https://www.bizmatch.net/email-authorized';
if (currentHost.includes('localhost')) {
verificationUrl = 'http://localhost:4200/email-authorized';
} else if (currentHost.includes('dev.bizmatch.net')) {
verificationUrl = 'https://dev.bizmatch.net/email-authorized';
} else {
verificationUrl = 'https://www.bizmatch.net/email-authorized';
}
}
// ActionCode-Einstellungen mit der dynamischen URL
@@ -93,10 +122,10 @@ export class AuthService {
}
// const token = await userCredential.user.getIdToken();
// localStorage.setItem('authToken', token);
// localStorage.setItem('refreshToken', userCredential.user.refreshToken);
// this.setLocalStorageItem('authToken', token);
// this.setLocalStorageItem('refreshToken', userCredential.user.refreshToken);
// if (userCredential.user.photoURL) {
// localStorage.setItem('photoURL', userCredential.user.photoURL);
// this.setLocalStorageItem('photoURL', userCredential.user.photoURL);
// }
return userCredential;
@@ -104,13 +133,16 @@ export class AuthService {
// Login mit Email und Passwort
loginWithEmail(email: string, password: string): Promise<UserCredential> {
if (!this.isBrowser || !this.auth) {
throw new Error('Auth is only available in browser context');
}
return signInWithEmailAndPassword(this.auth, email, password).then(async userCredential => {
if (userCredential.user) {
const token = await userCredential.user.getIdToken();
localStorage.setItem('authToken', token);
localStorage.setItem('refreshToken', userCredential.user.refreshToken);
this.setLocalStorageItem('authToken', token);
this.setLocalStorageItem('refreshToken', userCredential.user.refreshToken);
if (userCredential.user.photoURL) {
localStorage.setItem('photoURL', userCredential.user.photoURL);
this.setLocalStorageItem('photoURL', userCredential.user.photoURL);
}
this.loadRoleFromToken();
}
@@ -120,14 +152,17 @@ export class AuthService {
// Login mit Google
loginWithGoogle(): Promise<UserCredential> {
if (!this.isBrowser || !this.auth) {
throw new Error('Auth is only available in browser context');
}
const provider = new GoogleAuthProvider();
return signInWithPopup(this.auth, provider).then(async userCredential => {
if (userCredential.user) {
const token = await userCredential.user.getIdToken();
localStorage.setItem('authToken', token);
localStorage.setItem('refreshToken', userCredential.user.refreshToken);
this.setLocalStorageItem('authToken', token);
this.setLocalStorageItem('refreshToken', userCredential.user.refreshToken);
if (userCredential.user.photoURL) {
localStorage.setItem('photoURL', userCredential.user.photoURL);
this.setLocalStorageItem('photoURL', userCredential.user.photoURL);
}
this.loadRoleFromToken();
}
@@ -137,12 +172,15 @@ export class AuthService {
// Logout: Token, RefreshToken und photoURL entfernen
logout(): Promise<void> {
localStorage.removeItem('authToken');
localStorage.removeItem('refreshToken');
localStorage.removeItem('photoURL');
this.removeLocalStorageItem('authToken');
this.removeLocalStorageItem('refreshToken');
this.removeLocalStorageItem('photoURL');
this.clearRoleCache();
this.userRoleSubject.next(null);
return this.auth.signOut();
if (this.auth) {
return this.auth.signOut();
}
return Promise.resolve();
}
isAdmin(): Observable<boolean> {
return this.getUserRole().pipe(
@@ -202,10 +240,10 @@ export class AuthService {
// Force refresh the token to get updated custom claims
async refreshUserClaims(): Promise<void> {
this.clearRoleCache();
if (this.auth.currentUser) {
if (this.auth && this.auth.currentUser) {
await this.auth.currentUser.getIdToken(true);
const token = await this.auth.currentUser.getIdToken();
localStorage.setItem('authToken', token);
this.setLocalStorageItem('authToken', token);
this.loadRoleFromToken();
}
}
@@ -234,7 +272,12 @@ export class AuthService {
}
// Versucht, mit dem RefreshToken einen neuen Access Token zu erhalten
async refreshToken(): Promise<string | null> {
const storedRefreshToken = localStorage.getItem('refreshToken');
const storedRefreshToken = this.getLocalStorageItem('refreshToken');
// SSR protection: refreshToken should only run in browser
if (!this.isBrowser) {
return null;
}
if (!storedRefreshToken) {
return null;
}
@@ -250,8 +293,8 @@ export class AuthService {
// response enthält z.B. id_token, refresh_token, expires_in etc.
const newToken = response.id_token;
const newRefreshToken = response.refresh_token;
localStorage.setItem('authToken', newToken);
localStorage.setItem('refreshToken', newRefreshToken);
this.setLocalStorageItem('authToken', newToken);
this.setLocalStorageItem('refreshToken', newRefreshToken);
return newToken;
} catch (error) {
console.error('Error refreshing token:', error);
@@ -266,7 +309,12 @@ export class AuthService {
* Ist auch das nicht möglich, wird null zurückgegeben.
*/
async getToken(): Promise<string | null> {
const token = localStorage.getItem('authToken');
const token = this.getLocalStorageItem('authToken');
// SSR protection: return null on server
if (!this.isBrowser) {
return null;
}
if (token && !this.isEMailVerified(token)) {
return null;
} else if (token && this.isTokenValid(token) && this.isEMailVerified(token)) {
@@ -278,6 +326,9 @@ export class AuthService {
// Add this new method to sign in with a custom token
async signInWithCustomToken(token: string): Promise<void> {
if (!this.isBrowser || !this.auth) {
throw new Error('Auth is only available in browser context');
}
try {
// Sign in to Firebase with the custom token
const userCredential = await signInWithCustomToken(this.auth, token);
@@ -285,11 +336,11 @@ export class AuthService {
// Store the authentication token
if (userCredential.user) {
const idToken = await userCredential.user.getIdToken();
localStorage.setItem('authToken', idToken);
localStorage.setItem('refreshToken', userCredential.user.refreshToken);
this.setLocalStorageItem('authToken', idToken);
this.setLocalStorageItem('refreshToken', userCredential.user.refreshToken);
if (userCredential.user.photoURL) {
localStorage.setItem('photoURL', userCredential.user.photoURL);
this.setLocalStorageItem('photoURL', userCredential.user.photoURL);
}
// Load user role from the token