93 lines
3.2 KiB
TypeScript
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),
|
|
});
|
|
}
|
|
}
|