2
0

feat(account): Add coupon code input

This commit is contained in:
Baptiste Arnaud
2022-02-14 09:00:47 +01:00
parent 9c20ef00b9
commit b345131b0b
5 changed files with 92 additions and 7 deletions

View File

@ -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">
@ -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>
)

View File

@ -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

View File

@ -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 },
})

View File

@ -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"
}
}

View File

@ -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
@ -143,3 +143,9 @@ model Answer {
@@unique([resultId, blockId, stepId])
}
model Coupon {
userPropertiesToUpdate Json
code String @id
dateRedeemed DateTime?
}