diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 20c5dd3..8ac7595 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -32,7 +32,7 @@ import Playlists from "./components/Playlists"; import Stats from "./components/Stats"; import Scheduler from "./components/Scheduler"; import ConfigPanel from "./components/ConfigPanel"; -import AdminUsers from "./components/AdminUsers"; +import AdminUsers, { focusAccessRequestsTab } from "./components/AdminUsers"; import SettingsPanel from "./components/SettingsPanel"; import NotificationsPanel from "./components/NotificationsPanel"; import Messages from "./components/Messages"; @@ -372,7 +372,13 @@ export default function App() { // Durable inbox link (survives reload, unlike a live action callback); the toast also // gets a click via the action. meta: { kind: "access-requests" }, - action: { label: t("common.accessRequestsReview"), onClick: () => setPage("users") }, + action: { + label: t("common.accessRequestsReview"), + onClick: () => { + focusAccessRequestsTab(); + setPage("users"); + }, + }, }); } } diff --git a/frontend/src/components/AdminUsers.tsx b/frontend/src/components/AdminUsers.tsx index 8c6aeae..e90b8e5 100644 --- a/frontend/src/components/AdminUsers.tsx +++ b/frontend/src/components/AdminUsers.tsx @@ -11,9 +11,19 @@ import Tabs, { usePersistedTab } from "./Tabs"; // Admin-only user & access management: roles, access requests (the Invite whitelist), and the // demo whitelist + reset. Each section is its own tab (persisted across reloads); the Access tab // carries a badge with the count of pending requests so it's visible without switching to it. +// The persisted-tab storage key + the access-requests tab id, exported so a notification's +// "Review" link can pre-select that tab before navigating here (usePersistedTab reads the key +// on mount, and this page mounts fresh on navigation). +export const ADMIN_USERS_TAB_KEY = "siftlode.adminUsersTab"; +export const ADMIN_USERS_ACCESS_TAB = "access"; + +export function focusAccessRequestsTab(): void { + localStorage.setItem(ADMIN_USERS_TAB_KEY, ADMIN_USERS_ACCESS_TAB); +} + export default function AdminUsers({ me }: { me: Me }) { const { t } = useTranslation(); - const [tab, setTab] = usePersistedTab("siftlode.adminUsersTab", "roles"); + const [tab, setTab] = usePersistedTab(ADMIN_USERS_TAB_KEY, "roles"); const tabs = [ { id: "roles", label: t("users.tabs.roles") }, { id: "access", label: t("users.tabs.access"), badge: me.pending_invites }, diff --git a/frontend/src/components/NotificationsPanel.tsx b/frontend/src/components/NotificationsPanel.tsx index e4883b5..044074d 100644 --- a/frontend/src/components/NotificationsPanel.tsx +++ b/frontend/src/components/NotificationsPanel.tsx @@ -4,6 +4,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Activity, Bell, Check, CheckCheck, ExternalLink, Eye, RotateCcw, Search, Trash2, Tv, UserPlus, X } from "lucide-react"; import { api, type AppNotification, type FeedFilters } from "../lib/api"; import { useLiveQuery } from "../lib/useLiveQuery"; +import { focusAccessRequestsTab } from "./AdminUsers"; import { clearAll as clearClient, dismiss as dismissClient, @@ -190,7 +191,10 @@ export default function NotificationsPanel({ onFind={locate} onRevert={revertState} onFocusChannel={onFocusChannel} - onReviewAccess={() => setPage("users")} + onReviewAccess={() => { + focusAccessRequestsTab(); + setPage("users"); + }} onRemove={() => removeClient(n.id)} /> ))}