import { GetCityPageCount } from "@/lib/graphql/Query/DestinationCityPage/DestinationCityPageCount.graphql" import { GetCityPageUrls } from "@/lib/graphql/Query/DestinationCityPage/DestinationCityPageUrl.graphql" import { request } from "@/lib/graphql/request" import { generateTag, generateTagsFromSystem } from "@/utils/generateTag" import { batchedCityPageUrlsSchema, cityPageCountSchema } from "./output" import { getCityPageCountCounter, getCityPageCountFailCounter, getCityPageCountSuccessCounter, getCityPageUrlsCounter, getCityPageUrlsFailCounter, getCityPageUrlsSuccessCounter, } from "./telemetry" import { DestinationCityPageEnum } from "@/types/enums/destinationCityPage" import type { System } from "@/types/requests/system" import type { DestinationCityPageRefs, GetCityPageCountData, GetCityPageUrlsData, } from "@/types/trpc/routers/contentstack/destinationCityPage" import type { Lang } from "@/constants/languages" export function generatePageTags( validatedData: DestinationCityPageRefs, lang: Lang ): string[] { const connections = getConnections(validatedData) return [ // This tag is added for the city list data on country pages to invalidate the list when city page changes. generateTag( lang, `city_list_data:${validatedData.destination_city_page.destination_settings.city}` ), generateTagsFromSystem(lang, connections), generateTag(lang, validatedData.destination_city_page.system.uid), ].flat() } export function getConnections({ destination_city_page, }: DestinationCityPageRefs) { const connections: System["system"][] = [destination_city_page.system] if (destination_city_page.blocks) { destination_city_page.blocks.forEach((block) => { switch (block.__typename) { case DestinationCityPageEnum.ContentStack.blocks.Accordion: { if (block.accordion.length) { connections.push(...block.accordion) } break } case DestinationCityPageEnum.ContentStack.blocks.Content: { if (block.content.length) { // TS has trouble infering the filtered types // @ts-ignore connections.push(...block.content) } } break } }) } if (destination_city_page.sidepeek_content) { destination_city_page.sidepeek_content.content.embedded_itemsConnection.edges.forEach( ({ node }) => { connections.push(node.system) } ) } return connections } export async function getCityPageCount(lang: Lang) { getCityPageCountCounter.add(1, { lang }) console.info( "contentstack.cityPageCount start", JSON.stringify({ query: { lang } }) ) const response = await request( GetCityPageCount, { locale: lang, }, { key: `${lang}:city_page_count`, ttl: "max", } ) if (!response.data) { getCityPageCountFailCounter.add(1, { lang, error_type: "not_found", error: `City pages count not found for lang: ${lang}`, }) console.error( "contentstack.cityPageCount not found error", JSON.stringify({ query: { lang } }) ) return 0 } const validatedResponse = cityPageCountSchema.safeParse(response.data) if (!validatedResponse.success) { getCityPageCountFailCounter.add(1, { lang, error_type: "validation_error", error: JSON.stringify(validatedResponse.error), }) console.error( "contentstack.hotelPageCount validation error", JSON.stringify({ query: { lang }, error: validatedResponse.error, }) ) return 0 } getCityPageCountSuccessCounter.add(1, { lang }) console.info( "contentstack.cityPageCount success", JSON.stringify({ query: { lang } }) ) return validatedResponse.data } export async function getCityPageUrls(lang: Lang) { getCityPageUrlsCounter.add(1, { lang }) console.info( "contentstack.cityPageUrls start", JSON.stringify({ query: { lang } }) ) const count = await getCityPageCount(lang) if (count === 0) { return [] } // Calculating the amount of requests needed to fetch all pages. // Contentstack has a limit of 100 items per request. // So we need to make multiple requests to fetch urls to all pages. // The `batchRequest` function is not working here, because the arrayMerge is // used for other purposes. const amountOfRequests = Math.ceil(count / 100) const batchedResponse = await Promise.all( Array.from({ length: amountOfRequests }).map((_, i) => request( GetCityPageUrls, { locale: lang, skip: i * 100 }, { key: `${lang}:city_page_urls_batch_${i}`, ttl: "max" } ) ) ) const validatedResponse = batchedCityPageUrlsSchema.safeParse(batchedResponse) if (!validatedResponse.success) { getCityPageUrlsFailCounter.add(1, { lang, error_type: "validation_error", error: JSON.stringify(validatedResponse.error), }) console.error( "contentstack.cityPageUrls validation error", JSON.stringify({ query: { lang }, error: validatedResponse.error, }) ) return [] } getCityPageUrlsSuccessCounter.add(1, { lang }) console.info( "contentstack.cityPageUrls success", JSON.stringify({ query: { lang } }) ) return validatedResponse.data }