webapp/src/routes/[slug]/(author-or-post).tsx

115 lines
3.7 KiB
TypeScript
Raw Normal View History

2024-07-13 09:36:23 +00:00
import { RouteDefinition, RouteSectionProps, createAsync, useLocation } from '@solidjs/router'
2024-07-13 09:06:49 +00:00
import { HttpStatusCode } from '@solidjs/start'
import {
ErrorBoundary,
Show,
Suspense,
createEffect,
createMemo,
createSignal,
on,
onMount
} from 'solid-js'
import { FourOuFourView } from '~/components/Views/FourOuFour'
import { Loading } from '~/components/_shared/Loading'
import { gaIdentity } from '~/config'
import { useLocalize } from '~/context/localize'
2024-07-13 09:36:23 +00:00
import { getShout } from '~/graphql/api/public'
2024-07-13 09:06:49 +00:00
import type { Author, Reaction, Shout } from '~/graphql/schema/core.gen'
import { initGA, loadGAScript } from '~/utils/ga'
import { descFromBody, keywordsFromTopics } from '~/utils/meta'
import { FullArticle } from '../../components/Article/FullArticle'
import { PageLayout } from '../../components/_shared/PageLayout'
import { ReactionsProvider } from '../../context/reactions'
import AuthorPage, { AuthorPageProps } from '../author/[slug]/[...tab]'
const fetchShout = async (slug: string): Promise<Shout | undefined> => {
const shoutLoader = getShout({ slug })
const result = await shoutLoader()
return result
}
export const route: RouteDefinition = {
load: async ({ params }) => ({
article: await fetchShout(params.slug)
})
}
type SlugPageProps = { article?: Shout; comments?: Reaction[]; votes?: Reaction[]; author?: Author }
export default (props: RouteSectionProps<SlugPageProps>) => {
2024-07-13 09:36:23 +00:00
if (props.params.slug.startsWith('@')) {
console.debug('[slug] @ found, render as author page')
const patchedProps = {
...props,
params: {
...props.params,
slug: props.params.slug.slice(1, props.params.slug.length)
}
} as RouteSectionProps<AuthorPageProps>
return AuthorPage(patchedProps)
}
2024-07-13 09:06:49 +00:00
const loc = useLocation()
const { t } = useLocalize()
const [scrollToComments, setScrollToComments] = createSignal<boolean>(false)
2024-07-13 09:36:23 +00:00
const article = createAsync(async () => props.data.article || (await fetchShout(props.params.slug)))
const titleSuffix = createMemo(() => (article()?.title ? ` :: ${article()?.title || ''}` : ''))
2024-07-13 09:06:49 +00:00
onMount(async () => {
if (gaIdentity && article()?.id) {
try {
await loadGAScript(gaIdentity)
initGA(gaIdentity)
} catch (error) {
console.warn('Failed to connect Google Analytics:', error)
}
}
})
createEffect(
on(
article,
(a?: Shout) => {
if (!a?.id) return
window?.gtag?.('event', 'page_view', {
page_title: a.title,
page_location: window?.location.href || '',
page_path: loc.pathname
})
},
{ defer: true }
)
)
return (
<ErrorBoundary fallback={() => <HttpStatusCode code={500} />}>
<Suspense fallback={<Loading />}>
<Show
when={article()?.id}
fallback={
<PageLayout isHeaderFixed={false} hideFooter={true} title={t('Nothing is here')}>
<FourOuFourView />
<HttpStatusCode code={404} />
</PageLayout>
}
>
2024-07-13 09:36:23 +00:00
<PageLayout
title={`${t('Discours')}${titleSuffix()}`}
desc={descFromBody(article()?.body || '')}
keywords={keywordsFromTopics(article()?.topics as { title: string }[])}
headerTitle={article()?.title || ''}
slug={article()?.slug}
cover={article()?.cover || ''}
scrollToComments={(value) => setScrollToComments(value)}
2024-07-13 09:06:49 +00:00
>
2024-07-13 09:36:23 +00:00
<ReactionsProvider>
<FullArticle article={article() as Shout} scrollToComments={scrollToComments()} />
</ReactionsProvider>
</PageLayout>
2024-07-13 09:06:49 +00:00
</Show>
</Suspense>
</ErrorBoundary>
)
}