fenghuo/apps/web/app/auth/callback/page.tsx

121 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useEffect, useState } from 'react';
import { useSearchParams, useRouter } from 'next/navigation';
import { userManager } from '@/lib/oidc-config';
import { Loader2, CheckCircle, XCircle } from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@repo/ui/components/card';
import { Alert, AlertDescription } from '@repo/ui/components/alert';
export default function CallbackPage() {
const searchParams = useSearchParams();
const router = useRouter();
const [status, setStatus] = useState<'loading' | 'success' | 'error'>('loading');
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const handleCallback = async () => {
try {
if (!userManager) {
throw new Error('用户管理器未初始化');
}
// 处理OIDC回调
const user = await userManager.signinRedirectCallback();
if (user) {
setStatus('success');
// 延迟跳转到首页
setTimeout(() => {
router.push('/');
}, 2000);
} else {
throw new Error('未收到用户信息');
}
} catch (err) {
console.error('回调处理失败:', err);
setError(err instanceof Error ? err.message : '未知错误');
setStatus('error');
}
};
// 检查是否有授权码或错误参数
const code = searchParams.get('code');
const error = searchParams.get('error');
const errorDescription = searchParams.get('error_description');
if (error) {
setError(`${error}: ${errorDescription || '授权失败'}`);
setStatus('error');
return;
}
if (code) {
handleCallback();
} else {
setError('缺少授权码');
setStatus('error');
}
}, [searchParams, router]);
const getStatusIcon = () => {
switch (status) {
case 'loading':
return <Loader2 className="h-8 w-8 animate-spin text-blue-500" />;
case 'success':
return <CheckCircle className="h-8 w-8 text-green-500" />;
case 'error':
return <XCircle className="h-8 w-8 text-red-500" />;
}
};
const getStatusMessage = () => {
switch (status) {
case 'loading':
return '正在处理登录回调...';
case 'success':
return '登录成功!正在跳转...';
case 'error':
return '登录失败';
}
};
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900">
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<div className="flex justify-center mb-4">{getStatusIcon()}</div>
<CardTitle className="text-xl">{getStatusMessage()}</CardTitle>
</CardHeader>
<CardContent>
{status === 'error' && error && (
<Alert variant="destructive">
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
{status === 'loading' && (
<div className="text-center text-sm text-gray-600 dark:text-gray-400">
<p>...</p>
</div>
)}
{status === 'success' && (
<div className="text-center text-sm text-gray-600 dark:text-gray-400">
<p>...</p>
</div>
)}
{status === 'error' && (
<div className="text-center mt-4">
<button onClick={() => router.push('/')} className="text-blue-600 hover:text-blue-800 text-sm">
</button>
</div>
)}
</CardContent>
</Card>
</div>
);
}