Angular 16 (#2007)

* Removed adv, which isn't needed.

* Updated zone

* Updated to angular 16

* Updated to angular 16 (partially)

* Updated to angular 16

* Package update for Angular 16 (and other dependencies) is complete.

* Replaced all takeUntil(this.onDestroy) with new takeUntilDestroyed()

* Updated all inputs that have ! to be required and deleted all unit tests.

* Corrected how takeUntilDestroyed() is supposed to be implemented.
This commit is contained in:
Joe Milazzo 2023-05-21 12:30:32 -05:00 committed by GitHub
parent 9bc8361381
commit 9c06cccd35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 3964 additions and 20426 deletions

View file

@ -1,20 +1,20 @@
import { Component, OnDestroy } from '@angular/core';
import { FormControl } from '@angular/forms';
import { LegendPosition } from '@swimlane/ngx-charts';
import { Subject, map, takeUntil, Observable } from 'rxjs';
import { DayOfWeek, StatisticsService } from 'src/app/_services/statistics.service';
import { PieDataItem } from '../../_models/pie-data-item';
import { StatCount } from '../../_models/stat-count';
import { DayOfWeekPipe } from '../../_pipes/day-of-week.pipe';
import {ChangeDetectionStrategy, Component, DestroyRef, inject} from '@angular/core';
import {FormControl} from '@angular/forms';
import {LegendPosition} from '@swimlane/ngx-charts';
import {map, Observable} from 'rxjs';
import {DayOfWeek, StatisticsService} from 'src/app/_services/statistics.service';
import {PieDataItem} from '../../_models/pie-data-item';
import {StatCount} from '../../_models/stat-count';
import {DayOfWeekPipe} from '../../_pipes/day-of-week.pipe';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
@Component({
selector: 'app-day-breakdown',
templateUrl: './day-breakdown.component.html',
styleUrls: ['./day-breakdown.component.scss']
styleUrls: ['./day-breakdown.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DayBreakdownComponent implements OnDestroy {
private readonly onDestroy = new Subject<void>();
export class DayBreakdownComponent {
view: [number, number] = [0,0];
gradient: boolean = true;
@ -28,6 +28,7 @@ export class DayBreakdownComponent implements OnDestroy {
formControl: FormControl = new FormControl(true, []);
dayBreakdown$!: Observable<Array<PieDataItem>>;
private readonly destroyRef = inject(DestroyRef);
constructor(private statService: StatisticsService) {
const dayOfWeekPipe = new DayOfWeekPipe();
@ -37,13 +38,8 @@ export class DayBreakdownComponent implements OnDestroy {
return {name: dayOfWeekPipe.transform(d.value), value: d.count};
})
}),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
}

View file

@ -1,27 +1,33 @@
import { ChangeDetectionStrategy, Component, OnDestroy, QueryList, ViewChildren } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
DestroyRef,
inject,
OnDestroy,
QueryList,
ViewChildren
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { LegendPosition } from '@swimlane/ngx-charts';
import { Observable, Subject, BehaviorSubject, combineLatest, map, takeUntil, shareReplay } from 'rxjs';
import { MangaFormatPipe } from 'src/app/pipe/manga-format.pipe';
import { StatisticsService } from 'src/app/_services/statistics.service';
import { SortableHeader, SortEvent, compare } from 'src/app/_single-module/table/_directives/sortable-header.directive';
import { FileExtension, FileExtensionBreakdown } from '../../_models/file-breakdown';
import { PieDataItem } from '../../_models/pie-data-item';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
export interface StackedBarChartDataItem {
name: string,
series: Array<PieDataItem>;
}
const mangaFormatPipe = new MangaFormatPipe();
@Component({
selector: 'app-file-breakdown-stats',
templateUrl: './file-breakdown-stats.component.html',
styleUrls: ['./file-breakdown-stats.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FileBreakdownStatsComponent implements OnDestroy {
export class FileBreakdownStatsComponent {
@ViewChildren(SortableHeader<PieDataItem>) headers!: QueryList<SortableHeader<PieDataItem>>;
@ -29,11 +35,12 @@ export class FileBreakdownStatsComponent implements OnDestroy {
files$!: Observable<Array<FileExtension>>;
vizData$!: Observable<Array<StackedBarChartDataItem>>;
vizData2$!: Observable<Array<PieDataItem>>;
private readonly onDestroy = new Subject<void>();
currentSort = new BehaviorSubject<SortEvent<FileExtension>>({column: 'extension', direction: 'asc'});
currentSort$: Observable<SortEvent<FileExtension>> = this.currentSort.asObservable();
private readonly destroyRef = inject(DestroyRef);
view: [number, number] = [700, 400];
gradient: boolean = true;
showLegend: boolean = true;
@ -48,7 +55,7 @@ export class FileBreakdownStatsComponent implements OnDestroy {
constructor(private statService: StatisticsService) {
this.rawData$ = this.statService.getFileBreakdown().pipe(takeUntil(this.onDestroy), shareReplay());
this.rawData$ = this.statService.getFileBreakdown().pipe(takeUntilDestroyed(this.destroyRef), shareReplay());
this.files$ = combineLatest([this.currentSort$, this.rawData$]).pipe(
map(([sortConfig, data]) => {
@ -61,20 +68,15 @@ export class FileBreakdownStatsComponent implements OnDestroy {
return sortConfig.direction === 'asc' ? res : -res;
}) : fileBreakdown;
}),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
this.vizData2$ = this.files$.pipe(takeUntil(this.onDestroy), map(data => data.map(d => {
this.vizData2$ = this.files$.pipe(takeUntilDestroyed(this.destroyRef), map(data => data.map(d => {
return {name: d.extension || 'Not Categorized', value: d.totalFiles, extra: d.totalSize};
})));
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
onSort(evt: SortEvent<FileExtension>) {
this.currentSort.next(evt);

View file

@ -1,10 +1,20 @@
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
DestroyRef,
inject,
OnDestroy,
OnInit,
QueryList,
ViewChildren
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { LegendPosition } from '@swimlane/ngx-charts';
import { Observable, Subject, BehaviorSubject, combineLatest, map, takeUntil } from 'rxjs';
import { StatisticsService } from 'src/app/_services/statistics.service';
import { compare, SortableHeader, SortEvent } from 'src/app/_single-module/table/_directives/sortable-header.directive';
import { PieDataItem } from '../../_models/pie-data-item';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
@Component({
selector: 'app-manga-format-stats',
@ -12,13 +22,13 @@ import { PieDataItem } from '../../_models/pie-data-item';
styleUrls: ['./manga-format-stats.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MangaFormatStatsComponent implements OnInit, OnDestroy {
export class MangaFormatStatsComponent {
@ViewChildren(SortableHeader<PieDataItem>) headers!: QueryList<SortableHeader<PieDataItem>>;
private readonly destroyRef = inject(DestroyRef);
formats$!: Observable<Array<PieDataItem>>;
private readonly onDestroy = new Subject<void>();
currentSort = new BehaviorSubject<SortEvent<PieDataItem>>({column: 'value', direction: 'asc'});
currentSort$: Observable<SortEvent<PieDataItem>> = this.currentSort.asObservable();
@ -44,20 +54,10 @@ export class MangaFormatStatsComponent implements OnInit, OnDestroy {
return sortConfig.direction === 'asc' ? res : -res;
}) : data;
}),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
}
ngOnInit(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
onSort(evt: SortEvent<PieDataItem>) {
this.currentSort.next(evt);

View file

@ -1,10 +1,19 @@
import { ChangeDetectionStrategy, Component, OnDestroy, QueryList, ViewChildren } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
DestroyRef,
inject,
OnDestroy,
QueryList,
ViewChildren
} from '@angular/core';
import { FormControl } from '@angular/forms';
import { LegendPosition } from '@swimlane/ngx-charts';
import { Observable, Subject, map, takeUntil, combineLatest, BehaviorSubject } from 'rxjs';
import { StatisticsService } from 'src/app/_services/statistics.service';
import { compare, SortableHeader, SortEvent } from 'src/app/_single-module/table/_directives/sortable-header.directive';
import { PieDataItem } from '../../_models/pie-data-item';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
@Component({
selector: 'app-publication-status-stats',
@ -12,13 +21,12 @@ import { PieDataItem } from '../../_models/pie-data-item';
styleUrls: ['./publication-status-stats.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PublicationStatusStatsComponent implements OnDestroy {
export class PublicationStatusStatsComponent {
@ViewChildren(SortableHeader<PieDataItem>) headers!: QueryList<SortableHeader<PieDataItem>>;
publicationStatues$!: Observable<Array<PieDataItem>>;
private readonly onDestroy = new Subject<void>();
currentSort = new BehaviorSubject<SortEvent<PieDataItem>>({column: 'value', direction: 'asc'});
currentSort$: Observable<SortEvent<PieDataItem>> = this.currentSort.asObservable();
@ -32,6 +40,8 @@ export class PublicationStatusStatsComponent implements OnDestroy {
domain: ['#5AA454', '#A10A28', '#C7B42C', '#AAAAAA']
};
private readonly destroyRef = inject(DestroyRef);
formControl: FormControl = new FormControl(true, []);
@ -44,15 +54,10 @@ export class PublicationStatusStatsComponent implements OnDestroy {
return sortConfig.direction === 'asc' ? res : -res;
}) : data;
}),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
onSort(evt: SortEvent<PieDataItem>) {
this.currentSort.next(evt);

View file

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit } from '@angular/core';
import {ChangeDetectionStrategy, Component, DestroyRef, inject, Input, OnDestroy, OnInit} from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { filter, map, Observable, of, shareReplay, Subject, switchMap, takeUntil } from 'rxjs';
import { MangaFormatPipe } from 'src/app/pipe/manga-format.pipe';
@ -7,6 +7,7 @@ import { MemberService } from 'src/app/_services/member.service';
import { StatisticsService } from 'src/app/_services/statistics.service';
import { PieDataItem } from '../../_models/pie-data-item';
import { TimePeriods } from '../top-readers/top-readers.component';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
const options: Intl.DateTimeFormatOptions = { month: "short", day: "numeric" };
const mangaFormatPipe = new MangaFormatPipe();
@ -17,7 +18,7 @@ const mangaFormatPipe = new MangaFormatPipe();
styleUrls: ['./reading-activity.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ReadingActivityComponent implements OnInit, OnDestroy {
export class ReadingActivityComponent implements OnInit {
/**
* Only show for one user
*/
@ -33,10 +34,10 @@ export class ReadingActivityComponent implements OnInit, OnDestroy {
users$: Observable<Member[]> | undefined;
data$: Observable<Array<PieDataItem>>;
timePeriods = TimePeriods;
private readonly onDestroy = new Subject<void>();
private readonly destroyRef = inject(DestroyRef);
constructor(private statService: StatisticsService, private memberService: MemberService) {
this.data$ = this.formGroup.valueChanges.pipe(
this.data$ = this.formGroup.valueChanges.pipe(
switchMap(_ => this.statService.getReadCountByDay(this.formGroup.get('users')!.value, this.formGroup.get('days')!.value)),
map(data => {
const gList = data.reduce((formats, entry) => {
@ -56,26 +57,20 @@ export class ReadingActivityComponent implements OnInit, OnDestroy {
return {name: format, value: 0, series: gList[format].series}
});
}),
takeUntil(this.onDestroy),
takeUntilDestroyed(this.destroyRef),
shareReplay(),
);
this.data$.subscribe();
}
ngOnInit(): void {
this.users$ = (this.isAdmin ? this.memberService.getMembers() : of([])).pipe(filter(_ => this.isAdmin), takeUntil(this.onDestroy), shareReplay());
this.users$ = (this.isAdmin ? this.memberService.getMembers() : of([])).pipe(filter(_ => this.isAdmin), takeUntilDestroyed(this.destroyRef), shareReplay());
this.formGroup.get('users')?.setValue(this.userId, {emitValue: true});
if (!this.isAdmin) {
this.formGroup.get('users')?.disable();
}
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
}

View file

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, HostListener, OnDestroy } from '@angular/core';
import {ChangeDetectionStrategy, Component, DestroyRef, HostListener, inject, OnDestroy} from '@angular/core';
import { Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { BehaviorSubject, map, Observable, shareReplay, Subject, takeUntil } from 'rxjs';
import {BehaviorSubject, map, Observable, ReplaySubject, shareReplay, Subject, takeUntil} from 'rxjs';
import { FilterQueryParam } from 'src/app/shared/_services/filter-utilities.service';
import { Breakpoint, UtilityService } from 'src/app/shared/_services/utility.service';
import { Series } from 'src/app/_models/series';
@ -11,6 +11,7 @@ import { StatisticsService } from 'src/app/_services/statistics.service';
import { PieDataItem } from '../../_models/pie-data-item';
import { ServerStatistics } from '../../_models/server-statistics';
import { GenericListModalComponent } from '../_modals/generic-list-modal/generic-list-modal.component';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
@Component({
selector: 'app-server-stats',
@ -18,7 +19,7 @@ import { GenericListModalComponent } from '../_modals/generic-list-modal/generic
styleUrls: ['./server-stats.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ServerStatsComponent implements OnDestroy {
export class ServerStatsComponent {
releaseYears$!: Observable<Array<PieDataItem>>;
mostActiveUsers$!: Observable<Array<PieDataItem>>;
@ -27,41 +28,42 @@ export class ServerStatsComponent implements OnDestroy {
recentlyRead$!: Observable<Array<PieDataItem>>;
stats$!: Observable<ServerStatistics>;
seriesImage: (data: PieDataItem) => string;
private readonly onDestroy = new Subject<void>();
openSeries = (data: PieDataItem) => {
const series = data.extra as Series;
this.router.navigate(['library', series.libraryId, 'series', series.id]);
}
breakpointSubject = new BehaviorSubject<Breakpoint>(1);
breakpointSubject = new ReplaySubject<Breakpoint>(1);
breakpoint$: Observable<Breakpoint> = this.breakpointSubject.asObservable();
private readonly destroyRef = inject(DestroyRef);
@HostListener('window:resize', ['$event'])
@HostListener('window:orientationchange', ['$event'])
onResize() {
onResize() {
this.breakpointSubject.next(this.utilityService.getActiveBreakpoint());
}
get Breakpoint() { return Breakpoint; }
constructor(private statService: StatisticsService, private router: Router, private imageService: ImageService,
constructor(private statService: StatisticsService, private router: Router, private imageService: ImageService,
private metadataService: MetadataService, private modalService: NgbModal, private utilityService: UtilityService) {
this.seriesImage = (data: PieDataItem) => {
if (data.extra) return this.imageService.getSeriesCoverImage(data.extra.id);
return '';
return '';
}
this.breakpointSubject.next(this.utilityService.getActiveBreakpoint());
this.stats$ = this.statService.getServerStatistics().pipe(takeUntil(this.onDestroy), shareReplay());
this.releaseYears$ = this.statService.getTopYears().pipe(takeUntil(this.onDestroy));
this.stats$ = this.statService.getServerStatistics().pipe(takeUntilDestroyed(this.destroyRef), shareReplay());
this.releaseYears$ = this.statService.getTopYears().pipe(takeUntilDestroyed(this.destroyRef));
this.mostActiveUsers$ = this.stats$.pipe(
map(d => d.mostActiveUsers),
map(userCounts => userCounts.map(count => {
return {name: count.value.username, value: count.count};
})),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
this.mostActiveLibrary$ = this.stats$.pipe(
@ -69,7 +71,7 @@ export class ServerStatsComponent implements OnDestroy {
map(counts => counts.map(count => {
return {name: count.value.name, value: count.count};
})),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
this.mostActiveSeries$ = this.stats$.pipe(
@ -77,7 +79,7 @@ export class ServerStatsComponent implements OnDestroy {
map(counts => counts.map(count => {
return {name: count.value.name, value: count.count, extra: count.value};
})),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
this.recentlyRead$ = this.stats$.pipe(
@ -85,15 +87,10 @@ export class ServerStatsComponent implements OnDestroy {
map(counts => counts.map(count => {
return {name: count.name, value: -1, extra: count};
})),
takeUntil(this.onDestroy)
takeUntilDestroyed(this.destroyRef)
);
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
openGenreList() {
this.metadataService.getAllGenres().subscribe(genres => {
const ref = this.modalService.open(GenericListModalComponent, { scrollable: true });
@ -130,6 +127,6 @@ export class ServerStatsComponent implements OnDestroy {
});
}
}

View file

@ -23,7 +23,7 @@ export class StatListComponent {
* Optional data to put in tooltip
*/
@Input() description: string = '';
@Input() data$!: Observable<PieDataItem[]>;
@Input({required: true}) data$!: Observable<PieDataItem[]>;
@Input() image: ((data: PieDataItem) => string) | undefined = undefined;
/**
* Optional callback handler when an item is clicked
@ -31,7 +31,7 @@ export class StatListComponent {
@Input() handleClick: ((data: PieDataItem) => void) | undefined = undefined;
doClick(item: PieDataItem) {
if (!this.handleClick) return;
if (!this.handleClick) return;
this.handleClick(item);
}

View file

@ -1,8 +1,17 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
inject,
OnDestroy,
OnInit
} from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { Observable, Subject, takeUntil, switchMap, shareReplay } from 'rxjs';
import { StatisticsService } from 'src/app/_services/statistics.service';
import { TopUserRead } from '../../_models/top-reads';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
export const TimePeriods: Array<{title: string, value: number}> = [{title: 'This Week', value: new Date().getDay() || 1}, {title: 'Last 7 Days', value: 7}, {title: 'Last 30 Days', value: 30}, {title: 'Last 90 Days', value: 90}, {title: 'Last Year', value: 365}, {title: 'All Time', value: 0}];
@ -12,22 +21,22 @@ export const TimePeriods: Array<{title: string, value: number}> = [{title: 'This
styleUrls: ['./top-readers.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TopReadersComponent implements OnInit, OnDestroy {
export class TopReadersComponent implements OnInit {
formGroup: FormGroup;
timePeriods = TimePeriods;
users$: Observable<TopUserRead[]>;
private readonly onDestroy = new Subject<void>();
constructor(private statsService: StatisticsService, private readonly cdRef: ChangeDetectorRef) {
private readonly destroyRef = inject(DestroyRef);
constructor(private statsService: StatisticsService, private readonly cdRef: ChangeDetectorRef) {
this.formGroup = new FormGroup({
'days': new FormControl(this.timePeriods[0].value, []),
});
this.users$ = this.formGroup.valueChanges.pipe(
switchMap(_ => this.statsService.getTopUsers(this.formGroup.get('days')?.value as number)),
takeUntil(this.onDestroy),
takeUntilDestroyed(this.destroyRef),
shareReplay(),
);
}
@ -38,9 +47,4 @@ export class TopReadersComponent implements OnInit, OnDestroy {
this.formGroup.get('days')?.setValue(this.timePeriods[0].value, {emitEvent: true});
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
}

View file

@ -14,6 +14,6 @@
</div>
<div class="row g-0 pt-4 pb-2 " style="height: 242px">
<app-stat-list [data$]="precentageRead$" label="% Read" title="Library Read Progress"></app-stat-list>
<app-stat-list [data$]="percentageRead$" label="% Read" title="Library Read Progress"></app-stat-list>
</div>
</div>
</div>

View file

@ -1,4 +1,12 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
inject,
OnDestroy,
OnInit
} from '@angular/core';
import { map, Observable, shareReplay, Subject, takeUntil } from 'rxjs';
import { FilterUtilitiesService } from 'src/app/shared/_services/filter-utilities.service';
import { UserReadStatistics } from 'src/app/statistics/_models/user-read-statistics';
@ -9,6 +17,7 @@ import { AccountService } from 'src/app/_services/account.service';
import { PieDataItem } from '../../_models/pie-data-item';
import { LibraryService } from 'src/app/_services/library.service';
import { PercentPipe } from '@angular/common';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
@Component({
selector: 'app-user-stats',
@ -16,20 +25,19 @@ import { PercentPipe } from '@angular/common';
styleUrls: ['./user-stats.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UserStatsComponent implements OnInit, OnDestroy {
export class UserStatsComponent implements OnInit {
userId: number | undefined = undefined;
userStats$!: Observable<UserReadStatistics>;
readSeries$!: Observable<ReadHistoryEvent[]>;
isAdmin$: Observable<boolean>;
precentageRead$!: Observable<PieDataItem[]>;
percentageRead$!: Observable<PieDataItem[]>;
private readonly destroyRef = inject(DestroyRef);
private readonly onDestroy = new Subject<void>();
constructor(private readonly cdRef: ChangeDetectorRef, private statService: StatisticsService,
constructor(private readonly cdRef: ChangeDetectorRef, private statService: StatisticsService,
private filterService: FilterUtilitiesService, private accountService: AccountService, private memberService: MemberService,
private libraryService: LibraryService) {
this.isAdmin$ = this.accountService.currentUser$.pipe(takeUntil(this.onDestroy), map(u => {
private libraryService: LibraryService) {
this.isAdmin$ = this.accountService.currentUser$.pipe(takeUntilDestroyed(this.destroyRef), map(u => {
if (!u) return false;
return this.accountService.hasAdminRole(u);
}));
@ -42,26 +50,20 @@ export class UserStatsComponent implements OnInit, OnDestroy {
this.memberService.getMember().subscribe(me => {
this.userId = me.id;
this.cdRef.markForCheck();
this.userStats$ = this.statService.getUserStatistics(this.userId).pipe(takeUntil(this.onDestroy), shareReplay());
this.userStats$ = this.statService.getUserStatistics(this.userId).pipe(takeUntilDestroyed(this.destroyRef), shareReplay());
this.readSeries$ = this.statService.getReadingHistory(this.userId).pipe(
takeUntil(this.onDestroy),
takeUntilDestroyed(this.destroyRef),
);
const pipe = new PercentPipe('en-US');
this.libraryService.getLibraryNames().subscribe(names => {
this.precentageRead$ = this.userStats$.pipe(takeUntil(this.onDestroy), map(d => d.percentReadPerLibrary.map(l => {
this.percentageRead$ = this.userStats$.pipe(takeUntilDestroyed(this.destroyRef), map(d => d.percentReadPerLibrary.map(l => {
return {name: names[l.count], value: parseFloat((pipe.transform(l.value, '1.1-1') || '0').replace('%', ''))};
}).sort((a: PieDataItem, b: PieDataItem) => b.value - a.value)));
})
});
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
});
}
}