From de7d5066dbd21d98dbd39d503ba32a36119db33e Mon Sep 17 00:00:00 2001 From: tromesh Date: Thu, 20 Feb 2025 16:17:16 +0100 Subject: [PATCH 1/2] Refactor index file to handle templates and split queries --- .../experience.graphql.ts | 23 +++---- .../{ => blankexperience}/experience.style.ts | 0 .../experience.template.tsx | 47 ++++++++++++--- .../base/page/justpage/justpage.graphql.tsx | 31 ++++++++++ .../base/page/justpage/justpage.template.tsx | 60 +++++++++++++++++++ .../base/page/justpage/justpages.styles.ts | 0 .../base/page/newabout/newabout.graphql.tsx | 30 ++++++++++ .../base/page/newabout/newabout.styles.ts | 0 .../base/page/newabout/newabout.template.tsx | 55 +++++++++++++++++ .../base/templates/metadata.graphql.ts | 17 ++++++ .../base/templates/template.factory.tsx | 32 ++++++++++ .../layout/header/header.graphql.ts | 6 +- src/pages/[[...slug]]/index.tsx | 38 ++++++------ src/pages/_app.tsx | 9 ++- src/pages/preview/index.tsx | 8 ++- 15 files changed, 308 insertions(+), 48 deletions(-) rename src/components/base/experience/{ => blankexperience}/experience.graphql.ts (63%) rename src/components/base/experience/{ => blankexperience}/experience.style.ts (100%) rename src/components/base/experience/{ => blankexperience}/experience.template.tsx (66%) create mode 100644 src/components/base/page/justpage/justpage.graphql.tsx create mode 100644 src/components/base/page/justpage/justpage.template.tsx create mode 100644 src/components/base/page/justpage/justpages.styles.ts create mode 100644 src/components/base/page/newabout/newabout.graphql.tsx create mode 100644 src/components/base/page/newabout/newabout.styles.ts create mode 100644 src/components/base/page/newabout/newabout.template.tsx create mode 100644 src/components/base/templates/metadata.graphql.ts create mode 100644 src/components/base/templates/template.factory.tsx diff --git a/src/components/base/experience/experience.graphql.ts b/src/components/base/experience/blankexperience/experience.graphql.ts similarity index 63% rename from src/components/base/experience/experience.graphql.ts rename to src/components/base/experience/blankexperience/experience.graphql.ts index 7be6c68..c828c17 100644 --- a/src/components/base/experience/experience.graphql.ts +++ b/src/components/base/experience/blankexperience/experience.graphql.ts @@ -1,8 +1,14 @@ import { graphql } from "@generated/graphql/gql"; export const ExperienceQuery = graphql(/* GraphQL */ ` - query GetExperience($key: String, $version: String, $locale: String, $url: String, $status: String) { - content: _Experience( + query GetExperience( + $key: String + $version: String + $locale: String + $url: String + $status: String + ) { + content: BlankExperience( where: { _metadata: { url: { default: { eq: $url } } @@ -14,19 +20,6 @@ export const ExperienceQuery = graphql(/* GraphQL */ ` } ) { items { - metadata: _metadata { - key - version - locale - displayName - url { - default - } - published - status - created - lastModified - } composition { key displayName diff --git a/src/components/base/experience/experience.style.ts b/src/components/base/experience/blankexperience/experience.style.ts similarity index 100% rename from src/components/base/experience/experience.style.ts rename to src/components/base/experience/blankexperience/experience.style.ts diff --git a/src/components/base/experience/experience.template.tsx b/src/components/base/experience/blankexperience/experience.template.tsx similarity index 66% rename from src/components/base/experience/experience.template.tsx rename to src/components/base/experience/blankexperience/experience.template.tsx index b750640..b2c9877 100644 --- a/src/components/base/experience/experience.template.tsx +++ b/src/components/base/experience/blankexperience/experience.template.tsx @@ -1,8 +1,11 @@ import { useQuery } from "@apollo/client"; -import { CompositionDisplaySetting, SectionNodeFragment } from "@generated/graphql"; +import { + CompositionDisplaySetting, + SectionNodeFragment, +} from "@generated/graphql"; import { useContentSaved } from "@hooks"; import { useEffect, useMemo } from "react"; -import { SectionTemplate } from "../section/section.template"; +import { SectionTemplate } from "../../section/section.template"; import { ExperienceQuery } from "./experience.graphql"; import { GetExperienceStyles } from "./experience.style"; import { useGlobalContext } from "@context"; @@ -15,9 +18,20 @@ interface ExperienceTemplateProps { url?: string | null; // Matched against the URL.Default } -export const ExperienceTemplate: React.FC = ({ contentGuid, version, locale, url }) => { +export const ExperienceTemplate: React.FC = ({ + contentGuid, + version, + locale, + url, +}) => { const { setIsLoading } = useGlobalContext(); - const queryVariables = { key: contentGuid, version, locale, url, status: url ? "Published" : undefined }; + const queryVariables = { + key: contentGuid, + version, + locale, + url, + status: url ? "Published" : undefined, + }; const { data, refetch, error, loading } = useQuery(ExperienceQuery, { variables: queryVariables, @@ -27,7 +41,11 @@ export const ExperienceTemplate: React.FC = ({ contentG // refetch(queryVariables); }, onCompleted: (data) => { - console.log("[QUERY] Query finished with variables", queryVariables, data); + console.log( + "[QUERY] Query finished with variables", + queryVariables, + data + ); setIsLoading(false); }, }); @@ -56,10 +74,15 @@ export const ExperienceTemplate: React.FC = ({ contentG } }, [loading]); - const sections = useMemo(() => experience?.composition?.sections ?? [], [experience]); + const sections = useMemo( + () => experience?.composition?.sections ?? [], + [experience] + ); const classes = useMemo(() => { - return GetExperienceStyles(experience?.composition?.displaySettings as CompositionDisplaySetting[]); + return GetExperienceStyles( + experience?.composition?.displaySettings as CompositionDisplaySetting[] + ); }, [experience]); if (error) { @@ -72,7 +95,15 @@ export const ExperienceTemplate: React.FC = ({ contentG return (
- {sections.map((section) => section && )} + {sections.map( + (section) => + section && ( + + ) + )}
); }; diff --git a/src/components/base/page/justpage/justpage.graphql.tsx b/src/components/base/page/justpage/justpage.graphql.tsx new file mode 100644 index 0000000..e13a186 --- /dev/null +++ b/src/components/base/page/justpage/justpage.graphql.tsx @@ -0,0 +1,31 @@ +import { graphql } from "@generated/graphql/gql"; + +export const JustPageQuery = graphql(/* GraphQL */ ` + query GetJustPage( + $key: String + $version: String + $locale: String + $url: String + $status: String + ) { + content: JustPage( + where: { + _metadata: { + url: { default: { eq: $url } } + status: { eq: $status } + key: { eq: $key } + version: { eq: $version } + locale: { eq: $locale } + } + } + ) { + items { + Block { + Text { + json + } + } + } + } + } +`); diff --git a/src/components/base/page/justpage/justpage.template.tsx b/src/components/base/page/justpage/justpage.template.tsx new file mode 100644 index 0000000..508605e --- /dev/null +++ b/src/components/base/page/justpage/justpage.template.tsx @@ -0,0 +1,60 @@ +import { useQuery } from "@apollo/client"; +import { useGlobalContext } from "@context"; +import { JustPageQuery } from "./justpage.graphql"; + +export interface JustPageTemplateProps { + contentGuid?: string | null; // Content GUID + version?: string | null; // Optional version + locale?: string | null; // Optional locale + // Or queried by just URL + url?: string | null; // Matched against the URL.Default +} + +interface Node { + text?: string; + children?: Node[]; +} + +function extractText(node: Node): string { + if (!node) return ""; + + if (typeof node.text === "string" && node.text !== " ") return node.text; + + if (Array.isArray(node.children)) { + return node.children.reduce((acc, child) => acc + extractText(child), ""); + } + + return ""; +} + +export const JustPageTemplate: React.FC = ({ + url, + contentGuid, +}) => { + const { setIsLoading } = useGlobalContext(); + const { data, refetch, error, loading } = useQuery(JustPageQuery, { + variables: { url, key: contentGuid }, + notifyOnNetworkStatusChange: true, + onError: (error) => { + console.error("[QUERY] Error fetching Experience", error); + // refetch(queryVariables); + }, + onCompleted: (data) => { + console.log("[QUERY] Query finished with variables", {}, data); + setIsLoading(false); + }, + }); + + const paragraph = + extractText(data?.content?.items?.[0]?.Block?.Text?.json) || ""; + + return ( +
+
+
+

{paragraph}

+
+
+
+ ); +}; diff --git a/src/components/base/page/justpage/justpages.styles.ts b/src/components/base/page/justpage/justpages.styles.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/components/base/page/newabout/newabout.graphql.tsx b/src/components/base/page/newabout/newabout.graphql.tsx new file mode 100644 index 0000000..1fabb31 --- /dev/null +++ b/src/components/base/page/newabout/newabout.graphql.tsx @@ -0,0 +1,30 @@ +import { graphql } from "@generated/graphql/gql"; + +export const NewAboutQuery = graphql(/* GraphQL */ ` + query GetNewAboutPage( + $key: String + $version: String + $locale: String + $url: String + $status: String + ) { + content: BlankPage( + where: { + _metadata: { + url: { default: { eq: $url } } + status: { eq: $status } + key: { eq: $key } + version: { eq: $version } + locale: { eq: $locale } + } + } + ) { + items { + Title + Block { + Heading + } + } + } + } +`); diff --git a/src/components/base/page/newabout/newabout.styles.ts b/src/components/base/page/newabout/newabout.styles.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/components/base/page/newabout/newabout.template.tsx b/src/components/base/page/newabout/newabout.template.tsx new file mode 100644 index 0000000..ef34846 --- /dev/null +++ b/src/components/base/page/newabout/newabout.template.tsx @@ -0,0 +1,55 @@ +import { useQuery } from "@apollo/client"; +import { useGlobalContext } from "@context"; +import { NewAboutQuery } from "./newabout.graphql"; +import { ElementTemplate } from "@components/base/element/element.template"; +import { ElementNodeFragment } from "@generated/graphql"; + +export interface NewAboutTemplateProps { + contentGuid?: string | null; // Content GUID + version?: string | null; // Optional version + locale?: string | null; // Optional locale + // Or queried by just URL + url?: string | null; // Matched against the URL.Default +} + +export const NewAboutTemplate: React.FC = ({ + url, + contentGuid, +}) => { + const { setIsLoading } = useGlobalContext(); + + const { data, refetch, error, loading } = useQuery(NewAboutQuery, { + variables: { url, key: contentGuid }, + notifyOnNetworkStatusChange: true, + onError: (error) => { + console.error("[QUERY] Error fetching Experience", error); + // refetch(queryVariables); + }, + onCompleted: (data) => { + console.log("[QUERY] Query finished with variables", {}, data); + setIsLoading(false); + }, + }); + + const title = data?.content?.items?.[0]?.Title || "No Title"; + const heading = data?.content?.items?.[0]?.Block?.Heading || "No Heading"; + + return ( +
+
+
+ {/* + */} +

{title}

+

{heading}

+
+
+
+ ); +}; diff --git a/src/components/base/templates/metadata.graphql.ts b/src/components/base/templates/metadata.graphql.ts new file mode 100644 index 0000000..06ed873 --- /dev/null +++ b/src/components/base/templates/metadata.graphql.ts @@ -0,0 +1,17 @@ +import { graphql } from "@generated/graphql/gql"; + +export const MetadataQuery = graphql(/* GraphQL */ ` + query GetPageMetaData($url: String) { + content: _Content( + where: { _metadata: { url: { default: { eq: $url } } } } + ) { + items { + _metadata { + displayName + key + types + } + } + } + } +`); diff --git a/src/components/base/templates/template.factory.tsx b/src/components/base/templates/template.factory.tsx new file mode 100644 index 0000000..44871b9 --- /dev/null +++ b/src/components/base/templates/template.factory.tsx @@ -0,0 +1,32 @@ +import { useQuery } from "@apollo/client"; +import { MetadataQuery } from "./metadata.graphql"; +import { ExperienceTemplate } from "../experience/blankexperience/experience.template"; +import { NewAboutTemplate } from "../page/newabout/newabout.template"; +import { JustPageTemplate } from "../page/justpage/justpage.template"; + +const TemplateFactory = ({ url }: { url: string }) => { + const { data: metadata } = useQuery(MetadataQuery, { + skip: !url, + variables: { url }, + notifyOnNetworkStatusChange: true, + onError: (error) => console.error("GraphQL Error:", error), + }); + + const type = + metadata?.content?.items?.[0]?._metadata?.types?.[0] ?? "default"; + + const contentGuid = metadata?.content?.items?.[0]?._metadata?.key; + + switch (type) { + case "BlankExperience": + return ; + case "JustPage": + return ; + case "BlankPage": + return ; + default: + return ; + } +}; + +export default TemplateFactory; diff --git a/src/components/layout/header/header.graphql.ts b/src/components/layout/header/header.graphql.ts index 3fdfb79..0e3f82c 100644 --- a/src/components/layout/header/header.graphql.ts +++ b/src/components/layout/header/header.graphql.ts @@ -3,8 +3,10 @@ import { graphql } from "@generated/graphql/gql"; export const NavigationItemsQuery = graphql(/* GraphQL */ ` query GetNavigationLinks($status: String! = "Published", $host: String) { content: _Page( - where: { _metadata: { status: { eq: $status }, url: { base: { eq: $host } } } } - limit: 5 + where: { + _metadata: { status: { eq: $status }, url: { base: { eq: $host } } } + } + limit: 8 orderBy: { _metadata: { created: ASC } } ) { items { diff --git a/src/pages/[[...slug]]/index.tsx b/src/pages/[[...slug]]/index.tsx index e497cc2..437ac41 100644 --- a/src/pages/[[...slug]]/index.tsx +++ b/src/pages/[[...slug]]/index.tsx @@ -1,29 +1,27 @@ import { CMSUrlProps } from "@helpers/cms/parsers"; import { useParams } from "next/navigation"; -import { useEffect, useState } from "react"; -import { ExperienceTemplate } from "../../components/base/experience/experience.template"; +import { useMemo } from "react"; +import TemplateFactory from "@components/base/templates/template.factory"; -export default function Home() { - const params = useParams(); - const [urlProps, setUrlProps] = useState(); - - useEffect(() => { - let url = "/"; - const slug = params?.slug; - if (slug) { - if (Array.isArray(slug)) { - url = `/${slug.join("/")}/`; - } else { - url = slug.startsWith("/") ? slug : `/${slug}/`; - } - } +const getUrlFromParams = (slug: string | string[] | undefined) => { + if (!slug) return "/"; + if (Array.isArray(slug)) { + return `/${slug.join("/")}/`; + } + return slug.startsWith("/") ? slug : `/${slug}/`; +}; - setUrlProps({ url }); - }, [params]); +export default function Home() { + const { slug } = useParams() ?? {}; + const url = useMemo(() => getUrlFromParams(slug), [slug]); - if (!urlProps?.url) { + if (!url) { return <>Expected some URL data.; } - return
{urlProps && }
; + return ( +
+ +
+ ); } diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 7fad807..a410e16 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -6,6 +6,7 @@ import { GlobalProvider, useGlobalContext } from "@context"; import type { AppProps } from "next/app"; import Script from "next/script"; import { client } from "../client"; +import { useReportWebVitals } from "next/web-vitals"; import "../styles/globals.css"; const Main: React.FC = ({ Component, pageProps }) => { @@ -21,10 +22,16 @@ const Main: React.FC = ({ Component, pageProps }) => { }; export default function App(props: AppProps) { + useReportWebVitals((metric) => { + console.log(metric); + }); return ( -