Skip to content

Commit

Permalink
♻️ Add a new unlimited plan
Browse files Browse the repository at this point in the history
Closes #273
  • Loading branch information
baptisteArno committed Jan 27, 2023
1 parent 4f78dda commit 409e764
Show file tree
Hide file tree
Showing 12 changed files with 49 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion apps/builder/src/features/billing/components/PlanTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ({
Expand Down Expand Up @@ -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>
)
}
}
}
5 changes: 4 additions & 1 deletion apps/builder/src/features/billing/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const planToReadable = (plan?: Plan) => {
return 'Offered'
case Plan.PRO:
return 'Pro'
case Plan.UNLIMITED:
return 'Unlimited'
}
}

Expand All @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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 && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/self-hosting/configuration/builder.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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: {
Expand Down Expand Up @@ -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 &&
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "Plan" ADD VALUE 'UNLIMITED';
1 change: 1 addition & 0 deletions packages/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ enum Plan {
LIFETIME
OFFERED
CUSTOM
UNLIMITED
}

enum CollaborationType {
Expand Down
3 changes: 3 additions & 0 deletions packages/utils/pricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const chatsLimit = {
},
[Plan.OFFERED]: { totalIncluded: infinity },
[Plan.LIFETIME]: { totalIncluded: infinity },
[Plan.UNLIMITED]: { totalIncluded: infinity },
} as const

export const storageLimit = {
Expand Down Expand Up @@ -60,6 +61,7 @@ export const storageLimit = {
},
[Plan.OFFERED]: { totalIncluded: 2 },
[Plan.LIFETIME]: { totalIncluded: 10 },
[Plan.UNLIMITED]: { totalIncluded: infinity },
} as const

export const seatsLimit = {
Expand All @@ -75,6 +77,7 @@ export const seatsLimit = {
},
[Plan.OFFERED]: { totalIncluded: 2 },
[Plan.LIFETIME]: { totalIncluded: 8 },
[Plan.UNLIMITED]: { totalIncluded: infinity },
} as const

export const getChatsLimit = ({
Expand Down

4 comments on commit 409e764

@vercel
Copy link

@vercel vercel bot commented on 409e764 Jan 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 409e764 Jan 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viewer-v2 – ./apps/viewer

start.taxtree.io
typebot.aloe.bot
voicehelp.cr8.ai
zap.fundviser.in
app.chatforms.net
bot.hostnation.de
bot.maitempah.com
bot.phuonghub.com
bot.reviewzer.com
bot.rihabilita.it
cares.urlabout.me
fmm.wpwakanda.com
gentleman-shop.fr
k1.kandabrand.com
lb.ticketfute.com
ov1.wpwakanda.com
ov2.wpwakanda.com
ov3.wpwakanda.com
viewer.typebot.io
1988.bouclidom.com
andreimayer.com.br
bot.danyservice.it
bot.iconicbrows.it
bot.megafox.com.br
bot.neferlopez.com
bots.robomotion.io
cadu.uninta.edu.br
dicanatural.online
digitalhelp.com.au
goalsettingbot.com
pant.maxbot.com.br
positivobra.com.br
survey.digienge.io
this-is-a-test.com
zap.techadviser.in
bot.boston-voip.com
bot.cabinpromos.com
bot.digitalbled.com
bot.dsignagency.com
bot.eventhub.com.au
bot.jepierre.com.br
bot.viralsangat.com
bot.winglabs.com.br
carsalesenquiry.com
chat.marius.digital
chatbot.matthesv.de
chatbot.repplai.com
demo.botscientis.us
demo.wemakebots.xyz
forms.webisharp.com
kbsub.wpwakanda.com
live.botscientis.us
mentoria.omelhor.vc
nutrisamirbayde.com
order.maitempah.com
quest.wpwakanda.com
survey1.digienge.io
test.botscientis.us
test.reventepro.com
typebot.stillio.com
wordsandimagery.com
tarian.theiofoundation.org
ted.meujalecobrasil.com.br
type.dericsoncalari.com.br
bot.pinpointinteractive.com
bot.polychromes-project.com
bot.seidinembroseanchetu.it
chatbot.berbelanjabiz.trade
designguide.techyscouts.com
liveconvert2.kandalearn.com
presente.empresarias.com.mx
sell.sellthemotorhome.co.uk
anamnese.odontopavani.com.br
austin.channelautomation.com
bot.marketingplusmindset.com
bot.seidibergamoseanchetu.it
desabafe.sergiolimajr.com.br
piazzatorre.barrettamario.it
type.cookieacademyonline.com
bot.brigadeirosemdrama.com.br
forms.escoladeautomacao.com.br
onboarding.libertydreamcare.ie
type.talitasouzamarques.com.br
agendamento.sergiolimajr.com.br
anamnese.clinicamegasjdr.com.br
bookings.littlepartymonkeys.com
bot.comercializadoraomicron.com
elevateyourmind.groovepages.com
viewer-v2-typebot-io.vercel.app
yourfeedback.comebackreward.com
gerador.verificadordehospedes.com
personal-trainer.barrettamario.it
preagendamento.sergiolimajr.com.br
studiotecnicoimmobiliaremerelli.it
download.thailandmicespecialist.com
register.thailandmicespecialist.com
bot.studiotecnicoimmobiliaremerelli.it
pesquisa.escolamodacomproposito.com.br
anamnese.clinicaramosodontologia.com.br
viewer-v2-git-main-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 409e764 Jan 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./apps/docs

docs-git-main-typebot-io.vercel.app
docs.typebot.io
docs-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 409e764 Jan 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-git-main-typebot-io.vercel.app
app.typebot.io
builder-v2-typebot-io.vercel.app

Please sign in to comment.