Files
teamwallet/myteamwallet_frontend_modern/src/app/features/team/notifications/notifications.ts
2026-08-04 20:26:06 +02:00

93 lines
3.2 KiB
TypeScript

import { Component, DestroyRef, OnInit, inject, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router } from '@angular/router';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { NotificationItem } from '../../../models/notification.model';
import { NotificationsApi } from '../../../core/notifications/notifications-api';
import { NotificationsStore } from '../../../core/notifications/notifications-store';
import {
notificationIcon,
notificationLabel,
notificationTarget,
} from '../../../core/notifications/notification-presentation';
const PAGE_SIZE = 20;
@Component({
selector: 'app-notifications',
imports: [MatButtonModule, MatIconModule, MatListModule, MatProgressSpinnerModule],
templateUrl: './notifications.html',
styleUrl: './notifications.scss',
})
export class Notifications implements OnInit {
private readonly route = inject(ActivatedRoute);
private readonly router = inject(Router);
private readonly api = inject(NotificationsApi);
private readonly notificationsStore = inject(NotificationsStore);
private readonly destroyRef = inject(DestroyRef);
protected readonly items = signal<NotificationItem[]>([]);
protected readonly loading = signal(false);
protected readonly hasNextPage = signal(false);
private teamId: number | null = null;
private page = 1;
ngOnInit(): void {
const parentRoute = this.route.parent;
if (!parentRoute) return;
parentRoute.paramMap.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {
const raw = params.get('id');
const id = raw === null ? Number.NaN : Number(raw);
if (Number.isInteger(id) && id > 0 && id !== this.teamId) {
this.teamId = id;
this.page = 1;
this.items.set([]);
this.hasNextPage.set(false);
this.loadPage();
}
});
}
protected notificationLabel(item: NotificationItem): string {
return notificationLabel(item);
}
protected notificationIcon(item: NotificationItem): string {
return notificationIcon(item.event);
}
protected loadMore(): void {
this.page += 1;
this.loadPage();
}
protected onItemClick(item: NotificationItem): void {
if (this.teamId === null) return;
const teamId = this.teamId;
this.notificationsStore.markRead(teamId, item.id);
this.items.update((current) =>
current.map((entry) => (entry.id === item.id ? { ...entry, read: true } : entry)),
);
void this.router.navigate(notificationTarget(item, teamId));
}
private loadPage(): void {
if (this.teamId === null) return;
const teamId = this.teamId;
this.loading.set(true);
this.api.loadNotifications(teamId, { page: this.page, limit: PAGE_SIZE }).subscribe({
next: (result) => {
this.items.update((current) => [...current, ...result.data]);
this.hasNextPage.set(result.hasNextPage);
this.loading.set(false);
},
error: () => this.loading.set(false),
});
}
}