Merge branch 'develop' into feature/tracking
This commit is contained in:
@@ -2,6 +2,10 @@ import { z } from "zod"
|
||||
|
||||
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
|
||||
|
||||
import {
|
||||
accordionRefsSchema,
|
||||
accordionSchema,
|
||||
} from "../schemas/blocks/accordion"
|
||||
import {
|
||||
cardGridRefsSchema,
|
||||
cardsGridSchema,
|
||||
@@ -81,8 +85,14 @@ export const contentPageTable = z
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Table),
|
||||
})
|
||||
.merge(tableSchema)
|
||||
export const contentPageAccordion = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Accordion),
|
||||
})
|
||||
.merge(accordionSchema)
|
||||
|
||||
export const blocksSchema = z.discriminatedUnion("__typename", [
|
||||
contentPageAccordion,
|
||||
contentPageCards,
|
||||
contentPageContent,
|
||||
contentPageDynamicContent,
|
||||
@@ -158,6 +168,12 @@ export const contentPageSchema = z.object({
|
||||
}),
|
||||
})
|
||||
|
||||
export const contentPageSchemaBlocks = z.object({
|
||||
content_page: z.object({
|
||||
blocks: discriminatedUnionArray(blocksSchema.options).nullable(),
|
||||
}),
|
||||
})
|
||||
|
||||
/** REFS */
|
||||
const contentPageCardsRefs = z
|
||||
.object({
|
||||
@@ -195,7 +211,14 @@ const contentPageUspGridRefs = z
|
||||
})
|
||||
.merge(uspGridRefsSchema)
|
||||
|
||||
const contentPageAccordionRefs = z
|
||||
.object({
|
||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Accordion),
|
||||
})
|
||||
.merge(accordionRefsSchema)
|
||||
|
||||
const contentPageBlockRefsItem = z.discriminatedUnion("__typename", [
|
||||
contentPageAccordionRefs,
|
||||
contentPageBlockContentRefs,
|
||||
contentPageShortcutsRefs,
|
||||
contentPageCardsRefs,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Lang } from "@/constants/languages"
|
||||
import {
|
||||
GetContentPage,
|
||||
GetContentPageBlocks,
|
||||
GetContentPageBlocksBatch1,
|
||||
GetContentPageBlocksBatch2,
|
||||
} from "@/lib/graphql/Query/ContentPage/ContentPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
|
||||
@@ -25,6 +26,7 @@ export const contentPageQueryRouter = router({
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const contentPageRefsData = await fetchContentPageRefs(lang, uid)
|
||||
|
||||
const contentPageRefs = validateContentPageRefs(
|
||||
contentPageRefsData,
|
||||
lang,
|
||||
@@ -33,6 +35,7 @@ export const contentPageQueryRouter = router({
|
||||
if (!contentPageRefs) {
|
||||
return null
|
||||
}
|
||||
|
||||
const tags = generatePageTags(contentPageRefs, lang)
|
||||
|
||||
getContentPageCounter.add(1, { lang, uid })
|
||||
@@ -43,7 +46,7 @@ export const contentPageQueryRouter = router({
|
||||
})
|
||||
)
|
||||
|
||||
const [mainResponse, blocksResponse] = await Promise.all([
|
||||
const [mainResponse, blocksResponse1, blocksResponse2] = await Promise.all([
|
||||
request<GetContentPageSchema>(
|
||||
GetContentPage,
|
||||
{ locale: lang, uid },
|
||||
@@ -55,7 +58,17 @@ export const contentPageQueryRouter = router({
|
||||
}
|
||||
),
|
||||
request<GetContentPageSchema>(
|
||||
GetContentPageBlocks,
|
||||
GetContentPageBlocksBatch1,
|
||||
{ locale: lang, uid },
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags,
|
||||
},
|
||||
}
|
||||
),
|
||||
request<GetContentPageSchema>(
|
||||
GetContentPageBlocksBatch2,
|
||||
{ locale: lang, uid },
|
||||
{
|
||||
cache: "force-cache",
|
||||
@@ -70,7 +83,12 @@ export const contentPageQueryRouter = router({
|
||||
...mainResponse.data,
|
||||
content_page: {
|
||||
...mainResponse.data.content_page,
|
||||
blocks: blocksResponse.data.content_page.blocks,
|
||||
blocks: [
|
||||
blocksResponse1.data.content_page.blocks,
|
||||
blocksResponse2.data.content_page.blocks,
|
||||
]
|
||||
.flat(2)
|
||||
.filter((obj) => !(obj && Object.keys(obj).length < 2)), // Remove empty objects and objects with only typename
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,12 @@ export function getConnections({ content_page }: ContentPageRefs) {
|
||||
if (content_page.blocks) {
|
||||
content_page.blocks.forEach((block) => {
|
||||
switch (block.__typename) {
|
||||
case ContentPageEnum.ContentStack.blocks.Accordion: {
|
||||
if (block.accordion.length) {
|
||||
connections.push(...block.accordion)
|
||||
}
|
||||
break
|
||||
}
|
||||
case ContentPageEnum.ContentStack.blocks.Content:
|
||||
{
|
||||
if (block.content.length) {
|
||||
|
||||
@@ -2,7 +2,12 @@ import { z } from "zod"
|
||||
|
||||
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
|
||||
|
||||
import { activitiesCard } from "../schemas/blocks/activitiesCard"
|
||||
import {
|
||||
activitiesCardRefSchema,
|
||||
activitiesCardSchema,
|
||||
} from "../schemas/blocks/activitiesCard"
|
||||
import { hotelFaqRefsSchema, hotelFaqSchema } from "../schemas/blocks/hotelFaq"
|
||||
import { systemSchema } from "../schemas/system"
|
||||
|
||||
import { HotelPageEnum } from "@/types/enums/hotelPage"
|
||||
|
||||
@@ -10,7 +15,7 @@ const contentBlockActivities = z
|
||||
.object({
|
||||
__typename: z.literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard),
|
||||
})
|
||||
.merge(activitiesCard)
|
||||
.merge(activitiesCardSchema)
|
||||
|
||||
export const contentBlock = z.discriminatedUnion("__typename", [
|
||||
contentBlockActivities,
|
||||
@@ -19,9 +24,35 @@ export const contentBlock = z.discriminatedUnion("__typename", [
|
||||
export const hotelPageSchema = z.object({
|
||||
hotel_page: z.object({
|
||||
content: discriminatedUnionArray(contentBlock.options).nullable(),
|
||||
faq: hotelFaqSchema,
|
||||
hotel_page_id: z.string(),
|
||||
title: 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: hotelFaqRefsSchema.nullable(),
|
||||
system: systemSchema,
|
||||
}),
|
||||
trackingProps: z.object({
|
||||
url: z.string(),
|
||||
|
||||
142
server/routers/contentstack/hotelPage/utils.ts
Normal file
142
server/routers/contentstack/hotelPage/utils.ts
Normal 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
|
||||
}
|
||||
@@ -97,6 +97,8 @@ const getAllCachedApiRewards = unstable_cache(
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
throw apiResponse
|
||||
}
|
||||
|
||||
const data = await apiResponse.json()
|
||||
@@ -114,7 +116,7 @@ const getAllCachedApiRewards = unstable_cache(
|
||||
error: validatedApiTierRewards.error,
|
||||
})
|
||||
)
|
||||
return null
|
||||
throw validatedApiTierRewards.error
|
||||
}
|
||||
|
||||
return validatedApiTierRewards.data
|
||||
|
||||
188
server/routers/contentstack/schemas/blocks/accordion.ts
Normal file
188
server/routers/contentstack/schemas/blocks/accordion.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
|
||||
export const accordionItemsSchema = z.array(
|
||||
z.object({
|
||||
question: z.string(),
|
||||
answer: z.object({
|
||||
json: z.any(), // JSON
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z
|
||||
.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageSchema,
|
||||
pageLinks.contentPageSchema,
|
||||
pageLinks.hotelPageSchema,
|
||||
pageLinks.loyaltyPageSchema,
|
||||
])
|
||||
.transform((data) => {
|
||||
const link = pageLinks.transform(data)
|
||||
if (link) {
|
||||
return link
|
||||
}
|
||||
return data
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
||||
export type Accordion = z.infer<typeof accordionSchema>
|
||||
|
||||
enum AccordionEnum {
|
||||
ContentPageBlocksAccordionBlockAccordionsGlobalAccordion = "ContentPageBlocksAccordionBlockAccordionsGlobalAccordion",
|
||||
ContentPageBlocksAccordionBlockAccordionsSpecificAccordion = "ContentPageBlocksAccordionBlockAccordionsSpecificAccordion",
|
||||
}
|
||||
|
||||
export const accordionSchema = z.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.Accordion)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.Accordion),
|
||||
accordion: z
|
||||
.object({
|
||||
title: z.string().optional().default(""),
|
||||
accordions: z.array(
|
||||
z.object({
|
||||
__typename: z.enum([
|
||||
AccordionEnum.ContentPageBlocksAccordionBlockAccordionsGlobalAccordion,
|
||||
AccordionEnum.ContentPageBlocksAccordionBlockAccordionsSpecificAccordion,
|
||||
]),
|
||||
global_accordion: z
|
||||
.object({
|
||||
global_accordionConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
questions: accordionItemsSchema,
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
specific_accordion: z
|
||||
.object({
|
||||
questions: accordionItemsSchema,
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
return {
|
||||
...data,
|
||||
accordions: data.accordions.flatMap((acc) => {
|
||||
switch (acc.__typename) {
|
||||
case AccordionEnum.ContentPageBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
return (
|
||||
acc.global_accordion?.global_accordionConnection.edges.flatMap(
|
||||
({ node: accordionConnection }) => {
|
||||
return accordionConnection.questions
|
||||
}
|
||||
) || []
|
||||
)
|
||||
case AccordionEnum.ContentPageBlocksAccordionBlockAccordionsSpecificAccordion:
|
||||
return acc.specific_accordion?.questions || []
|
||||
}
|
||||
}),
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const actualRefs = z.discriminatedUnion("__typename", [
|
||||
pageLinks.accountPageRefSchema,
|
||||
pageLinks.contentPageRefSchema,
|
||||
pageLinks.hotelPageRefSchema,
|
||||
pageLinks.loyaltyPageRefSchema,
|
||||
])
|
||||
|
||||
export const globalAccordionConnectionRefs = z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
questions: z.array(
|
||||
z.object({
|
||||
answer: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: actualRefs,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export const specificAccordionConnectionRefs = z.object({
|
||||
questions: z.array(
|
||||
z.object({
|
||||
answer: z.object({
|
||||
embedded_itemsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: actualRefs,
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export const accordionRefsSchema = z.object({
|
||||
accordion: z
|
||||
.object({
|
||||
accordions: z.array(
|
||||
z.object({
|
||||
__typename: z.enum([
|
||||
AccordionEnum.ContentPageBlocksAccordionBlockAccordionsGlobalAccordion,
|
||||
AccordionEnum.ContentPageBlocksAccordionBlockAccordionsSpecificAccordion,
|
||||
]),
|
||||
global_accordion: z
|
||||
.object({
|
||||
global_accordionConnection: globalAccordionConnectionRefs,
|
||||
})
|
||||
.optional(),
|
||||
specific_accordion: specificAccordionConnectionRefs.optional(),
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
return data.accordions.flatMap((accordion) => {
|
||||
switch (accordion.__typename) {
|
||||
case AccordionEnum.ContentPageBlocksAccordionBlockAccordionsGlobalAccordion:
|
||||
return (
|
||||
accordion.global_accordion?.global_accordionConnection.edges.flatMap(
|
||||
({ node: accordionConnection }) => {
|
||||
return accordionConnection.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
)
|
||||
}
|
||||
) || []
|
||||
)
|
||||
case AccordionEnum.ContentPageBlocksAccordionBlockAccordionsSpecificAccordion:
|
||||
return (
|
||||
accordion.specific_accordion?.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
) || []
|
||||
)
|
||||
}
|
||||
})
|
||||
}),
|
||||
})
|
||||
@@ -8,7 +8,7 @@ import { tempImageVaultAssetSchema } from "../imageVault"
|
||||
|
||||
import { HotelPageEnum } from "@/types/enums/hotelPage"
|
||||
|
||||
export const activitiesCard = z.object({
|
||||
export const activitiesCardSchema = z.object({
|
||||
typename: z
|
||||
.literal(HotelPageEnum.ContentStack.blocks.ActivitiesCard)
|
||||
.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
|
||||
) || []
|
||||
)
|
||||
}),
|
||||
})
|
||||
|
||||
75
server/routers/contentstack/schemas/blocks/hotelFaq.ts
Normal file
75
server/routers/contentstack/schemas/blocks/hotelFaq.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import {
|
||||
accordionItemsSchema,
|
||||
globalAccordionConnectionRefs,
|
||||
specificAccordionConnectionRefs,
|
||||
} from "./accordion"
|
||||
|
||||
import { BlocksEnums } from "@/types/enums/blocks"
|
||||
import { HotelPageEnum } from "@/types/enums/hotelPage"
|
||||
|
||||
export const hotelFaqSchema = z
|
||||
.object({
|
||||
typename: z
|
||||
.literal(BlocksEnums.block.Accordion)
|
||||
.optional()
|
||||
.default(BlocksEnums.block.Accordion),
|
||||
title: z.string().optional().default(""),
|
||||
global_faqConnection: z
|
||||
.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
questions: accordionItemsSchema,
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
.optional(),
|
||||
specific_faq: z
|
||||
.object({
|
||||
questions: accordionItemsSchema,
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.transform((data) => {
|
||||
const array = []
|
||||
array.push(
|
||||
data.global_faqConnection?.edges.flatMap(({ node: faqConnection }) => {
|
||||
return faqConnection.questions
|
||||
}) || []
|
||||
)
|
||||
array.push(data.specific_faq?.questions || [])
|
||||
return { ...data, accordions: array.flat(2) }
|
||||
})
|
||||
|
||||
export const hotelFaqRefsSchema = z
|
||||
.object({
|
||||
__typename: z
|
||||
.literal(HotelPageEnum.ContentStack.blocks.Faq)
|
||||
.optional()
|
||||
.default(HotelPageEnum.ContentStack.blocks.Faq),
|
||||
global_faqConnection: globalAccordionConnectionRefs.optional(),
|
||||
specific_faq: specificAccordionConnectionRefs.optional(),
|
||||
})
|
||||
.transform((data) => {
|
||||
const array = []
|
||||
array.push(
|
||||
data.global_faqConnection?.edges.flatMap(({ node: faqConnection }) => {
|
||||
return faqConnection.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
)
|
||||
}) || []
|
||||
)
|
||||
array.push(
|
||||
data.specific_faq?.questions.flatMap((question) =>
|
||||
question.answer.embedded_itemsConnection.edges.flatMap(
|
||||
({ node }) => node.system
|
||||
)
|
||||
) || []
|
||||
)
|
||||
return array.flat(2)
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { metrics } from "@opentelemetry/api"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import * as api from "@/lib/api"
|
||||
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
@@ -18,6 +19,12 @@ import {
|
||||
import { toApiLang } from "@/server/utils"
|
||||
|
||||
import { hotelPageSchema } from "../contentstack/hotelPage/output"
|
||||
import {
|
||||
fetchHotelPageRefs,
|
||||
generatePageTags,
|
||||
getHotelPageCounter,
|
||||
validateHotelPageRefs,
|
||||
} from "../contentstack/hotelPage/utils"
|
||||
import {
|
||||
getHotelInputSchema,
|
||||
getHotelsAvailabilityInputSchema,
|
||||
@@ -70,14 +77,38 @@ const roomsAvailabilityFailCounter = meter.createCounter(
|
||||
"trpc.hotel.availability.rooms-fail"
|
||||
)
|
||||
|
||||
async function getContentstackData(
|
||||
locale: string,
|
||||
uid: string | null | undefined
|
||||
) {
|
||||
const response = await request<GetHotelPageData>(GetHotelPage, {
|
||||
locale,
|
||||
uid,
|
||||
})
|
||||
async function getContentstackData(lang: Lang, uid?: string | null) {
|
||||
if (!uid) {
|
||||
return null
|
||||
}
|
||||
const contentPageRefsData = await fetchHotelPageRefs(lang, uid)
|
||||
const contentPageRefs = validateHotelPageRefs(contentPageRefsData, lang, uid)
|
||||
if (!contentPageRefs) {
|
||||
return null
|
||||
}
|
||||
|
||||
const tags = generatePageTags(contentPageRefs, lang)
|
||||
|
||||
getHotelPageCounter.add(1, { lang, uid })
|
||||
console.info(
|
||||
"contentstack.hotelPage start",
|
||||
JSON.stringify({
|
||||
query: { lang, uid },
|
||||
})
|
||||
)
|
||||
const response = await request<GetHotelPageData>(
|
||||
GetHotelPage,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
throw notFound(response)
|
||||
@@ -86,7 +117,7 @@ async function getContentstackData(
|
||||
const hotelPageData = hotelPageSchema.safeParse(response.data)
|
||||
if (!hotelPageData.success) {
|
||||
console.error(
|
||||
`Failed to validate Hotel Page - (uid: ${uid}, lang: ${locale})`
|
||||
`Failed to validate Hotel Page - (uid: ${uid}, lang: ${lang})`
|
||||
)
|
||||
console.error(hotelPageData.error)
|
||||
return null
|
||||
@@ -101,6 +132,7 @@ export const hotelQueryRouter = router({
|
||||
.query(async ({ ctx, input }) => {
|
||||
const { lang, uid } = ctx
|
||||
const { include } = input
|
||||
|
||||
const contentstackData = await getContentstackData(lang, uid)
|
||||
const hotelId = contentstackData?.hotel_page_id
|
||||
|
||||
@@ -230,6 +262,7 @@ export const hotelQueryRouter = router({
|
||||
roomCategories,
|
||||
activitiesCard: activities?.upcoming_activities_card,
|
||||
facilities,
|
||||
faq: contentstackData?.faq,
|
||||
}
|
||||
}),
|
||||
availability: router({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { metrics } from "@opentelemetry/api"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { env } from "@/env/server"
|
||||
import * as api from "@/lib/api"
|
||||
@@ -9,7 +10,9 @@ import type { FriendTransaction, Stay } from "./output"
|
||||
|
||||
const meter = metrics.getMeter("trpc.user")
|
||||
const getProfileCounter = meter.createCounter("trpc.user.profile")
|
||||
const getProfileSuccessCounter = meter.createCounter("trpc.user.profile-success")
|
||||
const getProfileSuccessCounter = meter.createCounter(
|
||||
"trpc.user.profile-success"
|
||||
)
|
||||
const getProfileFailCounter = meter.createCounter("trpc.user.profile-fail")
|
||||
|
||||
async function updateStaysBookingUrl(
|
||||
@@ -41,7 +44,7 @@ async function updateStaysBookingUrl(
|
||||
// Temporary Url, domain and lang support for current web
|
||||
const bookingUrl = new URL(
|
||||
"/hotelreservation/my-booking",
|
||||
env.PUBLIC_URL ?? ""
|
||||
env.PUBLIC_URL || "https://www.scandichotels.com" // fallback to production for ephemeral envs (like deploy previews)
|
||||
)
|
||||
switch (lang) {
|
||||
case Lang.sv:
|
||||
@@ -83,10 +86,7 @@ async function updateStaysBookingUrl(
|
||||
}
|
||||
|
||||
getProfileSuccessCounter.add(1)
|
||||
console.info(
|
||||
"api.user.profile updatebookingurl success",
|
||||
JSON.stringify({})
|
||||
)
|
||||
console.info("api.user.profile updatebookingurl success", JSON.stringify({}))
|
||||
|
||||
return data.map((d) => {
|
||||
const originalString =
|
||||
@@ -98,10 +98,7 @@ async function updateStaysBookingUrl(
|
||||
bookingUrl.searchParams.set("RefId", encryptedBookingValue)
|
||||
} else {
|
||||
bookingUrl.searchParams.set("lastName", apiJson.data.attributes.lastName)
|
||||
bookingUrl.searchParams.set(
|
||||
"bookingId",
|
||||
d.attributes.confirmationNumber
|
||||
)
|
||||
bookingUrl.searchParams.set("bookingId", d.attributes.confirmationNumber)
|
||||
}
|
||||
return {
|
||||
...d,
|
||||
@@ -113,4 +110,4 @@ async function updateStaysBookingUrl(
|
||||
})
|
||||
}
|
||||
|
||||
export { updateStaysBookingUrl }
|
||||
export { updateStaysBookingUrl }
|
||||
|
||||
Reference in New Issue
Block a user