feat(sw-187): Refactor footer output and fixed urls to include language
This commit is contained in:
@@ -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}
|
||||
</a>
|
||||
) : (
|
||||
<Link href={link.url} key={link.title}>
|
||||
<Link
|
||||
href={link.url}
|
||||
key={link.title}
|
||||
target={link.openInNewTab ? "_blank" : "_self"}
|
||||
color="burgundy"
|
||||
>
|
||||
{link.title}
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 <FooterDetails />
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -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 []
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,5 +8,4 @@ import {
|
||||
|
||||
export type FooterRefDataRaw = z.infer<typeof validateFooterRefConfigSchema>
|
||||
export type FooterDataRaw = z.infer<typeof validateFooterConfigSchema>
|
||||
export type FooterData = FooterDataRaw["all_footer"]["items"][0]
|
||||
export type FooterLinkItem = z.infer<typeof validateLinkItem>
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LanguageSwitcherData } from "@/types/requests/languageSwitcher"
|
||||
import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher"
|
||||
|
||||
export interface LanguageSwitcherProps {
|
||||
type: "mobileHeader" | "desktopHeader" | "footer"
|
||||
|
||||
Reference in New Issue
Block a user