diff --git a/CHANGELOG.md b/CHANGELOG.md index c41dc64aa..8f0e15370 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added the logotype to the footer +- Added the data providers management to the admin control panel ### Changed diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.html b/apps/client/src/app/components/admin-settings/admin-settings.component.html index 4c4a6df1e..b3a63df7a 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.html +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -1,4 +1,39 @@
+
+
+

Data Providers

+ + +
+ +
+ +
+
+
+
+
+

Platforms

diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.ts b/apps/client/src/app/components/admin-settings/admin-settings.component.ts index 35e6d5c63..51fd81576 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.ts +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.ts @@ -1,10 +1,18 @@ +import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { User } from '@ghostfolio/common/interfaces'; + import { ChangeDetectionStrategy, + ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; -import { Subject } from 'rxjs'; +import { MatDialog } from '@angular/material/dialog'; +import { DeviceDetectorService } from 'ngx-device-detector'; +import { Subject, takeUntil } from 'rxjs'; + +import { GfGhostfolioPremiumApiDialogComponent } from './ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -12,12 +20,49 @@ import { Subject } from 'rxjs'; styleUrls: ['./admin-settings.component.scss'], templateUrl: './admin-settings.component.html' }) -export class AdminSettingsComponent implements OnInit, OnDestroy { +export class AdminSettingsComponent implements OnDestroy, OnInit { + public pricingUrl: string; + + private deviceType: string; private unsubscribeSubject = new Subject(); + private user: User; + + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private deviceService: DeviceDetectorService, + private matDialog: MatDialog, + private userService: UserService + ) {} + + public ngOnInit() { + this.deviceType = this.deviceService.getDeviceInfo().deviceType; - public constructor() {} + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; - public ngOnInit() {} + this.pricingUrl = + `https://ghostfol.io/${this.user.settings.language}/` + + $localize`:snake-case:pricing`; + + this.changeDetectorRef.markForCheck(); + } + }); + } + + public onSetGhostfolioApiKey() { + this.matDialog.open(GfGhostfolioPremiumApiDialogComponent, { + autoFocus: false, + data: { + deviceType: this.deviceType, + pricingUrl: this.pricingUrl + }, + height: this.deviceType === 'mobile' ? '97.5vh' : undefined, + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); + } public ngOnDestroy() { this.unsubscribeSubject.next(); diff --git a/apps/client/src/app/components/admin-settings/admin-settings.module.ts b/apps/client/src/app/components/admin-settings/admin-settings.module.ts index d7fe79f26..3a3e04a2d 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.module.ts +++ b/apps/client/src/app/components/admin-settings/admin-settings.module.ts @@ -1,8 +1,11 @@ import { GfAdminPlatformModule } from '@ghostfolio/client/components/admin-platform/admin-platform.module'; import { GfAdminTagModule } from '@ghostfolio/client/components/admin-tag/admin-tag.module'; +import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; 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 { AdminSettingsComponent } from './admin-settings.component'; @@ -13,6 +16,9 @@ import { AdminSettingsComponent } from './admin-settings.component'; CommonModule, GfAdminPlatformModule, GfAdminTagModule, + GfPremiumIndicatorComponent, + MatButtonModule, + MatCardModule, RouterModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA] diff --git a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts new file mode 100644 index 000000000..856ddc852 --- /dev/null +++ b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts @@ -0,0 +1,39 @@ +import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; + +import { CommonModule } from '@angular/common'; +import { Component, Inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogModule, + MatDialogRef +} from '@angular/material/dialog'; + +import { GfDialogFooterModule } from '../../dialog-footer/dialog-footer.module'; +import { GfDialogHeaderModule } from '../../dialog-header/dialog-header.module'; +import { GhostfolioPremiumApiDialogParams } from './interfaces/interfaces'; + +@Component({ + imports: [ + CommonModule, + GfDialogFooterModule, + GfDialogHeaderModule, + GfPremiumIndicatorComponent, + MatButtonModule, + MatDialogModule + ], + selector: 'gf-ghostfolio-premium-api-dialog', + standalone: true, + styleUrls: ['./ghostfolio-premium-api-dialog.scss'], + templateUrl: './ghostfolio-premium-api-dialog.html' +}) +export class GfGhostfolioPremiumApiDialogComponent { + public constructor( + @Inject(MAT_DIALOG_DATA) public data: GhostfolioPremiumApiDialogParams, + public dialogRef: MatDialogRef + ) {} + + public onCancel() { + this.dialogRef.close(); + } +} diff --git a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html new file mode 100644 index 000000000..25673075d --- /dev/null +++ b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html @@ -0,0 +1,42 @@ + + +
+

+ The official + Ghostfolio Premium + + + data provider for self-hosters, offering + 100’000+ tickers from over 50 exchanges, + is coming soon! +

+

+ Want to stay updated? Click below to get notified as soon as it’s available. +

+ +
+ + diff --git a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.scss b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.scss new file mode 100644 index 000000000..dc9093b45 --- /dev/null +++ b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.scss @@ -0,0 +1,2 @@ +:host { +} diff --git a/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/interfaces/interfaces.ts new file mode 100644 index 000000000..0c629599e --- /dev/null +++ b/apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/interfaces/interfaces.ts @@ -0,0 +1,4 @@ +export interface GhostfolioPremiumApiDialogParams { + deviceType: string; + pricingUrl: string; +} diff --git a/apps/client/src/app/pages/pricing/pricing-page.component.ts b/apps/client/src/app/pages/pricing/pricing-page.component.ts index 9eb0cf491..8bd0f1bd5 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.component.ts +++ b/apps/client/src/app/pages/pricing/pricing-page.component.ts @@ -33,6 +33,9 @@ export class PricingPageComponent implements OnDestroy, OnInit { public isLoggedIn: boolean; public price: number; public priceId: string; + public professionalDataProviderTooltipPremium = translate( + 'PROFESSIONAL_DATA_PROVIDER_TOOLTIP_PREMIUM' + ); public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; public routerLinkRegister = ['/' + $localize`:snake-case:register`]; public user: User; diff --git a/apps/client/src/app/pages/pricing/pricing-page.html b/apps/client/src/app/pages/pricing/pricing-page.html index 0c7238253..1caa4e8a0 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.html +++ b/apps/client/src/app/pages/pricing/pricing-page.html @@ -228,6 +228,13 @@
  • Professional Data Provider + + +
  • diff --git a/apps/client/src/styles.scss b/apps/client/src/styles.scss index 1f068da1b..b72583050 100644 --- a/apps/client/src/styles.scss +++ b/apps/client/src/styles.scss @@ -377,6 +377,10 @@ ngx-skeleton-loader { @include gf-table; } +.gf-text-wrap-balance { + text-wrap: balance; +} + .has-fab { padding-bottom: 3rem !important; } diff --git a/libs/ui/src/lib/i18n.ts b/libs/ui/src/lib/i18n.ts index 46a8cd0fa..c0f95d457 100644 --- a/libs/ui/src/lib/i18n.ts +++ b/libs/ui/src/lib/i18n.ts @@ -21,6 +21,7 @@ const locales = { MONTH: $localize`Month`, MONTHS: $localize`Months`, OTHER: $localize`Other`, + PROFESSIONAL_DATA_PROVIDER_TOOLTIP_PREMIUM: $localize`Get access to 100’000+ tickers from over 50 exchanges`, PRESET_ID: $localize`Preset`, RETIREMENT_PROVISION: $localize`Retirement Provision`, SATELLITE: $localize`Satellite`,