fix: better webhook error handling

This commit is contained in:
vas3k
2025-05-22 17:04:19 +02:00
parent da16558298
commit 3976db1114
4 changed files with 26 additions and 11 deletions

View File

@@ -37,7 +37,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
id: user.id, id: user.id,
name: user.name || "", name: user.name || "",
email: user.email, email: user.email,
avatar: user.avatar || undefined, avatar: user.avatar ? user.avatar + "?" + user.id : undefined,
membershipPlan: user.membershipPlan || "unlimited", membershipPlan: user.membershipPlan || "unlimited",
storageUsed: user.storageUsed || 0, storageUsed: user.storageUsed || 0,
storageLimit: user.storageLimit || -1, storageLimit: user.storageLimit || -1,

View File

@@ -36,25 +36,28 @@ export async function POST(request: Request) {
const customerId = session.customer as string const customerId = session.customer as string
const subscriptionId = session.subscription as string const subscriptionId = session.subscription as string
const subscription = await stripeClient.subscriptions.retrieve(subscriptionId) const subscription = await stripeClient.subscriptions.retrieve(subscriptionId)
const item = subscription.items.data[0]
await handleUserSubscriptionUpdate(customerId, item) for (const item of subscription.items.data) {
await handleUserSubscriptionUpdate(customerId, item)
}
break break
} }
case "customer.subscription.created": case "customer.subscription.created":
case "customer.subscription.updated": { case "customer.subscription.updated":
case "customer.subscription.deleted": {
const subscription = event.data.object as Stripe.Subscription const subscription = event.data.object as Stripe.Subscription
const customerId = subscription.customer as string const customerId = subscription.customer as string
const item = subscription.items.data[0]
await handleUserSubscriptionUpdate(customerId, item) for (const item of subscription.items.data) {
await handleUserSubscriptionUpdate(customerId, item)
}
break break
} }
default: default:
console.log(`Unhandled event type ${event.type}`) console.log(`Unhandled event type ${event.type}`)
return new NextResponse("No handler for event type", { status: 200 }) return new NextResponse("No handler for event type", { status: 400 })
} }
return new NextResponse("Webhook processed successfully", { status: 200 }) return new NextResponse("Webhook processed successfully", { status: 200 })
@@ -91,11 +94,18 @@ async function handleUserSubscriptionUpdate(
} }
} }
const newMembershipExpiresAt = new Date(item.current_period_end * 1000)
await updateUser(user.id, { await updateUser(user.id, {
membershipPlan: plan.code, membershipPlan: plan.code,
membershipExpiresAt: new Date(item.current_period_end * 1000), membershipExpiresAt:
user.membershipExpiresAt && user.membershipExpiresAt > newMembershipExpiresAt
? user.membershipExpiresAt
: newMembershipExpiresAt,
storageLimit: plan.limits.storage, storageLimit: plan.limits.storage,
aiBalance: plan.limits.ai, aiBalance: plan.limits.ai,
updatedAt: new Date(), updatedAt: new Date(),
}) })
console.log(`Updated user ${user.id} with plan ${plan.code} and expires at ${newMembershipExpiresAt}`)
} }

View File

@@ -2,7 +2,7 @@
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import * as Sentry from "@sentry/nextjs" import * as Sentry from "@sentry/nextjs"
import { Angry } from "lucide-react" import { Ghost } from "lucide-react"
import Link from "next/link" import Link from "next/link"
import { useEffect } from "react" import { useEffect } from "react"
@@ -16,7 +16,7 @@ export default function GlobalError({ error }: { error: Error }) {
<body> <body>
<div className="min-h-screen flex flex-col items-center justify-center bg-background p-4"> <div className="min-h-screen flex flex-col items-center justify-center bg-background p-4">
<div className="text-center space-y-4"> <div className="text-center space-y-4">
<Angry className="w-24 h-24 text-destructive mx-auto" /> <Ghost className="w-24 h-24 text-destructive mx-auto" />
<h1 className="text-4xl font-bold text-foreground">Oops! Something went wrong</h1> <h1 className="text-4xl font-bold text-foreground">Oops! Something went wrong</h1>
<p className="text-muted-foreground max-w-md mx-auto"> <p className="text-muted-foreground max-w-md mx-auto">
We apologize for the inconvenience. Our team has been notified and is working to fix the issue. We apologize for the inconvenience. Our team has been notified and is working to fix the issue.

View File

@@ -15,7 +15,12 @@ export default function ProfileSettingsForm({ user }: { user: User }) {
return ( return (
<div> <div>
<form action={saveAction} className="space-y-4"> <form action={saveAction} className="space-y-4">
<FormAvatar title="Avatar" name="avatar" className="w-24 h-24" defaultValue={user.avatar || ""} /> <FormAvatar
title="Avatar"
name="avatar"
className="w-24 h-24"
defaultValue={user.avatar ? user.avatar + "?" + user.id : ""}
/>
<FormInput title="Account Name" name="name" defaultValue={user.name || ""} /> <FormInput title="Account Name" name="name" defaultValue={user.name || ""} />