From dc5b4f8ac12696d181224cfb26bcd955fcac3fcf Mon Sep 17 00:00:00 2001 From: reya Date: Tue, 14 Nov 2023 15:15:13 +0700 Subject: [PATCH] refactor publish event --- src/app/new/post.tsx | 58 ++++++++--------------- src/app/notes/text.tsx | 4 +- src/app/personal/components/relayCard.tsx | 7 ++- src/app/personal/components/zapCard.tsx | 2 +- src/shared/notes/actions.tsx | 56 +++++++++++++++------- src/shared/notes/actions/reaction.tsx | 26 ++++------ src/shared/notes/actions/reply.tsx | 45 ------------------ src/shared/notes/actions/repost.tsx | 29 ++++-------- src/shared/notes/actions/zap.tsx | 14 ++---- src/shared/notes/article.tsx | 2 +- src/shared/notes/child.tsx | 2 +- src/shared/notes/file.tsx | 2 +- src/shared/notes/index.ts | 1 - src/shared/notes/replies/form.tsx | 42 ++++++++++------ src/shared/notes/replies/item.tsx | 9 +--- src/shared/notes/replies/sub.tsx | 2 +- src/shared/notes/repost.tsx | 20 ++++---- src/shared/notes/text.tsx | 2 +- src/shared/notes/unknown.tsx | 2 +- src/shared/widgets/thread.tsx | 4 +- src/utils/hooks/useEvent.ts | 4 +- src/utils/hooks/useProfile.ts | 1 + 22 files changed, 143 insertions(+), 191 deletions(-) delete mode 100644 src/shared/notes/actions/reply.tsx 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 }) {
{renderFileType()}
- +
); 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,