optimize remote #2
This commit is contained in:
@@ -83,31 +83,40 @@ export class RemoteComponent implements OnDestroy {
|
|||||||
globalSettingsService: GlobalSettingsService,
|
globalSettingsService: GlobalSettingsService,
|
||||||
private cRef: ChangeDetectorRef
|
private cRef: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
globalSettingsService.get$
|
const currentShowId$ = globalSettingsService.get$
|
||||||
.pipe(
|
.pipe(
|
||||||
filter((settings): settings is NonNullable<typeof settings> => !!settings),
|
filter((settings): settings is NonNullable<typeof settings> => !!settings),
|
||||||
map(_ => _.currentShow),
|
map(_ => _.currentShow),
|
||||||
filter((showId): showId is string => !!showId),
|
filter((showId): showId is string => !!showId),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
switchMap(showId =>
|
takeUntil(this.destroy$)
|
||||||
combineLatest([this.showService.read$(showId), this.showSongService.list$(showId)]).pipe(
|
);
|
||||||
map(([show, list]) => {
|
|
||||||
const presentationSongs = list.map(song => ({
|
const show$ = currentShowId$.pipe(
|
||||||
|
switchMap(showId => this.showService.read$(showId)),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsedSongs$ = currentShowId$.pipe(
|
||||||
|
switchMap(showId => this.showSongService.list$(showId)),
|
||||||
|
map(list => ({
|
||||||
|
list,
|
||||||
|
parsed: list.map(song => ({
|
||||||
id: song.id,
|
id: song.id,
|
||||||
title: song.title,
|
title: song.title,
|
||||||
sections: this.textRenderingService.parse(song.text, null, false),
|
sections: this.textRenderingService.parse(song.text, null, false),
|
||||||
}));
|
})),
|
||||||
return {show, list, presentationSongs};
|
})),
|
||||||
})
|
|
||||||
)
|
|
||||||
),
|
|
||||||
takeUntil(this.destroy$)
|
takeUntil(this.destroy$)
|
||||||
)
|
);
|
||||||
.subscribe(({show, list, presentationSongs}) => {
|
|
||||||
this.showSongs = list;
|
combineLatest([show$, parsedSongs$])
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(([show, parsedSongs]) => {
|
||||||
|
this.showSongs = parsedSongs.list;
|
||||||
this.show = show;
|
this.show = show;
|
||||||
const order = show?.order ?? [];
|
const order = show?.order ?? [];
|
||||||
const presentationSongsById = new Map(presentationSongs.map(song => [song.id, song] as const));
|
const presentationSongsById = new Map(parsedSongs.parsed.map(song => [song.id, song] as const));
|
||||||
this.presentationSongs = order.map(id => presentationSongsById.get(id) ?? null).filter((s): s is PresentationSong => !!s);
|
this.presentationSongs = order.map(id => presentationSongsById.get(id) ?? null).filter((s): s is PresentationSong => !!s);
|
||||||
this.cRef.markForCheck();
|
this.cRef.markForCheck();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -60,12 +60,14 @@
|
|||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
</swiper-container>
|
</swiper-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="songs$ | async as songs">
|
||||||
<app-add-song
|
<app-add-song
|
||||||
*ngIf="songs && !show.published && !useSwiper"
|
*ngIf="songs && !show.published && !useSwiper"
|
||||||
[showSongs]="showSongs"
|
[showSongs]="showSongs"
|
||||||
[show]="show"
|
[show]="show"
|
||||||
[songs]="songs"
|
[songs]="songs"
|
||||||
></app-add-song>
|
></app-add-song>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<app-button-row *ngIf="!useSwiper">
|
<app-button-row *ngIf="!useSwiper">
|
||||||
<ng-container *appRole="['leader']">
|
<ng-container *appRole="['leader']">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, HostListener, OnDestroy, OnInit} from '@angular/core';
|
import {ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, HostListener, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {filter, map, switchMap, tap} from 'rxjs/operators';
|
import {filter, map, shareReplay, switchMap, tap} from 'rxjs/operators';
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
import {ShowService} from '../services/show.service';
|
import {ShowService} from '../services/show.service';
|
||||||
import {Observable, Subscription} from 'rxjs';
|
import {Observable, of, Subscription} from 'rxjs';
|
||||||
import {Show} from '../services/show';
|
import {Show} from '../services/show';
|
||||||
import {SongService} from '../../songs/services/song.service';
|
import {SongService} from '../../songs/services/song.service';
|
||||||
import {Song} from '../../songs/services/song';
|
import {Song} from '../../songs/services/song';
|
||||||
@@ -83,7 +83,7 @@ import {ShowTypePipe} from '../../../widget-modules/pipes/show-type-translater/s
|
|||||||
})
|
})
|
||||||
export class ShowComponent implements OnInit, OnDestroy {
|
export class ShowComponent implements OnInit, OnDestroy {
|
||||||
public show$: Observable<Show | null> | null = null;
|
public show$: Observable<Show | null> | null = null;
|
||||||
public songs: Song[] | null = null;
|
public songs$: Observable<Song[] | null> | null = null;
|
||||||
public showSongs: ShowSong[] | null = null;
|
public showSongs: ShowSong[] | null = null;
|
||||||
public showId: string | null = null;
|
public showId: string | null = null;
|
||||||
public showText = false;
|
public showText = false;
|
||||||
@@ -128,7 +128,11 @@ export class ShowComponent implements OnInit, OnDestroy {
|
|||||||
map(param => param as {showId: string}),
|
map(param => param as {showId: string}),
|
||||||
map(param => param.showId),
|
map(param => param.showId),
|
||||||
tap((_: string) => (this.showId = _)),
|
tap((_: string) => (this.showId = _)),
|
||||||
switchMap((showId: string) => this.showService.read$(showId))
|
switchMap((showId: string) => this.showService.read$(showId)),
|
||||||
|
shareReplay({
|
||||||
|
bufferSize: 1,
|
||||||
|
refCount: true,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
this.subs.push(
|
this.subs.push(
|
||||||
this.activatedRoute.params
|
this.activatedRoute.params
|
||||||
@@ -141,13 +145,14 @@ export class ShowComponent implements OnInit, OnDestroy {
|
|||||||
.subscribe(_ => {
|
.subscribe(_ => {
|
||||||
this.showSongs = _;
|
this.showSongs = _;
|
||||||
this.cRef.markForCheck();
|
this.cRef.markForCheck();
|
||||||
}),
|
})
|
||||||
this.songService
|
);
|
||||||
.list$()
|
|
||||||
.pipe(filter(_ => !!_))
|
this.songs$ = this.show$.pipe(
|
||||||
.subscribe(_ => {
|
switchMap(show => (show && !show.published ? this.songService.list$() : of(null))),
|
||||||
this.songs = _;
|
shareReplay({
|
||||||
this.cRef.markForCheck();
|
bufferSize: 1,
|
||||||
|
refCount: true,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -217,7 +222,8 @@ export class ShowComponent implements OnInit, OnDestroy {
|
|||||||
public orderedShowSongs(show: Show): ShowSong[] {
|
public orderedShowSongs(show: Show): ShowSong[] {
|
||||||
const list = this.showSongs;
|
const list = this.showSongs;
|
||||||
if (!list) return [];
|
if (!list) return [];
|
||||||
return show.order.map(_ => list.filter(f => f.id === _)[0]);
|
const byId = new Map(list.map(item => [item.id, item] as const));
|
||||||
|
return show.order.map(id => byId.get(id)).filter((song): song is ShowSong => !!song);
|
||||||
}
|
}
|
||||||
|
|
||||||
public trackBy = (_: number, show: ShowSong) => show?.id;
|
public trackBy = (_: number, show: ShowSong) => show?.id;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {SongService} from '../../services/song.service';
|
|||||||
import {Song} from '../../services/song';
|
import {Song} from '../../services/song';
|
||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
import {Subscription} from 'rxjs';
|
import {Subscription} from 'rxjs';
|
||||||
|
import {take} from 'rxjs/operators';
|
||||||
import {CardComponent} from '../../../../widget-modules/components/card/card.component';
|
import {CardComponent} from '../../../../widget-modules/components/card/card.component';
|
||||||
import {MatFormField, MatLabel} from '@angular/material/form-field';
|
import {MatFormField, MatLabel} from '@angular/material/form-field';
|
||||||
import {MatInput} from '@angular/material/input';
|
import {MatInput} from '@angular/material/input';
|
||||||
@@ -34,7 +35,7 @@ export class NewComponent implements OnInit, OnDestroy {
|
|||||||
this.form.reset();
|
this.form.reset();
|
||||||
|
|
||||||
this.subs.push(
|
this.subs.push(
|
||||||
this.songService.list$().subscribe(songs => {
|
this.songService.list$().pipe(take(1)).subscribe(songs => {
|
||||||
const freeSongnumber = this.getFreeSongNumber(songs);
|
const freeSongnumber = this.getFreeSongNumber(songs);
|
||||||
this.form.controls.number.setValue(freeSongnumber);
|
this.form.controls.number.setValue(freeSongnumber);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export class UserService {
|
|||||||
public users$ = this.db.col$<User>('users').pipe(shareReplay({bufferSize: 1, refCount: true}));
|
public users$ = this.db.col$<User>('users').pipe(shareReplay({bufferSize: 1, refCount: true}));
|
||||||
private iUserId$ = new BehaviorSubject<string | null>(null);
|
private iUserId$ = new BehaviorSubject<string | null>(null);
|
||||||
private iUser$ = new BehaviorSubject<User | null>(null);
|
private iUser$ = new BehaviorSubject<User | null>(null);
|
||||||
|
private userByIdCache = new Map<string, Observable<User | null>>();
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private afAuth: AngularFireAuth,
|
private afAuth: AngularFireAuth,
|
||||||
@@ -52,7 +53,16 @@ export class UserService {
|
|||||||
public currentUser = async (): Promise<User | null> => firstValueFrom(this.user$);
|
public currentUser = async (): Promise<User | null> => firstValueFrom(this.user$);
|
||||||
|
|
||||||
public getUserbyId = (userId: string): Promise<User | null> => firstValueFrom(this.getUserbyId$(userId));
|
public getUserbyId = (userId: string): Promise<User | null> => firstValueFrom(this.getUserbyId$(userId));
|
||||||
public getUserbyId$ = (userId: string): Observable<User | null> => this.users$.pipe(map(_ => _.find(f => f.id === userId) || null));
|
public getUserbyId$ = (userId: string): Observable<User | null> => {
|
||||||
|
const cached = this.userByIdCache.get(userId);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user$ = this.db.doc$<User>(`users/${userId}`).pipe(shareReplay({bufferSize: 1, refCount: true}));
|
||||||
|
this.userByIdCache.set(userId, user$);
|
||||||
|
return user$;
|
||||||
|
};
|
||||||
|
|
||||||
public async login(user: string, password: string): Promise<string | null> {
|
public async login(user: string, password: string): Promise<string | null> {
|
||||||
const aUser = await this.afAuth.signInWithEmailAndPassword(user, password);
|
const aUser = await this.afAuth.signInWithEmailAndPassword(user, password);
|
||||||
|
|||||||
Reference in New Issue
Block a user