From 343b71defd02bbe999cb0847779d93e1ef3d5711 Mon Sep 17 00:00:00 2001 From: dufok Date: Tue, 24 Sep 2024 00:40:57 -0300 Subject: [PATCH] feat: renamed ArticalPage to component, added useParam for slug and reactivity --- src/routes/[slug]/[...tab].tsx | 177 ++++++++++++++++++++------------- 1 file changed, 108 insertions(+), 69 deletions(-) diff --git a/src/routes/[slug]/[...tab].tsx b/src/routes/[slug]/[...tab].tsx index ef9fc842..a0d63feb 100644 --- a/src/routes/[slug]/[...tab].tsx +++ b/src/routes/[slug]/[...tab].tsx @@ -1,6 +1,32 @@ -import { RouteDefinition, RouteSectionProps, createAsync, useLocation } from '@solidjs/router' +/** + * [slug].tsx + * + * # Dynamic Slug Route Handler + * + * ## Overview + * + * This file handles dynamic routing based on the `slug` parameter in the URL. Depending on the prefix of the slug, it renders different pages: + * + * - **Author Page**: If the `slug` starts with `@`, it renders the `AuthorPage` component for the specified author. + * - **Topic Page**: If the `slug` starts with `!`, it renders the `TopicPage` component for the specified topic. + * - **Article Page**: For all other slugs, it renders the `ArticlePageComponent`, displaying the full article details. + * + * ## Components + * + * - **SlugPage**: The main component that determines which page to render based on the `slug`. + * - **ArticlePageComponent**: Fetches and displays the detailed view of an article. + * - **AuthorPage**: Displays author-specific information (imported from `../author/[slug]/[...tab]`). + * - **TopicPage**: Displays topic-specific information (imported from `../topic/[slug]/[...tab]`). + * + * ## Data Fetching + * + * - **fetchShout**: Asynchronously fetches article data based on the `slug` using the `getShout` GraphQL query. + * - **createResource**: Utilized in `ArticlePageComponent` to fetch and manage article data reactively.**/ + + +import { RouteDefinition, RouteSectionProps, useLocation, useParams } from '@solidjs/router' import { HttpStatusCode } from '@solidjs/start' -import { ErrorBoundary, Show, Suspense, createEffect, on, onMount } from 'solid-js' +import { ErrorBoundary, Show, Suspense, createEffect, on, onMount, createResource } from 'solid-js' import { FourOuFourView } from '~/components/Views/FourOuFour' import { Loading } from '~/components/_shared/Loading' import { gaIdentity } from '~/config' @@ -16,7 +42,7 @@ import AuthorPage, { AuthorPageProps } from '../author/[slug]/[...tab]' import TopicPage, { TopicPageProps } from '../topic/[slug]/[...tab]' const fetchShout = async (slug: string): Promise => { - if (slug.startsWith('@')) return + if (slug.startsWith('@') || slug.startsWith('!')) return const shoutLoader = getShout({ slug }) const result = await shoutLoader() return result @@ -43,90 +69,103 @@ export type SlugPageProps = { topics: Topic[] } -export default function ArticlePage(props: RouteSectionProps) { - if (props.params.slug.startsWith('@')) { +export default function SlugPage(props: RouteSectionProps) { + const { t } = useLocalize() + const loc = useLocation() + + const params = useParams() + const slug = createMemo(() => params.slug) + + if (slug.startsWith('@')) { console.debug('[routes] [slug]/[...tab] starts with @, render as author page') const patchedProps = { ...props, params: { ...props.params, - slug: props.params.slug.slice(1, props.params.slug.length) + slug: slug.slice(1) } } as RouteSectionProps return } - if (props.params.slug.startsWith('!')) { + if (slug.startsWith('!')) { console.debug('[routes] [slug]/[...tab] starts with !, render as topic page') const patchedProps = { ...props, params: { ...props.params, - slug: props.params.slug.slice(1, props.params.slug.length) + slug: slug.slice(1) } } as RouteSectionProps return } - function ArticlePage(props: RouteSectionProps) { - const loc = useLocation() - const { t } = useLocalize() - const data = createAsync(async () => props.data?.article || (await fetchShout(props.params.slug))) - - onMount(async () => { - if (gaIdentity && data()?.id) { - try { - await loadGAScript(gaIdentity) - initGA(gaIdentity) - } catch (error) { - console.warn('[routes] [slug]/[...tab] Failed to connect Google Analytics:', error) - } - } - }) - - createEffect( - on( - data, - (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 ( - }> - }> - - - - - } - > - - - - - - - - - ) - } - return + // Pass slug as a prop to ArticlePageComponent + return +} + +function ArticlePageComponent(props: RouteSectionProps & { slug: string }) { + const loc = useLocation() + const { t } = useLocalize() + const { slug } = props + + // Define the fetcher function + const fetchArticle = async (slug: string): Promise => { + return await fetchShout(slug) + } + + // Create a resource that fetches the article based on slug + const [article, { refetch, mutate }] = createResource(slug, fetchArticle) + + // Handle Google Analytics + createEffect(() => { + const currentArticle = article() + if (gaIdentity && currentArticle?.id) { + loadGAScript(gaIdentity) + .then(() => initGA(gaIdentity)) + .catch((error) => { + console.warn('[routes] [slug]/[...tab] Failed to connect Google Analytics:', error) + }) + } + }) + + createEffect(() => { + const currentArticle = article() + if (currentArticle?.id) { + window?.gtag?.('event', 'page_view', { + page_title: currentArticle.title, + page_location: window?.location.href || '', + page_path: loc.pathname + }) + } + }) + + return ( + }> + }> + + + + + } + > + + + + + + + + + ) }