From 621bb5f6eea26420f80a4793903b3f87bfa83ce3 Mon Sep 17 00:00:00 2001 From: Kieran Date: Wed, 18 Jan 2023 22:04:52 +0000 Subject: [PATCH] feat: mark all dms read --- src/element/DM.tsx | 21 +++++++++++------- src/pages/MessagesPage.tsx | 27 +++++++++++++++++------ src/state/Login.ts | 45 +++++++++++++++++++++++--------------- 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/element/DM.tsx b/src/element/DM.tsx index 96d45ee6..f80ea471 100644 --- a/src/element/DM.tsx +++ b/src/element/DM.tsx @@ -1,33 +1,38 @@ import "./DM.css"; import { useEffect, useState } from "react"; -import { useSelector } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { useInView } from 'react-intersection-observer'; import useEventPublisher from "../feed/EventPublisher"; import Event from "../nostr/Event"; import NoteTime from "./NoteTime"; import Text from "./Text"; -import { lastReadDm, setLastReadDm } from "../pages/MessagesPage"; +import { setLastReadDm } from "../pages/MessagesPage"; +import { RootState } from "../state/Store"; +import { HexKey, TaggedRawEvent } from "../nostr"; +import { incDmInteraction } from "../state/Login"; export type DMProps = { - data: any + data: TaggedRawEvent } export default function DM(props: DMProps) { - const pubKey = useSelector(s => s.login.publicKey); + const dispatch = useDispatch(); + const pubKey = useSelector(s => s.login.publicKey); const publisher = useEventPublisher(); const [content, setContent] = useState("Loading..."); const [decrypted, setDecrypted] = useState(false); - const { ref, inView, entry } = useInView(); + const { ref, inView } = useInView(); const isMe = props.data.pubkey === pubKey; async function decrypt() { let e = new Event(props.data); - if (!isMe) { - setLastReadDm(e.PubKey); - } let decrypted = await publisher.decryptDm(e); setContent(decrypted || ""); + if (!isMe) { + setLastReadDm(e.PubKey); + dispatch(incDmInteraction()); + } } useEffect(() => { diff --git a/src/pages/MessagesPage.tsx b/src/pages/MessagesPage.tsx index 39608e00..1be9daa0 100644 --- a/src/pages/MessagesPage.tsx +++ b/src/pages/MessagesPage.tsx @@ -1,9 +1,11 @@ import { useMemo } from "react"; -import { useSelector } from "react-redux" +import { useDispatch, useSelector } from "react-redux" import { HexKey, RawEvent } from "../nostr"; import ProfileImage from "../element/ProfileImage"; import { hexToBech32 } from "../Util"; +import { incDmInteraction } from "../state/Login"; +import { RootState } from "../state/Store"; type DmChat = { pubkey: HexKey, @@ -12,12 +14,14 @@ type DmChat = { } export default function MessagesPage() { - const myPubKey = useSelector(s => s.login.publicKey); - const dms = useSelector(s => s.login.dms); + const dispatch = useDispatch(); + const myPubKey = useSelector(s => s.login.publicKey); + const dms = useSelector(s => s.login.dms); + const dmInteraction = useSelector(s => s.login.dmInteraction); const chats = useMemo(() => { - return extractChats(dms, myPubKey); - }, [dms]); + return extractChats(dms, myPubKey!); + }, [dms, myPubKey, dmInteraction]); function person(chat: DmChat) { return ( @@ -30,9 +34,19 @@ export default function MessagesPage() { ) } + function markAllRead() { + for (let c of chats) { + setLastReadDm(c.pubkey); + } + dispatch(incDmInteraction()); + } + return ( <> -

Messages

+
+

Messages

+
markAllRead()}>Mark All Read
+
{chats.sort((a, b) => b.newestMessage - a.newestMessage).map(person)} ) @@ -81,7 +95,6 @@ function newestMessage(dms: RawEvent[], myPubKey: HexKey, pk: HexKey) { return dmsInChat(dms, pk).reduce((acc, v) => acc = v.created_at > acc ? v.created_at : acc, 0); } - export function extractChats(dms: RawEvent[], myPubKey: HexKey) { const keys = dms.map(a => [a.pubkey, dmTo(a)]).flat(); const filteredKeys = Array.from(new Set(keys)); diff --git a/src/state/Login.ts b/src/state/Login.ts index df88cc01..c06ad0b5 100644 --- a/src/state/Login.ts +++ b/src/state/Login.ts @@ -52,9 +52,27 @@ interface LoginStore { /** * Encrypted DM's */ - dms: TaggedRawEvent[] + dms: TaggedRawEvent[], + + /** + * Counter to trigger refresh of unread dms + */ + dmInteraction: 0 }; +const InitState = { + loggedOut: undefined, + publicKey: undefined, + privateKey: undefined, + relays: {}, + latestRelays: 0, + follows: [], + notifications: [], + readNotifications: 0, + dms: [], + dmInteraction: 0 +} as LoginStore; + export interface SetRelaysPayload { relays: Record, createdAt: number @@ -62,14 +80,7 @@ export interface SetRelaysPayload { const LoginSlice = createSlice({ name: "Login", - initialState: { - relays: {}, - latestRelays: 0, - follows: [], - notifications: [], - readNotifications: 0, - dms: [] - }, + initialState: InitState, reducers: { init: (state) => { state.privateKey = window.localStorage.getItem(PrivateKeyItem) ?? undefined; @@ -182,17 +193,14 @@ const LoginSlice = createSlice({ ]; } }, + incDmInteraction: (state) => { + state.dmInteraction += 1; + }, logout: (state) => { - window.localStorage.removeItem(PrivateKeyItem); - window.localStorage.removeItem(PublicKeyItem); - window.localStorage.removeItem(NotificationsReadItem); - state.privateKey = undefined; - state.publicKey = undefined; - state.follows = []; - state.notifications = []; + window.localStorage.clear(); + Object.assign(state, InitState); state.loggedOut = true; - state.readNotifications = 0; - state.dms = []; + state.relays = Object.fromEntries(DefaultRelays.entries()); }, markNotificationsRead: (state) => { state.readNotifications = new Date().getTime(); @@ -210,6 +218,7 @@ export const { setFollows, addNotifications, addDirectMessage, + incDmInteraction, logout, markNotificationsRead } = LoginSlice.actions;