Browse Source

resolve comments

pull/4604/head
KenTandrian 4 months ago
parent
commit
854e774f94
  1. 7
      apps/api/src/app/endpoints/watchlist/watchlist.controller.ts
  2. 4
      apps/api/src/app/endpoints/watchlist/watchlist.service.ts
  3. 25
      apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.component.ts
  4. 25
      apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.module.ts
  5. 47
      apps/client/src/app/components/home-watchlist/home-watchlist.component.ts
  6. 4
      apps/client/src/app/components/home-watchlist/home-watchlist.module.ts
  7. 3
      apps/client/src/app/pages/home/home-page.component.ts
  8. 6
      apps/client/src/app/services/data.service.ts

7
apps/api/src/app/endpoints/watchlist/watchlist.controller.ts

@ -2,7 +2,6 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor';
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor';
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import { RequestWithUser } from '@ghostfolio/common/types';
@ -55,8 +54,8 @@ export class WatchlistController {
) {
const watchlistItem = await this.watchlistService
.getWatchlistItems(this.request.user.id)
.then((items) => {
return items.find((item) => {
.then(({ watchlist }) => {
return watchlist.find((item) => {
return item.dataSource === dataSource && item.symbol === symbol;
});
});
@ -79,7 +78,7 @@ export class WatchlistController {
@HasPermission(permissions.readWatchlist)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getWatchlistItems(): Promise<AssetProfileIdentifier[]> {
public async getWatchlistItems() {
return this.watchlistService.getWatchlistItems(this.request.user.id);
}
}

4
apps/api/src/app/endpoints/watchlist/watchlist.service.ts

@ -64,7 +64,7 @@ export class WatchlistService {
public async getWatchlistItems(
userId: string
): Promise<AssetProfileIdentifier[]> {
): Promise<{ watchlist: AssetProfileIdentifier[] }> {
const user = await this.prismaService.user.findUnique({
select: {
watchlist: {
@ -74,6 +74,6 @@ export class WatchlistService {
where: { id: userId }
});
return user.watchlist ?? [];
return { watchlist: user.watchlist ?? [] };
}
}

25
apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.component.ts

@ -1,3 +1,6 @@
import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete';
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
@ -9,27 +12,39 @@ import {
FormBuilder,
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule,
ValidationErrors,
Validators
} from '@angular/forms';
import { MatDialogRef } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field';
import { Subject } from 'rxjs';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'h-100' },
imports: [
CommonModule,
FormsModule,
GfSymbolAutocompleteComponent,
MatButtonModule,
MatDialogModule,
MatFormFieldModule,
ReactiveFormsModule
],
selector: 'gf-create-watchlist-item-dialog',
styleUrls: ['./create-watchlist-item-dialog.component.scss'],
templateUrl: 'create-watchlist-item-dialog.html',
standalone: false
templateUrl: 'create-watchlist-item-dialog.html'
})
export class CreateWatchlistItemDialog implements OnInit, OnDestroy {
export class CreateWatchlistItemDialogComponent implements OnInit, OnDestroy {
public createWatchlistItemForm: FormGroup;
private unsubscribeSubject = new Subject<void>();
public constructor(
public readonly dialogRef: MatDialogRef<CreateWatchlistItemDialog>,
public readonly dialogRef: MatDialogRef<CreateWatchlistItemDialogComponent>,
public readonly formBuilder: FormBuilder
) {}

25
apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.module.ts

@ -1,25 +0,0 @@
import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field';
import { CreateWatchlistItemDialog } from './create-watchlist-item-dialog.component';
@NgModule({
declarations: [CreateWatchlistItemDialog],
imports: [
CommonModule,
FormsModule,
GfSymbolAutocompleteComponent,
MatButtonModule,
MatDialogModule,
MatFormFieldModule,
ReactiveFormsModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class GfCreateWatchlistItemDialogModule {}

47
apps/client/src/app/components/home-watchlist/home-watchlist.component.ts

@ -12,10 +12,10 @@ import {
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { DeviceDetectorService } from 'ngx-device-detector';
import { forkJoin, Subject } from 'rxjs';
import { map, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { CreateWatchlistItemDialog } from './create-watchlist-item-dialog/create-watchlist-item-dialog.component';
import { CreateWatchlistItemDialogComponent } from './create-watchlist-item-dialog/create-watchlist-item-dialog.component';
import { CreateWatchlistItemDialogParams } from './create-watchlist-item-dialog/interfaces/interfaces';
@Component({
@ -72,28 +72,21 @@ export class HomeWatchlistComponent implements OnDestroy, OnInit {
}
private loadWatchlistData() {
forkJoin({
watchlistItems: this.dataService.fetchWatchlist(),
allBenchmarks: this.dataService
.fetchBenchmarks()
.pipe(map((response) => response.benchmarks))
})
.pipe(
takeUntil(this.unsubscribeSubject),
map(({ watchlistItems, allBenchmarks }) => {
const watchlistLookup = new Set(
watchlistItems.map((item) => `${item.dataSource}:${item.symbol}`)
);
return allBenchmarks.filter((benchmark) =>
watchlistLookup.has(`${benchmark.dataSource}:${benchmark.symbol}`)
);
})
)
.subscribe({
next: (filteredBenchmarks) => {
this.watchlist = filteredBenchmarks;
this.changeDetectorRef.markForCheck();
}
this.dataService
.fetchWatchlist()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ watchlist }) => {
this.watchlist = watchlist.map((item) => ({
dataSource: item.dataSource,
symbol: item.symbol,
name: item.symbol,
marketCondition: null,
performances: null,
trend200d: 'UNKNOWN',
trend50d: 'UNKNOWN'
}));
this.changeDetectorRef.markForCheck();
});
}
@ -104,7 +97,7 @@ export class HomeWatchlistComponent implements OnDestroy, OnInit {
.subscribe((user) => {
this.user = user;
const dialogRef = this.dialog.open(CreateWatchlistItemDialog, {
const dialogRef = this.dialog.open(CreateWatchlistItemDialogComponent, {
autoFocus: false,
data: {
deviceType: this.deviceType,
@ -119,7 +112,7 @@ export class HomeWatchlistComponent implements OnDestroy, OnInit {
.subscribe(({ dataSource, symbol } = {}) => {
if (dataSource && symbol) {
this.dataService
.postWatchlist({ dataSource, symbol })
.postWatchlistItem({ dataSource, symbol })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe({
next: () => this.loadWatchlistData()

4
apps/client/src/app/components/home-watchlist/home-watchlist.module.ts

@ -5,7 +5,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
import { GfCreateWatchlistItemDialogModule } from './create-watchlist-item-dialog/create-watchlist-item-dialog.module';
import { CreateWatchlistItemDialogComponent } from './create-watchlist-item-dialog/create-watchlist-item-dialog.component';
import { HomeWatchlistComponent } from './home-watchlist.component';
@NgModule({
@ -14,7 +14,7 @@ import { HomeWatchlistComponent } from './home-watchlist.component';
imports: [
CommonModule,
GfBenchmarkComponent,
GfCreateWatchlistItemDialogModule,
CreateWatchlistItemDialogComponent,
MatButtonModule,
RouterModule
],

3
apps/client/src/app/pages/home/home-page.component.ts

@ -56,7 +56,8 @@ export class HomePageComponent implements OnDestroy, OnInit {
{
iconName: 'star-outline',
label: $localize`Watchlist`,
path: ['/home', 'watchlist']
path: ['/home', 'watchlist'],
showCondition: this.user?.settings?.isExperimentalFeatures
}
];
this.user = state.user;

6
apps/client/src/app/services/data.service.ts

@ -688,7 +688,9 @@ export class DataService {
}
public fetchWatchlist() {
return this.http.get<AssetProfileIdentifier[]>('/api/v1/watchlist');
return this.http.get<{ watchlist: AssetProfileIdentifier[] }>(
'/api/v1/watchlist'
);
}
public generateAccessToken(aUserId: string) {
@ -753,7 +755,7 @@ export class DataService {
return this.http.post<UserItem>('/api/v1/user', {});
}
public postWatchlist(watchlistItem: CreateWatchlistItemDto) {
public postWatchlistItem(watchlistItem: CreateWatchlistItemDto) {
return this.http.post('/api/v1/watchlist', watchlistItem);
}

Loading…
Cancel
Save