108 lines
3.1 KiB
TypeScript
108 lines
3.1 KiB
TypeScript
import {
|
|
RouteDefinition,
|
|
RouteSectionProps,
|
|
createAsync,
|
|
redirect,
|
|
useLocation,
|
|
useParams
|
|
} from '@solidjs/router'
|
|
import { HttpStatusCode } from '@solidjs/start'
|
|
import { ErrorBoundary, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js'
|
|
import { Loading } from '~/components/_shared/Loading'
|
|
import { gaIdentity } from '~/config'
|
|
import { useFeed } from '~/context/feed'
|
|
import { useLocalize } from '~/context/localize'
|
|
import { getShout } from '~/graphql/api/public'
|
|
import type { Shout } from '~/graphql/schema/core.gen'
|
|
import { initGA, loadGAScript } from '~/utils/ga'
|
|
import { FullArticle } from '../components/Article/FullArticle'
|
|
import { PageLayout } from '../components/_shared/PageLayout'
|
|
import { ReactionsProvider } from '../context/reactions'
|
|
|
|
const fetchShout = async (slug: string): Promise<Shout> => {
|
|
const shoutLoader = getShout({ slug })
|
|
const shout = await shoutLoader()
|
|
if (!shout) {
|
|
throw new Error('Shout not found')
|
|
}
|
|
return shout
|
|
}
|
|
|
|
export const route: RouteDefinition = {
|
|
load: async ({ params }) => {
|
|
try {
|
|
return await fetchShout(params.slug)
|
|
} catch (error) {
|
|
console.error('Error loading shout:', error)
|
|
throw new Response(null, {
|
|
status: 404,
|
|
statusText: 'Not Found'
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
export default (props: RouteSectionProps<{ article: Shout }>) => {
|
|
const params = useParams()
|
|
const loc = useLocation()
|
|
const { articleEntities } = useFeed()
|
|
const { t } = useLocalize()
|
|
const [scrollToComments, setScrollToComments] = createSignal<boolean>(false)
|
|
|
|
const article = createAsync(async () => {
|
|
if (params.slug && articleEntities?.()) {
|
|
return articleEntities()?.[params.slug] || props.data.article || (await fetchShout(params.slug))
|
|
}
|
|
throw redirect('/404', { status: 404 })
|
|
})
|
|
|
|
const title = createMemo(
|
|
() => `${article()?.authors?.[0]?.name || t('Discours')} :: ${article()?.title || ''}`
|
|
)
|
|
|
|
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) 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={404} />}>
|
|
<Show when={article()?.id} fallback={<Loading />}>
|
|
<PageLayout
|
|
title={title()}
|
|
headerTitle={article()?.title || ''}
|
|
slug={article()?.slug}
|
|
articleBody={article()?.body}
|
|
cover={article()?.cover || ''}
|
|
scrollToComments={(value) => setScrollToComments(value)}
|
|
>
|
|
<ReactionsProvider>
|
|
<FullArticle article={article() as Shout} scrollToComments={scrollToComments()} />
|
|
</ReactionsProvider>
|
|
</PageLayout>
|
|
</Show>
|
|
</ErrorBoundary>
|
|
)
|
|
}
|