diff --git a/components/Blocks/FullWidthCampaign/fullWidthCampaign.module.css b/components/Blocks/FullWidthCampaign/fullWidthCampaign.module.css new file mode 100644 index 000000000..e2672cc5a --- /dev/null +++ b/components/Blocks/FullWidthCampaign/fullWidthCampaign.module.css @@ -0,0 +1,41 @@ +.container { + position: relative; + height: 640px; + overflow: hidden; +} + +.content { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + max-width: 800px; + margin: 0 auto; + gap: var(--Spacing-x1); + padding: var(--Spacing-x4) var(--Spacing-x3); +} + +.mainContent { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--Spacing-x2); +} + +.buttons { + display: flex; + gap: var(--Spacing-x1); +} + +.image { + max-width: 100%; + height: 600px; +} + +@media screen and (min-width: 768px) { + .image { + height: 880px; + } +} diff --git a/components/Blocks/FullWidthCampaign/index.tsx b/components/Blocks/FullWidthCampaign/index.tsx new file mode 100644 index 000000000..d1f84f5b5 --- /dev/null +++ b/components/Blocks/FullWidthCampaign/index.tsx @@ -0,0 +1,57 @@ +import Image from "@/components/Image" +import Button from "@/components/TempDesignSystem/Button" +import BiroScript from "@/components/TempDesignSystem/Text/BiroScript" +import Body from "@/components/TempDesignSystem/Text/Body" +import Title from "@/components/TempDesignSystem/Text/Title" + +import styles from "./fullWidthCampaign.module.css" + +import type { FullWidthCampaign } from "@/types/trpc/routers/contentstack/startPage" + +interface FullWidthCampaignProps { + content: FullWidthCampaign +} + +export default function FullWidthCampaign({ content }: FullWidthCampaignProps) { + return content.full_width_campaignConnection.edges.map(({ node }) => ( +
+ {node.background_image ? ( + { + ) : null} +
+ {node.scripted_top_title} +
+ + {node.heading} + + + {node.body_text} + +
+ {node.has_primary_button ? ( + + ) : null} + {node.has_secondary_button ? ( + + ) : null} +
+
+
+
+ )) +} diff --git a/components/Blocks/index.tsx b/components/Blocks/index.tsx index a67a3880e..87283a5a9 100644 --- a/components/Blocks/index.tsx +++ b/components/Blocks/index.tsx @@ -7,6 +7,7 @@ import JsonToHtml from "@/components/JsonToHtml" import { SasTierComparison } from "@/components/SasTierComparison" import AccordionSection from "./Accordion" +import FullWidthCampaign from "./FullWidthCampaign" import HotelListing from "./HotelListing" import Table from "./Table" @@ -98,6 +99,8 @@ export default function Blocks({ blocks }: BlocksProps) { firstItem={firstItem} /> ) + case BlocksEnums.block.FullWidthCampaign: + return default: return null } diff --git a/components/ContentType/StartPage/index.tsx b/components/ContentType/StartPage/index.tsx index 33972541f..9ecf0e007 100644 --- a/components/ContentType/StartPage/index.tsx +++ b/components/ContentType/StartPage/index.tsx @@ -43,13 +43,13 @@ export default async function StartPage() { ) : null}
+ {blocks ? : null}
JSON data
{JSON.stringify(content, null, 2)}
- {blocks ? : null}
diff --git a/lib/graphql/Fragments/Blocks/FullWidthCampaign.graphql b/lib/graphql/Fragments/Blocks/FullWidthCampaign.graphql new file mode 100644 index 000000000..14d98cec1 --- /dev/null +++ b/lib/graphql/Fragments/Blocks/FullWidthCampaign.graphql @@ -0,0 +1,99 @@ +#import "../PageLink/AccountPageLink.graphql" +#import "../PageLink/ContentPageLink.graphql" +#import "../PageLink/LoyaltyPageLink.graphql" +#import "../PageLink/HotelPageLink.graphql" +#import "../PageLink/CollectionPageLink.graphql" + +#import "../AccountPage/Ref.graphql" +#import "../ContentPage/Ref.graphql" +#import "../HotelPage/Ref.graphql" +#import "../LoyaltyPage/Ref.graphql" +#import "../CollectionPage/Ref.graphql" + +fragment FullWidthCampaign on FullWidthCampaign { + background_image + scripted_top_title + heading + body_text + has_primary_button + primary_button { + cta_text + open_in_new_tab + is_contentstack_link + external_link { + href + title + } + linkConnection { + edges { + node { + __typename + ...AccountPageLink + ...ContentPageLink + ...LoyaltyPageLink + ...HotelPageLink + ...CollectionPageLink + } + } + } + } + has_secondary_button + secondary_button { + cta_text + open_in_new_tab + is_contentstack_link + external_link { + href + title + } + linkConnection { + edges { + node { + __typename + ...AccountPageLink + ...ContentPageLink + ...LoyaltyPageLink + ...HotelPageLink + ...CollectionPageLink + } + } + } + } + system { + ...System + } +} + +fragment FullWidthCampaignRefs on FullWidthCampaign { + primary_button { + linkConnection { + edges { + node { + __typename + ...AccountPageRef + ...ContentPageRef + ...HotelPageRef + ...LoyaltyPageRef + ...CollectionPageRef + } + } + } + } + secondary_button { + linkConnection { + edges { + node { + __typename + ...AccountPageRef + ...ContentPageRef + ...HotelPageRef + ...LoyaltyPageRef + ...CollectionPageRef + } + } + } + } + system { + ...System + } +} diff --git a/lib/graphql/Query/StartPage/StartPage.graphql b/lib/graphql/Query/StartPage/StartPage.graphql index a3bcfea4e..4e118ceba 100644 --- a/lib/graphql/Query/StartPage/StartPage.graphql +++ b/lib/graphql/Query/StartPage/StartPage.graphql @@ -1,14 +1,30 @@ #import "../../Fragments/System.graphql" #import "../../Fragments/Blocks/CardsGrid.graphql" +#import "../../Fragments/Blocks/FullWidthCampaign.graphql" query GetStartPage($locale: String!, $uid: String!) { - start_page(uid: $uid, locale: $locale) { + start_page(locale: $locale, uid: $uid) { title url header { heading hero_image } + blocks { + __typename + ... on StartPageBlocksFullWidthCampaign { + __typename + full_width_campaign { + full_width_campaignConnection { + edges { + node { + ...FullWidthCampaign + } + } + } + } + } + } system { ...System created_at @@ -29,6 +45,17 @@ query GetStartPageRefs($locale: String!, $uid: String!) { blocks { __typename ...CardsGrid_StartPageRefs + ... on StartPageBlocksFullWidthCampaign { + full_width_campaign { + full_width_campaignConnection { + edges { + node { + ...FullWidthCampaignRefs + } + } + } + } + } } system { ...System diff --git a/server/routers/contentstack/schemas/blocks/fullWidthCampaign.ts b/server/routers/contentstack/schemas/blocks/fullWidthCampaign.ts new file mode 100644 index 000000000..f75f7d304 --- /dev/null +++ b/server/routers/contentstack/schemas/blocks/fullWidthCampaign.ts @@ -0,0 +1,58 @@ +import { z } from "zod" + +import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks" + +import { tempImageVaultAssetSchema } from "../imageVault" +import { systemSchema } from "../system" +import { buttonSchema } from "./utils/buttonLinkSchema" + +import { BlocksEnums } from "@/types/enums/blocks" + +export const fullWidthCampaignSchema = z.object({ + full_width_campaign: z.object({ + full_width_campaignConnection: z.object({ + edges: z.array( + z.object({ + node: z.object({ + background_image: tempImageVaultAssetSchema, + heading: z.string().optional(), + body_text: z.string().optional(), + scripted_top_title: z.string().optional(), + has_primary_button: z.boolean().default(false), + primary_button: buttonSchema, + has_secondary_button: z.boolean().default(false), + secondary_button: buttonSchema, + system: systemSchema, + }), + }) + ), + }), + }), +}) + +export const fullWidthCampaignBlockSchema = z + .object({ + typename: z + .literal(BlocksEnums.block.FullWidthCampaign) + .optional() + .default(BlocksEnums.block.FullWidthCampaign), + }) + .merge(fullWidthCampaignSchema) + +export const fullWidthCampaignBlockRefsSchema = z.object({ + full_width_campaign: z.object({ + full_width_campaignConnection: z.object({ + edges: z.array( + z.object({ + node: z.discriminatedUnion("__typename", [ + pageLinks.accountPageRefSchema, + pageLinks.contentPageRefSchema, + pageLinks.loyaltyPageRefSchema, + pageLinks.collectionPageRefSchema, + pageLinks.hotelPageRefSchema, + ]), + }) + ), + }), + }), +}) diff --git a/server/routers/contentstack/startPage/output.ts b/server/routers/contentstack/startPage/output.ts index f52c911eb..69c6dc02b 100644 --- a/server/routers/contentstack/startPage/output.ts +++ b/server/routers/contentstack/startPage/output.ts @@ -6,27 +6,40 @@ import { cardGridRefsSchema, cardsGridSchema, } from "../schemas/blocks/cardsGrid" +import { + fullWidthCampaignBlockRefsSchema, + fullWidthCampaignBlockSchema, +} from "../schemas/blocks/fullWidthCampaign" import { tempImageVaultAssetSchema } from "../schemas/imageVault" import { systemSchema } from "../schemas/system" import { StartPageEnum } from "@/types/enums/startPage" -export const startPageCards = z +const startPageCards = z .object({ __typename: z.literal(StartPageEnum.ContentStack.blocks.CardsGrid), }) .merge(cardsGridSchema) -export const blocksSchema = z.discriminatedUnion("__typename", [startPageCards]) +const startPageFullWidthCampaign = z + .object({ + __typename: z.literal(StartPageEnum.ContentStack.blocks.FullWidthCampaign), + }) + .merge(fullWidthCampaignBlockSchema) + +export const blocksSchema = z.discriminatedUnion("__typename", [ + startPageCards, + startPageFullWidthCampaign, +]) export const startPageSchema = z.object({ start_page: z.object({ - blocks: discriminatedUnionArray(blocksSchema.options).nullable(), title: z.string(), header: z.object({ heading: z.string(), hero_image: tempImageVaultAssetSchema, }), + blocks: discriminatedUnionArray(blocksSchema.options).nullable(), system: systemSchema.merge( z.object({ created_at: z.string(), @@ -46,8 +59,15 @@ const startPageCardsRefs = z }) .merge(cardGridRefsSchema) +const startPageFullWidthCampaignRef = z + .object({ + __typename: z.literal(StartPageEnum.ContentStack.blocks.FullWidthCampaign), + }) + .merge(fullWidthCampaignBlockRefsSchema) + const startPageBlockRefsItem = z.discriminatedUnion("__typename", [ startPageCardsRefs, + startPageFullWidthCampaignRef, ]) export const startPageRefsSchema = z.object({ diff --git a/server/routers/contentstack/startPage/query.ts b/server/routers/contentstack/startPage/query.ts index d6cdf1986..5ce2c5ace 100644 --- a/server/routers/contentstack/startPage/query.ts +++ b/server/routers/contentstack/startPage/query.ts @@ -6,7 +6,7 @@ import { request } from "@/lib/graphql/request" import { notFound } from "@/server/errors/trpc" import { contentstackExtendedProcedureUID, router } from "@/server/trpc" -import { generateTag } from "@/utils/generateTag" +import { generateTag, generateTagsFromSystem } from "@/utils/generateTag" import { startPageRefsSchema, startPageSchema } from "./output" import { @@ -17,6 +17,7 @@ import { getStartPageRefsSuccessCounter, getStartPageSuccessCounter, } from "./telemetry" +import { getConnections } from "./utils" import { TrackingChannelEnum, @@ -103,6 +104,13 @@ export const startPageQueryRouter = router({ query: { lang, uid }, }) ) + + const connections = getConnections(validatedRefsData.data) + + const tags = [ + generateTagsFromSystem(lang, connections), + generateTag(lang, validatedRefsData.data.start_page.system.uid), + ].flat() const response = await request( GetStartPage, { @@ -112,10 +120,11 @@ export const startPageQueryRouter = router({ { cache: "force-cache", next: { - tags: [generateTag(lang, uid)], + tags, }, } ) + if (!response.data) { const notFoundError = notFound(response) getStartPageFailCounter.add(1, { diff --git a/server/routers/contentstack/startPage/utils.ts b/server/routers/contentstack/startPage/utils.ts new file mode 100644 index 000000000..9edb0720e --- /dev/null +++ b/server/routers/contentstack/startPage/utils.ts @@ -0,0 +1,24 @@ +import { StartPageEnum } from "@/types/enums/startPage" +import type { System } from "@/types/requests/system" +import type { StartPageRefs } from "@/types/trpc/routers/contentstack/startPage" + +export function getConnections({ start_page }: StartPageRefs) { + const connections: System["system"][] = [start_page.system] + + if (start_page.blocks) { + start_page.blocks.forEach((block) => { + switch (block.__typename) { + case StartPageEnum.ContentStack.blocks.FullWidthCampaign: { + block.full_width_campaign.full_width_campaignConnection.edges.forEach( + ({ node }) => { + connections.push(node.system) + } + ) + break + } + } + }) + } + + return connections +} diff --git a/types/enums/blocks.ts b/types/enums/blocks.ts index baf9a4a9c..4fd753abf 100644 --- a/types/enums/blocks.ts +++ b/types/enums/blocks.ts @@ -11,5 +11,6 @@ export namespace BlocksEnums { UspGrid = "UspGrid", SasTierComparison = "SasTierComparison", HotelListing = "HotelListing", + FullWidthCampaign = "FullWidthCampaign", } } diff --git a/types/enums/startPage.ts b/types/enums/startPage.ts index fff235db4..339e5f26e 100644 --- a/types/enums/startPage.ts +++ b/types/enums/startPage.ts @@ -2,6 +2,7 @@ export namespace StartPageEnum { export namespace ContentStack { export const enum blocks { CardsGrid = "StartPageBlocksCardsGrid", + FullWidthCampaign = "StartPageBlocksFullWidthCampaign", } } } diff --git a/types/trpc/routers/contentstack/startPage.ts b/types/trpc/routers/contentstack/startPage.ts index 61219679e..c204c04c5 100644 --- a/types/trpc/routers/contentstack/startPage.ts +++ b/types/trpc/routers/contentstack/startPage.ts @@ -15,3 +15,5 @@ export interface GetStartPageRefsSchema export interface StartPageRefs extends z.output {} export type Block = z.output + +export type FullWidthCampaign = Block["full_width_campaign"]