diff --git a/CHANGELOG.md b/CHANGELOG.md index e36ff4918..ace591773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Made the data provider warning more discreet +- Upgraded `http-status-codes` from version `2.1.4` to `2.2.0` - Upgraded `ngx-device-detector` from version `2.1.1` to `3.0.0` - Upgraded `ngx-markdown` from version `12.0.1` to `13.0.0` - Upgraded `ngx-stripe` from version `12.0.2` to `13.0.0` diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index f4578e070..879b11bb5 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -51,7 +51,7 @@ export class PortfolioController { @Get('investments') @UseGuards(AuthGuard('jwt')) public async findAll( - @Headers('impersonation-id') impersonationId, + @Headers('impersonation-id') impersonationId: string, @Res() res: Response ): Promise { if ( @@ -87,7 +87,7 @@ export class PortfolioController { @Get('chart') @UseGuards(AuthGuard('jwt')) public async getChart( - @Headers('impersonation-id') impersonationId, + @Headers('impersonation-id') impersonationId: string, @Query('range') range, @Res() res: Response ): Promise { @@ -98,18 +98,14 @@ export class PortfolioController { let chartData = historicalDataContainer.items; - let hasNullValue = false; + let hasError = false; chartData.forEach((chartDataItem) => { if (hasNotDefinedValuesInObject(chartDataItem)) { - hasNullValue = true; + hasError = true; } }); - if (hasNullValue) { - res.status(StatusCodes.ACCEPTED); - } - if ( impersonationId || this.userService.isRestrictedView(this.request.user) @@ -131,6 +127,7 @@ export class PortfolioController { } return res.json({ + hasError, chart: chartData, isAllTimeHigh: historicalDataContainer.isAllTimeHigh, isAllTimeLow: historicalDataContainer.isAllTimeLow @@ -140,7 +137,7 @@ export class PortfolioController { @Get('details') @UseGuards(AuthGuard('jwt')) public async getDetails( - @Headers('impersonation-id') impersonationId, + @Headers('impersonation-id') impersonationId: string, @Query('range') range, @Res() res: Response ): Promise { @@ -152,6 +149,8 @@ export class PortfolioController { return res.json({ accounts: {}, holdings: {} }); } + let hasError = false; + const { accounts, holdings, hasErrors } = await this.portfolioService.getDetails( impersonationId, @@ -160,7 +159,7 @@ export class PortfolioController { ); if (hasErrors || hasNotDefinedValuesInObject(holdings)) { - res.status(StatusCodes.ACCEPTED); + hasError = true; } if ( @@ -198,43 +197,38 @@ export class PortfolioController { } } - return res.json({ accounts, holdings }); + return res.json({ accounts, hasError, holdings }); } @Get('performance') @UseGuards(AuthGuard('jwt')) public async getPerformance( - @Headers('impersonation-id') impersonationId, + @Headers('impersonation-id') impersonationId: string, @Query('range') range, @Res() res: Response - ): Promise { + ): Promise<{ hasErrors: boolean; performance: PortfolioPerformance }> { const performanceInformation = await this.portfolioService.getPerformance( impersonationId, range ); - if (performanceInformation?.hasErrors) { - res.status(StatusCodes.ACCEPTED); - } - - let performance = performanceInformation.performance; if ( impersonationId || this.userService.isRestrictedView(this.request.user) ) { - performance = nullifyValuesInObject(performance, [ - 'currentGrossPerformance', - 'currentValue' - ]); + performanceInformation.performance = nullifyValuesInObject( + performanceInformation.performance, + ['currentGrossPerformance', 'currentValue'] + ); } - return res.json(performance); + return res.json(performanceInformation); } @Get('positions') @UseGuards(AuthGuard('jwt')) public async getPositions( - @Headers('impersonation-id') impersonationId, + @Headers('impersonation-id') impersonationId: string, @Query('range') range, @Res() res: Response ): Promise { @@ -243,10 +237,6 @@ export class PortfolioController { range ); - if (result?.hasErrors) { - res.status(StatusCodes.ACCEPTED); - } - if ( impersonationId || this.userService.isRestrictedView(this.request.user) @@ -353,7 +343,7 @@ export class PortfolioController { @Get('position/:symbol') @UseGuards(AuthGuard('jwt')) public async getPosition( - @Headers('impersonation-id') impersonationId, + @Headers('impersonation-id') impersonationId: string, @Param('symbol') symbol ): Promise { let position = await this.portfolioService.getPosition( @@ -387,7 +377,7 @@ export class PortfolioController { @Get('report') @UseGuards(AuthGuard('jwt')) public async getReport( - @Headers('impersonation-id') impersonationId, + @Headers('impersonation-id') impersonationId: string, @Res() res: Response ): Promise { if ( diff --git a/apps/client/src/app/components/home-overview/home-overview.component.ts b/apps/client/src/app/components/home-overview/home-overview.component.ts index afc77f766..393de9fe8 100644 --- a/apps/client/src/app/components/home-overview/home-overview.component.ts +++ b/apps/client/src/app/components/home-overview/home-overview.component.ts @@ -29,6 +29,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit { { label: 'Max', value: 'max' } ]; public deviceType: string; + public hasError: boolean; public hasImpersonationId: boolean; public historicalDataItems: LineChartItem[]; public isAllTimeHigh: boolean; @@ -116,7 +117,8 @@ export class HomeOverviewComponent implements OnDestroy, OnInit { .fetchPortfolioPerformance({ range: this.dateRange }) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((response) => { - this.performance = response; + this.hasError = response.hasErrors; + this.performance = response.performance; this.isLoadingPerformance = false; this.changeDetectorRef.markForCheck(); diff --git a/apps/client/src/app/components/home-overview/home-overview.html b/apps/client/src/app/components/home-overview/home-overview.html index efe001161..0cfb29642 100644 --- a/apps/client/src/app/components/home-overview/home-overview.html +++ b/apps/client/src/app/components/home-overview/home-overview.html @@ -1,15 +1,5 @@
@@ -37,6 +27,8 @@ -
-
+
+
+ +
diff --git a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.scss b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.scss index 850cce442..398a2981a 100644 --- a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.scss +++ b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.scss @@ -1,6 +1,10 @@ :host { display: block; + .status { + font-size: 1.33rem; + } + .value-container { #value { font-variant-numeric: tabular-nums; diff --git a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts index 8c69eea1d..318f6e169 100644 --- a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts +++ b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts @@ -19,6 +19,8 @@ import { isNumber } from 'lodash'; }) export class PortfolioPerformanceComponent implements OnChanges, OnInit { @Input() baseCurrency: string; + @Input() deviceType: string; + @Input() hasError: boolean; @Input() isAllTimeHigh: boolean; @Input() isAllTimeLow: boolean; @Input() isLoading: boolean; @@ -44,7 +46,11 @@ export class PortfolioPerformanceComponent implements OnChanges, OnInit { this.unit = this.baseCurrency; new CountUp('value', this.performance?.currentValue, { - decimalPlaces: 2, + decimalPlaces: + this.deviceType === 'mobile' && + this.performance?.currentValue >= 100000 + ? 0 + : 2, duration: 1, separator: `'` }).start(); diff --git a/apps/client/src/app/core/http-response.interceptor.ts b/apps/client/src/app/core/http-response.interceptor.ts index 1df29e7ec..9ac221e62 100644 --- a/apps/client/src/app/core/http-response.interceptor.ts +++ b/apps/client/src/app/core/http-response.interceptor.ts @@ -4,8 +4,7 @@ import { HttpEvent, HttpHandler, HttpInterceptor, - HttpRequest, - HttpResponse + HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { @@ -43,26 +42,6 @@ export class HttpResponseInterceptor implements HttpInterceptor { ): Observable> { return next.handle(request).pipe( tap((event: HttpEvent) => { - if (event instanceof HttpResponse) { - if (event.status === StatusCodes.ACCEPTED) { - if (!this.snackBarRef) { - this.snackBarRef = this.snackBar.open( - 'Sorry! Our data provider partner is experiencing a mild case of the hiccups ;(', - 'Try again?', - { duration: 6000 } - ); - - this.snackBarRef.afterDismissed().subscribe(() => { - this.snackBarRef = undefined; - }); - - this.snackBarRef.onAction().subscribe(() => { - window.location.reload(); - }); - } - } - } - return event; }), catchError((error: HttpErrorResponse) => { diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 9ba5ca669..586192db5 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -181,7 +181,10 @@ export class DataService { } public fetchPortfolioPerformance(aParams: { [param: string]: any }) { - return this.http.get('/api/portfolio/performance', { + return this.http.get<{ + hasErrors: boolean; + performance: PortfolioPerformance; + }>('/api/portfolio/performance', { params: aParams }); } diff --git a/libs/common/src/lib/interfaces/portfolio-chart.interface.ts b/libs/common/src/lib/interfaces/portfolio-chart.interface.ts index d9946746d..a696fe632 100644 --- a/libs/common/src/lib/interfaces/portfolio-chart.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-chart.interface.ts @@ -1,6 +1,7 @@ import { HistoricalDataItem } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-position-detail.interface'; export interface PortfolioChart { + hasError: boolean; isAllTimeHigh: boolean; isAllTimeLow: boolean; chart: HistoricalDataItem[]; diff --git a/package.json b/package.json index 3efea3b72..d54a466a2 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "cryptocurrencies": "7.0.0", "date-fns": "2.22.1", "envalid": "7.2.1", - "http-status-codes": "2.1.4", + "http-status-codes": "2.2.0", "ionicons": "5.5.1", "lodash": "4.17.21", "ngx-device-detector": "3.0.0", diff --git a/yarn.lock b/yarn.lock index fc787ab83..2ffd99626 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10032,10 +10032,10 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -http-status-codes@2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.1.4.tgz#453d99b4bd9424254c4f6a9a3a03715923052798" - integrity sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg== +http-status-codes@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.2.0.tgz#bb2efe63d941dfc2be18e15f703da525169622be" + integrity sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng== https-browserify@^1.0.0: version "1.0.0"