feat(web): make settings tabs URL-addressable via ?tab=

Add an optional `tab` search param (validated against the known tab set)
to /dashboard/settings and drive the Tabs component from it, so each tab
is shareable/bookmarkable (e.g. /dashboard/settings?tab=referral). Tab
clicks update the URL with replace to avoid history spam; existing links
need no search param since `tab` is optional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 23:23:44 +03:00
parent 681a25ec2e
commit d679907e2c
2 changed files with 32 additions and 3 deletions

View File

@@ -8,11 +8,31 @@ const SettingsContent = lazy(() =>
})),
);
export const SETTINGS_TABS = [
"profile",
"security",
"connections",
"referral",
"account",
"changelog",
] as const;
export type SettingsTab = (typeof SETTINGS_TABS)[number];
function isSettingsTab(value: unknown): value is SettingsTab {
return SETTINGS_TABS.includes(value as SettingsTab);
}
export const Route = createFileRoute("/dashboard/settings")({
// `tab` is optional so existing <Link to="/dashboard/settings"> need no search param.
validateSearch: (search: Record<string, unknown>): { tab?: SettingsTab } =>
isSettingsTab(search.tab) ? { tab: search.tab } : {},
component: SettingsPage,
});
function SettingsPage() {
const { tab } = Route.useSearch();
const navigate = Route.useNavigate();
return (
<Suspense
fallback={
@@ -23,7 +43,10 @@ function SettingsPage() {
</div>
}
>
<SettingsContent />
<SettingsContent
tab={tab ?? "profile"}
onTabChange={(next) => navigate({ search: { tab: next as SettingsTab }, replace: true })}
/>
</Suspense>
);
}