146 lines
4.3 KiB
TypeScript
146 lines
4.3 KiB
TypeScript
import "./Thread.css";
|
|
|
|
import { EventExt, TaggedNostrEvent, u256 } from "@snort/system";
|
|
import { ReactNode, useCallback, useContext, useMemo } from "react";
|
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
import { useNavigate } from "react-router-dom";
|
|
|
|
import BackButton from "@/Components/Button/BackButton";
|
|
import Note from "@/Components/Event/EventComponent";
|
|
import NoteGhost from "@/Components/Event/Note/NoteGhost";
|
|
import { Subthread } from "@/Components/Event/Thread/Subthread";
|
|
import { chainKey } from "@/Utils/Thread/ChainKey";
|
|
import { ThreadContext } from "@/Utils/Thread/ThreadContext";
|
|
|
|
export function Thread(props: { onBack?: () => void; disableSpotlight?: boolean }) {
|
|
const thread = useContext(ThreadContext);
|
|
|
|
const navigate = useNavigate();
|
|
const isSingleNote = thread.chains?.size === 1 && [thread.chains.values].every(v => v.length === 0);
|
|
const { formatMessage } = useIntl();
|
|
|
|
const rootOptions = useMemo(
|
|
() => ({ showReactionsLink: true, showMediaSpotlight: !props.disableSpotlight, isRoot: true }),
|
|
[props.disableSpotlight],
|
|
);
|
|
|
|
const navigateThread = useCallback(
|
|
(e: TaggedNostrEvent) => {
|
|
thread.setCurrent(e.id);
|
|
// navigate(`/${NostrLink.fromEvent(e).encode()}`, { replace: true });
|
|
},
|
|
[thread],
|
|
);
|
|
|
|
const parent = useMemo(() => {
|
|
if (thread.root) {
|
|
const currentThread = EventExt.extractThread(thread.root);
|
|
return (
|
|
currentThread?.replyTo?.value ??
|
|
currentThread?.root?.value ??
|
|
(currentThread?.root?.key === "a" && currentThread.root?.value)
|
|
);
|
|
}
|
|
}, [thread.root]);
|
|
|
|
function renderRoot(note: TaggedNostrEvent) {
|
|
const className = `thread-root${isSingleNote ? " thread-root-single" : ""}`;
|
|
if (note) {
|
|
return (
|
|
<Note
|
|
className={className}
|
|
key={note.id}
|
|
data={note}
|
|
options={rootOptions}
|
|
onClick={navigateThread}
|
|
threadChains={thread.chains}
|
|
waitUntilInView={false}
|
|
/>
|
|
);
|
|
} else {
|
|
return <NoteGhost className={className}>Loading thread root.. ({thread.data?.length} notes loaded)</NoteGhost>;
|
|
}
|
|
}
|
|
|
|
function renderChain(from: u256): ReactNode {
|
|
if (!from || thread.chains.size === 0) {
|
|
return;
|
|
}
|
|
const replies = thread.chains.get(from);
|
|
if (replies && thread.current) {
|
|
return <Subthread active={thread.current} notes={replies} chains={thread.chains} onNavigate={navigateThread} />;
|
|
}
|
|
}
|
|
|
|
function renderCurrent() {
|
|
if (thread.current) {
|
|
const note = thread.data.find(n => n.id === thread.current);
|
|
return (
|
|
note && (
|
|
<Note
|
|
data={note}
|
|
options={{ showReactionsLink: true, showMediaSpotlight: true }}
|
|
threadChains={thread.chains}
|
|
onClick={navigateThread}
|
|
/>
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
function goBack() {
|
|
if (parent) {
|
|
thread.setCurrent(parent);
|
|
} else if (props.onBack) {
|
|
props.onBack();
|
|
} else {
|
|
navigate(-1);
|
|
}
|
|
}
|
|
|
|
const parentText = formatMessage({
|
|
defaultMessage: "Parent",
|
|
id: "ADmfQT",
|
|
description: "Link to parent note in thread",
|
|
});
|
|
|
|
const debug = window.location.search.includes("debug=true");
|
|
return (
|
|
<>
|
|
{debug && (
|
|
<div className="main-content p xs">
|
|
<h1>Chains</h1>
|
|
<pre>
|
|
{JSON.stringify(
|
|
Object.fromEntries([...thread.chains.entries()].map(([k, v]) => [k, v.map(c => c.id)])),
|
|
undefined,
|
|
" ",
|
|
)}
|
|
</pre>
|
|
<h1>Current</h1>
|
|
<pre>{JSON.stringify(thread.current)}</pre>
|
|
<h1>Root</h1>
|
|
<pre>{JSON.stringify(thread.root, undefined, " ")}</pre>
|
|
<h1>Data</h1>
|
|
<pre>{JSON.stringify(thread.data, undefined, " ")}</pre>
|
|
</div>
|
|
)}
|
|
{parent && (
|
|
<div className="main-content p">
|
|
<BackButton onClick={goBack} text={parentText} />
|
|
</div>
|
|
)}
|
|
<div className="main-content">
|
|
{thread.root && renderRoot(thread.root)}
|
|
{thread.root && renderChain(chainKey(thread.root))}
|
|
{!thread.root && renderCurrent()}
|
|
{!thread.root && !thread.current && (
|
|
<NoteGhost>
|
|
<FormattedMessage defaultMessage="Looking up thread..." id="JA+tz3" />
|
|
</NoteGhost>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|