Skip to content

Commit ddc29b4

Browse files
committed
UI
1 parent bb8783c commit ddc29b4

3 files changed

Lines changed: 55 additions & 46 deletions

File tree

apps/web/src/app/account/plan/page.tsx

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,13 @@
11
'use client'
22

3-
import { useEffect, useState } from 'react'
4-
import { useRouter } from 'next/navigation'
53
import { useTranslations } from 'next-intl'
64
import { Loader2 } from 'lucide-react'
7-
import { backendFetch } from '@/lib/backend-auth'
8-
import { PlanCard, type PlanProfile } from '@/components/plan-card'
5+
import { PlanCard } from '@/components/plan-card'
6+
import { useAccountProfile } from '@/lib/use-account-profile'
97

108
export default function AccountPlanPage() {
119
const t = useTranslations('AccountPlan')
12-
const router = useRouter()
13-
const [profile, setProfile] = useState<PlanProfile | null>(null)
14-
15-
useEffect(() => {
16-
let cancelled = false
17-
backendFetch('/api/backend/auth/me')
18-
.then(async (res) => {
19-
if (cancelled) return
20-
if (!res.ok) {
21-
router.replace('/login?next=/account/plan')
22-
return
23-
}
24-
setProfile(await res.json())
25-
})
26-
.catch(() => {
27-
if (!cancelled) router.replace('/login?next=/account/plan')
28-
})
29-
return () => { cancelled = true }
30-
}, [router])
10+
const { profile } = useAccountProfile('/account/plan')
3111

3212
if (!profile) {
3313
return (

apps/web/src/app/dashboard/page.tsx

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,16 @@
11
'use client'
22

3-
import { useEffect, useState } from 'react'
4-
import { useRouter } from 'next/navigation'
53
import { useTranslations } from 'next-intl'
64
import { Loader2 } from 'lucide-react'
75
import { Header } from '@/components/header'
86
import { Footer } from '@/components/footer'
9-
import { backendFetch } from '@/lib/backend-auth'
10-
import { PlanCard, type PlanProfile } from '@/components/plan-card'
7+
import { PlanCard } from '@/components/plan-card'
118
import { PasskeysManager } from '@/components/passkeys-manager'
9+
import { useAccountProfile } from '@/lib/use-account-profile'
1210

1311
export default function DashboardPage() {
1412
const t = useTranslations('Dashboard')
15-
const router = useRouter()
16-
const [profile, setProfile] = useState<PlanProfile | null>(null)
17-
18-
useEffect(() => {
19-
let cancelled = false
20-
backendFetch('/api/backend/auth/me')
21-
.then(async (res) => {
22-
if (cancelled) return
23-
if (!res.ok) {
24-
router.replace('/login?next=/dashboard')
25-
return
26-
}
27-
setProfile(await res.json())
28-
})
29-
.catch(() => {
30-
if (!cancelled) router.replace('/login?next=/dashboard')
31-
})
32-
return () => { cancelled = true }
33-
}, [router])
13+
const { profile } = useAccountProfile('/dashboard')
3414

3515
return (
3616
<>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use client'
2+
3+
import { useEffect, useState } from 'react'
4+
import { useRouter } from 'next/navigation'
5+
import useAuth from '@/utils/useAuth'
6+
import { backendFetch, ensureBackendSession } from '@/lib/backend-auth'
7+
import type { PlanProfile } from '@/components/plan-card'
8+
9+
/**
10+
* Loads the signed-in user's account profile for authed pages (dashboard, plan).
11+
*
12+
* Right after OAuth sign-in, LoginRedirectIfAuthed navigates here on the
13+
* `onAuthStateChanged` event — which can fire *before* login-form's
14+
* `establishBackendSession` has set the API cookie. Calling `ensureBackendSession`
15+
* first mints/verifies that cookie from the Firebase user, so `/auth/me` doesn't
16+
* 401 → forceLogout → bounce the user straight back to /login.
17+
*/
18+
export function useAccountProfile(nextPath: string): { profile: PlanProfile | null } {
19+
const { user, loading } = useAuth(false)
20+
const router = useRouter()
21+
const [profile, setProfile] = useState<PlanProfile | null>(null)
22+
23+
useEffect(() => {
24+
if (loading) return
25+
const toLogin = () => router.replace(`/login?next=${encodeURIComponent(nextPath)}`)
26+
if (!user) {
27+
toLogin()
28+
return
29+
}
30+
let cancelled = false
31+
;(async () => {
32+
try {
33+
await ensureBackendSession(user)
34+
const res = await backendFetch('/api/backend/auth/me')
35+
if (cancelled) return
36+
if (!res.ok) {
37+
toLogin()
38+
return
39+
}
40+
setProfile(await res.json())
41+
} catch {
42+
if (!cancelled) toLogin()
43+
}
44+
})()
45+
return () => { cancelled = true }
46+
}, [user, loading, router, nextPath])
47+
48+
return { profile }
49+
}

0 commit comments

Comments
 (0)