Skip to content

Commit

Permalink
🚸 (billing) Improve feedback when subscription is "past_due"
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Sep 12, 2023
1 parent 6375a24 commit 0ccc2ef
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 26 deletions.
20 changes: 12 additions & 8 deletions apps/builder/src/features/billing/api/getSubscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,30 +61,34 @@ export const getSubscription = authenticatedProcedure
})
const subscriptions = await stripe.subscriptions.list({
customer: workspace.stripeId,
limit: 1,
status: 'active',
})

const subscription = subscriptions?.data.shift()
const currentSubscription = subscriptions.data
.filter((sub) => ['past_due', 'active'].includes(sub.status))
.sort((a, b) => a.created - b.created)
.shift()

if (!subscription)
if (!currentSubscription)
return {
subscription: null,
}

return {
subscription: {
isYearly: subscription.items.data.some((item) => {
status: subscriptionSchema.shape.status.parse(
currentSubscription.status
),
isYearly: currentSubscription.items.data.some((item) => {
return (
priceIds.STARTER.chats.yearly === item.price.id ||
priceIds.STARTER.storage.yearly === item.price.id ||
priceIds.PRO.chats.yearly === item.price.id ||
priceIds.PRO.storage.yearly === item.price.id
)
}),
currency: subscription.currency as 'usd' | 'eur',
cancelDate: subscription.cancel_at
? new Date(subscription.cancel_at * 1000)
currency: currentSubscription.currency as 'usd' | 'eur',
cancelDate: currentSubscription.cancel_at
? new Date(currentSubscription.cancel_at * 1000)
: undefined,
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useToast } from '@/hooks/useToast'
import { trpc } from '@/lib/trpc'
import { useScopedI18n } from '@/locales'
import { Button, Link } from '@chakra-ui/react'
import { Button, ButtonProps, Link } from '@chakra-ui/react'

type Props = {
workspaceId: string
}
} & Pick<ButtonProps, 'colorScheme'>

export const BillingPortalButton = ({ workspaceId }: Props) => {
export const BillingPortalButton = ({ workspaceId, colorScheme }: Props) => {
const scopedT = useScopedI18n('billing')
const { showToast } = useToast()
const { data } = trpc.billing.getBillingPortalUrl.useQuery(
Expand All @@ -23,7 +23,12 @@ export const BillingPortalButton = ({ workspaceId }: Props) => {
}
)
return (
<Button as={Link} href={data?.billingPortalUrl} isLoading={!data}>
<Button
as={Link}
href={data?.billingPortalUrl}
isLoading={!data}
colorScheme={colorScheme}
>
{scopedT('billingPortalButton.label')}
</Button>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ export const ChangePlanForm = ({ workspace }: Props) => {
}
}

if (data?.subscription?.cancelDate) return null
if (
data?.subscription?.cancelDate ||
data?.subscription?.status === 'past_due'
)
return null

return (
<Stack spacing={6}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Text, HStack, Stack, Heading } from '@chakra-ui/react'
import {
Text,
HStack,
Stack,
Heading,
Alert,
AlertIcon,
} from '@chakra-ui/react'
import { Plan } from '@typebot.io/prisma'
import React from 'react'
import { PlanTag } from './PlanTag'
Expand Down Expand Up @@ -35,8 +42,21 @@ export const CurrentSubscriptionSummary = ({ workspace }: Props) => {
</Text>
)}
</HStack>
{data?.subscription?.status === 'past_due' && (
<Alert fontSize="sm" status="error">
<AlertIcon />
{scopedT('pastDueAlert')}
</Alert>
)}

{isSubscribed && <BillingPortalButton workspaceId={workspace.id} />}
{isSubscribed && (
<BillingPortalButton
workspaceId={workspace.id}
colorScheme={
data?.subscription?.status === 'past_due' ? 'blue' : undefined
}
/>
)}
</Stack>
)
}
2 changes: 2 additions & 0 deletions apps/builder/src/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export default {
'billing.currentSubscription.heading': 'Abonnement',
'billing.currentSubscription.subheading': 'Aktuelles Workspace-Abonnement:',
'billing.currentSubscription.cancelDate': 'Wird storniert am',
'billing.currentSubscription.pastDueAlert':
'Die letzte Zahlung ist fehlgeschlagen. Gehen Sie zum Abrechnungsportal, um fortzufahren und eine Kündigung Ihres Abonnements zu vermeiden.',
'billing.invoices.heading': 'Rechnungen',
'billing.invoices.empty': 'Keine Rechnungen für diesen Workspace gefunden.',
'billing.invoices.paidAt': 'Bezahlt am',
Expand Down
2 changes: 2 additions & 0 deletions apps/builder/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ export default {
'billing.currentSubscription.heading': 'Subscription',
'billing.currentSubscription.subheading': 'Current workspace subscription:',
'billing.currentSubscription.cancelDate': 'Will be cancelled on',
'billing.currentSubscription.pastDueAlert':
'The latest payment failed. Head over to the billing portal to proceed and avoid having your subscription canceled.',
'billing.invoices.heading': 'Invoices',
'billing.invoices.empty': 'No invoices found for this workspace.',
'billing.invoices.paidAt': 'Paid at',
Expand Down
2 changes: 2 additions & 0 deletions apps/builder/src/locales/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ export default {
'billing.currentSubscription.heading': 'Abonnement',
'billing.currentSubscription.subheading': 'Abonnement actuel du workspace :',
'billing.currentSubscription.cancelDate': 'Sera annulé le',
'billing.currentSubscription.pastDueAlert':
"Le dernier paiement a échoué. Rendez-vous sur le portail de facturation pour effectuer la procédure et éviter l'annulation de votre abonnement.",
'billing.invoices.heading': 'Factures',
'billing.invoices.empty': 'Aucune facture trouvée pour ce workspace.',
'billing.invoices.paidAt': 'Payé le',
Expand Down
2 changes: 2 additions & 0 deletions apps/builder/src/locales/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ export default {
'billing.currentSubscription.subheading':
'Assinatura atual do espaço de trabalho:',
'billing.currentSubscription.cancelDate': 'Será cancelado em',
'billing.currentSubscription.pastDueAlert':
'O último pagamento falhou. Acesse o portal de faturamento para prosseguir e evitar o cancelamento da sua assinatura.',
'billing.invoices.heading': 'Faturas',
'billing.invoices.empty':
'Nenhuma fatura encontrada para este espaço de trabalho.',
Expand Down
2 changes: 2 additions & 0 deletions apps/builder/src/locales/pt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export default {
'billing.currentSubscription.subheading':
'Subscrição actual do espaço de trabalho:',
'billing.currentSubscription.cancelDate': 'Será cancelado em',
'billing.currentSubscription.pastDueAlert':
'O último pagamento falhou. Acesse o portal de faturamento para continuar e evitar o cancelamento da sua assinatura.',
'billing.invoices.heading': 'Facturas',
'billing.invoices.empty':
'Nenhuma factura encontrada para este espaço de trabalho.',
Expand Down
31 changes: 20 additions & 11 deletions apps/docs/openapi/builder/_spec_.json
Original file line number Diff line number Diff line change
Expand Up @@ -30689,11 +30689,19 @@
"cancelDate": {
"type": "string",
"format": "date-time"
},
"status": {
"type": "string",
"enum": [
"active",
"past_due"
]
}
},
"required": [
"isYearly",
"currency"
"currency",
"status"
],
"additionalProperties": false
},
Expand Down Expand Up @@ -32760,7 +32768,7 @@
}
}
},
"/typebots/{typebotId}/blocks/{blockId}/openai/models": {
"/openai/models": {
"get": {
"operationId": "openAI-listModels",
"summary": "List OpenAI models",
Expand All @@ -32774,33 +32782,34 @@
],
"parameters": [
{
"name": "typebotId",
"in": "path",
"name": "credentialsId",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "blockId",
"in": "path",
"name": "workspaceId",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "credentialsId",
"name": "baseUrl",
"in": "query",
"required": true,
"required": false,
"schema": {
"type": "string"
"type": "string",
"default": "https://api.openai.com/v1"
}
},
{
"name": "workspaceId",
"name": "apiVersion",
"in": "query",
"required": true,
"required": false,
"schema": {
"type": "string"
}
Expand Down
1 change: 1 addition & 0 deletions packages/schemas/features/billing/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const subscriptionSchema = z.object({
isYearly: z.boolean(),
currency: z.enum(['eur', 'usd']),
cancelDate: z.date().optional(),
status: z.enum(['active', 'past_due']),
})

export type Subscription = z.infer<typeof subscriptionSchema>

4 comments on commit 0ccc2ef

@vercel
Copy link

@vercel vercel bot commented on 0ccc2ef Sep 12, 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.vercel.app
docs.typebot.io

@vercel
Copy link

@vercel vercel bot commented on 0ccc2ef Sep 12, 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-typebot-io.vercel.app
app.typebot.io
builder-v2-git-main-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 0ccc2ef Sep 12, 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

bot.tobb.pro
cinecorn.com
ezbooking.ai
gniorder.com
help.taxt.co
kusamint.com
psmix.online
receita.info
rhino.cr8.ai
sheep.cr8.ai
snake.cr8.ai
svhm.mprs.in
tiger.cr8.ai
video.cr8.ai
webwhats.fun
webwhats.pro
yoda.riku.ai
zebra.cr8.ai
akademicq.com
alvodelas.com
bemestar.club
bot.krdfy.com
cat.hidden.sg
cgcassets.com
cnvhub.com.br
drapamela.com
facelabko.com
filmylogy.com
goldorayo.com
rabbit.cr8.ai
shop.mexwa.my
signup.cr8.ai
start.taxt.co
theusm.com.br
turkey.cr8.ai
vhpage.cr8.ai
vitamyway.com
whatchat.site
www.wiccom.it
am.nigerias.io
an.nigerias.io
app.yvon.earth
ar.nigerias.io
bot.enreso.org
bot.mail2wa.me
bot.rslabs.pro
bots.bng.tools
bots.bridge.ai
chad.gocto.com
chat.hayuri.id
chat.uprize.hu
chatgpt.lam.ee
chicken.cr8.ai
drayumi.social
gollum.riku.ai
gsbulletin.com
journey.cr8.ai
kopibayane.com
panther.cr7.ai
panther.cr8.ai
pay.sifuim.com
penguin.cr8.ai
segredomeu.com
talk.gocare.io
test.bot.gives
ticketfute.com
unicorn.cr8.ai
whats-app.chat
apo.nigerias.io
app.blogely.com
apr.nigerias.io
aso.nigerias.io
blackcan.cr8.ai
blackvip.online
bot.4display.nl
bot.a6t-you.com
bot.artiweb.app
bot.devitus.com
bot.reeplai.com
bot.scayver.com
bot.tc-mail.com
carspecs.lam.ee
chat.lalmon.com
chat.sureb4.com
conversawpp.com
eventhub.com.au
feiraododia.com
fitness.riku.ai
games.klujo.com
localove.online
proscale.com.br
sellmycarbr.com
svhmapp.mprs.in
typebot.aloe.do
app-liberado.pro
ask.pemantau.org
chat.gaswadern.de
chat.onrentme.com
chat.rojie.online
chatdocidadao.com

@vercel
Copy link

@vercel vercel bot commented on 0ccc2ef Sep 12, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.