red-ui/apps/red-ui/src/app/components/notifications/notifications.component.ts

80 lines
3.2 KiB
TypeScript

import { Component } from '@angular/core';
import { DatePipe } from '@shared/pipes/date.pipe';
import { NotificationsService } from '@services/notifications.service';
import { Notification } from '@red/domain';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { isToday, shareLast, trackByFactory } from '@iqser/common-ui';
import dayjs, { Dayjs } from 'dayjs';
import { TranslateService } from '@ngx-translate/core';
interface NotificationsGroup {
date: string;
notifications: Notification[];
}
export function isOlderThan(date: string | Date | Dayjs, years: number) {
return dayjs(date).year() <= dayjs(Date.now()).subtract(years, 'year').year();
}
function chronologically(first: string, second: string) {
return dayjs(first).isAfter(second) ? -1 : 1;
}
@Component({
selector: 'redaction-notifications',
templateUrl: './notifications.component.html',
styleUrls: ['./notifications.component.scss'],
})
export class NotificationsComponent {
readonly hasUnreadNotifications$: Observable<boolean>;
readonly groupedNotifications$: Observable<NotificationsGroup[]>;
readonly trackBy = trackByFactory();
constructor(
private readonly _notificationsService: NotificationsService,
private readonly _datePipe: DatePipe,
private readonly _translateService: TranslateService,
) {
this.groupedNotifications$ = this._notificationsService.all$.pipe(map(notifications => this.#groupNotifications(notifications)));
this.hasUnreadNotifications$ = this.#hasUnreadNotifications$;
}
get #hasUnreadNotifications$(): Observable<boolean> {
return this._notificationsService.all$.pipe(
map(notifications => notifications.filter(n => !n.readDate).length > 0),
distinctUntilChanged(),
shareLast(),
);
}
async markRead(notifications: Notification[] = this._notificationsService.all, isRead = true): Promise<void> {
if (!notifications.find(notification => !!notification.readDate !== isRead)) {
// If no notification changes status after the request, abort
return;
}
const notificationsIds = notifications.map(n => n.id);
await this._notificationsService.toggleNotificationRead(notificationsIds, isRead);
}
#groupNotifications(notifications: Notification[]): NotificationsGroup[] {
const todayTranslation = this._translateService.instant('today');
const groupedMap = notifications.groupBy(n => {
if (isOlderThan(n.creationDate, 2)) {
return dayjs(n.creationDate).year().toString();
} else if (isOlderThan(n.creationDate, 1)) {
return dayjs(n.creationDate).format('YYYY-MM');
}
return n.creationDate.split('T')[0];
});
const sortedGroups = [...groupedMap.entries()].sort(([aDate], [bDate]) => chronologically(aDate, bDate));
return sortedGroups.map(([date, _notifications]) => ({
date: isToday(date) ? todayTranslation : this._datePipe.transform(date, 'sophisticatedDate'),
notifications: [..._notifications].sort((a, b) => chronologically(a.creationDate, b.creationDate)),
}));
}
}