feat(notes): finalize repost action

This commit is contained in:
en 2025-02-19 21:22:56 +01:00
parent f73a4277b3
commit 9c153e4a18
4 changed files with 108 additions and 36 deletions

View File

@ -18,7 +18,7 @@ import {
import { useComments } from 'hooks/useComments' import { useComments } from 'hooks/useComments'
import { nip19 } from 'nostr-tools' import { nip19 } from 'nostr-tools'
import { useState } from 'react' import { useState } from 'react'
import { Link } from 'react-router-dom' import { Link, useSubmit } from 'react-router-dom'
import { appRoutes, getProfilePageRoute } from 'routes' import { appRoutes, getProfilePageRoute } from 'routes'
import { FeedPostsFilter, NSFWFilter, UserProfile } from 'types' import { FeedPostsFilter, NSFWFilter, UserProfile } from 'types'
import { DEFAULT_FILTER_OPTIONS, hexToNpub, log, LogType } from 'utils' import { DEFAULT_FILTER_OPTIONS, hexToNpub, log, LogType } from 'utils'
@ -32,6 +32,7 @@ interface NoteProps {
export const Note = ({ ndkEvent }: NoteProps) => { export const Note = ({ ndkEvent }: NoteProps) => {
const { ndk } = useNDKContext() const { ndk } = useNDKContext()
const submit = useSubmit()
const userState = useAppSelector((state) => state.user) const userState = useAppSelector((state) => state.user)
const userPubkey = userState.user?.pubkey as string | undefined const userPubkey = userState.user?.pubkey as string | undefined
const [eventProfile, setEventProfile] = useState<UserProfile>() const [eventProfile, setEventProfile] = useState<UserProfile>()
@ -172,7 +173,18 @@ export const Note = ({ ndkEvent }: NoteProps) => {
if (!confirm) return if (!confirm) return
const repostNdkEvent = await ndkEvent.repost(false) 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? // Is this user's repost?

View File

@ -55,9 +55,12 @@ export const NoteSubmit = ({
const handleFormSubmit = async (event: React.FormEvent<HTMLFormElement>) => { const handleFormSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault() event.preventDefault()
const formSubmit = { const formSubmit = {
intent: 'submit',
data: {
content, content,
nsfw nsfw
} }
}
// Reset form // Reset form
setContent('') setContent('')

View File

@ -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 { NDKContextType } from 'contexts/NDKContext'
import { ActionFunctionArgs, redirect } from 'react-router-dom' import { ActionFunctionArgs, redirect } from 'react-router-dom'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { getFeedNotePageRoute } from 'routes' import { getFeedNotePageRoute } from 'routes'
import { store } from 'store' import { store } from 'store'
import { NoteSubmitForm, NoteSubmitFormErrors } from 'types' import { NoteAction, NoteSubmitForm, NoteSubmitFormErrors } from 'types'
import { import {
log, log,
LogType, LogType,
@ -38,15 +38,56 @@ export const feedPostRouteAction =
return null return null
} }
const formSubmit = (await request.json()) as NoteSubmitForm try {
const formErrors = validateFormData(formSubmit) const action = (await request.json()) as NoteAction
switch (action.intent) {
case 'submit':
return await handleActionSubmit(
ndkContext.ndk,
action.data,
hexPubkey
)
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)
toast.error('Failed to publish note')
return null
}
}
const validateFormData = (formSubmit: NoteSubmitForm): NoteSubmitFormErrors => {
const errors: NoteSubmitFormErrors = {}
if (!formSubmit.content.trim()) {
errors.content = 'Content is required'
}
return errors
}
async function handleActionSubmit(
ndk: NDK,
data: NoteSubmitForm,
pubkey: string
) {
const formErrors = validateFormData(data)
if (Object.keys(formErrors).length) return formErrors if (Object.keys(formErrors).length) return formErrors
const content = decodeURIComponent(formSubmit.content!) const content = decodeURIComponent(data.content!)
const currentTimeStamp = now() const currentTimeStamp = now()
const ndkEvent = new NDKEvent(ndkContext.ndk, { const ndkEvent = new NDKEvent(ndk, {
kind: NDKKind.Text, kind: NDKKind.Text,
created_at: currentTimeStamp, created_at: currentTimeStamp,
content: content, content: content,
@ -54,11 +95,11 @@ export const feedPostRouteAction =
['L', 'source'], ['L', 'source'],
['l', window.location.host, 'source'] ['l', window.location.host, 'source']
], ],
pubkey: hexPubkey pubkey
}) })
try { try {
if (formSubmit.nsfw) ndkEvent.tags.push(['L', 'content-warning']) if (data.nsfw) ndkEvent.tags.push(['L', 'content-warning'])
await ndkEvent.sign() await ndkEvent.sign()
const note1 = ndkEvent.encode() const note1 = ndkEvent.encode()
@ -77,13 +118,16 @@ export const feedPostRouteAction =
return null return null
} }
} }
async function handleActionRepost(ndk: NDK, data: NostrEvent, note1: string) {
const ndkEvent = new NDKEvent(ndk, data)
await ndkEvent.sign()
const validateFormData = (formSubmit: NoteSubmitForm): NoteSubmitFormErrors => { const publishedOnRelays = await ndkEvent.publish()
const errors: NoteSubmitFormErrors = {} if (publishedOnRelays.size === 0) {
toast.error('Failed to publish note on any relay')
if (!formSubmit.content.trim()) { return null
errors.content = 'Content is required' } else {
toast.success('Note published successfully')
return redirect(getFeedNotePageRoute(note1))
} }
return errors
} }

View File

@ -1,6 +1,19 @@
import { NostrEvent } from '@nostr-dev-kit/ndk'
export interface NoteSubmitForm { export interface NoteSubmitForm {
content: string content: string
nsfw: boolean nsfw: boolean
} }
export interface NoteSubmitFormErrors extends Partial<NoteSubmitForm> {} export interface NoteSubmitFormErrors extends Partial<NoteSubmitForm> {}
export type NoteAction =
| {
intent: 'submit'
data: NoteSubmitForm
}
| {
intent: 'repost'
note1: string
data: NostrEvent
}