snort/src/element/Note.js

90 lines
3.2 KiB
JavaScript
Raw Normal View History

2022-12-18 14:51:47 +00:00
import "./Note.css";
import { useCallback, useMemo } from "react";
2023-01-07 20:54:12 +00:00
import { useNavigate } from "react-router-dom";
2022-12-29 15:36:40 +00:00
2022-12-28 22:09:39 +00:00
import Event from "../nostr/Event";
2022-12-27 23:46:13 +00:00
import ProfileImage from "./ProfileImage";
2023-01-14 14:37:31 +00:00
import Text from "./Text";
2023-01-09 16:18:34 +00:00
import { eventLink, hexToBech32 } from "../Util";
2023-01-08 00:29:59 +00:00
import NoteFooter from "./NoteFooter";
2023-01-09 16:18:34 +00:00
import NoteTime from "./NoteTime";
2023-01-15 19:40:47 +00:00
import EventKind from "../nostr/EventKind";
import useProfile from "../feed/ProfileFeed";
2022-12-18 14:51:47 +00:00
export default function Note(props) {
const navigate = useNavigate();
const { data, isThread, reactions, deletion, hightlight, options: opt, ["data-ev"]: parsedEvent } = props
const ev = useMemo(() => parsedEvent ?? new Event(data), [data]);
const pubKeys = useMemo(() => ev.Thread?.PubKeys || [], [ev]);
2023-01-08 00:29:59 +00:00
const users = useProfile(pubKeys);
2022-12-18 14:51:47 +00:00
2023-01-02 11:15:13 +00:00
const options = {
showHeader: true,
showTime: true,
showFooter: true,
...opt
};
2023-01-02 13:40:42 +00:00
const transformBody = useCallback(() => {
let body = ev?.Content ?? "";
if (deletion?.length > 0) {
2023-01-12 09:48:39 +00:00
return (<b className="error">Deleted</b>);
}
return <Text content={body} tags={ev.Tags} users={users || []} />;
}, [props]);
2023-01-02 13:40:42 +00:00
2022-12-18 14:51:47 +00:00
function goToEvent(e, id) {
2022-12-20 12:08:41 +00:00
if (!window.location.pathname.startsWith("/e/")) {
e.stopPropagation();
2023-01-06 14:36:13 +00:00
navigate(eventLink(id));
2022-12-20 12:08:41 +00:00
}
2022-12-18 14:51:47 +00:00
}
function replyTag() {
2023-01-06 19:29:12 +00:00
if (ev.Thread === null) {
2022-12-18 14:51:47 +00:00
return null;
}
2023-01-09 16:18:34 +00:00
const maxMentions = 2;
2023-01-09 16:48:03 +00:00
let replyId = ev.Thread?.ReplyTo?.Event ?? ev.Thread?.Root?.Event;
let mentions = ev.Thread?.PubKeys?.map(a => [a, users ? users[a] : null])?.map(a => (a[1]?.name?.length ?? 0) > 0 ? a[1].name : hexToBech32("npub", a[0]).substring(0, 12))
2023-01-09 16:18:34 +00:00
.sort((a, b) => a.startsWith("npub") ? 1 : -1);
2023-01-15 23:45:23 +00:00
let othersLength = mentions.length - maxMentions
let pubMentions = mentions.length > maxMentions ? `${mentions?.slice(0, maxMentions).join(", ")} & ${othersLength} other${othersLength > 1 ? 's' : ''}` : mentions?.join(", ");
2022-12-18 14:51:47 +00:00
return (
2023-01-09 16:18:34 +00:00
<div className="reply">
2023-01-10 11:20:51 +00:00
{(pubMentions?.length ?? 0) > 0 ? pubMentions : hexToBech32("note", replyId)?.substring(0, 12)}
2022-12-18 14:51:47 +00:00
</div>
)
}
2023-01-15 19:40:47 +00:00
if (ev.Kind !== EventKind.TextNote) {
2022-12-18 22:23:52 +00:00
return (
<>
2023-01-08 18:35:36 +00:00
<h4>Unknown event kind: {ev.Kind}</h4>
<pre>
{JSON.stringify(ev.ToObject(), undefined, ' ')}
</pre>
2022-12-18 22:23:52 +00:00
</>
);
2022-12-18 14:51:47 +00:00
}
return (
<div className={`note ${hightlight ? "active" : ""} ${isThread ? "thread" : ""}`}>
2023-01-02 11:15:13 +00:00
{options.showHeader ?
<div className="header flex">
2023-01-08 00:29:59 +00:00
<ProfileImage pubkey={ev.RootPubKey} subHeader={replyTag()} />
2023-01-02 11:15:13 +00:00
{options.showTime ?
<div className="info">
2023-01-09 16:18:34 +00:00
<NoteTime from={ev.CreatedAt * 1000} />
2023-01-02 11:15:13 +00:00
</div> : null}
</div> : null}
2022-12-18 14:51:47 +00:00
<div className="body" onClick={(e) => goToEvent(e, ev.Id)}>
2022-12-20 12:08:41 +00:00
{transformBody()}
2022-12-18 14:51:47 +00:00
</div>
2023-01-08 00:29:59 +00:00
{options.showFooter ? <NoteFooter ev={ev} reactions={reactions} /> : null}
2022-12-18 14:51:47 +00:00
</div>
)
2023-01-14 01:39:20 +00:00
}