Files
speckle-server/packages/frontend-2/components/viewer/limits/Dialog.vue
T

141 lines
4.7 KiB
Vue

<template>
<WorkspacePlanLimitReachedDialog
v-model:open="dialogOpen"
:buttons="buttons"
prevent-close
:condensed="isEmbedEnabled || undefined"
>
<template #header>{{ title }}</template>
<div class="mb-2">
<p>{{ message }}</p>
</div>
</WorkspacePlanLimitReachedDialog>
</template>
<script setup lang="ts">
import { Roles, type MaybeNullOrUndefined } from '@speckle/shared'
import type { LayoutDialogButton } from '@speckle/ui-components'
import { modelRoute, settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
import { useEmbed } from '~/lib/viewer/composables/setup/embed'
import { useWorkspaceLimits } from '~/lib/workspaces/composables/limits'
import { useMixpanel } from '~/lib/core/composables/mp'
import { useNavigation } from '~/lib/navigation/composables/navigation'
type LimitType = 'version' | 'comment' | 'federated'
const props = defineProps<{
limitType: LimitType
workspaceSlug: string
workspaceRole: MaybeNullOrUndefined<string>
projectId: string
resourceIdString: string
}>()
const { isEnabled: isEmbedEnabled } = useEmbed()
const { versionLimitFormatted } = useWorkspaceLimits(props.workspaceSlug)
const mixpanel = useMixpanel()
const { mutateActiveWorkspaceSlug } = useNavigation()
const dialogOpen = defineModel<boolean>('open', {
required: true
})
const title = computed(() => {
switch (props.limitType) {
case 'version':
return 'Plan limit reached'
case 'federated':
return "The federated models couldn't be loaded"
case 'comment':
return 'The comment could not be loaded'
default:
return 'Plan limit reached'
}
})
const message = computed(() => {
switch (props.limitType) {
case 'version':
return `The version you're trying to load is older than the ${versionLimitFormatted.value} version history limit allowed by your workspace plan. Upgrade your workspace plan to gain access.`
case 'federated':
return `One of the models is older than the ${versionLimitFormatted.value}-day version history limit allowed by your workspace plan. Upgrade your workspace plan to gain access.`
case 'comment':
return `Unable to load the comment because one or more of the referenced models is older than the ${versionLimitFormatted.value}-day version history limit. Upgrade your workspace plan to gain access.`
default:
return "You've reached the limit of your plan. Please upgrade to continue."
}
})
const stripVersionIds = (resourceIdString: string) => {
const resources = resourceIdString.split(',')
// For each resource, remove @versionId if present
const cleanedResources = resources.map((resource) => {
const atIndex = resource.indexOf('@')
return atIndex > -1 ? resource.substring(0, atIndex) : resource
})
return cleanedResources.join(',')
}
const loadLatestButton = (isPrimary = true): LayoutDialogButton => ({
text: 'Load latest version',
props: {
color: isPrimary ? 'primary' : 'outline'
},
onClick: () => {
mixpanel.track('Load Latest Version Button Clicked', {
location: 'viewer',
// eslint-disable-next-line camelcase
workspace_id: props.workspaceSlug
})
const latestResourceIdString = stripVersionIds(props.resourceIdString)
// Use the modelRoute but with the cleaned resource string that has no version IDs
navigateTo(modelRoute(props.projectId, latestResourceIdString))
}
})
const explorePlansButton: LayoutDialogButton = {
text: 'Explore plans',
disabled: props.workspaceRole === Roles.Workspace.Guest,
disabledMessage: 'As a Guest you cannot access plans and billing',
onClick: () => {
mixpanel.track('Limit Reached Dialog Upgrade Button Clicked', {
type: props.limitType === 'version' ? 'version' : 'model',
location: 'viewer',
// eslint-disable-next-line camelcase
workspace_id: props.workspaceSlug
})
mutateActiveWorkspaceSlug(props.workspaceSlug)
return navigateTo(settingsWorkspaceRoutes.billing.route(props.workspaceSlug || ''))
}
}
const buttons = computed((): LayoutDialogButton[] => {
const buttons: Record<LimitType, LayoutDialogButton[]> = {
version: isEmbedEnabled.value
? [loadLatestButton(false)]
: [loadLatestButton(false), explorePlansButton],
federated: isEmbedEnabled.value
? [loadLatestButton(false)]
: [loadLatestButton(false), explorePlansButton],
comment: [loadLatestButton(true)]
}
return buttons[props.limitType]
})
watch(dialogOpen, (value) => {
if (value) {
mixpanel.track('Limit Reached Dialog Viewed', {
type: props.limitType === 'version' ? 'version' : 'model',
location: 'viewer',
// eslint-disable-next-line camelcase
workspace_id: props.workspaceSlug,
limitType: props.limitType
})
}
})
</script>