From 44bcbf6147366b89cff7542869bb68b1f470551e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 21 Oct 2026 22:38:23 +0200 Subject: [PATCH] Feature/trial variation of subscription interstitials (#8258) * Extend variations * Update changelog --- CHANGELOG.md | 1 + ...scription-interstitial-dialog.component.ts | 18 ++++++-- .../subscription-interstitial-dialog.html | 42 +++++++++++++++++++ .../user-account-membership.component.ts | 10 +---- .../user-account-membership.html | 5 ++- libs/common/src/lib/config.ts | 14 +++++++ 6 files changed, 78 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccdc8d5ddd..6e363e6b71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Extended the variations of the interstitials for the subscription by a trial - Deprecated the `api/v1/auth-device` endpoint in favor of the `api/v1/auth-devices` endpoint - Deprecated the `api/v1/exchange-rate` endpoint in favor of the `api/v1/exchange-rates` endpoint - Upgraded `@modelcontextprotocol/core` and `@modelcontextprotocol/server` from version `2.0.0` to `2.3.1` 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 d10be10bd0..08f4d203e3 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,3 +1,5 @@ +import { TRY_SUBSCRIPTION_MAIL_HREF } from '@ghostfolio/common/config'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfMembershipCardComponent } from '@ghostfolio/ui/membership-card'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; @@ -51,6 +53,7 @@ export class GfSubscriptionInterstitialDialogComponent implements OnInit { public remainingSkipButtonDelay = GfSubscriptionInterstitialDialogComponent.SKIP_BUTTON_DELAY_IN_SECONDS; public routerLinkPricing = publicRoutes.pricing.routerLink; + public trySubscriptionMailHref = TRY_SUBSCRIPTION_MAIL_HREF; public variantIndex: number; public constructor( @@ -59,9 +62,18 @@ export class GfSubscriptionInterstitialDialogComponent implements OnInit { private destroyRef: DestroyRef, public dialogRef: MatDialogRef ) { - this.variantIndex = Math.floor( - Math.random() * GfSubscriptionInterstitialDialogComponent.VARIANTS_COUNT - ); + const isEligibleForTrial = + !this.data.user?.subscription?.subscribedAt && + hasPermission( + this.data.user?.permissions, + permissions.updateUserSettings + ); + + const variantsCount = isEligibleForTrial + ? GfSubscriptionInterstitialDialogComponent.VARIANTS_COUNT + 1 + : GfSubscriptionInterstitialDialogComponent.VARIANTS_COUNT; + + this.variantIndex = Math.floor(Math.random() * variantsCount); addIcons({ arrowForwardOutline, checkmarkCircleOutline }); } 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 8280067a87..5bac0e9baa 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 @@ -195,4 +195,46 @@ } + @case (4) { +
+
+
+
+
+
+
+
+ Ghostfolio Premium + +
+
+ Request a free trial +
+

+ No credit card required. The trial ends automatically. +

+
+
+
+ + + Try Premium + + +
+ } } diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts index defe751ee8..20425d831e 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts @@ -1,5 +1,5 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { E_MAIL_LINE_BREAK } from '@ghostfolio/common/config'; +import { TRY_SUBSCRIPTION_MAIL_HREF } from '@ghostfolio/common/config'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { getDateFormatString } from '@ghostfolio/common/helper'; import { User } from '@ghostfolio/common/interfaces'; @@ -49,13 +49,7 @@ export class GfUserAccountMembershipComponent { protected hasPermissionToCreateApiKey: boolean; protected hasPermissionToUpdateUserSettings: boolean; protected price: number; - protected readonly trySubscriptionMailHref = `mailto:hi@ghostfol.io?subject=Ghostfolio Premium Trial&body=${[ - 'Hello', - '', - 'I am interested in Ghostfolio Premium. Can you please send me a coupon code to try it for some time?', - '', - 'Kind regards' - ].join(E_MAIL_LINE_BREAK)}`; + protected readonly trySubscriptionMailHref = TRY_SUBSCRIPTION_MAIL_HREF; protected user: User; private couponId: string | undefined; diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.html b/apps/client/src/app/components/user-account-membership/user-account-membership.html index f18da13ed9..336f386139 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.html +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -50,7 +50,10 @@ } }
- @if (!user?.subscription?.subscribedAt) { + @if ( + !user?.subscription?.subscribedAt && + hasPermissionToUpdateUserSettings + ) { { + return encodeURIComponent(line); + }) + .join(E_MAIL_LINE_BREAK)}`; + export const UNKNOWN_KEY = 'UNKNOWN';