import { cache } from "react" import { createCounter } from "@scandic-hotels/common/telemetry" import { router } from "../../.." import { notFound } from "../../../errors" import { GetContactConfig } from "../../../graphql/Query/ContactConfig.graphql" import { GetCurrentFooter, GetCurrentFooterRef, } from "../../../graphql/Query/Current/Footer.graphql" import { GetCurrentHeader, GetCurrentHeaderRef, } from "../../../graphql/Query/Current/Header.graphql" import { GetFooter, GetFooterRef } from "../../../graphql/Query/Footer.graphql" import { GetHeader, GetHeaderRef } from "../../../graphql/Query/Header.graphql" import { GetSiteConfig, GetSiteConfigRef, } from "../../../graphql/Query/SiteConfig.graphql" // import { router } from "../../.." import { request } from "../../../graphql/request" import { contentstackBaseProcedure } from "../../../procedures" import { langInput } from "../../../utils" import { generateRefsResponseTag, generateTag, generateTags, generateTagsFromSystem, } from "../../../utils/generateTag" import { type ContactConfigData, type CurrentFooterDataRaw, type CurrentFooterRefDataRaw, type CurrentHeaderRefDataRaw, type GetCurrentHeaderData, headerRefsSchema, headerSchema, siteConfigRefSchema, siteConfigSchema, validateContactConfigSchema, validateCurrentFooterConfigSchema, validateCurrentHeaderConfigSchema, validateFooterConfigSchema, validateFooterRefConfigSchema, } from "./output" import { getAlertPhoneContactData, getConnections, getFooterConnections, getSiteConfigConnections, } from "./utils" import type { Lang } from "@scandic-hotels/common/constants/language" import type { FooterDataRaw, FooterRefDataRaw } from "../../../types/footer" import type { GetHeader as GetHeaderData, GetHeaderRefs, } from "../../../types/header" import type { GetSiteConfigData, GetSiteConfigRefData, } from "../../../types/siteConfig" const getContactConfig = cache(async (lang: Lang) => { const getContactConfigCounter = createCounter( "trpc.contentstack", "contactConfig.get" ) const metricsGetContactConfig = getContactConfigCounter.init({ lang }) metricsGetContactConfig.start() const response = await request( GetContactConfig, { locale: lang, }, { key: `${lang}:contact`, ttl: "max", } ) if (!response.data) { const notFoundError = notFound(response) metricsGetContactConfig.noDataError() throw notFoundError } const verifiedData = validateContactConfigSchema.safeParse(response.data) if (!verifiedData.success) { metricsGetContactConfig.validationError(verifiedData.error) return null } metricsGetContactConfig.success() return verifiedData.data.all_contact_config.items[0] }) export const baseQueryRouter = router({ contact: contentstackBaseProcedure.query(async ({ ctx }) => { return await getContactConfig(ctx.lang) }), header: contentstackBaseProcedure.query(async ({ ctx }) => { const { lang } = ctx const getHeaderRefsCounter = createCounter( "trpc.contentstack", "header.get.refs" ) const metricsGetHeaderRefs = getHeaderRefsCounter.init({ lang }) metricsGetHeaderRefs.start() const responseRef = await request( GetHeaderRef, { locale: lang, }, { key: generateRefsResponseTag(lang, "header"), ttl: "max", } ) if (!responseRef.data) { const notFoundError = notFound(responseRef) metricsGetHeaderRefs.noDataError() throw notFoundError } const validatedHeaderRefs = headerRefsSchema.safeParse(responseRef.data) if (!validatedHeaderRefs.success) { metricsGetHeaderRefs.validationError(validatedHeaderRefs.error) return null } metricsGetHeaderRefs.success() const connections = getConnections(validatedHeaderRefs.data) const getHeaderCounter = createCounter("trpc.contentstack", "header.get") const metricsGetHeader = getHeaderCounter.init({ lang }) metricsGetHeader.start() const tags = [ generateTagsFromSystem(lang, connections), generateTag(lang, validatedHeaderRefs.data.header.system.uid), ].flat() const response = await request( GetHeader, { locale: lang }, { key: tags, ttl: "max" } ) if (!response.data) { const notFoundError = notFound(response) metricsGetHeader.noDataError() throw notFoundError } const validatedHeaderConfig = headerSchema.safeParse(response.data) if (!validatedHeaderConfig.success) { metricsGetHeader.validationError(validatedHeaderConfig.error) return null } metricsGetHeader.success() return { data: validatedHeaderConfig.data.header, } }), currentHeader: contentstackBaseProcedure .input(langInput) .query(async ({ input }) => { const getCurrentHeaderRefsCounter = createCounter( "trpc.contentstack", "currentHeader.get.refs" ) const metricsGetCurrentHeaderRefs = getCurrentHeaderRefsCounter.init({ lang: input.lang, }) metricsGetCurrentHeaderRefs.start() const responseRef = await request( GetCurrentHeaderRef, { locale: input.lang, }, { key: generateRefsResponseTag(input.lang, "current_header"), ttl: "max", } ) const getCurrentHeaderCounter = createCounter( "trpc.contentstack", "currentHeader.get" ) const metricsGetCurrentHeader = getCurrentHeaderCounter.init({ lang: input.lang, }) metricsGetCurrentHeader.start() const currentHeaderUID = responseRef.data.all_current_header.items[0].system.uid // There's currently no error handling/validation for the responseRef, should it be added? const response = await request( GetCurrentHeader, { locale: input.lang }, { key: generateTag(input.lang, currentHeaderUID), ttl: "max", } ) if (!response.data) { const notFoundError = notFound(response) metricsGetCurrentHeader.noDataError() throw notFoundError } const validatedHeaderConfig = validateCurrentHeaderConfigSchema.safeParse( response.data ) if (!validatedHeaderConfig.success) { metricsGetCurrentHeader.validationError(validatedHeaderConfig.error) return null } metricsGetCurrentHeader.success() return validatedHeaderConfig.data }), currentFooter: contentstackBaseProcedure .input(langInput) .query(async ({ input }) => { const getCurrentFooterRefsCounter = createCounter( "trpc.contentstack", "currentFooter.get.refs" ) const metricsGetCurrentFooterRefs = getCurrentFooterRefsCounter.init({ lang: input.lang, }) metricsGetCurrentFooterRefs.start() const responseRef = await request( GetCurrentFooterRef, { locale: input.lang, }, { key: generateRefsResponseTag(input.lang, "current_footer"), ttl: "max", } ) const getCurrentFooterCounter = createCounter( "trpc.contentstack", "currentFooter.get" ) const metricsGetCurrentFooter = getCurrentFooterCounter.init({ lang: input.lang, }) metricsGetCurrentFooter.start() const currentFooterUID = responseRef.data.all_current_footer.items[0].system.uid const response = await request( GetCurrentFooter, { locale: input.lang, }, { key: generateTag(input.lang, currentFooterUID), ttl: "max", } ) if (!response.data) { const notFoundError = notFound(response) metricsGetCurrentFooter.noDataError() throw notFoundError } const validatedCurrentFooterConfig = validateCurrentFooterConfigSchema.safeParse(response.data) if (!validatedCurrentFooterConfig.success) { metricsGetCurrentFooter.validationError( validatedCurrentFooterConfig.error ) return null } metricsGetCurrentFooter.success() return validatedCurrentFooterConfig.data.all_current_footer.items[0] }), footer: contentstackBaseProcedure.query(async ({ ctx }) => { const { lang } = ctx const getFooterRefsCounter = createCounter( "trpc.contentstack", "footer.get.refs" ) const metricsGetFooterRefs = getFooterRefsCounter.init({ lang }) metricsGetFooterRefs.start() const responseRef = await request( GetFooterRef, { locale: lang, }, { key: generateRefsResponseTag(lang, "footer"), ttl: "max", } ) if (!responseRef.data) { const notFoundError = notFound(responseRef) metricsGetFooterRefs.noDataError() throw notFoundError } const validatedFooterRefs = validateFooterRefConfigSchema.safeParse( responseRef.data ) if (!validatedFooterRefs.success) { metricsGetFooterRefs.validationError(validatedFooterRefs.error) return null } metricsGetFooterRefs.success() const connections = getFooterConnections(validatedFooterRefs.data) const footerUID = responseRef.data.all_footer.items[0].system.uid const getFooterCounter = createCounter("trpc.contentstack", "footer.get") const metricsGetFooter = getFooterCounter.init({ lang }) metricsGetFooter.start() const tags = [ generateTags(lang, connections), generateTag(lang, footerUID), ].flat() const response = await request( GetFooter, { locale: lang, }, { key: tags, ttl: "max", } ) if (!response.data) { const notFoundError = notFound(response) metricsGetFooter.noDataError() throw notFoundError } const validatedFooterConfig = validateFooterConfigSchema.safeParse( response.data ) if (!validatedFooterConfig.success) { metricsGetFooter.validationError(validatedFooterConfig.error) return null } metricsGetFooter.success() return validatedFooterConfig.data }), siteConfig: contentstackBaseProcedure .input(langInput) .query(async ({ input, ctx }) => { const lang = input.lang ?? ctx.lang const getSiteConfigRefsCounter = createCounter( "trpc.contentstack", "siteConfig.get.refs" ) const metricsGetSiteConfigRefs = getSiteConfigRefsCounter.init({ lang }) metricsGetSiteConfigRefs.start() const responseRef = await request( GetSiteConfigRef, { locale: lang, }, { key: generateRefsResponseTag(lang, "site_config"), ttl: "max", } ) if (!responseRef.data) { const notFoundError = notFound(responseRef) metricsGetSiteConfigRefs.noDataError() throw notFoundError } const validatedSiteConfigRef = siteConfigRefSchema.safeParse( responseRef.data ) if (!validatedSiteConfigRef.success) { metricsGetSiteConfigRefs.validationError(validatedSiteConfigRef.error) return null } const connections = getSiteConfigConnections(validatedSiteConfigRef.data) const siteConfigUid = responseRef.data.all_site_config.items[0].system.uid const tags = [ generateTagsFromSystem(lang, connections), generateTag(lang, siteConfigUid), ].flat() metricsGetSiteConfigRefs.success() const getSiteConfigCounter = createCounter( "trpc.contentstack", "siteConfig.get" ) const metricsGetSiteConfig = getSiteConfigCounter.init({ lang }) metricsGetSiteConfig.start() const [siteConfigResponse, contactConfig] = await Promise.all([ request( GetSiteConfig, { locale: lang, }, { key: tags, ttl: "max", } ), getContactConfig(lang), ]) if (!siteConfigResponse.data) { const notFoundError = notFound(siteConfigResponse) metricsGetSiteConfig.noDataError() throw notFoundError } const validatedSiteConfig = siteConfigSchema.safeParse( siteConfigResponse.data ) if (!validatedSiteConfig.success) { metricsGetSiteConfig.validationError(validatedSiteConfig.error) return null } metricsGetSiteConfig.success() const { sitewideAlert } = validatedSiteConfig.data return { ...validatedSiteConfig.data, sitewideAlert: sitewideAlert ? { ...sitewideAlert, phoneContact: contactConfig ? getAlertPhoneContactData(sitewideAlert, contactConfig) : null, } : null, } }), })