diff --git a/app/(dashboard)/dashboard/billing/page.tsx b/app/(dashboard)/dashboard/billing/page.tsx index 795244b..b701477 100644 --- a/app/(dashboard)/dashboard/billing/page.tsx +++ b/app/(dashboard)/dashboard/billing/page.tsx @@ -2,6 +2,7 @@ import { redirect } from "next/navigation" import { getCurrentUser } from "@/lib/session" import { authOptions } from "@/lib/auth" +import { stripe } from "@/lib/stripe" import { getUserSubscriptionPlan as getUserSubscriptionPlan } from "@/lib/subscription" import { Card } from "@/ui/card" import { DashboardHeader } from "@/components/dashboard/header" @@ -17,6 +18,15 @@ export default async function BillingPage() { const subscriptionPlan = await getUserSubscriptionPlan(user.id) + // If user has a pro plan, check cancel status on Stripe. + let isCanceled = false + if (subscriptionPlan.isPro) { + const stripePlan = await stripe.subscriptions.retrieve( + subscriptionPlan.stripeSubscriptionId + ) + isCanceled = stripePlan.cancel_at_period_end + } + return (
- + Note diff --git a/components/dashboard/billing-form.tsx b/components/dashboard/billing-form.tsx index 092c576..a7a3bc6 100644 --- a/components/dashboard/billing-form.tsx +++ b/components/dashboard/billing-form.tsx @@ -9,7 +9,9 @@ import { toast } from "@/ui/toast" import { Icons } from "@/components/icons" interface BillingFormProps extends React.HTMLAttributes { - subscriptionPlan: UserSubscriptionPlan + subscriptionPlan: UserSubscriptionPlan & { + isCanceled: boolean + } } export function BillingForm({ diff --git a/components/dashboard/editor.tsx b/components/dashboard/editor.tsx index 6ebe453..0e4641b 100644 --- a/components/dashboard/editor.tsx +++ b/components/dashboard/editor.tsx @@ -87,6 +87,9 @@ export function Editor({ post }: EditorProps) { const response = await fetch(`/api/posts/${post.id}`, { method: "PATCH", + headers: { + "Content-Type": "application/json", + }, body: JSON.stringify({ title: data.title, content: blocks, diff --git a/components/dashboard/post-create-button.tsx b/components/dashboard/post-create-button.tsx index ce8bfd1..12436e8 100644 --- a/components/dashboard/post-create-button.tsx +++ b/components/dashboard/post-create-button.tsx @@ -22,6 +22,9 @@ export function PostCreateButton({ const response = await fetch("/api/posts", { method: "POST", + headers: { + "Content-Type": "application/json", + }, body: JSON.stringify({ title: "Untitled Post", }), diff --git a/components/dashboard/user-name-form.tsx b/components/dashboard/user-name-form.tsx index f0af425..625ae10 100644 --- a/components/dashboard/user-name-form.tsx +++ b/components/dashboard/user-name-form.tsx @@ -38,6 +38,9 @@ export function UserNameForm({ user, className, ...props }: UserNameFormProps) { const response = await fetch(`/api/users/${user.id}`, { method: "PATCH", + headers: { + "Content-Type": "application/json", + }, body: JSON.stringify({ name: data.name, }), diff --git a/lib/api-middlewares/with-validation.ts b/lib/api-middlewares/with-validation.ts index 43b26bb..e9cbb62 100644 --- a/lib/api-middlewares/with-validation.ts +++ b/lib/api-middlewares/with-validation.ts @@ -8,7 +8,7 @@ export function withValidation( ) { return async function (req: NextApiRequest, res: NextApiResponse) { try { - const body = req.body ? JSON.parse(req.body) : {} + const body = req.body ? req.body : {} await schema.parse(body) diff --git a/lib/subscription.ts b/lib/subscription.ts index 4561bf8..bb58700 100644 --- a/lib/subscription.ts +++ b/lib/subscription.ts @@ -1,7 +1,6 @@ import { UserSubscriptionPlan } from "types" import { freePlan, proPlan } from "@/config/subscriptions" import { db } from "@/lib/db" -import { stripe } from "@/lib/stripe" export async function getUserSubscriptionPlan( userId: string @@ -25,20 +24,10 @@ export async function getUserSubscriptionPlan( const plan = isPro ? proPlan : freePlan - // If user has a pro plan, check cancel status on Stripe. - let isCanceled = false - if (isPro && user.stripeSubscriptionId) { - const stripePlan = await stripe.subscriptions.retrieve( - user.stripeSubscriptionId - ) - isCanceled = stripePlan.cancel_at_period_end - } - return { ...plan, ...user, stripeCurrentPeriodEnd: user.stripeCurrentPeriodEnd?.getTime(), - isCanceled, isPro, } } diff --git a/pages/api/posts/[postId].ts b/pages/api/posts/[postId].ts index 9e55a1c..59d43db 100644 --- a/pages/api/posts/[postId].ts +++ b/pages/api/posts/[postId].ts @@ -30,7 +30,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { }, }) - const body = postPatchSchema.parse(JSON.parse(req.body)) + const body = postPatchSchema.parse(req.body) // TODO: Implement sanitization for content. diff --git a/pages/api/posts/index.ts b/pages/api/posts/index.ts index 65bf97d..10c96ef 100644 --- a/pages/api/posts/index.ts +++ b/pages/api/posts/index.ts @@ -1,12 +1,13 @@ import { NextApiRequest, NextApiResponse } from "next" -import { getSession } from "next-auth/react" import * as z from "zod" +import { unstable_getServerSession } from "next-auth/next" import { db } from "@/lib/db" import { withMethods } from "@/lib/api-middlewares/with-methods" import { withAuthentication } from "@/lib/api-middlewares/with-authentication" import { getUserSubscriptionPlan } from "@/lib/subscription" import { RequiresProPlanError } from "@/lib/exceptions" +import { authOptions } from "@/lib/auth" const postCreateSchema = z.object({ title: z.string().optional(), @@ -14,7 +15,7 @@ const postCreateSchema = z.object({ }) async function handler(req: NextApiRequest, res: NextApiResponse) { - const session = await getSession({ req }) + const session = await unstable_getServerSession(req, res, authOptions) const user = session?.user if (req.method === "GET") { @@ -55,7 +56,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { } } - const body = postCreateSchema.parse(JSON.parse(req.body)) + const body = postCreateSchema.parse(req.body) const post = await db.post.create({ data: { diff --git a/pages/api/users/[userId].ts b/pages/api/users/[userId].ts index 28bbafd..337d6ca 100644 --- a/pages/api/users/[userId].ts +++ b/pages/api/users/[userId].ts @@ -1,19 +1,20 @@ import { NextApiRequest, NextApiResponse } from "next" import * as z from "zod" -import { getSession } from "next-auth/react" +import { unstable_getServerSession } from "next-auth/next" import { db } from "@/lib/db" import { withMethods } from "@/lib/api-middlewares/with-methods" import { withCurrentUser } from "@/lib/api-middlewares/with-current-user" import { userNameSchema } from "@/lib/validations/user" +import { authOptions } from "@/lib/auth" async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === "PATCH") { try { - const session = await getSession({ req }) + const session = await unstable_getServerSession(req, res, authOptions) const user = session?.user - const body = JSON.parse(req.body) + const body = req.body if (body?.name) { const payload = userNameSchema.parse(body) @@ -30,7 +31,6 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { return res.end() } catch (error) { - console.log(error) if (error instanceof z.ZodError) { return res.status(422).json(error.issues) } diff --git a/pages/api/users/stripe.ts b/pages/api/users/stripe.ts index c2d2d60..fc282a5 100644 --- a/pages/api/users/stripe.ts +++ b/pages/api/users/stripe.ts @@ -1,5 +1,5 @@ import { NextApiRequest, NextApiResponse } from "next" -import { getSession } from "next-auth/react" +import { unstable_getServerSession } from "next-auth/next" import { proPlan } from "@/config/subscriptions" import { withMethods } from "@/lib/api-middlewares/with-methods" @@ -7,13 +7,14 @@ import { getUserSubscriptionPlan } from "@/lib/subscription" import { stripe } from "@/lib/stripe" import { withAuthentication } from "@/lib/api-middlewares/with-authentication" import { absoluteUrl } from "@/lib/utils" +import { authOptions } from "@/lib/auth" const billingUrl = absoluteUrl("/dashboard/billing") async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === "GET") { try { - const session = await getSession({ req }) + const session = await unstable_getServerSession(req, res, authOptions) const user = session.user const subscriptionPlan = await getUserSubscriptionPlan(user.id) diff --git a/types/index.d.ts b/types/index.d.ts index 0be7044..94097e3 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -58,5 +58,4 @@ export type UserSubscriptionPlan = SubscriptionPlan & Pick & { stripeCurrentPeriodEnd: number isPro: boolean - isCanceled: boolean }