diff --git a/app/analytics/page.tsx b/app/analytics/page.tsx index c290ed4..dbe235a 100644 --- a/app/analytics/page.tsx +++ b/app/analytics/page.tsx @@ -14,6 +14,7 @@ import { ProjectSelector } from '@/app/components/ui/ProjectSelector'; import { TagSelector } from '@/app/components/ui/TagSelector'; import { useSearchParams } from 'next/navigation'; import { useShortUrlStore } from '@/app/utils/store'; +import ClientRouteGuard from '@/app/components/ClientRouteGuard'; // 事件类型定义 interface Event { @@ -1109,12 +1110,14 @@ function AnalyticsContent() { // Main page component with Suspense export default function AnalyticsPage() { return ( - -
-
- }> - -
+ + +
+
+ }> + +
+
); } \ No newline at end of file diff --git a/app/components/ClientRouteGuard.tsx b/app/components/ClientRouteGuard.tsx new file mode 100644 index 0000000..36b66c7 --- /dev/null +++ b/app/components/ClientRouteGuard.tsx @@ -0,0 +1,45 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; + +// 这个组件会检查 localStorage 中是否有认证令牌,如果没有则重定向到登录页面 +export default function ClientRouteGuard({ children }: { children: React.ReactNode }) { + const router = useRouter(); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + // 检查 localStorage 中是否有认证令牌 + const checkAuth = () => { + // 查找 Supabase 认证令牌 + const hasAuthToken = !!localStorage.getItem('sb-mwwvqwevplndzvmqmrxa-auth-token') || + !!localStorage.getItem('sb-auth-token'); + + if (!hasAuthToken) { + // 如果没有令牌,重定向到登录页面 + router.push('/login'); + } else { + setIsAuthenticated(true); + } + setIsLoading(false); + }; + + checkAuth(); + }, [router]); + + // 显示加载状态 + if (isLoading) { + return ( +
+
+
+

加载中...

+
+
+ ); + } + + // 只有当用户已认证时才显示子组件 + return isAuthenticated ? <>{children} : null; +} \ No newline at end of file diff --git a/app/create-shorturl/page.tsx b/app/create-shorturl/page.tsx index f6dc1d1..c6cbd80 100644 --- a/app/create-shorturl/page.tsx +++ b/app/create-shorturl/page.tsx @@ -3,10 +3,10 @@ import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useAuth } from '@/lib/auth'; -import { ProtectedRoute } from '@/lib/auth'; import { limqRequest } from '@/lib/api'; import { TeamSelector } from '@/app/components/ui/TeamSelector'; import { ProjectSelector } from '@/app/components/ui/ProjectSelector'; +import ClientRouteGuard from '@/app/components/ClientRouteGuard'; interface ShortUrlData { originalUrl: string; @@ -21,9 +21,9 @@ interface ShortUrlData { export default function CreateShortUrlPage() { return ( - + - + ); } diff --git a/app/links/page.tsx b/app/links/page.tsx index dcd25cb..31e135c 100644 --- a/app/links/page.tsx +++ b/app/links/page.tsx @@ -7,6 +7,7 @@ import { Loader2, ExternalLink, Search } from 'lucide-react'; import { TeamSelector } from '@/app/components/ui/TeamSelector'; import { useRouter } from 'next/navigation'; import { useShortUrlStore, ShortUrlData } from '@/app/utils/store'; +import ClientRouteGuard from '@/app/components/ClientRouteGuard'; // Define attribute type to avoid using 'any' interface LinkAttributes { @@ -102,6 +103,14 @@ const convertClickHouseToShortLink = (data: Record): ShortLink }; export default function LinksPage() { + return ( + + + + ); +} + +function LinksPageContent() { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [links, setLinks] = useState([]);