diff --git a/src/app/new/post.tsx b/src/app/new/post.tsx
index a77e5f74..528ccbd5 100644
--- a/src/app/new/post.tsx
+++ b/src/app/new/post.tsx
@@ -1,4 +1,4 @@
-import { NDKEvent, NDKKind, NDKTag } from '@nostr-dev-kit/ndk';
+import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import CharacterCount from '@tiptap/extension-character-count';
import Image from '@tiptap/extension-image';
import Placeholder from '@tiptap/extension-placeholder';
@@ -21,7 +21,7 @@ import { WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
export function NewPostScreen() {
- const { ndk, relayUrls } = useNDK();
+ const { ndk } = useNDK();
const { addWidget } = useWidget();
const [loading, setLoading] = useState(false);
@@ -56,12 +56,6 @@ export function NewPostScreen() {
try {
setLoading(true);
- const reply = {
- id: searchParams.get('id'),
- root: searchParams.get('root'),
- pubkey: searchParams.get('pubkey'),
- };
-
// get plaintext content
const html = editor.getHTML();
const serializedContent = convert(html, {
@@ -71,37 +65,23 @@ export function NewPostScreen() {
],
});
- // define tags
- let tags: NDKTag[] = [];
-
- // add reply to tags if present
- if (reply.id && reply.pubkey) {
- if (reply.root) {
- tags = [
- ['e', reply.root, relayUrls[0], 'root'],
- ['e', reply.id, relayUrls[0], 'reply'],
- ['p', reply.pubkey],
- ];
- } else {
- tags = [
- ['e', reply.id, relayUrls[0], 'reply'],
- ['p', reply.pubkey],
- ];
- }
- }
-
- // add hashtag to tags if present
- const hashtags = serializedContent
- .split(/\s/gm)
- .filter((s: string) => s.startsWith('#'));
- hashtags?.forEach((tag: string) => {
- tags.push(['t', tag.replace('#', '')]);
- });
-
const event = new NDKEvent(ndk);
event.content = serializedContent;
event.kind = NDKKind.Text;
- event.tags = tags;
+
+ // add reply to tags if present
+ const replyTo = searchParams.get('replyTo');
+ const rootReplyTo = searchParams.get('rootReplyTo');
+
+ if (rootReplyTo) {
+ const rootEvent = await ndk.fetchEvent(rootReplyTo);
+ event.tag(rootEvent, 'root');
+ }
+
+ if (replyTo) {
+ const replyEvent = await ndk.fetchEvent(replyTo);
+ event.tag(replyEvent, 'reply');
+ }
// publish event
const publishedRelays = await event.publish();
@@ -114,7 +94,7 @@ export function NewPostScreen() {
setSearchParams({});
// open new widget with this event id
- if (!reply.id && !reply.pubkey) {
+ if (!replyTo) {
addWidget.mutate({
title: 'Thread',
content: event.id,
@@ -146,9 +126,9 @@ export function NewPostScreen() {
autoCorrect="off"
autoCapitalize="off"
/>
- {searchParams.get('id') && (
+ {searchParams.get('replyTo') && (
-
+
)}
diff --git a/src/app/personal/components/relayCard.tsx b/src/app/personal/components/relayCard.tsx
index af088253..f5591c1c 100644
--- a/src/app/personal/components/relayCard.tsx
+++ b/src/app/personal/components/relayCard.tsx
@@ -15,7 +15,10 @@ export function RelayCard() {
queryKey: ['relays'],
queryFn: async () => {
const user = ndk.getUser({ pubkey: db.account.pubkey });
- return await user.relayList();
+ const relays = await user.relayList();
+
+ if (!relays) return Promise.reject(new Error("user's relay set not found"));
+ return relays;
},
refetchOnWindowFocus: false,
});
@@ -29,7 +32,7 @@ export function RelayCard() {
) : (
- {compactNumber.format(data?.relays?.length)}
+ {compactNumber.format(data?.relays?.length || 0)}
diff --git a/src/app/personal/components/zapCard.tsx b/src/app/personal/components/zapCard.tsx
index e2aa5309..bde0bba9 100644
--- a/src/app/personal/components/zapCard.tsx
+++ b/src/app/personal/components/zapCard.tsx
@@ -40,7 +40,7 @@ export function ZapCard() {
{compactNumber.format(
- data.stats[db.account.pubkey].zaps_received.msats / 1000
+ data?.stats[db.account.pubkey]?.zaps_received?.msats / 1000 || 0
)}
diff --git a/src/shared/notes/actions.tsx b/src/shared/notes/actions.tsx
index b2455841..0cb66591 100644
--- a/src/shared/notes/actions.tsx
+++ b/src/shared/notes/actions.tsx
@@ -1,8 +1,9 @@
+import { NDKEvent } from '@nostr-dev-kit/ndk';
import * as Tooltip from '@radix-ui/react-tooltip';
+import { createSearchParams, useNavigate } from 'react-router-dom';
-import { FocusIcon } from '@shared/icons';
+import { FocusIcon, ReplyIcon } from '@shared/icons';
import { NoteReaction } from '@shared/notes/actions/reaction';
-import { NoteReply } from '@shared/notes/actions/reply';
import { NoteRepost } from '@shared/notes/actions/repost';
import { NoteZap } from '@shared/notes/actions/zap';
@@ -11,22 +12,21 @@ import { WIDGET_KIND } from '@stores/constants';
import { useWidget } from '@utils/hooks/useWidget';
export function NoteActions({
- id,
- pubkey,
- extraButtons = true,
- root,
+ event,
+ rootEventId,
+ canOpenEvent = true,
}: {
- id: string;
- pubkey: string;
- extraButtons?: boolean;
- root?: string;
+ event: NDKEvent;
+ rootEventId?: string;
+ canOpenEvent?: boolean;
}) {
const { addWidget } = useWidget();
+ const navigate = useNavigate();
return (
- {extraButtons && (
+ {canOpenEvent && (
@@ -36,7 +36,7 @@ export function NoteActions({
addWidget.mutate({
kind: WIDGET_KIND.thread,
title: 'Thread',
- content: id,
+ content: event.id,
})
}
className="inline-flex h-7 w-max items-center justify-center gap-2 rounded-full bg-neutral-100 px-2 text-sm font-medium dark:bg-neutral-900"
@@ -55,10 +55,34 @@ export function NoteActions({
)}
-
-
-
-
+
+
+
+
+
+
+ Quick reply
+
+
+
+
+
+
+
diff --git a/src/shared/notes/actions/reaction.tsx b/src/shared/notes/actions/reaction.tsx
index 9a126c33..d4d78fa1 100644
--- a/src/shared/notes/actions/reaction.tsx
+++ b/src/shared/notes/actions/reaction.tsx
@@ -1,8 +1,7 @@
-import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
+import { NDKEvent } from '@nostr-dev-kit/ndk';
import * as Popover from '@radix-ui/react-popover';
import { useState } from 'react';
-
-import { useNDK } from '@libs/ndk/provider';
+import { toast } from 'sonner';
import { ReactionIcon } from '@shared/icons';
@@ -29,9 +28,7 @@ const REACTIONS = [
},
];
-export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
- const { ndk } = useNDK();
-
+export function NoteReaction({ event }: { event: NDKEvent }) {
const [open, setOpen] = useState(false);
const [reaction, setReaction] = useState
(null);
@@ -41,19 +38,14 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
};
const react = async (content: string) => {
- setReaction(content);
+ try {
+ setReaction(content);
- const event = new NDKEvent(ndk);
- event.content = content;
- event.kind = NDKKind.Reaction;
- event.tags = [
- ['e', id],
- ['p', pubkey],
- ];
-
- const publishedRelays = await event.publish();
- if (publishedRelays) {
+ // react
+ await event.react(content);
setOpen(false);
+ } catch (e) {
+ toast.error(e);
}
};
diff --git a/src/shared/notes/actions/reply.tsx b/src/shared/notes/actions/reply.tsx
deleted file mode 100644
index 29fc1c4e..00000000
--- a/src/shared/notes/actions/reply.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import * as Tooltip from '@radix-ui/react-tooltip';
-import { createSearchParams, useNavigate } from 'react-router-dom';
-
-import { ReplyIcon } from '@shared/icons';
-
-export function NoteReply({
- id,
- pubkey,
- root,
-}: {
- id: string;
- pubkey: string;
- root?: string;
-}) {
- const navigate = useNavigate();
-
- return (
-
-
-
-
-
-
- Quick reply
-
-
-
-
- );
-}
diff --git a/src/shared/notes/actions/repost.tsx b/src/shared/notes/actions/repost.tsx
index 14a275be..135e22b9 100644
--- a/src/shared/notes/actions/repost.tsx
+++ b/src/shared/notes/actions/repost.tsx
@@ -1,41 +1,30 @@
-import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
+import { NDKEvent } from '@nostr-dev-kit/ndk';
import * as AlertDialog from '@radix-ui/react-alert-dialog';
import * as Tooltip from '@radix-ui/react-tooltip';
import { useState } from 'react';
import { toast } from 'sonner';
import { twMerge } from 'tailwind-merge';
-import { useNDK } from '@libs/ndk/provider';
-
import { LoaderIcon, RepostIcon } from '@shared/icons';
-export function NoteRepost({ id, pubkey }: { id: string; pubkey: string }) {
- const { ndk, relayUrls } = useNDK();
-
+export function NoteRepost({ event }: { event: NDKEvent }) {
const [open, setOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isRepost, setIsRepost] = useState(false);
const submit = async () => {
- setIsLoading(true);
+ try {
+ setIsLoading(true);
- const tags = [
- ['e', id, relayUrls[0], 'root'],
- ['p', pubkey],
- ];
+ // repsot
+ await event.repost(true);
- const event = new NDKEvent(ndk);
- event.content = '';
- event.kind = NDKKind.Repost;
- event.tags = tags;
-
- const publishedRelays = await event.publish();
- if (publishedRelays) {
+ // reset state
setOpen(false);
setIsRepost(true);
- toast.success(`Broadcasted to ${publishedRelays.size} relays successfully.`);
- } else {
+ toast.success("You've reposted this post successfully");
+ } catch (e) {
setIsLoading(false);
toast.error('Repost failed, try again later');
}
diff --git a/src/shared/notes/actions/zap.tsx b/src/shared/notes/actions/zap.tsx
index 9b2828c2..0adebd5d 100644
--- a/src/shared/notes/actions/zap.tsx
+++ b/src/shared/notes/actions/zap.tsx
@@ -1,5 +1,6 @@
import { webln } from '@getalby/sdk';
import { SendPaymentResponse } from '@getalby/sdk/dist/types';
+import { NDKEvent } from '@nostr-dev-kit/ndk';
import * as Dialog from '@radix-ui/react-dialog';
import { invoke } from '@tauri-apps/api/primitives';
import { message } from '@tauri-apps/plugin-dialog';
@@ -9,16 +10,13 @@ import CurrencyInput from 'react-currency-input-field';
import { CancelIcon, ZapIcon } from '@shared/icons';
-import { useEvent } from '@utils/hooks/useEvent';
-import { useNostr } from '@utils/hooks/useNostr';
import { useProfile } from '@utils/hooks/useProfile';
import { sendNativeNotification } from '@utils/notification';
import { compactNumber } from '@utils/number';
-export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
- const { createZap } = useNostr();
- const { user } = useProfile(pubkey);
- const { data: event } = useEvent(id);
+export function NoteZap({ event }: { event: NDKEvent }) {
+ const nwc = useRef(null);
+ const { user } = useProfile(event.pubkey);
const [walletConnectURL, setWalletConnectURL] = useState(null);
const [amount, setAmount] = useState('21');
@@ -28,12 +26,10 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
const [isCompleted, setIsCompleted] = useState(false);
const [isLoading, setIsLoading] = useState(false);
- const nwc = useRef(null);
-
const createZapRequest = async () => {
try {
const zapAmount = parseInt(amount) * 1000;
- const res = await createZap(event, zapAmount, zapMessage);
+ const res = await event.zap(zapAmount, zapMessage);
if (!res)
return await message('Cannot create zap request', {
diff --git a/src/shared/notes/article.tsx b/src/shared/notes/article.tsx
index 1f2126bd..90aa6caf 100644
--- a/src/shared/notes/article.tsx
+++ b/src/shared/notes/article.tsx
@@ -63,7 +63,7 @@ export function ArticleNote({ event }: { event: NDKEvent }) {
-
+
);
diff --git a/src/shared/notes/child.tsx b/src/shared/notes/child.tsx
index 5cf63e8a..00f9ed15 100644
--- a/src/shared/notes/child.tsx
+++ b/src/shared/notes/child.tsx
@@ -6,7 +6,7 @@ import { useEvent } from '@utils/hooks/useEvent';
export function ChildNote({ id, isRoot }: { id: string; isRoot?: boolean }) {
const { status, data } = useEvent(id);
- if (status === 'pending') {
+ if (status === 'pending' || !data) {
return ;
}
diff --git a/src/shared/notes/file.tsx b/src/shared/notes/file.tsx
index 3829c75e..1e5a845f 100644
--- a/src/shared/notes/file.tsx
+++ b/src/shared/notes/file.tsx
@@ -84,7 +84,7 @@ export function FileNote({ event }: { event: NDKEvent }) {
);
diff --git a/src/shared/notes/index.ts b/src/shared/notes/index.ts
index 37aad1d6..b8dd7c07 100644
--- a/src/shared/notes/index.ts
+++ b/src/shared/notes/index.ts
@@ -8,7 +8,6 @@ export * from './unknown';
export * from './skeleton';
export * from './actions';
export * from './actions/reaction';
-export * from './actions/reply';
export * from './actions/repost';
export * from './actions/zap';
export * from './actions/more';
diff --git a/src/shared/notes/replies/form.tsx b/src/shared/notes/replies/form.tsx
index 4d123ee7..4d804ede 100644
--- a/src/shared/notes/replies/form.tsx
+++ b/src/shared/notes/replies/form.tsx
@@ -4,25 +4,39 @@ import { toast } from 'sonner';
import { useNDK } from '@libs/ndk/provider';
+import { LoaderIcon } from '@shared/icons';
import { ReplyMediaUploader } from '@shared/notes';
-export function NoteReplyForm({ eventId }: { eventId: string }) {
- const { ndk, relayUrls } = useNDK();
+export function NoteReplyForm({ rootEvent }: { rootEvent: NDKEvent }) {
+ const { ndk } = useNDK();
+
const [value, setValue] = useState('');
+ const [loading, setLoading] = useState(false);
const submit = async () => {
- const tags = [['e', eventId, relayUrls[0], 'root']];
+ try {
+ setLoading(true);
- // publish event
- const event = new NDKEvent(ndk);
- event.content = value;
- event.kind = NDKKind.Text;
- event.tags = tags;
+ const event = new NDKEvent(ndk);
+ event.content = value;
+ event.kind = NDKKind.Text;
- const publishedRelays = await event.publish();
- if (publishedRelays) {
- toast.success(`Broadcasted to ${publishedRelays.size} relays successfully.`);
- setValue('');
+ // tag root event
+ event.tag(rootEvent, 'reply');
+
+ // publish event
+ const publishedRelays = await event.publish();
+
+ if (publishedRelays) {
+ toast.success(`Broadcasted to ${publishedRelays.size} relays successfully.`);
+
+ // reset state
+ setValue('');
+ setLoading(false);
+ }
+ } catch (e) {
+ setLoading(false);
+ toast.error(e);
}
};
@@ -40,9 +54,9 @@ export function NoteReplyForm({ eventId }: { eventId: string }) {
diff --git a/src/shared/notes/replies/item.tsx b/src/shared/notes/replies/item.tsx
index 9f6fc08c..8ac52dbd 100644
--- a/src/shared/notes/replies/item.tsx
+++ b/src/shared/notes/replies/item.tsx
@@ -8,7 +8,7 @@ import { User } from '@shared/user';
import { NDKEventWithReplies } from '@utils/types';
-export function Reply({ event, root }: { event: NDKEventWithReplies; root?: string }) {
+export function Reply({ event }: { event: NDKEventWithReplies }) {
const [open, setOpen] = useState(false);
return (
@@ -30,12 +30,7 @@ export function Reply({ event, root }: { event: NDKEventWithReplies; root?: stri
) : null}
-
+
diff --git a/src/shared/notes/replies/sub.tsx b/src/shared/notes/replies/sub.tsx
index 7e3117ae..6b08add5 100644
--- a/src/shared/notes/replies/sub.tsx
+++ b/src/shared/notes/replies/sub.tsx
@@ -9,7 +9,7 @@ export function SubReply({ event }: { event: NDKEvent }) {
-
+
);
diff --git a/src/shared/notes/repost.tsx b/src/shared/notes/repost.tsx
index ab1c10b4..8317732c 100644
--- a/src/shared/notes/repost.tsx
+++ b/src/shared/notes/repost.tsx
@@ -15,7 +15,7 @@ import { User } from '@shared/user';
export function Repost({ event }: { event: NDKEvent }) {
const { ndk } = useNDK();
- const { status, data } = useQuery({
+ const { status, data: repostEvent } = useQuery({
queryKey: ['repost', event.id],
queryFn: async () => {
try {
@@ -40,14 +40,14 @@ export function Repost({ event }: { event: NDKEvent }) {
});
const renderContentByKind = () => {
- if (!data) return null;
- switch (data.kind) {
+ if (!repostEvent) return null;
+ switch (repostEvent.kind) {
case NDKKind.Text:
- return ;
+ return ;
case 1063:
- return ;
+ return ;
case NDKKind.Article:
- return ;
+ return ;
default:
return null;
}
@@ -66,9 +66,13 @@ export function Repost({ event }: { event: NDKEvent }) {
-
+
{renderContentByKind()}
-
+
diff --git a/src/shared/notes/text.tsx b/src/shared/notes/text.tsx
index 72a104be..68183e8d 100644
--- a/src/shared/notes/text.tsx
+++ b/src/shared/notes/text.tsx
@@ -47,7 +47,7 @@ export function TextNote({ event }: { event: NDKEvent }) {
{parsedContent}
-
+
);
diff --git a/src/shared/notes/unknown.tsx b/src/shared/notes/unknown.tsx
index 7e79a6e9..5eb15a7f 100644
--- a/src/shared/notes/unknown.tsx
+++ b/src/shared/notes/unknown.tsx
@@ -21,7 +21,7 @@ export function UnknownNote({ event }: { event: NDKEvent }) {
{event.content.toString()}
-
+
);
diff --git a/src/shared/widgets/thread.tsx b/src/shared/widgets/thread.tsx
index ff8b63e2..8e10d255 100644
--- a/src/shared/widgets/thread.tsx
+++ b/src/shared/widgets/thread.tsx
@@ -68,9 +68,9 @@ export function ThreadWidget({ widget }: { widget: Widget }) {
{renderKind(data)}
-
+
-
+
>
)}
diff --git a/src/utils/hooks/useEvent.ts b/src/utils/hooks/useEvent.ts
index 8b27b993..6082ff74 100644
--- a/src/utils/hooks/useEvent.ts
+++ b/src/utils/hooks/useEvent.ts
@@ -23,8 +23,8 @@ export function useEvent(id: undefined | string, embed?: undefined | string) {
});
const rEvent = [...rEvents].slice(-1)[0];
- if (!rEvent) return Promise.reject(new Error('event not found'));
+ if (!rEvent) return Promise.reject(new Error('event not found'));
return rEvent;
}
@@ -36,8 +36,8 @@ export function useEvent(id: undefined | string, embed?: undefined | string) {
// get event from relay
const event = await ndk.fetchEvent(id);
- if (!event) return Promise.reject(new Error('event not found'));
+ if (!event) return Promise.reject(new Error('event not found'));
return event;
},
refetchOnWindowFocus: false,
diff --git a/src/utils/hooks/useProfile.ts b/src/utils/hooks/useProfile.ts
index 7f162a4a..ebf984ec 100644
--- a/src/utils/hooks/useProfile.ts
+++ b/src/utils/hooks/useProfile.ts
@@ -20,6 +20,7 @@ export function useProfile(pubkey: string, embed?: string) {
const cleanPubkey = pubkey.replace(/[^a-zA-Z0-9]/g, '');
const user = ndk.getUser({ pubkey: cleanPubkey });
+ if (!user) return Promise.reject(new Error("user's profile not found"));
return await user.fetchProfile();
},
staleTime: Infinity,