♻️ Remove storage limit related code
This commit is contained in:
@ -27,7 +27,6 @@ export const createCheckoutSession = authenticatedProcedure
|
||||
plan: z.enum([Plan.STARTER, Plan.PRO]),
|
||||
returnUrl: z.string(),
|
||||
additionalChats: z.number(),
|
||||
additionalStorage: z.number(),
|
||||
vat: z
|
||||
.object({
|
||||
type: z.string(),
|
||||
@ -53,7 +52,6 @@ export const createCheckoutSession = authenticatedProcedure
|
||||
plan,
|
||||
returnUrl,
|
||||
additionalChats,
|
||||
additionalStorage,
|
||||
isYearly,
|
||||
},
|
||||
ctx: { user },
|
||||
@ -119,7 +117,6 @@ export const createCheckoutSession = authenticatedProcedure
|
||||
plan,
|
||||
returnUrl,
|
||||
additionalChats,
|
||||
additionalStorage,
|
||||
isYearly,
|
||||
})
|
||||
|
||||
@ -142,7 +139,6 @@ type Props = {
|
||||
plan: 'STARTER' | 'PRO'
|
||||
returnUrl: string
|
||||
additionalChats: number
|
||||
additionalStorage: number
|
||||
isYearly: boolean
|
||||
userId: string
|
||||
}
|
||||
@ -156,7 +152,6 @@ export const createCheckoutSessionUrl =
|
||||
plan,
|
||||
returnUrl,
|
||||
additionalChats,
|
||||
additionalStorage,
|
||||
isYearly,
|
||||
}: Props) => {
|
||||
const session = await stripe.checkout.sessions.create({
|
||||
@ -173,17 +168,11 @@ export const createCheckoutSessionUrl =
|
||||
workspaceId,
|
||||
plan,
|
||||
additionalChats,
|
||||
additionalStorage,
|
||||
},
|
||||
currency,
|
||||
billing_address_collection: 'required',
|
||||
automatic_tax: { enabled: true },
|
||||
line_items: parseSubscriptionItems(
|
||||
plan,
|
||||
additionalChats,
|
||||
additionalStorage,
|
||||
isYearly
|
||||
),
|
||||
line_items: parseSubscriptionItems(plan, additionalChats, isYearly),
|
||||
})
|
||||
|
||||
return session.url
|
||||
|
@ -19,9 +19,7 @@ export const getUsage = authenticatedProcedure
|
||||
workspaceId: z.string(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({ totalChatsUsed: z.number(), totalStorageUsed: z.number() })
|
||||
)
|
||||
.output(z.object({ totalChatsUsed: z.number() }))
|
||||
.query(async ({ input: { workspaceId }, ctx: { user } }) => {
|
||||
const workspace = await prisma.workspace.findFirst({
|
||||
where: {
|
||||
@ -55,20 +53,8 @@ export const getUsage = authenticatedProcedure
|
||||
},
|
||||
},
|
||||
})
|
||||
const {
|
||||
_sum: { storageUsed: totalStorageUsed },
|
||||
} = await prisma.answer.aggregate({
|
||||
where: {
|
||||
storageUsed: { gt: 0 },
|
||||
result: {
|
||||
typebotId: { in: workspace.typebots.map((typebot) => typebot.id) },
|
||||
},
|
||||
},
|
||||
_sum: { storageUsed: true },
|
||||
})
|
||||
|
||||
return {
|
||||
totalChatsUsed,
|
||||
totalStorageUsed: totalStorageUsed ?? 0,
|
||||
}
|
||||
})
|
||||
|
@ -7,8 +7,8 @@ import { workspaceSchema } from '@typebot.io/schemas'
|
||||
import Stripe from 'stripe'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { z } from 'zod'
|
||||
import { getChatsLimit, getStorageLimit } from '@typebot.io/lib/pricing'
|
||||
import { chatPriceIds, storagePriceIds } from './getSubscription'
|
||||
import { getChatsLimit } from '@typebot.io/lib/pricing'
|
||||
import { chatPriceIds } from './getSubscription'
|
||||
import { createCheckoutSessionUrl } from './createCheckoutSession'
|
||||
import { isAdminWriteWorkspaceForbidden } from '@/features/workspace/helpers/isAdminWriteWorkspaceForbidden'
|
||||
import { getUsage } from '@typebot.io/lib/api/getUsage'
|
||||
@ -31,7 +31,6 @@ export const updateSubscription = authenticatedProcedure
|
||||
workspaceId: z.string(),
|
||||
plan: z.enum([Plan.STARTER, Plan.PRO]),
|
||||
additionalChats: z.number(),
|
||||
additionalStorage: z.number(),
|
||||
currency: z.enum(['usd', 'eur']),
|
||||
isYearly: z.boolean(),
|
||||
})
|
||||
@ -48,7 +47,6 @@ export const updateSubscription = authenticatedProcedure
|
||||
workspaceId,
|
||||
plan,
|
||||
additionalChats,
|
||||
additionalStorage,
|
||||
currency,
|
||||
isYearly,
|
||||
returnUrl,
|
||||
@ -100,9 +98,6 @@ export const updateSubscription = authenticatedProcedure
|
||||
const currentAdditionalChatsItemId = subscription?.items.data.find(
|
||||
(item) => chatPriceIds.includes(item.price.id)
|
||||
)?.id
|
||||
const currentAdditionalStorageItemId = subscription?.items.data.find(
|
||||
(item) => storagePriceIds.includes(item.price.id)
|
||||
)?.id
|
||||
const frequency = isYearly ? 'yearly' : 'monthly'
|
||||
|
||||
const items = [
|
||||
@ -123,18 +118,6 @@ export const updateSubscription = authenticatedProcedure
|
||||
}),
|
||||
deleted: subscription ? additionalChats === 0 : undefined,
|
||||
},
|
||||
additionalStorage === 0 && !currentAdditionalStorageItemId
|
||||
? undefined
|
||||
: {
|
||||
id: currentAdditionalStorageItemId,
|
||||
price: priceIds[plan].storage[frequency],
|
||||
quantity: getStorageLimit({
|
||||
plan,
|
||||
additionalStorageIndex: additionalStorage,
|
||||
customStorageLimit: null,
|
||||
}),
|
||||
deleted: subscription ? additionalStorage === 0 : undefined,
|
||||
},
|
||||
].filter(isDefined)
|
||||
|
||||
if (subscription) {
|
||||
@ -151,7 +134,6 @@ export const updateSubscription = authenticatedProcedure
|
||||
plan,
|
||||
returnUrl,
|
||||
additionalChats,
|
||||
additionalStorage,
|
||||
isYearly,
|
||||
})
|
||||
|
||||
@ -175,7 +157,6 @@ export const updateSubscription = authenticatedProcedure
|
||||
data: {
|
||||
plan,
|
||||
additionalChatsIndex: additionalChats,
|
||||
additionalStorageIndex: additionalStorage,
|
||||
isQuarantined,
|
||||
},
|
||||
})
|
||||
@ -188,7 +169,6 @@ export const updateSubscription = authenticatedProcedure
|
||||
data: {
|
||||
plan,
|
||||
additionalChatsIndex: additionalChats,
|
||||
additionalStorageIndex: additionalStorage,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
@ -85,7 +85,6 @@ test('should display valid usage', async ({ page }) => {
|
||||
await injectFakeResults({
|
||||
count: 10,
|
||||
typebotId: usageTypebotId,
|
||||
fakeStorage: 1100 * 1024 * 1024,
|
||||
})
|
||||
await page.click('text=Free workspace')
|
||||
await page.click('text="Usage Workspace"')
|
||||
@ -101,7 +100,6 @@ test('should display valid usage', async ({ page }) => {
|
||||
await injectFakeResults({
|
||||
typebotId: usageTypebotId,
|
||||
count: 1090,
|
||||
fakeStorage: 1200 * 1024 * 1024,
|
||||
})
|
||||
await page.click('text="Settings"')
|
||||
await page.click('text="Billing & Usage"')
|
||||
@ -140,7 +138,7 @@ test('plan changes should work', async ({ page }) => {
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
{ plan: Plan.STARTER, additionalChatsIndex: 0, additionalStorageIndex: 0 }
|
||||
{ plan: Plan.STARTER, additionalChatsIndex: 0 }
|
||||
)
|
||||
|
||||
// Update plan with additional quotas
|
||||
|
@ -84,7 +84,6 @@ export const ChangePlanForm = ({ workspace }: Props) => {
|
||||
plan,
|
||||
workspaceId: workspace.id,
|
||||
additionalChats: selectedChatsLimitIndex,
|
||||
additionalStorage: selectedStorageLimitIndex,
|
||||
currency:
|
||||
data?.subscription?.currency ??
|
||||
(guessIfUserIsEuropean() ? 'eur' : 'usd'),
|
||||
|
@ -26,7 +26,6 @@ export type PreCheckoutModalProps = {
|
||||
plan: 'STARTER' | 'PRO'
|
||||
workspaceId: string
|
||||
additionalChats: number
|
||||
additionalStorage: number
|
||||
currency: 'eur' | 'usd'
|
||||
isYearly: boolean
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ import {
|
||||
computePrice,
|
||||
formatPrice,
|
||||
getChatsLimit,
|
||||
getStorageLimit,
|
||||
storageLimit,
|
||||
} from '@typebot.io/lib/pricing'
|
||||
import { FeaturesList } from './FeaturesList'
|
||||
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
|
||||
@ -35,7 +33,6 @@ type Props = {
|
||||
workspace: Pick<
|
||||
Workspace,
|
||||
| 'additionalChatsIndex'
|
||||
| 'additionalStorageIndex'
|
||||
| 'plan'
|
||||
| 'customChatsLimit'
|
||||
| 'customStorageLimit'
|
||||
@ -80,25 +77,18 @@ export const ProPlanPricingCard = ({
|
||||
return
|
||||
}
|
||||
setSelectedChatsLimitIndex(workspace.additionalChatsIndex ?? 0)
|
||||
setSelectedStorageLimitIndex(workspace.additionalStorageIndex ?? 0)
|
||||
}, [
|
||||
selectedChatsLimitIndex,
|
||||
selectedStorageLimitIndex,
|
||||
workspace.additionalChatsIndex,
|
||||
workspace.additionalStorageIndex,
|
||||
workspace?.plan,
|
||||
])
|
||||
|
||||
const workspaceChatsLimit = workspace ? getChatsLimit(workspace) : undefined
|
||||
const workspaceStorageLimit = workspace
|
||||
? getStorageLimit(workspace)
|
||||
: undefined
|
||||
|
||||
const isCurrentPlan =
|
||||
chatsLimit[Plan.PRO].graduatedPrice[selectedChatsLimitIndex ?? 0]
|
||||
.totalIncluded === workspaceChatsLimit &&
|
||||
storageLimit[Plan.PRO].graduatedPrice[selectedStorageLimitIndex ?? 0]
|
||||
.totalIncluded === workspaceStorageLimit &&
|
||||
isYearly === currentSubscription?.isYearly
|
||||
|
||||
const getButtonLabel = () => {
|
||||
@ -110,10 +100,7 @@ export const ProPlanPricingCard = ({
|
||||
if (workspace?.plan === Plan.PRO) {
|
||||
if (isCurrentPlan) return scopedT('upgradeButton.current')
|
||||
|
||||
if (
|
||||
selectedChatsLimitIndex !== workspace.additionalChatsIndex ||
|
||||
selectedStorageLimitIndex !== workspace.additionalStorageIndex
|
||||
)
|
||||
if (selectedChatsLimitIndex !== workspace.additionalChatsIndex)
|
||||
return t('update')
|
||||
}
|
||||
return t('upgrade')
|
||||
@ -135,7 +122,6 @@ export const ProPlanPricingCard = ({
|
||||
computePrice(
|
||||
Plan.PRO,
|
||||
selectedChatsLimitIndex ?? 0,
|
||||
selectedStorageLimitIndex ?? 0,
|
||||
isYearly ? 'yearly' : 'monthly'
|
||||
) ?? NaN
|
||||
|
||||
@ -238,40 +224,6 @@ export const ProPlanPricingCard = ({
|
||||
</Text>
|
||||
<MoreInfoTooltip>{scopedT('chatsTooltip')}</MoreInfoTooltip>
|
||||
</HStack>,
|
||||
<HStack key="test">
|
||||
<Text>
|
||||
<Menu>
|
||||
<MenuButton
|
||||
as={Button}
|
||||
rightIcon={<ChevronLeftIcon transform="rotate(-90deg)" />}
|
||||
size="sm"
|
||||
isLoading={selectedStorageLimitIndex === undefined}
|
||||
>
|
||||
{selectedStorageLimitIndex !== undefined
|
||||
? parseNumberWithCommas(
|
||||
storageLimit.PRO.graduatedPrice[
|
||||
selectedStorageLimitIndex
|
||||
].totalIncluded
|
||||
)
|
||||
: undefined}
|
||||
</MenuButton>
|
||||
<MenuList>
|
||||
{storageLimit.PRO.graduatedPrice.map((price, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
onClick={() => setSelectedStorageLimitIndex(index)}
|
||||
>
|
||||
{parseNumberWithCommas(price.totalIncluded)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
</Menu>{' '}
|
||||
{scopedT('storageLimit')}
|
||||
</Text>
|
||||
<MoreInfoTooltip>
|
||||
{scopedT('storageLimitTooltip')}
|
||||
</MoreInfoTooltip>
|
||||
</HStack>,
|
||||
scopedT('pro.customDomains'),
|
||||
scopedT('pro.analytics'),
|
||||
]}
|
||||
|
@ -19,8 +19,6 @@ import {
|
||||
computePrice,
|
||||
formatPrice,
|
||||
getChatsLimit,
|
||||
getStorageLimit,
|
||||
storageLimit,
|
||||
} from '@typebot.io/lib/pricing'
|
||||
import { FeaturesList } from './FeaturesList'
|
||||
import { MoreInfoTooltip } from '@/components/MoreInfoTooltip'
|
||||
@ -31,7 +29,6 @@ type Props = {
|
||||
workspace: Pick<
|
||||
Workspace,
|
||||
| 'additionalChatsIndex'
|
||||
| 'additionalStorageIndex'
|
||||
| 'plan'
|
||||
| 'customChatsLimit'
|
||||
| 'customStorageLimit'
|
||||
@ -76,25 +73,18 @@ export const StarterPlanPricingCard = ({
|
||||
return
|
||||
}
|
||||
setSelectedChatsLimitIndex(workspace.additionalChatsIndex ?? 0)
|
||||
setSelectedStorageLimitIndex(workspace.additionalStorageIndex ?? 0)
|
||||
}, [
|
||||
selectedChatsLimitIndex,
|
||||
selectedStorageLimitIndex,
|
||||
workspace.additionalChatsIndex,
|
||||
workspace.additionalStorageIndex,
|
||||
workspace?.plan,
|
||||
])
|
||||
|
||||
const workspaceChatsLimit = workspace ? getChatsLimit(workspace) : undefined
|
||||
const workspaceStorageLimit = workspace
|
||||
? getStorageLimit(workspace)
|
||||
: undefined
|
||||
|
||||
const isCurrentPlan =
|
||||
chatsLimit[Plan.STARTER].graduatedPrice[selectedChatsLimitIndex ?? 0]
|
||||
.totalIncluded === workspaceChatsLimit &&
|
||||
storageLimit[Plan.STARTER].graduatedPrice[selectedStorageLimitIndex ?? 0]
|
||||
.totalIncluded === workspaceStorageLimit &&
|
||||
isYearly === currentSubscription?.isYearly
|
||||
|
||||
const getButtonLabel = () => {
|
||||
@ -109,7 +99,6 @@ export const StarterPlanPricingCard = ({
|
||||
|
||||
if (
|
||||
selectedChatsLimitIndex !== workspace.additionalChatsIndex ||
|
||||
selectedStorageLimitIndex !== workspace.additionalStorageIndex ||
|
||||
isYearly !== currentSubscription?.isYearly
|
||||
)
|
||||
return t('update')
|
||||
@ -133,7 +122,6 @@ export const StarterPlanPricingCard = ({
|
||||
computePrice(
|
||||
Plan.STARTER,
|
||||
selectedChatsLimitIndex ?? 0,
|
||||
selectedStorageLimitIndex ?? 0,
|
||||
isYearly ? 'yearly' : 'monthly'
|
||||
) ?? NaN
|
||||
|
||||
@ -185,40 +173,6 @@ export const StarterPlanPricingCard = ({
|
||||
</Text>
|
||||
<MoreInfoTooltip>{scopedT('chatsTooltip')}</MoreInfoTooltip>
|
||||
</HStack>,
|
||||
<HStack key="test">
|
||||
<Text>
|
||||
<Menu>
|
||||
<MenuButton
|
||||
as={Button}
|
||||
rightIcon={<ChevronLeftIcon transform="rotate(-90deg)" />}
|
||||
size="sm"
|
||||
isLoading={selectedStorageLimitIndex === undefined}
|
||||
>
|
||||
{selectedStorageLimitIndex !== undefined
|
||||
? parseNumberWithCommas(
|
||||
storageLimit.STARTER.graduatedPrice[
|
||||
selectedStorageLimitIndex
|
||||
].totalIncluded
|
||||
)
|
||||
: undefined}
|
||||
</MenuButton>
|
||||
<MenuList>
|
||||
{storageLimit.STARTER.graduatedPrice.map((price, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
onClick={() => setSelectedStorageLimitIndex(index)}
|
||||
>
|
||||
{parseNumberWithCommas(price.totalIncluded)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
</Menu>{' '}
|
||||
{scopedT('storageLimit')}
|
||||
</Text>
|
||||
<MoreInfoTooltip>
|
||||
{scopedT('storageLimitTooltip')}
|
||||
</MoreInfoTooltip>
|
||||
</HStack>,
|
||||
scopedT('starter.brandingRemoved'),
|
||||
scopedT('starter.fileUploadBlock'),
|
||||
scopedT('starter.createFolders'),
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { getChatsLimit, getStorageLimit } from '@typebot.io/lib/pricing'
|
||||
import { getChatsLimit } from '@typebot.io/lib/pricing'
|
||||
import { priceIds } from '@typebot.io/lib/api/pricing'
|
||||
|
||||
export const parseSubscriptionItems = (
|
||||
plan: 'STARTER' | 'PRO',
|
||||
additionalChats: number,
|
||||
additionalStorage: number,
|
||||
isYearly: boolean
|
||||
) => {
|
||||
const frequency = isYearly ? 'yearly' : 'monthly'
|
||||
@ -13,33 +12,18 @@ export const parseSubscriptionItems = (
|
||||
price: priceIds[plan].base[frequency],
|
||||
quantity: 1,
|
||||
},
|
||||
]
|
||||
.concat(
|
||||
additionalChats > 0
|
||||
? [
|
||||
{
|
||||
price: priceIds[plan].chats[frequency],
|
||||
quantity: getChatsLimit({
|
||||
plan,
|
||||
additionalChatsIndex: additionalChats,
|
||||
customChatsLimit: null,
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []
|
||||
)
|
||||
.concat(
|
||||
additionalStorage > 0
|
||||
? [
|
||||
{
|
||||
price: priceIds[plan].storage[frequency],
|
||||
quantity: getStorageLimit({
|
||||
plan,
|
||||
additionalStorageIndex: additionalStorage,
|
||||
customStorageLimit: null,
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []
|
||||
)
|
||||
].concat(
|
||||
additionalChats > 0
|
||||
? [
|
||||
{
|
||||
price: priceIds[plan].chats[frequency],
|
||||
quantity: getChatsLimit({
|
||||
plan,
|
||||
additionalChatsIndex: additionalChats,
|
||||
customChatsLimit: null,
|
||||
}),
|
||||
},
|
||||
]
|
||||
: []
|
||||
)
|
||||
}
|
||||
|
@ -33,11 +33,10 @@ export const DashboardPage = () => {
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const { subscribePlan, chats, storage, isYearly, claimCustomPlan } =
|
||||
const { subscribePlan, chats, isYearly, claimCustomPlan } =
|
||||
router.query as {
|
||||
subscribePlan: Plan | undefined
|
||||
chats: string | undefined
|
||||
storage: string | undefined
|
||||
isYearly: string | undefined
|
||||
claimCustomPlan: string | undefined
|
||||
}
|
||||
@ -55,7 +54,6 @@ export const DashboardPage = () => {
|
||||
plan: subscribePlan as 'PRO' | 'STARTER',
|
||||
workspaceId: workspace.id,
|
||||
additionalChats: chats ? parseInt(chats) : 0,
|
||||
additionalStorage: storage ? parseInt(storage) : 0,
|
||||
currency: guessIfUserIsEuropean() ? 'eur' : 'usd',
|
||||
isYearly: isYearly === 'false' ? false : true,
|
||||
})
|
||||
|
@ -47,15 +47,13 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
| {
|
||||
plan: 'STARTER' | 'PRO'
|
||||
additionalChats: string
|
||||
additionalStorage: string
|
||||
workspaceId: string
|
||||
userId: string
|
||||
}
|
||||
| { claimableCustomPlanId: string; userId: string }
|
||||
if ('plan' in metadata) {
|
||||
const { workspaceId, plan, additionalChats, additionalStorage } =
|
||||
metadata
|
||||
if (!workspaceId || !plan || !additionalChats || !additionalStorage)
|
||||
const { workspaceId, plan, additionalChats } = metadata
|
||||
if (!workspaceId || !plan || !additionalChats)
|
||||
return res
|
||||
.status(500)
|
||||
.send({ message: `Couldn't retrieve valid metadata` })
|
||||
@ -65,7 +63,6 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
plan,
|
||||
stripeId: session.customer as string,
|
||||
additionalChatsIndex: parseInt(additionalChats),
|
||||
additionalStorageIndex: parseInt(additionalStorage),
|
||||
isQuarantined: false,
|
||||
},
|
||||
include: {
|
||||
@ -88,7 +85,6 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
data: {
|
||||
plan,
|
||||
additionalChatsIndex: parseInt(additionalChats),
|
||||
additionalStorageIndex: parseInt(additionalStorage),
|
||||
},
|
||||
},
|
||||
])
|
||||
@ -124,7 +120,6 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
data: {
|
||||
plan: Plan.CUSTOM,
|
||||
additionalChatsIndex: 0,
|
||||
additionalStorageIndex: 0,
|
||||
},
|
||||
},
|
||||
])
|
||||
@ -154,7 +149,6 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
data: {
|
||||
plan: Plan.FREE,
|
||||
additionalChatsIndex: 0,
|
||||
additionalStorageIndex: 0,
|
||||
customChatsLimit: null,
|
||||
customStorageLimit: null,
|
||||
customSeatsLimit: null,
|
||||
@ -179,7 +173,6 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
data: {
|
||||
plan: Plan.FREE,
|
||||
additionalChatsIndex: 0,
|
||||
additionalStorageIndex: 0,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
@ -18,10 +18,7 @@ const stripe = new Stripe(env.STRIPE_SECRET_KEY ?? '', {
|
||||
export const addSubscriptionToWorkspace = async (
|
||||
workspaceId: string,
|
||||
items: Stripe.SubscriptionCreateParams.Item[],
|
||||
metadata: Pick<
|
||||
Workspace,
|
||||
'additionalChatsIndex' | 'additionalStorageIndex' | 'plan'
|
||||
>
|
||||
metadata: Pick<Workspace, 'additionalChatsIndex' | 'plan'>
|
||||
) => {
|
||||
const { id: stripeId } = await stripe.customers.create({
|
||||
email: 'test-user@gmail.com',
|
||||
|
Reference in New Issue
Block a user