fix(frontend): replace alert() with ToastService, remove console.*, fix UI bugs

- Replace alert() with ToastService in admin-user-approval and admin-energy-community
- Remove all console.error/console.warn statements from components and guards
- Fix admin-energy-community modal title (now shows 'Bearbeiten' in edit mode)
- Fix admin-user-approval table header ('Zählpunkt' -> 'Status')
- Remove broken header nav links (#so-gehts, #faq) that pointed to non-existent sections
This commit is contained in:
Bernhard Müller 2026-07-22 09:25:50 +02:00
parent fea8332976
commit a90b7ecc7e
8 changed files with 20 additions and 26 deletions

View File

@ -10,6 +10,5 @@ export const authGuard: CanActivateFn = () => {
return true; return true;
} }
console.warn('Zugriff verweigert: Login erforderlich.');
return router.createUrlTree(['/login']); return router.createUrlTree(['/login']);
}; };

View File

@ -12,7 +12,6 @@ export function roleGuard(allowedRoles: string[]): CanActivateFn {
return true; return true;
} }
console.warn(`Zugriff verweigert: benötigt eine der Rollen [${allowedRoles.join(', ')}].`);
return router.createUrlTree(['/dashboard']); return router.createUrlTree(['/dashboard']);
}; };
} }

View File

@ -16,8 +16,6 @@
<div class="hidden md:flex absolute left-1/2 transform -translate-x-1/2"> <div class="hidden md:flex absolute left-1/2 transform -translate-x-1/2">
<nav class="flex gap-6"> <nav class="flex gap-6">
<a href="#vorteile" class="text-slate-600 hover:text-slate-900 font-medium">Vorteile</a> <a href="#vorteile" class="text-slate-600 hover:text-slate-900 font-medium">Vorteile</a>
<a href="#so-gehts" class="text-slate-600 hover:text-slate-900 font-medium">So funktioniert's</a>
<a href="#faq" class="text-slate-600 hover:text-slate-900 font-medium">FAQ</a>
</nav> </nav>
</div> </div>

View File

@ -64,7 +64,7 @@
<div class="bg-white rounded-2xl shadow-xl w-full max-w-lg overflow-hidden flex flex-col max-h-[90vh]"> <div class="bg-white rounded-2xl shadow-xl w-full max-w-lg overflow-hidden flex flex-col max-h-[90vh]">
<div class="px-6 py-4 border-b border-slate-200 flex justify-between items-center bg-slate-50 shrink-0"> <div class="px-6 py-4 border-b border-slate-200 flex justify-between items-center bg-slate-50 shrink-0">
<h3 class="text-lg font-bold text-slate-800">Neue Energiegemeinschaft anlegen</h3> <h3 class="text-lg font-bold text-slate-800">{{ isEditMode ? 'Energiegemeinschaft bearbeiten' : 'Neue Energiegemeinschaft anlegen' }}</h3>
<button (click)="closeModal()" class="text-slate-400 hover:text-slate-600 transition-colors"> <button (click)="closeModal()" class="text-slate-400 hover:text-slate-600 transition-colors">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />

View File

@ -2,6 +2,7 @@ import {Component, inject, OnInit} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {FormBuilder, ReactiveFormsModule, Validators} from '@angular/forms'; import {FormBuilder, ReactiveFormsModule, Validators} from '@angular/forms';
import {EnergyCommunityAdminControllerService, EnergyCommunityDto} from '../../api'; import {EnergyCommunityAdminControllerService, EnergyCommunityDto} from '../../api';
import {ToastService} from '../../services/toast';
@Component({ @Component({
selector: 'app-admin-energy-community', selector: 'app-admin-energy-community',
@ -12,6 +13,7 @@ import {EnergyCommunityAdminControllerService, EnergyCommunityDto} from '../../a
export class AdminEnergyCommunity implements OnInit { export class AdminEnergyCommunity implements OnInit {
private ecService = inject(EnergyCommunityAdminControllerService); private ecService = inject(EnergyCommunityAdminControllerService);
private fb = inject(FormBuilder); private fb = inject(FormBuilder);
private toastService = inject(ToastService);
communities: EnergyCommunityDto[] = []; communities: EnergyCommunityDto[] = [];
@ -38,8 +40,7 @@ export class AdminEnergyCommunity implements OnInit {
this.communities = data; this.communities = data;
}, },
error: (err) => { error: (err) => {
console.error('Fehler beim Laden der Energiegemeinschaften', err); this.toastService.error(err.error?.message || 'Fehler beim Laden der Energiegemeinschaften.');
// Hier würde später ein globaler Error-Toast getriggert werden
} }
}); });
} }
@ -80,7 +81,9 @@ export class AdminEnergyCommunity implements OnInit {
if (index !== -1) this.communities[index] = updatedEc; if (index !== -1) this.communities[index] = updatedEc;
this.closeModal(); this.closeModal();
}, },
error: (err) => console.error('Fehler beim Updaten', err) error: (err) => {
this.toastService.error(err.error?.message || 'Fehler beim Aktualisieren der Energiegemeinschaft.');
}
}); });
} else { } else {
this.ecService.createEnergyCommunity(formData as any).subscribe({ this.ecService.createEnergyCommunity(formData as any).subscribe({
@ -88,7 +91,9 @@ export class AdminEnergyCommunity implements OnInit {
this.communities.push(newCommunity); this.communities.push(newCommunity);
this.closeModal(); this.closeModal();
}, },
error: (err) => console.error('Fehler beim Erstellen', err) error: (err) => {
this.toastService.error(err.error?.message || 'Fehler beim Erstellen der Energiegemeinschaft.');
}
}); });
} }
} else { } else {
@ -109,9 +114,7 @@ export class AdminEnergyCommunity implements OnInit {
this.communities = this.communities.filter(c => c.id !== id); this.communities = this.communities.filter(c => c.id !== id);
}, },
error: (err) => { error: (err) => {
console.error('Löschen fehlgeschlagen', err); this.toastService.error(err.error?.message || 'Die Energiegemeinschaft konnte nicht gelöscht werden.');
const errorMsg = err.error?.message || 'Die Energiegemeinschaft konnte nicht gelöscht werden.';
alert(errorMsg);
} }
}); });
} }

View File

@ -29,7 +29,7 @@
<thead> <thead>
<tr class="bg-gray-50 border-b border-gray-200"> <tr class="bg-gray-50 border-b border-gray-200">
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">Benutzer</th> <th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">Benutzer</th>
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">Zählpunkt</th> <th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">Status</th>
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">Status</th> <th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider">Status</th>
<th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider text-right">Aktionen</th> <th class="p-4 text-sm font-semibold text-gray-700 uppercase tracking-wider text-right">Aktionen</th>
</tr> </tr>

View File

@ -1,6 +1,7 @@
import {Component, DestroyRef, inject, OnInit, signal} from '@angular/core'; import {Component, DestroyRef, inject, OnInit, signal} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {AdminIAMService, UserProfileResponse} from '../../api'; import {AdminIAMService, UserProfileResponse} from '../../api';
import {ToastService} from '../../services/toast';
@Component({ @Component({
selector: 'app-admin-user-approval', selector: 'app-admin-user-approval',
@ -16,7 +17,8 @@ export class AdminUserApprovalComponent implements OnInit {
public readonly errorMessage = signal<string>(''); public readonly errorMessage = signal<string>('');
private readonly adminService = inject(AdminIAMService); private readonly adminService = inject(AdminIAMService);
private readonly destroyRef = inject(DestroyRef); // Für sauberes Ressourcen-Management private readonly destroyRef = inject(DestroyRef);
private readonly toastService = inject(ToastService);
public ngOnInit(): void { public ngOnInit(): void {
this.loadPendingUsers(); this.loadPendingUsers();
@ -33,8 +35,7 @@ export class AdminUserApprovalComponent implements OnInit {
this.pendingUsers.set(users); this.pendingUsers.set(users);
this.isLoading.set(false); this.isLoading.set(false);
}, },
error: (error) => { error: () => {
console.error('Failed to load pending users:', error);
this.errorMessage.set('Fehler beim Laden der Daten aus dem EDA-Netz-Check.'); this.errorMessage.set('Fehler beim Laden der Daten aus dem EDA-Netz-Check.');
this.isLoading.set(false); this.isLoading.set(false);
} }
@ -51,18 +52,14 @@ export class AdminUserApprovalComponent implements OnInit {
next: () => { next: () => {
this.pendingUsers.update(users => users.filter(user => user.id !== userId)); this.pendingUsers.update(users => users.filter(user => user.id !== userId));
}, },
error: (error) => { error: () => {
console.error(`Failed to approve user with ID ${userId}:`, error);
this.errorMessage.set('Der User konnte nicht freigegeben werden.'); this.errorMessage.set('Der User konnte nicht freigegeben werden.');
} }
}); });
} }
public rejectUser(user: UserProfileResponse): void { public rejectUser(user: UserProfileResponse): void {
if (!user.id) { if (!user.id) return;
console.error('Fehler: UserProfileResponse hat keine ID.');
return;
}
if (confirm(`Möchtest du die Registrierung von ${user.firstName} ${user.lastName} wirklich ablehnen?`)) { if (confirm(`Möchtest du die Registrierung von ${user.firstName} ${user.lastName} wirklich ablehnen?`)) {
this.adminService.rejectUser(user.id).subscribe({ this.adminService.rejectUser(user.id).subscribe({
@ -70,8 +67,7 @@ export class AdminUserApprovalComponent implements OnInit {
this.pendingUsers.update(users => users.filter(u => u.id !== user.id)); this.pendingUsers.update(users => users.filter(u => u.id !== user.id));
}, },
error: (err) => { error: (err) => {
console.error('Fehler beim Ablehnen des Users', err); this.toastService.error(err.error?.message || 'Der User konnte nicht abgelehnt werden.');
alert(err.error?.message || 'Der User konnte nicht abgelehnt werden.');
} }
}); });
} }

View File

@ -80,8 +80,7 @@ export class Register {
next: () => { next: () => {
this.registeredSuccessfully = true; this.registeredSuccessfully = true;
}, },
error: (err) => { error: () => {
console.error('Fehler bei der Registrierung', err);
} }
}); });
} }