✨ (billing) Implement custom plan
This commit is contained in:
committed by
Baptiste Arnaud
parent
3f7dc79918
commit
385853ca3c
@@ -1,4 +1,6 @@
|
||||
import { Stack } from '@chakra-ui/react'
|
||||
import { HStack, Stack, Text } from '@chakra-ui/react'
|
||||
import { StripeClimateLogo } from 'assets/logos/StripeClimateLogo'
|
||||
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
|
||||
import { ChangePlanForm } from 'components/shared/ChangePlanForm'
|
||||
import { useWorkspace } from 'contexts/WorkspaceContext'
|
||||
import { Plan } from 'db'
|
||||
@@ -26,7 +28,22 @@ export const BillingContent = () => {
|
||||
})
|
||||
}
|
||||
/>
|
||||
{workspace.plan !== Plan.LIFETIME &&
|
||||
<HStack maxW="500px">
|
||||
<StripeClimateLogo />
|
||||
<Text fontSize="xs" color="gray.500">
|
||||
Typebot is contributing 1% of your subscription to remove CO₂ from
|
||||
the atmosphere.{' '}
|
||||
<NextChakraLink
|
||||
href="https://climate.stripe.com/5VCRAq"
|
||||
isExternal
|
||||
textDecor="underline"
|
||||
>
|
||||
More info.
|
||||
</NextChakraLink>
|
||||
</Text>
|
||||
</HStack>
|
||||
{workspace.plan !== Plan.CUSTOM &&
|
||||
workspace.plan !== Plan.LIFETIME &&
|
||||
workspace.plan !== Plan.OFFERED && <ChangePlanForm />}
|
||||
</Stack>
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export const AddMemberForm = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<HStack as="form" onSubmit={handleInvitationSubmit} pb="4">
|
||||
<HStack as="form" onSubmit={handleInvitationSubmit}>
|
||||
<Input
|
||||
placeholder="colleague@company.com"
|
||||
name="inviteEmail"
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { HStack, SkeletonCircle, SkeletonText, Stack } from '@chakra-ui/react'
|
||||
import {
|
||||
Heading,
|
||||
HStack,
|
||||
SkeletonCircle,
|
||||
SkeletonText,
|
||||
Stack,
|
||||
} from '@chakra-ui/react'
|
||||
import { UnlockPlanInfo } from 'components/shared/Info'
|
||||
import { useUser } from 'contexts/UserContext'
|
||||
import { useWorkspace } from 'contexts/WorkspaceContext'
|
||||
@@ -12,6 +18,7 @@ import {
|
||||
updateMember,
|
||||
useMembers,
|
||||
} from 'services/workspace'
|
||||
import { getSeatsLimit } from 'utils'
|
||||
import { AddMemberForm } from './AddMemberForm'
|
||||
import { checkCanInviteMember } from './helpers'
|
||||
import { MemberItem } from './MemberItem'
|
||||
@@ -77,9 +84,12 @@ export const MembersList = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const currentMembersCount = members.length + invitations.length
|
||||
|
||||
const canInviteNewMember = checkCanInviteMember({
|
||||
plan: workspace?.plan,
|
||||
currentMembersCount: [...members, ...invitations].length,
|
||||
customSeatsLimit: workspace?.customSeatsLimit,
|
||||
currentMembersCount,
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -92,6 +102,11 @@ export const MembersList = () => {
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
{workspace && (
|
||||
<Heading fontSize="2xl">
|
||||
Members ({currentMembersCount}/{getSeatsLimit(workspace)})
|
||||
</Heading>
|
||||
)}
|
||||
{workspace?.id && canEdit && (
|
||||
<AddMemberForm
|
||||
workspaceId={workspace.id}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import { Plan } from 'db'
|
||||
import { seatsLimit } from 'utils'
|
||||
import { getSeatsLimit } from 'utils'
|
||||
|
||||
export function checkCanInviteMember({
|
||||
plan,
|
||||
customSeatsLimit,
|
||||
currentMembersCount,
|
||||
}: {
|
||||
plan?: Plan
|
||||
customSeatsLimit?: number | null
|
||||
currentMembersCount?: number
|
||||
}) {
|
||||
if (!plan || !currentMembersCount) return false
|
||||
|
||||
return seatsLimit[plan].totalIncluded > currentMembersCount
|
||||
return (
|
||||
getSeatsLimit({ plan, customSeatsLimit: customSeatsLimit ?? null }) >
|
||||
currentMembersCount
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Stack, HStack, Text } from '@chakra-ui/react'
|
||||
import { StripeClimateLogo } from 'assets/logos/StripeClimateLogo'
|
||||
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
|
||||
import { useUser } from 'contexts/UserContext'
|
||||
import { useWorkspace } from 'contexts/WorkspaceContext'
|
||||
@@ -65,20 +64,6 @@ export const ChangePlanForm = () => {
|
||||
|
||||
return (
|
||||
<Stack spacing={6}>
|
||||
<HStack maxW="500px">
|
||||
<StripeClimateLogo />
|
||||
<Text fontSize="xs" color="gray.500">
|
||||
Typebot is contributing 1% of your subscription to remove CO₂ from the
|
||||
atmosphere.{' '}
|
||||
<NextChakraLink
|
||||
href="https://climate.stripe.com/5VCRAq"
|
||||
isExternal
|
||||
textDecor="underline"
|
||||
>
|
||||
More info.
|
||||
</NextChakraLink>
|
||||
</Text>
|
||||
</HStack>
|
||||
<HStack alignItems="stretch" spacing="4" w="full">
|
||||
<StarterPlanContent
|
||||
initialChatsLimitIndex={
|
||||
|
||||
@@ -7,9 +7,13 @@ export const planColorSchemes: Record<Plan, ThemeTypings['colorSchemes']> = {
|
||||
[Plan.OFFERED]: 'orange',
|
||||
[Plan.STARTER]: 'orange',
|
||||
[Plan.FREE]: 'gray',
|
||||
[Plan.CUSTOM]: 'yellow',
|
||||
}
|
||||
|
||||
export const PlanTag = ({ plan, ...props }: { plan?: Plan } & TagProps) => {
|
||||
export const PlanTag = ({
|
||||
plan,
|
||||
...props
|
||||
}: { plan: Plan } & TagProps): JSX.Element => {
|
||||
switch (plan) {
|
||||
case Plan.LIFETIME: {
|
||||
return (
|
||||
@@ -45,7 +49,7 @@ export const PlanTag = ({ plan, ...props }: { plan?: Plan } & TagProps) => {
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
default: {
|
||||
case Plan.FREE: {
|
||||
return (
|
||||
<Tag
|
||||
colorScheme={planColorSchemes[Plan.FREE]}
|
||||
@@ -56,5 +60,16 @@ export const PlanTag = ({ plan, ...props }: { plan?: Plan } & TagProps) => {
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
case Plan.CUSTOM: {
|
||||
return (
|
||||
<Tag
|
||||
colorScheme={planColorSchemes[Plan.CUSTOM]}
|
||||
data-testid="free-plan-tag"
|
||||
{...props}
|
||||
>
|
||||
Custom
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user