Browse Source

Bugfix/fix page navigation (#4711)

* Fix page navigation and use paths references
pull/4732/head
Kenrick Tandrian 1 month ago
committed by GitHub
parent
commit
4bffb3107d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 44
      apps/client/src/app/app-routing.module.ts
  2. 33
      apps/client/src/app/app.component.ts
  3. 3
      apps/client/src/app/components/access-table/access-table.component.ts
  4. 5
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
  5. 5
      apps/client/src/app/components/admin-settings/admin-settings.component.ts
  6. 23
      apps/client/src/app/components/header/header.component.ts
  7. 5
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
  8. 4
      apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts
  9. 3
      apps/client/src/app/components/user-account-membership/user-account-membership.component.ts
  10. 37
      apps/client/src/app/core/auth.guard.ts
  11. 5
      apps/client/src/app/core/http-response.interceptor.ts
  12. 12
      apps/client/src/app/core/paths.ts
  13. 6
      apps/client/src/app/pages/about/about-page-routing.module.ts
  14. 13
      apps/client/src/app/pages/about/about-page.component.ts
  15. 5
      apps/client/src/app/pages/about/overview/about-overview-page.component.ts
  16. 9
      apps/client/src/app/pages/admin/admin-page-routing.module.ts
  17. 11
      apps/client/src/app/pages/admin/admin-page.component.ts
  18. 6
      apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts
  19. 6
      apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts
  20. 4
      apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts
  21. 4
      apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.component.ts
  22. 6
      apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts
  23. 5
      apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts
  24. 6
      apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts
  25. 6
      apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts
  26. 4
      apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts
  27. 7
      apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts
  28. 13
      apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts
  29. 4
      apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts
  30. 5
      apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts
  31. 6
      apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts
  32. 4
      apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts
  33. 5
      apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts
  34. 5
      apps/client/src/app/pages/faq/faq-page-routing.module.ts
  35. 7
      apps/client/src/app/pages/faq/faq-page.component.ts
  36. 7
      apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts
  37. 9
      apps/client/src/app/pages/faq/saas/saas-page.component.ts
  38. 6
      apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts
  39. 5
      apps/client/src/app/pages/features/features-page.component.ts
  40. 14
      apps/client/src/app/pages/home/home-page-routing.module.ts
  41. 11
      apps/client/src/app/pages/home/home-page.component.ts
  42. 5
      apps/client/src/app/pages/landing/landing-page.component.ts
  43. 9
      apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
  44. 11
      apps/client/src/app/pages/portfolio/portfolio-page.component.ts
  45. 5
      apps/client/src/app/pages/pricing/pricing-page.component.ts
  46. 5
      apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.component.ts
  47. 5
      apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts
  48. 19
      apps/client/src/app/pages/resources/overview/resources-overview.component.ts
  49. 3
      apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page-routing.module.ts
  50. 7
      apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts
  51. 9
      apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts
  52. 9
      apps/client/src/app/pages/resources/resources-page-routing.module.ts
  53. 8
      apps/client/src/app/pages/resources/resources-page.component.ts
  54. 5
      apps/client/src/app/pages/user-account/user-account-page-routing.module.ts
  55. 7
      apps/client/src/app/pages/user-account/user-account-page.component.ts
  56. 3
      apps/client/src/app/pages/zen/zen-page-routing.module.ts
  57. 5
      apps/client/src/app/pages/zen/zen-page.component.ts
  58. 714
      apps/client/src/locales/messages.ca.xlf
  59. 892
      apps/client/src/locales/messages.de.xlf
  60. 892
      apps/client/src/locales/messages.es.xlf
  61. 892
      apps/client/src/locales/messages.fr.xlf
  62. 892
      apps/client/src/locales/messages.it.xlf
  63. 892
      apps/client/src/locales/messages.nl.xlf
  64. 712
      apps/client/src/locales/messages.pl.xlf
  65. 892
      apps/client/src/locales/messages.pt.xlf
  66. 712
      apps/client/src/locales/messages.tr.xlf
  67. 714
      apps/client/src/locales/messages.uk.xlf
  68. 706
      apps/client/src/locales/messages.xlf
  69. 716
      apps/client/src/locales/messages.zh.xlf
  70. 53
      libs/common/src/lib/paths.ts
  71. 4
      libs/ui/src/lib/membership-card/membership-card.component.ts
  72. 4
      libs/ui/src/lib/premium-indicator/premium-indicator.component.ts

44
apps/client/src/app/app-routing.module.ts

@ -1,6 +1,6 @@
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/client/core/paths';
import { PageTitleStrategy } from '@ghostfolio/client/services/page-title.strategy';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes, TitleStrategy } from '@angular/router';
@ -14,21 +14,21 @@ const routes: Routes = [
import('./pages/about/about-page.module').then((m) => m.AboutPageModule)
},
{
path: 'account',
path: paths.account,
loadChildren: () =>
import('./pages/user-account/user-account-page.module').then(
(m) => m.UserAccountPageModule
)
},
{
path: 'accounts',
path: paths.accounts,
loadChildren: () =>
import('./pages/accounts/accounts-page.module').then(
(m) => m.AccountsPageModule
)
},
{
path: 'admin',
path: paths.admin,
loadChildren: () =>
import('./pages/admin/admin-page.module').then((m) => m.AdminPageModule)
},
@ -38,16 +38,16 @@ const routes: Routes = [
import('./pages/api/api-page.component').then(
(c) => c.GfApiPageComponent
),
path: 'api',
path: paths.api,
title: 'Ghostfolio API'
},
{
path: 'auth',
path: paths.auth,
loadChildren: () =>
import('./pages/auth/auth-page.module').then((m) => m.AuthPageModule)
},
{
path: 'blog',
path: paths.blog,
loadChildren: () =>
import('./pages/blog/blog-page.module').then((m) => m.BlogPageModule)
},
@ -57,7 +57,7 @@ const routes: Routes = [
import('./pages/demo/demo-page.component').then(
(c) => c.GfDemoPageComponent
),
path: 'demo'
path: paths.demo
},
{
path: paths.faq,
@ -74,7 +74,7 @@ const routes: Routes = [
title: $localize`Features`
},
{
path: 'home',
path: paths.home,
loadChildren: () =>
import('./pages/home/home-page.module').then((m) => m.HomePageModule)
},
@ -84,7 +84,7 @@ const routes: Routes = [
import('./pages/i18n/i18n-page.component').then(
(c) => c.GfI18nPageComponent
),
path: 'i18n',
path: paths.i18n,
title: $localize`Internationalization`
},
{
@ -95,19 +95,12 @@ const routes: Routes = [
)
},
{
path: 'open',
path: paths.open,
loadChildren: () =>
import('./pages/open/open-page.module').then((m) => m.OpenPageModule)
},
{
path: 'p',
loadChildren: () =>
import('./pages/public/public-page.module').then(
(m) => m.PublicPageModule
)
},
{
path: 'portfolio',
path: paths.portfolio,
loadChildren: () =>
import('./pages/portfolio/portfolio-page.module').then(
(m) => m.PortfolioPageModule
@ -120,6 +113,13 @@ const routes: Routes = [
(m) => m.PricingPageModule
)
},
{
path: paths.public,
loadChildren: () =>
import('./pages/public/public-page.module').then(
(m) => m.PublicPageModule
)
},
{
path: paths.register,
loadChildren: () =>
@ -135,7 +135,7 @@ const routes: Routes = [
)
},
{
path: 'start',
path: paths.start,
loadChildren: () =>
import('./pages/landing/landing-page.module').then(
(m) => m.LandingPageModule
@ -146,11 +146,11 @@ const routes: Routes = [
import('./pages/webauthn/webauthn-page.component').then(
(c) => c.GfWebauthnPageComponent
),
path: 'webauthn',
path: paths.webauthn,
title: $localize`Sign in`
},
{
path: 'zen',
path: paths.zen,
loadChildren: () =>
import('./pages/zen/zen-page.module').then((m) => m.ZenPageModule)
},

33
apps/client/src/app/app.component.ts

@ -2,6 +2,7 @@ import { GfHoldingDetailDialogComponent } from '@ghostfolio/client/components/ho
import { HoldingDetailDialogParams } from '@ghostfolio/client/components/holding-detail-dialog/interfaces/interfaces';
import { getCssVariable } from '@ghostfolio/common/helper';
import { InfoItem, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { ColorScheme } from '@ghostfolio/common/types';
@ -62,29 +63,23 @@ export class AppComponent implements OnDestroy, OnInit {
public hasTabs = false;
public info: InfoItem;
public pageTitle: string;
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkAboutChangelog = [
'/' + $localize`:snake-case:about`,
'changelog'
];
public routerLinkAboutLicense = [
'/' + $localize`:snake-case:about`,
$localize`:snake-case:license`
];
public routerLinkAbout = ['/' + paths.about];
public routerLinkAboutChangelog = ['/' + paths.about, paths.changelog];
public routerLinkAboutLicense = ['/' + paths.about, paths.license];
public routerLinkAboutPrivacyPolicy = [
'/' + $localize`:snake-case:about`,
$localize`:snake-case:privacy-policy`
'/' + paths.about,
paths.privacyPolicy
];
public routerLinkAboutTermsOfService = [
'/' + $localize`:snake-case:about`,
$localize`:snake-case:terms-of-service`
'/' + paths.about,
paths.termsOfService
];
public routerLinkFaq = ['/' + $localize`:snake-case:faq`];
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkMarkets = ['/' + $localize`:snake-case:markets`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkRegister = ['/' + $localize`:snake-case:register`];
public routerLinkResources = ['/' + $localize`:snake-case:resources`];
public routerLinkFaq = ['/' + paths.faq];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkMarkets = ['/' + paths.markets];
public routerLinkPricing = ['/' + paths.pricing];
public routerLinkRegister = ['/' + paths.register];
public routerLinkResources = ['/' + paths.resources];
public showFooter = false;
public user: User;

3
apps/client/src/app/components/access-table/access-table.component.ts

@ -2,6 +2,7 @@ import { ConfirmationDialogType } from '@ghostfolio/client/core/notification/con
import { NotificationService } from '@ghostfolio/client/core/notification/notification.service';
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
import { Access, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { Clipboard } from '@angular/cdk/clipboard';
import {
@ -55,7 +56,7 @@ export class AccessTableComponent implements OnChanges {
public getPublicUrl(aId: string): string {
const languageCode = this.user?.settings?.language ?? DEFAULT_LANGUAGE_CODE;
return `${this.baseUrl}/${languageCode}/p/${aId}`;
return `${this.baseUrl}/${languageCode}/${paths.public}/${aId}`;
}
public onCopyUrlToClipboard(aId: string): void {

5
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts

@ -9,6 +9,7 @@ import {
PortfolioPosition,
User
} from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { OrderWithAccount } from '@ghostfolio/common/types';
@ -92,7 +93,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
}
public onCloneActivity(aActivity: Activity) {
this.router.navigate(['/portfolio', 'activities'], {
this.router.navigate(['/' + paths.portfolio, paths.activities], {
queryParams: { activityId: aActivity.id, createDialog: true }
});
@ -151,7 +152,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
}
public onUpdateActivity(aActivity: Activity) {
this.router.navigate(['/portfolio', 'activities'], {
this.router.navigate(['/' + paths.portfolio, paths.activities], {
queryParams: { activityId: aActivity.id, editDialog: true }
});

5
apps/client/src/app/components/admin-settings/admin-settings.component.ts

@ -13,6 +13,7 @@ import {
DataProviderInfo,
User
} from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import {
ChangeDetectionStrategy,
@ -75,9 +76,7 @@ export class AdminSettingsComponent implements OnDestroy, OnInit {
const languageCode =
this.user?.settings?.language ?? DEFAULT_LANGUAGE_CODE;
this.pricingUrl =
`https://ghostfol.io/${languageCode}/` +
$localize`:snake-case:pricing`;
this.pricingUrl = `https://ghostfol.io/${languageCode}/${paths.pricing}`;
this.changeDetectorRef.markForCheck();
}

23
apps/client/src/app/components/header/header.component.ts

@ -11,6 +11,7 @@ import {
import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { Filter, InfoItem, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { DateRange } from '@ghostfolio/common/types';
import { GfAssistantComponent } from '@ghostfolio/ui/assistant/assistant.component';
@ -79,17 +80,17 @@ export class HeaderComponent implements OnChanges {
public hasPermissionToCreateUser: boolean;
public impersonationId: string;
public isMenuOpen: boolean;
public routeAbout = $localize`:snake-case:about`;
public routeFeatures = $localize`:snake-case:features`;
public routeMarkets = $localize`:snake-case:markets`;
public routePricing = $localize`:snake-case:pricing`;
public routeResources = $localize`:snake-case:resources`;
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkMarkets = ['/' + $localize`:snake-case:markets`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkRegister = ['/' + $localize`:snake-case:register`];
public routerLinkResources = ['/' + $localize`:snake-case:resources`];
public routeAbout = paths.about;
public routeFeatures = paths.features;
public routeMarkets = paths.markets;
public routePricing = paths.pricing;
public routeResources = paths.resources;
public routerLinkAbout = ['/' + paths.about];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkMarkets = ['/' + paths.markets];
public routerLinkPricing = ['/' + paths.pricing];
public routerLinkRegister = ['/' + paths.register];
public routerLinkResources = ['/' + paths.resources];
private unsubscribeSubject = new Subject<void>();

5
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts

@ -13,6 +13,7 @@ import {
LineChartItem,
User
} from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table';
import { GfDataProviderCreditsComponent } from '@ghostfolio/ui/data-provider-credits';
@ -468,7 +469,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
}
public onCloneActivity(aActivity: Activity) {
this.router.navigate(['/portfolio', 'activities'], {
this.router.navigate(['/' + paths.portfolio, paths.activities], {
queryParams: { activityId: aActivity.id, createDialog: true }
});
@ -510,7 +511,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
}
public onUpdateActivity(aActivity: Activity) {
this.router.navigate(['/portfolio', 'activities'], {
this.router.navigate(['/' + paths.portfolio, paths.activities], {
queryParams: { activityId: aActivity.id, editDialog: true }
});

4
apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
@ -26,7 +28,7 @@ export class SubscriptionInterstitialDialog implements OnInit {
public remainingSkipButtonDelay =
SubscriptionInterstitialDialog.SKIP_BUTTON_DELAY_IN_SECONDS;
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkPricing = ['/' + paths.pricing];
public variantIndex: number;
private unsubscribeSubject = new Subject<void>();

3
apps/client/src/app/components/user-account-membership/user-account-membership.component.ts

@ -4,6 +4,7 @@ import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { getDateFormatString } from '@ghostfolio/common/helper';
import { User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import {
@ -36,7 +37,7 @@ export class UserAccountMembershipComponent implements OnDestroy {
public hasPermissionToUpdateUserSettings: boolean;
public price: number;
public priceId: string;
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkPricing = ['/' + paths.pricing];
public trySubscriptionMail =
'mailto:hi@ghostfol.io?Subject=Ghostfolio Premium Trial&body=Hello%0D%0DI am interested in Ghostfolio Premium. Can you please send me a coupon code to try it for some time?%0D%0DKind regards';
public user: User;

37
apps/client/src/app/core/auth.guard.ts

@ -1,6 +1,7 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { paths } from '@ghostfolio/common/paths';
import { Injectable } from '@angular/core';
import {
@ -11,20 +12,18 @@ import {
import { EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { paths } from './paths';
@Injectable({ providedIn: 'root' })
export class AuthGuard {
private static PUBLIC_PAGE_ROUTES = [
`/${paths.about}`,
'/blog',
'/demo',
`/${paths.blog}`,
`/${paths.demo}`,
`/${paths.faq}`,
`/${paths.features}`,
`/${paths.markets}`,
'/open',
'/p',
`/${paths.open}`,
`/${paths.pricing}`,
`/${paths.public}`,
`/${paths.register}`,
`/${paths.resources}`
];
@ -49,21 +48,21 @@ export class AuthGuard {
.pipe(
catchError(() => {
if (utmSource === 'ios') {
this.router.navigate(['/demo']);
this.router.navigate(['/' + paths.demo]);
resolve(false);
} else if (utmSource === 'trusted-web-activity') {
this.router.navigate(['/' + $localize`register`]);
this.router.navigate(['/' + paths.register]);
resolve(false);
} else if (
AuthGuard.PUBLIC_PAGE_ROUTES.filter((publicPageRoute) => {
const [, url] = state.url.split('/');
AuthGuard.PUBLIC_PAGE_ROUTES.some((publicPageRoute) => {
const [, url] = decodeURIComponent(state.url).split('/');
return `/${url}` === publicPageRoute;
})?.length > 0
})
) {
resolve(true);
return EMPTY;
} else if (state.url !== '/start') {
this.router.navigate(['/start']);
this.router.navigate(['/' + paths.start]);
resolve(false);
return EMPTY;
}
@ -89,26 +88,26 @@ export class AuthGuard {
resolve(true);
return;
} else if (
state.url.startsWith('/home') &&
state.url.startsWith(`/${paths.home}`) &&
user.settings.viewMode === 'ZEN'
) {
this.router.navigate(['/zen']);
this.router.navigate(['/' + paths.zen]);
resolve(false);
return;
} else if (state.url.startsWith('/start')) {
} else if (state.url.startsWith(`/${paths.start}`)) {
if (user.settings.viewMode === 'ZEN') {
this.router.navigate(['/zen']);
this.router.navigate(['/' + paths.zen]);
} else {
this.router.navigate(['/home']);
this.router.navigate(['/' + paths.home]);
}
resolve(false);
return;
} else if (
state.url.startsWith('/zen') &&
state.url.startsWith(`/${paths.zen}`) &&
user.settings.viewMode === 'DEFAULT'
) {
this.router.navigate(['/home']);
this.router.navigate(['/' + paths.home]);
resolve(false);
return;
}

5
apps/client/src/app/core/http-response.interceptor.ts

@ -2,6 +2,7 @@ import { DataService } from '@ghostfolio/client/services/data.service';
import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service';
import { InfoItem } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import {
HTTP_INTERCEPTORS,
@ -74,7 +75,7 @@ export class HttpResponseInterceptor implements HttpInterceptor {
});
this.snackBarRef.onAction().subscribe(() => {
this.router.navigate(['/' + $localize`pricing`]);
this.router.navigate(['/' + paths.pricing]);
});
}
} else if (error.status === StatusCodes.INTERNAL_SERVER_ERROR) {
@ -110,7 +111,7 @@ export class HttpResponseInterceptor implements HttpInterceptor {
} else if (error.status === StatusCodes.UNAUTHORIZED) {
if (!error.url.includes('/data-providers/ghostfolio/status')) {
if (this.webAuthnService.isEnabled()) {
this.router.navigate(['/webauthn']);
this.router.navigate(['/' + paths.webauthn]);
} else {
this.tokenStorageService.signOut();
}

12
apps/client/src/app/core/paths.ts

@ -1,12 +0,0 @@
export const paths = {
about: $localize`about`,
faq: $localize`faq`,
features: $localize`features`,
license: $localize`license`,
markets: $localize`markets`,
pricing: $localize`pricing`,
privacyPolicy: $localize`privacy-policy`,
register: $localize`register`,
resources: $localize`resources`,
termsOfService: $localize`terms-of-service`
};

6
apps/client/src/app/pages/about/about-page-routing.module.ts

@ -1,5 +1,5 @@
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/client/core/paths';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -18,7 +18,7 @@ const routes: Routes = [
)
},
{
path: 'changelog',
path: paths.changelog,
loadChildren: () =>
import('./changelog/changelog-page.module').then(
(m) => m.ChangelogPageModule
@ -32,7 +32,7 @@ const routes: Routes = [
)
},
{
path: 'oss-friends',
path: paths.ossFriends,
loadChildren: () =>
import('./oss-friends/oss-friends-page.module').then(
(m) => m.OpenSourceSoftwareFriendsPageModule

13
apps/client/src/app/pages/about/about-page.component.ts

@ -1,6 +1,7 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
@ -43,17 +44,17 @@ export class AboutPageComponent implements OnDestroy, OnInit {
{
iconName: 'information-circle-outline',
label: $localize`About`,
path: ['/' + $localize`about`]
path: ['/' + paths.about]
},
{
iconName: 'sparkles-outline',
label: $localize`Changelog`,
path: ['/' + $localize`about`, 'changelog']
path: ['/' + paths.about, paths.changelog]
},
{
iconName: 'ribbon-outline',
label: $localize`License`,
path: ['/' + $localize`about`, $localize`license`],
path: ['/' + paths.about, paths.license],
showCondition: !this.hasPermissionForSubscription
}
];
@ -62,14 +63,14 @@ export class AboutPageComponent implements OnDestroy, OnInit {
this.tabs.push({
iconName: 'shield-checkmark-outline',
label: $localize`Privacy Policy`,
path: ['/' + $localize`about`, $localize`privacy-policy`],
path: ['/' + paths.about, paths.privacyPolicy],
showCondition: this.hasPermissionForSubscription
});
this.tabs.push({
iconName: 'document-text-outline',
label: $localize`Terms of Service`,
path: ['/' + $localize`about`, $localize`terms-of-service`],
path: ['/' + paths.about, paths.termsOfService],
showCondition: this.hasPermissionForSubscription
});
@ -81,7 +82,7 @@ export class AboutPageComponent implements OnDestroy, OnInit {
this.tabs.push({
iconName: 'happy-outline',
label: 'OSS Friends',
path: ['/' + $localize`about`, 'oss-friends']
path: ['/' + paths.about, paths.ossFriends]
});
});
}

5
apps/client/src/app/pages/about/overview/about-overview-page.component.ts

@ -1,6 +1,7 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
@ -17,8 +18,8 @@ export class AboutOverviewPageComponent implements OnDestroy, OnInit {
public hasPermissionForStatistics: boolean;
public hasPermissionForSubscription: boolean;
public isLoggedIn: boolean;
public routerLinkFaq = ['/' + $localize`:snake-case:faq`];
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkFaq = ['/' + paths.faq];
public routerLinkFeatures = ['/' + paths.features];
public user: User;
private unsubscribeSubject = new Subject<void>();

9
apps/client/src/app/pages/admin/admin-page-routing.module.ts

@ -4,6 +4,7 @@ import { AdminOverviewComponent } from '@ghostfolio/client/components/admin-over
import { AdminSettingsComponent } from '@ghostfolio/client/components/admin-settings/admin-settings.component';
import { AdminUsersComponent } from '@ghostfolio/client/components/admin-users/admin-users.component';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -20,22 +21,22 @@ const routes: Routes = [
title: $localize`Admin Control`
},
{
path: 'jobs',
path: paths.jobs,
component: AdminJobsComponent,
title: $localize`Job Queue`
},
{
path: 'market-data',
path: paths.marketData,
component: AdminMarketDataComponent,
title: $localize`Market Data`
},
{
path: 'settings',
path: paths.settings,
component: AdminSettingsComponent,
title: $localize`Settings`
},
{
path: 'users',
path: paths.users,
component: AdminUsersComponent,
title: $localize`Users`
}

11
apps/client/src/app/pages/admin/admin-page.component.ts

@ -1,4 +1,5 @@
import { TabConfiguration } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
@ -26,27 +27,27 @@ export class AdminPageComponent implements OnDestroy, OnInit {
{
iconName: 'reader-outline',
label: $localize`Overview`,
path: ['/admin']
path: ['/' + paths.admin]
},
{
iconName: 'settings-outline',
label: $localize`Settings`,
path: ['/admin', 'settings']
path: ['/' + paths.admin, paths.settings]
},
{
iconName: 'server-outline',
label: $localize`Market Data`,
path: ['/admin', 'market-data']
path: ['/' + paths.admin, paths.marketData]
},
{
iconName: 'flash-outline',
label: $localize`Job Queue`,
path: ['/admin', 'jobs']
path: ['/' + paths.admin, paths.jobs]
},
{
iconName: 'people-outline',
label: $localize`Users`,
path: ['/admin', 'users']
path: ['/' + paths.admin, paths.users]
}
];
}

6
apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,6 +11,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './hallo-ghostfolio-page.html'
})
export class HalloGhostfolioPageComponent {
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkResources = ['/' + $localize`:snake-case:resources`];
public routerLinkPricing = ['/' + paths.pricing];
public routerLinkResources = ['/' + paths.resources];
}

6
apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,6 +11,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './hello-ghostfolio-page.html'
})
export class HelloGhostfolioPageComponent {
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkResources = ['/' + $localize`:snake-case:resources`];
public routerLinkPricing = ['/' + paths.pricing];
public routerLinkResources = ['/' + paths.resources];
}

4
apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,5 +11,5 @@ import { RouterModule } from '@angular/router';
templateUrl: './first-months-in-open-source-page.html'
})
export class FirstMonthsInOpenSourcePageComponent {
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkPricing = ['/' + paths.pricing];
}

4
apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,5 +11,5 @@ import { RouterModule } from '@angular/router';
templateUrl: './how-do-i-get-my-finances-in-order-page.html'
})
export class HowDoIGetMyFinancesInOrderPageComponent {
public routerLinkResources = ['/' + $localize`:snake-case:resources`];
public routerLinkResources = ['/' + paths.resources];
}

6
apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,6 +11,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './500-stars-on-github-page.html'
})
export class FiveHundredStarsOnGitHubPageComponent {
public routerLinkMarkets = ['/' + $localize`:snake-case:markets`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkMarkets = ['/' + paths.markets];
public routerLinkPricing = ['/' + paths.pricing];
}

5
apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts

@ -1,3 +1,4 @@
import { paths } from '@ghostfolio/common/paths';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { Component } from '@angular/core';
@ -11,6 +12,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './black-friday-2022-page.html'
})
export class BlackFriday2022PageComponent {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkPricing = ['/' + paths.pricing];
}

6
apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,6 +11,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './1000-stars-on-github-page.html'
})
export class ThousandStarsOnGitHubPageComponent {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkPricing = ['/' + paths.pricing];
}

6
apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,6 +11,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './unlock-your-financial-potential-with-ghostfolio-page.html'
})
export class UnlockYourFinancialPotentialWithGhostfolioPageComponent {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkResources = ['/' + $localize`:snake-case:resources`];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkResources = ['/' + paths.resources];
}

4
apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,5 +11,5 @@ import { RouterModule } from '@angular/router';
templateUrl: './exploring-the-path-to-fire-page.html'
})
export class ExploringThePathToFirePageComponent {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkFeatures = ['/' + paths.features];
}

7
apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,8 +11,5 @@ import { RouterModule } from '@angular/router';
templateUrl: './ghostfolio-joins-oss-friends-page.html'
})
export class GhostfolioJoinsOssFriendsPageComponent {
public routerLinkAboutOssFriends = [
'/' + $localize`:snake-case:about`,
'oss-friends'
];
public routerLinkAboutOssFriends = ['/' + paths.about, paths.ossFriends];
}

13
apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,11 +11,8 @@ import { RouterModule } from '@angular/router';
templateUrl: './ghostfolio-2-page.html'
})
export class Ghostfolio2PageComponent {
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkAboutChangelog = [
'/' + $localize`:snake-case:about`,
'changelog'
];
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkMarkets = ['/' + $localize`:snake-case:markets`];
public routerLinkAbout = ['/' + paths.about];
public routerLinkAboutChangelog = ['/' + paths.about, paths.changelog];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkMarkets = ['/' + paths.markets];
}

4
apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,5 +11,5 @@ import { RouterModule } from '@angular/router';
templateUrl: './hacktoberfest-2023-page.html'
})
export class Hacktoberfest2023PageComponent {
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkAbout = ['/' + paths.about];
}

5
apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts

@ -1,3 +1,4 @@
import { paths } from '@ghostfolio/common/paths';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { Component } from '@angular/core';
@ -11,6 +12,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './black-week-2023-page.html'
})
export class BlackWeek2023PageComponent {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkPricing = ['/' + paths.pricing];
}

6
apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,6 +11,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './hacktoberfest-2023-debriefing-page.html'
})
export class Hacktoberfest2023DebriefingPageComponent {
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkAbout = ['/' + paths.about];
public routerLinkFeatures = ['/' + paths.features];
}

4
apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@ -9,5 +11,5 @@ import { RouterModule } from '@angular/router';
templateUrl: './hacktoberfest-2024-page.html'
})
export class Hacktoberfest2024PageComponent {
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkAbout = ['/' + paths.about];
}

5
apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts

@ -1,3 +1,4 @@
import { paths } from '@ghostfolio/common/paths';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { Component } from '@angular/core';
@ -11,6 +12,6 @@ import { RouterModule } from '@angular/router';
templateUrl: './black-weeks-2024-page.html'
})
export class BlackWeeks2024PageComponent {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkPricing = ['/' + paths.pricing];
}

5
apps/client/src/app/pages/faq/faq-page-routing.module.ts

@ -1,4 +1,5 @@
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -17,12 +18,12 @@ const routes: Routes = [
)
},
{
path: 'saas',
path: paths.saas,
loadChildren: () =>
import('./saas/saas-page.module').then((m) => m.SaasPageModule)
},
{
path: 'self-hosting',
path: paths.selfHosting,
loadChildren: () =>
import('./self-hosting/self-hosting-page.module').then(
(m) => m.SelfHostingPageModule

7
apps/client/src/app/pages/faq/faq-page.component.ts

@ -1,5 +1,6 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { TabConfiguration } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { Component, OnDestroy, OnInit } from '@angular/core';
@ -35,18 +36,18 @@ export class FaqPageComponent implements OnDestroy, OnInit {
{
iconName: 'reader-outline',
label: $localize`General`,
path: ['/' + $localize`faq`]
path: ['/' + paths.faq]
},
{
iconName: 'cloudy-outline',
label: $localize`Cloud` + ' (SaaS)',
path: ['/' + $localize`faq`, 'saas'],
path: ['/' + paths.faq, paths.saas],
showCondition: this.hasPermissionForSubscription
},
{
iconName: 'server-outline',
label: $localize`Self-Hosting`,
path: ['/' + $localize`faq`, $localize`self-hosting`]
path: ['/' + paths.faq, paths.selfHosting]
}
];
}

7
apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts

@ -1,5 +1,6 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core';
import { Subject, takeUntil } from 'rxjs';
@ -12,10 +13,8 @@ import { Subject, takeUntil } from 'rxjs';
standalone: false
})
export class FaqOverviewPageComponent implements OnDestroy {
public pricingUrl =
`https://ghostfol.io/${document.documentElement.lang}/` +
$localize`:snake-case:pricing`;
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public pricingUrl = `https://ghostfol.io/${document.documentElement.lang}/${paths.pricing}`;
public routerLinkFeatures = ['/' + paths.features];
public user: User;
private unsubscribeSubject = new Subject<void>();

9
apps/client/src/app/pages/faq/saas/saas-page.component.ts

@ -1,5 +1,6 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core';
import { Subject, takeUntil } from 'rxjs';
@ -12,11 +13,9 @@ import { Subject, takeUntil } from 'rxjs';
standalone: false
})
export class SaasPageComponent implements OnDestroy {
public pricingUrl =
`https://ghostfol.io/${document.documentElement.lang}/` +
$localize`:snake-case:pricing`;
public routerLinkMarkets = ['/' + $localize`:snake-case:markets`];
public routerLinkRegister = ['/' + $localize`:snake-case:register`];
public pricingUrl = `https://ghostfol.io/${document.documentElement.lang}/${paths.pricing}`;
public routerLinkMarkets = ['/' + paths.markets];
public routerLinkRegister = ['/' + paths.register];
public user: User;
private unsubscribeSubject = new Subject<void>();

6
apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
@ -9,9 +11,7 @@ import { Subject } from 'rxjs';
standalone: false
})
export class SelfHostingPageComponent implements OnDestroy {
public pricingUrl =
`https://ghostfol.io/${document.documentElement.lang}/` +
$localize`:snake-case:pricing`;
public pricingUrl = `https://ghostfol.io/${document.documentElement.lang}/${paths.pricing}`;
private unsubscribeSubject = new Subject<void>();

5
apps/client/src/app/pages/features/features-page.component.ts

@ -1,6 +1,7 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { InfoItem, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
@ -25,8 +26,8 @@ import { Subject, takeUntil } from 'rxjs';
export class GfFeaturesPageComponent implements OnDestroy {
public hasPermissionForSubscription: boolean;
public info: InfoItem;
public routerLinkRegister = ['/' + $localize`:snake-case:register`];
public routerLinkResources = ['/' + $localize`:snake-case:resources`];
public routerLinkRegister = ['/' + paths.register];
public routerLinkResources = ['/' + paths.resources];
public user: User;
private unsubscribeSubject = new Subject<void>();

14
apps/client/src/app/pages/home/home-page-routing.module.ts

@ -4,6 +4,7 @@ import { HomeOverviewComponent } from '@ghostfolio/client/components/home-overvi
import { HomeSummaryComponent } from '@ghostfolio/client/components/home-summary/home-summary.component';
import { HomeWatchlistComponent } from '@ghostfolio/client/components/home-watchlist/home-watchlist.component';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -19,27 +20,22 @@ const routes: Routes = [
component: HomeOverviewComponent
},
{
path: 'holdings',
path: paths.holdings,
component: HomeHoldingsComponent,
title: $localize`Holdings`
},
{
path: 'holdings',
component: HomeHoldingsComponent,
title: $localize`Holdings`
},
{
path: 'summary',
path: paths.summary,
component: HomeSummaryComponent,
title: $localize`Summary`
},
{
path: 'market',
path: paths.market,
component: HomeMarketComponent,
title: $localize`Markets`
},
{
path: 'watchlist',
path: paths.watchlist,
component: HomeWatchlistComponent,
title: $localize`Watchlist`
}

11
apps/client/src/app/pages/home/home-page.component.ts

@ -1,6 +1,7 @@
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
@ -36,27 +37,27 @@ export class HomePageComponent implements OnDestroy, OnInit {
{
iconName: 'analytics-outline',
label: $localize`Overview`,
path: ['/home']
path: ['/' + paths.home]
},
{
iconName: 'wallet-outline',
label: $localize`Holdings`,
path: ['/home', 'holdings']
path: ['/' + paths.home, paths.holdings]
},
{
iconName: 'reader-outline',
label: $localize`Summary`,
path: ['/home', 'summary']
path: ['/' + paths.home, paths.summary]
},
{
iconName: 'bookmark-outline',
label: $localize`Watchlist`,
path: ['/home', 'watchlist']
path: ['/' + paths.home, paths.watchlist]
},
{
iconName: 'newspaper-outline',
label: $localize`Markets`,
path: ['/home', 'market']
path: ['/' + paths.home, paths.market]
}
];

5
apps/client/src/app/pages/landing/landing-page.component.ts

@ -1,5 +1,6 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { Statistics } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { Component, OnDestroy, OnInit } from '@angular/core';
@ -24,8 +25,8 @@ export class LandingPageComponent implements OnDestroy, OnInit {
public hasPermissionForStatistics: boolean;
public hasPermissionForSubscription: boolean;
public hasPermissionToCreateUser: boolean;
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkRegister = ['/' + $localize`:snake-case:register`];
public routerLinkAbout = ['/' + paths.about];
public routerLinkRegister = ['/' + paths.register];
public statistics: Statistics;
public testimonials = [
{

9
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts

@ -1,4 +1,5 @@
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -17,26 +18,26 @@ const routes: Routes = [
)
},
{
path: 'activities',
path: paths.activities,
loadChildren: () =>
import('./activities/activities-page.module').then(
(m) => m.ActivitiesPageModule
)
},
{
path: 'allocations',
path: paths.allocations,
loadChildren: () =>
import('./allocations/allocations-page.module').then(
(m) => m.AllocationsPageModule
)
},
{
path: 'fire',
path: paths.fire,
loadChildren: () =>
import('./fire/fire-page.module').then((m) => m.FirePageModule)
},
{
path: 'x-ray',
path: paths.xRay,
loadChildren: () =>
import('./x-ray/x-ray-page.module').then((m) => m.XRayPageModule)
}

11
apps/client/src/app/pages/portfolio/portfolio-page.component.ts

@ -1,5 +1,6 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
@ -33,27 +34,27 @@ export class PortfolioPageComponent implements OnDestroy, OnInit {
{
iconName: 'analytics-outline',
label: $localize`Analysis`,
path: ['/portfolio']
path: ['/' + paths.portfolio]
},
{
iconName: 'swap-vertical-outline',
label: $localize`Activities`,
path: ['/portfolio', 'activities']
path: ['/' + paths.portfolio, paths.activities]
},
{
iconName: 'pie-chart-outline',
label: $localize`Allocations`,
path: ['/portfolio', 'allocations']
path: ['/' + paths.portfolio, paths.allocations]
},
{
iconName: 'calculator-outline',
label: 'FIRE ',
path: ['/portfolio', 'fire']
path: ['/' + paths.portfolio, paths.fire]
},
{
iconName: 'scan-outline',
label: 'X-ray',
path: ['/portfolio', 'x-ray']
path: ['/' + paths.portfolio, paths.xRay]
}
];
this.user = state.user;

5
apps/client/src/app/pages/pricing/pricing-page.component.ts

@ -2,6 +2,7 @@ import { NotificationService } from '@ghostfolio/client/core/notification/notifi
import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { translate } from '@ghostfolio/ui/i18n';
@ -40,8 +41,8 @@ export class PricingPageComponent implements OnDestroy, OnInit {
public professionalDataProviderTooltipPremium = translate(
'PROFESSIONAL_DATA_PROVIDER_TOOLTIP_PREMIUM'
);
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkRegister = ['/' + $localize`:snake-case:register`];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkRegister = ['/' + paths.register];
public user: User;
private unsubscribeSubject = new Subject<void>();

5
apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.component.ts

@ -1,4 +1,5 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { paths } from '@ghostfolio/common/paths';
import {
ChangeDetectionStrategy,
@ -30,8 +31,8 @@ export class ShowAccessTokenDialog {
public isDisclaimerChecked = false;
public role: string;
public routerLinkAboutTermsOfService = [
'/' + $localize`:snake-case:about`,
$localize`:snake-case:terms-of-service`
'/' + paths.about,
paths.termsOfService
];
private unsubscribeSubject = new Subject<void>();

5
apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts

@ -1,5 +1,6 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { InfoItem } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { Component, OnInit } from '@angular/core';
@ -14,8 +15,8 @@ export class ResourcesGlossaryPageComponent implements OnInit {
public hasPermissionForSubscription: boolean;
public info: InfoItem;
public routerLinkResourcesPersonalFinanceTools = [
'/' + $localize`:snake-case:resources`,
'personal-finance-tools'
'/' + paths.resources,
paths.personalFinanceTools
];
public constructor(private dataService: DataService) {

19
apps/client/src/app/pages/resources/overview/resources-overview.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component } from '@angular/core';
@Component({
@ -12,34 +14,25 @@ export class ResourcesOverviewComponent {
title: 'Frequently Asked Questions (FAQ)',
description:
'Find quick answers to commonly asked questions about Ghostfolio in our Frequently Asked Questions (FAQ) section.',
link: ['/' + $localize`:snake-case:faq`]
link: ['/' + paths.faq]
},
{
title: 'Guides',
description:
'Explore our guides to help you get started with investing and managing your finances.',
link: [
'/' + $localize`:snake-case:resources`,
$localize`:snake-case:guides`
]
link: ['/' + paths.resources, paths.guides]
},
{
title: 'Markets',
description:
'Access various market resources and tools to stay informed about financial markets.',
link: [
'/' + $localize`:snake-case:resources`,
$localize`:snake-case:markets`
]
link: ['/' + paths.resources, paths.markets]
},
{
title: 'Glossary',
description:
'Learn key financial terms and concepts in our comprehensive glossary.',
link: [
'/' + $localize`:snake-case:resources`,
$localize`:snake-case:glossary`
]
link: ['/' + paths.resources, paths.glossary]
}
];
}

3
apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page-routing.module.ts

@ -1,4 +1,5 @@
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools';
import { NgModule } from '@angular/core';
@ -23,7 +24,7 @@ const routes: Routes = [
return GfProductPageComponent;
}
),
path: $localize`open-source-alternative-to` + `-${alias ?? key}`,
path: `${paths.openSourceAlternativeTo}-${alias ?? key}`,
title: $localize`Open Source Alternative to ${name}`
};
})

7
apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts

@ -1,3 +1,4 @@
import { paths } from '@ghostfolio/common/paths';
import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools';
import { Component, OnDestroy } from '@angular/core';
@ -11,12 +12,12 @@ import { Subject } from 'rxjs';
standalone: false
})
export class PersonalFinanceToolsPageComponent implements OnDestroy {
public pathAlternativeTo = $localize`open-source-alternative-to` + '-';
public pathResources = '/' + $localize`resources`;
public pathAlternativeTo = paths.openSourceAlternativeTo + '-';
public pathResources = '/' + paths.resources;
public personalFinanceTools = personalFinanceTools.sort((a, b) => {
return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });
});
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkAbout = ['/' + paths.about];
private unsubscribeSubject = new Subject<void>();

9
apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts

@ -1,5 +1,6 @@
import { DataService } from '@ghostfolio/client/services/data.service';
import { Product } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools';
import { translate } from '@ghostfolio/ui/i18n';
@ -19,11 +20,11 @@ export class GfProductPageComponent implements OnInit {
public price: number;
public product1: Product;
public product2: Product;
public routerLinkAbout = ['/' + $localize`:snake-case:about`];
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkAbout = ['/' + paths.about];
public routerLinkFeatures = ['/' + paths.features];
public routerLinkResourcesPersonalFinanceTools = [
'/' + $localize`:snake-case:resources`,
'personal-finance-tools'
'/' + paths.resources,
paths.personalFinanceTools
];
public tags: string[];

9
apps/client/src/app/pages/resources/resources-page-routing.module.ts

@ -1,4 +1,5 @@
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -18,27 +19,27 @@ const routes: Routes = [
)
},
{
path: $localize`:snake-case:glossary`,
path: paths.glossary,
loadChildren: () =>
import('./glossary/resources-glossary.module').then(
(m) => m.ResourcesGlossaryPageModule
)
},
{
path: $localize`:snake-case:guides`,
path: paths.guides,
loadChildren: () =>
import('./guides/resources-guides.module').then(
(m) => m.ResourcesGuidesModule
)
},
{
path: $localize`:snake-case:markets`,
path: paths.markets,
loadChildren: () =>
import('./markets/resources-markets.module').then(
(m) => m.ResourcesMarketsModule
)
},
...['personal-finance-tools'].map((path) => ({
...[paths.personalFinanceTools].map((path) => ({
path,
loadChildren: () =>
import(

8
apps/client/src/app/pages/resources/resources-page.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { Component, OnInit } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
@ -18,17 +20,17 @@ export class ResourcesPageComponent implements OnInit {
iconName: 'reader-outline'
},
{
path: 'guides',
path: paths.guides,
label: $localize`Guides`,
iconName: 'book-outline'
},
{
path: 'markets',
path: paths.markets,
label: $localize`Markets`,
iconName: 'newspaper-outline'
},
{
path: 'glossary',
path: paths.glossary,
label: $localize`Glossary`,
iconName: 'library-outline'
}

5
apps/client/src/app/pages/user-account/user-account-page-routing.module.ts

@ -2,6 +2,7 @@ import { UserAccountAccessComponent } from '@ghostfolio/client/components/user-a
import { UserAccountMembershipComponent } from '@ghostfolio/client/components/user-account-membership/user-account-membership.component';
import { UserAccountSettingsComponent } from '@ghostfolio/client/components/user-account-settings/user-account-settings.component';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -18,12 +19,12 @@ const routes: Routes = [
title: $localize`Settings`
},
{
path: 'membership',
path: paths.membership,
component: UserAccountMembershipComponent,
title: $localize`Membership`
},
{
path: 'access',
path: paths.access,
component: UserAccountAccessComponent,
title: $localize`Access`
}

7
apps/client/src/app/pages/user-account/user-account-page.component.ts

@ -1,5 +1,6 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
@ -34,18 +35,18 @@ export class UserAccountPageComponent implements OnDestroy, OnInit {
{
iconName: 'settings-outline',
label: $localize`Settings`,
path: ['/account']
path: ['/' + paths.account]
},
{
iconName: 'diamond-outline',
label: $localize`Membership`,
path: ['/account/membership'],
path: ['/' + paths.account, paths.membership],
showCondition: !!this.user?.subscription
},
{
iconName: 'key-outline',
label: $localize`Access`,
path: ['/account', 'access']
path: ['/' + paths.account, paths.access]
}
];

3
apps/client/src/app/pages/zen/zen-page-routing.module.ts

@ -1,6 +1,7 @@
import { HomeHoldingsComponent } from '@ghostfolio/client/components/home-holdings/home-holdings.component';
import { HomeOverviewComponent } from '@ghostfolio/client/components/home-overview/home-overview.component';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { paths } from '@ghostfolio/common/paths';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
@ -12,7 +13,7 @@ const routes: Routes = [
canActivate: [AuthGuard],
children: [
{ path: '', component: HomeOverviewComponent },
{ path: 'holdings', component: HomeHoldingsComponent }
{ path: paths.holdings, component: HomeHoldingsComponent }
],
component: ZenPageComponent,
path: '',

5
apps/client/src/app/pages/zen/zen-page.component.ts

@ -1,5 +1,6 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { paths } from '@ghostfolio/common/paths';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector';
@ -33,12 +34,12 @@ export class ZenPageComponent implements OnDestroy, OnInit {
{
iconName: 'analytics-outline',
label: $localize`Overview`,
path: ['/zen']
path: ['/' + paths.zen]
},
{
iconName: 'wallet-outline',
label: $localize`Holdings`,
path: ['/zen', 'holdings']
path: ['/' + paths.zen, paths.holdings]
}
];
this.user = state.user;

714
apps/client/src/locales/messages.ca.xlf

File diff suppressed because it is too large

892
apps/client/src/locales/messages.de.xlf

File diff suppressed because it is too large

892
apps/client/src/locales/messages.es.xlf

File diff suppressed because it is too large

892
apps/client/src/locales/messages.fr.xlf

File diff suppressed because it is too large

892
apps/client/src/locales/messages.it.xlf

File diff suppressed because it is too large

892
apps/client/src/locales/messages.nl.xlf

File diff suppressed because it is too large

712
apps/client/src/locales/messages.pl.xlf

File diff suppressed because it is too large

892
apps/client/src/locales/messages.pt.xlf

File diff suppressed because it is too large

712
apps/client/src/locales/messages.tr.xlf

File diff suppressed because it is too large

714
apps/client/src/locales/messages.uk.xlf

File diff suppressed because it is too large

706
apps/client/src/locales/messages.xlf

File diff suppressed because it is too large

716
apps/client/src/locales/messages.zh.xlf

File diff suppressed because it is too large

53
libs/common/src/lib/paths.ts

@ -0,0 +1,53 @@
import '@angular/localize/init';
export const paths = {
access: 'access',
account: 'account',
accounts: 'accounts',
activities: 'activities',
admin: 'admin',
allocations: 'allocations',
api: 'api',
auth: 'auth',
blog: 'blog',
demo: 'demo',
fire: 'fire',
holdings: 'holdings',
home: 'home',
i18n: 'i18n',
jobs: 'jobs',
market: 'market',
marketData: 'market-data',
membership: 'membership',
open: 'open',
personalFinanceTools: 'personal-finance-tools',
portfolio: 'portfolio',
public: 'p',
saas: 'saas',
settings: 'settings',
start: 'start',
summary: 'summary',
users: 'users',
watchlist: 'watchlist',
webauthn: 'webauthn',
xRay: 'x-ray',
zen: 'zen',
// Localized paths (public-facing pages)
about: $localize`:snake-case:about`,
changelog: $localize`:snake-case:changelog`,
faq: $localize`:snake-case:faq`,
features: $localize`:snake-case:features`,
glossary: $localize`:snake-case:glossary`,
guides: $localize`:snake-case:guides`,
license: $localize`:snake-case:license`,
markets: $localize`:snake-case:markets`,
openSourceAlternativeTo: $localize`:snake-case:open-source-alternative-to`,
ossFriends: $localize`:snake-case:oss-friends`,
pricing: $localize`:snake-case:pricing`,
privacyPolicy: $localize`:snake-case:privacy-policy`,
register: $localize`:snake-case:register`,
resources: $localize`:snake-case:resources`,
selfHosting: $localize`:snake-case:self-hosting`,
termsOfService: $localize`:snake-case:terms-of-service`
};

4
libs/ui/src/lib/membership-card/membership-card.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { CommonModule } from '@angular/common';
import {
CUSTOM_ELEMENTS_SCHEMA,
@ -27,7 +29,7 @@ export class GfMembershipCardComponent {
@Output() generateApiKeyClicked = new EventEmitter<void>();
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkPricing = ['/' + paths.pricing];
public onGenerateApiKey(event: MouseEvent) {
event.preventDefault();

4
libs/ui/src/lib/premium-indicator/premium-indicator.component.ts

@ -1,3 +1,5 @@
import { paths } from '@ghostfolio/common/paths';
import { CommonModule } from '@angular/common';
import {
CUSTOM_ELEMENTS_SCHEMA,
@ -18,5 +20,5 @@ import { RouterModule } from '@angular/router';
export class GfPremiumIndicatorComponent {
@Input() enableLink = true;
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
public routerLinkPricing = ['/' + paths.pricing];
}

Loading…
Cancel
Save