Skip to content

Commit f68ac73

Browse files
committed
Fetch authenticated billing portal link!
1 parent fadcc88 commit f68ac73

File tree

3 files changed

+22
-4
lines changed

3 files changed

+22
-4
lines changed

common/src/types/subscription.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export interface ActiveSubscriptionResponse {
5252
subscription: SubscriptionInfo
5353
rateLimit: SubscriptionRateLimit
5454
limits: SubscriptionLimits
55+
billingPortalUrl?: string
5556
}
5657

5758
/**

web/src/app/api/user/subscription/route.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import {
44
getSubscriptionLimits,
55
} from '@codebuff/billing'
66
import { SUBSCRIPTION_DISPLAY_NAME } from '@codebuff/common/constants/subscription-plans'
7+
import { env } from '@codebuff/internal/env'
8+
import { stripeServer } from '@codebuff/internal/util/stripe'
79
import { NextResponse } from 'next/server'
810
import { getServerSession } from 'next-auth'
911

@@ -29,9 +31,23 @@ export async function GET() {
2931
return NextResponse.json(response)
3032
}
3133

32-
const [rateLimit, limits] = await Promise.all([
34+
const stripeCustomerId = session.user.stripe_customer_id
35+
36+
const [rateLimit, limits, billingPortalUrl] = await Promise.all([
3337
checkRateLimit({ userId, subscription, logger }),
3438
getSubscriptionLimits({ userId, logger, tier: subscription.tier }),
39+
stripeCustomerId
40+
? stripeServer.billingPortal.sessions
41+
.create({
42+
customer: stripeCustomerId,
43+
return_url: `${env.NEXT_PUBLIC_CODEBUFF_APP_URL}/profile`,
44+
})
45+
.then((portalSession) => portalSession.url)
46+
.catch((error) => {
47+
logger.warn({ userId, error }, 'Failed to create billing portal session')
48+
return undefined
49+
})
50+
: Promise.resolve(undefined),
3551
])
3652

3753
const response: ActiveSubscriptionResponse = {
@@ -58,6 +74,7 @@ export async function GET() {
5874
weeklyPercentUsed: rateLimit.weeklyPercentUsed,
5975
},
6076
limits,
77+
billingPortalUrl,
6178
}
6279
return NextResponse.json(response)
6380
}

web/src/app/profile/components/subscription-section.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ function ProgressBar({ percentAvailable, label }: { percentAvailable: number; la
4848
function SubscriptionActive({ data, email }: { data: ActiveSubscriptionResponse; email: string }) {
4949
const { subscription, rateLimit } = data
5050
const isCanceling = subscription.cancelAtPeriodEnd
51-
const billingPortalUrl = `${env.NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL}?prefilled_email=${encodeURIComponent(email)}`
51+
const fallbackPortalUrl = `${env.NEXT_PUBLIC_STRIPE_CUSTOMER_PORTAL}?prefilled_email=${encodeURIComponent(email)}`
52+
const billingPortalUrl = data.billingPortalUrl ?? fallbackPortalUrl
5253

5354
return (
5455
<Card className="max-w-xl">
@@ -155,8 +156,7 @@ function SubscriptionCta() {
155156
Upgrade to {SUBSCRIPTION_DISPLAY_NAME}
156157
</h3>
157158
<p className="text-sm text-muted-foreground">
158-
From $100/mo · Work in focused 5-hour sessions with no
159-
interruptions.
159+
From $100/mo · Save credits with 5-hour work sessions included
160160
</p>
161161
</div>
162162
</div>

0 commit comments

Comments
 (0)