Deep link the tabs in the recording view

This commit is contained in:
mccahan 2026-01-22 15:30:30 -07:00
parent 8c09103841
commit 9beb63f921
No known key found for this signature in database
GPG Key ID: 4AD93D9FB6994DFA
2 changed files with 37 additions and 5 deletions

View File

@ -111,7 +111,7 @@ export default function Events() {
const [recording, setRecording] = useOverlayState<RecordingStartingPoint>(
"recording",
undefined,
false,
true, // preserveSearch: keep URL params for deep linking
);
// Wrapper to update URL with review ID for deep linking when opening a recording.
@ -145,6 +145,12 @@ export default function Events() {
useState<TimelineType>("timeline");
useSearchEffect("tab", (tab: string) => {
// Don't process or strip tab param when viewing a recording or deep linking
// to one - the tab param is used for RecordingView's Timeline/Events/Detail tabs
if (recording || searchParams.has("id")) {
return false;
}
if (tab === "timeline" || tab === "events" || tab === "detail") {
setNotificationTab(tab as TimelineType);
}

View File

@ -101,11 +101,12 @@ export function RecordingView({
const [searchParams] = useSearchParams();
const contentRef = useRef<HTMLDivElement | null>(null);
// Navigate back while clearing the review id param to prevent
// Navigate back while clearing recording-specific params (id, tab) to prevent
// useSearchEffect from re-opening the recording
const handleBack = useCallback(() => {
const updated = new URLSearchParams(searchParams);
updated.delete("id");
updated.delete("tab");
const search = updated.toString();
navigate(
{
@ -163,9 +164,34 @@ export function RecordingView({
false,
);
const [timelineType, setTimelineType] = useOverlayState<TimelineType>(
"timelineType",
recording?.timelineType ?? "timeline",
// Timeline type from URL search params for deep linking
const timelineType = useMemo<TimelineType>(() => {
const tabParam = searchParams.get("tab");
if (tabParam === "events" || tabParam === "detail" || tabParam === "timeline") {
return tabParam;
}
return recording?.timelineType ?? "timeline";
}, [searchParams, recording?.timelineType]);
const setTimelineType = useCallback(
(type: TimelineType, replace: boolean = false) => {
const updated = new URLSearchParams(searchParams);
if (type === "timeline") {
updated.delete("tab"); // timeline is default, no need to include in URL
} else {
updated.set("tab", type);
}
const search = updated.toString();
navigate(
{
pathname: location.pathname,
search: search ? `?${search}` : "",
hash: location.hash,
},
{ replace, state: location.state },
);
},
[searchParams, navigate, location.pathname, location.hash, location.state],
);
const chunkedTimeRange = useMemo(