From 9c153e4a18189206dd47ac96de04e5c049d89662 Mon Sep 17 00:00:00 2001 From: en Date: Wed, 19 Feb 2025 21:22:56 +0100 Subject: [PATCH] feat(notes): finalize repost action --- src/components/Notes/Note.tsx | 16 ++++- src/components/Notes/NoteSubmit.tsx | 7 +- src/pages/feed/action.ts | 108 +++++++++++++++++++--------- src/types/note.ts | 13 ++++ 4 files changed, 108 insertions(+), 36 deletions(-) diff --git a/src/components/Notes/Note.tsx b/src/components/Notes/Note.tsx index 4995736..8f37947 100644 --- a/src/components/Notes/Note.tsx +++ b/src/components/Notes/Note.tsx @@ -18,7 +18,7 @@ import { import { useComments } from 'hooks/useComments' import { nip19 } from 'nostr-tools' import { useState } from 'react' -import { Link } from 'react-router-dom' +import { Link, useSubmit } from 'react-router-dom' import { appRoutes, getProfilePageRoute } from 'routes' import { FeedPostsFilter, NSFWFilter, UserProfile } from 'types' import { DEFAULT_FILTER_OPTIONS, hexToNpub, log, LogType } from 'utils' @@ -32,6 +32,7 @@ interface NoteProps { export const Note = ({ ndkEvent }: NoteProps) => { const { ndk } = useNDKContext() + const submit = useSubmit() const userState = useAppSelector((state) => state.user) const userPubkey = userState.user?.pubkey as string | undefined const [eventProfile, setEventProfile] = useState() @@ -172,7 +173,18 @@ export const Note = ({ ndkEvent }: NoteProps) => { if (!confirm) return const repostNdkEvent = await ndkEvent.repost(false) - await repostNdkEvent.sign() + const rawEvent = repostNdkEvent.rawEvent() + submit( + JSON.stringify({ + intent: 'repost', + note1: ndkEvent.encode(), + data: rawEvent + }), + { + method: 'post', + encType: 'application/json' + } + ) } // Is this user's repost? diff --git a/src/components/Notes/NoteSubmit.tsx b/src/components/Notes/NoteSubmit.tsx index c57943c..dd0a028 100644 --- a/src/components/Notes/NoteSubmit.tsx +++ b/src/components/Notes/NoteSubmit.tsx @@ -55,8 +55,11 @@ export const NoteSubmit = ({ const handleFormSubmit = async (event: React.FormEvent) => { event.preventDefault() const formSubmit = { - content, - nsfw + intent: 'submit', + data: { + content, + nsfw + } } // Reset form diff --git a/src/pages/feed/action.ts b/src/pages/feed/action.ts index 5a0c439..61a3ce8 100644 --- a/src/pages/feed/action.ts +++ b/src/pages/feed/action.ts @@ -1,10 +1,10 @@ -import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk' +import NDK, { NDKEvent, NDKKind, NostrEvent } from '@nostr-dev-kit/ndk' import { NDKContextType } from 'contexts/NDKContext' import { ActionFunctionArgs, redirect } from 'react-router-dom' import { toast } from 'react-toastify' import { getFeedNotePageRoute } from 'routes' import { store } from 'store' -import { NoteSubmitForm, NoteSubmitFormErrors } from 'types' +import { NoteAction, NoteSubmitForm, NoteSubmitFormErrors } from 'types' import { log, LogType, @@ -38,38 +38,25 @@ export const feedPostRouteAction = return null } - const formSubmit = (await request.json()) as NoteSubmitForm - const formErrors = validateFormData(formSubmit) - - if (Object.keys(formErrors).length) return formErrors - - const content = decodeURIComponent(formSubmit.content!) - const currentTimeStamp = now() - - const ndkEvent = new NDKEvent(ndkContext.ndk, { - kind: NDKKind.Text, - created_at: currentTimeStamp, - content: content, - tags: [ - ['L', 'source'], - ['l', window.location.host, 'source'] - ], - pubkey: hexPubkey - }) - try { - if (formSubmit.nsfw) ndkEvent.tags.push(['L', 'content-warning']) + const action = (await request.json()) as NoteAction + switch (action.intent) { + case 'submit': + return await handleActionSubmit( + ndkContext.ndk, + action.data, + hexPubkey + ) - await ndkEvent.sign() - const note1 = ndkEvent.encode() - const publishedOnRelays = await ndkEvent.publish() - if (publishedOnRelays.size === 0) { - toast.error('Failed to publish note on any relay') - return null - } else { - toast.success('Note published successfully') - removeLocalStorageItem(NOTE_DRAFT_CACHE_KEY) - return redirect(getFeedNotePageRoute(note1)) + case 'repost': + return await handleActionRepost( + ndkContext.ndk, + action.data, + action.note1 + ) + + default: + throw new Error('Unsupported feed action. Intent missing.') } } catch (error) { log(true, LogType.Error, 'Failed to publish note', error) @@ -87,3 +74,60 @@ const validateFormData = (formSubmit: NoteSubmitForm): NoteSubmitFormErrors => { return errors } + +async function handleActionSubmit( + ndk: NDK, + data: NoteSubmitForm, + pubkey: string +) { + const formErrors = validateFormData(data) + + if (Object.keys(formErrors).length) return formErrors + + const content = decodeURIComponent(data.content!) + const currentTimeStamp = now() + + const ndkEvent = new NDKEvent(ndk, { + kind: NDKKind.Text, + created_at: currentTimeStamp, + content: content, + tags: [ + ['L', 'source'], + ['l', window.location.host, 'source'] + ], + pubkey + }) + + try { + if (data.nsfw) ndkEvent.tags.push(['L', 'content-warning']) + + await ndkEvent.sign() + const note1 = ndkEvent.encode() + const publishedOnRelays = await ndkEvent.publish() + if (publishedOnRelays.size === 0) { + toast.error('Failed to publish note on any relay') + return null + } else { + toast.success('Note published successfully') + removeLocalStorageItem(NOTE_DRAFT_CACHE_KEY) + return redirect(getFeedNotePageRoute(note1)) + } + } catch (error) { + log(true, LogType.Error, 'Failed to publish note', error) + toast.error('Failed to publish note') + return null + } +} +async function handleActionRepost(ndk: NDK, data: NostrEvent, note1: string) { + const ndkEvent = new NDKEvent(ndk, data) + await ndkEvent.sign() + + const publishedOnRelays = await ndkEvent.publish() + if (publishedOnRelays.size === 0) { + toast.error('Failed to publish note on any relay') + return null + } else { + toast.success('Note published successfully') + return redirect(getFeedNotePageRoute(note1)) + } +} diff --git a/src/types/note.ts b/src/types/note.ts index 5e2f179..31668b3 100644 --- a/src/types/note.ts +++ b/src/types/note.ts @@ -1,6 +1,19 @@ +import { NostrEvent } from '@nostr-dev-kit/ndk' + export interface NoteSubmitForm { content: string nsfw: boolean } export interface NoteSubmitFormErrors extends Partial {} + +export type NoteAction = + | { + intent: 'submit' + data: NoteSubmitForm + } + | { + intent: 'repost' + note1: string + data: NostrEvent + }