99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { useRouter } from 'next/router';
|
|
import { AppProps } from 'next/app';
|
|
import { Toaster } from 'react-hot-toast';
|
|
import { supabase } from '../lib/supabase';
|
|
import { User } from '@supabase/supabase-js';
|
|
import '../styles/globals.css';
|
|
|
|
export default function App({ Component, pageProps }: AppProps) {
|
|
const [user, setUser] = useState<User | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const router = useRouter();
|
|
|
|
useEffect(() => {
|
|
// 检查是否为演示模式
|
|
const isDemoMode = !process.env.NEXT_PUBLIC_SUPABASE_URL ||
|
|
process.env.NEXT_PUBLIC_SUPABASE_URL === 'https://demo.supabase.co' ||
|
|
process.env.NEXT_PUBLIC_SUPABASE_URL === '';
|
|
|
|
const checkUser = async () => {
|
|
try {
|
|
if (isDemoMode) {
|
|
// 演示模式下不检查用户认证
|
|
setUser(null);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
const { data: { user } } = await supabase.auth.getUser();
|
|
setUser(user);
|
|
} catch (error) {
|
|
console.error('Auth check error:', error);
|
|
setUser(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
checkUser();
|
|
|
|
if (!isDemoMode) {
|
|
// 只在非演示模式下监听认证状态变化
|
|
const { data: { subscription } } = supabase.auth.onAuthStateChange(
|
|
async (event: any, session: any) => {
|
|
setUser(session?.user ?? null);
|
|
|
|
if (event === 'SIGNED_OUT' || !session?.user) {
|
|
router.push('/auth/login');
|
|
} else if (event === 'SIGNED_IN' && session?.user) {
|
|
router.push('/dashboard');
|
|
}
|
|
}
|
|
);
|
|
|
|
return () => {
|
|
subscription.unsubscribe();
|
|
};
|
|
}
|
|
}, [router]);
|
|
|
|
// 显示加载状态
|
|
if (loading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
|
<div className="loading-spinner"></div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Component {...pageProps} user={user} />
|
|
<Toaster
|
|
position="top-right"
|
|
toastOptions={{
|
|
duration: 4000,
|
|
style: {
|
|
background: '#363636',
|
|
color: '#fff',
|
|
},
|
|
success: {
|
|
duration: 3000,
|
|
iconTheme: {
|
|
primary: '#10b981',
|
|
secondary: '#fff',
|
|
},
|
|
},
|
|
error: {
|
|
duration: 5000,
|
|
iconTheme: {
|
|
primary: '#ef4444',
|
|
secondary: '#fff',
|
|
},
|
|
},
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|