feat(feed): add feed outlet, note action and types
This commit is contained in:
parent
eb27eabcc6
commit
27cd22f47b
85
src/pages/feed/action.ts
Normal file
85
src/pages/feed/action.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { NDKEvent, NDKKind } 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 { log, LogType, now } from 'utils'
|
||||||
|
|
||||||
|
export const feedPostRouteAction =
|
||||||
|
(ndkContext: NDKContextType) =>
|
||||||
|
async ({ request }: ActionFunctionArgs) => {
|
||||||
|
const userState = store.getState().user
|
||||||
|
let hexPubkey: string
|
||||||
|
if (userState.auth && userState.user?.pubkey) {
|
||||||
|
hexPubkey = userState.user.pubkey as string
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
hexPubkey = (await window.nostr?.getPublicKey()) as string
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
log(true, LogType.Error, 'Failed to get public key.', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.error('Failed to get public key.')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hexPubkey) {
|
||||||
|
toast.error('Could not get pubkey')
|
||||||
|
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: [],
|
||||||
|
pubkey: hexPubkey
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ndkEvent.generateTags()
|
||||||
|
|
||||||
|
if (formSubmit.nsfw) ndkEvent.tags.push(['L', 'content-warning'])
|
||||||
|
|
||||||
|
ndkEvent.tags.push(['L', 'source'])
|
||||||
|
ndkEvent.tags.push(['l', window.location.host, 'source'])
|
||||||
|
ndkEvent.tags.push(['client', 'DEG Mods'])
|
||||||
|
|
||||||
|
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')
|
||||||
|
return redirect(getFeedNotePageRoute(note1))
|
||||||
|
}
|
||||||
|
} 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
|
||||||
|
}
|
@ -4,9 +4,12 @@ import { FeedTabBlogs } from './FeedTabBlogs'
|
|||||||
import { FeedTabMods } from './FeedTabMods'
|
import { FeedTabMods } from './FeedTabMods'
|
||||||
import { FeedTabPosts } from './FeedTabPosts'
|
import { FeedTabPosts } from './FeedTabPosts'
|
||||||
import { FeedFilter } from 'components/Filters/FeedFilter'
|
import { FeedFilter } from 'components/Filters/FeedFilter'
|
||||||
|
import { Outlet, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
export const FeedPage = () => {
|
export const FeedPage = () => {
|
||||||
const [tab, setTab] = useState(0)
|
const { note } = useParams()
|
||||||
|
// Open posts tab if note is present
|
||||||
|
const [tab, setTab] = useState(note ? 2 : 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -17,6 +20,8 @@ export const FeedPage = () => {
|
|||||||
{tab === 0 && <FeedTabMods />}
|
{tab === 0 && <FeedTabMods />}
|
||||||
{tab === 1 && <FeedTabBlogs />}
|
{tab === 1 && <FeedTabBlogs />}
|
||||||
{tab === 2 && <FeedTabPosts />}
|
{tab === 2 && <FeedTabPosts />}
|
||||||
|
|
||||||
|
<Outlet key={note} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import { BackupPage } from 'pages/backup'
|
|||||||
import { SupportersPage } from 'pages/supporters'
|
import { SupportersPage } from 'pages/supporters'
|
||||||
import { commentsLoader } from 'loaders/comment'
|
import { commentsLoader } from 'loaders/comment'
|
||||||
import { CommentsPopup } from 'components/comment/CommentsPopup'
|
import { CommentsPopup } from 'components/comment/CommentsPopup'
|
||||||
|
import { feedPostRouteAction } from 'pages/feed/action'
|
||||||
|
|
||||||
export const appRoutes = {
|
export const appRoutes = {
|
||||||
home: '/',
|
home: '/',
|
||||||
@ -56,6 +57,7 @@ export const appRoutes = {
|
|||||||
settingsAdmin: '/settings-admin',
|
settingsAdmin: '/settings-admin',
|
||||||
profile: '/profile/:nprofile?',
|
profile: '/profile/:nprofile?',
|
||||||
feed: '/feed',
|
feed: '/feed',
|
||||||
|
note: '/feed/:note',
|
||||||
notifications: '/notifications',
|
notifications: '/notifications',
|
||||||
backup: '/backup',
|
backup: '/backup',
|
||||||
supporters: '/supporters'
|
supporters: '/supporters'
|
||||||
@ -76,6 +78,9 @@ export const getBlogPageRoute = (eventId: string) =>
|
|||||||
export const getProfilePageRoute = (nprofile: string) =>
|
export const getProfilePageRoute = (nprofile: string) =>
|
||||||
appRoutes.profile.replace(':nprofile', nprofile)
|
appRoutes.profile.replace(':nprofile', nprofile)
|
||||||
|
|
||||||
|
export const getFeedNotePageRoute = (note: string) =>
|
||||||
|
appRoutes.note.replace(':note', note)
|
||||||
|
|
||||||
export const routerWithNdkContext = (context: NDKContextType) =>
|
export const routerWithNdkContext = (context: NDKContextType) =>
|
||||||
createBrowserRouter([
|
createBrowserRouter([
|
||||||
{
|
{
|
||||||
@ -199,7 +204,15 @@ export const routerWithNdkContext = (context: NDKContextType) =>
|
|||||||
{
|
{
|
||||||
path: appRoutes.feed,
|
path: appRoutes.feed,
|
||||||
element: <FeedPage />,
|
element: <FeedPage />,
|
||||||
loader: feedPageLoader(context)
|
loader: feedPageLoader(context),
|
||||||
|
action: feedPostRouteAction(context),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: ':note',
|
||||||
|
element: <CommentsPopup />,
|
||||||
|
loader: commentsLoader(context)
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: appRoutes.notifications,
|
path: appRoutes.notifications,
|
||||||
|
@ -8,3 +8,4 @@ export * from './category'
|
|||||||
export * from './popup'
|
export * from './popup'
|
||||||
export * from './errors'
|
export * from './errors'
|
||||||
export * from './comments'
|
export * from './comments'
|
||||||
|
export * from './note'
|
||||||
|
6
src/types/note.ts
Normal file
6
src/types/note.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export interface NoteSubmitForm {
|
||||||
|
content: string
|
||||||
|
nsfw: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoteSubmitFormErrors extends Partial<NoteSubmitForm> {}
|
Loading…
x
Reference in New Issue
Block a user