diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e0a350a9..4fba0cb84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Extended the variations of the interstitials for the subscription - Renamed the job identifier column in the jobs queue view of the admin control panel - Refactored the markets page to standalone - Refactored the header component to standalone - Refactored the rule component to standalone - Refactored the rules component to standalone +- Refactored the subscription interstitial dialog component to standalone ## 2.197.0 - 2025-09-07 diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index a84e10c44..10f8d3744 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -184,6 +184,7 @@ export class UserService { userWhereUniqueInput: Prisma.UserWhereUniqueInput ): Promise { const { + _count, accessesGet, accessToken, accounts, @@ -199,6 +200,11 @@ export class UserService { updatedAt } = await this.prismaService.user.findUnique({ include: { + _count: { + select: { + activities: true + } + }, accessesGet: true, accounts: { include: { platform: true } @@ -210,6 +216,8 @@ export class UserService { where: userWhereUniqueInput }); + const activitiesCount = _count?.activities ?? 0; + const user: UserWithSettings = { accessesGet, accessToken, @@ -404,13 +412,13 @@ export class UserService { ); let frequency = 7; - if (daysSinceRegistration > 720) { + if (activitiesCount > 1000 || daysSinceRegistration > 720) { frequency = 1; - } else if (daysSinceRegistration > 360) { + } else if (activitiesCount > 750 || daysSinceRegistration > 360) { frequency = 2; - } else if (daysSinceRegistration > 180) { + } else if (activitiesCount > 500 || daysSinceRegistration > 180) { frequency = 3; - } else if (daysSinceRegistration > 60) { + } else if (activitiesCount > 250 || daysSinceRegistration > 60) { frequency = 4; } else if (daysSinceRegistration > 30) { frequency = 5; diff --git a/apps/client/src/app/app.module.ts b/apps/client/src/app/app.module.ts index 384b83d6c..de52a043d 100644 --- a/apps/client/src/app/app.module.ts +++ b/apps/client/src/app/app.module.ts @@ -31,7 +31,6 @@ import { DateFormats } from './adapter/date-formats'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { GfHeaderComponent } from './components/header/header.component'; -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'; @@ -51,7 +50,6 @@ export function NgxStripeFactory(): string { GfHeaderComponent, GfLogoComponent, GfNotificationModule, - GfSubscriptionInterstitialDialogModule, IonIcon, MatAutocompleteModule, MatChipsModule, diff --git a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts index 48f17b886..7a17ec32d 100644 --- a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts +++ b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -1,13 +1,24 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { GfMembershipCardComponent } from '@ghostfolio/ui/membership-card'; +import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + CUSTOM_ELEMENTS_SCHEMA, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogModule, + MatDialogRef +} from '@angular/material/dialog'; +import { RouterModule } from '@angular/router'; +import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { arrowForwardOutline, checkmarkCircleOutline } from 'ionicons/icons'; import ms from 'ms'; @@ -19,17 +30,26 @@ import { SubscriptionInterstitialDialogParams } from './interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'd-flex flex-column flex-grow-1 h-100' }, + imports: [ + CommonModule, + GfMembershipCardComponent, + GfPremiumIndicatorComponent, + IonIcon, + MatButtonModule, + MatDialogModule, + RouterModule + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-subscription-interstitial-dialog', styleUrls: ['./subscription-interstitial-dialog.scss'], - templateUrl: 'subscription-interstitial-dialog.html', - standalone: false + templateUrl: 'subscription-interstitial-dialog.html' }) -export class SubscriptionInterstitialDialog implements OnInit { +export class GfSubscriptionInterstitialDialogComponent implements OnInit { private static readonly SKIP_BUTTON_DELAY_IN_SECONDS = 5; - private static readonly VARIANTS_COUNT = 2; + private static readonly VARIANTS_COUNT = 4; public remainingSkipButtonDelay = - SubscriptionInterstitialDialog.SKIP_BUTTON_DELAY_IN_SECONDS; + GfSubscriptionInterstitialDialogComponent.SKIP_BUTTON_DELAY_IN_SECONDS; public routerLinkPricing = publicRoutes.pricing.routerLink; public variantIndex: number; @@ -38,10 +58,10 @@ export class SubscriptionInterstitialDialog implements OnInit { public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: SubscriptionInterstitialDialogParams, - public dialogRef: MatDialogRef + public dialogRef: MatDialogRef ) { this.variantIndex = Math.floor( - Math.random() * SubscriptionInterstitialDialog.VARIANTS_COUNT + Math.random() * GfSubscriptionInterstitialDialogComponent.VARIANTS_COUNT ); addIcons({ arrowForwardOutline, checkmarkCircleOutline }); @@ -50,7 +70,9 @@ export class SubscriptionInterstitialDialog implements OnInit { public ngOnInit() { interval(ms('1 second')) .pipe( - take(SubscriptionInterstitialDialog.SKIP_BUTTON_DELAY_IN_SECONDS), + take( + GfSubscriptionInterstitialDialogComponent.SKIP_BUTTON_DELAY_IN_SECONDS + ), tap(() => { this.remainingSkipButtonDelay--; diff --git a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html index 92d9da835..d86ea2816 100644 --- a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html +++ b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html @@ -73,6 +73,89 @@ } @case (1) { +
+
+
+
+
+
+
+
+ Get access to 80’000+ tickers from over 50 exchanges +
+

with

+
+ Ghostfolio Premium + +
+
+
+
+ + + Upgrade Plan + + +
+ } + @case (2) { +
+
+
+
+
+
+
+
+ Ghostfolio Premium + +
+

for

+
+ less than $1 + per week +
+
+
+
+ + + Upgrade Plan + + +
+ } + @case (3) {

{ permissions.enableSubscriptionInterstitial ) ) { - const dialogRef = this.dialog.open(SubscriptionInterstitialDialog, { - autoFocus: false, - data: { - user - } as SubscriptionInterstitialDialogParams, - disableClose: true, - height: this.deviceType === 'mobile' ? '98vh' : '80vh', - width: this.deviceType === 'mobile' ? '100vw' : '50rem' - }); + const dialogRef = this.dialog.open( + GfSubscriptionInterstitialDialogComponent, + { + autoFocus: false, + data: { + user + } as SubscriptionInterstitialDialogParams, + disableClose: true, + height: this.deviceType === 'mobile' ? '98vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + } + ); dialogRef .afterClosed()