Feat/BOOK-424 campaign banner
Approved-by: Bianca Widstam
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
overflow-y: auto;
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
position: fixed;
|
||||
top: calc(140px + max(var(--sitewide-alert-height), 25px));
|
||||
top: calc(140px + max(var(--alert-and-banner-height), 25px));
|
||||
width: 100%;
|
||||
height: calc(100% - 200px);
|
||||
z-index: 10010;
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
.container[data-datepicker-open="true"] .hideWrapper {
|
||||
border-radius: var(--Corner-radius-lg) var(--Corner-radius-lg) 0 0;
|
||||
top: calc(max(var(--sitewide-alert-height), 20px));
|
||||
top: calc(max(var(--alert-and-banner-height), 20px));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
background-color: var(--UI-Input-Controls-Surface-Normal);
|
||||
border-radius: 0;
|
||||
gap: var(--Spacing-x3);
|
||||
height: calc(100dvh - max(var(--sitewide-alert-height), 20px));
|
||||
height: calc(100dvh - max(var(--alert-and-banner-height), 20px));
|
||||
width: 100%;
|
||||
padding: var(--Spacing-x3) var(--Spacing-x2) var(--Spacing-x7);
|
||||
position: fixed;
|
||||
|
||||
82
packages/trpc/lib/graphql/Fragments/Banner.graphql
Normal file
82
packages/trpc/lib/graphql/Fragments/Banner.graphql
Normal file
@@ -0,0 +1,82 @@
|
||||
#import "./PageLink/AccountPageLink.graphql"
|
||||
#import "./PageLink/CampaignOverviewPageLink.graphql"
|
||||
#import "./PageLink/CampaignPageLink.graphql"
|
||||
#import "./PageLink/CollectionPageLink.graphql"
|
||||
#import "./PageLink/ContentPageLink.graphql"
|
||||
#import "./PageLink/DestinationCityPageLink.graphql"
|
||||
#import "./PageLink/DestinationCountryPageLink.graphql"
|
||||
#import "./PageLink/DestinationOverviewPageLink.graphql"
|
||||
#import "./PageLink/HotelPageLink.graphql"
|
||||
#import "./PageLink/LoyaltyPageLink.graphql"
|
||||
#import "./PageLink/StartPageLink.graphql"
|
||||
#import "./PageLink/PromoCampaignPageLink.graphql"
|
||||
|
||||
#import "./AccountPage/Ref.graphql"
|
||||
#import "./CampaignOverviewPage/Ref.graphql"
|
||||
#import "./CampaignPage/Ref.graphql"
|
||||
#import "./CollectionPage/Ref.graphql"
|
||||
#import "./ContentPage/Ref.graphql"
|
||||
#import "./DestinationCityPage/Ref.graphql"
|
||||
#import "./DestinationCountryPage/Ref.graphql"
|
||||
#import "./DestinationOverviewPage/Ref.graphql"
|
||||
#import "./HotelPage/Ref.graphql"
|
||||
#import "./LoyaltyPage/Ref.graphql"
|
||||
#import "./StartPage/Ref.graphql"
|
||||
#import "./PromoCampaignPage/Ref.graphql"
|
||||
|
||||
fragment Banner on Banner {
|
||||
tag
|
||||
text
|
||||
link {
|
||||
title
|
||||
linkConnection {
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
...AccountPageLink
|
||||
...CampaignOverviewPageLink
|
||||
...CampaignPageLink
|
||||
...CollectionPageLink
|
||||
...ContentPageLink
|
||||
...DestinationCityPageLink
|
||||
...DestinationCountryPageLink
|
||||
...DestinationOverviewPageLink
|
||||
...HotelPageLink
|
||||
...LoyaltyPageLink
|
||||
...StartPageLink
|
||||
...PromoCampaignPageLink
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
booking_code
|
||||
visible_on
|
||||
}
|
||||
|
||||
fragment BannerRef on Banner {
|
||||
link {
|
||||
linkConnection {
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
...AccountPageRef
|
||||
...CampaignOverviewPageRef
|
||||
...CampaignPageRef
|
||||
...CollectionPageRef
|
||||
...ContentPageRef
|
||||
...DestinationCityPageRef
|
||||
...DestinationCountryPageRef
|
||||
...DestinationOverviewPageRef
|
||||
...HotelPageRef
|
||||
...LoyaltyPageRef
|
||||
...StartPageRef
|
||||
...PromoCampaignPageRef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
visible_on
|
||||
system {
|
||||
...System
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#import "../Fragments/System.graphql"
|
||||
|
||||
#import "../Fragments/Banner.graphql"
|
||||
|
||||
query GetSitewideCampaignBanner($locale: String!) {
|
||||
all_sitewide_campaign_banner(limit: 1, locale: $locale) {
|
||||
items {
|
||||
bannerConnection {
|
||||
edges {
|
||||
node {
|
||||
...Banner
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query GetSitewideCampaignBannerRef($locale: String!) {
|
||||
all_sitewide_campaign_banner(limit: 1, locale: $locale) {
|
||||
items {
|
||||
bannerConnection {
|
||||
edges {
|
||||
node {
|
||||
...BannerRef
|
||||
}
|
||||
}
|
||||
}
|
||||
system {
|
||||
...System
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
transformCardBlock,
|
||||
transformCardBlockRefs,
|
||||
} from "../schemas/blocks/cardsGrid"
|
||||
import { linkConnectionRefsSchema } from "../schemas/blocks/utils/linkConnection"
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
@@ -594,7 +595,7 @@ export const alertSchema = z
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
visible_on: z.array(z.string()).nullable().default([]),
|
||||
visible_on: z.array(z.string()).nullish().default([]),
|
||||
})
|
||||
.transform(
|
||||
({
|
||||
@@ -673,13 +674,12 @@ export const siteConfigSchema = z
|
||||
}
|
||||
}
|
||||
|
||||
const { sitewide_alert } = data.all_site_config.items[0]
|
||||
|
||||
const sitewideAlertWeb = sitewide_alert.alerts?.find((alert) =>
|
||||
alert.alertConnection.edges[0]?.node.visible_on?.includes(
|
||||
AlertVisibleOnEnum.WEB
|
||||
const sitewideAlertWeb =
|
||||
data.all_site_config.items[0].sitewide_alert.alerts?.find((alert) =>
|
||||
alert.alertConnection.edges[0]?.node.visible_on?.includes(
|
||||
AlertVisibleOnEnum.WEB
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return {
|
||||
sitewideAlert: sitewideAlertWeb?.alertConnection.edges[0]?.node || null,
|
||||
@@ -709,7 +709,7 @@ const alertConnectionRefSchema = z.object({
|
||||
}),
|
||||
})
|
||||
),
|
||||
visible_on: z.array(z.string()).nullable().default([]),
|
||||
visible_on: z.array(z.string()).nullish().default([]),
|
||||
})
|
||||
|
||||
export const siteConfigRefSchema = z.object({
|
||||
@@ -737,3 +737,98 @@ export const siteConfigRefSchema = z.object({
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
const bannerSchema = z
|
||||
.object({
|
||||
tag: z.string(),
|
||||
text: z.string(),
|
||||
link: linkAndTitleSchema,
|
||||
booking_code: z.string().nullish(),
|
||||
visible_on: z.array(z.string()).nullish().default([]),
|
||||
})
|
||||
.transform(({ tag, text, link, visible_on, booking_code }) => {
|
||||
const linkUrl = link.link?.url || null
|
||||
return {
|
||||
tag,
|
||||
text,
|
||||
link: linkUrl
|
||||
? {
|
||||
url: linkUrl,
|
||||
title: link.title,
|
||||
}
|
||||
: null,
|
||||
booking_code,
|
||||
visible_on,
|
||||
}
|
||||
})
|
||||
|
||||
const bannerRefSchema = z
|
||||
.object({
|
||||
link: linkConnectionRefsSchema,
|
||||
visible_on: z.array(z.string()).nullish().default([]),
|
||||
system: systemSchema,
|
||||
})
|
||||
.transform(({ link, visible_on, system }) => {
|
||||
return {
|
||||
linkSystem: link,
|
||||
visible_on,
|
||||
system,
|
||||
}
|
||||
})
|
||||
|
||||
export const sitewideCampaignBannerSchema = z
|
||||
.object({
|
||||
all_sitewide_campaign_banner: z.object({
|
||||
items: z
|
||||
.array(
|
||||
z.object({
|
||||
bannerConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: bannerSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.max(1),
|
||||
}),
|
||||
})
|
||||
.transform((data) => {
|
||||
if (!data.all_sitewide_campaign_banner.items.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const sitewideCampaignBannerWeb =
|
||||
data.all_sitewide_campaign_banner.items[0].bannerConnection.edges.find(
|
||||
(banner) => banner.node.visible_on?.includes(AlertVisibleOnEnum.WEB)
|
||||
)
|
||||
|
||||
return sitewideCampaignBannerWeb?.node ?? null
|
||||
})
|
||||
|
||||
export const sitewideCampaignBannerRefSchema = z.object({
|
||||
all_sitewide_campaign_banner: z
|
||||
.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
bannerConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: bannerRefSchema,
|
||||
})
|
||||
),
|
||||
}),
|
||||
system: systemSchema,
|
||||
})
|
||||
),
|
||||
})
|
||||
.transform((data) => {
|
||||
const webBanner = data.items.find((item) => {
|
||||
const bannerNode = item.bannerConnection.edges[0]?.node
|
||||
return bannerNode?.visible_on?.includes(AlertVisibleOnEnum.WEB)
|
||||
})
|
||||
|
||||
return webBanner ?? null
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -11,7 +11,10 @@ import {
|
||||
GetSiteConfig,
|
||||
GetSiteConfigRef,
|
||||
} from "../../../graphql/Query/SiteConfig.graphql"
|
||||
// import { router } from "../../.."
|
||||
import {
|
||||
GetSitewideCampaignBanner,
|
||||
GetSitewideCampaignBannerRef,
|
||||
} from "../../../graphql/Query/SitewideCampaignBanner.graphql"
|
||||
import { request } from "../../../graphql/request"
|
||||
import { contentstackBaseProcedure } from "../../../procedures"
|
||||
import { langInput } from "../../../utils"
|
||||
@@ -27,6 +30,8 @@ import {
|
||||
headerSchema,
|
||||
siteConfigRefSchema,
|
||||
siteConfigSchema,
|
||||
sitewideCampaignBannerRefSchema,
|
||||
sitewideCampaignBannerSchema,
|
||||
validateContactConfigSchema,
|
||||
validateFooterConfigSchema,
|
||||
validateFooterRefConfigSchema,
|
||||
@@ -36,6 +41,7 @@ import {
|
||||
getConnections,
|
||||
getFooterConnections,
|
||||
getSiteConfigConnections,
|
||||
getSitewideCampaignBannerConnections,
|
||||
} from "./utils"
|
||||
|
||||
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||
@@ -48,6 +54,8 @@ import type {
|
||||
import type {
|
||||
GetSiteConfigData,
|
||||
GetSiteConfigRefData,
|
||||
GetSitewideCampaignBannerData,
|
||||
GetSitewideCampaignBannerRefData,
|
||||
} from "../../../types/siteConfig"
|
||||
|
||||
const getContactConfig = cache(async (lang: Lang) => {
|
||||
@@ -248,6 +256,97 @@ export const baseQueryRouter = router({
|
||||
|
||||
return validatedFooterConfig.data
|
||||
}),
|
||||
sitewideCampaignBanner: router({
|
||||
get: contentstackBaseProcedure
|
||||
.input(langInput)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const lang = input.lang ?? ctx.lang
|
||||
|
||||
const getSitewideCampaignBannerRefsCounter = createCounter(
|
||||
"trpc.contentstack",
|
||||
"sitewideCampaignBanner.get.refs"
|
||||
)
|
||||
const metricsGetSitewideCampaignBannerRefs =
|
||||
getSitewideCampaignBannerRefsCounter.init({
|
||||
lang,
|
||||
})
|
||||
|
||||
metricsGetSitewideCampaignBannerRefs.start()
|
||||
|
||||
const responseRef = await request<GetSitewideCampaignBannerRefData>(
|
||||
GetSitewideCampaignBannerRef,
|
||||
{ locale: lang },
|
||||
{
|
||||
key: generateRefsResponseTag(lang, "sitewide_campaign_banner"),
|
||||
ttl: "max",
|
||||
}
|
||||
)
|
||||
|
||||
if (!responseRef.data) {
|
||||
const notFoundError = notFound(responseRef)
|
||||
metricsGetSitewideCampaignBannerRefs.noDataError()
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const validatedSitewideCampaignBannerRef =
|
||||
sitewideCampaignBannerRefSchema.safeParse(responseRef.data)
|
||||
|
||||
if (!validatedSitewideCampaignBannerRef.success) {
|
||||
metricsGetSitewideCampaignBannerRefs.validationError(
|
||||
validatedSitewideCampaignBannerRef.error
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const connections = getSitewideCampaignBannerConnections(
|
||||
validatedSitewideCampaignBannerRef.data
|
||||
)
|
||||
|
||||
const tags = [generateTagsFromSystem(lang, connections)].flat()
|
||||
|
||||
metricsGetSitewideCampaignBannerRefs.success()
|
||||
|
||||
const getSitewideCampaignBannerCounter = createCounter(
|
||||
"trpc.contentstack",
|
||||
"sitewideCampaignBanner.get"
|
||||
)
|
||||
const metricsGetSitewideCampaignBanner =
|
||||
getSitewideCampaignBannerCounter.init({
|
||||
lang,
|
||||
})
|
||||
|
||||
metricsGetSitewideCampaignBanner.start()
|
||||
|
||||
const sitewideCampaignBannerResponse =
|
||||
await request<GetSitewideCampaignBannerData>(
|
||||
GetSitewideCampaignBanner,
|
||||
{ locale: lang },
|
||||
{ key: tags, ttl: "max" }
|
||||
)
|
||||
|
||||
if (!sitewideCampaignBannerResponse.data) {
|
||||
const notFoundError = notFound(sitewideCampaignBannerResponse)
|
||||
metricsGetSitewideCampaignBanner.noDataError()
|
||||
throw notFoundError
|
||||
}
|
||||
|
||||
const validatedSitewideCampaignBanner =
|
||||
sitewideCampaignBannerSchema.safeParse(
|
||||
sitewideCampaignBannerResponse.data
|
||||
)
|
||||
|
||||
if (!validatedSitewideCampaignBanner.success) {
|
||||
metricsGetSitewideCampaignBanner.validationError(
|
||||
validatedSitewideCampaignBanner.error
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
metricsGetSitewideCampaignBanner.success()
|
||||
|
||||
return validatedSitewideCampaignBanner.data
|
||||
}),
|
||||
}),
|
||||
siteConfig: contentstackBaseProcedure
|
||||
.input(langInput)
|
||||
.query(async ({ input, ctx }) => {
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { NodeRefs } from "../../../types/refs"
|
||||
import type {
|
||||
AlertOutput,
|
||||
GetSiteConfigRefData,
|
||||
GetSitewideCampaignBannerRefData,
|
||||
} from "../../../types/siteConfig"
|
||||
import type { System } from "../schemas/system"
|
||||
import type { ContactConfig } from "./output"
|
||||
@@ -138,3 +139,21 @@ export const safeUnion = <T extends z.ZodTypeAny>(schema: T) =>
|
||||
return null
|
||||
}
|
||||
}, schema)
|
||||
|
||||
export function getSitewideCampaignBannerConnections(
|
||||
refs: GetSitewideCampaignBannerRefData
|
||||
) {
|
||||
const system = refs.all_sitewide_campaign_banner?.system
|
||||
const banner =
|
||||
refs.all_sitewide_campaign_banner?.bannerConnection.edges[0]?.node
|
||||
const connections: System["system"][] = []
|
||||
|
||||
if (system) {
|
||||
connections.push(system)
|
||||
}
|
||||
if (banner?.system) {
|
||||
connections.push(banner.system)
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/stringValidator"
|
||||
|
||||
import {
|
||||
linkRefsUnionSchema,
|
||||
linkUnionSchema,
|
||||
@@ -8,7 +10,7 @@ import {
|
||||
} from "./pageLinks"
|
||||
|
||||
const titleSchema = z.object({
|
||||
title: z.string().optional().default(""),
|
||||
title: nullableStringValidator,
|
||||
})
|
||||
|
||||
export const linkConnectionSchema = z
|
||||
|
||||
@@ -4,6 +4,8 @@ import type {
|
||||
alertSchema,
|
||||
siteConfigRefSchema,
|
||||
siteConfigSchema,
|
||||
sitewideCampaignBannerRefSchema,
|
||||
sitewideCampaignBannerSchema,
|
||||
} from "../routers/contentstack/base/output"
|
||||
|
||||
export type GetSiteConfigRefData = z.infer<typeof siteConfigRefSchema>
|
||||
@@ -23,3 +25,10 @@ export type AlertPhoneContact = {
|
||||
export type Alert = Omit<AlertOutput, "phoneContact"> & {
|
||||
phoneContact: AlertPhoneContact | null
|
||||
}
|
||||
|
||||
export type GetSitewideCampaignBannerRefData = z.infer<
|
||||
typeof sitewideCampaignBannerRefSchema
|
||||
>
|
||||
export type GetSitewideCampaignBannerData = z.output<
|
||||
typeof sitewideCampaignBannerSchema
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user