Skip to content
58 changes: 36 additions & 22 deletions frontend/src/features/org/org-status-banner.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { localized, msg, str } from "@lit/localize";
import type { SlAlert } from "@shoelace-style/shoelace";
import { differenceInHours } from "date-fns/fp";
import { html, type TemplateResult } from "lit";
import { customElement } from "lit/decorators.js";
import { when } from "lit/directives/when.js";

import { BtrixElement } from "@/classes/BtrixElement";
import { SubscriptionStatus } from "@/types/billing";
import { OrgReadOnlyReason } from "@/types/org";

type Alert = {
test: () => boolean;
variant?: SlAlert["variant"];
content: () => {
title: string | TemplateResult;
detail: string | TemplateResult;
Expand All @@ -30,7 +33,7 @@ export class OrgStatusBanner extends BtrixElement {
return html`
<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">
<sl-alert variant="danger" open>
<sl-alert variant=${alert.variant || "danger"} open>
<sl-icon slot="icon" name="exclamation-triangle-fill"></sl-icon>
<strong class="block font-semibold">${content.title}</strong>
${content.detail}
Expand All @@ -56,11 +59,12 @@ export class OrgStatusBanner extends BtrixElement {
const {
readOnly,
readOnlyReason,
readOnlyOnCancel,
subscription,
storageQuotaReached,
execMinutesQuotaReached,
} = this.org;
const readOnlyOnCancel =
subscription?.readOnlyOnCancel ?? this.org.readOnlyOnCancel;

let hoursDiff = 0;
let daysDiff = 0;
Expand All @@ -69,7 +73,7 @@ export class OrgStatusBanner extends BtrixElement {

if (futureCancelDate) {
hoursDiff = differenceInHours(new Date(), new Date(futureCancelDate));
daysDiff = Math.trunc(hoursDiff / 24);
daysDiff = Math.ceil(hoursDiff / 24);

dateStr = this.localize.date(futureCancelDate, {
month: "long",
Expand All @@ -80,14 +84,13 @@ export class OrgStatusBanner extends BtrixElement {
});
}

const isTrialingCanceled =
const isCancelingTrial =
subscription?.status == SubscriptionStatus.TrialingCanceled;
const isTrial =
subscription?.status === SubscriptionStatus.Trialing ||
isTrialingCanceled;
subscription?.status === SubscriptionStatus.Trialing || isCancelingTrial;

// 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 [
{
Expand Down Expand Up @@ -125,8 +128,8 @@ export class OrgStatusBanner extends BtrixElement {
!readOnlyOnCancel &&
!!futureCancelDate &&
((isTrial && daysDiff < MAX_TRIAL_DAYS_SHOW_BANNER) ||
isTrialingCanceled),

isCancelingTrial),
variant: isCancelingTrial ? "danger" : "warning",
content: () => {
return {
title:
Expand All @@ -138,21 +141,32 @@ export class OrgStatusBanner extends BtrixElement {
str`You have ${daysDiff} days left of your Browsertrix trial`,
),

detail: html`
<p>
${msg(
html`Your free trial ends on ${dateStr}. To continue using
Browsertrix, select <strong>Subscribe Now</strong> in
${billingTabLink}.`,
)}
detail: html`<p>
${msg(str`Your free trial ends on ${dateStr}.`)}
${isCancelingTrial
? msg(
html`To continue using Browsertrix, select
<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>
${msg(
str`Your web archives are always yours — you can download any archived items you'd like to keep
${when(
isCancelingTrial,
() => 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!`,
)}
</p>
`,
)}
</p>
`,
)} `,
};
},
},
Expand Down
90 changes: 62 additions & 28 deletions frontend/src/pages/org/settings/components/billing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Task } from "@lit/task";
import clsx from "clsx";
import { css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { choose } from "lit/directives/choose.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { when } from "lit/directives/when.js";
import capitalize from "lodash/fp/capitalize";
Expand Down Expand Up @@ -38,11 +39,10 @@ export class OrgSettingsBilling extends BtrixElement {

if (!subscription) return;

let label = msg("Manage Billing");
let label = msg("Manage Subscription");

switch (subscription.status) {
case SubscriptionStatus.TrialingCanceled:
case SubscriptionStatus.Trialing: {
case SubscriptionStatus.TrialingCanceled: {
label = msg("Subscribe Now");
break;
}
Expand Down Expand Up @@ -86,6 +86,10 @@ export class OrgSettingsBilling extends BtrixElement {
});

render() {
const manageSubscriptionMessage = msg(
str`Click “${this.portalUrlLabel}” to view plan details, payment methods, and billing information.`,
);

return html`
<section class="-mt-5">
${columns([
Expand Down Expand Up @@ -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`&mdash; ${detail}`)}
`;

return html`
<div
class="mb-3 flex items-center gap-2 border-b pb-3 text-neutral-500"
Expand All @@ -140,22 +151,31 @@ export class OrgSettingsBilling extends BtrixElement {
class="size-4 flex-shrink-0"
></sl-icon>
<div>
${org.subscription.status ===
SubscriptionStatus.Trialing ||
org.subscription.status ===
SubscriptionStatus.TrialingCanceled
? html`
<span class="font-medium text-neutral-700">
${msg(
str`Your trial will end on ${futureCancelDate}`,
)}
</span>
&mdash;
${msg(str`subscribe to keep your account`)}
`
: msg(
${choose(
org.subscription.status,
[
[
SubscriptionStatus.Trialing,
() =>
trialMessage(
msg(
"subscription will automatically continue",
),
),
],
[
SubscriptionStatus.TrialingCanceled,
() =>
trialMessage(
msg("subscribe to keep your account"),
),
],
],
() =>
html`${msg(
str`Your plan will be canceled on ${futureCancelDate}`,
)}
)}`,
)}
</div>
</div>
`;
Expand Down Expand Up @@ -185,16 +205,30 @@ export class OrgSettingsBilling extends BtrixElement {
${when(this.org, (org) =>
org.subscription
? html` <p class="mb-3 leading-normal">
${org.subscription.status ===
SubscriptionStatus.Trialing ||
org.subscription.status ===
SubscriptionStatus.TrialingCanceled
? msg(
str`To continue using Browsertrix at the end of your trial, click “${this.portalUrlLabel}”.`,
)
: msg(
str`You can view plan details, update payment methods, and update billing information by clicking “${this.portalUrlLabel}”.`,
)}
${choose(
org.subscription.status,
[
[
SubscriptionStatus.Trialing,
() => [
manageSubscriptionMessage,
html`<br /><br />`,
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>
${this.salesEmail
? html`<p class="leading-normal">
Expand Down
Loading