Feature/add interstitial for subscription (#1637)
* Add interstitial * Improve pricing page * Update changelog
This commit is contained in:
parent
662231e830
commit
5d8a50a80d
@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- Added an interstitial for the subscription
|
||||
- Added a quote to the blog post _Ghostfolio auf Sackgeld.com vorgestellt_
|
||||
|
||||
### Changed
|
||||
|
||||
- Improved the pricing page
|
||||
- Upgraded `Node.js` from version `16` to `18` (`Dockerfile`)
|
||||
- Upgraded `prisma` from version `4.8.0` to `4.9.0`
|
||||
|
||||
|
@ -97,6 +97,7 @@ export class UserService {
|
||||
const {
|
||||
accessToken,
|
||||
Account,
|
||||
Analytics,
|
||||
authChallenge,
|
||||
createdAt,
|
||||
id,
|
||||
@ -107,7 +108,12 @@ export class UserService {
|
||||
thirdPartyId,
|
||||
updatedAt
|
||||
} = await this.prismaService.user.findUnique({
|
||||
include: { Account: true, Settings: true, Subscription: true },
|
||||
include: {
|
||||
Account: true,
|
||||
Analytics: true,
|
||||
Settings: true,
|
||||
Subscription: true
|
||||
},
|
||||
where: userWhereUniqueInput
|
||||
});
|
||||
|
||||
@ -121,7 +127,8 @@ export class UserService {
|
||||
role,
|
||||
Settings,
|
||||
thirdPartyId,
|
||||
updatedAt
|
||||
updatedAt,
|
||||
activityCount: Analytics?.activityCount
|
||||
};
|
||||
|
||||
if (user?.Settings) {
|
||||
@ -154,15 +161,22 @@ export class UserService {
|
||||
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
|
||||
}
|
||||
|
||||
let currentPermissions = getPermissions(user.role);
|
||||
|
||||
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
|
||||
user.subscription =
|
||||
this.subscriptionService.getSubscription(Subscription);
|
||||
}
|
||||
|
||||
let currentPermissions = getPermissions(user.role);
|
||||
if (
|
||||
Analytics?.activityCount % 25 === 0 &&
|
||||
user.subscription?.type === 'Basic'
|
||||
) {
|
||||
currentPermissions.push(permissions.enableSubscriptionInterstitial);
|
||||
}
|
||||
|
||||
if (user.subscription?.type === 'Premium') {
|
||||
currentPermissions.push(permissions.reportDataGlitch);
|
||||
if (user.subscription?.type === 'Premium') {
|
||||
currentPermissions.push(permissions.reportDataGlitch);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.configurationService.get('ENABLE_FEATURE_READ_ONLY_MODE')) {
|
||||
|
@ -25,6 +25,7 @@ import { DateFormats } from './adapter/date-formats';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { GfHeaderModule } from './components/header/header.module';
|
||||
import { GfSubscriptionInterstitialDialogModule } from './components/subscription-interstitial-dialog/subscription-interstitial-dialog.module';
|
||||
import { authInterceptorProviders } from './core/auth.interceptor';
|
||||
import { httpResponseInterceptorProviders } from './core/http-response.interceptor';
|
||||
import { LanguageService } from './core/language.service';
|
||||
@ -40,6 +41,7 @@ export function NgxStripeFactory(): string {
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
GfHeaderModule,
|
||||
GfSubscriptionInterstitialDialogModule,
|
||||
HttpClientModule,
|
||||
MarkdownModule.forRoot(),
|
||||
MatAutocompleteModule,
|
||||
|
@ -36,7 +36,7 @@ export class MarketDataDetailDialog implements OnDestroy {
|
||||
this.dateAdapter.setLocale(this.locale);
|
||||
}
|
||||
|
||||
public onCancel(): void {
|
||||
public onCancel() {
|
||||
this.dialogRef.close({ withRefresh: false });
|
||||
}
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
export interface SubscriptionInterstitialDialogParams {}
|
@ -0,0 +1,22 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
import { SubscriptionInterstitialDialogParams } from './interfaces/interfaces';
|
||||
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'd-flex flex-column flex-grow-1 h-100' },
|
||||
selector: 'gf-subscription-interstitial-dialog',
|
||||
styleUrls: ['./subscription-interstitial-dialog.scss'],
|
||||
templateUrl: 'subscription-interstitial-dialog.html'
|
||||
})
|
||||
export class SubscriptionInterstitialDialog {
|
||||
public constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data: SubscriptionInterstitialDialogParams,
|
||||
public dialogRef: MatDialogRef<SubscriptionInterstitialDialog>
|
||||
) {}
|
||||
|
||||
public onCancel() {
|
||||
this.dialogRef.close({});
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<h1 class="align-items-center d-flex" mat-dialog-title>
|
||||
<span>Ghostfolio Premium</span>
|
||||
<gf-premium-indicator class="ml-1"></gf-premium-indicator>
|
||||
</h1>
|
||||
<div class="flex-grow-1" mat-dialog-content>
|
||||
<p class="h5" i18n>
|
||||
Are you an ambitious investor who needs the full picture?
|
||||
</p>
|
||||
<p i18n>
|
||||
By upgrading to Ghostfolio Premium, you will get these additional features:
|
||||
</p>
|
||||
<ul class="list-unstyled mb-3">
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
|
||||
<span i18n>Portfolio Summary</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
|
||||
<span i18n>Performance Benchmarks</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
|
||||
<span i18n>Allocations</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
|
||||
<span i18n>FIRE Calculator</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
|
||||
<a i18n [routerLink]="['/features']">and more Features...</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Refine your personal investment strategy now.</p>
|
||||
</div>
|
||||
<div class="justify-content-end" mat-dialog-actions>
|
||||
<button i18n mat-button (click)="onCancel()">Skip</button>
|
||||
<a color="primary" mat-flat-button [routerLink]="['/pricing']">
|
||||
<span i18n>Upgrade Plan</span>
|
||||
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
|
||||
</a>
|
||||
</div>
|
@ -0,0 +1,21 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { GfPremiumIndicatorModule } from '@ghostfolio/ui/premium-indicator';
|
||||
|
||||
import { SubscriptionInterstitialDialog } from './subscription-interstitial-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SubscriptionInterstitialDialog],
|
||||
imports: [
|
||||
CommonModule,
|
||||
GfPremiumIndicatorModule,
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
RouterModule
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class GfSubscriptionInterstitialDialogModule {}
|
@ -0,0 +1,11 @@
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
.mat-dialog-content {
|
||||
max-height: unset;
|
||||
|
||||
ion-icon[name='checkmark-circle-outline'] {
|
||||
color: rgba(var(--palette-accent-500), 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ export class CreateOrUpdateAccessDialog implements OnDestroy {
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
public onCancel(): void {
|
||||
public onCancel() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ export class CreateOrUpdateAccountDialog implements OnDestroy {
|
||||
this.platforms = platforms;
|
||||
}
|
||||
|
||||
public onCancel(): void {
|
||||
public onCancel() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ export class ImportActivitiesDialog implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
public onCancel(): void {
|
||||
public onCancel() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
|
@ -31,50 +31,71 @@
|
||||
<mat-card class="d-flex flex-column h-100">
|
||||
<div class="flex-grow-1">
|
||||
<h4>Open Source</h4>
|
||||
<p>
|
||||
For tech-savvy investors who prefer to run
|
||||
<strong>Ghostfolio</strong> on their own infrastructure.
|
||||
<p i18n>
|
||||
For tech-savvy investors who prefer to run Ghostfolio on their
|
||||
own infrastructure.
|
||||
</p>
|
||||
<ul class="list-unstyled mb-3">
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Unlimited Transactions</span>
|
||||
<span i18n>Unlimited Transactions</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Portfolio Performance</span>
|
||||
<span i18n>Unlimited Accounts</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Zen Mode</span>
|
||||
<span i18n>Portfolio Performance</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Portfolio Summary</span>
|
||||
<span i18n>Portfolio Summary</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Advanced Insights</span>
|
||||
<span i18n>Performance Benchmarks</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span i18n>Allocations</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span i18n>FIRE Calculator</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<a i18n [routerLink]="['/features']">and more Features...</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Self-hosted, update manually.</p>
|
||||
<p class="h5 text-right">Free</p>
|
||||
<p i18n>Self-hosted, update manually.</p>
|
||||
<p class="h5 text-right" i18n>Free</p>
|
||||
<div
|
||||
*ngIf="user?.subscription?.type === 'Basic'"
|
||||
class="d-none d-lg-block hidden mt-3 text-center"
|
||||
@ -92,31 +113,54 @@
|
||||
[ngClass]="{ 'active': user?.subscription?.type === 'Basic' }"
|
||||
>
|
||||
<div class="flex-grow-1">
|
||||
<h4 class="align-items-center d-flex">Basic</h4>
|
||||
<p>
|
||||
<div class="align-items-center d-flex mb-2">
|
||||
<h4 class="flex-grow-1 m-0">Basic</h4>
|
||||
<div *ngIf="user?.subscription?.type === 'Basic'">
|
||||
<ion-icon class="mr-1" name="checkmark-outline"></ion-icon>
|
||||
</div>
|
||||
</div>
|
||||
<p i18n>
|
||||
For new investors who are just getting started with trading.
|
||||
</p>
|
||||
<ul class="list-unstyled mb-3">
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Unlimited Transactions</span>
|
||||
<span i18n>Unlimited Transactions</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Portfolio Performance</span>
|
||||
<span i18n>Unlimited Accounts</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span i18n>Portfolio Performance</span>
|
||||
</li>
|
||||
<li>
|
||||
<ion-icon
|
||||
class="invisible"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
</li>
|
||||
<li>
|
||||
<ion-icon
|
||||
class="invisible"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
</li>
|
||||
<li>
|
||||
<ion-icon
|
||||
class="invisible"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Zen Mode</span>
|
||||
</li>
|
||||
<li>
|
||||
<ion-icon
|
||||
@ -132,8 +176,8 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Fully managed <strong>Ghostfolio</strong> cloud offering.</p>
|
||||
<p class="h5 text-right">Free</p>
|
||||
<p i18n>Fully managed Ghostfolio cloud offering.</p>
|
||||
<p class="h5 text-right" i18n>Free</p>
|
||||
<div
|
||||
*ngIf="user?.subscription?.type === 'Basic'"
|
||||
class="d-none d-lg-block hidden mt-3 text-center"
|
||||
@ -151,56 +195,82 @@
|
||||
[ngClass]="{ 'active': user?.subscription?.type === 'Premium' }"
|
||||
>
|
||||
<div class="flex-grow-1">
|
||||
<h4 class="align-items-center d-flex">
|
||||
<span>Premium</span>
|
||||
<gf-premium-indicator
|
||||
class="ml-1"
|
||||
[enableLink]="false"
|
||||
></gf-premium-indicator>
|
||||
</h4>
|
||||
<p>
|
||||
<div class="align-items-center d-flex mb-2">
|
||||
<h4 class="align-items-center d-flex flex-grow-1 m-0">
|
||||
<span>Premium</span>
|
||||
<gf-premium-indicator
|
||||
class="ml-1"
|
||||
[enableLink]="false"
|
||||
></gf-premium-indicator>
|
||||
</h4>
|
||||
<div *ngIf="user?.subscription?.type === 'Premium'">
|
||||
<ion-icon class="mr-1" name="checkmark-outline"></ion-icon>
|
||||
</div>
|
||||
</div>
|
||||
<p i18n>
|
||||
For ambitious investors who need the full picture of their
|
||||
financial assets.
|
||||
</p>
|
||||
<ul class="list-unstyled mb-3">
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Unlimited Transactions</span>
|
||||
<span i18n>Unlimited Transactions</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Portfolio Performance</span>
|
||||
<span i18n>Unlimited Accounts</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Zen Mode</span>
|
||||
<span i18n>Portfolio Performance</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Portfolio Summary</span>
|
||||
<span i18n>Portfolio Summary</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1 text-muted"
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span>Advanced Insights</span>
|
||||
<span i18n>Performance Benchmarks</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span i18n>Allocations</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<span i18n>FIRE Calculator</span>
|
||||
</li>
|
||||
<li class="align-items-center d-flex mb-1">
|
||||
<ion-icon
|
||||
class="mr-1"
|
||||
name="checkmark-circle-outline"
|
||||
></ion-icon>
|
||||
<a i18n [routerLink]="['/features']">and more Features...</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Fully managed <strong>Ghostfolio</strong> cloud offering.</p>
|
||||
<p i18n>Fully managed Ghostfolio cloud offering.</p>
|
||||
<p class="h5 text-right" [hidden]="!price">
|
||||
<span class="font-weight-normal">
|
||||
<ng-container *ngIf="coupon"
|
||||
@ -221,11 +291,16 @@
|
||||
*ngIf="user?.subscription?.type === 'Basic'"
|
||||
class="mt-3 text-center"
|
||||
>
|
||||
<a color="primary" mat-flat-button [routerLink]="['/account']">
|
||||
<a
|
||||
color="primary"
|
||||
i18n
|
||||
mat-flat-button
|
||||
[routerLink]="['/account']"
|
||||
>
|
||||
Upgrade Plan
|
||||
</a>
|
||||
<p class="m-0 text-muted">
|
||||
<small>One-time payment, no auto-renewal.</small>
|
||||
<small i18n>One-time payment, no auto-renewal.</small>
|
||||
</p>
|
||||
</div>
|
||||
</mat-card>
|
||||
@ -235,10 +310,10 @@
|
||||
</div>
|
||||
<div *ngIf="!user" class="row">
|
||||
<div class="col mt-3 text-center">
|
||||
<a color="primary" mat-flat-button [routerLink]="['/register']">
|
||||
<a color="primary" i18n mat-flat-button [routerLink]="['/register']">
|
||||
Get Started
|
||||
</a>
|
||||
<p class="m-0 text-muted"><small>It’s free.</small></p>
|
||||
<p class="m-0 text-muted"><small i18n>It’s free.</small></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,12 +2,14 @@
|
||||
color: rgb(var(--dark-primary-text));
|
||||
display: block;
|
||||
|
||||
a {
|
||||
color: rgba(var(--palette-primary-500), 1);
|
||||
font-weight: 500;
|
||||
p {
|
||||
a {
|
||||
color: rgba(var(--palette-primary-500), 1);
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
color: rgba(var(--palette-primary-300), 1);
|
||||
&:hover {
|
||||
color: rgba(var(--palette-primary-300), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +19,10 @@
|
||||
border-color: rgba(var(--palette-primary-500), 1);
|
||||
box-shadow: 0 0 0 1px rgba(var(--palette-primary-500), 1);
|
||||
}
|
||||
|
||||
ion-icon[name='checkmark-circle-outline'] {
|
||||
color: rgba(var(--palette-accent-500), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,15 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ObservableStore } from '@codewithdan/observable-store';
|
||||
import { SubscriptionInterstitialDialogParams } from '@ghostfolio/client/components/subscription-interstitial-dialog/interfaces/interfaces';
|
||||
import { SubscriptionInterstitialDialog } from '@ghostfolio/client/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component';
|
||||
import { User } from '@ghostfolio/common/interfaces';
|
||||
import { of } from 'rxjs';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { throwError } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { catchError, map, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { UserStoreActions } from './user-store.actions';
|
||||
import { UserStoreState } from './user-store.state';
|
||||
@ -13,10 +18,19 @@ import { UserStoreState } from './user-store.state';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService extends ObservableStore<UserStoreState> {
|
||||
public constructor(private http: HttpClient) {
|
||||
private deviceType: string;
|
||||
private unsubscribeSubject = new Subject<void>();
|
||||
|
||||
public constructor(
|
||||
private deviceService: DeviceDetectorService,
|
||||
private dialog: MatDialog,
|
||||
private http: HttpClient
|
||||
) {
|
||||
super({ trackStateHistory: true });
|
||||
|
||||
this.setState({ user: undefined }, UserStoreActions.Initialize);
|
||||
|
||||
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
|
||||
}
|
||||
|
||||
public get(force = false) {
|
||||
@ -39,6 +53,26 @@ export class UserService extends ObservableStore<UserStoreState> {
|
||||
return this.http.get<User>('/api/v1/user').pipe(
|
||||
map((user) => {
|
||||
this.setState({ user }, UserStoreActions.GetUser);
|
||||
|
||||
if (
|
||||
hasPermission(
|
||||
user.permissions,
|
||||
permissions.enableSubscriptionInterstitial
|
||||
)
|
||||
) {
|
||||
const dialogRef = this.dialog.open(SubscriptionInterstitialDialog, {
|
||||
autoFocus: false,
|
||||
data: <SubscriptionInterstitialDialogParams>{},
|
||||
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh',
|
||||
width: this.deviceType === 'mobile' ? '100vw' : '50rem'
|
||||
});
|
||||
|
||||
dialogRef
|
||||
.afterClosed()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(() => {});
|
||||
}
|
||||
|
||||
return user;
|
||||
}),
|
||||
catchError(this.handleError)
|
||||
|
@ -5,6 +5,7 @@ import { UserSettings } from './user-settings.interface';
|
||||
|
||||
export type UserWithSettings = User & {
|
||||
Account: Account[];
|
||||
activityCount: number;
|
||||
permissions?: string[];
|
||||
Settings: Settings & { settings: UserSettings };
|
||||
subscription?: {
|
||||
|
@ -19,6 +19,7 @@ export const permissions = {
|
||||
enableSocialLogin: 'enableSocialLogin',
|
||||
enableStatistics: 'enableStatistics',
|
||||
enableSubscription: 'enableSubscription',
|
||||
enableSubscriptionInterstitial: 'enableSubscriptionInterstitial',
|
||||
enableSystemMessage: 'enableSystemMessage',
|
||||
reportDataGlitch: 'reportDataGlitch',
|
||||
toggleReadOnlyMode: 'toggleReadOnlyMode',
|
||||
|
Loading…
x
Reference in New Issue
Block a user