From 7c1312477dcf5ca89e248f9415a060c2d3cb8f70 Mon Sep 17 00:00:00 2001
From: Thomas <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 20 May 2021 21:41:53 +0200
Subject: [PATCH] Start with implementation
---
apps/client/src/app/app-routing.module.ts | 5 +
.../pages/account/account-page.component.ts | 15 +++
.../src/app/pages/account/account-page.html | 16 ++-
.../src/app/pages/home/home-page.component.ts | 10 +-
.../src/app/pages/home/home-page.module.ts | 2 -
.../app/pages/zen/zen-page-routing.module.ts | 15 +++
.../src/app/pages/zen/zen-page.component.ts | 104 ++++++++++++++++++
apps/client/src/app/pages/zen/zen-page.html | 25 +++++
.../src/app/pages/zen/zen-page.module.ts | 23 ++++
apps/client/src/app/pages/zen/zen-page.scss | 39 +++++++
.../lib/interfaces/user-settings.interface.ts | 1 +
11 files changed, 247 insertions(+), 8 deletions(-)
create mode 100644 apps/client/src/app/pages/zen/zen-page-routing.module.ts
create mode 100644 apps/client/src/app/pages/zen/zen-page.component.ts
create mode 100644 apps/client/src/app/pages/zen/zen-page.html
create mode 100644 apps/client/src/app/pages/zen/zen-page.module.ts
create mode 100644 apps/client/src/app/pages/zen/zen-page.scss
diff --git a/apps/client/src/app/app-routing.module.ts b/apps/client/src/app/app-routing.module.ts
index 8c81bd1bd..e26e0dc9f 100644
--- a/apps/client/src/app/app-routing.module.ts
+++ b/apps/client/src/app/app-routing.module.ts
@@ -78,6 +78,11 @@ const routes: Routes = [
(m) => m.TransactionsPageModule
)
},
+ {
+ path: 'zen',
+ loadChildren: () =>
+ import('./pages/zen/zen-page.module').then((m) => m.ZenPageModule)
+ },
{
// wildcard, if requested url doesn't match any paths for routes defined
// earlier
diff --git a/apps/client/src/app/pages/account/account-page.component.ts b/apps/client/src/app/pages/account/account-page.component.ts
index 957b4007c..a710ca2a5 100644
--- a/apps/client/src/app/pages/account/account-page.component.ts
+++ b/apps/client/src/app/pages/account/account-page.component.ts
@@ -51,6 +51,8 @@ export class AccountPageComponent implements OnDestroy, OnInit {
this.dataService.fetchUser().subscribe((user) => {
this.user = user;
+ this.user.settings.mode = 'ZEN';
+
this.hasPermissionToUpdateUserSettings = hasPermission(
this.user.permissions,
permissions.updateUserSettings
@@ -81,6 +83,19 @@ export class AccountPageComponent implements OnDestroy, OnInit {
});
}
+ public onChangeMode({ value: mode }: { value: Currency }) {
+ /*this.dataService
+ .putUserSettings({ currency })
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe(() => {
+ this.dataService.fetchUser().subscribe((user) => {
+ this.user = user;
+
+ this.cd.markForCheck();
+ });
+ });*/
+ }
+
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
diff --git a/apps/client/src/app/pages/account/account-page.html b/apps/client/src/app/pages/account/account-page.html
index e5bad92db..e3b6f830a 100644
--- a/apps/client/src/app/pages/account/account-page.html
+++ b/apps/client/src/app/pages/account/account-page.html
@@ -30,7 +30,7 @@
diff --git a/apps/client/src/app/pages/home/home-page.component.ts b/apps/client/src/app/pages/home/home-page.component.ts
index ef2932096..515d1e63b 100644
--- a/apps/client/src/app/pages/home/home-page.component.ts
+++ b/apps/client/src/app/pages/home/home-page.component.ts
@@ -132,6 +132,11 @@ export class HomePageComponent implements OnDestroy, OnInit {
this.update();
}
+ public ngOnDestroy() {
+ this.unsubscribeSubject.next();
+ this.unsubscribeSubject.complete();
+ }
+
private openDialog(): void {
const dialogRef = this.dialog.open(PerformanceChartDialog, {
autoFocus: false,
@@ -195,9 +200,4 @@ export class HomePageComponent implements OnDestroy, OnInit {
this.cd.markForCheck();
}
-
- public ngOnDestroy() {
- this.unsubscribeSubject.next();
- this.unsubscribeSubject.complete();
- }
}
diff --git a/apps/client/src/app/pages/home/home-page.module.ts b/apps/client/src/app/pages/home/home-page.module.ts
index 9f3c495e2..3306228dd 100644
--- a/apps/client/src/app/pages/home/home-page.module.ts
+++ b/apps/client/src/app/pages/home/home-page.module.ts
@@ -1,6 +1,5 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
-import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { RouterModule } from '@angular/router';
import { GfLineChartModule } from '@ghostfolio/client/components/line-chart/line-chart.module';
@@ -27,7 +26,6 @@ import { HomePageComponent } from './home-page.component';
GfPositionsModule,
GfToggleModule,
HomePageRoutingModule,
- MatButtonModule,
MatCardModule,
RouterModule
],
diff --git a/apps/client/src/app/pages/zen/zen-page-routing.module.ts b/apps/client/src/app/pages/zen/zen-page-routing.module.ts
new file mode 100644
index 000000000..59d4cb062
--- /dev/null
+++ b/apps/client/src/app/pages/zen/zen-page-routing.module.ts
@@ -0,0 +1,15 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
+
+import { ZenPageComponent } from './zen-page.component';
+
+const routes: Routes = [
+ { path: '', component: ZenPageComponent, canActivate: [AuthGuard] }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class ZenPageRoutingModule {}
diff --git a/apps/client/src/app/pages/zen/zen-page.component.ts b/apps/client/src/app/pages/zen/zen-page.component.ts
new file mode 100644
index 000000000..1fc5e65ee
--- /dev/null
+++ b/apps/client/src/app/pages/zen/zen-page.component.ts
@@ -0,0 +1,104 @@
+import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { LineChartItem } from '@ghostfolio/client/components/line-chart/interfaces/line-chart.interface';
+import { DataService } from '@ghostfolio/client/services/data.service';
+import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
+import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
+import { PortfolioPerformance, User } from '@ghostfolio/common/interfaces';
+import { hasPermission, permissions } from '@ghostfolio/common/permissions';
+import { DateRange } from '@ghostfolio/common/types';
+import { DeviceDetectorService } from 'ngx-device-detector';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+
+@Component({
+ selector: 'gf-zen-page',
+ templateUrl: './zen-page.html',
+ styleUrls: ['./zen-page.scss']
+})
+export class ZenPageComponent implements OnDestroy, OnInit {
+ public dateRange: DateRange = 'max';
+ public deviceType: string;
+ public hasImpersonationId: boolean;
+ public hasPermissionToReadForeignPortfolio: boolean;
+ public historicalDataItems: LineChartItem[];
+ public isLoadingPerformance = true;
+ public performance: PortfolioPerformance;
+ public user: User;
+
+ private unsubscribeSubject = new Subject();
+
+ /**
+ * @constructor
+ */
+ public constructor(
+ private cd: ChangeDetectorRef,
+ private dataService: DataService,
+ private deviceService: DeviceDetectorService,
+ private impersonationStorageService: ImpersonationStorageService,
+ private tokenStorageService: TokenStorageService
+ ) {
+ this.tokenStorageService
+ .onChangeHasToken()
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe(() => {
+ this.dataService.fetchUser().subscribe((user) => {
+ this.user = user;
+
+ this.hasPermissionToReadForeignPortfolio = hasPermission(
+ user.permissions,
+ permissions.readForeignPortfolio
+ );
+
+ this.cd.markForCheck();
+ });
+ });
+ }
+
+ /**
+ * Initializes the controller
+ */
+ public ngOnInit() {
+ this.deviceType = this.deviceService.getDeviceInfo().deviceType;
+
+ this.impersonationStorageService
+ .onChangeHasImpersonation()
+ .subscribe((aId) => {
+ this.hasImpersonationId = !!aId;
+ });
+
+ this.update();
+ }
+
+ public ngOnDestroy() {
+ this.unsubscribeSubject.next();
+ this.unsubscribeSubject.complete();
+ }
+
+ private update() {
+ this.isLoadingPerformance = true;
+
+ this.dataService
+ .fetchChart({ range: this.dateRange })
+ .subscribe((chartData) => {
+ this.historicalDataItems = chartData.map((chartDataItem) => {
+ return {
+ date: chartDataItem.date,
+ value: chartDataItem.value
+ };
+ });
+
+ this.cd.markForCheck();
+ });
+
+ this.dataService
+ .fetchPortfolioPerformance({ range: this.dateRange })
+ .subscribe((response) => {
+ this.performance = response;
+ this.isLoadingPerformance = false;
+
+ this.cd.markForCheck();
+ });
+
+ this.cd.markForCheck();
+ }
+}
diff --git a/apps/client/src/app/pages/zen/zen-page.html b/apps/client/src/app/pages/zen/zen-page.html
new file mode 100644
index 000000000..a3e16b732
--- /dev/null
+++ b/apps/client/src/app/pages/zen/zen-page.html
@@ -0,0 +1,25 @@
+
diff --git a/apps/client/src/app/pages/zen/zen-page.module.ts b/apps/client/src/app/pages/zen/zen-page.module.ts
new file mode 100644
index 000000000..117f69136
--- /dev/null
+++ b/apps/client/src/app/pages/zen/zen-page.module.ts
@@ -0,0 +1,23 @@
+import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { MatCardModule } from '@angular/material/card';
+import { GfLineChartModule } from '@ghostfolio/client/components/line-chart/line-chart.module';
+import { GfPortfolioPerformanceSummaryModule } from '@ghostfolio/client/components/portfolio-performance-summary/portfolio-performance-summary.module';
+
+import { ZenPageRoutingModule } from './zen-page-routing.module';
+import { ZenPageComponent } from './zen-page.component';
+
+@NgModule({
+ declarations: [ZenPageComponent],
+ exports: [],
+ imports: [
+ CommonModule,
+ GfLineChartModule,
+ GfPortfolioPerformanceSummaryModule,
+ MatCardModule,
+ ZenPageRoutingModule
+ ],
+ providers: [],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+})
+export class ZenPageModule {}
diff --git a/apps/client/src/app/pages/zen/zen-page.scss b/apps/client/src/app/pages/zen/zen-page.scss
new file mode 100644
index 000000000..d3be6211f
--- /dev/null
+++ b/apps/client/src/app/pages/zen/zen-page.scss
@@ -0,0 +1,39 @@
+:host {
+ color: rgb(var(--dark-primary-text));
+ display: block;
+
+ .chart-container {
+ aspect-ratio: 16 / 9;
+ cursor: pointer;
+ margin-top: -1rem;
+ max-height: 50vh;
+
+ // Fallback for aspect-ratio (using padding hack)
+ @supports not (aspect-ratio: 16 / 9) {
+ &::before {
+ float: left;
+ padding-top: 56.25%;
+ content: '';
+ }
+
+ &::after {
+ display: block;
+ content: '';
+ clear: both;
+ }
+ }
+
+ gf-line-chart {
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: -1;
+ }
+ }
+}
+
+:host-context(.is-dark-theme) {
+ color: rgb(var(--light-primary-text));
+}
diff --git a/libs/common/src/lib/interfaces/user-settings.interface.ts b/libs/common/src/lib/interfaces/user-settings.interface.ts
index 182845b71..e025e0832 100644
--- a/libs/common/src/lib/interfaces/user-settings.interface.ts
+++ b/libs/common/src/lib/interfaces/user-settings.interface.ts
@@ -3,4 +3,5 @@ import { Currency } from '@prisma/client';
export interface UserSettings {
baseCurrency: Currency;
locale: string;
+ mode: 'DEFAULT' | 'ZEN';
}