@ -34,6 +34,7 @@ export const BillingContent = () => {
|
||||
</HStack>
|
||||
{workspace.plan !== Plan.CUSTOM &&
|
||||
workspace.plan !== Plan.LIFETIME &&
|
||||
workspace.plan !== Plan.UNLIMITED &&
|
||||
workspace.plan !== Plan.OFFERED && <ChangePlanForm />}
|
||||
</Stack>
|
||||
|
||||
|
@ -136,7 +136,12 @@ export const UsageContent = ({ workspace }: Props) => {
|
||||
>
|
||||
{storageToReadable(totalStorageUsed)}
|
||||
</Skeleton>
|
||||
<Text>/ {workspaceStorageLimit} GB</Text>
|
||||
<Text>
|
||||
/{' '}
|
||||
{workspaceStorageLimit === -1
|
||||
? 'Unlimited'
|
||||
: `${workspaceStorageLimit} GB`}
|
||||
</Text>
|
||||
</HStack>
|
||||
</Flex>
|
||||
<Progress
|
||||
|
@ -8,6 +8,7 @@ export const planColorSchemes: Record<Plan, ThemeTypings['colorSchemes']> = {
|
||||
[Plan.STARTER]: 'orange',
|
||||
[Plan.FREE]: 'gray',
|
||||
[Plan.CUSTOM]: 'yellow',
|
||||
[Plan.UNLIMITED]: 'yellow',
|
||||
}
|
||||
|
||||
export const PlanTag = ({
|
||||
@ -64,12 +65,23 @@ export const PlanTag = ({
|
||||
return (
|
||||
<Tag
|
||||
colorScheme={planColorSchemes[Plan.CUSTOM]}
|
||||
data-testid="free-plan-tag"
|
||||
data-testid="custom-plan-tag"
|
||||
{...props}
|
||||
>
|
||||
Custom
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
case Plan.UNLIMITED: {
|
||||
return (
|
||||
<Tag
|
||||
colorScheme={planColorSchemes[Plan.UNLIMITED]}
|
||||
data-testid="custom-unlimite-tag"
|
||||
{...props}
|
||||
>
|
||||
Unlimited
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ export const planToReadable = (plan?: Plan) => {
|
||||
return 'Offered'
|
||||
case Plan.PRO:
|
||||
return 'Pro'
|
||||
case Plan.UNLIMITED:
|
||||
return 'Unlimited'
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,4 +24,5 @@ export const isProPlan = (workspace?: Pick<Workspace, 'plan'>) =>
|
||||
isDefined(workspace) &&
|
||||
(workspace.plan === Plan.PRO ||
|
||||
workspace.plan === Plan.LIFETIME ||
|
||||
workspace.plan === Plan.CUSTOM)
|
||||
workspace.plan === Plan.CUSTOM ||
|
||||
workspace.plan === Plan.UNLIMITED)
|
||||
|
@ -106,7 +106,10 @@ export const MembersList = () => {
|
||||
)}
|
||||
{workspace && (
|
||||
<Heading fontSize="2xl">
|
||||
Members ({currentMembersCount}/{getSeatsLimit(workspace)})
|
||||
Members{' '}
|
||||
{getSeatsLimit(workspace) === -1
|
||||
? ''
|
||||
: `(${currentMembersCount}/${getSeatsLimit(workspace)})`}
|
||||
</Heading>
|
||||
)}
|
||||
{workspace?.id && canEdit && (
|
||||
|
@ -12,8 +12,12 @@ export function checkCanInviteMember({
|
||||
}) {
|
||||
if (!plan || !currentMembersCount) return false
|
||||
|
||||
return (
|
||||
getSeatsLimit({ plan, customSeatsLimit: customSeatsLimit ?? null }) >
|
||||
currentMembersCount
|
||||
)
|
||||
const seatsLimit = getSeatsLimit({
|
||||
plan,
|
||||
customSeatsLimit: customSeatsLimit ?? null,
|
||||
})
|
||||
|
||||
if (seatsLimit === -1) return true
|
||||
|
||||
return seatsLimit > currentMembersCount
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Plan } from 'db'
|
||||
|
||||
export const parseWorkspaceDefaultPlan = (userEmail: string) => {
|
||||
if (process.env.ADMIN_EMAIL === userEmail) return Plan.LIFETIME
|
||||
if (process.env.ADMIN_EMAIL === userEmail) return Plan.UNLIMITED
|
||||
const defaultPlan = process.env.DEFAULT_WORKSPACE_PLAN as Plan | undefined
|
||||
if (defaultPlan && Object.values(Plan).includes(defaultPlan))
|
||||
return defaultPlan
|
||||
|
@ -16,7 +16,7 @@ import { SponsorButton } from '../../../src/js/SponsorButton.jsx'
|
||||
| NEXTAUTH_URL | | The builder base URL. Should be the publicly accessible URL (i.e. `https://typebot.domain.com`) |
|
||||
| NEXT_PUBLIC_VIEWER_URL | | The viewer base URL. Should be the publicly accessible URL (i.e. `https://bot.domain.com`) |
|
||||
| NEXTAUTH_URL_INTERNAL | | The internal builder base URL. You have to set it only when `NEXTAUTH_URL` can't be reached by your builder container / server. For a docker deployment, you should set it to `http://localhost:3000`. |
|
||||
| DEFAULT_WORKSPACE_PLAN | FREE | Default workspace plan on user creation or when a user creates a new workspace. Possible values are `FREE`, `STARTER`, `PRO`, `LIFETIME`. The default plan for admin user is `LIFETIME` |
|
||||
| DEFAULT_WORKSPACE_PLAN | FREE | Default workspace plan on user creation or when a user creates a new workspace. Possible values are `FREE`, `STARTER`, `PRO`, `LIFETIME`, `UNLIMITED`. The default plan for admin user is `UNLIMITED` |
|
||||
| DISABLE_SIGNUP | false | To disable new sign ups but still be able to sign in with existing users or admin email |
|
||||
|
||||
## Email (Auth, notifications)
|
||||
|
@ -32,7 +32,7 @@ const handler = async (
|
||||
const typebotId = req.query.typebotId as string
|
||||
const blockId = req.query.blockId as string
|
||||
if (!filePath) return badRequest(res, 'Missing filePath or fileType')
|
||||
const hasReachedStorageLimit = await checkStorageLimit(typebotId)
|
||||
const hasReachedStorageLimit = await checkIfStorageLimitReached(typebotId)
|
||||
const typebot = (await prisma.publicTypebot.findFirst({
|
||||
where: { typebotId },
|
||||
})) as unknown as PublicTypebot
|
||||
@ -59,7 +59,9 @@ const handler = async (
|
||||
return methodNotAllowed(res)
|
||||
}
|
||||
|
||||
const checkStorageLimit = async (typebotId: string): Promise<boolean> => {
|
||||
const checkIfStorageLimitReached = async (
|
||||
typebotId: string
|
||||
): Promise<boolean> => {
|
||||
const typebot = await prisma.typebot.findUnique({
|
||||
where: { id: typebotId },
|
||||
include: {
|
||||
@ -94,6 +96,7 @@ const checkStorageLimit = async (typebotId: string): Promise<boolean> => {
|
||||
const hasSentFirstEmail = workspace.storageLimitFirstEmailSentAt !== null
|
||||
const hasSentSecondEmail = workspace.storageLimitSecondEmailSentAt !== null
|
||||
const storageLimit = getStorageLimit(typebot.workspace)
|
||||
if (storageLimit === -1) return false
|
||||
const storageLimitBytes = storageLimit * 1024 * 1024 * 1024
|
||||
if (
|
||||
totalStorageUsed >= storageLimitBytes * LIMIT_EMAIL_TRIGGER_PERCENT &&
|
||||
|
@ -0,0 +1,2 @@
|
||||
-- AlterEnum
|
||||
ALTER TYPE "Plan" ADD VALUE 'UNLIMITED';
|
@ -314,6 +314,7 @@ enum Plan {
|
||||
LIFETIME
|
||||
OFFERED
|
||||
CUSTOM
|
||||
UNLIMITED
|
||||
}
|
||||
|
||||
enum CollaborationType {
|
||||
|
@ -33,6 +33,7 @@ export const chatsLimit = {
|
||||
},
|
||||
[Plan.OFFERED]: { totalIncluded: infinity },
|
||||
[Plan.LIFETIME]: { totalIncluded: infinity },
|
||||
[Plan.UNLIMITED]: { totalIncluded: infinity },
|
||||
} as const
|
||||
|
||||
export const storageLimit = {
|
||||
@ -60,6 +61,7 @@ export const storageLimit = {
|
||||
},
|
||||
[Plan.OFFERED]: { totalIncluded: 2 },
|
||||
[Plan.LIFETIME]: { totalIncluded: 10 },
|
||||
[Plan.UNLIMITED]: { totalIncluded: infinity },
|
||||
} as const
|
||||
|
||||
export const seatsLimit = {
|
||||
@ -75,6 +77,7 @@ export const seatsLimit = {
|
||||
},
|
||||
[Plan.OFFERED]: { totalIncluded: 2 },
|
||||
[Plan.LIFETIME]: { totalIncluded: 8 },
|
||||
[Plan.UNLIMITED]: { totalIncluded: infinity },
|
||||
} as const
|
||||
|
||||
export const getChatsLimit = ({
|
||||
|
Reference in New Issue
Block a user