Feature/refactor demo account as route (#1058)
* Refactor demo account as route * Update changelog
This commit is contained in:
parent
c6b9e0aa5b
commit
35e039748f
@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Improved the label of the (symbol) search
|
- Improved the label of the (symbol) search
|
||||||
|
- Refactored the demo account as a route (`/demo`)
|
||||||
- Upgraded `nestjs` from version `8.2.3` to `8.4.7`
|
- Upgraded `nestjs` from version `8.2.3` to `8.4.7`
|
||||||
- Upgraded `prisma` from version `3.14.0` to `3.15.2`
|
- Upgraded `prisma` from version `3.14.0` to `3.15.2`
|
||||||
- Upgraded `yahoo-finance2` from version `2.3.2` to `2.3.3`
|
- Upgraded `yahoo-finance2` from version `2.3.2` to `2.3.3`
|
||||||
|
@ -59,6 +59,11 @@ const routes: Routes = [
|
|||||||
'./pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.module'
|
'./pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.module'
|
||||||
).then((m) => m.HalloGhostfolioPageModule)
|
).then((m) => m.HalloGhostfolioPageModule)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'demo',
|
||||||
|
loadChildren: () =>
|
||||||
|
import('./pages/demo/demo-page.module').then((m) => m.DemoPageModule)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'en/blog/2021/07/hello-ghostfolio',
|
path: 'en/blog/2021/07/hello-ghostfolio',
|
||||||
loadChildren: () =>
|
loadChildren: () =>
|
||||||
|
@ -5,13 +5,12 @@ import {
|
|||||||
Router,
|
Router,
|
||||||
RouterStateSnapshot
|
RouterStateSnapshot
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service';
|
||||||
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
import { ViewMode } from '@prisma/client';
|
import { ViewMode } from '@prisma/client';
|
||||||
import { EMPTY } from 'rxjs';
|
import { EMPTY } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
import { SettingsStorageService } from '../services/settings-storage.service';
|
|
||||||
import { UserService } from '../services/user/user.service';
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class AuthGuard implements CanActivate {
|
export class AuthGuard implements CanActivate {
|
||||||
private static PUBLIC_PAGE_ROUTES = [
|
private static PUBLIC_PAGE_ROUTES = [
|
||||||
@ -20,6 +19,7 @@ export class AuthGuard implements CanActivate {
|
|||||||
'/about/privacy-policy',
|
'/about/privacy-policy',
|
||||||
'/blog',
|
'/blog',
|
||||||
'/de/blog',
|
'/de/blog',
|
||||||
|
'/demo',
|
||||||
'/en/blog',
|
'/en/blog',
|
||||||
'/features',
|
'/features',
|
||||||
'/p',
|
'/p',
|
||||||
@ -35,11 +35,10 @@ export class AuthGuard implements CanActivate {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
if (route.queryParams?.utm_source) {
|
const utmSource = route.queryParams?.utm_source;
|
||||||
this.settingsStorageService.setSetting(
|
|
||||||
'utm_source',
|
if (utmSource) {
|
||||||
route.queryParams?.utm_source
|
this.settingsStorageService.setSetting('utm_source', utmSource);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<boolean>((resolve) => {
|
return new Promise<boolean>((resolve) => {
|
||||||
@ -47,7 +46,10 @@ export class AuthGuard implements CanActivate {
|
|||||||
.get()
|
.get()
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
if (route.queryParams?.utm_source) {
|
if (utmSource === 'ios') {
|
||||||
|
this.router.navigate(['/demo']);
|
||||||
|
resolve(false);
|
||||||
|
} else if (utmSource === 'trusted-web-activity') {
|
||||||
this.router.navigate(['/register']);
|
this.router.navigate(['/register']);
|
||||||
resolve(false);
|
resolve(false);
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -5,7 +5,6 @@ import {
|
|||||||
HttpRequest
|
HttpRequest
|
||||||
} from '@angular/common/http';
|
} from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { ImpersonationStorageService } from '../services/impersonation-storage.service';
|
import { ImpersonationStorageService } from '../services/impersonation-storage.service';
|
||||||
@ -18,7 +17,6 @@ const TOKEN_HEADER_KEY = 'Authorization';
|
|||||||
export class AuthInterceptor implements HttpInterceptor {
|
export class AuthInterceptor implements HttpInterceptor {
|
||||||
public constructor(
|
public constructor(
|
||||||
private impersonationStorageService: ImpersonationStorageService,
|
private impersonationStorageService: ImpersonationStorageService,
|
||||||
private router: Router,
|
|
||||||
private tokenStorageService: TokenStorageService
|
private tokenStorageService: TokenStorageService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
<div class="pr-1 w-50" i18n>Alias</div>
|
<div class="pr-1 w-50" i18n>Alias</div>
|
||||||
<div class="pl-1 w-50">{{ user.alias }}</div>
|
<div class="pl-1 w-50">{{ user.alias }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="user?.subscription" class="d-flex py-1">
|
<div
|
||||||
|
*ngIf="hasPermissionToUpdateUserSettings && user?.subscription"
|
||||||
|
class="d-flex py-1"
|
||||||
|
>
|
||||||
<div class="pr-1 w-50" i18n>Membership</div>
|
<div class="pr-1 w-50" i18n>Membership</div>
|
||||||
<div class="pl-1 w-50">
|
<div class="pl-1 w-50">
|
||||||
<div class="align-items-center d-flex mb-1">
|
<div class="align-items-center d-flex mb-1">
|
||||||
|
15
apps/client/src/app/pages/demo/demo-page-routing.module.ts
Normal file
15
apps/client/src/app/pages/demo/demo-page-routing.module.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
|
||||||
|
|
||||||
|
import { DemoPageComponent } from './demo-page.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: '', component: DemoPageComponent, canActivate: [AuthGuard] }
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class DemoPageRoutingModule {}
|
44
apps/client/src/app/pages/demo/demo-page.component.ts
Normal file
44
apps/client/src/app/pages/demo/demo-page.component.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Component, OnDestroy } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
|
import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
|
||||||
|
import { InfoItem } from '@ghostfolio/common/interfaces';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
host: { class: 'page' },
|
||||||
|
selector: 'gf-demo-page',
|
||||||
|
templateUrl: './demo-page.html'
|
||||||
|
})
|
||||||
|
export class DemoPageComponent implements OnDestroy {
|
||||||
|
public info: InfoItem;
|
||||||
|
|
||||||
|
private unsubscribeSubject = new Subject<void>();
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private dataService: DataService,
|
||||||
|
private router: Router,
|
||||||
|
private tokenStorageService: TokenStorageService
|
||||||
|
) {
|
||||||
|
this.info = this.dataService.fetchInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ngOnInit() {
|
||||||
|
const hasToken = this.tokenStorageService.getToken()?.length > 0;
|
||||||
|
|
||||||
|
if (hasToken) {
|
||||||
|
alert(
|
||||||
|
'As you are already logged in, you cannot access the demo account.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.tokenStorageService.saveToken(this.info.demoAuthToken, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ngOnDestroy() {
|
||||||
|
this.unsubscribeSubject.next();
|
||||||
|
this.unsubscribeSubject.complete();
|
||||||
|
}
|
||||||
|
}
|
0
apps/client/src/app/pages/demo/demo-page.html
Normal file
0
apps/client/src/app/pages/demo/demo-page.html
Normal file
12
apps/client/src/app/pages/demo/demo-page.module.ts
Normal file
12
apps/client/src/app/pages/demo/demo-page.module.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { DemoPageRoutingModule } from './demo-page-routing.module';
|
||||||
|
import { DemoPageComponent } from './demo-page.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [DemoPageComponent],
|
||||||
|
imports: [CommonModule, DemoPageRoutingModule],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class DemoPageModule {}
|
@ -1,7 +1,4 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
|
||||||
import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
|
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
@ -39,23 +36,9 @@ export class LandingPageComponent implements OnDestroy, OnInit {
|
|||||||
|
|
||||||
private unsubscribeSubject = new Subject<void>();
|
private unsubscribeSubject = new Subject<void>();
|
||||||
|
|
||||||
public constructor(
|
public constructor() {}
|
||||||
private dataService: DataService,
|
|
||||||
private router: Router,
|
|
||||||
private tokenStorageService: TokenStorageService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public ngOnInit() {
|
public ngOnInit() {}
|
||||||
const { demoAuthToken } = this.dataService.fetchInfo();
|
|
||||||
|
|
||||||
this.demoAuthToken = demoAuthToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setToken(aToken: string) {
|
|
||||||
this.tokenStorageService.saveToken(aToken, true);
|
|
||||||
|
|
||||||
this.router.navigate(['/']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
this.unsubscribeSubject.next();
|
this.unsubscribeSubject.next();
|
||||||
|
@ -31,20 +31,19 @@
|
|||||||
color="primary"
|
color="primary"
|
||||||
i18n
|
i18n
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
[disabled]="!demoAuthToken"
|
|
||||||
[routerLink]="['/register']"
|
[routerLink]="['/register']"
|
||||||
>
|
>
|
||||||
Get Started
|
Get Started
|
||||||
</a>
|
</a>
|
||||||
<div class="d-inline-block mx-3 text-muted" i18n>or</div>
|
<div class="d-inline-block mx-3 text-muted" i18n>or</div>
|
||||||
<button
|
<a
|
||||||
class="d-inline-block"
|
class="d-inline-block"
|
||||||
|
i18n
|
||||||
mat-stroked-button
|
mat-stroked-button
|
||||||
[disabled]="!demoAuthToken"
|
[routerLink]="['/demo']"
|
||||||
(click)="setToken(demoAuthToken)"
|
|
||||||
>
|
>
|
||||||
<span i18n>Live Demo</span>
|
Live Demo
|
||||||
</button>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -163,24 +162,18 @@
|
|||||||
Join now or check out the example account
|
Join now or check out the example account
|
||||||
</p>
|
</p>
|
||||||
<div class="py-2 text-center">
|
<div class="py-2 text-center">
|
||||||
<a
|
<a color="primary" i18n mat-flat-button [routerLink]="['/register']">
|
||||||
color="primary"
|
|
||||||
i18n
|
|
||||||
mat-flat-button
|
|
||||||
[disabled]="!demoAuthToken"
|
|
||||||
[routerLink]="['/register']"
|
|
||||||
>
|
|
||||||
Get Started
|
Get Started
|
||||||
</a>
|
</a>
|
||||||
<div class="d-inline-block mx-3 text-muted" i18n>or</div>
|
<div class="d-inline-block mx-3 text-muted" i18n>or</div>
|
||||||
<button
|
<a
|
||||||
class="d-inline-block"
|
class="d-inline-block"
|
||||||
|
i18n
|
||||||
mat-stroked-button
|
mat-stroked-button
|
||||||
[disabled]="!demoAuthToken"
|
[routerLink]="['/demo']"
|
||||||
(click)="setToken(demoAuthToken)"
|
|
||||||
>
|
>
|
||||||
<span i18n>Live Demo</span>
|
Live Demo
|
||||||
</button>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user