Feat: Add seats and estimated bill (#3684)
This commit is contained in:
@@ -68,6 +68,16 @@ export type AdminInviteList = {
|
||||
totalCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type AdminMutations = {
|
||||
__typename?: 'AdminMutations';
|
||||
updateWorkspacePlan: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
|
||||
export type AdminMutationsUpdateWorkspacePlanArgs = {
|
||||
input: AdminUpdateWorkspacePlanInput;
|
||||
};
|
||||
|
||||
export type AdminQueries = {
|
||||
__typename?: 'AdminQueries';
|
||||
inviteList: AdminInviteList;
|
||||
@@ -108,6 +118,12 @@ export type AdminQueriesWorkspaceListArgs = {
|
||||
query?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type AdminUpdateWorkspacePlanInput = {
|
||||
plan: WorkspacePlans;
|
||||
status: WorkspacePlanStatuses;
|
||||
workspaceId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type AdminUserList = {
|
||||
__typename?: 'AdminUserList';
|
||||
cursor?: Maybe<Scalars['String']['output']>;
|
||||
@@ -1240,6 +1256,7 @@ export type Mutation = {
|
||||
_?: Maybe<Scalars['String']['output']>;
|
||||
/** Various Active User oriented mutations */
|
||||
activeUserMutations: ActiveUserMutations;
|
||||
admin: AdminMutations;
|
||||
adminDeleteUser: Scalars['Boolean']['output'];
|
||||
/** Creates an personal api token. */
|
||||
apiTokenCreate: Scalars['String']['output'];
|
||||
@@ -4535,9 +4552,16 @@ export type WorkspaceSubscription = {
|
||||
billingInterval: BillingInterval;
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
currentBillingCycleEnd: Scalars['DateTime']['output'];
|
||||
seats: WorkspaceSubscriptionSeats;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
|
||||
export type WorkspaceSubscriptionSeats = {
|
||||
__typename?: 'WorkspaceSubscriptionSeats';
|
||||
guest: Scalars['Int']['output'];
|
||||
plan: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type WorkspaceTeamFilter = {
|
||||
/** Limit team members to provided role(s) */
|
||||
roles?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
|
||||
@@ -345,7 +345,7 @@ const documents = {
|
||||
"\n fragment LinkableComment on Comment {\n id\n viewerResources {\n modelId\n versionId\n objectId\n }\n }\n": types.LinkableCommentFragmentDoc,
|
||||
"\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n workspaceSlug\n user {\n id\n }\n }\n": types.UseWorkspaceInviteManager_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n }\n": types.WorkspaceMixpanelUpdateGroup_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n plan {\n status\n name\n createdAt\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n defaultRegion {\n key\n }\n }\n": types.WorkspaceMixpanelUpdateGroup_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n plan {\n status\n name\n createdAt\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n defaultRegion {\n key\n }\n }\n": types.WorkspaceMixpanelUpdateGroup_WorkspaceFragmentDoc,
|
||||
"\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": types.OnWorkspaceProjectsUpdateDocument,
|
||||
"\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n": types.WorkspaceHasCustomDataResidency_WorkspaceFragmentDoc,
|
||||
"\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n": types.CheckProjectWorkspaceDataResidencyDocument,
|
||||
@@ -1725,7 +1725,7 @@ export function graphql(source: "\n fragment WorkspaceMixpanelUpdateGroup_Works
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n plan {\n status\n name\n createdAt\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n defaultRegion {\n key\n }\n }\n"): (typeof documents)["\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n plan {\n status\n name\n createdAt\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n defaultRegion {\n key\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n plan {\n status\n name\n createdAt\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n defaultRegion {\n key\n }\n }\n"): (typeof documents)["\n fragment WorkspaceMixpanelUpdateGroup_Workspace on Workspace {\n id\n name\n description\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n plan {\n status\n name\n createdAt\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n team {\n totalCount\n items {\n ...WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator\n }\n }\n defaultRegion {\n key\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,11 +1,16 @@
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type {
|
||||
WorkspaceMixpanelUpdateGroup_WorkspaceFragment,
|
||||
WorkspaceMixpanelUpdateGroup_WorkspaceCollaboratorFragment
|
||||
import {
|
||||
type WorkspaceMixpanelUpdateGroup_WorkspaceFragment,
|
||||
type WorkspaceMixpanelUpdateGroup_WorkspaceCollaboratorFragment,
|
||||
type PaidWorkspacePlans,
|
||||
BillingInterval
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { type MaybeNullOrUndefined, Roles, type WorkspaceRoles } from '@speckle/shared'
|
||||
import { resolveMixpanelServerId } from '@speckle/shared'
|
||||
import { WorkspacePlanStatuses } from '~/lib/common/generated/gql/graphql'
|
||||
import { isPaidPlan } from '@/lib/billing/helpers/types'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceMixpanelUpdateGroup_WorkspaceCollaborator on WorkspaceCollaborator {
|
||||
@@ -29,6 +34,10 @@ graphql(`
|
||||
subscription {
|
||||
billingInterval
|
||||
currentBillingCycleEnd
|
||||
seats {
|
||||
guest
|
||||
plan
|
||||
}
|
||||
}
|
||||
team {
|
||||
totalCount
|
||||
@@ -44,12 +53,36 @@ graphql(`
|
||||
|
||||
export const useWorkspacesMixpanel = () => {
|
||||
const mixpanel = useMixpanel()
|
||||
const isBillingIntegrationEnabled = useIsBillingIntegrationEnabled()
|
||||
|
||||
const workspaceMixpanelUpdateGroup = (
|
||||
workspace: WorkspaceMixpanelUpdateGroup_WorkspaceFragment,
|
||||
userEmail: MaybeNullOrUndefined<string>
|
||||
) => {
|
||||
if (!workspace.id || !import.meta.client) return
|
||||
|
||||
const getEstimatedBill = () => {
|
||||
if (
|
||||
!isBillingIntegrationEnabled.value ||
|
||||
!isPaidPlan(workspace.plan?.name) ||
|
||||
workspace.plan?.status !== WorkspacePlanStatuses.Valid ||
|
||||
!workspace.subscription?.billingInterval
|
||||
)
|
||||
return null
|
||||
|
||||
const planConfig =
|
||||
pricingPlansConfig.plans[workspace.plan.name as unknown as PaidWorkspacePlans]
|
||||
const cost = planConfig.cost[workspace.subscription.billingInterval]
|
||||
const memberPrice = cost[Roles.Workspace.Member]
|
||||
const guestPrice = cost[Roles.Workspace.Guest]
|
||||
const memberCount = workspace.subscription?.seats?.plan || 0
|
||||
const guestCount = workspace.subscription?.seats?.guest || 0
|
||||
const totalPrice = memberPrice * memberCount + guestPrice * guestCount
|
||||
return workspace.subscription.billingInterval === BillingInterval.Yearly
|
||||
? totalPrice * 12
|
||||
: totalPrice
|
||||
}
|
||||
|
||||
const roleCount = {
|
||||
[Roles.Workspace.Admin]: 0,
|
||||
[Roles.Workspace.Member]: 0,
|
||||
@@ -74,14 +107,17 @@ export const useWorkspacesMixpanel = () => {
|
||||
teamMemberCount: roleCount[Roles.Workspace.Member],
|
||||
teamGuestCount: roleCount[Roles.Workspace.Guest],
|
||||
defaultRegionKey: workspace.defaultRegion?.key,
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
server_id: resolveMixpanelServerId(window.location.hostname),
|
||||
planName: workspace.plan?.name || '',
|
||||
planStatus: workspace.plan?.status || '',
|
||||
planCreatedAt: workspace.plan?.createdAt,
|
||||
subscriptionBillingInterval: workspace.subscription?.billingInterval,
|
||||
subscriptionCurrentBillingCycleEnd: workspace.subscription?.currentBillingCycleEnd
|
||||
subscriptionCurrentBillingCycleEnd:
|
||||
workspace.subscription?.currentBillingCycleEnd,
|
||||
seats: workspace.subscription?.seats?.plan || 0,
|
||||
seatsGuest: workspace.subscription?.seats?.guest || 0,
|
||||
estimatedBill: getEstimatedBill(),
|
||||
// eslint-disable-next-line camelcase
|
||||
server_id: resolveMixpanelServerId(window.location.hostname)
|
||||
}
|
||||
|
||||
mixpanel.get_group('workspace_id', workspace.id).set(input)
|
||||
|
||||
@@ -68,6 +68,16 @@ export type AdminInviteList = {
|
||||
totalCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type AdminMutations = {
|
||||
__typename?: 'AdminMutations';
|
||||
updateWorkspacePlan: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
|
||||
export type AdminMutationsUpdateWorkspacePlanArgs = {
|
||||
input: AdminUpdateWorkspacePlanInput;
|
||||
};
|
||||
|
||||
export type AdminQueries = {
|
||||
__typename?: 'AdminQueries';
|
||||
inviteList: AdminInviteList;
|
||||
@@ -108,6 +118,12 @@ export type AdminQueriesWorkspaceListArgs = {
|
||||
query?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type AdminUpdateWorkspacePlanInput = {
|
||||
plan: WorkspacePlans;
|
||||
status: WorkspacePlanStatuses;
|
||||
workspaceId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type AdminUserList = {
|
||||
__typename?: 'AdminUserList';
|
||||
cursor?: Maybe<Scalars['String']['output']>;
|
||||
@@ -1255,6 +1271,7 @@ export type Mutation = {
|
||||
_?: Maybe<Scalars['String']['output']>;
|
||||
/** Various Active User oriented mutations */
|
||||
activeUserMutations: ActiveUserMutations;
|
||||
admin: AdminMutations;
|
||||
adminDeleteUser: Scalars['Boolean']['output'];
|
||||
/** Creates an personal api token. */
|
||||
apiTokenCreate: Scalars['String']['output'];
|
||||
@@ -4558,9 +4575,16 @@ export type WorkspaceSubscription = {
|
||||
billingInterval: BillingInterval;
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
currentBillingCycleEnd: Scalars['DateTime']['output'];
|
||||
seats: WorkspaceSubscriptionSeats;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
|
||||
export type WorkspaceSubscriptionSeats = {
|
||||
__typename?: 'WorkspaceSubscriptionSeats';
|
||||
guest: Scalars['Int']['output'];
|
||||
plan: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type WorkspaceTeamFilter = {
|
||||
/** Limit team members to provided role(s) */
|
||||
roles?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
|
||||
Reference in New Issue
Block a user