🚸 (billing) Add precheckout form
Collects required company name and email and create the customer before redirecting to checkout
This commit is contained in:
@@ -7,8 +7,9 @@ import { TextLink } from '@/components/TextLink'
|
||||
import { useToast } from '@/hooks/useToast'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
import { guessIfUserIsEuropean } from 'utils/pricing'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Workspace } from 'models'
|
||||
import { PreCheckoutModal, PreCheckoutModalProps } from '../PreCheckoutModal'
|
||||
import { useState } from 'react'
|
||||
|
||||
type Props = {
|
||||
workspace: Pick<Workspace, 'id' | 'stripeId' | 'plan'>
|
||||
@@ -16,25 +17,15 @@ type Props = {
|
||||
}
|
||||
|
||||
export const ChangePlanForm = ({ workspace, onUpgradeSuccess }: Props) => {
|
||||
const router = useRouter()
|
||||
const { user } = useUser()
|
||||
const { showToast } = useToast()
|
||||
const [preCheckoutPlan, setPreCheckoutPlan] =
|
||||
useState<PreCheckoutModalProps['selectedSubscription']>()
|
||||
|
||||
const { data } = trpc.billing.getSubscription.useQuery({
|
||||
workspaceId: workspace.id,
|
||||
})
|
||||
|
||||
const { mutate: createCheckoutSession, isLoading: isCreatingCheckout } =
|
||||
trpc.billing.createCheckoutSession.useMutation({
|
||||
onError: (error) => {
|
||||
showToast({
|
||||
description: error.message,
|
||||
})
|
||||
},
|
||||
onSuccess: ({ checkoutUrl }) => {
|
||||
router.push(checkoutUrl)
|
||||
},
|
||||
})
|
||||
|
||||
const { mutate: updateSubscription, isLoading: isUpdatingSubscription } =
|
||||
trpc.billing.updateSubscription.useMutation({
|
||||
onError: (error) => {
|
||||
@@ -79,15 +70,20 @@ export const ChangePlanForm = ({ workspace, onUpgradeSuccess }: Props) => {
|
||||
if (workspace.stripeId) {
|
||||
updateSubscription(newSubscription)
|
||||
} else {
|
||||
createCheckoutSession({
|
||||
...newSubscription,
|
||||
returnUrl: window.location.href,
|
||||
})
|
||||
setPreCheckoutPlan(newSubscription)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack spacing={6}>
|
||||
{!workspace.stripeId && (
|
||||
<PreCheckoutModal
|
||||
selectedSubscription={preCheckoutPlan}
|
||||
existingEmail={user?.email ?? undefined}
|
||||
existingCompany={user?.company ?? undefined}
|
||||
onClose={() => setPreCheckoutPlan(undefined)}
|
||||
/>
|
||||
)}
|
||||
<HStack alignItems="stretch" spacing="4" w="full">
|
||||
<StarterPlanContent
|
||||
initialChatsLimitIndex={
|
||||
@@ -103,7 +99,7 @@ export const ChangePlanForm = ({ workspace, onUpgradeSuccess }: Props) => {
|
||||
onPayClick={(props) =>
|
||||
handlePayClick({ ...props, plan: Plan.STARTER })
|
||||
}
|
||||
isLoading={isCreatingCheckout || isUpdatingSubscription}
|
||||
isLoading={isUpdatingSubscription}
|
||||
currency={data?.subscription.currency}
|
||||
/>
|
||||
|
||||
@@ -119,7 +115,7 @@ export const ChangePlanForm = ({ workspace, onUpgradeSuccess }: Props) => {
|
||||
: 0
|
||||
}
|
||||
onPayClick={(props) => handlePayClick({ ...props, plan: Plan.PRO })}
|
||||
isLoading={isCreatingCheckout || isUpdatingSubscription}
|
||||
isLoading={isUpdatingSubscription}
|
||||
currency={data?.subscription.currency}
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { TextInput } from '@/components/inputs'
|
||||
import { useToast } from '@/hooks/useToast'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalContent,
|
||||
ModalOverlay,
|
||||
Stack,
|
||||
} from '@chakra-ui/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import React, { FormEvent, useState } from 'react'
|
||||
import { isDefined } from 'utils'
|
||||
|
||||
export type PreCheckoutModalProps = {
|
||||
selectedSubscription:
|
||||
| {
|
||||
plan: 'STARTER' | 'PRO'
|
||||
workspaceId: string
|
||||
additionalChats: number
|
||||
additionalStorage: number
|
||||
currency: 'eur' | 'usd'
|
||||
}
|
||||
| undefined
|
||||
existingCompany?: string
|
||||
existingEmail?: string
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export const PreCheckoutModal = ({
|
||||
selectedSubscription,
|
||||
existingCompany,
|
||||
existingEmail,
|
||||
onClose,
|
||||
}: PreCheckoutModalProps) => {
|
||||
const router = useRouter()
|
||||
const { showToast } = useToast()
|
||||
const { mutate: createCheckoutSession, isLoading: isCreatingCheckout } =
|
||||
trpc.billing.createCheckoutSession.useMutation({
|
||||
onError: (error) => {
|
||||
showToast({
|
||||
description: error.message,
|
||||
})
|
||||
},
|
||||
onSuccess: ({ checkoutUrl }) => {
|
||||
router.push(checkoutUrl)
|
||||
},
|
||||
})
|
||||
|
||||
const [customer, setCustomer] = useState({
|
||||
company: existingCompany ?? '',
|
||||
email: existingEmail ?? '',
|
||||
})
|
||||
|
||||
const updateCustomerCompany = (company: string) => {
|
||||
setCustomer((customer) => ({ ...customer, company }))
|
||||
}
|
||||
|
||||
const updateCustomerEmail = (email: string) => {
|
||||
setCustomer((customer) => ({ ...customer, email }))
|
||||
}
|
||||
|
||||
const createCustomer = (e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (!selectedSubscription) return
|
||||
createCheckoutSession({
|
||||
...selectedSubscription,
|
||||
email: customer.email,
|
||||
company: customer.company,
|
||||
returnUrl: window.location.href,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={isDefined(selectedSubscription)} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalBody py="8">
|
||||
<Stack as="form" onSubmit={createCustomer} spacing="4">
|
||||
<TextInput
|
||||
isRequired
|
||||
label="Company name"
|
||||
defaultValue={customer.company}
|
||||
onChange={updateCustomerCompany}
|
||||
withVariableButton={false}
|
||||
debounceTimeout={0}
|
||||
/>
|
||||
<TextInput
|
||||
isRequired
|
||||
type="email"
|
||||
label="Email"
|
||||
defaultValue={customer.email}
|
||||
onChange={updateCustomerEmail}
|
||||
withVariableButton={false}
|
||||
debounceTimeout={0}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
isLoading={isCreatingCheckout}
|
||||
colorScheme="blue"
|
||||
isDisabled={customer.company === '' || customer.email === ''}
|
||||
>
|
||||
Go to checkout
|
||||
</Button>
|
||||
</Stack>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user