snort/src/element/Note.js

150 lines
5.1 KiB
JavaScript
Raw Normal View History

2022-12-18 14:51:47 +00:00
import "./Note.css";
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import moment from "moment";
2022-12-20 12:08:41 +00:00
import { Link, useNavigate } from "react-router-dom";
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";
2022-12-28 22:09:39 +00:00
import useEventPublisher from "../pages/feed/EventPublisher";
2022-12-20 12:08:41 +00:00
const UrlRegex = /((?:http|ftp|https):\/\/(?:[\w+?\.\w+])+(?:[a-zA-Z0-9\~\!\@\#\$\%\^\&\*\(\)_\-\=\+\\\/\?\.\:\;\'\,]*)?)/;
const FileExtensionRegex = /\.([\w]+)$/;
const MentionRegex = /(#\[\d+\])/g;
2022-12-18 14:51:47 +00:00
export default function Note(props) {
const navigate = useNavigate();
const data = props.data;
2022-12-28 22:09:39 +00:00
const dataEvent = props["data-ev"];
2022-12-20 23:14:13 +00:00
const reactions = props.reactions;
2022-12-28 22:09:39 +00:00
const publisher = useEventPublisher();
2022-12-18 14:51:47 +00:00
const [sig, setSig] = useState(false);
2022-12-20 12:08:41 +00:00
const users = useSelector(s => s.users?.users);
2022-12-28 22:09:39 +00:00
const ev = dataEvent ?? Event.FromObject(data);
2022-12-18 14:51:47 +00:00
useEffect(() => {
if (sig === false) {
verifyEvent();
}
}, []);
async function verifyEvent() {
let res = await ev.Verify();
setSig(res);
}
function goToEvent(e, id) {
2022-12-20 12:08:41 +00:00
if (!window.location.pathname.startsWith("/e/")) {
e.stopPropagation();
navigate(`/e/${id}`);
}
2022-12-18 14:51:47 +00:00
}
function replyTag() {
let thread = ev.GetThread();
if (thread === null) {
return null;
}
2022-12-18 22:23:52 +00:00
let replyId = thread?.ReplyTo?.Event;
2022-12-20 12:08:41 +00:00
let mentions = thread?.PubKeys?.map(a => [a, users[a]])?.map(a => a[1]?.name ?? a[0].substring(0, 8));
2022-12-18 14:51:47 +00:00
return (
<div className="reply" onClick={(e) => goToEvent(e, replyId)}>
2022-12-20 12:08:41 +00:00
{mentions?.join(", ") ?? replyId?.substring(0, 8)}
2022-12-18 14:51:47 +00:00
</div>
)
}
2022-12-20 12:08:41 +00:00
function transformBody() {
let body = ev.Content;
let urlBody = body.split(UrlRegex);
return urlBody.map(a => {
if (a.startsWith("http")) {
let url = new URL(a);
let ext = url.pathname.match(FileExtensionRegex);
if (ext) {
switch (ext[1]) {
case "gif":
case "jpg":
case "jpeg":
case "png":
case "bmp":
case "webp": {
2022-12-20 23:14:13 +00:00
return <img key={url} src={url} />;
2022-12-20 12:08:41 +00:00
}
case "mp4":
case "mkv":
case "avi":
case "m4v": {
2022-12-20 23:14:13 +00:00
return <video key={url} src={url} controls />
2022-12-20 12:08:41 +00:00
}
}
2022-12-28 17:05:20 +00:00
} else {
2022-12-28 17:07:52 +00:00
return <a href={url}>{url.toString()}</a>
2022-12-20 12:08:41 +00:00
}
} else {
let mentions = a.split(MentionRegex).map((match) => {
2022-12-28 20:27:25 +00:00
let matchTag = match.match(/#\[(\d+)\]/);
if (matchTag && matchTag.length === 2) {
let idx = parseInt(matchTag[1]);
let ref = ev.Tags.find(a => a.Index === idx);
if (ref) {
switch(ref.Key) {
case "p": {
let pUser = users[ref.PubKey]?.name ?? ref.PubKey.substring(0, 8);
return <Link key={ref.PubKey} to={`/p/${ref.PubKey}`}>@{pUser}</Link>;
}
case "e": {
let eText = ref.Event.substring(0, 8);
return <Link key={ref.Event} to={`/e/${ref.Event}`}>#{eText}</Link>;
}
}
}
return <b style={{color: "red"}}>{matchTag[0]}?</b>;
2022-12-20 12:08:41 +00:00
} else {
return match;
}
});
return mentions;
}
2022-12-20 23:14:13 +00:00
return a;
2022-12-20 12:08:41 +00:00
});
}
2022-12-28 22:09:39 +00:00
async function like() {
let evLike = await publisher.like(ev);
publisher.broadcast(evLike);
}
2022-12-18 22:23:52 +00:00
if (!ev.IsContent()) {
return (
<>
<pre>{ev.Id}</pre>
<pre>Kind: {ev.Kind}</pre>
<pre>Content: {ev.Content}</pre>
</>
);
2022-12-18 14:51:47 +00:00
}
return (
<div className="note">
<div className="header">
2022-12-27 23:46:13 +00:00
<ProfileImage pubKey={ev.PubKey} subHeader={replyTag()}/>
2022-12-18 14:51:47 +00:00
<div className="info">
{moment(ev.CreatedAt * 1000).fromNow()}
</div>
</div>
<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>
2022-12-20 23:14:13 +00:00
<div className="footer">
2022-12-28 22:09:39 +00:00
<span className="pill" onClick={() => like()}>
2022-12-20 23:14:13 +00:00
👍 {(reactions?.length ?? 0)}
</span>
2022-12-28 20:27:25 +00:00
<span className="pill" onClick={() => console.debug(ev)}>
<i>i</i>
</span>
2022-12-20 23:14:13 +00:00
</div>
2022-12-18 14:51:47 +00:00
</div>
)
}