snort/src/Pages/ChatPage.tsx

101 lines
2.8 KiB
TypeScript
Raw Normal View History

2023-01-12 09:48:39 +00:00
import "./ChatPage.css";
2023-01-14 11:50:06 +00:00
import { KeyboardEvent, useEffect, useMemo, useRef, useState } from "react";
2023-01-12 09:48:39 +00:00
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import { useInView } from "react-intersection-observer";
2023-01-12 09:48:39 +00:00
2023-01-20 11:11:50 +00:00
import ProfileImage from "Element/ProfileImage";
import { bech32ToHex } from "Util";
import useEventPublisher from "Feed/EventPublisher";
2023-01-12 09:48:39 +00:00
2023-01-20 11:11:50 +00:00
import DM from "Element/DM";
2023-02-07 19:47:57 +00:00
import { RawEvent, TaggedRawEvent } from "Nostr";
2023-01-20 11:11:50 +00:00
import { dmsInChat, isToSelf } from "Pages/MessagesPage";
import NoteToSelf from "Element/NoteToSelf";
2023-01-12 09:48:39 +00:00
type RouterParams = {
id: string;
};
2023-01-12 09:48:39 +00:00
2023-02-07 19:47:57 +00:00
interface State {
login: {
dms: TaggedRawEvent[];
};
}
2023-01-12 09:48:39 +00:00
export default function ChatPage() {
const params = useParams<RouterParams>();
const publisher = useEventPublisher();
const id = bech32ToHex(params.id ?? "");
2023-02-07 19:47:57 +00:00
const pubKey = useSelector<{ login: { publicKey: string } }>(
(s) => s.login.publicKey
);
const dms = useSelector<State, RawEvent[]>((s) => filterDms(s.login.dms));
const [content, setContent] = useState<string>();
2023-02-07 19:47:57 +00:00
const { ref, inView } = useInView();
const dmListRef = useRef<HTMLDivElement>(null);
2023-01-12 09:48:39 +00:00
2023-02-07 19:47:57 +00:00
function filterDms(dms: TaggedRawEvent[]) {
return dmsInChat(
id === pubKey ? dms.filter((d) => isToSelf(d, pubKey)) : dms,
id
);
}
2023-01-12 09:48:39 +00:00
2023-02-07 19:47:57 +00:00
const sortedDms = useMemo<RawEvent[]>(() => {
return [...dms].sort((a, b) => a.created_at - b.created_at);
}, [dms]);
2023-01-12 09:48:39 +00:00
useEffect(() => {
if (inView && dmListRef.current) {
dmListRef.current.scroll(0, dmListRef.current.scrollHeight);
}
}, [inView, dmListRef, sortedDms]);
2023-01-14 11:50:06 +00:00
async function sendDm() {
if (content) {
2023-02-07 19:47:57 +00:00
const ev = await publisher.sendDm(content, id);
console.debug(ev);
publisher.broadcast(ev);
setContent("");
2023-01-14 11:50:06 +00:00
}
}
2023-01-14 11:50:06 +00:00
async function onEnter(e: KeyboardEvent) {
2023-02-07 19:47:57 +00:00
const isEnter = e.code === "Enter";
if (isEnter && !e.shiftKey) {
await sendDm();
2023-01-12 09:48:39 +00:00
}
}
2023-01-12 09:48:39 +00:00
return (
<>
{(id === pubKey && (
<NoteToSelf className="f-grow mb-10" pubkey={id} />
)) || <ProfileImage pubkey={id} className="f-grow mb10" />}
<div className="dm-list" ref={dmListRef}>
<div>
2023-02-07 19:47:57 +00:00
{/* TODO I need to look into this again, something's being bricked with the RawEvent and TaggedRawEvent */}
{sortedDms.map((a) => (
2023-02-07 19:47:57 +00:00
<DM data={a as TaggedRawEvent} key={a.id} />
))}
<div ref={ref} className="mb10"></div>
</div>
</div>
<div className="write-dm">
<div className="inner">
<textarea
className="f-grow mr10"
value={content}
onChange={(e) => setContent(e.target.value)}
onKeyDown={(e) => onEnter(e)}
></textarea>
<button type="button" onClick={() => sendDm()}>
Send
</button>
</div>
</div>
</>
);
2023-01-25 18:08:53 +00:00
}