Skip to content

Commit a7c990f

Browse files
jahoomaclaude
andcommitted
Simplify referrer plumbing and clean up onboard/profile pages
- Consolidate to a single `codebuff_referrer` localStorage key. WelcomeCard now both fires the PostHog attribution event (post-auth) and renders the personalized title, removing the tracker/welcome-card race. - Delete ReferrerTracker and its mount in the root layout. - Replace HTTP self-fetch in /referrals/[code] with a direct DB query and delete the now-unused /api/referrals/[code] route. - Inline the trivial renderSuccessPage/renderErrorCard wrappers in the onboard page. - Hide the Referrals profile tab when the user has no referral history. - Strip leftover console.log debug statements from SignInButton. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 459ad5a commit a7c990f

9 files changed

Lines changed: 149 additions & 197 deletions

File tree

web/src/app/api/referrals/[code]/route.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

web/src/app/layout.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { Footer } from '@/components/footer'
77
import { LayoutWrapper } from '@/components/layout-wrapper'
88
import { Navbar } from '@/components/navbar/navbar'
99
import QueryProvider from '@/components/providers/query-client-provider'
10-
import { ReferrerTracker } from '@/components/referral/referrer-tracker'
1110
import { ThemeProvider } from '@/components/theme-provider'
1211
import { Toaster } from '@/components/ui/toaster'
1312
import { siteConfig } from '@/lib/constant'
@@ -67,7 +66,6 @@ export default function RootLayout({
6766
<SessionProvider>
6867
<QueryProvider>
6968
<PostHogProvider>
70-
<ReferrerTracker />
7169
<Navbar />
7270
<div className="flex-grow">
7371
<LayoutWrapper>{children}</LayoutWrapper>

web/src/app/onboard/page.tsx

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -25,28 +25,6 @@ interface PageProps {
2525
}>
2626
}
2727

28-
function renderErrorCard(title: string, description: string, message: string) {
29-
return CardWithBeams({
30-
title,
31-
description,
32-
content: <p>{message}</p>,
33-
})
34-
}
35-
36-
function renderSuccessPage(
37-
fallbackTitle: string,
38-
description: string,
39-
message: string,
40-
) {
41-
return (
42-
<WelcomeCard
43-
fallbackTitle={fallbackTitle}
44-
description={description}
45-
message={message}
46-
/>
47-
)
48-
}
49-
5028
const Onboard = async ({ searchParams }: PageProps) => {
5129
const resolvedSearchParams = searchParams ? await searchParams : {}
5230
const authCode = resolvedSearchParams.auth_code
@@ -58,10 +36,12 @@ const Onboard = async ({ searchParams }: PageProps) => {
5836
}
5937

6038
if (!authCode) {
61-
return renderSuccessPage(
62-
'Welcome to Codebuff!',
63-
'',
64-
"You're all set! Head back to your terminal to continue.",
39+
return (
40+
<WelcomeCard
41+
fallbackTitle="Welcome to Codebuff!"
42+
description=""
43+
message="You're all set! Head back to your terminal to continue."
44+
/>
6545
)
6646
}
6747

@@ -74,29 +54,44 @@ const Onboard = async ({ searchParams }: PageProps) => {
7454
)
7555

7656
if (!valid) {
77-
return renderErrorCard(
78-
'Uh-oh, spaghettio!',
79-
'Invalid auth code.',
80-
'Please try again and reach out to support@codebuff.com if the problem persists.',
57+
return (
58+
<CardWithBeams
59+
title="Uh-oh, spaghettio!"
60+
description="Invalid auth code."
61+
content={
62+
<p>
63+
Please try again and reach out to support@codebuff.com if the
64+
problem persists.
65+
</p>
66+
}
67+
/>
8168
)
8269
}
8370

8471
if (isAuthCodeExpired(expiresAt)) {
85-
return renderErrorCard(
86-
'Uh-oh, spaghettio!',
87-
'Auth code expired.',
88-
'Please generate a new code and reach out to support@codebuff.com if the problem persists.',
72+
return (
73+
<CardWithBeams
74+
title="Uh-oh, spaghettio!"
75+
description="Auth code expired."
76+
content={
77+
<p>
78+
Please generate a new code and reach out to support@codebuff.com if
79+
the problem persists.
80+
</p>
81+
}
82+
/>
8983
)
9084
}
9185

9286
const isReplay = await checkReplayAttack(fingerprintHash, user.id)
9387
if (isReplay) {
94-
return CardWithBeams({
95-
title: 'Your account is already connected to your CLI!',
96-
description:
97-
'Feel free to close this window and head back to your terminal.',
98-
content: <p>No replay attack for you 👊</p>,
99-
})
88+
return (
89+
<CardWithBeams
90+
title="Your account is already connected to your CLI!"
91+
description="Feel free to close this window and head back to your terminal."
92+
content={<p>No replay attack for you 👊</p>}
93+
/>
94+
)
10095
}
10196

10297
const { hasConflict, existingUserId } = await checkFingerprintConflict(
@@ -108,10 +103,17 @@ const Onboard = async ({ searchParams }: PageProps) => {
108103
{ fingerprintId, existingUserId, attemptedUserId: user.id },
109104
'Fingerprint ownership conflict',
110105
)
111-
return renderErrorCard(
112-
'Unable to complete login',
113-
'Something went wrong during the login process.',
114-
`Please try generating a new login code. If the problem persists, contact ${env.NEXT_PUBLIC_SUPPORT_EMAIL} for assistance.`,
106+
return (
107+
<CardWithBeams
108+
title="Unable to complete login"
109+
description="Something went wrong during the login process."
110+
content={
111+
<p>
112+
Please try generating a new login code. If the problem persists,
113+
contact {env.NEXT_PUBLIC_SUPPORT_EMAIL} for assistance.
114+
</p>
115+
}
116+
/>
115117
)
116118
}
117119

@@ -124,17 +126,26 @@ const Onboard = async ({ searchParams }: PageProps) => {
124126
)
125127

126128
if (success) {
127-
return renderSuccessPage(
128-
'Login successful!',
129-
'',
130-
'Return to your terminal to continue.',
129+
return (
130+
<WelcomeCard
131+
fallbackTitle="Login successful!"
132+
description=""
133+
message="Return to your terminal to continue."
134+
/>
131135
)
132136
}
133137

134-
return renderErrorCard(
135-
'Uh-oh, spaghettio!',
136-
'Something went wrong.',
137-
`Not sure what happened. Please try again and reach out to ${env.NEXT_PUBLIC_SUPPORT_EMAIL} if the problem persists.`,
138+
return (
139+
<CardWithBeams
140+
title="Uh-oh, spaghettio!"
141+
description="Something went wrong."
142+
content={
143+
<p>
144+
Not sure what happened. Please try again and reach out to{' '}
145+
{env.NEXT_PUBLIC_SUPPORT_EMAIL} if the problem persists.
146+
</p>
147+
}
148+
/>
138149
)
139150
}
140151

web/src/app/profile/page.tsx

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client'
22

3+
import { useQuery } from '@tanstack/react-query'
34
import { CreditCard, Shield, Users, Key, Menu, User } from 'lucide-react'
45
import { useRouter, useSearchParams } from 'next/navigation'
56
import { useSession } from 'next-auth/react'
@@ -14,50 +15,65 @@ import { ReferralsSection } from './components/referrals-section'
1415
import { SecuritySection } from './components/security-section'
1516
import { UsageSection } from './components/usage-section'
1617

18+
import type { ReferralData } from '@/app/api/referrals/route'
19+
1720
import { Button } from '@/components/ui/button'
1821
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
1922
import { Skeleton } from '@/components/ui/skeleton'
2023
import { cn } from '@/lib/utils'
2124
import { toast } from '@/components/ui/use-toast'
2225

23-
const sections = [
24-
{
25-
id: 'usage',
26-
title: 'Usage & Credits',
27-
icon: CreditCard,
28-
component: UsageSection,
29-
},
30-
{
31-
id: 'security',
32-
title: 'Security',
33-
icon: Shield,
34-
component: SecuritySection,
35-
},
36-
{
37-
id: 'api-keys',
38-
title: 'API Keys',
39-
icon: Key,
40-
component: ApiKeysSection,
41-
},
42-
{
43-
id: 'referrals',
44-
title: 'Referrals',
45-
icon: Users,
46-
component: ReferralsSection,
47-
},
48-
{
49-
id: 'account',
50-
title: 'Account',
51-
icon: User,
52-
component: AccountSection,
53-
},
54-
]
26+
type Section = {
27+
id: string
28+
title: string
29+
icon: typeof CreditCard
30+
component: React.ComponentType
31+
}
32+
33+
const REFERRALS_SECTION: Section = {
34+
id: 'referrals',
35+
title: 'Referrals',
36+
icon: Users,
37+
component: ReferralsSection,
38+
}
39+
40+
function buildSections(hasReferralHistory: boolean): Section[] {
41+
return [
42+
{
43+
id: 'usage',
44+
title: 'Usage & Credits',
45+
icon: CreditCard,
46+
component: UsageSection,
47+
},
48+
{
49+
id: 'security',
50+
title: 'Security',
51+
icon: Shield,
52+
component: SecuritySection,
53+
},
54+
{
55+
id: 'api-keys',
56+
title: 'API Keys',
57+
icon: Key,
58+
component: ApiKeysSection,
59+
},
60+
...(hasReferralHistory ? [REFERRALS_SECTION] : []),
61+
{
62+
id: 'account',
63+
title: 'Account',
64+
icon: User,
65+
component: AccountSection,
66+
},
67+
]
68+
}
5569

5670
function ProfileSidebar({
71+
sections,
5772
activeSection,
5873
onSectionChange,
5974
onNavigate,
6075
}: {
76+
sections: Section[]
6177
activeSection: string
6278
onSectionChange: (section: string) => void
6379
onNavigate?: () => void
@@ -89,18 +105,34 @@ function ProfileSidebar({
89105
}
90106

91107
function ProfilePageContent() {
92-
const { status } = useSession()
108+
const { data: session, status } = useSession()
93109
const router = useRouter()
94110
const searchParams = useSearchParams() ?? new URLSearchParams()
95111
const [activeSection, setActiveSection] = useState('usage')
96112
const [open, setOpen] = useState(false)
97113

114+
const { data: referralData } = useQuery<ReferralData>({
115+
queryKey: ['referrals'],
116+
queryFn: async () => {
117+
const response = await fetch('/api/referrals')
118+
const ret = await response.json()
119+
if (!response.ok) {
120+
throw new Error(`Failed to fetch referral data: ${ret.error}`)
121+
}
122+
return ret
123+
},
124+
enabled: !!session?.user,
125+
})
126+
const hasReferralHistory =
127+
!!referralData?.referredBy || (referralData?.referrals.length ?? 0) > 0
128+
const sections = buildSections(hasReferralHistory)
129+
98130
useEffect(() => {
99131
const tab = searchParams.get('tab')
100132
if (tab && sections.find((s) => s.id === tab)) {
101133
setActiveSection(tab)
102134
}
103-
}, [searchParams])
135+
}, [searchParams, sections])
104136

105137
// Check for subscription success
106138
useEffect(() => {
@@ -162,6 +194,7 @@ function ProfilePageContent() {
162194
</p>
163195
</div>
164196
<ProfileSidebar
197+
sections={sections}
165198
activeSection={activeSection}
166199
onSectionChange={handleSectionChange}
167200
onNavigate={() => setOpen(false)}
@@ -207,6 +240,7 @@ function ProfilePageContent() {
207240
</p>
208241
</div>
209242
<ProfileSidebar
243+
sections={sections}
210244
activeSection={activeSection}
211245
onSectionChange={handleSectionChange}
212246
onNavigate={() => setOpen(false)}

0 commit comments

Comments
 (0)