608 lines
15 KiB
TypeScript
608 lines
15 KiB
TypeScript
import { z } from "zod"
|
|
|
|
import { Lang } from "@/constants/languages"
|
|
|
|
import { removeMultipleSlashes } from "@/utils/url"
|
|
|
|
import { imageVaultAssetTransformedSchema } from "../schemas/imageVault"
|
|
|
|
import { Image } from "@/types/image"
|
|
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
|
|
|
// Help me write this zod schema based on the type ContactConfig
|
|
export const validateContactConfigSchema = z.object({
|
|
all_contact_config: z.object({
|
|
items: z.array(
|
|
z.object({
|
|
email: z.object({
|
|
name: z.string().nullable(),
|
|
address: z.string().nullable(),
|
|
}),
|
|
email_loyalty: z.object({
|
|
name: z.string().nullable(),
|
|
address: z.string().nullable(),
|
|
}),
|
|
mailing_address: z.object({
|
|
zip: z.string().nullable(),
|
|
street: z.string().nullable(),
|
|
name: z.string().nullable(),
|
|
city: z.string().nullable(),
|
|
country: z.string().nullable(),
|
|
}),
|
|
phone: z.object({
|
|
number: z.string().nullable(),
|
|
name: z.string().nullable(),
|
|
}),
|
|
phone_loyalty: z.object({
|
|
number: z.string().nullable(),
|
|
name: z.string().nullable(),
|
|
}),
|
|
visiting_address: z.object({
|
|
zip: z.string().nullable(),
|
|
country: z.string().nullable(),
|
|
city: z.string().nullable(),
|
|
street: z.string().nullable(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
export enum ContactFieldGroupsEnum {
|
|
email = "email",
|
|
email_loyalty = "email_loyalty",
|
|
mailing_address = "mailing_address",
|
|
phone = "phone",
|
|
phone_loyalty = "phone_loyalty",
|
|
visiting_address = "visiting_address",
|
|
}
|
|
|
|
export type ContactFieldGroups = keyof typeof ContactFieldGroupsEnum
|
|
|
|
export type ContactConfigData = z.infer<typeof validateContactConfigSchema>
|
|
|
|
export type ContactConfig = ContactConfigData["all_contact_config"]["items"][0]
|
|
|
|
export type ContactFields = {
|
|
display_text: string | null
|
|
contact_field: string
|
|
footnote: string | null
|
|
}
|
|
|
|
export const validateCurrentHeaderConfigSchema = z.object({
|
|
all_current_header: z.object({
|
|
items: z.array(
|
|
z.object({
|
|
frontpage_link_text: z.string(),
|
|
logoConnection: z.object({
|
|
edges: z.array(
|
|
z.object({
|
|
node: z.object({
|
|
description: z.string().optional().nullable(),
|
|
dimension: z.object({
|
|
height: z.number(),
|
|
width: z.number(),
|
|
}),
|
|
metadata: z.any().nullable(),
|
|
system: z.object({
|
|
uid: z.string(),
|
|
}),
|
|
title: z.string().nullable(),
|
|
url: z.string().nullable(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
menu: z.object({
|
|
links: z.array(
|
|
z.object({
|
|
href: z.string(),
|
|
title: z.string(),
|
|
})
|
|
),
|
|
}),
|
|
top_menu: z.object({
|
|
links: z.array(
|
|
z.object({
|
|
link: z.object({
|
|
href: z.string(),
|
|
title: z.string(),
|
|
}),
|
|
show_on_mobile: z.boolean(),
|
|
sort_order_mobile: z.number(),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
export type CurrentHeaderDataRaw = z.infer<
|
|
typeof validateCurrentHeaderConfigSchema
|
|
>
|
|
|
|
export type CurrentHeaderData = Omit<
|
|
CurrentHeaderDataRaw["all_current_header"]["items"][0],
|
|
"logoConnection"
|
|
> & {
|
|
logo: Image
|
|
}
|
|
|
|
const validateCurrentHeaderRefConfigSchema = z.object({
|
|
all_current_header: z.object({
|
|
items: z.array(
|
|
z.object({
|
|
system: z.object({
|
|
content_type_uid: z.string(),
|
|
uid: z.string(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
export type CurrentHeaderRefDataRaw = z.infer<
|
|
typeof validateCurrentHeaderRefConfigSchema
|
|
>
|
|
|
|
const validateAppDownload = z.object({
|
|
href: z.string(),
|
|
imageConnection: z.object({
|
|
edges: z.array(
|
|
z.object({
|
|
node: z.object({
|
|
description: z.string().optional().nullable(),
|
|
dimension: z.object({
|
|
height: z.number(),
|
|
width: z.number(),
|
|
}),
|
|
metadata: z.any().nullable(),
|
|
system: z.object({
|
|
uid: z.string(),
|
|
}),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
const validateNavigationItem = z.object({
|
|
links: z.array(z.object({ href: z.string(), title: z.string() })),
|
|
title: z.string(),
|
|
})
|
|
|
|
export type NavigationItem = z.infer<typeof validateNavigationItem>
|
|
|
|
export const validateCurrentFooterConfigSchema = z.object({
|
|
all_current_footer: z.object({
|
|
items: z.array(
|
|
z.object({
|
|
title: z.string(),
|
|
about: z.object({
|
|
title: z.string(),
|
|
text: z.string(),
|
|
}),
|
|
app_downloads: z.object({
|
|
title: z.string(),
|
|
app_store: validateAppDownload,
|
|
google_play: validateAppDownload,
|
|
}),
|
|
logoConnection: z.object({
|
|
edges: z.array(
|
|
z.object({
|
|
node: z.object({
|
|
description: z.string().optional().nullable(),
|
|
dimension: z.object({
|
|
height: z.number(),
|
|
width: z.number(),
|
|
}),
|
|
metadata: z.any().nullable(),
|
|
system: z.object({
|
|
uid: z.string(),
|
|
}),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
navigation: z.array(validateNavigationItem),
|
|
social_media: z.object({
|
|
title: z.string(),
|
|
facebook: z.object({ href: z.string(), title: z.string() }),
|
|
instagram: z.object({ href: z.string(), title: z.string() }),
|
|
twitter: z.object({ href: z.string(), title: z.string() }),
|
|
}),
|
|
trip_advisor: z.object({
|
|
title: z.string(),
|
|
logoConnection: z.object({
|
|
edges: z.array(
|
|
z.object({
|
|
node: z.object({
|
|
description: z.string().optional().nullable(),
|
|
dimension: z.object({
|
|
height: z.number(),
|
|
width: z.number(),
|
|
}),
|
|
metadata: z.any().nullable(),
|
|
system: z.object({
|
|
uid: z.string(),
|
|
}),
|
|
title: z.string(),
|
|
url: z.string(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
export type CurrentFooterDataRaw = z.infer<
|
|
typeof validateCurrentFooterConfigSchema
|
|
>
|
|
|
|
export type CurrentFooterData = Omit<
|
|
CurrentFooterDataRaw["all_current_footer"]["items"][0],
|
|
"logoConnection"
|
|
> & {
|
|
logo: Image
|
|
}
|
|
|
|
const validateCurrentFooterRefConfigSchema = z.object({
|
|
all_current_footer: z.object({
|
|
items: z.array(
|
|
z.object({
|
|
system: z.object({
|
|
content_type_uid: z.string(),
|
|
uid: z.string(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
export type CurrentFooterRefDataRaw = z.infer<
|
|
typeof validateCurrentFooterRefConfigSchema
|
|
>
|
|
|
|
const validateExternalLink = z
|
|
.object({
|
|
href: z.string(),
|
|
title: z.string(),
|
|
})
|
|
.optional()
|
|
|
|
const validateInternalLink = z
|
|
.object({
|
|
edges: z.array(
|
|
z.object({
|
|
node: z.object({
|
|
title: z.string().optional(),
|
|
url: z.string().optional(),
|
|
}),
|
|
})
|
|
),
|
|
})
|
|
.optional()
|
|
|
|
const validateLinkItem = z.object({
|
|
title: z.string(),
|
|
open_in_new_tab: z.boolean(),
|
|
link: validateExternalLink,
|
|
pageConnection: validateInternalLink,
|
|
})
|
|
|
|
export type FooterLinkItem = z.infer<typeof validateLinkItem>
|
|
|
|
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({
|
|
title: z.string(),
|
|
links: z.array(validateLinkItem),
|
|
})
|
|
),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
export type FooterDataRaw = z.infer<typeof validateFooterConfigSchema>
|
|
export type FooterData = FooterDataRaw["all_footer"]["items"][0]
|
|
|
|
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(),
|
|
}),
|
|
}),
|
|
})
|
|
),
|
|
})
|
|
|
|
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,
|
|
})
|
|
),
|
|
})
|
|
),
|
|
system: z.object({
|
|
content_type_uid: z.string(),
|
|
uid: z.string(),
|
|
}),
|
|
})
|
|
),
|
|
}),
|
|
})
|
|
|
|
export type FooterRefDataRaw = z.infer<typeof validateFooterRefConfigSchema>
|
|
|
|
const linkConnectionNodeSchema = z
|
|
.object({
|
|
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(),
|
|
}),
|
|
}),
|
|
})
|
|
)
|
|
.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 {
|
|
href: originalUrl || removeMultipleSlashes(`/${lang}/${url}`),
|
|
isExternal: !!originalUrl,
|
|
}
|
|
})
|
|
|
|
const linkWithTitleSchema = z
|
|
.object({
|
|
title: z.string(),
|
|
linkConnection: linkConnectionNodeSchema,
|
|
})
|
|
.transform((rawData) => {
|
|
return rawData.linkConnection && rawData.title
|
|
? {
|
|
...rawData.linkConnection,
|
|
title: rawData.title,
|
|
}
|
|
: null
|
|
})
|
|
|
|
const cardButtonSchema = z
|
|
.object({
|
|
cta_text: z.string(),
|
|
external_link: z.object({
|
|
href: z.string(),
|
|
title: z.string(),
|
|
}),
|
|
is_contentstack_link: z.boolean(),
|
|
linkConnection: linkConnectionNodeSchema,
|
|
open_in_new_tab: z.boolean(),
|
|
})
|
|
.transform((data) => {
|
|
const linkConnectionData = data.linkConnection
|
|
const isContentstackLink = data.is_contentstack_link
|
|
const externalLink = data.external_link
|
|
const href =
|
|
isContentstackLink && externalLink.href
|
|
? externalLink.href
|
|
: linkConnectionData?.href || ""
|
|
|
|
return {
|
|
openInNewTab: data.open_in_new_tab,
|
|
title: data.cta_text,
|
|
href,
|
|
isExternal: !isContentstackLink || linkConnectionData?.isExternal,
|
|
}
|
|
})
|
|
|
|
const cardConnectionSchema = z
|
|
.object({
|
|
edges: z
|
|
.array(
|
|
z.object({
|
|
node: z.object({
|
|
heading: z.string(),
|
|
body_text: z.string(),
|
|
background_image: imageVaultAssetTransformedSchema,
|
|
has_primary_button: z.boolean(),
|
|
has_secondary_button: z.boolean(),
|
|
scripted_top_title: z.string(),
|
|
primary_button: cardButtonSchema.nullable(),
|
|
secondary_button: cardButtonSchema.nullable(),
|
|
}),
|
|
})
|
|
)
|
|
.max(1),
|
|
})
|
|
.transform((data) => {
|
|
const node = data.edges[0]?.node
|
|
if (!node) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
scriptedTopTitle: node.scripted_top_title,
|
|
heading: node.heading,
|
|
bodyText: node.body_text,
|
|
backgroundImage: node.background_image,
|
|
primaryButton: node.has_primary_button ? node.primary_button : null,
|
|
secondaryButton: node.has_secondary_button ? node.secondary_button : null,
|
|
}
|
|
})
|
|
|
|
export const menuItemSchema = z
|
|
.object({
|
|
title: z.string(),
|
|
linkConnection: linkConnectionNodeSchema,
|
|
submenu: z.array(
|
|
z.object({
|
|
title: z.string(),
|
|
links: z.array(linkWithTitleSchema),
|
|
})
|
|
),
|
|
see_all_link: linkWithTitleSchema,
|
|
cardConnection: cardConnectionSchema,
|
|
})
|
|
.transform((data) => {
|
|
const { submenu, linkConnection, cardConnection, see_all_link, title } =
|
|
data
|
|
return {
|
|
title,
|
|
link: submenu.length ? null : linkConnection,
|
|
seeAllLink: submenu.length ? see_all_link : null,
|
|
submenu,
|
|
card: cardConnection,
|
|
}
|
|
})
|
|
|
|
export const getHeaderSchema = z
|
|
.object({
|
|
all_header: z.object({
|
|
items: z
|
|
.array(
|
|
z.object({
|
|
top_link: linkWithTitleSchema,
|
|
menu_items: z.array(menuItemSchema),
|
|
})
|
|
)
|
|
.length(1),
|
|
}),
|
|
})
|
|
.transform((data) => {
|
|
const { top_link, menu_items } = data.all_header.items[0]
|
|
|
|
return {
|
|
topLink: top_link,
|
|
menuItems: menu_items,
|
|
}
|
|
})
|
|
|
|
const linkConnectionRefs = z.object({
|
|
edges: z
|
|
.array(
|
|
z.object({
|
|
node: z.object({
|
|
system: z.object({
|
|
content_type_uid: z.string(),
|
|
uid: z.string(),
|
|
}),
|
|
}),
|
|
})
|
|
)
|
|
.max(1),
|
|
})
|
|
|
|
const cardConnectionRefs = z.object({
|
|
primary_button: z
|
|
.object({
|
|
linkConnection: linkConnectionRefs,
|
|
})
|
|
.nullable(),
|
|
secondary_button: z
|
|
.object({
|
|
linkConnection: linkConnectionRefs,
|
|
})
|
|
.nullable(),
|
|
system: z.object({
|
|
content_type_uid: z.string(),
|
|
uid: z.string(),
|
|
}),
|
|
})
|
|
|
|
export const getHeaderRefSchema = z.object({
|
|
all_header: z.object({
|
|
items: z
|
|
.array(
|
|
z.object({
|
|
top_link: z
|
|
.object({
|
|
linkConnection: linkConnectionRefs,
|
|
})
|
|
.nullable(),
|
|
menu_items: z.array(
|
|
z.object({
|
|
linkConnection: linkConnectionRefs,
|
|
see_all_link: z.object({
|
|
linkConnection: linkConnectionRefs,
|
|
}),
|
|
cardConnection: z.object({
|
|
edges: z
|
|
.array(
|
|
z.object({
|
|
node: cardConnectionRefs,
|
|
})
|
|
)
|
|
.max(1),
|
|
}),
|
|
submenu: z.array(
|
|
z.object({
|
|
links: z.array(
|
|
z.object({ linkConnection: linkConnectionRefs })
|
|
),
|
|
})
|
|
),
|
|
})
|
|
),
|
|
system: z.object({
|
|
content_type_uid: z.string(),
|
|
uid: z.string(),
|
|
}),
|
|
})
|
|
)
|
|
.length(1),
|
|
}),
|
|
})
|