-
-
-
-
-
-
-
-
+ ) : (
+ <>
+
+
+
+
+
+ {contentParser(data.content, data.tags)}
+
+
+
e.stopPropagation()} className="mt-5 pl-[52px]">
+
-
-
- );
- }
+ >
+ )}
+
+ );
});
diff --git a/src/components/note/quote.tsx b/src/components/note/quote.tsx
index ccf080bb..9e73a54f 100644
--- a/src/components/note/quote.tsx
+++ b/src/components/note/quote.tsx
@@ -1,95 +1,60 @@
-import { AccountContext } from '@components/accountProvider';
import { RelayContext } from '@components/relaysProvider';
import { UserExtend } from '@components/user/extend';
import { READONLY_RELAYS } from '@stores/constants';
import { contentParser } from '@utils/parser';
-import { createNote, getNoteByID } from '@utils/storage';
-import { getParentID } from '@utils/transform';
-import { memo, useCallback, useContext, useEffect, useState } from 'react';
+import { memo, useContext } from 'react';
+import useSWRSubscription from 'swr/subscription';
export const NoteQuote = memo(function NoteQuote({ id }: { id: string }) {
const pool: any = useContext(RelayContext);
- const activeAccount: any = useContext(AccountContext);
- const [event, setEvent] = useState(null);
- const content = event ? contentParser(event.content, event.tags) : '';
-
- const fetchEvent = useCallback(async () => {
- const unsubscribe = pool.subscribe(
- [
- {
- ids: [id],
- kinds: [1],
+ const { data, error } = useSWRSubscription(
+ id
+ ? [
+ {
+ ids: [id],
+ kinds: [1],
+ },
+ ]
+ : null,
+ (key, { next }) => {
+ const unsubscribe = pool.subscribe(
+ key,
+ READONLY_RELAYS,
+ (event: any) => {
+ next(null, event);
},
- ],
- READONLY_RELAYS,
- (event: any) => {
- // update state
- setEvent(event);
- // insert to database
- const parentID = getParentID(event.tags, event.id);
- createNote(
- event.id,
- activeAccount.id,
- event.pubkey,
- event.kind,
- event.tags,
- event.content,
- event.created_at,
- parentID
- );
- },
- undefined,
- undefined,
- {
- unsubscribeOnEose: true,
- }
- );
-
- return () => {
- unsubscribe();
- };
- }, [activeAccount.id, id, pool]);
-
- const checkNoteIsSaved = useCallback(async () => {
- getNoteByID(id)
- .then((res) => {
- if (res) {
- setEvent(res);
- } else {
- fetchEvent();
+ undefined,
+ undefined,
+ {
+ unsubscribeOnEose: true,
}
- })
- .catch(console.error);
- }, [fetchEvent, id]);
+ );
- useEffect(() => {
- let ignore = false;
-
- if (!ignore) {
- checkNoteIsSaved();
+ return () => {
+ unsubscribe();
+ };
}
+ );
- return () => {
- ignore = true;
- };
- }, [checkNoteIsSaved]);
-
- if (event) {
- return (
-
+ return (
+
+ {error &&
failed to load
}
+ {!data ? (
+
+ ) : (
-
+
-
{content}
+
+ {contentParser(data.content, data.tags)}
+
-
- );
- } else {
- return
;
- }
+ )}
+
+ );
});
diff --git a/src/components/note/quoteRepost.tsx b/src/components/note/quoteRepost.tsx
index e80f3aba..729fdbfe 100644
--- a/src/components/note/quoteRepost.tsx
+++ b/src/components/note/quoteRepost.tsx
@@ -1,24 +1,12 @@
import { RootNote } from '@components/note/rootNote';
import { UserQuoteRepost } from '@components/user/quoteRepost';
-import destr from 'destr';
+import { getQuoteID } from '@utils/transform';
+
import { memo } from 'react';
export const NoteQuoteRepost = memo(function NoteQuoteRepost({ event }: { event: any }) {
- const rootNote = () => {
- let note = null;
-
- if (event.content) {
- const content = destr(event.content);
- if (content) {
- note =
;
- }
- } else {
- note =
;
- }
-
- return note;
- };
+ const rootID = getQuoteID(event.tags);
return (
@@ -26,7 +14,7 @@ export const NoteQuoteRepost = memo(function NoteQuoteRepost({ event }: { event:
- {rootNote()}
+
);
});
diff --git a/src/components/note/rootNote.tsx b/src/components/note/rootNote.tsx
index f43cb3ca..b73759a8 100644
--- a/src/components/note/rootNote.tsx
+++ b/src/components/note/rootNote.tsx
@@ -6,42 +6,37 @@ import { READONLY_RELAYS } from '@stores/constants';
import { contentParser } from '@utils/parser';
-import { memo, useCallback, useContext, useEffect, useState } from 'react';
+import { memo, useContext } from 'react';
+import useSWRSubscription from 'swr/subscription';
import { navigate } from 'vite-plugin-ssr/client/router';
-export const RootNote = memo(function RootNote({ event }: { event: any }) {
+export const RootNote = memo(function RootNote({ id }: { id: string }) {
const pool: any = useContext(RelayContext);
- const [data, setData] = useState(null);
- const [content, setContent] = useState('');
-
- const openUserPage = (e) => {
- e.stopPropagation();
- navigate(`/user?pubkey=${event.pubkey}`);
- };
-
const openThread = (e) => {
const selection = window.getSelection();
if (selection.toString().length === 0) {
- navigate(`/newsfeed/note?id=${event.parent_id}`);
+ navigate(`/newsfeed/note?id=${id}`);
} else {
e.stopPropagation();
}
};
- const fetchEvent = useCallback(
- async (id: string) => {
- const unsubscribe = pool.subscribe(
- [
+ const { data, error } = useSWRSubscription(
+ id
+ ? [
{
ids: [id],
kinds: [1],
},
- ],
+ ]
+ : null,
+ (key, { next }) => {
+ const unsubscribe = pool.subscribe(
+ key,
READONLY_RELAYS,
(event: any) => {
- setData(event);
- setContent(contentParser(event.content, event.tags));
+ next(null, event);
},
undefined,
undefined,
@@ -53,72 +48,32 @@ export const RootNote = memo(function RootNote({ event }: { event: any }) {
return () => {
unsubscribe();
};
- },
- [pool]
+ }
);
- useEffect(() => {
- let ignore = false;
-
- if (!ignore) {
- if (typeof event === 'object') {
- setData(event);
- setContent(contentParser(event.content, event.tags));
- } else {
- fetchEvent(event);
- }
- }
-
- return () => {
- ignore = true;
- };
- }, [event, fetchEvent]);
-
- if (data) {
- return (
-
openThread(e)} className="relative z-10 flex flex-col">
-
openUserPage(e)}>
+ return (
+ <>
+ {error &&
failed to load
}
+ {!data ? (
+
+ ) : (
+
openThread(e)} className="relative z-10 flex flex-col">
-
-
-
e.stopPropagation()} className="mt-5 pl-[52px]">
-
-
-
- );
- } else {
- return (
-
-
-
-
-
-
-
+
+
+ {contentParser(data.content, data.tags)}
-
-
-
-
-
+
e.stopPropagation()} className="mt-5 pl-[52px]">
+
-
- );
- }
+ )}
+ >
+ );
});
diff --git a/src/pages/index.page.tsx b/src/pages/index.page.tsx
index e11a0f99..3be7beec 100644
--- a/src/pages/index.page.tsx
+++ b/src/pages/index.page.tsx
@@ -1,6 +1,6 @@
import { RelayContext } from '@components/relaysProvider';
-import { FULL_RELAYS } from '@stores/constants';
+import { READONLY_RELAYS } from '@stores/constants';
import { dateToUnix, hoursAgo } from '@utils/getDate';
import {
@@ -16,17 +16,18 @@ import { getParentID } from '@utils/transform';
import LumeSymbol from '@assets/icons/Lume';
-import { useCallback, useContext, useEffect, useRef } from 'react';
+import { useContext, useEffect, useRef } from 'react';
import { navigate } from 'vite-plugin-ssr/client/router';
export function Page() {
const pool: any = useContext(RelayContext);
-
const now = useRef(new Date());
- const timeout = useRef(null);
- const fetchData = useCallback(
- async (account: { id: number; pubkey: string; chats: string[] }, tags: any) => {
+ useEffect(() => {
+ let unsubscribe: () => void;
+ let timeout: any;
+
+ const fetchInitalData = async (account: { pubkey: string; id: number }, tags: string) => {
const lastLogin = await getLastLogin();
const notes = await countTotalNotes();
@@ -52,6 +53,7 @@ export function Page() {
since: since,
until: dateToUnix(now.current),
});
+
// kind 4 (chats) query
query.push({
kinds: [4],
@@ -59,6 +61,7 @@ export function Page() {
since: 0,
until: dateToUnix(now.current),
});
+
// kind 43, 43 (mute user, hide message) query
query.push({
authors: [account.pubkey],
@@ -66,10 +69,11 @@ export function Page() {
since: 0,
until: dateToUnix(now.current),
});
+
// subscribe relays
- const unsubscribe = pool.subscribe(
+ unsubscribe = pool.subscribe(
query,
- FULL_RELAYS,
+ READONLY_RELAYS,
(event: { kind: number; tags: string[]; id: string; pubkey: string; content: string; created_at: number }) => {
switch (event.kind) {
// short text note
@@ -123,44 +127,30 @@ export function Page() {
undefined,
() => {
updateLastLogin(dateToUnix(now.current));
- timeout.current = setTimeout(() => {
+ timeout = setTimeout(() => {
navigate('/newsfeed/following', { overwriteLastHistoryEntry: true });
}, 5000);
- },
- {
- unsubscribeOnEose: true,
- logAllEvents: false,
}
);
+ };
- return () => {
- unsubscribe();
- };
- },
- [pool]
- );
-
- useEffect(() => {
- let ignore = false;
-
- if (!ignore) {
- getActiveAccount()
- .then((res: any) => {
- if (res) {
- const account = res;
- fetchData(account, account.follows);
- } else {
- navigate('/onboarding', { overwriteLastHistoryEntry: true });
- }
- })
- .catch(console.error);
- }
+ getActiveAccount()
+ .then((res: any) => {
+ if (res) {
+ fetchInitalData(res, res.follows);
+ } else {
+ navigate('/onboarding', { overwriteLastHistoryEntry: true });
+ }
+ })
+ .catch(console.error);
return () => {
- ignore = true;
- clearTimeout(timeout.current);
+ if (unsubscribe) {
+ unsubscribe();
+ }
+ clearTimeout(timeout);
};
- }, [fetchData]);
+ }, []);
return (
diff --git a/src/utils/broadcast.tsx b/src/utils/broadcast.tsx
new file mode 100644
index 00000000..26778af0
--- /dev/null
+++ b/src/utils/broadcast.tsx
@@ -0,0 +1,11 @@
+import { WRITEONLY_RELAYS } from '@stores/constants';
+
+import { getEventHash, signEvent } from 'nostr-tools';
+
+export const broadcast = ({ pool, data, privkey }: { pool: any; data: any; privkey: string }) => {
+ const event = data;
+ event.id = getEventHash(event);
+ event.sig = signEvent(event, privkey);
+
+ pool.publish(event, WRITEONLY_RELAYS);
+};
diff --git a/src/utils/transform.tsx b/src/utils/transform.tsx
index 1fb1caf2..aca05ac9 100644
--- a/src/utils/transform.tsx
+++ b/src/utils/transform.tsx
@@ -50,6 +50,26 @@ export const getParentID = (arr: string[], fallback: string) => {
return parentID;
};
+// get parent id from event tags
+export const getQuoteID = (arr: string[]) => {
+ const tags = destr(arr);
+ let quoteID = null;
+
+ if (tags.length > 0) {
+ if (tags[0][0] === 'e') {
+ quoteID = tags[0][1];
+ } else {
+ tags.forEach((tag) => {
+ if (tag[0] === 'e') {
+ quoteID = tag[1];
+ }
+ });
+ }
+ }
+
+ return quoteID;
+};
+
// sort messages by timestamp
export const sortMessages = (arr: any) => {
arr.sort((a, b) => {