Browse Source

Bugfix/improve symbol lookup (#322)

* Improve symbol lookup

* Update changelog
pull/323/head
Thomas Kaul 3 years ago
committed by GitHub
parent
commit
6386786ac0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 12
      apps/api/src/app/symbol/symbol.controller.ts
  3. 6
      apps/api/src/app/symbol/symbol.service.ts
  4. 50
      apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts
  5. 2
      apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html

1
CHANGELOG.md

@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Filtered out positions without any quantity in the positions table - Filtered out positions without any quantity in the positions table
- Improved the symbol lookup: allow saving with valid symbol in create or edit transaction dialog
## 1.43.0 - 24.08.2021 ## 1.43.0 - 24.08.2021

12
apps/api/src/app/symbol/symbol.controller.ts

@ -11,6 +11,7 @@ import {
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { isEmpty } from 'lodash';
import { LookupItem } from './interfaces/lookup-item.interface'; import { LookupItem } from './interfaces/lookup-item.interface';
import { SymbolItem } from './interfaces/symbol-item.interface'; import { SymbolItem } from './interfaces/symbol-item.interface';
@ -48,6 +49,15 @@ export class SymbolController {
@Get(':symbol') @Get(':symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
public async getPosition(@Param('symbol') symbol): Promise<SymbolItem> { public async getPosition(@Param('symbol') symbol): Promise<SymbolItem> {
return this.symbolService.get(symbol); const result = await this.symbolService.get(symbol);
if (!result || isEmpty(result)) {
throw new HttpException(
getReasonPhrase(StatusCodes.NOT_FOUND),
StatusCodes.NOT_FOUND
);
}
return result;
} }
} }

6
apps/api/src/app/symbol/symbol.service.ts

@ -15,8 +15,9 @@ export class SymbolService {
public async get(aSymbol: string): Promise<SymbolItem> { public async get(aSymbol: string): Promise<SymbolItem> {
const response = await this.dataProviderService.get([aSymbol]); const response = await this.dataProviderService.get([aSymbol]);
const { currency, dataSource, marketPrice } = response[aSymbol]; const { currency, dataSource, marketPrice } = response[aSymbol] ?? {};
if (currency && dataSource && marketPrice) {
return { return {
dataSource, dataSource,
marketPrice, marketPrice,
@ -24,6 +25,9 @@ export class SymbolService {
}; };
} }
return undefined;
}
public async lookup(aQuery: string): Promise<{ items: LookupItem[] }> { public async lookup(aQuery: string): Promise<{ items: LookupItem[] }> {
const results: { items: LookupItem[] } = { items: [] }; const results: { items: LookupItem[] } = { items: [] };

50
apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts

@ -11,8 +11,9 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { Currency } from '@prisma/client'; import { Currency } from '@prisma/client';
import { Observable, Subject } from 'rxjs'; import { EMPTY, Observable, Subject } from 'rxjs';
import { import {
catchError,
debounceTime, debounceTime,
distinctUntilChanged, distinctUntilChanged,
startWith, startWith,
@ -49,7 +50,7 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
@Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateTransactionDialogParams @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateTransactionDialogParams
) {} ) {}
ngOnInit() { public ngOnInit() {
const { currencies, platforms } = this.dataService.fetchInfo(); const { currencies, platforms } = this.dataService.fetchInfo();
this.currencies = currencies; this.currencies = currencies;
@ -84,17 +85,45 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
this.data.transaction.unitPrice = this.currentMarketPrice; this.data.transaction.unitPrice = this.currentMarketPrice;
} }
public onBlurSymbol() {
const symbol = this.searchSymbolCtrl.value;
this.updateSymbol(symbol);
}
public onCancel(): void { public onCancel(): void {
this.dialogRef.close(); this.dialogRef.close();
} }
public onUpdateSymbol(event: MatAutocompleteSelectedEvent) { public onUpdateSymbol(event: MatAutocompleteSelectedEvent) {
this.updateSymbol(event.option.value);
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
private updateSymbol(symbol: string) {
this.isLoading = true; this.isLoading = true;
this.data.transaction.symbol = event.option.value;
this.data.transaction.symbol = symbol;
this.dataService this.dataService
.fetchSymbolItem(this.data.transaction.symbol) .fetchSymbolItem(this.data.transaction.symbol)
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(
catchError(() => {
this.data.transaction.currency = null;
this.data.transaction.dataSource = null;
this.data.transaction.unitPrice = null;
this.isLoading = false;
this.changeDetectorRef.markForCheck();
return EMPTY;
}),
takeUntil(this.unsubscribeSubject)
)
.subscribe(({ currency, dataSource, marketPrice }) => { .subscribe(({ currency, dataSource, marketPrice }) => {
this.data.transaction.currency = currency; this.data.transaction.currency = currency;
this.data.transaction.dataSource = dataSource; this.data.transaction.dataSource = dataSource;
@ -105,17 +134,4 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });
} }
public onUpdateSymbolByTyping(value: string) {
this.data.transaction.currency = null;
this.data.transaction.dataSource = null;
this.data.transaction.unitPrice = null;
this.data.transaction.symbol = value;
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
} }

2
apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html

@ -29,7 +29,7 @@
required required
[formControl]="searchSymbolCtrl" [formControl]="searchSymbolCtrl"
[matAutocomplete]="auto" [matAutocomplete]="auto"
(change)="onUpdateSymbolByTyping($event.target.value)" (blur)="onBlurSymbol()"
/> />
<mat-autocomplete <mat-autocomplete
#auto="matAutocomplete" #auto="matAutocomplete"

Loading…
Cancel
Save