From cac73ac11103f513fe890849086c24c3dc9bcb80 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 16 Feb 2024 18:57:34 +0100 Subject: [PATCH] Feature/divide faq page in three sections (#3003) * Divide FAQ page in three sections * General * Cloud (SaaS) * Self-Hosting * Update changelog --- CHANGELOG.md | 4 + apps/api/src/assets/sitemap.xml | 8 + apps/client/src/app/app.component.ts | 2 +- .../pages/about/about-page-routing.module.ts | 1 - .../src/app/pages/about/about-page.module.ts | 2 +- .../app/pages/faq/faq-page-routing.module.ts | 21 ++ .../src/app/pages/faq/faq-page.component.ts | 64 ++-- apps/client/src/app/pages/faq/faq-page.html | 320 ++---------------- .../src/app/pages/faq/faq-page.module.ts | 5 +- apps/client/src/app/pages/faq/faq-page.scss | 13 +- .../faq-overview-page-routing.module.ts | 21 ++ .../overview/faq-overview-page.component.ts | 41 +++ .../pages/faq/overview/faq-overview-page.html | 172 ++++++++++ .../faq/overview/faq-overview-page.module.ts | 13 + .../pages/faq/overview/faq-overview-page.scss | 12 + .../faq/saas/saas-page-routing.module.ts | 21 ++ .../app/pages/faq/saas/saas-page.component.ts | 42 +++ .../src/app/pages/faq/saas/saas-page.html | 162 +++++++++ .../app/pages/faq/saas/saas-page.module.ts | 13 + .../src/app/pages/faq/saas/saas-page.scss | 12 + .../self-hosting-page-routing.module.ts | 21 ++ .../self-hosting-page.component.ts | 21 ++ .../faq/self-hosting/self-hosting-page.html | 56 +++ .../self-hosting/self-hosting-page.module.ts | 13 + .../faq/self-hosting/self-hosting-page.scss | 12 + 25 files changed, 744 insertions(+), 328 deletions(-) create mode 100644 apps/client/src/app/pages/faq/overview/faq-overview-page-routing.module.ts create mode 100644 apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts create mode 100644 apps/client/src/app/pages/faq/overview/faq-overview-page.html create mode 100644 apps/client/src/app/pages/faq/overview/faq-overview-page.module.ts create mode 100644 apps/client/src/app/pages/faq/overview/faq-overview-page.scss create mode 100644 apps/client/src/app/pages/faq/saas/saas-page-routing.module.ts create mode 100644 apps/client/src/app/pages/faq/saas/saas-page.component.ts create mode 100644 apps/client/src/app/pages/faq/saas/saas-page.html create mode 100644 apps/client/src/app/pages/faq/saas/saas-page.module.ts create mode 100644 apps/client/src/app/pages/faq/saas/saas-page.scss create mode 100644 apps/client/src/app/pages/faq/self-hosting/self-hosting-page-routing.module.ts create mode 100644 apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts create mode 100644 apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html create mode 100644 apps/client/src/app/pages/faq/self-hosting/self-hosting-page.module.ts create mode 100644 apps/client/src/app/pages/faq/self-hosting/self-hosting-page.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index cf26a7fb2..9446e3ca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a loading indicator to the investment timeline on the analysis page - Added support for the cryptocurrency _Jupiter_ (`JUP29210-USD`) +### Changed + +- Divided the content of the Frequently Asked Questions (FAQ) page into three sections: _General_, _Cloud (SaaS)_ and _Self-Hosting_ + ## 2.51.0 - 2024-02-12 ### Changed diff --git a/apps/api/src/assets/sitemap.xml b/apps/api/src/assets/sitemap.xml index 11a1822b3..3aeadc035 100644 --- a/apps/api/src/assets/sitemap.xml +++ b/apps/api/src/assets/sitemap.xml @@ -370,6 +370,14 @@ https://ghostfol.io/en/faq ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/en/saas + ${currentDate}T00:00:00+00:00 + + + https://ghostfol.io/en/self-hosting + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/en/features ${currentDate}T00:00:00+00:00 diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index 048741b19..450e014f8 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -111,6 +111,7 @@ export class AppComponent implements OnDestroy, OnInit { this.hasTabs = (this.currentRoute === this.routerLinkAbout[0].slice(1) || + this.currentRoute === this.routerLinkFaq[0].slice(1) || this.currentRoute === 'account' || this.currentRoute === 'admin' || this.currentRoute === 'home' || @@ -120,7 +121,6 @@ export class AppComponent implements OnDestroy, OnInit { this.showFooter = (this.currentRoute === 'blog' || - this.currentRoute === this.routerLinkFaq[0].slice(1) || this.currentRoute === this.routerLinkFeatures[0].slice(1) || this.currentRoute === this.routerLinkMarkets[0].slice(1) || this.currentRoute === 'open' || diff --git a/apps/client/src/app/pages/about/about-page-routing.module.ts b/apps/client/src/app/pages/about/about-page-routing.module.ts index 4b28945e9..ac02124ae 100644 --- a/apps/client/src/app/pages/about/about-page-routing.module.ts +++ b/apps/client/src/app/pages/about/about-page-routing.module.ts @@ -3,7 +3,6 @@ import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import * as path from 'path'; import { AboutPageComponent } from './about-page.component'; diff --git a/apps/client/src/app/pages/about/about-page.module.ts b/apps/client/src/app/pages/about/about-page.module.ts index bd2a1bc80..161faaee7 100644 --- a/apps/client/src/app/pages/about/about-page.module.ts +++ b/apps/client/src/app/pages/about/about-page.module.ts @@ -8,7 +8,7 @@ import { AboutPageComponent } from './about-page.component'; @NgModule({ declarations: [AboutPageComponent], - imports: [CommonModule, MatTabsModule, AboutPageRoutingModule, RouterModule], + imports: [AboutPageRoutingModule, CommonModule, MatTabsModule, RouterModule], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class AboutPageModule {} diff --git a/apps/client/src/app/pages/faq/faq-page-routing.module.ts b/apps/client/src/app/pages/faq/faq-page-routing.module.ts index 4b7888e0c..17c087834 100644 --- a/apps/client/src/app/pages/faq/faq-page-routing.module.ts +++ b/apps/client/src/app/pages/faq/faq-page-routing.module.ts @@ -8,6 +8,27 @@ import { FaqPageComponent } from './faq-page.component'; const routes: Routes = [ { canActivate: [AuthGuard], + children: [ + { + path: '', + loadChildren: () => + import('./overview/faq-overview-page.module').then( + (m) => m.FaqOverviewPageModule + ) + }, + { + path: 'saas', + loadChildren: () => + import('./saas/saas-page.module').then((m) => m.SaasPageModule) + }, + { + path: 'self-hosting', + loadChildren: () => + import('./self-hosting/self-hosting-page.module').then( + (m) => m.SelfHostingPageModule + ) + } + ], component: FaqPageComponent, path: '', title: $localize`Frequently Asked Questions (FAQ)` diff --git a/apps/client/src/app/pages/faq/faq-page.component.ts b/apps/client/src/app/pages/faq/faq-page.component.ts index e4aea3bd9..0bbe1c904 100644 --- a/apps/client/src/app/pages/faq/faq-page.component.ts +++ b/apps/client/src/app/pages/faq/faq-page.component.ts @@ -1,39 +1,57 @@ -import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { User } from '@ghostfolio/common/interfaces'; +import { DataService } from '@ghostfolio/client/services/data.service'; +import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; -import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; -import { Subject, takeUntil } from 'rxjs'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { DeviceDetectorService } from 'ngx-device-detector'; +import { Subject } from 'rxjs'; @Component({ - host: { class: 'page' }, + host: { class: 'page has-tabs' }, selector: 'gf-faq-page', styleUrls: ['./faq-page.scss'], templateUrl: './faq-page.html' }) -export class FaqPageComponent implements OnDestroy { - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkMarkets = ['/' + $localize`markets`]; - public routerLinkPricing = ['/' + $localize`pricing`]; - public routerLinkRegister = ['/' + $localize`register`]; - public user: User; +export class FaqPageComponent implements OnDestroy, OnInit { + public deviceType: string; + public hasPermissionForSubscription: boolean; + public tabs: TabConfiguration[] = []; private unsubscribeSubject = new Subject(); public constructor( - private changeDetectorRef: ChangeDetectorRef, - private userService: UserService - ) {} + private dataService: DataService, + private deviceService: DeviceDetectorService + ) { + const { globalPermissions } = this.dataService.fetchInfo(); + + this.hasPermissionForSubscription = hasPermission( + globalPermissions, + permissions.enableSubscription + ); + + this.tabs = [ + { + iconName: 'reader-outline', + label: $localize`General`, + path: ['/' + $localize`faq`] + }, + { + iconName: 'cloudy-outline', + label: $localize`Cloud` + ' (SaaS)', + path: ['/' + $localize`faq`, 'saas'], + showCondition: this.hasPermissionForSubscription + }, + { + iconName: 'server-outline', + label: $localize`Self-Hosting`, + path: ['/' + $localize`faq`, $localize`self-hosting`] + } + ]; + } public ngOnInit() { - this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((state) => { - if (state?.user) { - this.user = state.user; - - this.changeDetectorRef.markForCheck(); - } - }); + this.deviceType = this.deviceService.getDeviceInfo().deviceType; } public ngOnDestroy() { diff --git a/apps/client/src/app/pages/faq/faq-page.html b/apps/client/src/app/pages/faq/faq-page.html index d89d5cf60..839e8114f 100644 --- a/apps/client/src/app/pages/faq/faq-page.html +++ b/apps/client/src/app/pages/faq/faq-page.html @@ -1,291 +1,29 @@ -
-
-
-

- Frequently Asked Questions (FAQ) -

-

- Find quick answers to commonly asked questions about Ghostfolio in our - Frequently Asked Questions (FAQ) section. Discover what Ghostfolio is, - explore its features, and learn about our privacy practices. Get all the - information you need in one place. -

- - - What is Ghostfolio? - - - Ghostfolio is a lightweight, open source wealth management application - for individuals to keep track of their net worth. The software - empowers you to make solid, data-driven investment decisions. - - - - - What assets can I track with Ghostfolio? - - - With Ghostfolio, you can keep track of various assets like stocks, - ETFs, bonds, cryptocurrencies and commodities. - - - - - What else is included in Ghostfolio? - - Please find a feature overview to manage your wealth - here. - - - - - How do I start? - - - You can sign up via the “Get Started” button at the top of the page. You have multiple options to join - Ghostfolio: Create an account with a security token or - Google Sign. We will guide you to set up your portfolio. - - - - - Will you spam me with emails once I sign up? - - No, we do not even collect your email address, so you will not receive - any spam emails from us. - - - - - Can I use Ghostfolio anonymously? - - Yes, the authentication system via security token enables you to sign - in securely and anonymously to Ghostfolio. There is no need for an - e-mail address, phone number, or a username. - - - - - How can Ghostfolio be free? - This project is driven by the efforts of contributors from around the - world. The - source code is - fully available as open source software (OSS). Thanks to our generous - Ghostfolio Premium users and - sponsors we have - the ability to run a free, limited plan for novice - investors. - - - - Is it really free? - Yes, it is! Our - pricing page details - everything you get for free. - - - - Do you monetize or sell my financial data? - No, we value your privacy. We do not sell or share your financial - data with any third parties. - - - - What is your business model? - By offering - Ghostfolio Premium, a - subscription plan with a managed hosting service and enhanced - features, we fund our business while providing added value to our - users. - - - - What is Ghostfolio Premium? - Ghostfolio Premium is a fully - managed Ghostfolio cloud offering for ambitious investors. Revenue is - used to cover the costs of the hosting infrastructure and to fund - ongoing development. It is the Open Source code base with some extras - like the markets overview and - a professional data provider. - - - - Can I start with a trial version? - Yes, you can try - Ghostfolio Premium by signing - up for Ghostfolio and applying for a trial (see “My Ghostfolio”). It - is easy, free and there is no commitment. You can stop using it at any - time. - - - - How can I get a student discount for Ghostfolio - Premium? - - Request your student discount - here with - your university e-mail address. - - - - Does the Ghostfolio Premium subscription renew - automatically? - - No, Ghostfolio Premium does - not include auto-renewal. Upon expiration, you can choose whether to - start a new subscription. - - - - Which devices are supported? - - Ghostfolio works in every modern web browser on smartphones, tablets - and desktop computers. For Android users, there is a dedicated - Ghostfolio app available in the - Google Play Store. - - - - I cannot find my broker in the list of platforms. What can I - do? - - - Please send an e-mail with the web address of your broker to - hi@ghostfol.io and we are - happy to add it. - - - - - Ghostfolio sounds cool, how can I get involved? - - Any support for Ghostfolio is welcome. Be it with a - Ghostfolio Premium - subscription to finance the hosting infrastructure, a positive rating - in the - Google Play Store, a star on - GitHub, - feedback, bug reports, feature requests and of course contributions! - You can reach us via Ghostfolio - Slack - community, - @ghostfolio_, - hi@ghostfol.io - or - GitHub. - - - - Got any other questions? - - Please join the Ghostfolio - Slack community, post to - @ghostfolio_, send an e-mail to - hi@ghostfol.io - or start a discussion at - GitHub. - -
-
-
+ + + + + diff --git a/apps/client/src/app/pages/faq/faq-page.module.ts b/apps/client/src/app/pages/faq/faq-page.module.ts index b411437eb..026fe9e71 100644 --- a/apps/client/src/app/pages/faq/faq-page.module.ts +++ b/apps/client/src/app/pages/faq/faq-page.module.ts @@ -1,13 +1,14 @@ import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; -import { MatCardModule } from '@angular/material/card'; +import { MatTabsModule } from '@angular/material/tabs'; +import { RouterModule } from '@angular/router'; import { FaqPageRoutingModule } from './faq-page-routing.module'; import { FaqPageComponent } from './faq-page.component'; @NgModule({ declarations: [FaqPageComponent], - imports: [CommonModule, FaqPageRoutingModule, MatCardModule], + imports: [CommonModule, FaqPageRoutingModule, MatTabsModule, RouterModule], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class FaqPageModule {} diff --git a/apps/client/src/app/pages/faq/faq-page.scss b/apps/client/src/app/pages/faq/faq-page.scss index 75bda52c9..e87d9a05b 100644 --- a/apps/client/src/app/pages/faq/faq-page.scss +++ b/apps/client/src/app/pages/faq/faq-page.scss @@ -1,12 +1,7 @@ :host { - display: block; - - a { - color: rgba(var(--palette-primary-500), 1); - font-weight: 500; + color: rgb(var(--dark-primary-text)); +} - &:hover { - color: rgba(var(--palette-primary-300), 1); - } - } +:host-context(.is-dark-theme) { + color: rgb(var(--light-primary-text)); } diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page-routing.module.ts b/apps/client/src/app/pages/faq/overview/faq-overview-page-routing.module.ts new file mode 100644 index 000000000..78a466e70 --- /dev/null +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page-routing.module.ts @@ -0,0 +1,21 @@ +import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { FaqOverviewPageComponent } from './faq-overview-page.component'; + +const routes: Routes = [ + { + canActivate: [AuthGuard], + component: FaqOverviewPageComponent, + path: '', + title: $localize`Frequently Asked Questions (FAQ)` + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class FaqOverviewPageRoutingModule {} diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts b/apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts new file mode 100644 index 000000000..02c9389c4 --- /dev/null +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts @@ -0,0 +1,41 @@ +import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { User } from '@ghostfolio/common/interfaces'; + +import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + host: { class: 'page' }, + selector: 'gf-faq-overview-page', + styleUrls: ['./faq-overview-page.scss'], + templateUrl: './faq-overview-page.html' +}) +export class FaqOverviewPageComponent implements OnDestroy { + public routerLinkFeatures = ['/' + $localize`features`]; + public routerLinkPricing = ['/' + $localize`pricing`]; + public user: User; + + private unsubscribeSubject = new Subject(); + + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private userService: UserService + ) {} + + public ngOnInit() { + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; + + this.changeDetectorRef.markForCheck(); + } + }); + } + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } +} diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page.html b/apps/client/src/app/pages/faq/overview/faq-overview-page.html new file mode 100644 index 000000000..5827aac6c --- /dev/null +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page.html @@ -0,0 +1,172 @@ +
+
+
+

+ Frequently Asked Questions (FAQ) +

+

+ Find quick answers to commonly asked questions about Ghostfolio in our + Frequently Asked Questions (FAQ) section. Discover what Ghostfolio is, + explore its features, and learn about our privacy practices. Get all the + information you need in one place. +

+ + + What is Ghostfolio? + + + Ghostfolio is a lightweight, open source wealth management application + for individuals to keep track of their net worth. The software + empowers you to make solid, data-driven investment decisions. + + + + + What assets can I track with Ghostfolio? + + + With Ghostfolio, you can keep track of various assets like stocks, + ETFs, bonds, cryptocurrencies and commodities. + + + + + What else is included in Ghostfolio? + + Please find a feature overview to manage your wealth + here. + + + + + Can I use Ghostfolio anonymously? + + Yes, the authentication system via security token enables you to sign + in securely and anonymously to Ghostfolio. There is no need for an + e-mail address, phone number, or a username. + + + + + How can Ghostfolio be free? + This project is driven by the efforts of contributors from around the + world. The + source code is + fully available as open source software (OSS). Thanks to our generous + Ghostfolio Premium users and + sponsors we have + the ability to run a free, limited plan for novice + investors. + + + + Do you monetize or sell my financial data? + No, we value your privacy. We do not sell or share your financial + data with any third parties. + + + + What is your business model? + By offering + Ghostfolio Premium, a + subscription plan with a managed hosting service and enhanced + features, we fund our business while providing added value to our + users. + + + + Ghostfolio sounds cool, how can I get involved? + + Any support for Ghostfolio is welcome. Be it with a + Ghostfolio Premium + subscription to finance the hosting infrastructure, a positive rating + in the + Google Play Store, a star on + GitHub, + feedback, bug reports, feature requests and of course contributions! + You can reach us via Ghostfolio + Slack + community, + @ghostfolio_, + hi@ghostfol.io + or + GitHub. + + + + Got any other questions? + + Please join the Ghostfolio + Slack community, post to + @ghostfolio_, send an e-mail to + hi@ghostfol.io + or start a discussion at + GitHub. + +
+
+
diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page.module.ts b/apps/client/src/app/pages/faq/overview/faq-overview-page.module.ts new file mode 100644 index 000000000..1f26d623a --- /dev/null +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page.module.ts @@ -0,0 +1,13 @@ +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; + +import { FaqOverviewPageRoutingModule } from './faq-overview-page-routing.module'; +import { FaqOverviewPageComponent } from './faq-overview-page.component'; + +@NgModule({ + declarations: [FaqOverviewPageComponent], + imports: [CommonModule, FaqOverviewPageRoutingModule, MatCardModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class FaqOverviewPageModule {} diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page.scss b/apps/client/src/app/pages/faq/overview/faq-overview-page.scss new file mode 100644 index 000000000..75bda52c9 --- /dev/null +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page.scss @@ -0,0 +1,12 @@ +:host { + display: block; + + a { + color: rgba(var(--palette-primary-500), 1); + font-weight: 500; + + &:hover { + color: rgba(var(--palette-primary-300), 1); + } + } +} diff --git a/apps/client/src/app/pages/faq/saas/saas-page-routing.module.ts b/apps/client/src/app/pages/faq/saas/saas-page-routing.module.ts new file mode 100644 index 000000000..4c4c3d62c --- /dev/null +++ b/apps/client/src/app/pages/faq/saas/saas-page-routing.module.ts @@ -0,0 +1,21 @@ +import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { SaasPageComponent } from './saas-page.component'; + +const routes: Routes = [ + { + canActivate: [AuthGuard], + component: SaasPageComponent, + path: '', + title: $localize`Cloud` + ' (SaaS) – ' + $localize`FAQ` + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class SaasPageRoutingModule {} diff --git a/apps/client/src/app/pages/faq/saas/saas-page.component.ts b/apps/client/src/app/pages/faq/saas/saas-page.component.ts new file mode 100644 index 000000000..b06a7dbd1 --- /dev/null +++ b/apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -0,0 +1,42 @@ +import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { User } from '@ghostfolio/common/interfaces'; + +import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + host: { class: 'page' }, + selector: 'gf-saas-page', + styleUrls: ['./saas-page.scss'], + templateUrl: './saas-page.html' +}) +export class SaasPageComponent implements OnDestroy { + public routerLinkMarkets = ['/' + $localize`markets`]; + public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkRegister = ['/' + $localize`register`]; + public user: User; + + private unsubscribeSubject = new Subject(); + + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private userService: UserService + ) {} + + public ngOnInit() { + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; + + this.changeDetectorRef.markForCheck(); + } + }); + } + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } +} diff --git a/apps/client/src/app/pages/faq/saas/saas-page.html b/apps/client/src/app/pages/faq/saas/saas-page.html new file mode 100644 index 000000000..f834e1f6f --- /dev/null +++ b/apps/client/src/app/pages/faq/saas/saas-page.html @@ -0,0 +1,162 @@ +
+
+
+

+ Frequently Asked Questions (FAQ) +

+

+ Find quick answers to commonly asked questions about the fully managed + Ghostfolio cloud offering in our Frequently Asked Questions (FAQ) + section. +

+ + + How do I start? + + + You can sign up via the “Get Started” button at the top of the page. You have multiple options to join + Ghostfolio: Create an account with a security token or + Google Sign. We will guide you to set up your portfolio. + + + + + Will you spam me with emails once I sign up? + + No, we do not even collect your email address, so you will not receive + any spam emails from us. + + + + + Is it really free? + Yes, it is! Our + pricing page details + everything you get for free. + + + + What is Ghostfolio Premium? + Ghostfolio Premium is a fully + managed Ghostfolio cloud offering for ambitious investors. Revenue is + used to cover the costs of the hosting infrastructure and to fund + ongoing development. It is the Open Source code base with some extras + like the markets overview and + a professional data provider. + + + + Can I start with a trial version? + Yes, you can try + Ghostfolio Premium by signing + up for Ghostfolio and applying for a trial (see “My Ghostfolio”). It + is easy, free and there is no commitment. You can stop using it at any + time. + + + + How can I get a student discount for Ghostfolio + Premium? + + Request your student discount + here with + your university e-mail address. + + + + Does the Ghostfolio Premium subscription renew + automatically? + + No, Ghostfolio Premium does + not include auto-renewal. Upon expiration, you can choose whether to + start a new subscription. + + + + I cannot find my broker in the list of platforms. What can I + do? + + + Please send an e-mail with the web address of your broker to + hi@ghostfol.io and we are + happy to add it. + + + + + Which devices are supported? + + Ghostfolio works in every modern web browser on smartphones, tablets + and desktop computers. For Android users of the managed cloud + offering, there is a dedicated Ghostfolio app available in the + Google Play Store. + + + + Got any other questions? + + Please join the Ghostfolio + Slack community, post to + @ghostfolio_, send an e-mail to + hi@ghostfol.io + or start a discussion at + GitHub. + +
+
+
diff --git a/apps/client/src/app/pages/faq/saas/saas-page.module.ts b/apps/client/src/app/pages/faq/saas/saas-page.module.ts new file mode 100644 index 000000000..4ddcf9d24 --- /dev/null +++ b/apps/client/src/app/pages/faq/saas/saas-page.module.ts @@ -0,0 +1,13 @@ +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; + +import { SaasPageRoutingModule } from './saas-page-routing.module'; +import { SaasPageComponent } from './saas-page.component'; + +@NgModule({ + declarations: [SaasPageComponent], + imports: [CommonModule, MatCardModule, SaasPageRoutingModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class SaasPageModule {} diff --git a/apps/client/src/app/pages/faq/saas/saas-page.scss b/apps/client/src/app/pages/faq/saas/saas-page.scss new file mode 100644 index 000000000..75bda52c9 --- /dev/null +++ b/apps/client/src/app/pages/faq/saas/saas-page.scss @@ -0,0 +1,12 @@ +:host { + display: block; + + a { + color: rgba(var(--palette-primary-500), 1); + font-weight: 500; + + &:hover { + color: rgba(var(--palette-primary-300), 1); + } + } +} diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page-routing.module.ts b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page-routing.module.ts new file mode 100644 index 000000000..3879f7dbb --- /dev/null +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page-routing.module.ts @@ -0,0 +1,21 @@ +import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { SelfHostingPageComponent } from './self-hosting-page.component'; + +const routes: Routes = [ + { + canActivate: [AuthGuard], + component: SelfHostingPageComponent, + path: '', + title: $localize`Self-Hosting` + ' – ' + $localize`FAQ` + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class SelfHostingPageRoutingModule {} diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts new file mode 100644 index 000000000..b454020e1 --- /dev/null +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts @@ -0,0 +1,21 @@ +import { Component, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Component({ + host: { class: 'page' }, + selector: 'gf-self-hosting-page', + styleUrls: ['./self-hosting-page.scss'], + templateUrl: './self-hosting-page.html' +}) +export class SelfHostingPageComponent implements OnDestroy { + private unsubscribeSubject = new Subject(); + + public constructor() {} + + public ngOnInit() {} + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } +} diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html new file mode 100644 index 000000000..28a4d9b27 --- /dev/null +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html @@ -0,0 +1,56 @@ +
+
+
+

+ Frequently Asked Questions (FAQ) +

+

+ Find quick answers to commonly asked questions about self-hosting + Ghostfolio in our Frequently Asked Questions (FAQ) section. +

+ + + How do I start? + + + If you prefer to run Ghostfolio on your own infrastructure, please + find the source code and further instructions on + GitHub. + + + + + Which devices are supported? + + Ghostfolio works in every modern web browser on smartphones, tablets + and desktop computers. + + + + Got any other questions? + + Please join the Ghostfolio + Slack community, post to + @ghostfolio_ + or start a discussion at + GitHub. + +
+
+
diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.module.ts b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.module.ts new file mode 100644 index 000000000..65f9969a3 --- /dev/null +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.module.ts @@ -0,0 +1,13 @@ +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; + +import { SelfHostingPageRoutingModule } from './self-hosting-page-routing.module'; +import { SelfHostingPageComponent } from './self-hosting-page.component'; + +@NgModule({ + declarations: [SelfHostingPageComponent], + imports: [CommonModule, MatCardModule, SelfHostingPageRoutingModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class SelfHostingPageModule {} diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.scss b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.scss new file mode 100644 index 000000000..75bda52c9 --- /dev/null +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.scss @@ -0,0 +1,12 @@ +:host { + display: block; + + a { + color: rgba(var(--palette-primary-500), 1); + font-weight: 500; + + &:hover { + color: rgba(var(--palette-primary-300), 1); + } + } +}