Files
mimic/frontend/src/hooks/useHashTab.ts
Knacky 11ce3cfb86 fix(frontend): code-review polish — replaceState, arrow-key nav, TabId, comment
Fix 4: useHashTab navigate() uses history.replaceState instead of
window.location.hash assignment — no spurious history entries, no
anchor-jump scroll side-effect.
Fix 5: Tabs ArrowLeft/ArrowRight keyboard nav (WAI-ARIA tabs pattern).
Fix 6: TabId union type in EngagementDetailPage, cast from string for
type-safe switch on activeTab without breaking Tabs.onChange signature.
Fix 7: intentional comment on UsersAdminPage reset-password aerated row.
Tests: 236/236 (+2 arrow-key assertions in Tabs.test.tsx).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 22:20:51 +02:00

27 lines
856 B
TypeScript

import { useCallback, useEffect, useState } from 'react';
function readHash(defaultId: string): string {
const hash = window.location.hash.slice(1); // strip leading '#'
return hash || defaultId;
}
export function useHashTab(defaultId: string): [string, (id: string) => void] {
const [activeId, setActiveId] = useState<string>(() => readHash(defaultId));
useEffect(() => {
function onHashChange() {
setActiveId(readHash(defaultId));
}
window.addEventListener('hashchange', onHashChange);
return () => window.removeEventListener('hashchange', onHashChange);
}, [defaultId]);
const navigate = useCallback((id: string) => {
// replaceState: no history entry (Back button unaffected), no anchor-jump scroll
history.replaceState(null, '', '#' + id);
setActiveId(id);
}, []);
return [activeId, navigate];
}