fix: Handle trial ending without cancelation (#2651)
Resolves https://github.com/webrecorder/browsertrix/issues/2650 ## Changes Differentials between `trialing` and `trialing_canceled` when displaying messages: - No changes to messages if `trialing_canceled`. - If `trialing`, show messaging that subscription will automatically continue. --------- Co-authored-by: Ilya Kreymer <ikreymer@gmail.com> Co-authored-by: Ilya Kreymer <ikreymer@users.noreply.github.com>
This commit is contained in:
parent
223221c31e
commit
40ebbd11d3
@ -1,7 +1,9 @@
|
|||||||
import { localized, msg, str } from "@lit/localize";
|
import { localized, msg, str } from "@lit/localize";
|
||||||
|
import type { SlAlert } from "@shoelace-style/shoelace";
|
||||||
import { differenceInHours } from "date-fns/fp";
|
import { differenceInHours } from "date-fns/fp";
|
||||||
import { html, type TemplateResult } from "lit";
|
import { html, type TemplateResult } from "lit";
|
||||||
import { customElement } from "lit/decorators.js";
|
import { customElement } from "lit/decorators.js";
|
||||||
|
import { when } from "lit/directives/when.js";
|
||||||
|
|
||||||
import { BtrixElement } from "@/classes/BtrixElement";
|
import { BtrixElement } from "@/classes/BtrixElement";
|
||||||
import { SubscriptionStatus } from "@/types/billing";
|
import { SubscriptionStatus } from "@/types/billing";
|
||||||
@ -9,6 +11,7 @@ import { OrgReadOnlyReason } from "@/types/org";
|
|||||||
|
|
||||||
type Alert = {
|
type Alert = {
|
||||||
test: () => boolean;
|
test: () => boolean;
|
||||||
|
variant?: SlAlert["variant"];
|
||||||
content: () => {
|
content: () => {
|
||||||
title: string | TemplateResult;
|
title: string | TemplateResult;
|
||||||
detail: string | TemplateResult;
|
detail: string | TemplateResult;
|
||||||
@ -30,7 +33,7 @@ export class OrgStatusBanner extends BtrixElement {
|
|||||||
return html`
|
return html`
|
||||||
<div id="banner" class="border-b bg-slate-100 py-5">
|
<div id="banner" class="border-b bg-slate-100 py-5">
|
||||||
<div class="mx-auto box-border w-full max-w-screen-desktop px-3">
|
<div class="mx-auto box-border w-full max-w-screen-desktop px-3">
|
||||||
<sl-alert variant="danger" open>
|
<sl-alert variant=${alert.variant || "danger"} open>
|
||||||
<sl-icon slot="icon" name="exclamation-triangle-fill"></sl-icon>
|
<sl-icon slot="icon" name="exclamation-triangle-fill"></sl-icon>
|
||||||
<strong class="block font-semibold">${content.title}</strong>
|
<strong class="block font-semibold">${content.title}</strong>
|
||||||
${content.detail}
|
${content.detail}
|
||||||
@ -56,11 +59,12 @@ export class OrgStatusBanner extends BtrixElement {
|
|||||||
const {
|
const {
|
||||||
readOnly,
|
readOnly,
|
||||||
readOnlyReason,
|
readOnlyReason,
|
||||||
readOnlyOnCancel,
|
|
||||||
subscription,
|
subscription,
|
||||||
storageQuotaReached,
|
storageQuotaReached,
|
||||||
execMinutesQuotaReached,
|
execMinutesQuotaReached,
|
||||||
} = this.org;
|
} = this.org;
|
||||||
|
const readOnlyOnCancel =
|
||||||
|
subscription?.readOnlyOnCancel ?? this.org.readOnlyOnCancel;
|
||||||
|
|
||||||
let hoursDiff = 0;
|
let hoursDiff = 0;
|
||||||
let daysDiff = 0;
|
let daysDiff = 0;
|
||||||
@ -69,7 +73,7 @@ export class OrgStatusBanner extends BtrixElement {
|
|||||||
|
|
||||||
if (futureCancelDate) {
|
if (futureCancelDate) {
|
||||||
hoursDiff = differenceInHours(new Date(), new Date(futureCancelDate));
|
hoursDiff = differenceInHours(new Date(), new Date(futureCancelDate));
|
||||||
daysDiff = Math.trunc(hoursDiff / 24);
|
daysDiff = Math.ceil(hoursDiff / 24);
|
||||||
|
|
||||||
dateStr = this.localize.date(futureCancelDate, {
|
dateStr = this.localize.date(futureCancelDate, {
|
||||||
month: "long",
|
month: "long",
|
||||||
@ -80,14 +84,13 @@ export class OrgStatusBanner extends BtrixElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTrialingCanceled =
|
const isCancelingTrial =
|
||||||
subscription?.status == SubscriptionStatus.TrialingCanceled;
|
subscription?.status == SubscriptionStatus.TrialingCanceled;
|
||||||
const isTrial =
|
const isTrial =
|
||||||
subscription?.status === SubscriptionStatus.Trialing ||
|
subscription?.status === SubscriptionStatus.Trialing || isCancelingTrial;
|
||||||
isTrialingCanceled;
|
|
||||||
|
|
||||||
// show banner if < this many days of trial is left
|
// show banner if < this many days of trial is left
|
||||||
const MAX_TRIAL_DAYS_SHOW_BANNER = 4;
|
const MAX_TRIAL_DAYS_SHOW_BANNER = 8;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -125,8 +128,8 @@ export class OrgStatusBanner extends BtrixElement {
|
|||||||
!readOnlyOnCancel &&
|
!readOnlyOnCancel &&
|
||||||
!!futureCancelDate &&
|
!!futureCancelDate &&
|
||||||
((isTrial && daysDiff < MAX_TRIAL_DAYS_SHOW_BANNER) ||
|
((isTrial && daysDiff < MAX_TRIAL_DAYS_SHOW_BANNER) ||
|
||||||
isTrialingCanceled),
|
isCancelingTrial),
|
||||||
|
variant: isCancelingTrial ? "danger" : "warning",
|
||||||
content: () => {
|
content: () => {
|
||||||
return {
|
return {
|
||||||
title:
|
title:
|
||||||
@ -138,21 +141,32 @@ export class OrgStatusBanner extends BtrixElement {
|
|||||||
str`You have ${daysDiff} days left of your Browsertrix trial`,
|
str`You have ${daysDiff} days left of your Browsertrix trial`,
|
||||||
),
|
),
|
||||||
|
|
||||||
detail: html`
|
detail: html`<p>
|
||||||
<p>
|
${msg(str`Your free trial ends on ${dateStr}.`)}
|
||||||
${msg(
|
${isCancelingTrial
|
||||||
html`Your free trial ends on ${dateStr}. To continue using
|
? msg(
|
||||||
Browsertrix, select <strong>Subscribe Now</strong> in
|
html`To continue using Browsertrix, select
|
||||||
${billingTabLink}.`,
|
<strong>Subscribe Now</strong> in ${billingTabLink}.`,
|
||||||
)}
|
)
|
||||||
|
: html`${msg(
|
||||||
|
"Afterwards, your subscription will continue automatically.",
|
||||||
|
)}
|
||||||
|
${msg(
|
||||||
|
html`View and manage your subscription in
|
||||||
|
${billingTabLink}.`,
|
||||||
|
)}`}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
${when(
|
||||||
${msg(
|
isCancelingTrial,
|
||||||
str`Your web archives are always yours — you can download any archived items you'd like to keep
|
() => html`
|
||||||
|
<p>
|
||||||
|
${msg(
|
||||||
|
str`Your web archives are always yours — you can download any archived items you'd like to keep
|
||||||
before the trial ends!`,
|
before the trial ends!`,
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
`,
|
`,
|
||||||
|
)} `,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3,6 +3,7 @@ import { Task } from "@lit/task";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { css, html, nothing } from "lit";
|
import { css, html, nothing } from "lit";
|
||||||
import { customElement, property } from "lit/decorators.js";
|
import { customElement, property } from "lit/decorators.js";
|
||||||
|
import { choose } from "lit/directives/choose.js";
|
||||||
import { ifDefined } from "lit/directives/if-defined.js";
|
import { ifDefined } from "lit/directives/if-defined.js";
|
||||||
import { when } from "lit/directives/when.js";
|
import { when } from "lit/directives/when.js";
|
||||||
import capitalize from "lodash/fp/capitalize";
|
import capitalize from "lodash/fp/capitalize";
|
||||||
@ -38,11 +39,10 @@ export class OrgSettingsBilling extends BtrixElement {
|
|||||||
|
|
||||||
if (!subscription) return;
|
if (!subscription) return;
|
||||||
|
|
||||||
let label = msg("Manage Billing");
|
let label = msg("Manage Subscription");
|
||||||
|
|
||||||
switch (subscription.status) {
|
switch (subscription.status) {
|
||||||
case SubscriptionStatus.TrialingCanceled:
|
case SubscriptionStatus.TrialingCanceled: {
|
||||||
case SubscriptionStatus.Trialing: {
|
|
||||||
label = msg("Subscribe Now");
|
label = msg("Subscribe Now");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -86,6 +86,10 @@ export class OrgSettingsBilling extends BtrixElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const manageSubscriptionMessage = msg(
|
||||||
|
str`Click “${this.portalUrlLabel}” to view plan details, payment methods, and billing information.`,
|
||||||
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<section class="-mt-5">
|
<section class="-mt-5">
|
||||||
${columns([
|
${columns([
|
||||||
@ -131,6 +135,13 @@ export class OrgSettingsBilling extends BtrixElement {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const trialMessage = (detail?: string) => html`
|
||||||
|
<span class="font-medium text-neutral-700">
|
||||||
|
${msg(str`Your trial ends ${futureCancelDate}`)}
|
||||||
|
</span>
|
||||||
|
${when(detail, () => html`— ${detail}`)}
|
||||||
|
`;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
class="mb-3 flex items-center gap-2 border-b pb-3 text-neutral-500"
|
class="mb-3 flex items-center gap-2 border-b pb-3 text-neutral-500"
|
||||||
@ -140,22 +151,31 @@ export class OrgSettingsBilling extends BtrixElement {
|
|||||||
class="size-4 flex-shrink-0"
|
class="size-4 flex-shrink-0"
|
||||||
></sl-icon>
|
></sl-icon>
|
||||||
<div>
|
<div>
|
||||||
${org.subscription.status ===
|
${choose(
|
||||||
SubscriptionStatus.Trialing ||
|
org.subscription.status,
|
||||||
org.subscription.status ===
|
[
|
||||||
SubscriptionStatus.TrialingCanceled
|
[
|
||||||
? html`
|
SubscriptionStatus.Trialing,
|
||||||
<span class="font-medium text-neutral-700">
|
() =>
|
||||||
${msg(
|
trialMessage(
|
||||||
str`Your trial will end on ${futureCancelDate}`,
|
msg(
|
||||||
)}
|
"subscription will automatically continue",
|
||||||
</span>
|
),
|
||||||
—
|
),
|
||||||
${msg(str`subscribe to keep your account`)}
|
],
|
||||||
`
|
[
|
||||||
: msg(
|
SubscriptionStatus.TrialingCanceled,
|
||||||
|
() =>
|
||||||
|
trialMessage(
|
||||||
|
msg("subscribe to keep your account"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
() =>
|
||||||
|
html`${msg(
|
||||||
str`Your plan will be canceled on ${futureCancelDate}`,
|
str`Your plan will be canceled on ${futureCancelDate}`,
|
||||||
)}
|
)}`,
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -185,16 +205,30 @@ export class OrgSettingsBilling extends BtrixElement {
|
|||||||
${when(this.org, (org) =>
|
${when(this.org, (org) =>
|
||||||
org.subscription
|
org.subscription
|
||||||
? html` <p class="mb-3 leading-normal">
|
? html` <p class="mb-3 leading-normal">
|
||||||
${org.subscription.status ===
|
${choose(
|
||||||
SubscriptionStatus.Trialing ||
|
org.subscription.status,
|
||||||
org.subscription.status ===
|
[
|
||||||
SubscriptionStatus.TrialingCanceled
|
[
|
||||||
? msg(
|
SubscriptionStatus.Trialing,
|
||||||
str`To continue using Browsertrix at the end of your trial, click “${this.portalUrlLabel}”.`,
|
() => [
|
||||||
)
|
manageSubscriptionMessage,
|
||||||
: msg(
|
html`<br /><br />`,
|
||||||
str`You can view plan details, update payment methods, and update billing information by clicking “${this.portalUrlLabel}”.`,
|
msg(
|
||||||
)}
|
"You also have the ability to cancel your trial or permanently delete your account from the subscription portal.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
SubscriptionStatus.TrialingCanceled,
|
||||||
|
() => [
|
||||||
|
msg(
|
||||||
|
str`To continue using Browsertrix at the end of your trial, click “${this.portalUrlLabel}”.`,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
() => [manageSubscriptionMessage],
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
${this.salesEmail
|
${this.salesEmail
|
||||||
? html`<p class="leading-normal">
|
? html`<p class="leading-normal">
|
||||||
|
Loading…
Reference in New Issue
Block a user