fix(SW-1830): Adjusted schemas for city and country pages to accept less data

* fix(SW-1830): Adjusted schemas for city and country pages to accept less data


Approved-by: Fredrik Thorsson
Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-03-08 07:53:39 +00:00
parent 63ea994f43
commit d45487a3c7
6 changed files with 76 additions and 58 deletions

View File

@@ -51,7 +51,9 @@ export default async function DestinationCityPage() {
<div className={styles.pageContainer}> <div className={styles.pageContainer}>
<header className={styles.header}> <header className={styles.header}>
<Breadcrumbs variant={PageContentTypeEnum.destinationCityPage} /> <Breadcrumbs variant={PageContentTypeEnum.destinationCityPage} />
<TopImages images={images} destinationName={city.name} /> {images?.length && (
<TopImages images={images} destinationName={city.name} />
)}
</header> </header>
<main className={styles.mainContent}> <main className={styles.mainContent}>
<HotelListing /> <HotelListing />
@@ -61,7 +63,7 @@ export default async function DestinationCityPage() {
<SidebarContentWrapper location={city.name}> <SidebarContentWrapper location={city.name}>
<Body color="uiTextMediumContrast">{preamble}</Body> <Body color="uiTextMediumContrast">{preamble}</Body>
<ExperienceList experiences={experiences} /> <ExperienceList experiences={experiences} />
{has_sidepeek && ( {has_sidepeek && sidepeek_content && (
<DestinationPageSidePeek <DestinationPageSidePeek
buttonText={sidepeek_button_text} buttonText={sidepeek_button_text}
sidePeekContent={sidepeek_content} sidePeekContent={sidepeek_content}

View File

@@ -55,7 +55,12 @@ export default async function DestinationCountryPage() {
variant={PageContentTypeEnum.destinationCityPage} variant={PageContentTypeEnum.destinationCityPage}
/> />
</Suspense> </Suspense>
<TopImages images={images} destinationName={translatedCountry} /> {images?.length && (
<TopImages
images={images}
destinationName={translatedCountry}
/>
)}
</header> </header>
<main className={styles.mainContent}> <main className={styles.mainContent}>
<CityListing /> <CityListing />
@@ -65,7 +70,7 @@ export default async function DestinationCountryPage() {
<SidebarContentWrapper location={translatedCountry}> <SidebarContentWrapper location={translatedCountry}>
<Body color="uiTextMediumContrast">{preamble}</Body> <Body color="uiTextMediumContrast">{preamble}</Body>
<ExperienceList experiences={experiences} /> <ExperienceList experiences={experiences} />
{has_sidepeek && ( {has_sidepeek && sidepeek_content && (
<DestinationPageSidePeek <DestinationPageSidePeek
buttonText={sidepeek_button_text} buttonText={sidepeek_button_text}
sidePeekContent={sidepeek_content} sidePeekContent={sidepeek_content}

View File

@@ -1,6 +1,7 @@
"use client" "use client"
import { useState } from "react" import { useState } from "react"
import { useIntl } from "react-intl"
import { ChevronRightSmallIcon } from "@/components/Icons" import { ChevronRightSmallIcon } from "@/components/Icons"
import JsonToHtml from "@/components/JsonToHtml" import JsonToHtml from "@/components/JsonToHtml"
@@ -12,7 +13,7 @@ import type { DestinationCityPageData } from "@/types/trpc/routers/contentstack/
import type { DestinationCountryPageData } from "@/types/trpc/routers/contentstack/destinationCountryPage" import type { DestinationCountryPageData } from "@/types/trpc/routers/contentstack/destinationCountryPage"
interface DestinationPageSidepeekProps { interface DestinationPageSidepeekProps {
buttonText: string buttonText?: string | null
sidePeekContent: NonNullable< sidePeekContent: NonNullable<
| DestinationCityPageData["sidepeek_content"] | DestinationCityPageData["sidepeek_content"]
| DestinationCountryPageData["sidepeek_content"] | DestinationCountryPageData["sidepeek_content"]
@@ -24,6 +25,7 @@ export default function DestinationPageSidepeek({
sidePeekContent, sidePeekContent,
location, location,
}: DestinationPageSidepeekProps) { }: DestinationPageSidepeekProps) {
const intl = useIntl()
const [sidePeekIsOpen, setSidePeekIsOpen] = useState(false) const [sidePeekIsOpen, setSidePeekIsOpen] = useState(false)
const { heading, content } = sidePeekContent const { heading, content } = sidePeekContent
@@ -42,7 +44,7 @@ export default function DestinationPageSidepeek({
size="small" size="small"
wrapping wrapping
> >
{buttonText} {buttonText || intl.formatMessage({ id: "Read more" })}
<ChevronRightSmallIcon /> <ChevronRightSmallIcon />
</Button> </Button>
<SidePeek <SidePeek

View File

@@ -23,7 +23,7 @@ export default function TopImages({ images, destinationName }: TopImageProps) {
open: false, open: false,
activeIndex: 0, activeIndex: 0,
}) })
const lightboxImages = mapImageVaultImagesToGalleryImages(images || []) const lightboxImages = mapImageVaultImagesToGalleryImages(images)
const maxWidth = 1366 // 1366px is the max width of the image container const maxWidth = 1366 // 1366px is the max width of the image container
const visibleImages = images.slice(0, 3) const visibleImages = images.slice(0, 3)

View File

@@ -125,35 +125,39 @@ export const destinationCityPageSchema = z.object({
.object({ .object({
destination_experiences: z.array(z.string()), destination_experiences: z.array(z.string()),
}) })
.transform(({ destination_experiences }) => destination_experiences), .nullish()
.transform((experiences) => experiences?.destination_experiences ?? []),
images: z images: z
.array(z.object({ image: tempImageVaultAssetSchema })) .array(z.object({ image: tempImageVaultAssetSchema }))
.transform((images) => .transform((images) =>
images images
.map((image) => image.image) .map((image) => image.image)
.filter((image): image is ImageVaultAsset => !!image) .filter((image): image is ImageVaultAsset => !!image)
), )
.nullish(),
has_sidepeek: z.boolean().default(false), has_sidepeek: z.boolean().default(false),
sidepeek_button_text: z.string().default(""), sidepeek_button_text: z.string().nullish().default(""),
sidepeek_content: z.object({ sidepeek_content: z
heading: z.string(), .object({
content: z.object({ heading: z.string(),
json: z.any(), content: z.object({
embedded_itemsConnection: z.object({ json: z.any(),
edges: z.array( embedded_itemsConnection: z.object({
z.object({ edges: z.array(
node: linkUnionSchema.transform((data) => { z.object({
const link = transformPageLink(data) node: linkUnionSchema.transform((data) => {
if (link) { const link = transformPageLink(data)
return link if (link) {
} return link
return data }
}), return data
}) }),
), })
),
}),
}), }),
}), })
}), .nullish(),
blocks: discriminatedUnionArray(blocksSchema.options).nullable(), blocks: discriminatedUnionArray(blocksSchema.options).nullable(),
system: systemSchema.merge( system: systemSchema.merge(
z.object({ z.object({
@@ -228,17 +232,19 @@ const blocksRefsSchema = z.discriminatedUnion("__typename", [
export const destinationCityPageRefsSchema = z.object({ export const destinationCityPageRefsSchema = z.object({
destination_city_page: z.object({ destination_city_page: z.object({
sidepeek_content: z.object({ sidepeek_content: z
content: z.object({ .object({
embedded_itemsConnection: z.object({ content: z.object({
edges: z.array( embedded_itemsConnection: z.object({
z.object({ edges: z.array(
node: linkRefsUnionSchema, z.object({
}) node: linkRefsUnionSchema,
), })
),
}),
}), }),
}), })
}), .nullish(),
blocks: discriminatedUnionArray(blocksRefsSchema.options).nullable(), blocks: discriminatedUnionArray(blocksRefsSchema.options).nullable(),
system: systemSchema, system: systemSchema,
}), }),

View File

@@ -63,28 +63,31 @@ export const destinationCountryPageSchema = z.object({
images images
.map((image) => image.image) .map((image) => image.image)
.filter((image): image is ImageVaultAsset => !!image) .filter((image): image is ImageVaultAsset => !!image)
), )
.nullish(),
has_sidepeek: z.boolean().default(false), has_sidepeek: z.boolean().default(false),
sidepeek_button_text: z.string().default(""), sidepeek_button_text: z.string().nullish(),
sidepeek_content: z.object({ sidepeek_content: z
heading: z.string(), .object({
content: z.object({ heading: z.string(),
json: z.any(), content: z.object({
embedded_itemsConnection: z.object({ json: z.any(),
edges: z.array( embedded_itemsConnection: z.object({
z.object({ edges: z.array(
node: linkUnionSchema.transform((data) => { z.object({
const link = transformPageLink(data) node: linkUnionSchema.transform((data) => {
if (link) { const link = transformPageLink(data)
return link if (link) {
} return link
return data }
}), return data
}) }),
), })
),
}),
}), }),
}), })
}), .nullish(),
blocks: discriminatedUnionArray(blocksSchema.options).nullable(), blocks: discriminatedUnionArray(blocksSchema.options).nullable(),
system: systemSchema.merge( system: systemSchema.merge(
z.object({ z.object({