From 0a5491eede148d9439831e0e11ec51d35400813c Mon Sep 17 00:00:00 2001 From: Sam Samskies Date: Sat, 4 Mar 2023 11:41:29 -1000 Subject: [PATCH] Fix broken note links (#380) * fix broken note links * remove unused prop * make comment easier to understand * handle case where root event ID is missing * add missing return * fix root finding logic * update comment --- packages/app/src/Element/Text.tsx | 9 ++++++-- packages/app/src/Element/Thread.tsx | 32 ++++++++++++++++++++++++---- packages/app/src/Pages/EventPage.tsx | 2 +- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/packages/app/src/Element/Text.tsx b/packages/app/src/Element/Text.tsx index eff969f5..05c99978 100644 --- a/packages/app/src/Element/Text.tsx +++ b/packages/app/src/Element/Text.tsx @@ -1,6 +1,6 @@ import "./Text.css"; import { useMemo, useCallback } from "react"; -import { Link } from "react-router-dom"; +import { Link, useLocation } from "react-router-dom"; import ReactMarkdown from "react-markdown"; import { visit, SKIP } from "unist-util-visit"; import * as unist from "unist"; @@ -28,6 +28,8 @@ export interface TextProps { } export default function Text({ content, tags, creator }: TextProps) { + const location = useLocation(); + function extractLinks(fragments: Fragment[]) { return fragments .map(f => { @@ -80,7 +82,10 @@ export default function Text({ content, tags, creator }: TextProps) { case "e": { const eText = hexToBech32("note", ref.Event).substring(0, 12); return ( - e.stopPropagation()}> + e.stopPropagation()} + state={{ from: location.pathname }}> #{eText} ); diff --git a/packages/app/src/Element/Thread.tsx b/packages/app/src/Element/Thread.tsx index 9a039d28..d1ba5895 100644 --- a/packages/app/src/Element/Thread.tsx +++ b/packages/app/src/Element/Thread.tsx @@ -254,15 +254,12 @@ const TierThree = ({ active, path, isLastSubthread, from, notes, related, chains }; export interface ThreadProps { - this?: u256; notes?: TaggedRawEvent[]; } export default function Thread(props: ThreadProps) { const notes = props.notes ?? []; const parsedNotes = notes.map(a => new NEvent(a)); - // root note has no thread info - const root = useMemo(() => parsedNotes.find(a => a.Thread === null), [notes]); const [path, setPath] = useState([]); const currentId = path.length > 0 && path[path.length - 1]; const currentRoot = useMemo(() => parsedNotes.find(a => a.Id === currentId), [notes, currentId]); @@ -295,6 +292,33 @@ export default function Thread(props: ThreadProps) { return chains; }, [notes]); + const root = useMemo(() => { + const isRoot = (ne?: NEvent) => ne?.Thread === null; + const currentNote = parsedNotes.find(ne => ne.Id === urlNoteHex); + + if (isRoot(currentNote)) { + return currentNote; + } + + const rootEventId = currentNote?.Thread?.Root?.Event; + + // sometimes the root event ID is missing, and we can only take the happy path if the root event ID exists + if (rootEventId) { + return parsedNotes.find(ne => ne.Id === rootEventId); + } + + const possibleRoots = parsedNotes.filter(isRoot); + + // worst case we need to check every possible root to see which one contains the current note as a child + for (const ne of possibleRoots) { + const children = chains.get(ne.Id) ?? []; + + if (children.find(ne => ne.Id === urlNoteHex)) { + return ne; + } + } + }, [notes, chains, urlNoteHex]); + useEffect(() => { if (!root) { return; @@ -370,7 +394,7 @@ export default function Thread(props: ThreadProps) { const newPath = path.slice(0, path.length - 1); setPath(newPath); } else { - navigate("/"); + navigate(location.state?.from ?? "/"); } } diff --git a/packages/app/src/Pages/EventPage.tsx b/packages/app/src/Pages/EventPage.tsx index f3f12181..753a41ee 100644 --- a/packages/app/src/Pages/EventPage.tsx +++ b/packages/app/src/Pages/EventPage.tsx @@ -8,5 +8,5 @@ export default function EventPage() { const id = parseId(params.id ?? ""); const thread = useThreadFeed(id); - return ; + return ; }