Files
speckle-server/packages/frontend-2/components/settings/workspaces/billing/addOns/AddOns.vue
T
Kristaps Fabians Geikins 211922b6a6 chore: get rid of all old workspace plan code (#4624)
* first batch of changes

* tests fix

* FE fixed

* renaming constants

* test fixes

* moar test fixes

* another test fix

* reenable app rover check

---------

Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
2025-04-30 19:18:32 +02:00

123 lines
3.7 KiB
Vue

<template>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2">
<SettingsWorkspacesBillingAddOnsCard
title="Unlimited projects and models"
:subtitle="`${addonPrice} per editor/month`"
info="Power through with unlimited projects and models in your workspace."
disclaimer="Only on Starter & Business plans"
:button="unlimitedAddOnButton"
/>
<SettingsWorkspacesBillingAddOnsCard
title="Extra data regions"
:subtitle="`${currency === Currency.Gbp ? '£' : '$'}500 per region/month`"
info="Unlock per-project data residency by adding additional data regions to your workspace."
disclaimer="Only on Business plan"
:button="contactButton"
/>
<SettingsWorkspacesBillingAddOnsCard
title="Priority support"
subtitle="Talk to us"
info="White-glove treatment with private support channel, onboarding calls and more."
disclaimer="Only on Business plan"
:button="contactButton"
/>
<SettingsWorkspacesBillingUpgradeDialog
v-model:open="isUpgradeDialogOpen"
:slug="props.slug"
:plan="planToUpgrade"
:billing-interval="
intervalIsYearly ? BillingInterval.Yearly : BillingInterval.Monthly
"
:workspace-id="workspaceId"
/>
</div>
</template>
<script lang="ts" setup>
import { useWorkspacePlan } from '~~/lib/workspaces/composables/plan'
import { useWorkspaceAddonPrices } from '~/lib/billing/composables/prices'
import { formatPrice } from '~/lib/billing/helpers/plan'
import { PaidWorkspacePlans, type MaybeNullOrUndefined } from '@speckle/shared'
import { BillingInterval, Currency } from '~/lib/common/generated/gql/graphql'
import { useActiveWorkspace } from '~/lib/workspaces/composables/activeWorkspace'
import { useMixpanel } from '~~/lib/core/composables/mp'
const props = defineProps<{
slug: string
workspaceId: MaybeNullOrUndefined<string>
}>()
const {
isPaidPlan,
currency,
plan,
intervalIsYearly,
billingInterval,
hasUnlimitedAddon
} = useWorkspacePlan(props.slug)
const { addonPrices } = useWorkspaceAddonPrices()
const { isAdmin } = useActiveWorkspace(props.slug)
const mixpanel = useMixpanel()
const isUpgradeDialogOpen = ref(false)
const contactButton = computed(() => ({
text: 'Contact us',
id: 'contact-us',
disabled: !isAdmin.value,
onClick: () => {
window.location.href = 'mailto:billing@speckle.systems'
}
}))
const addOnButtonTooltip = computed(() => {
if (!isAdmin.value)
return 'You must be a workspace admin in order to purchase the add-on'
if (hasUnlimitedAddon.value)
return 'The add-on is already included in your subscription'
if (!isPaidPlan.value) return 'Only available for Starter & Business plans'
return undefined
})
const unlimitedAddOnButton = computed(() => ({
text: 'Buy add-on',
id: 'buy-add-on',
disabled: !isPaidPlan.value || hasUnlimitedAddon.value || !isAdmin.value,
disabledMessage: addOnButtonTooltip.value,
onClick: () => {
isUpgradeDialogOpen.value = true
mixpanel.track('Add-on CTA Clicked', {
plan: plan.value?.name,
cycle: billingInterval.value,
type: 'unlimited',
// eslint-disable-next-line camelcase
workspace_id: props.workspaceId
})
}
}))
const planToUpgrade = computed(() => {
return plan.value?.name === PaidWorkspacePlans.Team
? PaidWorkspacePlans.TeamUnlimited
: PaidWorkspacePlans.ProUnlimited
})
const addonPrice = computed(() => {
if (!plan.value) return null
const addonPrice =
addonPrices.value?.[currency.value]?.[plan.value.name as PaidWorkspacePlans]
if (!addonPrice) return null
return formatPrice({
amount: intervalIsYearly.value
? addonPrice.yearly.amount / 12
: addonPrice.monthly.amount,
currency: currency.value
})
})
</script>