snort/src/Pages/MessagesPage.tsx

128 lines
4.2 KiB
TypeScript
Raw Normal View History

2023-01-12 09:48:39 +00:00
import { useMemo } from "react";
2023-01-18 22:04:52 +00:00
import { useDispatch, useSelector } from "react-redux"
2023-01-12 09:48:39 +00:00
2023-01-20 11:11:50 +00:00
import { HexKey, RawEvent } from "Nostr";
import UnreadCount from "Element/UnreadCount";
import ProfileImage from "Element/ProfileImage";
2023-01-12 09:48:39 +00:00
import { hexToBech32 } from "../Util";
2023-01-20 11:11:50 +00:00
import { incDmInteraction } from "State/Login";
import { RootState } from "State/Store";
import NoteToSelf from "Element/NoteToSelf";
2023-01-26 11:34:18 +00:00
import useModeration from "Hooks/useModeration";
2023-01-12 09:48:39 +00:00
2023-01-17 10:47:00 +00:00
type DmChat = {
pubkey: HexKey,
unreadMessages: number,
newestMessage: number
}
2023-01-12 09:48:39 +00:00
export default function MessagesPage() {
2023-01-18 22:04:52 +00:00
const dispatch = useDispatch();
const myPubKey = useSelector<RootState, HexKey | undefined>(s => s.login.publicKey);
const dms = useSelector<RootState, RawEvent[]>(s => s.login.dms);
const dmInteraction = useSelector<RootState, number>(s => s.login.dmInteraction);
const { isMuted } = useModeration();
2023-01-12 09:48:39 +00:00
2023-01-17 10:47:00 +00:00
const chats = useMemo(() => {
return extractChats(dms.filter(a => !isMuted(a.pubkey)), myPubKey!)
}, [dms, myPubKey, dmInteraction]);
2023-01-12 09:48:39 +00:00
function noteToSelf(chat: DmChat) {
return (
<div className="flex mb10" key={chat.pubkey}>
<NoteToSelf clickable={true} className="f-grow" link={`/messages/${hexToBech32("npub", chat.pubkey)}`} pubkey={chat.pubkey} />
</div>
)
}
2023-01-17 10:47:00 +00:00
function person(chat: DmChat) {
if(chat.pubkey === myPubKey) return noteToSelf(chat)
2023-01-12 09:48:39 +00:00
return (
2023-01-17 10:47:00 +00:00
<div className="flex mb10" key={chat.pubkey}>
<ProfileImage pubkey={chat.pubkey} className="f-grow" link={`/messages/${hexToBech32("npub", chat.pubkey)}`} />
2023-01-19 10:57:07 +00:00
<UnreadCount unread={chat.unreadMessages} />
2023-01-12 09:48:39 +00:00
</div>
)
}
2023-01-18 22:04:52 +00:00
function markAllRead() {
for (let c of chats) {
setLastReadDm(c.pubkey);
}
dispatch(incDmInteraction());
}
2023-01-12 09:48:39 +00:00
return (
2023-01-25 18:08:53 +00:00
<div className="main-content">
2023-01-18 22:04:52 +00:00
<div className="flex">
<h3 className="f-grow">Messages</h3>
2023-01-25 18:08:53 +00:00
<button type="button" onClick={() => markAllRead()}>Mark All Read</button>
2023-01-18 22:04:52 +00:00
</div>
{chats.sort((a, b) => {
return a.pubkey === myPubKey ? -1 :
b.pubkey === myPubKey ? 1 :
b.newestMessage - a.newestMessage
}).map(person)}
2023-01-25 18:08:53 +00:00
</div>
2023-01-12 09:48:39 +00:00
)
2023-01-17 10:47:00 +00:00
}
export function lastReadDm(pk: HexKey) {
let k = `dm:seen:${pk}`;
return parseInt(window.localStorage.getItem(k) ?? "0");
}
export function setLastReadDm(pk: HexKey) {
const now = Math.floor(new Date().getTime() / 1000);
let current = lastReadDm(pk);
if (current >= now) {
return;
}
let k = `dm:seen:${pk}`;
window.localStorage.setItem(k, now.toString());
}
2023-01-18 18:53:34 +00:00
export function dmTo(e: RawEvent) {
let firstP = e.tags.find(b => b[0] === "p");
return firstP ? firstP[1] : "";
}
2023-01-17 11:30:42 +00:00
export function isToSelf(e: RawEvent, pk: HexKey) {
2023-01-18 18:53:34 +00:00
return e.pubkey === pk && dmTo(e) === pk;
2023-01-17 11:30:42 +00:00
}
export function dmsInChat(dms: RawEvent[], pk: HexKey) {
return dms.filter(a => a.pubkey === pk || dmTo(a) === pk);
2023-01-17 11:30:42 +00:00
}
2023-01-17 10:47:00 +00:00
export function totalUnread(dms: RawEvent[], myPubKey: HexKey) {
return extractChats(dms, myPubKey).reduce((acc, v) => acc += v.unreadMessages, 0);
}
function unreadDms(dms: RawEvent[], myPubKey: HexKey, pk: HexKey) {
2023-01-17 11:30:42 +00:00
if (pk === myPubKey) return 0;
2023-01-17 10:47:00 +00:00
let lastRead = lastReadDm(pk);
2023-01-17 11:30:42 +00:00
return dmsInChat(dms, pk).filter(a => a.created_at >= lastRead && a.pubkey !== myPubKey).length;
2023-01-17 10:47:00 +00:00
}
function newestMessage(dms: RawEvent[], myPubKey: HexKey, pk: HexKey) {
2023-01-18 23:49:37 +00:00
if(pk === myPubKey) {
return dmsInChat(dms.filter(d => isToSelf(d, myPubKey)), pk).reduce((acc, v) => acc = v.created_at > acc ? v.created_at : acc, 0);
}
2023-01-17 11:30:42 +00:00
return dmsInChat(dms, pk).reduce((acc, v) => acc = v.created_at > acc ? v.created_at : acc, 0);
2023-01-17 10:47:00 +00:00
}
export function extractChats(dms: RawEvent[], myPubKey: HexKey) {
2023-01-18 18:53:34 +00:00
const keys = dms.map(a => [a.pubkey, dmTo(a)]).flat();
2023-01-17 10:47:00 +00:00
const filteredKeys = Array.from(new Set<string>(keys));
return filteredKeys.map(a => {
return {
pubkey: a,
unreadMessages: unreadDms(dms, myPubKey, a),
newestMessage: newestMessage(dms, myPubKey, a)
} as DmChat;
})
2023-01-25 18:08:53 +00:00
}