chore: random fixes
This commit is contained in:
parent
a67263e5e1
commit
2884a35b5c
@ -16,7 +16,7 @@ enum Provider {
|
||||
}
|
||||
|
||||
export default function SuggestedProfiles() {
|
||||
const login = useLogin();
|
||||
const login = useLogin(s => ({ publicKey: s.publicKey, follows: s.follows.item }));
|
||||
const [userList, setUserList] = useState<HexKey[]>();
|
||||
const [provider, setProvider] = useState(Provider.NostrBand);
|
||||
const [error, setError] = useState<Error>();
|
||||
@ -37,7 +37,7 @@ export default function SuggestedProfiles() {
|
||||
}
|
||||
case Provider.SemisolDev: {
|
||||
const api = new SemisolDevApi();
|
||||
const users = await api.sugguestedFollows(login.publicKey, login.follows.item);
|
||||
const users = await api.sugguestedFollows(login.publicKey, login.follows);
|
||||
const keys = users.recommendations.sort(a => a[1]).map(a => a[0]);
|
||||
setUserList(keys);
|
||||
break;
|
||||
@ -52,7 +52,7 @@ export default function SuggestedProfiles() {
|
||||
|
||||
useEffect(() => {
|
||||
loadSuggestedProfiles();
|
||||
}, [login, provider]);
|
||||
}, [login.publicKey, login.follows, provider]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { TaggedNostrEvent, EventKind, RequestBuilder, NoteCollection, NostrLink } from "@snort/system";
|
||||
import { TaggedNostrEvent, EventKind, RequestBuilder, NoteCollection, NostrLink, parseRelayTags } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
|
||||
import { bech32ToHex, debounce, findTag, getNewest, getNewestEventTagsByKey, unwrap } from "@/SnortUtils";
|
||||
import { makeNotification, sendNotification } from "@/Notifications";
|
||||
import { bech32ToHex, debounce, getNewest, getNewestEventTagsByKey, unwrap } from "@/SnortUtils";
|
||||
import useEventPublisher from "@/Hooks/useEventPublisher";
|
||||
import useModeration from "@/Hooks/useModeration";
|
||||
import useLogin from "@/Hooks/useLogin";
|
||||
import {
|
||||
SnortAppData,
|
||||
@ -24,14 +22,14 @@ import { SubscriptionEvent } from "@/Subscription";
|
||||
import { FollowLists, FollowsFeed, GiftsCache, Notifications, UserRelays } from "@/Cache";
|
||||
import { Nip28Chats, Nip4Chats } from "@/chat";
|
||||
import { useRefreshFeedCache } from "@/Hooks/useRefreshFeedcache";
|
||||
import { usePrevious } from "@uidotdev/usehooks";
|
||||
|
||||
/**
|
||||
* Managed loading data for the current logged in user
|
||||
*/
|
||||
export default function useLoginFeed() {
|
||||
const login = useLogin();
|
||||
const { publicKey: pubKey, readNotifications, follows } = login;
|
||||
const { isMuted } = useModeration();
|
||||
const { publicKey: pubKey, follows } = login;
|
||||
const { publisher, system } = useEventPublisher();
|
||||
|
||||
useRefreshFeedCache(Notifications, true);
|
||||
@ -43,15 +41,19 @@ export default function useLoginFeed() {
|
||||
system.checkSigs = login.appData.item.preferences.checkSigs;
|
||||
}, [login]);
|
||||
|
||||
const previous = usePrevious(login.appData.item);
|
||||
// write appdata after 10s of no changes
|
||||
useEffect(() => {
|
||||
if (!previous || JSON.stringify(previous) === JSON.stringify(login.appData.item)) {
|
||||
return;
|
||||
}
|
||||
return debounce(10_000, async () => {
|
||||
if (publisher && login.appData.item) {
|
||||
const ev = await publisher.appData(login.appData.item, "snort");
|
||||
await system.BroadcastEvent(ev);
|
||||
}
|
||||
});
|
||||
}, [login.appData.timestamp]);
|
||||
}, [previous]);
|
||||
|
||||
const subLogin = useMemo(() => {
|
||||
if (!login || !pubKey) return null;
|
||||
@ -62,8 +64,16 @@ export default function useLoginFeed() {
|
||||
});
|
||||
b.withFilter()
|
||||
.authors([pubKey])
|
||||
.kinds([EventKind.ContactList, EventKind.Relays, EventKind.MuteList, EventKind.PinList]);
|
||||
b.withFilter().authors([pubKey]).kinds([EventKind.CategorizedBookmarks]).tag("d", ["follow", "bookmark"]);
|
||||
.kinds([
|
||||
EventKind.ContactList,
|
||||
EventKind.Relays,
|
||||
EventKind.MuteList,
|
||||
EventKind.PinList,
|
||||
EventKind.BookmarksList,
|
||||
EventKind.InterestsList,
|
||||
EventKind.PublicChatsList,
|
||||
]);
|
||||
b.withFilter().authors([pubKey]).kinds([]);
|
||||
if (CONFIG.features.subscriptions && !login.readonly) {
|
||||
b.withFilter().authors([pubKey]).kinds([EventKind.AppData]).tag("d", ["snort"]);
|
||||
b.withFilter()
|
||||
@ -100,17 +110,7 @@ export default function useLoginFeed() {
|
||||
|
||||
const relays = getNewest(loginFeed.data.filter(a => a.kind === EventKind.Relays));
|
||||
if (relays) {
|
||||
const parsedRelays = relays.tags
|
||||
.filter(a => a[0] === "r")
|
||||
.map(a => {
|
||||
return [
|
||||
a[1],
|
||||
{
|
||||
read: a[2] === "read" || a[2] === undefined,
|
||||
write: a[2] === "write" || a[2] === undefined,
|
||||
},
|
||||
];
|
||||
});
|
||||
const parsedRelays = parseRelayTags(relays.tags.filter(a => a[0] === "r")).map(a => [a.url, a.settings]);
|
||||
setRelays(login, Object.fromEntries(parsedRelays), relays.created_at * 1000);
|
||||
}
|
||||
|
||||
@ -144,21 +144,6 @@ export default function useLoginFeed() {
|
||||
}
|
||||
}, [loginFeed, publisher]);
|
||||
|
||||
// send out notifications
|
||||
useEffect(() => {
|
||||
if (loginFeed.data) {
|
||||
const replies = loginFeed.data.filter(
|
||||
a => a.kind === EventKind.TextNote && !isMuted(a.pubkey) && a.created_at > readNotifications,
|
||||
);
|
||||
replies.forEach(async nx => {
|
||||
const n = await makeNotification(nx);
|
||||
if (n) {
|
||||
sendNotification(login, n);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [loginFeed, readNotifications]);
|
||||
|
||||
async function handleMutedFeed(mutedFeed: TaggedNostrEvent[]) {
|
||||
const latest = getNewest(mutedFeed);
|
||||
if (!latest) return;
|
||||
@ -211,14 +196,10 @@ export default function useLoginFeed() {
|
||||
const pinnedFeed = loginFeed.data.filter(a => a.kind === EventKind.PinList);
|
||||
handlePinnedFeed(pinnedFeed);
|
||||
|
||||
const tagsFeed = loginFeed.data.filter(
|
||||
a => a.kind === EventKind.CategorizedBookmarks && findTag(a, "d") === "follow",
|
||||
);
|
||||
const tagsFeed = loginFeed.data.filter(a => a.kind === EventKind.InterestsList);
|
||||
handleTagFeed(tagsFeed);
|
||||
|
||||
const bookmarkFeed = loginFeed.data.filter(
|
||||
a => a.kind === EventKind.CategorizedBookmarks && findTag(a, "d") === "bookmark",
|
||||
);
|
||||
const bookmarkFeed = loginFeed.data.filter(a => a.kind === EventKind.BookmarksList);
|
||||
handleBookmarkFeed(bookmarkFeed);
|
||||
}
|
||||
}, [loginFeed]);
|
||||
|
@ -27,7 +27,7 @@ export function useLinkListEvents(id: string, fn: (rb: RequestBuilder) => void)
|
||||
}
|
||||
|
||||
export function usePinList(pubkey: string | undefined) {
|
||||
return useLinkListEvents(`pins:${pubkey?.slice(0, 12)}`, rb => {
|
||||
return useLinkListEvents(`list:pins:${pubkey?.slice(0, 12)}`, rb => {
|
||||
if (pubkey) {
|
||||
rb.withFilter().kinds([EventKind.PinList]).authors([pubkey]);
|
||||
}
|
||||
@ -35,17 +35,25 @@ export function usePinList(pubkey: string | undefined) {
|
||||
}
|
||||
|
||||
export function useMuteList(pubkey: string | undefined) {
|
||||
return useLinkList(`pins:${pubkey?.slice(0, 12)}`, rb => {
|
||||
return useLinkList(`list:mute:${pubkey?.slice(0, 12)}`, rb => {
|
||||
if (pubkey) {
|
||||
rb.withFilter().kinds([EventKind.MuteList]).authors([pubkey]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default function useCategorizedBookmarks(pubkey: string | undefined, list: string) {
|
||||
return useLinkListEvents(`categorized-bookmarks:${list}:${pubkey?.slice(0, 12)}`, rb => {
|
||||
export function useBookmarkList(pubkey: string | undefined) {
|
||||
return useLinkListEvents(`list:bookmark:${pubkey?.slice(0, 12)}`, rb => {
|
||||
if (pubkey) {
|
||||
rb.withFilter().kinds([EventKind.CategorizedBookmarks]).authors([pubkey]).tag("d", [list]);
|
||||
rb.withFilter().kinds([EventKind.BookmarksList]).authors([pubkey]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function useInterestsList(pubkey: string | undefined) {
|
||||
return useLinkList(`list:interest:${pubkey?.slice(0, 12)}`, rb => {
|
||||
if (pubkey) {
|
||||
rb.withFilter().kinds([EventKind.InterestsList]).authors([pubkey]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useMemo } from "react";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { FormattedMessage, FormattedNumber } from "react-intl";
|
||||
import { EventKind, NostrHashtagLink, NoteCollection, RequestBuilder } from "@snort/system";
|
||||
import { EventKind, NoteCollection, RequestBuilder } from "@snort/system";
|
||||
import { dedupe } from "@snort/shared";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
|
||||
@ -44,10 +44,11 @@ export function HashTagHeader({ tag, events, className }: { tag: string; events?
|
||||
|
||||
async function followTags(ts: string[]) {
|
||||
if (publisher) {
|
||||
const ev = await publisher.bookmarks(
|
||||
ts.map(a => new NostrHashtagLink(a)),
|
||||
"follow",
|
||||
);
|
||||
const ev = await publisher.generic(eb => {
|
||||
eb.kind(EventKind.InterestsList);
|
||||
ts.forEach(a => eb.tag(["t", a]));
|
||||
return eb;
|
||||
});
|
||||
setTags(login, ts, ev.created_at * 1000);
|
||||
await system.BroadcastEvent(ev);
|
||||
}
|
||||
@ -55,7 +56,7 @@ export function HashTagHeader({ tag, events, className }: { tag: string; events?
|
||||
|
||||
const sub = useMemo(() => {
|
||||
const rb = new RequestBuilder(`hashtag-counts:${tag}`);
|
||||
rb.withFilter().kinds([EventKind.CategorizedBookmarks]).tag("d", ["follow"]).tag("t", [tag.toLowerCase()]);
|
||||
rb.withFilter().kinds([EventKind.InterestsList]).tag("t", [tag.toLowerCase()]);
|
||||
return rb;
|
||||
}, [tag]);
|
||||
const followsTag = useRequestBuilder(NoteCollection, sub);
|
||||
|
@ -13,7 +13,7 @@ import Bookmarks from "@/Element/User/Bookmarks";
|
||||
import Icon from "@/Icons/Icon";
|
||||
import { Tab } from "@/Element/Tabs";
|
||||
import { default as ZapElement } from "@/Element/Event/Zap";
|
||||
import useCategorizedBookmarks from "@/Hooks/useLists";
|
||||
import { useBookmarkList } from "@/Hooks/useLists";
|
||||
|
||||
import messages from "../messages";
|
||||
|
||||
@ -60,7 +60,7 @@ export function RelaysTab({ id }: { id: HexKey }) {
|
||||
}
|
||||
|
||||
export function BookMarksTab({ id }: { id: HexKey }) {
|
||||
const bookmarks = useCategorizedBookmarks(id, "bookmark");
|
||||
const bookmarks = useBookmarkList(id);
|
||||
const reactions = useReactions(`bookmark:reactions:{id}`, bookmarks.map(NostrLink.fromEvent));
|
||||
return <Bookmarks pubkey={id} bookmarks={bookmarks} related={reactions.data ?? []} />;
|
||||
}
|
||||
|
@ -27,9 +27,20 @@ enum EventKind {
|
||||
|
||||
MuteList = 10_000, // NIP-51
|
||||
PinList = 10_001, // NIP-51
|
||||
BookmarksList = 10_003, // NIP-51
|
||||
CommunitiesList = 10_004, // NIP-51
|
||||
PublicChatsList = 10_005, // NIP-51
|
||||
BlockedRelaysList = 10_006, // NIP-51
|
||||
SearchRelaysList = 10_007, // NIP-51
|
||||
InterestsList = 10_015, // NIP-51
|
||||
EmojisList = 10_030, // NIP-51
|
||||
|
||||
CategorizedPeople = 30000, // NIP-51a
|
||||
CategorizedBookmarks = 30001, // NIP-51b
|
||||
FollowSet = 30_000, // NIP-51
|
||||
RelaySet = 30_002, // NIP-51
|
||||
BookmarkSet = 30_003, // NIP-51
|
||||
CurationSet = 30_004, // NIP-51
|
||||
InterestSet = 30_015, // NIP-15
|
||||
EmojiSet = 30_030, // NIP-51
|
||||
|
||||
Badge = 30009, // NIP-58
|
||||
ProfileBadges = 30008, // NIP-58
|
||||
|
@ -137,9 +137,8 @@ export class EventPublisher {
|
||||
* Build a categorized bookmarks event with a given label
|
||||
* @param notes List of bookmarked links
|
||||
*/
|
||||
async bookmarks(notes: Array<ToNostrEventTag>, list: "bookmark" | "follow") {
|
||||
const eb = this.#eb(EventKind.CategorizedBookmarks);
|
||||
eb.tag(["d", list]);
|
||||
async bookmarks(notes: Array<ToNostrEventTag>) {
|
||||
const eb = this.#eb(EventKind.BookmarksList);
|
||||
notes.forEach(n => {
|
||||
eb.tag(unwrap(n.toEventTag()));
|
||||
});
|
||||
|
@ -400,7 +400,7 @@ export class NostrSystem extends EventEmitter<NostrSystemEvents> implements Syst
|
||||
}
|
||||
return;
|
||||
}),
|
||||
...replyRelays.filter(a => !socks.some(b => b.Address === a)).map(a => this.WriteOnceToRelay(a, ev)),
|
||||
...replyRelays.filter(a => !this.#sockets.has(a)).map(a => this.WriteOnceToRelay(a, ev)),
|
||||
]);
|
||||
return removeUndefined(oks);
|
||||
}
|
||||
|
@ -1,5 +1,14 @@
|
||||
import { EventKind, FullRelaySettings, NostrEvent, ReqFilter, RequestBuilder, SystemInterface, UsersRelays } from ".";
|
||||
import { dedupe, sanitizeRelayUrl, unixNowMs, unwrap } from "@snort/shared";
|
||||
import {
|
||||
EventKind,
|
||||
FullRelaySettings,
|
||||
NostrEvent,
|
||||
ReqFilter,
|
||||
RequestBuilder,
|
||||
SystemInterface,
|
||||
TaggedNostrEvent,
|
||||
UsersRelays,
|
||||
} from ".";
|
||||
import { dedupe, removeUndefined, sanitizeRelayUrl, unixNowMs, unwrap } from "@snort/shared";
|
||||
import debug from "debug";
|
||||
import { FlatReqFilter } from "./query-optimizer";
|
||||
import { RelayListCacheExpire } from "./const";
|
||||
@ -193,7 +202,7 @@ export async function pickRelaysForReply(ev: NostrEvent, system: SystemInterface
|
||||
const recipients = dedupe(ev.tags.filter(a => a[0] === "p").map(a => a[1]));
|
||||
await updateRelayLists(recipients, system);
|
||||
const relays = pickTopRelays(system.RelayCache, recipients, 2, "read");
|
||||
const ret = dedupe(relays.map(a => a.relays).flat());
|
||||
const ret = removeUndefined(dedupe(relays.map(a => a.relays).flat()));
|
||||
logger("Picked %O from authors %O", ret, recipients);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user