fix(SW-194): add refs for hotel pages

This commit is contained in:
Matilda Landström
2024-10-09 16:33:14 +02:00
parent 99d537d40c
commit e234225c4b
8 changed files with 307 additions and 14 deletions

View File

@@ -1,4 +1,7 @@
#import "../../AccountPage/Ref.graphql"
#import "../../ContentPage/Ref.graphql" #import "../../ContentPage/Ref.graphql"
#import "../../HotelPage/Ref.graphql"
#import "../../LoyaltyPage/Ref.graphql"
fragment AccordionBlockRefs on Accordion { fragment AccordionBlockRefs on Accordion {
questions { questions {
@@ -7,7 +10,10 @@ fragment AccordionBlockRefs on Accordion {
edges { edges {
node { node {
__typename __typename
...AccountPageRef
...ContentPageRef ...ContentPageRef
...HotelPageRef
...LoyaltyPageRef
} }
} }
} }

View File

@@ -63,6 +63,60 @@ query GetHotelPage($locale: String!, $uid: String!) {
} }
} }
} }
system {
...System
created_at
updated_at
}
}
}
query GetHotelPageRefs($locale: String!, $uid: String!) {
hotel_page(locale: $locale, uid: $uid) {
faq {
global_faqConnection {
edges {
node {
...AccordionBlockRefs
}
}
}
specific_faq {
questions {
answer {
embedded_itemsConnection {
edges {
node {
__typename
...AccountPageRef
...ContentPageRef
...HotelPageRef
...LoyaltyPageRef
}
}
}
}
}
}
}
content {
__typename
... on HotelPageContentUpcomingActivitiesCard {
upcoming_activities_card {
hotel_page_activities_content_pageConnection {
edges {
node {
__typename
...ContentPageRef
}
}
}
}
}
}
system {
...System
}
} }
} }

View File

@@ -2,8 +2,12 @@ import { z } from "zod"
import { discriminatedUnionArray } from "@/lib/discriminatedUnion" import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
import { activitiesCardSchema } from "../schemas/blocks/activitiesCard" import {
import { accordionSchema } from "../schemas/blocks/faq" activitiesCardRefSchema,
activitiesCardSchema,
} from "../schemas/blocks/activitiesCard"
import { accordionRefsSchema,accordionSchema } from "../schemas/blocks/faq"
import { systemSchema } from "../schemas/system"
import { HotelPageEnum } from "@/types/enums/hotelPage" import { HotelPageEnum } from "@/types/enums/hotelPage"
@@ -24,5 +28,30 @@ export const hotelPageSchema = z.object({
hotel_page_id: z.string(), hotel_page_id: z.string(),
title: z.string(), title: z.string(),
url: z.string(), url: z.string(),
system: systemSchema.merge(
z.object({
created_at: z.string(),
updated_at: z.string(),
})
),
}),
})
/** REFS */
const hotelPageActiviesCardRefs = z
.object({
__typename: z.literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard),
})
.merge(activitiesCardRefSchema)
const hotelPageBlockRefsItem = z.discriminatedUnion("__typename", [
hotelPageActiviesCardRefs,
])
export const hotelPageRefsSchema = z.object({
hotel_page: z.object({
content: discriminatedUnionArray(hotelPageBlockRefsItem.options).nullable(),
faq: accordionRefsSchema.nullable(),
system: systemSchema,
}), }),
}) })

View File

@@ -0,0 +1,142 @@
import { metrics } from "@opentelemetry/api"
import { Lang } from "@/constants/languages"
import { GetHotelPageRefs } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { generateTag, generateTagsFromSystem } from "@/utils/generateTag"
import { hotelPageRefsSchema } from "./output"
import { HotelPageEnum } from "@/types/enums/hotelPage"
import { System } from "@/types/requests/system"
import {
GetHotelPageRefsSchema,
HotelPageRefs,
} from "@/types/trpc/routers/contentstack/hotelPage"
const meter = metrics.getMeter("trpc.hotelPage")
// OpenTelemetry metrics: HotelPage
export const getHotelPageCounter = meter.createCounter(
"trpc.contentstack.hotelPage.get"
)
const getHotelPageRefsCounter = meter.createCounter(
"trpc.contentstack.hotelPage.get"
)
const getHotelPageRefsFailCounter = meter.createCounter(
"trpc.contentstack.hotelPage.get-fail"
)
const getHotelPageRefsSuccessCounter = meter.createCounter(
"trpc.contentstack.hotelPage.get-success"
)
export async function fetchHotelPageRefs(lang: Lang, uid: string) {
getHotelPageRefsCounter.add(1, { lang, uid })
console.info(
"contentstack.hotelPage.refs start",
JSON.stringify({
query: { lang, uid },
})
)
const refsResponse = await request<GetHotelPageRefsSchema>(
GetHotelPageRefs,
{ locale: lang, uid },
{
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
)
if (!refsResponse.data) {
const notFoundError = notFound(refsResponse)
getHotelPageRefsFailCounter.add(1, {
lang,
uid,
error_type: "http_error",
error: JSON.stringify({
code: notFoundError.code,
}),
})
console.error(
"contentstack.hotelPage.refs not found error",
JSON.stringify({
query: {
lang,
uid,
},
error: { code: notFoundError.code },
})
)
throw notFoundError
}
return refsResponse.data
}
export function validateHotelPageRefs(
data: GetHotelPageRefsSchema,
lang: Lang,
uid: string
) {
const validatedData = hotelPageRefsSchema.safeParse(data)
if (!validatedData.success) {
getHotelPageRefsFailCounter.add(1, {
lang,
uid,
error_type: "validation_error",
error: JSON.stringify(validatedData.error),
})
console.error(
"contentstack.hotelPage.refs validation error",
JSON.stringify({
query: { lang, uid },
error: validatedData.error,
})
)
return null
}
getHotelPageRefsSuccessCounter.add(1, { lang, uid })
console.info(
"contentstack.hotelPage.refs success",
JSON.stringify({
query: { lang, uid },
})
)
return validatedData.data
}
export function generatePageTags(
validatedData: HotelPageRefs,
lang: Lang
): string[] {
const connections = getConnections(validatedData)
return [
generateTagsFromSystem(lang, connections),
generateTag(lang, validatedData.hotel_page.system.uid),
].flat()
}
export function getConnections({ hotel_page }: HotelPageRefs) {
const connections: System["system"][] = [hotel_page.system]
if (hotel_page.content) {
hotel_page.content.forEach((block) => {
switch (block.__typename) {
case HotelPageEnum.ContentStack.blocks.ActivitiesCard: {
if (block.upcoming_activities_card.length) {
connections.push(...block.upcoming_activities_card)
}
break
}
}
if (hotel_page.faq) {
connections.push(...hotel_page.faq)
}
})
}
return connections
}

View File

@@ -8,7 +8,7 @@ import { tempImageVaultAssetSchema } from "../imageVault"
import { HotelPageEnum } from "@/types/enums/hotelPage" import { HotelPageEnum } from "@/types/enums/hotelPage"
export const activitiesCard = z.object({ export const activitiesCardSchema = z.object({
typename: z typename: z
.literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard) .literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard)
.optional() .optional()
@@ -57,3 +57,25 @@ export const activitiesCard = z.object({
} }
}), }),
}) })
export const activitiesCardRefSchema = z.object({
upcoming_activities_card: z
.object({
hotel_page_activities_content_pageConnection: z.object({
edges: z.array(
z.object({
node: z.discriminatedUnion("__typename", [
pageLinks.contentPageRefSchema,
]),
})
),
}),
})
.transform((data) => {
return (
data.hotel_page_activities_content_pageConnection.edges.flatMap(
({ node }) => node.system
) || []
)
}),
})

View File

@@ -45,6 +45,10 @@ export const accordionSchema = z
export const accordionRefsSchema = z export const accordionRefsSchema = z
.object({ .object({
__typename: z
.literal(HotelPageEnum.ContentStack.blocks.Faq)
.optional()
.default(HotelPageEnum.ContentStack.blocks.Faq),
global_faqConnection: globalFaqConnectionRefs.optional(), global_faqConnection: globalFaqConnectionRefs.optional(),
specific_faq: specificFaqConnectionRefs.optional(), specific_faq: specificFaqConnectionRefs.optional(),
}) })
@@ -66,5 +70,5 @@ export const accordionRefsSchema = z
) )
) || [] ) || []
) )
return { faq: array.flat(2) } return array.flat(2)
}) })

View File

@@ -1,5 +1,6 @@
import { metrics } from "@opentelemetry/api" import { metrics } from "@opentelemetry/api"
import { Lang } from "@/constants/languages"
import * as api from "@/lib/api" import * as api from "@/lib/api"
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql" import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
import { request } from "@/lib/graphql/request" import { request } from "@/lib/graphql/request"
@@ -18,6 +19,12 @@ import {
import { toApiLang } from "@/server/utils" import { toApiLang } from "@/server/utils"
import { hotelPageSchema } from "../contentstack/hotelPage/output" import { hotelPageSchema } from "../contentstack/hotelPage/output"
import {
fetchHotelPageRefs,
generatePageTags,
getHotelPageCounter,
validateHotelPageRefs,
} from "../contentstack/hotelPage/utils"
import { import {
getHotelInputSchema, getHotelInputSchema,
getHotelsAvailabilityInputSchema, getHotelsAvailabilityInputSchema,
@@ -70,14 +77,38 @@ const roomsAvailabilityFailCounter = meter.createCounter(
"trpc.hotel.availability.rooms-fail" "trpc.hotel.availability.rooms-fail"
) )
async function getContentstackData( async function getContentstackData(lang: Lang, uid?: string | null) {
locale: string, if (!uid) {
uid: string | null | undefined return null
) { }
const response = await request<GetHotelPageData>(GetHotelPage, { const contentPageRefsData = await fetchHotelPageRefs(lang, uid)
locale, const contentPageRefs = validateHotelPageRefs(contentPageRefsData, lang, uid)
uid, if (!contentPageRefs) {
}) return null
}
const tags = generatePageTags(contentPageRefs, lang)
getHotelPageCounter.add(1, { lang, uid })
console.info(
"contentstack.contentPage start",
JSON.stringify({
query: { lang, uid },
})
)
const response = await request<GetHotelPageData>(
GetHotelPage,
{
locale: lang,
uid,
},
{
cache: "force-cache",
next: {
tags,
},
}
)
if (!response.data) { if (!response.data) {
throw notFound(response) throw notFound(response)
@@ -86,7 +117,7 @@ async function getContentstackData(
const hotelPageData = hotelPageSchema.safeParse(response.data) const hotelPageData = hotelPageSchema.safeParse(response.data)
if (!hotelPageData.success) { if (!hotelPageData.success) {
console.error( console.error(
`Failed to validate Hotel Page - (uid: ${uid}, lang: ${locale})` `Failed to validate Hotel Page - (uid: ${uid}, lang: ${lang})`
) )
console.error(hotelPageData.error) console.error(hotelPageData.error)
return null return null

View File

@@ -2,14 +2,19 @@ import { z } from "zod"
import { import {
contentBlock, contentBlock,
hotelPageRefsSchema,
hotelPageSchema, hotelPageSchema,
} from "@/server/routers/contentstack/hotelPage/output" } from "@/server/routers/contentstack/hotelPage/output"
import { activitiesCardSchema } from "@/server/routers/contentstack/schemas/blocks/activitiesCard" import { activitiesCardSchema } from "@/server/routers/contentstack/schemas/blocks/activitiesCard"
// Will be extended once we introduce more functionality to our entries.
export interface GetHotelPageData extends z.input<typeof hotelPageSchema> {} export interface GetHotelPageData extends z.input<typeof hotelPageSchema> {}
export interface HotelPage extends z.output<typeof hotelPageSchema> {} export interface HotelPage extends z.output<typeof hotelPageSchema> {}
export interface ActivitiesCard extends z.output<typeof activitiesCardSchema> {} export interface ActivitiesCard extends z.output<typeof activitiesCardSchema> {}
export type ActivityCard = ActivitiesCard["upcoming_activities_card"] export type ActivityCard = ActivitiesCard["upcoming_activities_card"]
export interface ContentBlock extends z.output<typeof contentBlock> {} export interface ContentBlock extends z.output<typeof contentBlock> {}
export interface GetHotelPageRefsSchema
extends z.input<typeof hotelPageRefsSchema> {}
export interface HotelPageRefs extends z.output<typeof hotelPageRefsSchema> {}