Skip to content

Commit

Permalink
Trial reactivation UX (#2962)
Browse files Browse the repository at this point in the history
* Updates account messaging to support trial reactivation

* Polishes and improved messaging
  • Loading branch information
axosoft-ramint authored Oct 11, 2023
1 parent a70e2b9 commit e03275f
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/commands/showView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class ShowViewCommand extends Command {
Commands.ShowFileHistoryView,
Commands.ShowGraphView,
Commands.ShowHomeView,
Commands.ShowAccountView,
Commands.ShowLineHistoryView,
Commands.ShowRemotesView,
Commands.ShowRepositoriesView,
Expand Down
31 changes: 24 additions & 7 deletions src/plus/subscription/subscriptionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export class SubscriptionService implements Disposable {
actual: getSubscriptionPlan(
SubscriptionPlanId.Free,
false,
0,
undefined,
this._subscription.plan?.actual?.startedOn != null
? new Date(this._subscription.plan.actual.startedOn)
Expand All @@ -312,6 +313,7 @@ export class SubscriptionService implements Disposable {
effective: getSubscriptionPlan(
SubscriptionPlanId.Free,
false,
0,
undefined,
this._subscription.plan?.effective?.startedOn != null
? new Date(this._subscription.plan.actual.startedOn)
Expand Down Expand Up @@ -462,7 +464,7 @@ export class SubscriptionService implements Disposable {
...this._subscription,
plan: {
...this._subscription.plan,
effective: getSubscriptionPlan(SubscriptionPlanId.Pro, false, undefined, startedOn, expiresOn),
effective: getSubscriptionPlan(SubscriptionPlanId.Pro, false, 0, undefined, startedOn, expiresOn),
},
previewTrial: previewTrial,
});
Expand Down Expand Up @@ -632,6 +634,7 @@ export class SubscriptionService implements Disposable {
actual = getSubscriptionPlan(
convertLicenseTypeToPlanId(licenseType),
isBundleLicenseType(licenseType),
license.reactivationCount ?? 0,
license.organizationId,
new Date(license.latestStartDate),
new Date(license.latestEndDate),
Expand All @@ -643,6 +646,7 @@ export class SubscriptionService implements Disposable {
actual = getSubscriptionPlan(
SubscriptionPlanId.FreePlus,
false,
0,
undefined,
data.user.firstGitLensCheckIn != null
? new Date(data.user.firstGitLensCheckIn)
Expand All @@ -668,6 +672,7 @@ export class SubscriptionService implements Disposable {
effective = getSubscriptionPlan(
convertLicenseTypeToPlanId(licenseType),
isBundleLicenseType(licenseType),
license.reactivationCount ?? 0,
license.organizationId,
new Date(license.latestStartDate),
new Date(license.latestEndDate),
Expand Down Expand Up @@ -825,8 +830,8 @@ export class SubscriptionService implements Disposable {
if (subscription == null) {
subscription = {
plan: {
actual: getSubscriptionPlan(SubscriptionPlanId.Free, false, undefined),
effective: getSubscriptionPlan(SubscriptionPlanId.Free, false, undefined),
actual: getSubscriptionPlan(SubscriptionPlanId.Free, false, 0, undefined),
effective: getSubscriptionPlan(SubscriptionPlanId.Free, false, 0, undefined),
},
account: undefined,
state: SubscriptionState.Free,
Expand Down Expand Up @@ -857,6 +862,7 @@ export class SubscriptionService implements Disposable {
effective: getSubscriptionPlan(
SubscriptionPlanId.Pro,
false,
0,
undefined,
new Date(subscription.previewTrial.startedOn),
new Date(subscription.previewTrial.expiresOn),
Expand Down Expand Up @@ -999,6 +1005,7 @@ export class SubscriptionService implements Disposable {
const {
account,
plan: { effective },
state,
} = this._subscription;

if (effective.id === SubscriptionPlanId.Free) {
Expand All @@ -1023,7 +1030,7 @@ export class SubscriptionService implements Disposable {
}

this._statusBarSubscription.name = 'GitKraken Subscription';
this._statusBarSubscription.command = Commands.ShowHomeView;
this._statusBarSubscription.command = Commands.ShowAccountView;

if (account?.verified === false) {
this._statusBarSubscription.text = `$(warning) ${effective.name} (Unverified)`;
Expand All @@ -1038,12 +1045,21 @@ export class SubscriptionService implements Disposable {
);
} else {
const remaining = getSubscriptionTimeRemaining(this._subscription, 'days');
const isReactivatedTrial =
state === SubscriptionState.FreePlusInTrial && effective.trialReactivationCount > 0;

this._statusBarSubscription.text = `${effective.name} (Trial)`;
this._statusBarSubscription.tooltip = new MarkdownString(
`You have ${pluralize('day', remaining ?? 0)} left in your free **${
effective.name
}** trial, which gives you additional access to Pro features on privately hosted repos.\n\nClick for details`,
`${
isReactivatedTrial
? `[See what's new](https://help.gitkraken.com/gitlens/gitlens-release-notes-current/) with
${pluralize('day', remaining ?? 0, {
infix: ' more ',
})}
in your **${effective.name}** trial.`
: `You have ${pluralize('day', remaining ?? 0)} remaining in your **${effective.name}** trial.`
} Once your trial ends, you'll need a paid plan to continue using ✨ features.\n\nTry our
[other developer tools](https://www.gitkraken.com/suite) also included in your trial.`,
true,
);
}
Expand Down Expand Up @@ -1095,6 +1111,7 @@ interface GKLicense {
readonly latestStartDate: string;
readonly latestEndDate: string;
readonly organizationId: string | undefined;
readonly reactivationCount?: number;
}

type GKLicenseType =
Expand Down
3 changes: 3 additions & 0 deletions src/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface SubscriptionPlan {
readonly id: SubscriptionPlanId;
readonly name: string;
readonly bundle: boolean;
readonly trialReactivationCount: number;
readonly cancelled: boolean;
readonly startedOn: string;
readonly expiresOn?: string | undefined;
Expand Down Expand Up @@ -112,6 +113,7 @@ export function computeSubscriptionState(subscription: Optional<Subscription, 's
export function getSubscriptionPlan(
id: SubscriptionPlanId,
bundle: boolean,
trialReactivationCount: number,
organizationId: string | undefined,
startedOn?: Date,
expiresOn?: Date,
Expand All @@ -123,6 +125,7 @@ export function getSubscriptionPlan(
bundle: bundle,
cancelled: cancelled,
organizationId: organizationId,
trialReactivationCount: trialReactivationCount,
startedOn: (startedOn ?? new Date()).toISOString(),
expiresOn: expiresOn != null ? expiresOn.toISOString() : undefined,
};
Expand Down
2 changes: 1 addition & 1 deletion src/webviews/apps/plus/account/account.scss
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ body {
}

account-content {
margin-top: 1.3rem;
margin-top: 0.3rem;
margin-bottom: 1.3rem;
}

Expand Down
1 change: 1 addition & 0 deletions src/webviews/apps/plus/account/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export class AccountApp extends App<State> {
$content.state = subscription.state;
$content.plan = subscription.plan.effective.name;
$content.days = days;
$content.trialReactivationCount = subscription.plan.effective.trialReactivationCount;
}
}

Expand Down
32 changes: 28 additions & 4 deletions src/webviews/apps/plus/account/components/account-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ export class AccountContent extends LitElement {
@property()
plan = '';

@property({ type: Number })
trialReactivationCount = 0;

get daysRemaining() {
if (this.days < 1) {
return '<1 day';
Expand Down Expand Up @@ -122,6 +125,10 @@ export class AccountContent extends LitElement {
return hasAccountFromSubscriptionState(this.state);
}

get isReactivatedTrial() {
return this.state === SubscriptionState.FreePlusInTrial && this.trialReactivationCount > 0;
}

private renderAccountInfo() {
if (!this.hasAccount) {
return nothing;
Expand Down Expand Up @@ -192,15 +199,28 @@ export class AccountContent extends LitElement {
case SubscriptionState.FreePlusInTrial:
return html`
<p>
Your have ${this.daysRemaining} remaining in your GitKraken trial. Once your trial ends, you'll
need a paid plan to continue using ✨ features.
${this.isReactivatedTrial
? html`<a href="https://help.gitkraken.com/gitlens/gitlens-release-notes-current/"
>See what's new</a
>
with
${pluralize('day', this.days, {
infix: ' more ',
})}
in your GitKraken trial.`
: `You have
${this.daysRemaining} remaining in your GitKraken trial.`}
Once your trial ends, you'll need a paid plan to continue using ✨ features.
</p>
<button-container>
<gl-button full href="command:gitlens.plus.purchase">Upgrade to Pro</gl-button>
</button-container>
<p>
You have access to ✨ features on privately hosted repos and ☁️ features based on the Pro plan
during your trial.
You have access to ✨ features on privately hosted repos and ☁️ features based on the Pro plan.
</p>
<p>
Try our
<a href="https://www.gitkraken.com/suite">other developer tools</a> also included in your trial.
</p>
`;

Expand All @@ -212,6 +232,10 @@ export class AccountContent extends LitElement {
>
</button-container>
<p>You have access to ✨ features on privately hosted repos and ☁️ features based on your plan.</p>
<p>
Try our
<a href="https://www.gitkraken.com/suite">other developer tools</a> also included in your plan.
</p>
`;
}

Expand Down

0 comments on commit e03275f

Please sign in to comment.