- {status === "loading" || isFetching ? (
+ {status === "loading" ? (
@@ -46,13 +46,16 @@ export function ThreadBlock({ params }: { params: any }) {
- {data.kind === 1 && }
+ {data.kind === 1 && }
{data.kind === 1063 && }
-
+
-
+
)}
diff --git a/src/app/space/hooks/useLiveThread.tsx b/src/app/space/hooks/useLiveThread.tsx
new file mode 100644
index 00000000..9374cf1e
--- /dev/null
+++ b/src/app/space/hooks/useLiveThread.tsx
@@ -0,0 +1,46 @@
+import { createReplyNote } from "@libs/storage";
+import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
+import { RelayContext } from "@shared/relayProvider";
+import { useMutation, useQueryClient } from "@tanstack/react-query";
+import { useContext, useEffect, useRef } from "react";
+
+export function useLiveThread(id: string) {
+ const ndk = useContext(RelayContext);
+ const queryClient = useQueryClient();
+ const now = useRef(Math.floor(Date.now() / 1000));
+
+ const thread = useMutation({
+ mutationFn: (data: NDKEvent) => {
+ return createReplyNote(
+ id,
+ data.id,
+ data.pubkey,
+ data.kind,
+ data.tags,
+ data.content,
+ data.created_at,
+ );
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ["replies", id] });
+ },
+ });
+
+ useEffect(() => {
+ const filter: NDKFilter = {
+ kinds: [1],
+ "#e": [id],
+ since: now.current,
+ };
+
+ const sub = ndk.subscribe(filter, { closeOnEose: false });
+
+ sub.addListener("event", (event: NDKEvent) => {
+ thread.mutate(event);
+ });
+
+ return () => {
+ sub.stop();
+ };
+ }, []);
+}
diff --git a/src/app/space/hooks/useNewsfeed.tsx b/src/app/space/hooks/useNewsfeed.tsx
new file mode 100644
index 00000000..2aa97bc6
--- /dev/null
+++ b/src/app/space/hooks/useNewsfeed.tsx
@@ -0,0 +1,48 @@
+import { createNote } from "@libs/storage";
+import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
+import { RelayContext } from "@shared/relayProvider";
+import { useNote } from "@stores/note";
+import { useAccount } from "@utils/hooks/useAccount";
+import { useContext, useEffect, useRef } from "react";
+
+export function useNewsfeed() {
+ const ndk = useContext(RelayContext);
+ const sub = useRef(null);
+ const now = useRef(Math.floor(Date.now() / 1000));
+ const toggleHasNewNote = useNote((state) => state.toggleHasNewNote);
+
+ const { status, account } = useAccount();
+
+ useEffect(() => {
+ if (status === "success" && account) {
+ const follows = account ? JSON.parse(account.follows) : [];
+
+ const filter: NDKFilter = {
+ kinds: [1, 6],
+ authors: follows,
+ since: now.current,
+ };
+
+ sub.current = ndk.subscribe(filter, { closeOnEose: false });
+
+ sub.current.addListener("event", (event: NDKEvent) => {
+ console.log("new note: ", event);
+ // add to db
+ createNote(
+ event.id,
+ event.pubkey,
+ event.kind,
+ event.tags,
+ event.content,
+ event.created_at,
+ );
+ // notify user about created note
+ toggleHasNewNote(true);
+ });
+ }
+
+ return () => {
+ sub.current.stop();
+ };
+ }, [status]);
+}
diff --git a/src/app/trending/components/profile.tsx b/src/app/trending/components/profile.tsx
index ff10e608..ab79a429 100644
--- a/src/app/trending/components/profile.tsx
+++ b/src/app/trending/components/profile.tsx
@@ -5,16 +5,15 @@ import { compactNumber } from "@utils/number";
import { shortenKey } from "@utils/shortenKey";
export function Profile({ data }: { data: any }) {
- const {
- status,
- data: userStats,
- isFetching,
- } = useQuery(["user-stats", data.pubkey], async () => {
- const res = await fetch(
- `https://api.nostr.band/v0/stats/profile/${data.pubkey}`,
- );
- return res.json();
- });
+ const { status, data: userStats } = useQuery(
+ ["user-stats", data.pubkey],
+ async () => {
+ const res = await fetch(
+ `https://api.nostr.band/v0/stats/profile/${data.pubkey}`,
+ );
+ return res.json();
+ },
+ );
const embedProfile = data.profile ? JSON.parse(data.profile.content) : null;
const profile = embedProfile;
@@ -51,7 +50,7 @@ export function Profile({ data }: { data: any }) {
- {status === "loading" || isFetching ? (
+ {status === "loading" ? (
Loading...
) : (
diff --git a/src/app/trending/components/trendingNotes.tsx b/src/app/trending/components/trendingNotes.tsx
index af38479d..6613142a 100644
--- a/src/app/trending/components/trendingNotes.tsx
+++ b/src/app/trending/components/trendingNotes.tsx
@@ -4,19 +4,16 @@ import { TitleBar } from "@shared/titleBar";
import { useQuery } from "@tanstack/react-query";
export function TrendingNotes() {
- const { status, data, isFetching } = useQuery(
- ["trending-notes"],
- async () => {
- const res = await fetch("https://api.nostr.band/v0/trending/notes");
- return res.json();
- },
- );
+ const { status, data } = useQuery(["trending-notes"], async () => {
+ const res = await fetch("https://api.nostr.band/v0/trending/notes");
+ return res.json();
+ });
return (
- {status === "loading" || isFetching ? (
+ {status === "loading" ? (
diff --git a/src/app/trending/components/trendingProfiles.tsx b/src/app/trending/components/trendingProfiles.tsx
index f7f12a4a..e6c23092 100644
--- a/src/app/trending/components/trendingProfiles.tsx
+++ b/src/app/trending/components/trendingProfiles.tsx
@@ -4,19 +4,16 @@ import { TitleBar } from "@shared/titleBar";
import { useQuery } from "@tanstack/react-query";
export function TrendingProfiles() {
- const { status, data, isFetching } = useQuery(
- ["trending-profiles"],
- async () => {
- const res = await fetch("https://api.nostr.band/v0/trending/profiles");
- return res.json();
- },
- );
+ const { status, data } = useQuery(["trending-profiles"], async () => {
+ const res = await fetch("https://api.nostr.band/v0/trending/profiles");
+ return res.json();
+ });
return (
- {status === "loading" || isFetching ? (
+ {status === "loading" ? (
diff --git a/src/libs/ndk.tsx b/src/libs/ndk.tsx
index eca863f2..a18c40ab 100644
--- a/src/libs/ndk.tsx
+++ b/src/libs/ndk.tsx
@@ -1,3 +1,4 @@
+import { createReplyNote } from "./storage";
import NDK, {
NDKConstructorParams,
NDKEvent,
@@ -10,12 +11,22 @@ import { FULL_RELAYS } from "@stores/constants";
import { useAccount } from "@utils/hooks/useAccount";
import { useContext } from "react";
-export async function initNDK(
- relays?: string[],
- cache?: boolean,
-): Promise
{
+export async function initNDK(relays?: string[]): Promise {
const opts: NDKConstructorParams = {};
- opts.explicitRelayUrls = relays || FULL_RELAYS;
+ const defaultRelays = new Set(relays || FULL_RELAYS);
+
+ /*
+ for (const relay of defaultRelays) {
+ const url = new URL(relay);
+ url.protocol = url.protocol = url.protocol.replace("wss", "https");
+ const res = await fetch(url.href, { method: "HEAD", timeout: 5 });
+ if (!res.ok) {
+ defaultRelays.delete(relay);
+ }
+ }
+ */
+
+ opts.explicitRelayUrls = [...defaultRelays];
const ndk = new NDK(opts);
await ndk.connect();
@@ -40,7 +51,7 @@ export async function prefetchEvents(
});
relaySetSubscription.on("eose", () => {
- setTimeout(() => resolve(new Set(events.values())), 5000);
+ setTimeout(() => resolve(new Set(events.values())), 3000);
});
});
}
@@ -54,11 +65,15 @@ export function usePublish() {
ndk.signer = signer;
}
- function publish({
+ const publish = ({
content,
kind,
tags,
- }: { content: string; kind: NDKKind; tags: string[][] }) {
+ }: {
+ content: string;
+ kind: NDKKind;
+ tags: string[][];
+ }): NDKEvent => {
const event = new NDKEvent(ndk);
event.content = content;
@@ -68,7 +83,9 @@ export function usePublish() {
event.tags = tags;
event.publish();
- }
+
+ return event;
+ };
return publish;
}
diff --git a/src/main.tsx b/src/main.tsx
index 3cea0f18..c4849826 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -20,6 +20,6 @@ root.render(
-
+
,
);
diff --git a/src/shared/accounts/active.tsx b/src/shared/accounts/active.tsx
index 71945b40..366caa3c 100644
--- a/src/shared/accounts/active.tsx
+++ b/src/shared/accounts/active.tsx
@@ -87,19 +87,21 @@ export function ActiveAccount({ data }: { data: any }) {
};
}, []);
+ if (status === "loading") {
+ return ;
+ }
+
return (
-