From ef33d082d8d82440ea2e3bf7f17a776ddde447a3 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Mon, 9 Sep 2024 13:59:36 +0200 Subject: [PATCH] feat(sw-187): Refactor footer output and fixed urls to include language --- .../Footer/Navigation/SecondaryNav/index.tsx | 8 +- .../SecondaryNav/secondarynav.module.css | 8 + components/Footer/index.tsx | 2 +- .../Fragments/Footer/MainLinks.graphql | 28 --- .../Fragments/Footer/Refs/MainLinks.graphql | 22 -- .../Footer/Refs/SecondaryLinks.graphql | 24 -- .../Fragments/Footer/SecondaryLinks.graphql | 31 --- .../Fragments/Footer/TertiaryLinks.graphql | 28 --- lib/graphql/Query/Footer.graphql | 113 ++++++++-- server/routers/contentstack/base/output.ts | 213 +++++++++++------- server/routers/contentstack/base/query.ts | 29 +-- server/routers/contentstack/base/utils.ts | 24 -- types/components/footer/footer.ts | 1 - types/components/footer/navigation.ts | 2 +- .../languageSwitcher/languageSwitcher.ts | 2 +- 15 files changed, 253 insertions(+), 282 deletions(-) delete mode 100644 lib/graphql/Fragments/Footer/MainLinks.graphql delete mode 100644 lib/graphql/Fragments/Footer/Refs/MainLinks.graphql delete mode 100644 lib/graphql/Fragments/Footer/Refs/SecondaryLinks.graphql delete mode 100644 lib/graphql/Fragments/Footer/SecondaryLinks.graphql delete mode 100644 lib/graphql/Fragments/Footer/TertiaryLinks.graphql diff --git a/components/Footer/Navigation/SecondaryNav/index.tsx b/components/Footer/Navigation/SecondaryNav/index.tsx index 1524ffbb6..f731c67a9 100644 --- a/components/Footer/Navigation/SecondaryNav/index.tsx +++ b/components/Footer/Navigation/SecondaryNav/index.tsx @@ -62,11 +62,17 @@ export default function FooterSecondaryNav({ key={link.title} target={link.openInNewTab ? "_blank" : "_self"} aria-label={link.title} + className={styles.secondaryNavigationLink} > {link.title} ) : ( - + {link.title} )} diff --git a/components/Footer/Navigation/SecondaryNav/secondarynav.module.css b/components/Footer/Navigation/SecondaryNav/secondarynav.module.css index bedaf577b..e4d1117ee 100644 --- a/components/Footer/Navigation/SecondaryNav/secondarynav.module.css +++ b/components/Footer/Navigation/SecondaryNav/secondarynav.module.css @@ -25,6 +25,14 @@ margin: 0; } +.secondaryNavigationLink { + color: var(--Base-Text-High-contrast); + font-weight: var(--typography-Body-Bold-fontWeight); + font-family: var(--typography-Body-Bold-fontFamily); + margin: 0; + text-decoration: none; +} + @media screen and (min-width: 767px) { .secondaryNavigation { margin-top: var(--Spacing-x4); diff --git a/components/Footer/index.tsx b/components/Footer/index.tsx index ee11328ba..3fa82e46b 100644 --- a/components/Footer/index.tsx +++ b/components/Footer/index.tsx @@ -4,8 +4,8 @@ import FooterDetails from "./Details" import FooterNavigation from "./Navigation" export default async function Footer() { - const languages = await serverClient().contentstack.languageSwitcher.get() const footerData = await serverClient().contentstack.base.footer() + const languages = await serverClient().contentstack.languageSwitcher.get() if (!footerData || !languages) { return diff --git a/lib/graphql/Fragments/Footer/MainLinks.graphql b/lib/graphql/Fragments/Footer/MainLinks.graphql deleted file mode 100644 index 6a7c5fba7..000000000 --- a/lib/graphql/Fragments/Footer/MainLinks.graphql +++ /dev/null @@ -1,28 +0,0 @@ -fragment MainLinks on Footer { - main_links { - open_in_new_tab - link { - href - title - } - pageConnection { - edges { - node { - __typename - ... on AccountPage { - title - url - } - ... on LoyaltyPage { - title - url - } - ... on ContentPage { - title - url - } - } - } - } - } -} diff --git a/lib/graphql/Fragments/Footer/Refs/MainLinks.graphql b/lib/graphql/Fragments/Footer/Refs/MainLinks.graphql deleted file mode 100644 index 6609f66c3..000000000 --- a/lib/graphql/Fragments/Footer/Refs/MainLinks.graphql +++ /dev/null @@ -1,22 +0,0 @@ -#import "../../Refs/LoyaltyPage/LoyaltyPage.graphql" -#import "../../Refs/MyPages/AccountPage.graphql" -#import "../../Refs/ContentPage/ContentPage.graphql" - -fragment MainLinksRef on Footer { - __typename - main_links { - pageConnection { - edges { - node { - __typename - ...LoyaltyPageRef - ...ContentPageRef - ...AccountPageRef - } - } - } - } - system { - ...System - } -} diff --git a/lib/graphql/Fragments/Footer/Refs/SecondaryLinks.graphql b/lib/graphql/Fragments/Footer/Refs/SecondaryLinks.graphql deleted file mode 100644 index 7022084e8..000000000 --- a/lib/graphql/Fragments/Footer/Refs/SecondaryLinks.graphql +++ /dev/null @@ -1,24 +0,0 @@ -#import "../../Refs/LoyaltyPage/LoyaltyPage.graphql" -#import "../../Refs/MyPages/AccountPage.graphql" -#import "../../Refs/ContentPage/ContentPage.graphql" - -fragment SecondaryLinksRef on Footer { - __typename - secondary_links { - links { - pageConnection { - edges { - node { - __typename - ...LoyaltyPageRef - ...ContentPageRef - ...AccountPageRef - } - } - } - } - } - system { - ...System - } -} diff --git a/lib/graphql/Fragments/Footer/SecondaryLinks.graphql b/lib/graphql/Fragments/Footer/SecondaryLinks.graphql deleted file mode 100644 index 4d48f5733..000000000 --- a/lib/graphql/Fragments/Footer/SecondaryLinks.graphql +++ /dev/null @@ -1,31 +0,0 @@ -fragment SecondaryLinks on Footer { - secondary_links { - title - links { - open_in_new_tab - pageConnection { - edges { - node { - __typename - ... on AccountPage { - title - url - } - ... on LoyaltyPage { - title - url - } - ... on ContentPage { - title - url - } - } - } - } - link { - href - title - } - } - } -} diff --git a/lib/graphql/Fragments/Footer/TertiaryLinks.graphql b/lib/graphql/Fragments/Footer/TertiaryLinks.graphql deleted file mode 100644 index 79e3ccec0..000000000 --- a/lib/graphql/Fragments/Footer/TertiaryLinks.graphql +++ /dev/null @@ -1,28 +0,0 @@ -fragment TertiaryLinks on Footer { - tertiary_links { - open_in_new_tab - link { - href - title - } - pageConnection { - edges { - node { - __typename - ... on AccountPage { - title - url - } - ... on LoyaltyPage { - title - url - } - ... on ContentPage { - title - url - } - } - } - } - } -} diff --git a/lib/graphql/Query/Footer.graphql b/lib/graphql/Query/Footer.graphql index 1551fc19a..17ed02395 100644 --- a/lib/graphql/Query/Footer.graphql +++ b/lib/graphql/Query/Footer.graphql @@ -1,21 +1,74 @@ -#import "../Fragments/Footer/AppDownloads.graphql" -#import "../Fragments/Footer/MainLinks.graphql" -#import "../Fragments/Footer/SecondaryLinks.graphql" -#import "../Fragments/Footer/SocialMedia.graphql" -#import "../Fragments/Footer/TertiaryLinks.graphql" -#import "../Fragments/Footer/Refs/MainLinks.graphql" -#import "../Fragments/Footer/Refs/SecondaryLinks.graphql" -#import "../Fragments/Footer/Refs/TertiaryLinks.graphql" #import "../Fragments/Refs/System.graphql" +#import "../Fragments/PageLink/AccountPageLink.graphql" +#import "../Fragments/PageLink/ContentPageLink.graphql" +#import "../Fragments/PageLink/HotelPageLink.graphql" +#import "../Fragments/PageLink/LoyaltyPageLink.graphql" + +#import "../Fragments/Refs/ContentPage/ContentPage.graphql" +#import "../Fragments/Refs/HotelPage/HotelPage.graphql" +#import "../Fragments/Refs/LoyaltyPage/LoyaltyPage.graphql" +#import "../Fragments/Refs/MyPages/AccountPage.graphql" + +#import "../Fragments/Footer/AppDownloads.graphql" +#import "../Fragments/Footer/SocialMedia.graphql" + query GetFooter($locale: String!) { all_footer(limit: 1, locale: $locale) { items { - ...MainLinks - ...SecondaryLinks + main_links { + open_in_new_tab + link { + href + title + } + pageConnection { + edges { + node { + ...ContentPageLink + ...HotelPageLink + ...LoyaltyPageLink + } + } + } + } + secondary_links { + title + links { + open_in_new_tab + pageConnection { + edges { + node { + ...ContentPageLink + ...HotelPageLink + ...LoyaltyPageLink + } + } + } + link { + href + title + } + } + } + tertiary_links { + open_in_new_tab + link { + href + title + } + pageConnection { + edges { + node { + ...ContentPageLink + ...HotelPageLink + ...LoyaltyPageLink + } + } + } + } ...AppDownloads ...SocialMedia - ...TertiaryLinks } } } @@ -23,9 +76,41 @@ query GetFooter($locale: String!) { query GetFooterRef($locale: String!) { all_footer(limit: 1, locale: $locale) { items { - ...MainLinksRef - ...SecondaryLinksRef - ...TertiaryLinksRef + main_links { + pageConnection { + edges { + node { + ...ContentPageRef + ...HotelPageRef + ...LoyaltyPageRef + } + } + } + } + secondary_links { + links { + pageConnection { + edges { + node { + ...ContentPageRef + ...HotelPageRef + ...LoyaltyPageRef + } + } + } + } + } + tertiary_links { + pageConnection { + edges { + node { + ...ContentPageRef + ...HotelPageRef + ...LoyaltyPageRef + } + } + } + } system { ...System } diff --git a/server/routers/contentstack/base/output.ts b/server/routers/contentstack/base/output.ts index 37c1a3ea1..9f02ed0e3 100644 --- a/server/routers/contentstack/base/output.ts +++ b/server/routers/contentstack/base/output.ts @@ -280,100 +280,155 @@ const validateExternalLink = z const validateInternalLink = z .object({ - edges: z.array( - z.object({ - node: z.object({ - title: z.string().optional(), - url: z.string().optional(), - }), - }) - ), + edges: z + .array( + z.object({ + node: z.object({ + system: z.object({ + uid: z.string(), + locale: z.nativeEnum(Lang), + }), + url: z.string(), + title: z.string(), + web: z + .object({ + original_url: z.string(), + }) + .optional(), + }), + }) + ) + .max(1), + }) + .transform((data) => { + const node = data.edges[0]?.node + if (!node) { + return null + } + const url = node.url + const originalUrl = node.web?.original_url + const lang = node.system.locale + + return { + url: originalUrl || removeMultipleSlashes(`/${lang}/${url}`), + title: node.title, + } }) .optional() -export const validateLinkItem = z.object({ - open_in_new_tab: z.boolean(), - link: validateExternalLink, - pageConnection: validateInternalLink, -}) +export const validateLinkItem = z + .object({ + open_in_new_tab: z.boolean(), + link: validateExternalLink, + pageConnection: validateInternalLink, + }) + .transform((data) => { + return { + url: data.pageConnection?.url ?? data.link?.href ?? "", + title: data.pageConnection?.title ?? data.link?.title, + openInNewTab: data.open_in_new_tab, + isExternal: !!data.link?.href, + } + }) -export const validateFooterConfigSchema = z.object({ - all_footer: z.object({ - items: z.array( - z.object({ - main_links: z.array(validateLinkItem), - app_downloads: z.object({ - title: z.string(), - links: z.array( - z.object({ - type: z.string(), - href: validateExternalLink, - }) - ), - }), - secondary_links: z.array( - z.object({ +export const validateFooterConfigSchema = z + .object({ + all_footer: z.object({ + items: z.array( + z.object({ + main_links: z.array(validateLinkItem), + app_downloads: z.object({ title: z.string(), - links: z.array(validateLinkItem), - }) - ), - social_media: z.object({ - links: z.array( + links: z.array( + z.object({ + type: z.string(), + href: validateExternalLink, + }) + ), + }), + secondary_links: z.array( z.object({ - type: z.string(), - href: validateExternalLink, + title: z.string(), + links: z.array(validateLinkItem), }) ), - }), - tertiary_links: z.array(validateLinkItem), - }) - ), - }), -}) + social_media: z.object({ + links: z.array( + z.object({ + type: z.string(), + href: validateExternalLink, + }) + ), + }), + tertiary_links: z.array(validateLinkItem), + }) + ), + }), + }) + .transform((data) => { + const { + main_links, + app_downloads, + secondary_links, + social_media, + tertiary_links, + } = data.all_footer.items[0] + + return { + mainLinks: main_links, + appDownloads: app_downloads, + secondaryLinks: secondary_links, + socialMedia: social_media, + tertiaryLinks: tertiary_links, + } + }) const pageConnectionRefs = z.object({ - edges: z.array( - z.object({ - node: z.object({ - __typename: z.nativeEnum(PageLinkEnum), - system: z.object({ - content_type_uid: z.string(), - uid: z.string(), + edges: z + .array( + z.object({ + node: z.object({ + system: z.object({ + content_type_uid: z.string(), + uid: z.string(), + }), }), - }), - }) - ), + }) + ) + .max(1), }) export const validateFooterRefConfigSchema = z.object({ all_footer: z.object({ - items: z.array( - z.object({ - main_links: z.array( - z.object({ - pageConnection: pageConnectionRefs, - }) - ), - secondary_links: z.array( - z.object({ - links: z.array( - z.object({ - pageConnection: pageConnectionRefs, - }) - ), - }) - ), - tertiary_links: z.array( - z.object({ - pageConnection: pageConnectionRefs, - }) - ), - system: z.object({ - content_type_uid: z.string(), - uid: z.string(), - }), - }) - ), + items: z + .array( + z.object({ + main_links: z.array( + z.object({ + pageConnection: pageConnectionRefs, + }) + ), + secondary_links: z.array( + z.object({ + links: z.array( + z.object({ + pageConnection: pageConnectionRefs, + }) + ), + }) + ), + tertiary_links: z.array( + z.object({ + pageConnection: pageConnectionRefs, + }) + ), + system: z.object({ + content_type_uid: z.string(), + uid: z.string(), + }), + }) + ) + .length(1), }), }) diff --git a/server/routers/contentstack/base/query.ts b/server/routers/contentstack/base/query.ts index 30a262a42..bde79d886 100644 --- a/server/routers/contentstack/base/query.ts +++ b/server/routers/contentstack/base/query.ts @@ -37,11 +37,7 @@ import { validateFooterConfigSchema, validateFooterRefConfigSchema, } from "./output" -import { - getConnections, - getFooterConnections, - transformPageConnectionLinks, -} from "./utils" +import { getConnections, getFooterConnections } from "./utils" import type { FooterDataRaw, @@ -658,28 +654,7 @@ export const baseQueryRouter = router({ "contentstack.footer success", JSON.stringify({ query: { lang } }) ) - const validatedFooterData = validatedFooterConfig.data.all_footer.items[0] - const mainLinks = transformPageConnectionLinks( - validatedFooterData.main_links - ) - const secondaryLinks = validatedFooterData.secondary_links.map( - (section) => ({ - title: section.title, - links: transformPageConnectionLinks(section.links), - }) - ) - - const tertiaryLinks = transformPageConnectionLinks( - validatedFooterData.tertiary_links - ) - - return { - mainLinks: mainLinks, - appDownloads: validatedFooterData.app_downloads, - secondaryLinks: secondaryLinks, - socialMedia: validatedFooterData.social_media, - tertiaryLinks: tertiaryLinks, - } + return validatedFooterConfig.data }), }) diff --git a/server/routers/contentstack/base/utils.ts b/server/routers/contentstack/base/utils.ts index 83347bdb6..6125eec92 100644 --- a/server/routers/contentstack/base/utils.ts +++ b/server/routers/contentstack/base/utils.ts @@ -69,27 +69,3 @@ export function getFooterConnections(refs: FooterRefDataRaw) { return connections } - -export function transformPageConnectionLinks(links: FooterLinkItem[]) { - if (!links) return [] - return links.flatMap((link) => { - if (link.pageConnection?.edges.length) { - return link.pageConnection.edges.map((edge) => ({ - title: edge.node.title || "", - url: edge.node.url || "", - openInNewTab: link.open_in_new_tab, - isExternal: false, - })) - } else if (link.link) { - return [ - { - title: link.link.title, - url: link.link.href, - openInNewTab: link.open_in_new_tab, - isExternal: true, - }, - ] - } - return [] - }) -} diff --git a/types/components/footer/footer.ts b/types/components/footer/footer.ts index 8df0eaf8a..a40443e0d 100644 --- a/types/components/footer/footer.ts +++ b/types/components/footer/footer.ts @@ -8,5 +8,4 @@ import { export type FooterRefDataRaw = z.infer export type FooterDataRaw = z.infer -export type FooterData = FooterDataRaw["all_footer"]["items"][0] export type FooterLinkItem = z.infer diff --git a/types/components/footer/navigation.ts b/types/components/footer/navigation.ts index 503c8ddb9..37c0a3600 100644 --- a/types/components/footer/navigation.ts +++ b/types/components/footer/navigation.ts @@ -3,7 +3,7 @@ import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher" export type FooterLink = { isExternal: boolean openInNewTab: boolean - title: string + title: string | undefined url: string } export type FooterMainNavProps = { diff --git a/types/components/languageSwitcher/languageSwitcher.ts b/types/components/languageSwitcher/languageSwitcher.ts index d938edc87..6672fbe83 100644 --- a/types/components/languageSwitcher/languageSwitcher.ts +++ b/types/components/languageSwitcher/languageSwitcher.ts @@ -1,4 +1,4 @@ -import { LanguageSwitcherData } from "@/types/requests/languageSwitcher" +import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher" export interface LanguageSwitcherProps { type: "mobileHeader" | "desktopHeader" | "footer"