Version Update Modal Rework + A few bugfixes (#3664)
This commit is contained in:
parent
9fb3bdd548
commit
43d0d1277f
65 changed files with 1963 additions and 805 deletions
|
|
@ -53,8 +53,8 @@ export class ServerService {
|
|||
return this.http.get<UpdateVersionEvent | null>(this.baseUrl + 'server/check-update');
|
||||
}
|
||||
|
||||
checkHowOutOfDate() {
|
||||
return this.http.get<string>(this.baseUrl + 'server/check-out-of-date', TextResonse)
|
||||
checkHowOutOfDate(stableOnly: boolean = true) {
|
||||
return this.http.get<string>(this.baseUrl + `server/check-out-of-date?stableOnly=${stableOnly}`, TextResonse)
|
||||
.pipe(map(r => parseInt(r, 10)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {inject, Injectable, OnDestroy} from '@angular/core';
|
|||
import {interval, Subscription, switchMap} from 'rxjs';
|
||||
import {ServerService} from "./server.service";
|
||||
import {AccountService} from "./account.service";
|
||||
import {filter, tap} from "rxjs/operators";
|
||||
import {filter, take} from "rxjs/operators";
|
||||
import {NgbModal} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {NewUpdateModalComponent} from "../announcements/_components/new-update-modal/new-update-modal.component";
|
||||
import {OutOfDateModalComponent} from "../announcements/_components/out-of-date-modal/out-of-date-modal.component";
|
||||
|
|
@ -16,82 +16,191 @@ export class VersionService implements OnDestroy{
|
|||
private readonly accountService = inject(AccountService);
|
||||
private readonly modalService = inject(NgbModal);
|
||||
|
||||
public static readonly versionKey = 'kavita--version';
|
||||
private readonly checkInterval = 600000; // 10 minutes (600000)
|
||||
private periodicCheckSubscription?: Subscription;
|
||||
public static readonly SERVER_VERSION_KEY = 'kavita--version';
|
||||
public static readonly CLIENT_REFRESH_KEY = 'kavita--client-refresh-last-shown';
|
||||
public static readonly NEW_UPDATE_KEY = 'kavita--new-update-last-shown';
|
||||
public static readonly OUT_OF_BAND_KEY = 'kavita--out-of-band-last-shown';
|
||||
|
||||
// Notification intervals
|
||||
private readonly CLIENT_REFRESH_INTERVAL = 0; // Show immediately (once)
|
||||
private readonly NEW_UPDATE_INTERVAL = 7 * 24 * 60 * 60 * 1000; // 1 week in milliseconds
|
||||
private readonly OUT_OF_BAND_INTERVAL = 30 * 24 * 60 * 60 * 1000; // 1 month in milliseconds
|
||||
|
||||
// Check intervals
|
||||
private readonly VERSION_CHECK_INTERVAL = 30 * 60 * 1000; // 30 minutes
|
||||
private readonly OUT_OF_DATE_CHECK_INTERVAL = this.VERSION_CHECK_INTERVAL; // 2 * 60 * 60 * 1000; // 2 hours
|
||||
|
||||
private readonly OUT_Of_BAND_AMOUNT = 2; // How many releases before we show "You're X releases out of date"
|
||||
|
||||
|
||||
private versionCheckSubscription?: Subscription;
|
||||
private outOfDateCheckSubscription?: Subscription;
|
||||
private modalOpen = false;
|
||||
|
||||
constructor() {
|
||||
this.startPeriodicUpdateCheck();
|
||||
this.startVersionCheck();
|
||||
this.startOutOfDateCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.periodicCheckSubscription?.unsubscribe();
|
||||
this.versionCheckSubscription?.unsubscribe();
|
||||
this.outOfDateCheckSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
private startOutOfDateCheck() {
|
||||
// Every hour, have the UI check for an update. People seriously stay out of date
|
||||
this.outOfDateCheckSubscription = interval(2* 60 * 60 * 1000) // 2 hours in milliseconds
|
||||
/**
|
||||
* Periodic check for server version to detect client refreshes and new updates
|
||||
*/
|
||||
private startVersionCheck(): void {
|
||||
console.log('Starting version checker');
|
||||
this.versionCheckSubscription = interval(this.VERSION_CHECK_INTERVAL)
|
||||
.pipe(
|
||||
switchMap(() => this.accountService.currentUser$),
|
||||
filter(u => u !== undefined && this.accountService.hasAdminRole(u)),
|
||||
switchMap(_ => this.serverService.checkHowOutOfDate()),
|
||||
filter(versionOutOfDate => {
|
||||
return !isNaN(versionOutOfDate) && versionOutOfDate > 2;
|
||||
}),
|
||||
tap(versionOutOfDate => {
|
||||
if (!this.modalService.hasOpenModals()) {
|
||||
const ref = this.modalService.open(OutOfDateModalComponent, {size: 'xl', fullscreen: 'md'});
|
||||
ref.componentInstance.versionsOutOfDate = versionOutOfDate;
|
||||
}
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private startPeriodicUpdateCheck(): void {
|
||||
console.log('Starting periodic version update checker');
|
||||
this.periodicCheckSubscription = interval(this.checkInterval)
|
||||
.pipe(
|
||||
switchMap(_ => this.accountService.currentUser$),
|
||||
filter(user => user !== undefined && !this.modalOpen),
|
||||
filter(user => !!user && !this.modalOpen),
|
||||
switchMap(user => this.serverService.getVersion(user!.apiKey)),
|
||||
filter(update => !!update),
|
||||
).subscribe(version => this.handleVersionUpdate(version));
|
||||
}
|
||||
|
||||
private handleVersionUpdate(version: string) {
|
||||
/**
|
||||
* Checks if the server is out of date compared to the latest release
|
||||
*/
|
||||
private startOutOfDateCheck() {
|
||||
console.log('Starting out-of-date checker');
|
||||
this.outOfDateCheckSubscription = interval(this.OUT_OF_DATE_CHECK_INTERVAL)
|
||||
.pipe(
|
||||
switchMap(() => this.accountService.currentUser$),
|
||||
filter(u => u !== undefined && this.accountService.hasAdminRole(u) && !this.modalOpen),
|
||||
switchMap(_ => this.serverService.checkHowOutOfDate(true)),
|
||||
filter(versionsOutOfDate => !isNaN(versionsOutOfDate) && versionsOutOfDate > this.OUT_Of_BAND_AMOUNT),
|
||||
)
|
||||
.subscribe(versionsOutOfDate => this.handleOutOfDateNotification(versionsOutOfDate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the version check response to determine if client refresh or new update notification is needed
|
||||
*/
|
||||
private handleVersionUpdate(serverVersion: string) {
|
||||
if (this.modalOpen) return;
|
||||
|
||||
// Pause periodic checks while the modal is open
|
||||
this.periodicCheckSubscription?.unsubscribe();
|
||||
const cachedVersion = localStorage.getItem(VersionService.SERVER_VERSION_KEY);
|
||||
console.log('Server version:', serverVersion, 'Cached version:', cachedVersion);
|
||||
|
||||
const cachedVersion = localStorage.getItem(VersionService.versionKey);
|
||||
console.log('Kavita version: ', version, ' Running version: ', cachedVersion);
|
||||
|
||||
const hasChanged = cachedVersion == null || cachedVersion != version;
|
||||
if (hasChanged) {
|
||||
this.modalOpen = true;
|
||||
|
||||
this.serverService.getChangelog(1).subscribe(changelog => {
|
||||
const ref = this.modalService.open(NewUpdateModalComponent, {size: 'lg', keyboard: false});
|
||||
ref.componentInstance.version = version;
|
||||
ref.componentInstance.update = changelog[0];
|
||||
|
||||
ref.closed.subscribe(_ => this.onModalClosed());
|
||||
ref.dismissed.subscribe(_ => this.onModalClosed());
|
||||
|
||||
});
|
||||
const isNewServerVersion = cachedVersion !== null && cachedVersion !== serverVersion;
|
||||
|
||||
// Case 1: Client Refresh needed (server has updated since last client load)
|
||||
if (isNewServerVersion) {
|
||||
this.showClientRefreshNotification(serverVersion);
|
||||
}
|
||||
// Case 2: Check for new updates (for server admin)
|
||||
else {
|
||||
this.checkForNewUpdates();
|
||||
}
|
||||
|
||||
localStorage.setItem(VersionService.versionKey, version);
|
||||
// Always update the cached version
|
||||
localStorage.setItem(VersionService.SERVER_VERSION_KEY, serverVersion);
|
||||
}
|
||||
|
||||
private onModalClosed() {
|
||||
/**
|
||||
* Shows a notification that client refresh is needed due to server update
|
||||
*/
|
||||
private showClientRefreshNotification(newVersion: string): void {
|
||||
this.pauseChecks();
|
||||
|
||||
// Client refresh notifications should always show (once)
|
||||
this.modalOpen = true;
|
||||
|
||||
this.serverService.getChangelog(1).subscribe(changelog => {
|
||||
const ref = this.modalService.open(NewUpdateModalComponent, {
|
||||
size: 'lg',
|
||||
keyboard: false,
|
||||
backdrop: 'static' // Prevent closing by clicking outside
|
||||
});
|
||||
|
||||
ref.componentInstance.version = newVersion;
|
||||
ref.componentInstance.update = changelog[0];
|
||||
ref.componentInstance.requiresRefresh = true;
|
||||
|
||||
// Update the last shown timestamp
|
||||
localStorage.setItem(VersionService.CLIENT_REFRESH_KEY, Date.now().toString());
|
||||
|
||||
ref.closed.subscribe(_ => this.onModalClosed());
|
||||
ref.dismissed.subscribe(_ => this.onModalClosed());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for new server updates and shows notification if appropriate
|
||||
*/
|
||||
private checkForNewUpdates(): void {
|
||||
this.accountService.currentUser$
|
||||
.pipe(
|
||||
take(1),
|
||||
filter(user => user !== undefined && this.accountService.hasAdminRole(user)),
|
||||
switchMap(_ => this.serverService.checkHowOutOfDate()),
|
||||
filter(versionsOutOfDate => !isNaN(versionsOutOfDate) && versionsOutOfDate > 0 && versionsOutOfDate <= this.OUT_Of_BAND_AMOUNT)
|
||||
)
|
||||
.subscribe(versionsOutOfDate => {
|
||||
const lastShown = Number(localStorage.getItem(VersionService.NEW_UPDATE_KEY) || '0');
|
||||
const currentTime = Date.now();
|
||||
|
||||
// Show notification if it hasn't been shown in the last week
|
||||
if (currentTime - lastShown >= this.NEW_UPDATE_INTERVAL) {
|
||||
this.pauseChecks();
|
||||
this.modalOpen = true;
|
||||
|
||||
this.serverService.getChangelog(1).subscribe(changelog => {
|
||||
const ref = this.modalService.open(NewUpdateModalComponent, { size: 'lg' });
|
||||
ref.componentInstance.versionsOutOfDate = versionsOutOfDate;
|
||||
ref.componentInstance.update = changelog[0];
|
||||
ref.componentInstance.requiresRefresh = false;
|
||||
|
||||
// Update the last shown timestamp
|
||||
localStorage.setItem(VersionService.NEW_UPDATE_KEY, currentTime.toString());
|
||||
|
||||
ref.closed.subscribe(_ => this.onModalClosed());
|
||||
ref.dismissed.subscribe(_ => this.onModalClosed());
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the notification for servers that are significantly out of date
|
||||
*/
|
||||
private handleOutOfDateNotification(versionsOutOfDate: number): void {
|
||||
const lastShown = Number(localStorage.getItem(VersionService.OUT_OF_BAND_KEY) || '0');
|
||||
const currentTime = Date.now();
|
||||
|
||||
// Show notification if it hasn't been shown in the last month
|
||||
if (currentTime - lastShown >= this.OUT_OF_BAND_INTERVAL) {
|
||||
this.pauseChecks();
|
||||
this.modalOpen = true;
|
||||
|
||||
const ref = this.modalService.open(OutOfDateModalComponent, { size: 'xl', fullscreen: 'md' });
|
||||
ref.componentInstance.versionsOutOfDate = versionsOutOfDate;
|
||||
|
||||
// Update the last shown timestamp
|
||||
localStorage.setItem(VersionService.OUT_OF_BAND_KEY, currentTime.toString());
|
||||
|
||||
ref.closed.subscribe(_ => this.onModalClosed());
|
||||
ref.dismissed.subscribe(_ => this.onModalClosed());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses all version checks while modals are open
|
||||
*/
|
||||
private pauseChecks(): void {
|
||||
this.versionCheckSubscription?.unsubscribe();
|
||||
this.outOfDateCheckSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes all checks when modals are closed
|
||||
*/
|
||||
private onModalClosed(): void {
|
||||
this.modalOpen = false;
|
||||
this.startPeriodicUpdateCheck();
|
||||
this.startVersionCheck();
|
||||
this.startOutOfDateCheck();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export interface RelatedSeriesPair {
|
|||
styleUrl: './related-tab.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class RelatedTabComponent implements OnInit {
|
||||
export class RelatedTabComponent {
|
||||
|
||||
protected readonly imageService = inject(ImageService);
|
||||
protected readonly router = inject(Router);
|
||||
|
|
@ -40,10 +40,6 @@ export class RelatedTabComponent implements OnInit {
|
|||
@Input() bookmarks: Array<PageBookmark> = [];
|
||||
@Input() libraryId!: number;
|
||||
|
||||
ngOnInit() {
|
||||
console.log('bookmarks: ', this.bookmarks);
|
||||
}
|
||||
|
||||
openReadingList(readingList: ReadingList) {
|
||||
this.router.navigate(['lists', readingList.id]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,7 +224,6 @@ export class LicenseComponent implements OnInit {
|
|||
|
||||
toggleViewMode() {
|
||||
this.isViewMode = !this.isViewMode;
|
||||
console.log('edit mode: ', !this.isViewMode)
|
||||
this.cdRef.markForCheck();
|
||||
this.resetForm();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export class ManageLogsComponent implements OnInit, OnDestroy {
|
|||
// unsubscribe from signalr connection
|
||||
if (this.hubConnection) {
|
||||
this.hubConnection.stop().catch(err => console.error(err));
|
||||
console.log('Stoping log connection');
|
||||
console.log('Stopping log connection');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {shareReplay} from 'rxjs/operators';
|
|||
import {debounceTime, defer, distinctUntilChanged, filter, forkJoin, Observable, of, switchMap, tap} from 'rxjs';
|
||||
import {ServerService} from 'src/app/_services/server.service';
|
||||
import {Job} from 'src/app/_models/job/job';
|
||||
import {UpdateNotificationModalComponent} from 'src/app/shared/update-notification/update-notification-modal.component';
|
||||
import {UpdateNotificationModalComponent} from 'src/app/announcements/_components/update-notification/update-notification-modal.component';
|
||||
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {DownloadService} from 'src/app/shared/_services/download.service';
|
||||
import {DefaultValuePipe} from '../../_pipes/default-value.pipe';
|
||||
|
|
@ -134,6 +134,7 @@ export class ManageTasksSettingsComponent implements OnInit {
|
|||
}
|
||||
},
|
||||
];
|
||||
|
||||
customOption = 'custom';
|
||||
|
||||
|
||||
|
|
@ -305,7 +306,6 @@ export class ManageTasksSettingsComponent implements OnInit {
|
|||
modelSettings.taskCleanup = this.settingsForm.get('taskCleanupCustom')?.value;
|
||||
}
|
||||
|
||||
console.log('modelSettings: ', modelSettings);
|
||||
return modelSettings;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ export class AllSeriesComponent implements OnInit {
|
|||
private readonly cdRef: ChangeDetectorRef) {
|
||||
|
||||
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
||||
console.log('url: ', this.route.snapshot);
|
||||
|
||||
this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => {
|
||||
this.filter = filter;
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import {SafeHtmlPipe} from "../../../_pipes/safe-html.pipe";
|
|||
import {VersionService} from "../../../_services/version.service";
|
||||
import {ChangelogUpdateItemComponent} from "../changelog-update-item/changelog-update-item.component";
|
||||
|
||||
/**
|
||||
* This modal is used when an update occurred and the UI needs to be refreshed to get the latest JS libraries
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-new-update-modal',
|
||||
standalone: true,
|
||||
imports: [
|
||||
TranslocoDirective,
|
||||
UpdateSectionComponent,
|
||||
SafeHtmlPipe,
|
||||
ChangelogUpdateItemComponent
|
||||
],
|
||||
templateUrl: './new-update-modal.component.html',
|
||||
|
|
@ -41,8 +42,6 @@ export class NewUpdateModalComponent {
|
|||
|
||||
private applyUpdate(version: string): void {
|
||||
this.bustLocaleCache();
|
||||
console.log('Setting version key: ', version);
|
||||
localStorage.setItem(VersionService.versionKey, version);
|
||||
location.reload();
|
||||
}
|
||||
|
||||
|
|
@ -54,8 +53,10 @@ export class NewUpdateModalComponent {
|
|||
(this.translocoService as any).cache.delete(locale);
|
||||
(this.translocoService as any).cache.clear();
|
||||
|
||||
// TODO: Retrigger transloco
|
||||
this.translocoService.setActiveLang(locale);
|
||||
// Retrigger transloco
|
||||
setTimeout(() => {
|
||||
this.translocoService.setActiveLang(locale);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
<button type="button" class="btn-close" [attr.aria-label]="t('close')" (click)="close()"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h5>{{updateData.updateTitle}}</h5>
|
||||
<pre class="update-body" [innerHtml]="updateData.updateBody | safeHtml"></pre>
|
||||
@if (updateData) {
|
||||
<app-changelog-update-item [update]="updateData" [showExtras]="false"></app-changelog-update-item>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
|
|
@ -2,15 +2,18 @@ import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core';
|
|||
import {NgbActiveModal, NgbModalModule} from '@ng-bootstrap/ng-bootstrap';
|
||||
import { UpdateVersionEvent } from 'src/app/_models/events/update-version-event';
|
||||
import {CommonModule} from "@angular/common";
|
||||
import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
|
||||
import {SafeHtmlPipe} from "../../../_pipes/safe-html.pipe";
|
||||
import {TranslocoDirective} from "@jsverse/transloco";
|
||||
import {WikiLink} from "../../_models/wiki";
|
||||
import {WikiLink} from "../../../_models/wiki";
|
||||
import {
|
||||
ChangelogUpdateItemComponent
|
||||
} from "../changelog-update-item/changelog-update-item.component";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-update-notification-modal',
|
||||
standalone: true,
|
||||
imports: [CommonModule, NgbModalModule, SafeHtmlPipe, TranslocoDirective],
|
||||
imports: [CommonModule, NgbModalModule, SafeHtmlPipe, TranslocoDirective, ChangelogUpdateItemComponent],
|
||||
templateUrl: './update-notification-modal.component.html',
|
||||
styleUrls: ['./update-notification-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
|
|
@ -20,6 +23,8 @@ export class UpdateNotificationModalComponent implements OnInit {
|
|||
@Input({required: true}) updateData!: UpdateVersionEvent;
|
||||
updateUrl: string = WikiLink.UpdateNative;
|
||||
|
||||
// TODO: I think I can remove this and just use NewUpdateModalComponent instead which handles both Nightly/Stable
|
||||
|
||||
constructor(public modal: NgbActiveModal) { }
|
||||
|
||||
ngOnInit() {
|
||||
|
|
@ -97,6 +97,7 @@ export class AppComponent implements OnInit {
|
|||
return user.preferences.noTransitions;
|
||||
}), takeUntilDestroyed(this.destroyRef));
|
||||
|
||||
this.localizationService.getLocales().subscribe(); // This will cache the localizations on startup
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +114,6 @@ export class AppComponent implements OnInit {
|
|||
this.setDocHeight();
|
||||
this.setCurrentUser();
|
||||
this.themeService.setColorScape('');
|
||||
this.localizationService.getLocales().subscribe(); // This will cache the localizations on startup
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -220,7 +220,6 @@ export class VolumeCardComponent implements OnInit {
|
|||
read(event: any) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
console.log('reading volume');
|
||||
this.readerService.readVolume(this.libraryId, this.seriesId, this.volume, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { NgbModal, NgbModalRef, NgbPopover } from '@ng-bootstrap/ng-bootstrap';
|
|||
import {BehaviorSubject, debounceTime, startWith} from 'rxjs';
|
||||
import { ConfirmConfig } from 'src/app/shared/confirm-dialog/_models/confirm-config';
|
||||
import { ConfirmService } from 'src/app/shared/confirm.service';
|
||||
import { UpdateNotificationModalComponent } from 'src/app/shared/update-notification/update-notification-modal.component';
|
||||
import { UpdateNotificationModalComponent } from 'src/app/announcements/_components/update-notification/update-notification-modal.component';
|
||||
import { DownloadService } from 'src/app/shared/_services/download.service';
|
||||
import { ErrorEvent } from 'src/app/_models/events/error-event';
|
||||
import { InfoEvent } from 'src/app/_models/events/info-event';
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@
|
|||
{{item.username}}
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">{{t('comics-label', {value: item.comicsTime})}}</li>
|
||||
<li class="list-group-item">{{t('manga-label', {value: item.mangaTime})}}</li>
|
||||
<li class="list-group-item">{{t('books-label', {value: item.booksTime})}}</li>
|
||||
<li class="list-group-item">{{t('comics-label', {value: item.comicsTime | number:'1.0-1'})}}</li>
|
||||
<li class="list-group-item">{{t('manga-label', {value: item.mangaTime | number:'1.0-1'})}}</li>
|
||||
<li class="list-group-item">{{t('books-label', {value: item.booksTime | number:'1.0-1'})}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Observable, 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";
|
||||
import { AsyncPipe } from '@angular/common';
|
||||
import {AsyncPipe, DecimalPipe} from '@angular/common';
|
||||
import {TranslocoDirective} from "@jsverse/transloco";
|
||||
import {CarouselReelComponent} from "../../../carousel/_components/carousel-reel/carousel-reel.component";
|
||||
|
||||
|
|
@ -29,18 +29,20 @@ export const TimePeriods: Array<{title: string, value: number}> =
|
|||
styleUrls: ['./top-readers.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [ReactiveFormsModule, AsyncPipe, TranslocoDirective, CarouselReelComponent]
|
||||
imports: [ReactiveFormsModule, AsyncPipe, TranslocoDirective, CarouselReelComponent, DecimalPipe]
|
||||
})
|
||||
export class TopReadersComponent implements OnInit {
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly statsService = inject(StatisticsService);
|
||||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
|
||||
formGroup: FormGroup;
|
||||
timePeriods = TimePeriods;
|
||||
users$: Observable<TopUserRead[]>;
|
||||
|
||||
|
||||
constructor(private statsService: StatisticsService, private readonly cdRef: ChangeDetectorRef) {
|
||||
constructor() {
|
||||
this.formGroup = new FormGroup({
|
||||
'days': new FormControl(this.timePeriods[0].value, []),
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue