diff --git a/src/feed/LoginFeed.js b/src/feed/LoginFeed.js index 0496730a..ee33b4d0 100644 --- a/src/feed/LoginFeed.js +++ b/src/feed/LoginFeed.js @@ -1,10 +1,9 @@ -import { useContext, useEffect } from "react"; +import { useEffect, useMemo } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { System } from ".."; -import Event from "../nostr/Event"; import EventKind from "../nostr/EventKind"; import { Subscriptions } from "../nostr/Subscriptions"; import { addNotifications, setFollows, setRelays } from "../state/Login"; +import useSubscription from "./Subscription"; /** * Managed loading data for the current logged in user @@ -13,41 +12,41 @@ export default function useLoginFeed() { const dispatch = useDispatch(); const pubKey = useSelector(s => s.login.publicKey); - useEffect(() => { - if (pubKey) { - let sub = new Subscriptions(); - sub.Id = "login"; - sub.Authors.add(pubKey); - sub.Kinds.add(EventKind.ContactList); - - let notifications = new Subscriptions(); - notifications.Kinds.add(EventKind.TextNote); - notifications.Kinds.add(EventKind.Reaction); - notifications.PTags.add(pubKey); - sub.AddSubscription(notifications); - - sub.OnEvent = (e) => { - let ev = Event.FromObject(e); - switch (ev.Kind) { - case EventKind.ContactList: { - if (ev.Content !== "") { - let relays = JSON.parse(ev.Content); - dispatch(setRelays(relays)); - } - let pTags = ev.Tags.filter(a => a.Key === "p").map(a => a.PubKey); - dispatch(setFollows(pTags)); - break; - } - default: { - dispatch(addNotifications(ev.ToObject())); - break; - } - } - } - System.AddSubscription(sub); - return () => System.RemoveSubscription(sub.Id); + const sub = useMemo(() => { + if(pubKey === null) { + return null; } + + let sub = new Subscriptions(); + sub.Id = `login:${sub.Id}`; + sub.Authors.add(pubKey); + sub.Kinds.add(EventKind.ContactList); + + let notifications = new Subscriptions(); + notifications.Kinds.add(EventKind.TextNote); + notifications.Kinds.add(EventKind.Reaction); + notifications.PTags.add(pubKey); + notifications.Limit = 100; + sub.AddSubscription(notifications); + + return sub; }, [pubKey]); - return {}; + const { notes } = useSubscription(sub, { leaveOpen: true }); + + useEffect(() => { + let metadatas = notes.filter(a => a.kind === EventKind.ContactList); + let others = notes.filter(a => a.kind !== EventKind.ContactList); + + for(let md of metadatas) { + if (md.content !== "") { + let relays = JSON.parse(md.content); + dispatch(setRelays(relays)); + } + let pTags = md.tags.filter(a => a[0] === "p").map(a => a[1]); + dispatch(setFollows(pTags)); + } + + dispatch(addNotifications(others)); + }, [notes]); } \ No newline at end of file diff --git a/src/feed/Subscription.js b/src/feed/Subscription.js index 3c11a400..df7baaea 100644 --- a/src/feed/Subscription.js +++ b/src/feed/Subscription.js @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useReducer, useState } from "react"; +import { useEffect, useReducer } from "react"; import { System } from ".."; import { Subscriptions } from "../nostr/Subscriptions"; @@ -45,8 +45,10 @@ export default function useSubscription(sub, opt) { }; } + console.debug("Adding sub: ", sub.ToObject()); System.AddSubscription(sub); return () => { + console.debug("Adding sub: ", sub.ToObject()); System.RemoveSubscription(sub.Id); }; } diff --git a/src/feed/ThreadFeed.js b/src/feed/ThreadFeed.js index 34cae040..8c1119b4 100644 --- a/src/feed/ThreadFeed.js +++ b/src/feed/ThreadFeed.js @@ -6,7 +6,7 @@ import useSubscription from "./Subscription"; export default function useThreadFeed(id) { const sub = useMemo(() => { const thisSub = new Subscriptions(); - thisSub.Id = "thread"; + thisSub.Id = `thread:${thisSub.Id}`; thisSub.Ids.add(id); // get replies to this event @@ -26,7 +26,7 @@ export default function useThreadFeed(id) { if (thisNote) { let otherSubs = new Subscriptions(); - otherSubs.Id = "thread-related"; + otherSubs.Id = `thread-related:${otherSubs.Id}`; for (let e of thisNote.tags.filter(a => a[0] === "e")) { otherSubs.Ids.add(e[1]); } diff --git a/src/feed/TimelineFeed.js b/src/feed/TimelineFeed.js index 0afb6727..82f1b9a7 100644 --- a/src/feed/TimelineFeed.js +++ b/src/feed/TimelineFeed.js @@ -1,19 +1,23 @@ -import { useCallback, useMemo } from "react"; +import { useMemo } from "react"; import EventKind from "../nostr/EventKind"; import { Subscriptions } from "../nostr/Subscriptions"; import useSubscription from "./Subscription"; export default function useTimelineFeed(pubKeys) { const sub = useMemo(() => { - if (pubKeys.length === 0) { + if (!Array.isArray(pubKeys)) { + pubKeys = [pubKeys]; + } + + if (!pubKeys || pubKeys.length === 0) { return null; } let sub = new Subscriptions(); - sub.Id = "timeline"; + sub.Id = `timeline:${sub.Id}`; sub.Authors = new Set(pubKeys); sub.Kinds.add(EventKind.TextNote); - sub.Limit = 10; + sub.Limit = 20; return sub; }, [pubKeys]); diff --git a/src/pages/Login.js b/src/pages/Login.js index 420730eb..861c3463 100644 --- a/src/pages/Login.js +++ b/src/pages/Login.js @@ -31,6 +31,11 @@ export default function LoginPage() { } } + async function makeRandomKey() { + let newKey = secp.utils.bytesToHex(secp.utils.randomPrivateKey()); + dispatch(setPrivateKey(newKey)) + } + async function doNip07Login() { let pubKey = await window.nostr.getPublicKey(); dispatch(setNip07PubKey(pubKey)); @@ -64,7 +69,10 @@ export default function LoginPage() {

Enter your private key:

setKey(e.target.value)} /> +
+
doLogin()}>Login
+
makeRandomKey()}>Generate Key
{altLogins()} diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js index 72efae2b..29d27d37 100644 --- a/src/pages/ProfilePage.js +++ b/src/pages/ProfilePage.js @@ -1,5 +1,5 @@ import "./ProfilePage.css"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { bech32 } from "bech32"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -21,7 +21,7 @@ export default function ProfilePage() { const id = params.id; const user = useProfile(id); const publisher = useEventPublisher(); - const { notes } = useTimelineFeed([id]); + const { notes } = useTimelineFeed(id); const loginPubKey = useSelector(s => s.login.publicKey); const isMe = loginPubKey === id; const qrRef = useRef(); @@ -34,7 +34,7 @@ export default function ProfilePage() { const [lud16, setLud16] = useState(""); const [showLnQr, setShowLnQr] = useState(false); - useEffect(() => { + useMemo(() => { if (user) { setName(user.name ?? ""); setPicture(user.picture ?? Nostrich); @@ -45,7 +45,7 @@ export default function ProfilePage() { } }, [user]); - useEffect(() => { + useMemo(() => { // some clients incorrectly set this to LNURL service, patch this if (lud16.toLowerCase().startsWith("lnurl")) { let decoded = bech32.decode(lud16, 1000); @@ -62,7 +62,7 @@ export default function ProfilePage() { } }, [lud16]); - useEffect(() => { + useMemo(() => { if (qrRef.current && showLnQr) { let qr = new QRCodeStyling({ data: {lud16}, diff --git a/src/state/Login.js b/src/state/Login.js index 7d902597..5a2c73dd 100644 --- a/src/state/Login.js +++ b/src/state/Login.js @@ -71,7 +71,11 @@ const LoginSlice = createSlice({ state.nip07 = true; }, setRelays: (state, action) => { - state.relays = action.payload; + // filter out non-websocket urls + let filtered = Object.entries(action.payload) + .filter(a => a[0].startsWith("ws://") || a[0].startsWith("wss://")); + + state.relays = Object.fromEntries(filtered); }, setFollows: (state, action) => { state.follows = action.payload;