116 lines
3.7 KiB
TypeScript
Raw Normal View History

import { filterForEventsTaggingId, NDKFilter } from '@nostr-dev-kit/ndk'
2024-10-31 20:14:29 +01:00
import { NDKContextType } from 'contexts/NDKContext'
import { kinds, nip19 } from 'nostr-tools'
2024-10-31 20:14:29 +01:00
import { LoaderFunctionArgs, redirect } from 'react-router-dom'
import { toast } from 'react-toastify'
import { appRoutes } from 'routes'
import { BlogPageLoaderResult, FilterOptions, NSFWFilter } from 'types'
import {
DEFAULT_FILTER_OPTIONS,
getLocalStorageItem,
log,
LogType
} from 'utils'
import { extractBlogCardDetails, extractBlogDetails } from 'utils/blog'
2024-10-31 20:14:29 +01:00
export const blogRouteLoader =
(ndkContext: NDKContextType) =>
async ({ params }: LoaderFunctionArgs) => {
const { naddr } = params
if (!naddr) {
log(true, LogType.Error, 'Required naddr.')
return redirect(appRoutes.blogs)
}
// Decode author from naddr
const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`)
const { pubkey } = decoded.data
2024-10-31 20:14:29 +01:00
try {
// Get the filter with #a from naddr for the main blog content
2024-10-31 20:14:29 +01:00
const filter = filterForEventsTaggingId(naddr)
if (!filter) {
log(true, LogType.Error, 'Unable to create filter from blog naddr.')
return redirect(appRoutes.blogs)
}
2024-11-05 16:22:08 +01:00
// Get the blog filter options for latest blogs
const filterOptions = JSON.parse(
getLocalStorageItem('filter-blog', DEFAULT_FILTER_OPTIONS)
) as FilterOptions
// Fetch 4 in case the current blog is included in the latest
const latestModsFilter: NDKFilter = {
authors: [pubkey],
kinds: [kinds.LongFormArticle],
limit: 4
}
// Add source filter
if (filterOptions.source === window.location.host) {
latestModsFilter['#r'] = [filterOptions.source]
}
// Filter by NSFW tag
// NSFWFilter.Show_NSFW -> filter not needed
// NSFWFilter.Only_NSFW -> true
// NSFWFilter.Hide_NSFW -> false
if (filterOptions.nsfw !== NSFWFilter.Show_NSFW) {
latestModsFilter['#nsfw'] = [
(filterOptions.nsfw === NSFWFilter.Only_NSFW).toString()
]
}
// Parallel fetch blog event and latest events
const settled = await Promise.allSettled([
ndkContext.fetchEvent(filter),
ndkContext.fetchEvents(latestModsFilter)
])
const result: BlogPageLoaderResult = {
blog: undefined,
latest: []
}
// Check the blog event result
const fetchEventResult = settled[0]
if (fetchEventResult.status === 'fulfilled' && fetchEventResult.value) {
// Extract the blog details from the event
result.blog = extractBlogDetails(fetchEventResult.value)
} else if (fetchEventResult.status === 'rejected') {
log(
true,
LogType.Error,
'Unable to fetch the blog event.',
fetchEventResult.reason
)
}
// Check the lateast blog events
const fetchEventsResult = settled[1]
if (fetchEventsResult.status === 'fulfilled' && fetchEventsResult.value) {
// Extract the blog card details from the events
result.latest = fetchEventsResult.value
.map(extractBlogCardDetails)
.filter((b) => b.id !== result.blog?.id) // Filter out current blog if present
.slice(0, 3) // Take only three
} else if (fetchEventsResult.status === 'rejected') {
log(
true,
LogType.Error,
'Unable to fetch the latest blog events.',
fetchEventsResult.reason
)
2024-10-31 20:14:29 +01:00
}
return result
2024-10-31 20:14:29 +01:00
} catch (error) {
log(
true,
LogType.Error,
'An error occurred in fetching blog details from relays',
error
)
toast.error('An error occurred in fetching blog details from relays')
2024-10-31 20:14:29 +01:00
return redirect(appRoutes.blogs)
}
}