Skip to content

Commit

Permalink
feat(account): ✨ Add coupon code input
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Feb 14, 2022
1 parent 9c20ef0 commit b345131
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 7 deletions.
44 changes: 42 additions & 2 deletions apps/builder/components/account/BillingSection.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,44 @@
import { Stack, Heading, HStack, Button, Text } from '@chakra-ui/react'
import {
Stack,
Heading,
HStack,
Button,
Text,
Input,
useToast,
} from '@chakra-ui/react'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { useUser } from 'contexts/UserContext'
import { Plan } from 'db'
import React from 'react'
import { useRouter } from 'next/router'
import React, { useState } from 'react'
import { redeemCoupon } from 'services/coupons'
import { SubscriptionTag } from './SubscriptionTag'

export const BillingSection = () => {
const { reload } = useRouter()
const [isLoading, setIsLoading] = useState(false)

const { user } = useUser()
const toast = useToast({
position: 'top-right',
})

const handleCouponCodeRedeem = async (e: React.FormEvent) => {
e.preventDefault()
const target = e.target as typeof e.target & {
coupon: { value: string }
}
setIsLoading(true)
const { data, error } = await redeemCoupon(target.coupon.value)
if (error) toast({ title: error.name, description: error.message })
else {
toast({ description: data?.message })
setTimeout(reload, 1000)
}
setIsLoading(false)
}

return (
<Stack direction="row" spacing="10" justifyContent={'space-between'}>
<Heading as="h2" fontSize="xl">
Expand All @@ -25,6 +57,14 @@ export const BillingSection = () => {
{user?.plan === Plan.FREE && (
<Button colorScheme="blue">Upgrade</Button>
)}
{user?.plan === Plan.FREE && (
<HStack as="form" onSubmit={handleCouponCodeRedeem}>
<Input name="coupon" placeholder="Coupon code..." />
<Button type="submit" isLoading={isLoading}>
Redeem
</Button>
</HStack>
)}
</Stack>
</Stack>
)
Expand Down
31 changes: 31 additions & 0 deletions apps/builder/pages/api/coupons/redeem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Prisma, User } from 'db'
import prisma from 'libs/prisma'
import { NextApiRequest, NextApiResponse } from 'next'
import { getSession } from 'next-auth/react'

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'POST') {
const session = await getSession({ req })

if (!session?.user)
return res.status(401).json({ message: 'Not authenticated' })

const user = session.user as User
const { code } = JSON.parse(req.body)
const coupon = await prisma.coupon.findFirst({
where: { code, dateRedeemed: null },
})
if (!coupon) return res.status(404).send({ message: 'Coupon not found' })
await prisma.user.update({
where: { id: user.id },
data: coupon.userPropertiesToUpdate as Prisma.UserUncheckedUpdateInput,
})
await prisma.coupon.update({
where: { code },
data: { dateRedeemed: new Date() },
})
return res.send({ message: 'Coupon redeemed 🎊' })
}
}

export default handler
8 changes: 8 additions & 0 deletions apps/builder/services/coupons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { sendRequest } from 'utils'

export const redeemCoupon = async (code: string) =>
sendRequest<{ message: string }>({
method: 'POST',
url: '/api/coupons/redeem',
body: { code },
})
6 changes: 3 additions & 3 deletions packages/db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"scripts": {
"dev": "dotenv -e .env yarn prisma db push && BROWSER=none yarn prisma studio",
"build": "yarn migration:push",
"migration:push": "dotenv -e ../../.env yarn prisma db push",
"migration:create": "dotenv -e ../../.env yarn prisma migrate dev",
"migration:reset": "dotenv -e ../../.env yarn prisma migrate reset"
"migration:push": "dotenv -e .env yarn prisma db push",
"migration:create": "dotenv -e .env yarn prisma migrate dev",
"migration:reset": "dotenv -e .env yarn prisma migrate reset"
}
}
10 changes: 8 additions & 2 deletions packages/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ model User {
}

model Credentials {
id String @id @default(cuid())
id String @id @default(cuid())
ownerId String
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
data String // Encrypted data
name String
type String
Expand Down Expand Up @@ -143,3 +143,9 @@ model Answer {
@@unique([resultId, blockId, stepId])
}

model Coupon {
userPropertiesToUpdate Json
code String @id
dateRedeemed DateTime?
}

3 comments on commit b345131

@vercel
Copy link

@vercel vercel bot commented on b345131 Feb 14, 2022

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:

landing-page-v2 – ./apps/landing-page

landing-page-v2-git-main-typebot-io.vercel.app
landing-page-v2-typebot-io.vercel.app
landing-page-v2-jade.vercel.app

@vercel
Copy link

@vercel vercel bot commented on b345131 Feb 14, 2022

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

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

@vercel
Copy link

@vercel vercel bot commented on b345131 Feb 14, 2022

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
builder-v2-typebot-io.vercel.app
next.typebot.io

Please sign in to comment.