openThread(e)} className="relative z-10 flex flex-col">
+
openNote(e)} className="relative z-10 flex flex-col">
@@ -92,7 +94,7 @@ export const RootNote = memo(function RootNote({ id, fallback }: { id: string; f
e.stopPropagation()} className="mt-5 pl-[52px]">
-
+
)}
diff --git a/src/app/note/_default.page.tsx b/src/app/note/_default.page.tsx
new file mode 100644
index 00000000..7a0967d9
--- /dev/null
+++ b/src/app/note/_default.page.tsx
@@ -0,0 +1 @@
+export { LayoutNewsfeed as Layout } from './layout';
diff --git a/src/app/note/components/form.tsx b/src/app/note/components/form.tsx
new file mode 100644
index 00000000..1816afff
--- /dev/null
+++ b/src/app/note/components/form.tsx
@@ -0,0 +1,71 @@
+import { RelayContext } from '@lume/shared/relayProvider';
+import { WRITEONLY_RELAYS } from '@lume/stores/constants';
+import { dateToUnix } from '@lume/utils/getDate';
+import { useActiveAccount } from '@lume/utils/hooks/useActiveAccount';
+
+import { getEventHash, signEvent } from 'nostr-tools';
+import { useContext, useState } from 'react';
+
+export default function NoteReplyForm({ id }: { id: string }) {
+ const pool: any = useContext(RelayContext);
+ const { account, isLoading, isError } = useActiveAccount();
+
+ const [value, setValue] = useState('');
+ const profile = account ? JSON.parse(account.metadata) : null;
+
+ const submitEvent = () => {
+ if (!isLoading && !isError && account) {
+ const event: any = {
+ content: value,
+ created_at: dateToUnix(),
+ kind: 1,
+ pubkey: account.pubkey,
+ tags: [['e', id]],
+ };
+ event.id = getEventHash(event);
+ event.sig = signEvent(event, account.privkey);
+
+ // publish note
+ pool.publish(event, WRITEONLY_RELAYS);
+ // reset form
+ setValue('');
+ } else {
+ console.log('error');
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/note/components/replies.tsx b/src/app/note/components/replies.tsx
new file mode 100644
index 00000000..3d4cb94c
--- /dev/null
+++ b/src/app/note/components/replies.tsx
@@ -0,0 +1,63 @@
+import NoteReplyForm from '@lume/app/note/components/form';
+import NoteReply from '@lume/app/note/components/reply';
+import { RelayContext } from '@lume/shared/relayProvider';
+import { READONLY_RELAYS } from '@lume/stores/constants';
+import { sortEvents } from '@lume/utils/transform';
+
+import { useContext } from 'react';
+import useSWRSubscription from 'swr/subscription';
+
+export default function NoteReplies({ id }: { id: string }) {
+ const pool: any = useContext(RelayContext);
+
+ const { data, error } = useSWRSubscription(id ? ['note-replies', id] : null, ([, key], { next }) => {
+ // subscribe to note
+ const unsubscribe = pool.subscribe(
+ [
+ {
+ '#e': [key],
+ since: 0,
+ kinds: [1],
+ limit: 20,
+ },
+ ],
+ READONLY_RELAYS,
+ (event: any) => {
+ next(null, (prev: any) => (prev ? [...prev, event] : [event]));
+ }
+ );
+
+ return () => {
+ unsubscribe();
+ };
+ });
+
+ return (
+
+
+
Replies
+
+
+
+
+ {error &&
failed to load
}
+ {!data ? (
+
+ ) : (
+ sortEvents(data).map((event: any) => {
+ return
;
+ })
+ )}
+
+
+
+ );
+}
diff --git a/src/app/note/components/reply.tsx b/src/app/note/components/reply.tsx
new file mode 100644
index 00000000..f0809a95
--- /dev/null
+++ b/src/app/note/components/reply.tsx
@@ -0,0 +1,18 @@
+import { contentParser } from '@lume/app/newsfeed/components/contentParser';
+
+import NoteReplyUser from './user';
+
+export default function NoteReply({ data }: { data: any }) {
+ const content = contentParser(data.content, data.tags);
+
+ return (
+
+ );
+}
diff --git a/src/app/note/components/user.tsx b/src/app/note/components/user.tsx
new file mode 100644
index 00000000..08c526db
--- /dev/null
+++ b/src/app/note/components/user.tsx
@@ -0,0 +1,48 @@
+import { DEFAULT_AVATAR, IMGPROXY_URL } from '@lume/stores/constants';
+import { useProfile } from '@lume/utils/hooks/useProfile';
+import { shortenKey } from '@lume/utils/shortenKey';
+
+import dayjs from 'dayjs';
+import relativeTime from 'dayjs/plugin/relativeTime';
+
+dayjs.extend(relativeTime);
+
+export default function NoteReplyUser({ pubkey, time }: { pubkey: string; time: number }) {
+ const { user, isError, isLoading } = useProfile(pubkey);
+
+ return (
+
+ {isError || isLoading ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+
+
+
+
+ {user?.display_name || user?.name || shortenKey(pubkey)}
+
+ ยท
+ {dayjs().to(dayjs.unix(time))}
+
+
+ >
+ )}
+
+ );
+}
diff --git a/src/app/note/layout.tsx b/src/app/note/layout.tsx
new file mode 100644
index 00000000..b0ce8030
--- /dev/null
+++ b/src/app/note/layout.tsx
@@ -0,0 +1,29 @@
+import AppHeader from '@lume/shared/appHeader';
+import MultiAccounts from '@lume/shared/multiAccounts';
+import Navigation from '@lume/shared/navigation';
+
+export function LayoutNewsfeed({ children }: { children: React.ReactNode }) {
+ return (
+
+ );
+}
diff --git a/src/app/note/pages/index.page.tsx b/src/app/note/pages/index.page.tsx
new file mode 100644
index 00000000..5be6ae95
--- /dev/null
+++ b/src/app/note/pages/index.page.tsx
@@ -0,0 +1,87 @@
+import { contentParser } from '@lume/app/newsfeed/components/contentParser';
+import NoteMetadata from '@lume/app/newsfeed/components/note/metadata';
+import { NoteDefaultUser } from '@lume/app/newsfeed/components/user/default';
+import NoteReplies from '@lume/app/note/components/replies';
+import { RelayContext } from '@lume/shared/relayProvider';
+import { READONLY_RELAYS } from '@lume/stores/constants';
+import { usePageContext } from '@lume/utils/hooks/usePageContext';
+
+import { useContext } from 'react';
+import useSWRSubscription from 'swr/subscription';
+
+export function Page() {
+ const pool: any = useContext(RelayContext);
+ const pageContext = usePageContext();
+ const searchParams: any = pageContext.urlParsed.search;
+
+ const noteID = searchParams.id;
+
+ const { data, error } = useSWRSubscription(noteID ? ['note', noteID] : null, ([, key], { next }) => {
+ // subscribe to note
+ const unsubscribe = pool.subscribe(
+ [
+ {
+ ids: [key],
+ },
+ ],
+ READONLY_RELAYS,
+ (event: { id: string; pubkey: string }) => {
+ next(null, event);
+ }
+ );
+
+ return () => {
+ unsubscribe();
+ };
+ });
+
+ return (
+
+
+
+ {error &&
failed to load
}
+ {!data ? (
+
+ ) : (
+ <>
+
+
+
+
+
+ {contentParser(data.content, data.tags)}
+
+
+
+
e.stopPropagation()} className="mt-5 border-t border-zinc-800 px-5 py-5">
+
+
+
+ >
+ )}
+
+
+
+
+ );
+}
diff --git a/src/shared/form/comment.tsx b/src/shared/form/comment.tsx
deleted file mode 100644
index af9b9f09..00000000
--- a/src/shared/form/comment.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { RelayContext } from '@lume/shared/relayProvider';
-import { WRITEONLY_RELAYS } from '@lume/stores/constants';
-import { dateToUnix } from '@lume/utils/getDate';
-import { useActiveAccount } from '@lume/utils/hooks/useActiveAccount';
-
-import { getEventHash, signEvent } from 'nostr-tools';
-import { useContext, useState } from 'react';
-
-export default function FormComment({ eventID }: { eventID: any }) {
- const pool: any = useContext(RelayContext);
- const { account } = useActiveAccount();
-
- const [value, setValue] = useState('');
- const profile = JSON.parse(account.metadata);
-
- const submitEvent = () => {
- const event: any = {
- content: value,
- created_at: dateToUnix(),
- kind: 1,
- pubkey: account.pubkey,
- tags: [['e', eventID]],
- };
- event.id = getEventHash(event);
- event.sig = signEvent(event, account.privkey);
-
- // publish note
- pool.publish(event, WRITEONLY_RELAYS);
- // send notification
- // sendNotification('Comment has been published successfully');
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/stores/note.tsx b/src/stores/note.tsx
index f071bbb6..bfda4ca8 100644
--- a/src/stores/note.tsx
+++ b/src/stores/note.tsx
@@ -1,13 +1,6 @@
import { atom } from 'jotai';
import { atomWithReset } from 'jotai/utils';
-// notes
-export const notesAtom = atom([]);
-export const filteredNotesAtom = atom((get) => {
- const notes = get(notesAtom);
- return notes.filter((item, index) => index === notes.findIndex((other) => item.parent_id === other.parent_id));
-});
-
// note content
export const noteContentAtom = atomWithReset('');
diff --git a/src/utils/transform.tsx b/src/utils/transform.tsx
index 850f9e5d..b42e5762 100644
--- a/src/utils/transform.tsx
+++ b/src/utils/transform.tsx
@@ -70,10 +70,10 @@ export const getQuoteID = (arr: string[]) => {
return quoteID;
};
-// sort messages by timestamp
-export const sortMessages = (arr: any) => {
+// sort events by timestamp
+export const sortEvents = (arr: any) => {
arr.sort((a, b) => {
- return b.created_at - a.created_at;
+ return a.created_at - b.created_at;
});
return arr;