mirror of
https://github.com/adityachandelgit/BookLore.git
synced 2026-02-11 05:19:21 -06:00
Fix: Navigating Booklore on a new device requires refreshes
This commit is contained in:
committed by
Aditya Chandel
parent
b1508493cf
commit
ea84a9dc6a
@@ -1,7 +1,8 @@
|
||||
import {inject, Injectable, OnDestroy} from '@angular/core';
|
||||
import {BehaviorSubject, Subscription} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {map, filter, take} from 'rxjs/operators';
|
||||
import {BookdropFileApiService} from './bookdrop-file-api.service';
|
||||
import {AuthService} from '../core/service/auth.service';
|
||||
|
||||
export interface BookdropFileNotification {
|
||||
pendingCount: number;
|
||||
@@ -25,14 +26,13 @@ export class BookdropFileService implements OnDestroy {
|
||||
);
|
||||
|
||||
private apiService = inject(BookdropFileApiService);
|
||||
private authService = inject(AuthService);
|
||||
private subscriptions = new Subscription();
|
||||
|
||||
constructor() {
|
||||
const sub = this.apiService.getNotification().subscribe({
|
||||
next: summary => this.summarySubject.next(summary),
|
||||
error: err => console.warn('Failed to fetch bookdrop file summary:', err)
|
||||
});
|
||||
this.subscriptions.add(sub);
|
||||
this.authService.token$
|
||||
.pipe(filter(t => !!t), take(1))
|
||||
.subscribe(() => this.refresh());
|
||||
}
|
||||
|
||||
handleIncomingFile(summary: BookdropFileNotification): void {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import {inject, Injectable, Injector} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {Observable, tap} from 'rxjs';
|
||||
import {BehaviorSubject, Observable, tap} from 'rxjs';
|
||||
import {RxStompService} from '../../shared/websocket/rx-stomp.service';
|
||||
import {API_CONFIG} from '../../config/api-config';
|
||||
import {createRxStompConfig} from '../../shared/websocket/rx-stomp.config';
|
||||
import {OAuthService} from 'angular-oauth2-oidc';
|
||||
import {AppSettingsService} from './app-settings.service';
|
||||
import {Router} from '@angular/router';
|
||||
|
||||
@Injectable({
|
||||
@@ -21,6 +20,9 @@ export class AuthService {
|
||||
private oAuthService = inject(OAuthService);
|
||||
private router = inject(Router);
|
||||
|
||||
private tokenSubject = new BehaviorSubject<string | null>(this.getOidcAccessToken() || this.getInternalAccessToken());
|
||||
public token$ = this.tokenSubject.asObservable();
|
||||
|
||||
internalLogin(credentials: { username: string; password: string }): Observable<{ accessToken: string; refreshToken: string, isDefaultPassword: string }> {
|
||||
return this.http.post<{ accessToken: string; refreshToken: string, isDefaultPassword: string }>(`${this.apiUrl}/login`, credentials).pipe(
|
||||
tap((response) => {
|
||||
@@ -57,6 +59,7 @@ export class AuthService {
|
||||
saveInternalTokens(accessToken: string, refreshToken: string): void {
|
||||
localStorage.setItem('accessToken_Internal', accessToken);
|
||||
localStorage.setItem('refreshToken_Internal', refreshToken);
|
||||
this.tokenSubject.next(accessToken);
|
||||
}
|
||||
|
||||
getInternalAccessToken(): string | null {
|
||||
@@ -74,6 +77,7 @@ export class AuthService {
|
||||
logout(): void {
|
||||
localStorage.removeItem('accessToken_Internal');
|
||||
localStorage.removeItem('refreshToken_Internal');
|
||||
this.tokenSubject.next(null);
|
||||
this.getRxStompService().deactivate();
|
||||
if (this.oAuthService.clientId) {
|
||||
this.oAuthService.logOut();
|
||||
|
||||
26
booklore-ui/src/app/core/service/startup.service.ts
Normal file
26
booklore-ui/src/app/core/service/startup.service.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { AuthService } from './auth.service';
|
||||
import { UserService } from '../../settings/user-management/user.service';
|
||||
import { filter, catchError } from 'rxjs/operators';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class StartupService {
|
||||
private auth = inject(AuthService);
|
||||
private userSvc = inject(UserService);
|
||||
|
||||
load(): Promise<void> {
|
||||
this.auth.token$
|
||||
.pipe(filter(t => !!t))
|
||||
.subscribe(() => {
|
||||
this.userSvc.getMyself()
|
||||
.pipe(catchError(() => of(null)))
|
||||
.subscribe(user => {
|
||||
if (user) {
|
||||
this.userSvc.setInitialUser(user);
|
||||
}
|
||||
});
|
||||
});
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import {RxStompService} from '../../shared/websocket/rx-stomp.service';
|
||||
import {Library} from '../../book/model/library.model';
|
||||
import {catchError} from 'rxjs/operators';
|
||||
import {CbxPageSpread, CbxPageViewMode, PdfPageSpread, PdfPageViewMode} from '../../book/model/book.model';
|
||||
import {filter, take} from 'rxjs/operators';
|
||||
import {AuthService} from '../../core/service/auth.service';
|
||||
|
||||
export interface EntityViewPreferences {
|
||||
global: EntityViewPreference;
|
||||
@@ -119,18 +121,12 @@ export class UserService {
|
||||
private readonly userUrl = `${API_CONFIG.BASE_URL}/api/v1/users`;
|
||||
|
||||
private http = inject(HttpClient);
|
||||
private injector = inject(Injector);
|
||||
|
||||
private rxStompService?: RxStompService;
|
||||
|
||||
private userStateSubject = new BehaviorSubject<User | null>(null);
|
||||
userState$ = this.userStateSubject.asObservable();
|
||||
|
||||
constructor() {
|
||||
this.getMyself().subscribe(user => {
|
||||
this.userStateSubject.next(user);
|
||||
this.startWebSocket();
|
||||
});
|
||||
public setInitialUser(user: User): void {
|
||||
this.userStateSubject.next(user);
|
||||
}
|
||||
|
||||
getCurrentUser(): User | null {
|
||||
@@ -200,29 +196,4 @@ export class UserService {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
updateUserSettingV2(userId: number, key: string, value: any): Observable<void> {
|
||||
const payload = { key, value };
|
||||
return this.http.put<void>(`${this.userUrl}/${userId}/settings`, payload);
|
||||
}
|
||||
|
||||
private startWebSocket(): void {
|
||||
const token = this.getToken();
|
||||
if (token) {
|
||||
const rxStompService = this.getRxStompService();
|
||||
rxStompService.activate();
|
||||
}
|
||||
}
|
||||
|
||||
private getRxStompService(): RxStompService {
|
||||
if (!this.rxStompService) {
|
||||
this.rxStompService = this.injector.get(RxStompService);
|
||||
}
|
||||
return this.rxStompService;
|
||||
}
|
||||
|
||||
getToken(): string | null {
|
||||
return localStorage.getItem('accessToken');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="flex flex-col items-center justify-center p-2 md:p-4 rounded-lg border border-neutral-700" style="max-width: 700px; margin: auto;">
|
||||
<div class="flex flex-col items-center justify-center p-2 md:p-6 rounded-lg border border-neutral-700" style="max-width: 700px; margin: auto;">
|
||||
<div class="mb-4 w-full text-center">
|
||||
<span class="inline-block px-3 py-1 rounded-full bg-blue-800/60 text-blue-200 text-xs font-semibold tracking-wide mb-2">
|
||||
Open Source & Community Driven
|
||||
|
||||
@@ -16,6 +16,7 @@ import {AuthService, websocketInitializer} from './app/core/service/auth.service
|
||||
import {provideOAuthClient} from 'angular-oauth2-oidc';
|
||||
import {APP_INITIALIZER, provideAppInitializer} from '@angular/core';
|
||||
import {initializeAuthFactory} from './app/auth-initializer';
|
||||
import {StartupService} from './app/core/service/startup.service';
|
||||
|
||||
bootstrapApplication(AppComponent, {
|
||||
providers: [
|
||||
@@ -25,6 +26,12 @@ bootstrapApplication(AppComponent, {
|
||||
deps: [AuthService],
|
||||
multi: true
|
||||
},
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: (startup: StartupService) => () => startup.load(),
|
||||
deps: [StartupService],
|
||||
multi: true
|
||||
},
|
||||
provideHttpClient(withInterceptors([AuthInterceptorService])),
|
||||
provideOAuthClient(),
|
||||
provideAppInitializer(initializeAuthFactory()),
|
||||
|
||||
Reference in New Issue
Block a user