diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx index bca66a1..9b7d28a 100644 --- a/src/pages/LoginPage.tsx +++ b/src/pages/LoginPage.tsx @@ -18,7 +18,7 @@ export function LoginPage() { const { error } = await login(email, password); if (error) { - setError(error.message || '登录失败'); + setError(error); } else { navigate('/'); } diff --git a/src/pages/RegisterPage.tsx b/src/pages/RegisterPage.tsx index 5b93d47..0063213 100644 --- a/src/pages/RegisterPage.tsx +++ b/src/pages/RegisterPage.tsx @@ -12,16 +12,33 @@ export function RegisterPage() { const [loading, setLoading] = useState(false); const [error, setError] = useState(''); + // 密码强度验证 + const passwordRequirements = [ + { label: '至少8个字符', met: password.length >= 8 }, + { label: '包含大写字母', met: /[A-Z]/.test(password) }, + { label: '包含小写字母', met: /[a-z]/.test(password) }, + { label: '包含数字', met: /\d/.test(password) }, + ]; + + const meetsAllRequirements = passwordRequirements.every((req) => req.met); + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(''); + if (!meetsAllRequirements) { + setError('密码不符合要求,请检查密码格式'); + setLoading(false); + return; + } + const { error } = await register(email, password, nickname); if (error) { - setError(error.message || '注册失败'); + setError(error); } else { - navigate('/login'); + // 注册成功后直接跳转到首页(已登录状态) + navigate('/'); } setLoading(false); }; @@ -48,16 +65,31 @@ export function RegisterPage() { onChange={(e) => setEmail(e.target.value)} required /> - setPassword(e.target.value)} - required - /> +
+ setPassword(e.target.value)} + required + /> + {/* 密码要求提示 */} + + {passwordRequirements.map((req, index) => ( + + {req.met ? '✓' : '○'} {req.label} + + ))} + +
{error && {error}} - diff --git a/src/routes.tsx b/src/routes.tsx index 3044c74..6932975 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -1,23 +1,76 @@ -import { createBrowserRouter } from 'react-router-dom'; +import { createBrowserRouter, Navigate } from 'react-router-dom'; import { LandingPage } from './pages/LandingPage'; import { LoginPage } from './pages/LoginPage'; import { RegisterPage } from './pages/RegisterPage'; import { HomePage } from './pages/HomePage'; import { useAppStore } from './stores'; -import { useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; -// Protected Route wrapper -function ProtectedRoute({ children }: { children: React.ReactNode }) { +// Loading spinner component +function AuthLoading() { + return ( +
+
+ +
+ ); +} + +// Auth loader - handles checkAuth and loading state +function useAuthLoader() { const isAuthenticated = useAppStore((state) => state.isAuthenticated); const checkAuth = useAppStore((state) => state.checkAuth); const isLoading = useAppStore((state) => state.isLoading); + // 使用 ref 跟踪是否已检查过,避免重复检查 + const checkedRef = useRef(false); + useEffect(() => { - checkAuth(); - }, [checkAuth]); + // 标记已检查,但只在未登录时调用 checkAuth + if (!checkedRef.current) { + checkedRef.current = true; + // 如果未登录,才需要检查 + if (!isAuthenticated) { + checkAuth(); + } + } + }, [checkAuth, isAuthenticated]); + + // 如果已登录,直接返回,不再显示 Loading + if (isAuthenticated) { + return { isAuthenticated: true, isLoading: false }; + } + + return { isAuthenticated: false, isLoading }; +} + +// Protected Route wrapper +function ProtectedRoute({ children }: { children: React.ReactNode }) { + const { isAuthenticated, isLoading } = useAuthLoader(); if (isLoading) { - return null; // Or a loading spinner + return ; + } + + if (!isAuthenticated) { + return ; } return <>{children}; @@ -25,15 +78,14 @@ function ProtectedRoute({ children }: { children: React.ReactNode }) { // Public Route wrapper (redirects to home if authenticated) function PublicRoute({ children }: { children: React.ReactNode }) { - const isAuthenticated = useAppStore((state) => state.isAuthenticated); - const checkAuth = useAppStore((state) => state.checkAuth); + const { isAuthenticated, isLoading } = useAuthLoader(); - useEffect(() => { - checkAuth(); - }, [checkAuth]); + if (isLoading) { + return ; + } if (isAuthenticated) { - return ; + return ; } return <>{children}; @@ -42,6 +94,10 @@ function PublicRoute({ children }: { children: React.ReactNode }) { export const router = createBrowserRouter([ { path: '/', + element: , + }, + { + path: '/landing', element: ( diff --git a/src/stores/index.ts b/src/stores/index.ts index aa54c49..ffa1865 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -93,7 +93,7 @@ export const useAppStore = create()( saveNotes: async (content) => { try { - const notes = await api.notes.save(content); + const notes = await api.notes.update(content); set({ notes }); } catch (error) { console.error('Failed to save notes:', error); @@ -143,7 +143,9 @@ export const useAppStore = create()( set({ user, isAuthenticated: true }); return { error: null }; } catch (error: any) { - return { error: error.message || '登录失败' }; + // 确保返回字符串错误信息 + const errorMessage = error.message || '登录失败,请检查邮箱和密码'; + return { error: errorMessage }; } }, @@ -154,7 +156,9 @@ export const useAppStore = create()( set({ user, isAuthenticated: true }); return { error: null }; } catch (error: any) { - return { error: error.message || '注册失败' }; + // 确保返回字符串错误信息 + const errorMessage = error.message || '注册失败,请稍后重试'; + return { error: errorMessage }; } },