70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, Suspense } from "react"
|
|
import { useRouter, useSearchParams } from "next/navigation"
|
|
import { useAuthStore } from "@/lib/api/auth-store"
|
|
import type { PlatformUser } from "@/lib/auth/jwt-claims"
|
|
|
|
function AuthCompleteInner() {
|
|
const router = useRouter()
|
|
const searchParams = useSearchParams()
|
|
const login = useAuthStore((s) => s.login)
|
|
const returnTo = searchParams.get("returnTo") ?? "/mail/inbox"
|
|
const accountNotice = searchParams.get("accountNotice")
|
|
|
|
useEffect(() => {
|
|
let cancelled = false
|
|
|
|
async function finish() {
|
|
try {
|
|
const res = await fetch("/api/auth/session", { credentials: "include" })
|
|
const data = (await res.json()) as {
|
|
authenticated?: boolean
|
|
accessToken?: string
|
|
refreshToken?: string | null
|
|
expiresAt?: number
|
|
user?: PlatformUser | null
|
|
}
|
|
if (
|
|
data.authenticated &&
|
|
data.accessToken &&
|
|
data.expiresAt &&
|
|
!cancelled
|
|
) {
|
|
login(
|
|
data.accessToken,
|
|
data.refreshToken ?? "",
|
|
data.expiresAt,
|
|
data.user ?? null
|
|
)
|
|
if (accountNotice === "same") {
|
|
sessionStorage.setItem("ulti_account_notice", "same")
|
|
}
|
|
router.replace(returnTo.startsWith("/") ? returnTo : "/mail/inbox")
|
|
return
|
|
}
|
|
} catch {
|
|
// fall through
|
|
}
|
|
if (!cancelled) {
|
|
router.replace("/login?error=session_failed")
|
|
}
|
|
}
|
|
|
|
void finish()
|
|
return () => {
|
|
cancelled = true
|
|
}
|
|
}, [accountNotice, login, returnTo, router])
|
|
|
|
return null
|
|
}
|
|
|
|
export default function AuthCompletePage() {
|
|
return (
|
|
<Suspense fallback={null}>
|
|
<AuthCompleteInner />
|
|
</Suspense>
|
|
)
|
|
}
|