refactor(frontend): refactor frontend services code

This commit is contained in:
raiper34
2024-09-30 14:29:40 +02:00
parent 7359a13a7c
commit 887ac2237a
6 changed files with 71 additions and 57 deletions
@@ -1,8 +1,9 @@
import {Component, Input} from '@angular/core'; import {Component, Input} from '@angular/core';
import {AsyncPipe, CommonModule, NgForOf, NgIf} from "@angular/common"; import {AsyncPipe, CommonModule, NgForOf, NgIf} from "@angular/common";
import {TrackListComponent} from "../track-list/track-list.component"; import {TrackListComponent} from "../track-list/track-list.component";
import {Playlist, PlaylistService, PlaylistStatusEnum, PlaylistUi} from "../../services/playlist.service"; import {PlaylistService, PlaylistStatusEnum, PlaylistUi} from "../../services/playlist.service";
import {Observable, map} from "rxjs"; import {Observable, map} from "rxjs";
import {Playlist} from "../../models/playlist";
const STATUS2CLASS = { const STATUS2CLASS = {
[PlaylistStatusEnum.Completed]: 'is-success', [PlaylistStatusEnum.Completed]: 'is-success',
@@ -1,7 +1,8 @@
import {Component, Input} from '@angular/core'; import {Component, Input} from '@angular/core';
import {CommonModule, NgFor, NgSwitch, NgSwitchCase} from "@angular/common"; import {CommonModule, NgFor, NgSwitch, NgSwitchCase} from "@angular/common";
import {Track, TrackService, TrackStatusEnum} from "../../services/track.service"; import {TrackService} from "../../services/track.service";
import {Observable} from "rxjs"; import {Observable} from "rxjs";
import {Track, TrackStatusEnum} from "../../models/track";
@Component({ @Component({
selector: 'app-track-list', selector: 'app-track-list',
+8
View File
@@ -0,0 +1,8 @@
export interface Playlist {
id: number;
name?: string;
spotifyUrl: string;
error?: string;
active: boolean;
createdAt: number;
}
+19
View File
@@ -0,0 +1,19 @@
export interface Track {
id: number;
artist: string;
name: string;
spotifyUrl: string;
youtubeUrl: string;
status: TrackStatusEnum;
playlistId?: number;
error?: string;
}
export enum TrackStatusEnum {
New,
Searching,
Queued,
Downloading,
Completed,
Error,
}
@@ -3,9 +3,7 @@ import {createStore} from "@ngneat/elf";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import { import {
deleteEntities, deleteEntities,
getEntityByPredicate,
selectAllEntities, selectEntities, selectEntity, selectAllEntities, selectEntities, selectEntity,
selectEntityByPredicate,
setEntities, setEntities,
UIEntitiesRef, UIEntitiesRef,
unionEntities, updateEntities, upsertEntities, unionEntities, updateEntities, upsertEntities,
@@ -14,20 +12,17 @@ import {
} from "@ngneat/elf-entities"; } from "@ngneat/elf-entities";
import {joinRequestResult, trackRequestResult} from "@ngneat/elf-requests"; import {joinRequestResult, trackRequestResult} from "@ngneat/elf-requests";
import {combineLatest, filter, first, map, Observable, of, switchMap, tap} from "rxjs"; import {combineLatest, filter, first, map, Observable, of, switchMap, tap} from "rxjs";
import {Track, TrackService} from "./track.service"; import {TrackService} from "./track.service";
import {Socket} from "ngx-socket-io"; import {Socket} from "ngx-socket-io";
import {Playlist} from "../models/playlist";
const STORE_NAME = 'playlist'; const STORE_NAME = 'playlist';
const ENDPOINT = '/api/playlist'; const ENDPOINT = '/api/playlist';
const CREATE_LOADING = 'CREATE_LOADING'; const CREATE_LOADING = 'CREATE_LOADING';
enum WsPlaylistOperation {
export interface Playlist { New = 'playlistNew',
id: number; Update = 'playlistUpdate',
name?: string; Delete = 'playlistDelete',
spotifyUrl: string;
error?: string;
active: boolean;
createdAt: number;
} }
export interface PlaylistUi { export interface PlaylistUi {
@@ -53,26 +48,18 @@ export class PlaylistService {
withEntities<Playlist>(), withEntities<Playlist>(),
withUIEntities<PlaylistUi>() withUIEntities<PlaylistUi>()
); );
all$ = this.store.combine({ all$ = this.store.combine({
entities: this.store.pipe(selectAllEntities()), entities: this.store.pipe(selectAllEntities()),
UIEntities: this.store.pipe(selectEntities({ ref: UIEntitiesRef })), UIEntities: this.store.pipe(selectEntities({ ref: UIEntitiesRef })),
}).pipe(unionEntities(), map(data => data.sort((a, b) => this.sort(a, b)))); }).pipe(unionEntities(), map(data => data.sort((a, b) => this.groupActiveAndSortByCreation(a, b))));
loading$ = this.store.pipe(joinRequestResult([STORE_NAME]));
createLoading$ = this.store.pipe(joinRequestResult([CREATE_LOADING], { initialStatus: 'idle' })); createLoading$ = this.store.pipe(joinRequestResult([CREATE_LOADING], { initialStatus: 'idle' }));
constructor(private readonly http: HttpClient, constructor(private readonly http: HttpClient,
private readonly socket: Socket, private readonly socket: Socket,
private readonly trackService: TrackService, private readonly trackService: TrackService,
) { ) {
this.socket.on('playlistUpdate', (playlist: Playlist) => this.store.update(upsertEntities(playlist))); this.initWsConnection();
this.socket.on('playlistDelete', ({id}: {id: number}) => this.store.update(deleteEntities(Number(id))));
this.socket.on('playlistNew', (playlist: Playlist) =>
this.store.update(
upsertEntities(playlist),
upsertEntities({id: playlist.id, collapsed: false}, {ref: UIEntitiesRef})
)
);
} }
getById(id: number): Observable<Playlist | undefined> { getById(id: number): Observable<Playlist | undefined> {
@@ -133,7 +120,6 @@ export class PlaylistService {
setEntities(data.map(item => ({id: item.id, collapsed: false})), {ref: UIEntitiesRef}) setEntities(data.map(item => ({id: item.id, collapsed: false})), {ref: UIEntitiesRef})
)), )),
tap((data: Playlist[]) => data.forEach(playlist => this.trackService.fetch(playlist.id))), tap((data: Playlist[]) => data.forEach(playlist => this.trackService.fetch(playlist.id))),
trackRequestResult([STORE_NAME], { skipCache: true }),
).subscribe(); ).subscribe();
} }
@@ -144,17 +130,13 @@ export class PlaylistService {
} }
toggleCollapsed(id: number): void { toggleCollapsed(id: number): void {
this.store.update(updateEntities(id, old => ({...old, collapsed: !old.collapsed}), { ref: UIEntitiesRef })) this.store.update(updateEntities(id, old => ({...old, collapsed: !old.collapsed}), { ref: UIEntitiesRef }));
} }
delete(id: number): void { delete(id: number): void {
this.delete$(id).subscribe(); this.delete$(id).subscribe();
} }
private delete$(id: number): Observable<void> {
return this.http.delete<void>(`${ENDPOINT}/${id}`);
}
retryFailed(id: number): void { retryFailed(id: number): void {
this.http.get<void>(`${ENDPOINT}/retry/${id}`).subscribe(); this.http.get<void>(`${ENDPOINT}/retry/${id}`).subscribe();
} }
@@ -163,7 +145,22 @@ export class PlaylistService {
this.http.put<void>(`${ENDPOINT}/${id}`, {active}).subscribe(); this.http.put<void>(`${ENDPOINT}/${id}`, {active}).subscribe();
} }
private sort(a: Playlist & PlaylistUi, b: Playlist & PlaylistUi): number { private delete$(id: number): Observable<void> {
return this.http.delete<void>(`${ENDPOINT}/${id}`);
}
private groupActiveAndSortByCreation(a: Playlist & PlaylistUi, b: Playlist & PlaylistUi): number {
return a.active === b.active ? (b.createdAt - a.createdAt) : (a.active < b.active ? 1 : -1); return a.active === b.active ? (b.createdAt - a.createdAt) : (a.active < b.active ? 1 : -1);
} }
private initWsConnection(): void {
this.socket.on(WsPlaylistOperation.Update, (playlist: Playlist) => this.store.update(upsertEntities(playlist)));
this.socket.on(WsPlaylistOperation.Delete, ({id}: {id: number}) => this.store.update(deleteEntities(Number(id))));
this.socket.on(WsPlaylistOperation.New, (playlist: Playlist) =>
this.store.update(
upsertEntities(playlist),
upsertEntities({id: playlist.id, collapsed: false}, {ref: UIEntitiesRef})
)
);
}
} }
+14 -26
View File
@@ -3,30 +3,15 @@ import {createStore} from "@ngneat/elf";
import {deleteEntities, selectManyByPredicate, upsertEntities, withEntities} from "@ngneat/elf-entities"; import {deleteEntities, selectManyByPredicate, upsertEntities, withEntities} from "@ngneat/elf-entities";
import {Socket} from "ngx-socket-io"; import {Socket} from "ngx-socket-io";
import {map, Observable, tap} from "rxjs"; import {map, Observable, tap} from "rxjs";
import {trackRequestResult} from "@ngneat/elf-requests";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {Track, TrackStatusEnum} from "../models/track";
const STORE_NAME = 'track'; const STORE_NAME = 'track';
const ENDPOINT = '/api/track'; const ENDPOINT = '/api/track';
enum WsTrackOperation {
export interface Track { New = 'trackNew',
id: number; Update = 'trackUpdate',
artist: string; Delete = 'trackDelete',
name: string;
spotifyUrl: string;
youtubeUrl: string;
status: TrackStatusEnum;
playlistId?: number;
error?: string;
}
export enum TrackStatusEnum {
New,
Searching,
Queued,
Downloading,
Completed,
Error,
} }
@Injectable({ @Injectable({
@@ -58,17 +43,12 @@ export class TrackService {
private readonly http: HttpClient, private readonly http: HttpClient,
private readonly socket: Socket, private readonly socket: Socket,
) { ) {
this.socket.on('trackUpdate', (track: Track) => this.store.update(upsertEntities(track))); this.initWsConnection();
this.socket.on('trackDelete', ({id}: {id: number}) => this.store.update(deleteEntities(id)));
this.socket.on('trackNew', ({track, playlistId}: {track: Track, playlistId: number}) =>
this.store.update(upsertEntities([{...track, playlistId}]))
);
} }
fetch(playlistId: number): void { fetch(playlistId: number): void {
this.http.get<Track[]>(`${ENDPOINT}/playlist/${playlistId}`).pipe( this.http.get<Track[]>(`${ENDPOINT}/playlist/${playlistId}`).pipe(
tap((data: Track[]) => this.store.update(upsertEntities(data.map(track => ({...track, playlistId}))))), tap((data: Track[]) => this.store.update(upsertEntities(data.map(track => ({...track, playlistId}))))),
trackRequestResult([STORE_NAME], { skipCache: true }),
).subscribe(); ).subscribe();
} }
@@ -79,4 +59,12 @@ export class TrackService {
retry(id: number): void { retry(id: number): void {
this.http.get(`${ENDPOINT}/retry/${id}`).subscribe(); this.http.get(`${ENDPOINT}/retry/${id}`).subscribe();
} }
private initWsConnection(): void {
this.socket.on(WsTrackOperation.Update, (track: Track) => this.store.update(upsertEntities(track)));
this.socket.on(WsTrackOperation.Delete, ({id}: {id: number}) => this.store.update(deleteEntities(id)));
this.socket.on(WsTrackOperation.New, ({track, playlistId}: {track: Track, playlistId: number}) =>
this.store.update(upsertEntities([{...track, playlistId}]))
);
}
} }