Remember last visited page per section in localStorage

This commit is contained in:
Steven RYDELL
2026-07-30 12:48:25 +02:00
parent 5127a3bf8a
commit 231f2ec3ee
3 changed files with 59 additions and 0 deletions
+5
View File
@@ -25,6 +25,7 @@ import {
isLinkEnterprise,
isLinkVisible,
} from '@/lib/layout';
import { findLastVisitedLinkInLayout, setLastVisitedSection } from '@/lib/lastVisited';
import type { Layout, LayoutItem, LayoutSubItem } from '@/types/schema';
function LucideIcon({ name, className }: { name: string; className?: string }) {
@@ -185,6 +186,7 @@ function SidebarSubItem({ item, depth, sectionName, currentPath, navigate, editi
if (isLocked) {
onUpsell();
} else {
setLastVisitedSection(sectionName, item.viewName);
navigate(path);
}
}}
@@ -270,6 +272,7 @@ function SidebarTopItem({ item, sectionName, currentPath, navigate, edition, onU
if (isLocked) {
onUpsell();
} else {
setLastVisitedSection(sectionName, viewName);
navigate(path);
}
}}
@@ -365,7 +368,9 @@ export function Sidebar() {
const handleSectionClick = (target: Layout) => {
setActiveSection(target.name);
const canGet = (prefix: string) => permissions.includes(`${prefix}Get`);
const last = findLastVisitedLinkInLayout(schema, target, edition, canGet, hasPermission);
const first =
last ??
findFirstAccessibleLinkInLayout(schema, target, edition, canGet, hasPermission) ??
findFirstVisibleLinkInLayout(schema, target, edition, canGet, hasPermission);
if (first) navigate(`/${target.name}/${first}`);
+3
View File
@@ -24,6 +24,7 @@ import { ModeToggle } from '@/components/common/ModeToggle';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { EnterpriseUpsell } from '@/components/common/EnterpriseUpsell';
import { findFirstAccessibleLinkInLayout, findFirstVisibleLinkInLayout, visibleLayouts } from '@/lib/layout';
import { findLastVisitedLinkInLayout } from '@/lib/lastVisited';
import { useUIStore } from '@/stores/uiStore';
import { useAuthStore } from '@/stores/authStore';
import { buildEndSessionUrl, getPostLogoutRedirectUri } from '@/services/auth/oauth';
@@ -152,7 +153,9 @@ export function TopBar() {
onClick={() => {
setActiveSection(layout.name);
const canGet = (prefix: string) => hasObjectPermission(prefix, 'Get');
const lastLink = findLastVisitedLinkInLayout(schema, layout, edition, canGet, hasPermission);
const firstLink =
lastLink ??
findFirstAccessibleLinkInLayout(schema, layout, edition, canGet, hasPermission) ??
findFirstVisibleLinkInLayout(schema, layout, edition, canGet, hasPermission);
if (firstLink) {
+51
View File
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
import { isLinkAccessible } from './layout';
import type { Layout, Schema } from '@/types/schema';
type CanGet = (prefix: string) => boolean;
type HasPermission = (permission: string) => boolean;
const STORAGE_KEY = 'stalwart-last-visited';
// Stores the last visited view name for a given top-level section in localStorage.
export function setLastVisitedSection(section: string, viewName: string): void {
try {
const raw = localStorage.getItem(STORAGE_KEY);
const data = raw ? (JSON.parse(raw) as Record<string, string>) : {};
data[section] = viewName;
localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
} catch {
// Ignore storage errors (e.g. private mode).
}
}
// Retrieves the last visited view name for a section, or null if none is stored.
export function getLastVisitedSection(section: string): string | null {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const data = JSON.parse(raw) as Record<string, string>;
return data[section] ?? null;
} catch {
return null;
}
}
// Returns the stored view name only if it is still accessible in the target layout.
export function findLastVisitedLinkInLayout(
schema: Schema,
layout: Layout,
edition: string,
canGet: CanGet,
hasPermission: HasPermission,
): string | null {
const last = getLastVisitedSection(layout.name);
if (!last) return null;
if (isLinkAccessible(schema, last, edition, canGet, hasPermission)) return last;
return null;
}