feat(frontend): persist selected tab on admin settings page refresh

Store the selected tab of the admin settings page in the URL query string under the tab parameter. Defend against invalid values by validating it against the list of known tabs.
This commit is contained in:
ryan
2026-06-30 20:52:24 +08:00
parent 1855b48028
commit c293a255d0
2 changed files with 26 additions and 3 deletions
@@ -7,7 +7,7 @@ import dynamic from "next/dynamic"
import {useEffect, useMemo} from "react"
import {useQuery} from "@tanstack/react-query"
import {Loader2, Settings} from "lucide-react"
import {useRouter} from "next/navigation"
import {useRouter, useSearchParams} from "next/navigation"
import {motion} from "motion/react"
import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs"
@@ -59,6 +59,17 @@ function systemConfigMap(configs: SystemConfig[]) {
export function AdminSettingsPageClient() {
const { user, loading } = useAuth()
const router = useRouter()
const searchParams = useSearchParams()
const activeTab = useMemo(() => {
const rawTab = searchParams.get("tab")
const validTabs = ["security", "operation", "system", "other", "status", "info"]
return rawTab && validTabs.includes(rawTab) ? rawTab : "security"
}, [searchParams])
const handleTabChange = (value: string) => {
router.push(`/admin/settings?tab=${value}`)
}
const systemConfigsQuery = useQuery({
queryKey: ["admin", "system-configs"],
@@ -98,7 +109,7 @@ export function AdminSettingsPageClient() {
<h1 className="text-2xl font-semibold tracking-tight">系统设置</h1>
</div>
</div>
<Tabs defaultValue="security" className="w-full">
<Tabs value={activeTab} onValueChange={handleTabChange} className="w-full">
<TabsList variant="line" className="w-fit inline-flex gap-8 mb-6">
<TabsTrigger value="security" className="px-0 pb-2 text-xs font-semibold">
安全设置
+13 -1
View File
@@ -1,8 +1,20 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
import {Suspense} from "react"
import {Loader2} from "lucide-react"
import {AdminSettingsPageClient} from "./page-client"
export default function AdminSettingsPage() {
return <AdminSettingsPageClient />
return (
<Suspense
fallback={
<div className="flex items-center justify-center min-h-[400px]">
<Loader2 className="size-6 animate-spin text-primary" />
</div>
}
>
<AdminSettingsPageClient />
</Suspense>
)
}