fix user cache

This commit is contained in:
BENEDEK László 2025-06-05 03:47:45 +02:00
parent bdc86eb26c
commit d8fd5028dd
4 changed files with 54 additions and 36 deletions

View File

@ -1,6 +1,7 @@
import { Component, EventEmitter, OnChanges, OnInit, Output } from '@angular/core';
import { Component, EventEmitter, OnChanges, OnDestroy, OnInit, Output } from '@angular/core';
import { Channel } from '../../../models/channel';
import { ChatService } from '../../../services/chat.service';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector: 'app-channel-list',
@ -8,22 +9,30 @@ import { ChatService } from '../../../services/chat.service';
templateUrl: './channel-list.component.html',
styleUrl: './channel-list.component.scss'
})
export class ChannelListComponent implements OnInit {
export class ChannelListComponent implements OnInit, OnDestroy {
@Output("select") selectEmitter: EventEmitter<Channel> = new EventEmitter<Channel>();
public channels!: Channel[];
public selectedChannel?: Channel;
private destroy = new Subject<void>();
constructor(private chatService: ChatService) { }
ngOnInit() {
this.chatService.ListChannels()
.pipe(takeUntil(this.destroy))
.subscribe(channels => {
this.channels = channels;
this.selectedChannel = this.channels[0];
});
}
ngOnDestroy(): void {
this.destroy.next();
this.destroy.complete();
}
public Select(index: number): void {
this.selectEmitter.emit(this.selectedChannel = this.channels[index]);
}

View File

@ -1,4 +1,4 @@
import { Component, Input, OnChanges, OnInit } from '@angular/core';
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
import { Message } from '../../../models/message';
import { ChatService } from '../../../services/chat.service';
import { UserService } from '../../../services/user.service';
@ -11,7 +11,7 @@ import { Subscription } from 'rxjs';
templateUrl: './feed.component.html',
styleUrl: './feed.component.scss'
})
export class FeedComponent implements OnChanges {
export class FeedComponent implements OnChanges, OnDestroy {
private readonly DEFAULT_CHANNEL_ID: number = 1;
@Input('channel') public channel?: Channel;
@ -19,7 +19,7 @@ export class FeedComponent implements OnChanges {
public subscription?: Subscription;
constructor(private chatService: ChatService, private userService: UserService) { }
constructor(private chatService: ChatService) { }
ngOnChanges() {
if (this.subscription) {
@ -29,6 +29,12 @@ export class FeedComponent implements OnChanges {
this.subscription =
this.chatService.GetMessages(this.channel?.id ?? this.DEFAULT_CHANNEL_ID)
.subscribe(message => this.messages.push(message));
.subscribe(message => this.messages.push(message));
}
ngOnDestroy(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}

View File

@ -1,6 +1,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { UserService } from '../../../../../services/user.service';
import { ToastrService } from 'ngx-toastr';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector: 'app-profile-picture',
@ -8,14 +9,17 @@ import { ToastrService } from 'ngx-toastr';
templateUrl: './profile-picture.component.html',
styleUrl: './profile-picture.component.scss'
})
export class ProfilePictureComponent implements OnInit {
export class ProfilePictureComponent implements OnInit, OnDestroy {
@Input("username") public username!: string;
public url?: string;
private destroy: Subject<void> = new Subject<void>();
constructor(private userService: UserService, private toastrService: ToastrService) { }
ngOnInit(): void {
this.userService.GetProfilePictureURL(this.username)
.pipe(takeUntil(this.destroy))
.subscribe({
next: url => this.url = url,
error: _ => {
@ -23,4 +27,9 @@ export class ProfilePictureComponent implements OnInit {
}
});
}
ngOnDestroy(): void {
this.destroy.next();
this.destroy.complete();
}
}

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { catchError, map, Observable, throwError } from 'rxjs';
import { catchError, map, Observable, shareReplay, tap, throwError } from 'rxjs';
import { User } from '../models/user';
import { HttpClient } from '@angular/common/http';
import { UserInfoResponse } from './responses/user';
@ -9,44 +9,38 @@ import { environment } from '../../environment/environment';
providedIn: 'root'
})
export class UserService {
private users: Map<string, User> = new Map<string, User>();
private users: Map<string, Observable<User>> = new Map<string, Observable<User>>();
constructor(private http: HttpClient) { }
public GetUser(username: string): Observable<User> {
if (this.users.has(username)) {
return new Observable<User>(subscriber => {
subscriber.next(this.users.get(username)!);
subscriber.complete();
});
let user = this.users.get(username);
if (user) {
return user;
} else {
let url = `${environment.apiBase}/user/info/${username}`
return this.http.get<UserInfoResponse>(url, { withCredentials: true }).pipe(
map(response => {
if (response.error) {
throw new Error(response.error);
}
let observable = this.http.get<UserInfoResponse>(url, { withCredentials: true })
.pipe(
map(response => {
if (response.error) {
throw new Error(response.error);
}
if (response.user) {
this.users.set(username, response.user);
return response.user;
}
if (response.user) {
return response.user;
}
throw new Error("bad API response, missing user with no error");
}),
catchError(error => throwError(() => new Error(error.error.message)))
);
throw new Error("bad API response, missing user with no error");
}),
catchError(error => throwError(() => new Error(error.error.message))),
shareReplay({ bufferSize: 1, refCount: true })
);
this.users.set(username, observable);
return observable;
}
}
public GetProfilePictureURL(username: string): Observable<string> {
if (this.users.has(username)) {
return new Observable<string>(subscriber => {
subscriber.next(this.users.get(username)!.picture);
subscriber.complete();
});
} else {
return this.GetUser(username).pipe(map(user => user.picture));
}
return this.GetUser(username).pipe(map(user => user.picture));
}
}