webapp/src/routes/author/[slug]/[...tab].tsx

156 lines
5.1 KiB
TypeScript
Raw Normal View History

2024-07-18 09:22:28 +00:00
import { RouteSectionProps } from '@solidjs/router'
import { ErrorBoundary, createEffect, createMemo, createSignal, on } from 'solid-js'
2024-07-12 12:10:22 +00:00
import { AuthorView } from '~/components/Views/Author'
import { FourOuFourView } from '~/components/Views/FourOuFour'
2024-07-16 00:14:08 +00:00
import { LoadMoreItems, LoadMoreWrapper } from '~/components/_shared/LoadMoreWrapper'
2024-07-12 12:10:22 +00:00
import { PageLayout } from '~/components/_shared/PageLayout'
import { useAuthors } from '~/context/authors'
2024-07-16 00:14:08 +00:00
import { useFeed } from '~/context/feed'
2024-07-12 12:10:22 +00:00
import { useLocalize } from '~/context/localize'
2024-07-16 00:14:08 +00:00
import { ReactionsProvider, useReactions } from '~/context/reactions'
import { loadAuthors, loadReactions, loadShouts, loadTopics } from '~/graphql/api/public'
2024-07-12 12:10:22 +00:00
import {
Author,
LoadShoutsOptions,
QueryLoad_Authors_ByArgs,
2024-07-18 09:22:28 +00:00
QueryLoad_Reactions_ByArgs,
Reaction,
ReactionKind,
2024-07-12 12:10:22 +00:00
Shout,
Topic
} from '~/graphql/schema/core.gen'
2024-07-13 12:25:25 +00:00
import { getImageUrl } from '~/lib/getThumbUrl'
2024-07-13 09:06:49 +00:00
import { SHOUTS_PER_PAGE } from '../../(main)'
2024-07-12 12:10:22 +00:00
const fetchAuthorShouts = async (slug: string, offset?: number) => {
const opts: LoadShoutsOptions = { filters: { author: slug }, limit: SHOUTS_PER_PAGE, offset }
const shoutsLoader = loadShouts(opts)
return await shoutsLoader()
}
2024-07-18 09:22:28 +00:00
const fetchAuthorComments = async (slug: string, offset?: number) => {
const opts: QueryLoad_Reactions_ByArgs = {
by: { comment: true, author: slug },
limit: SHOUTS_PER_PAGE,
offset
}
const shoutsLoader = loadReactions(opts)
return await shoutsLoader()
}
2024-07-12 12:10:22 +00:00
const fetchAllTopics = async () => {
const topicsFetcher = loadTopics()
return await topicsFetcher()
}
const fetchAuthor = async (slug: string) => {
2024-07-13 07:01:41 +00:00
const authorFetcher = loadAuthors({ by: { slug }, limit: 1, offset: 0 } as QueryLoad_Authors_ByArgs)
2024-07-12 12:10:22 +00:00
const aaa = await authorFetcher()
return aaa?.[0]
}
export const route = {
load: async ({ params, location: { query } }: RouteSectionProps<{ articles: Shout[] }>) => {
const offset: number = Number.parseInt(query.offset, 10)
return {
author: await fetchAuthor(params.slug),
2024-07-16 00:14:08 +00:00
shouts: await fetchAuthorShouts(params.slug, offset),
2024-07-12 12:10:22 +00:00
topics: await fetchAllTopics()
}
}
}
2024-07-13 09:06:49 +00:00
export type AuthorPageProps = { articles?: Shout[]; author?: Author; topics?: Topic[] }
2024-07-13 09:45:10 +00:00
export default function AuthorPage(props: RouteSectionProps<AuthorPageProps>) {
2024-07-16 00:14:08 +00:00
const { addAuthor, authorsEntities } = useAuthors()
2024-07-18 09:22:28 +00:00
const [author, setAuthor] = createSignal<Author | undefined>(undefined)
2024-07-16 00:14:08 +00:00
2024-07-12 12:10:22 +00:00
const { t } = useLocalize()
const title = createMemo(() => `${author()?.name || ''}`)
createEffect(() => {
if (author()) {
console.debug('[routes] author/[slug] author loaded fx')
window?.gtag?.('event', 'page_view', {
page_title: author()?.name || '',
page_location: window?.location.href || '',
page_path: window?.location.pathname || ''
})
}
})
const cover = createMemo(() =>
author()?.pic
? getImageUrl(author()?.pic || '', { width: 1200 })
: getImageUrl('production/image/logo_image.png')
)
2024-07-13 07:01:41 +00:00
2024-07-18 09:22:28 +00:00
// author comments
const { addReactions, reactionEntities } = useReactions()
const commentsByAuthor = createMemo(() =>
Object.values(reactionEntities).filter(
(r: Reaction) => r.kind === ReactionKind.Comment && r.created_by.id === author()?.id
)
)
// author shouts
2024-07-16 00:14:08 +00:00
const { addFeed, feedByAuthor } = useFeed()
2024-07-18 09:22:28 +00:00
const shoutsByAuthor = createMemo(() => feedByAuthor()[props.params.slug])
createEffect(
on(
[() => props.params.slug || '', author],
async ([slug, profile]) => {
if (!profile) {
const loadedAuthor = authorsEntities()[slug] || (await fetchAuthor(slug))
if (loadedAuthor) {
addAuthor(loadedAuthor)
setAuthor(loadedAuthor)
}
}
},
{ defer: true }
)
)
const loadAuthorDataMore = async (offset = 0) => {
if (props.params.tab === 'comments') {
const commentsOffset = commentsByAuthor().length
const loadedComments = await fetchAuthorComments(props.params.slug, commentsOffset)
loadedComments && addReactions(loadedComments)
return (loadedComments || []) as LoadMoreItems
}
const shoutsOffset = shoutsByAuthor().length
const loadedShouts = await fetchAuthorShouts(props.params.slug, shoutsOffset)
loadedShouts && addFeed(loadedShouts)
return (loadedShouts || []) as LoadMoreItems
2024-07-16 00:14:08 +00:00
}
2024-07-12 12:10:22 +00:00
return (
<ErrorBoundary fallback={(_err) => <FourOuFourView />}>
2024-07-16 00:14:08 +00:00
<PageLayout
title={`${t('Discours')} :: ${title()}`}
headerTitle={author()?.name || ''}
slug={author()?.slug}
desc={author()?.about || author()?.bio || ''}
cover={cover()}
>
<ReactionsProvider>
<LoadMoreWrapper
2024-07-18 09:22:28 +00:00
loadFunction={loadAuthorDataMore}
2024-07-16 00:14:08 +00:00
pageSize={SHOUTS_PER_PAGE}
2024-07-18 09:22:28 +00:00
hidden={!props.params.tab || props.params.tab !== 'comments'}
2024-07-16 00:14:08 +00:00
>
2024-07-12 12:10:22 +00:00
<AuthorView
author={author() as Author}
2024-07-18 09:22:28 +00:00
selectedTab={props.params.tab}
2024-07-13 09:36:23 +00:00
authorSlug={props.params.slug}
2024-07-18 09:22:28 +00:00
shouts={shoutsByAuthor()}
2024-07-12 12:10:22 +00:00
/>
2024-07-16 00:14:08 +00:00
</LoadMoreWrapper>
</ReactionsProvider>
</PageLayout>
2024-07-12 12:10:22 +00:00
</ErrorBoundary>
)
}