Skip to content

Commit

Permalink
Fix: Updates to trial expired state (#3762)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikehrn authored Jan 3, 2025
1 parent 457c532 commit 5024ebb
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 39 deletions.
2 changes: 1 addition & 1 deletion packages/frontend-2/components/billing/Alert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<template v-if="!hasValidPlan">
<div
v-if="condensed"
class="flex items-center justify-between rounded-md p-2 pl-3 text-body-3xs font-medium bg-info-lighter text-primary-focus"
class="flex items-center justify-between rounded-md p-2 pl-3 text-body-3xs font-medium bg-info-lighter text-primary-focus gap-x-2"
>
{{ title }}
<FormButton
Expand Down
1 change: 1 addition & 0 deletions packages/frontend-2/components/dashboard/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
:active="isActive(item.to)"
:tag="
item.plan.status === WorkspacePlanStatuses.Trial ||
item.plan.status === WorkspacePlanStatuses.Expired ||
!item.plan.status
? 'TRIAL'
: undefined
Expand Down
1 change: 1 addition & 0 deletions packages/frontend-2/components/settings/Dialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
class="workspace-item"
:tag="
workspaceItem.plan?.status === WorkspacePlanStatuses.Trial ||
workspaceItem.plan?.status === WorkspacePlanStatuses.Expired ||
!workspaceItem.plan?.status
? 'TRIAL'
: undefined
Expand Down
113 changes: 82 additions & 31 deletions packages/frontend-2/components/settings/workspaces/Billing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
>
<div class="p-5 pt-4 flex flex-col gap-y-1">
<h3 class="text-body-xs text-foreground-2 pb-1">
{{ statusIsTrial ? 'Trial plan' : 'Current plan' }}
{{ summaryPlanHeading }}
</h3>
<div class="flex gap-x-2">
<p class="text-heading-lg text-foreground">
Expand All @@ -28,7 +28,7 @@
</span>
</p>
<div>
<CommonBadge v-if="statusIsTrial" rounded>TRIAL</CommonBadge>
<CommonBadge v-if="showStatusBadge" rounded>TRIAL</CommonBadge>
</div>
</div>
<p v-if="isPurchasablePlan" class="text-body-xs text-foreground-2">
Expand All @@ -38,6 +38,11 @@
</span>
Free
</span>
<span
v-else-if="currentPlan?.status === WorkspacePlanStatuses.Expired"
>
£{{ seatPrice[Roles.Workspace.Member] }} per seat/month
</span>
<span v-else>
£{{ seatPrice[Roles.Workspace.Member] }} per seat/month, billed
{{
Expand All @@ -51,24 +56,18 @@
<div class="p-5 pt-4 flex flex-col gap-y-1">
<template v-if="isPurchasablePlan || statusIsTrial">
<h3 class="text-body-xs text-foreground-2 pb-1">
{{
statusIsTrial
? 'Expected bill'
: subscription?.billingInterval === BillingInterval.Yearly
? 'Annual bill'
: 'Monthly bill'
}}
{{ summaryBillHeading }}
</h3>
<p class="text-heading-lg text-foreground inline-block">
{{ billValue }} per
{{ summaryBillValue }} per
{{
subscription?.billingInterval === BillingInterval.Yearly
? 'year'
: 'month'
}}
</p>
<p class="text-body-xs text-foreground-2 flex gap-x-1 items-center">
{{ billDescription }}
{{ summaryBillDescription }}
<InformationCircleIcon
v-tippy="billTooltip"
class="w-4 h-4 text-foreground cursor-pointer"
Expand All @@ -84,18 +83,15 @@
</div>
<div class="p-5 pt-4 flex flex-col gap-y-1">
<h3 class="text-body-xs text-foreground-2 pb-1">
{{
statusIsTrial && isPurchasablePlan
? 'Trial ends'
: statusIsCanceled
? 'Cancels'
: 'Next payment due'
}}
{{ summaryDateHeading }}
</h3>
<p class="text-heading-lg text-foreground capitalize">
{{ isPurchasablePlan ? nextPaymentDue : 'Never' }}
</p>
<p v-if="isPurchasablePlan" class="text-body-xs text-foreground-2">
<p
v-if="showSummaryDateDescription"
class="text-body-xs text-foreground-2"
>
<span v-if="statusIsTrial">Subscribe before this date</span>
<span v-else>
{{
Expand Down Expand Up @@ -125,11 +121,7 @@
</div>
</div>

<SettingsSectionHeader
:title="statusIsTrial ? 'Start your subscription' : 'Upgrade your plan'"
subheading
class="pt-4"
/>
<SettingsSectionHeader :title="pricingTableHeading" subheading class="pt-4" />
<SettingsWorkspacesBillingPricingTable
v-if="isPurchasablePlan || statusIsTrial"
:workspace-id="workspaceId"
Expand Down Expand Up @@ -262,15 +254,14 @@ const statusIsTrial = computed(
currentPlan.value?.status === WorkspacePlanStatuses.Trial ||
!currentPlan.value?.status
)
const statusIsCanceled = computed(
() => currentPlan.value?.status === WorkspacePlanStatuses.Canceled
)
const isActivePlan = computed(
() =>
currentPlan.value &&
currentPlan.value?.status !== WorkspacePlanStatuses.Trial &&
currentPlan.value?.status !== WorkspacePlanStatuses.Canceled
currentPlan.value?.status !== WorkspacePlanStatuses.Canceled &&
currentPlan.value?.status !== WorkspacePlanStatuses.Expired
)
const isAcademiaPlan = computed(
() => currentPlan.value?.name === WorkspacePlans.Academia
)
Expand Down Expand Up @@ -303,14 +294,14 @@ const memberSeatCount = computed(() =>
? workspace.value.team.items.length - guestSeatCount.value
: 0
)
const billValue = computed(() => {
const summaryBillValue = computed(() => {
const guestPrice = seatPrice.value[Roles.Workspace.Guest] * guestSeatCount.value
const memberPrice = seatPrice.value[Roles.Workspace.Member] * memberSeatCount.value
const totalPrice = guestPrice + memberPrice
const isAnnual = subscription.value?.billingInterval === BillingInterval.Yearly
return isPurchasablePlan.value ? `£${isAnnual ? totalPrice * 12 : totalPrice}` : '£0'
})
const billDescription = computed(() => {
const summaryBillDescription = computed(() => {
const memberText =
memberSeatCount.value > 1 ? `${memberSeatCount.value} members` : '1 member'
const guestText =
Expand All @@ -328,12 +319,72 @@ const billTooltip = computed(() => {
return `${memberText}${guestSeatCount.value > 0 ? `, ${guestText}` : ''}`
})
const summaryPlanHeading = computed(() => {
switch (currentPlan.value?.status) {
case WorkspacePlanStatuses.Trial:
return 'Trial plan'
case WorkspacePlanStatuses.Expired:
case WorkspacePlanStatuses.Canceled:
return 'Plan'
default:
return 'Current plan'
}
})
const summaryBillHeading = computed(() => {
switch (currentPlan.value?.status) {
case WorkspacePlanStatuses.Trial:
case WorkspacePlanStatuses.Expired:
case WorkspacePlanStatuses.Canceled:
return 'Expected bill'
default:
return subscription.value?.billingInterval === BillingInterval.Yearly
? 'Annual bill'
: 'Monthly bill'
}
})
const summaryDateHeading = computed(() => {
if (statusIsTrial.value && isPurchasablePlan.value) {
return 'Trial ends'
} else if (currentPlan.value?.status === WorkspacePlanStatuses.Expired) {
return 'Trial expired at'
} else if (currentPlan.value?.status === WorkspacePlanStatuses.Canceled) {
return 'Cancels'
} else {
return 'Next payment due'
}
})
const showSummaryDateDescription = computed(() => {
return statusIsTrial.value && isPurchasablePlan.value
})
const pricingTableHeading = computed(() => {
switch (currentPlan.value?.status) {
case WorkspacePlanStatuses.Trial:
case WorkspacePlanStatuses.Expired:
return 'Start your subscription'
case WorkspacePlanStatuses.Canceled:
return 'Restart your subscription'
default:
return 'Upgrade your plan'
}
})
const showStatusBadge = computed(() => {
return (
(statusIsTrial.value ||
currentPlan.value?.status === WorkspacePlanStatuses.Expired) &&
isPurchasablePlan.value
)
})
const onPlanSelected = (plan: { name: WorkspacePlans; cycle: BillingInterval }) => {
const { name, cycle } = plan
if (!isPaidPlan(name) || !props.workspaceId) return
if (statusIsTrial.value) {
if (
statusIsTrial.value ||
currentPlan.value?.status === WorkspacePlanStatuses.Expired ||
currentPlan.value?.status === WorkspacePlanStatuses.Canceled
) {
mixpanel.track('Workspace Subscribe Button Clicked', {
plan,
cycle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,13 @@ const isMonthlyToAnnual = computed(() => {
const isSelectable = computed(() => {
if (!props.isAdmin) return false
// Always enable buttons during trial
if (statusIsTrial.value) return true
// Always enable buttons during trial, expired or canceled state
if (
statusIsTrial.value ||
props.currentPlan?.status === WorkspacePlanStatuses.Expired ||
props.currentPlan?.status === WorkspacePlanStatuses.Canceled
)
return true
// Allow selection if switching from monthly to yearly for the same plan
if (isMonthlyToAnnual.value && props.currentPlan?.name === props.plan.name)
Expand All @@ -213,15 +218,22 @@ const isSelectable = computed(() => {
})
const buttonColor = computed(() => {
if (statusIsTrial.value) {
if (
statusIsTrial.value ||
props.currentPlan?.status === WorkspacePlanStatuses.Expired
) {
return props.plan.name === WorkspacePlans.Starter ? 'primary' : 'outline'
}
return 'outline'
})
const buttonText = computed(() => {
// Trial plan case
if (statusIsTrial.value) {
// Allow selection during trial, expired or canceled state
if (
statusIsTrial.value ||
props.currentPlan?.status === WorkspacePlanStatuses.Expired ||
props.currentPlan?.status === WorkspacePlanStatuses.Canceled
) {
return `Subscribe to ${startCase(props.plan.name)}`
}
// Current plan case
Expand All @@ -248,7 +260,13 @@ const buttonTooltip = computed(() => {
return 'You must be a workspace admin.'
}
if (statusIsTrial.value || isCurrentPlan.value) return
if (
statusIsTrial.value ||
isCurrentPlan.value ||
props.currentPlan?.status === WorkspacePlanStatuses.Expired ||
props.currentPlan?.status === WorkspacePlanStatuses.Canceled
)
return undefined
if (isDowngrade.value) {
return 'Downgrading is not supported at the moment. Please contact billing@speckle.systems.'
Expand Down
6 changes: 5 additions & 1 deletion packages/frontend-2/components/workspace/header/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,18 @@ const isWorkspaceGuest = computed(
() => props.workspaceInfo.role === Roles.Workspace.Guest
)
const billingAlertAction = computed<Array<AlertAction>>(() => {
if (isInTrial.value && isWorkspaceAdmin.value) {
if (
(isInTrial.value && isWorkspaceAdmin.value) ||
props.workspaceInfo.plan?.status === WorkspacePlanStatuses.Expired
) {
return [
{
title: 'Subscribe',
onClick: () => openSettingsDialog(SettingMenuKeys.Workspace.Billing)
}
]
}
return []
})
Expand Down

0 comments on commit 5024ebb

Please sign in to comment.