From f30ac01ea649296d92663ce753d4918914cab022 Mon Sep 17 00:00:00 2001 From: enes Date: Wed, 6 Nov 2024 13:17:13 +0100 Subject: [PATCH] refactor(blog): re-render body, latest and filtering --- src/pages/blog/index.tsx | 98 +++++++++++++++++++--------------------- src/pages/blog/loader.ts | 90 ++++++++++++++++++++++++++++++++---- src/types/blog.ts | 5 ++ 3 files changed, 132 insertions(+), 61 deletions(-) diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx index 46becf8..7fb5814 100644 --- a/src/pages/blog/index.tsx +++ b/src/pages/blog/index.tsx @@ -9,37 +9,41 @@ import { marked } from 'marked' import { LoadingSpinner } from 'components/LoadingSpinner' import { ProfileSection } from 'components/ProfileSection' import { Comments } from 'components/comment' -import { Addressable, BlogDetails } from 'types' +import { Addressable, BlogPageLoaderResult } from 'types' import placeholder from '../../assets/img/DEGMods Placeholder Img.png' import { PublishDetails } from 'components/Internal/PublishDetails' import { Interactions } from 'components/Internal/Interactions' +import { BlogCard } from 'components/BlogCard' export const BlogPage = () => { - const data = useLoaderData() as Partial + const { blog, latest } = useLoaderData() as BlogPageLoaderResult const [commentCount, setCommentCount] = useState(0) - const html = marked.parse(data?.content || '', { async: false }) + const html = marked.parse(blog?.content || '', { async: false }) const sanitized = DOMPurify.sanitize(html) - const editor = useEditor({ - content: sanitized, - extensions: [ - StarterKit, - Link, - Image.configure({ - inline: true, - HTMLAttributes: { - class: 'IBMSMSMBSSPostImg' - } - }) - ], - editable: false - }) + const editor = useEditor( + { + content: sanitized, + extensions: [ + StarterKit, + Link, + Image.configure({ + inline: true, + HTMLAttributes: { + class: 'IBMSMSMBSSPostImg' + } + }) + ], + editable: false + }, + [sanitized] + ) return (
- {!data ? ( + {!blog ? ( ) : (
@@ -67,27 +71,27 @@ export const BlogPage = () => { className='IBMSMSMBSSPostPicture' style={{ background: `url("${ - data.image !== '' ? data.image : placeholder + blog.image !== '' ? blog.image : placeholder }") center / cover no-repeat` }} >

- {data.title} + {blog.title}

- {data.nsfw && ( + {blog.nsfw && (

NSFW

)} - {data.tTags && - data.tTags.map((t) => ( + {blog.tTags && + blog.tTags.map((t) => ( {t} @@ -96,48 +100,38 @@ export const BlogPage = () => {
- {/*
)} - {!!data?.author && } + {!!blog?.author && }
diff --git a/src/pages/blog/loader.ts b/src/pages/blog/loader.ts index f4313c7..e74c68e 100644 --- a/src/pages/blog/loader.ts +++ b/src/pages/blog/loader.ts @@ -1,10 +1,17 @@ -import { filterForEventsTaggingId } from '@nostr-dev-kit/ndk' +import { filterForEventsTaggingId, NDKFilter } from '@nostr-dev-kit/ndk' import { NDKContextType } from 'contexts/NDKContext' +import { kinds, nip19 } from 'nostr-tools' import { LoaderFunctionArgs, redirect } from 'react-router-dom' import { toast } from 'react-toastify' import { appRoutes } from 'routes' -import { log, LogType } from 'utils' -import { extractBlogDetails } from 'utils/blog' +import { BlogPageLoaderResult, FilterOptions, NSFWFilter } from 'types' +import { + DEFAULT_FILTER_OPTIONS, + getLocalStorageItem, + log, + LogType +} from 'utils' +import { extractBlogCardDetails, extractBlogDetails } from 'utils/blog' export const blogRouteLoader = (ndkContext: NDKContextType) => @@ -15,21 +22,86 @@ export const blogRouteLoader = return redirect(appRoutes.blogs) } + // Decode author from naddr + const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`) + const { pubkey } = decoded.data + try { + // Get the filter with #a from naddr for the main blog content const filter = filterForEventsTaggingId(naddr) if (!filter) { log(true, LogType.Error, 'Unable to create filter from blog naddr.') return redirect(appRoutes.blogs) } - const event = await ndkContext.fetchEvent(filter) - if (!event) { - log(true, LogType.Error, 'Unable to fetch the blog event.') - return null + // 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() + ] } - const blogDetails = extractBlogDetails(event) - return blogDetails + // 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 + ) + } + + return result } catch (error) { log( true, diff --git a/src/types/blog.ts b/src/types/blog.ts index 051c153..6e5b8b8 100644 --- a/src/types/blog.ts +++ b/src/types/blog.ts @@ -27,3 +27,8 @@ export interface BlogFormErrors extends Partial {} export interface BlogCardDetails extends BlogDetails { naddr: string } + +export interface BlogPageLoaderResult { + blog: Partial | undefined + latest: Partial[] +}