Merged in feat/LOY-361-add-promo-campaign-page-type (pull request #2826)
Feat/LOY-361 add promo campaign page type * feat(LOY-361): add Pomo Campaign page type * chore(SW-361): remove campaign page flag * fix(LOY-361): cleanup * fix(LOY-361): add promo code Approved-by: Erik Tiekstra Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
@@ -71,4 +71,4 @@ DTMC_ENTRA_ID_CLIENT=""
|
|||||||
DTMC_ENTRA_ID_ISSUER=""
|
DTMC_ENTRA_ID_ISSUER=""
|
||||||
DTMC_ENTRA_ID_SECRET=""
|
DTMC_ENTRA_ID_SECRET=""
|
||||||
|
|
||||||
CAMPAIGN_PAGES_ENABLED="0" # 0 - disabled, 1 - enabled
|
PROMO_CAMPAIGN_PAGES_ENABLED="0" # 0 - disabled, 1 - enabled
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Suspense } from "react"
|
||||||
|
|
||||||
|
import Breadcrumbs from "@/components/Breadcrumbs"
|
||||||
|
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
|
||||||
|
|
||||||
|
import type { BreadcrumbsProps } from "@/components/TempDesignSystem/Breadcrumbs/breadcrumbs"
|
||||||
|
|
||||||
|
export default function PromoCampaignPageBreadcrumbs() {
|
||||||
|
const variants: Pick<BreadcrumbsProps, "color" | "size"> = {
|
||||||
|
color: "Background/Primary",
|
||||||
|
size: "contentWidth",
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<BreadcrumbsSkeleton {...variants} />}>
|
||||||
|
<Breadcrumbs {...variants} />
|
||||||
|
</Suspense>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,18 +1,11 @@
|
|||||||
import { notFound } from "next/navigation"
|
|
||||||
import { Suspense } from "react"
|
import { Suspense } from "react"
|
||||||
|
|
||||||
import { env } from "@/env/server"
|
|
||||||
|
|
||||||
import CampaignOverviewPage from "@/components/ContentType/CampaignOverviewPage"
|
import CampaignOverviewPage from "@/components/ContentType/CampaignOverviewPage"
|
||||||
import CampaignOverviewPageSkeleton from "@/components/ContentType/CampaignOverviewPage/CampaignOverviewPageSkeleton"
|
import CampaignOverviewPageSkeleton from "@/components/ContentType/CampaignOverviewPage/CampaignOverviewPageSkeleton"
|
||||||
|
|
||||||
import styles from "./page.module.css"
|
import styles from "./page.module.css"
|
||||||
|
|
||||||
export default async function CampaignOverviewPagePage() {
|
export default async function CampaignOverviewPagePage() {
|
||||||
if (!env.CAMPAIGN_PAGES_ENABLED) {
|
|
||||||
notFound()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.page}>
|
<div className={styles.page}>
|
||||||
<Suspense fallback={<CampaignOverviewPageSkeleton />}>
|
<Suspense fallback={<CampaignOverviewPageSkeleton />}>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { notFound } from "next/navigation"
|
|
||||||
import { Suspense } from "react"
|
import { Suspense } from "react"
|
||||||
|
|
||||||
import { env } from "@/env/server"
|
|
||||||
|
|
||||||
import CampaignPage from "@/components/ContentType/CampaignPage"
|
import CampaignPage from "@/components/ContentType/CampaignPage"
|
||||||
import CampaignPageSkeleton from "@/components/ContentType/CampaignPage/CampaignPageSkeleton"
|
import CampaignPageSkeleton from "@/components/ContentType/CampaignPage/CampaignPageSkeleton"
|
||||||
|
|
||||||
@@ -11,10 +8,6 @@ import styles from "./page.module.css"
|
|||||||
export { generateMetadata } from "@/utils/metadata/generateMetadata"
|
export { generateMetadata } from "@/utils/metadata/generateMetadata"
|
||||||
|
|
||||||
export default async function CampaignPagePage() {
|
export default async function CampaignPagePage() {
|
||||||
if (!env.CAMPAIGN_PAGES_ENABLED) {
|
|
||||||
return notFound()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.page}>
|
<div className={styles.page}>
|
||||||
<Suspense fallback={<CampaignPageSkeleton />}>
|
<Suspense fallback={<CampaignPageSkeleton />}>
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.page {
|
||||||
|
background-color: var(--Background-Primary);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { notFound } from "next/navigation"
|
||||||
|
import { Suspense } from "react"
|
||||||
|
|
||||||
|
import { env } from "@/env/server"
|
||||||
|
|
||||||
|
import PromoCampaignPage from "@/components/ContentType/PromoCampaignPage"
|
||||||
|
import PromoCampaignPageSkeleton from "@/components/ContentType/PromoCampaignPage/PromoCampaignPageSkeleton"
|
||||||
|
|
||||||
|
import styles from "./page.module.css"
|
||||||
|
|
||||||
|
export { generateMetadata } from "@/utils/metadata/generateMetadata"
|
||||||
|
|
||||||
|
export default async function PromoCampaignPagePage() {
|
||||||
|
if (!env.PROMO_CAMPAIGN_PAGES_ENABLED) {
|
||||||
|
return notFound()
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={styles.page}>
|
||||||
|
<Suspense fallback={<PromoCampaignPageSkeleton />}>
|
||||||
|
<PromoCampaignPage />
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import styles from "./promoCampaignPage.module.css"
|
||||||
|
|
||||||
|
export default function PromoCampaignPageSkeleton() {
|
||||||
|
return (
|
||||||
|
<div className={styles.pageContainer}>
|
||||||
|
<SkeletonShimmer width="100%" height="478px" />
|
||||||
|
|
||||||
|
<div className={styles.intro}>
|
||||||
|
<div className={styles.headingWrapper}>
|
||||||
|
<Typography variant="Title/lg">
|
||||||
|
<SkeletonShimmer width="20ch" />
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="Title/Subtitle/lg">
|
||||||
|
<SkeletonShimmer width="50ch" />
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Typography variant="Title/smLowCase">
|
||||||
|
<SkeletonShimmer width="30ch" />
|
||||||
|
</Typography>
|
||||||
|
<SkeletonShimmer width="100%" height="110px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { notFound } from "next/navigation"
|
||||||
|
import { Suspense } from "react"
|
||||||
|
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
|
||||||
|
|
||||||
|
import { getPromoCampaignPage } from "@/lib/trpc/memoizedRequests"
|
||||||
|
|
||||||
|
import PromoCampaignPageSkeleton from "./PromoCampaignPageSkeleton"
|
||||||
|
|
||||||
|
import styles from "./promoCampaignPage.module.css"
|
||||||
|
|
||||||
|
export default async function PromoCampaignPage() {
|
||||||
|
const pageData = await getPromoCampaignPage()
|
||||||
|
if (!pageData) {
|
||||||
|
notFound()
|
||||||
|
}
|
||||||
|
//const isUserLoggedIn = await isLoggedInUser()
|
||||||
|
const { promo_campaign_page, tracking } = pageData
|
||||||
|
const { heading, subheading } = promo_campaign_page
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Suspense fallback={<PromoCampaignPageSkeleton />}>
|
||||||
|
<div className={styles.pageContainer}>
|
||||||
|
<div className={styles.intro}>
|
||||||
|
<div className={styles.headingWrapper}>
|
||||||
|
<Typography variant="Title/lg">
|
||||||
|
<h1 className={styles.heading}>{heading}</h1>
|
||||||
|
</Typography>
|
||||||
|
{subheading ? (
|
||||||
|
<Typography variant="Title/Subtitle/lg">
|
||||||
|
<p>{subheading}</p>
|
||||||
|
</Typography>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Suspense>
|
||||||
|
<TrackingSDK pageData={tracking} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
.pageContainer {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x6);
|
||||||
|
padding-bottom: var(--Space-x7);
|
||||||
|
width: var(--max-width-content);
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.headingWrapper {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: var(--Text-Heading);
|
||||||
|
text-wrap: balance;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1367px) {
|
||||||
|
.pageContainer {
|
||||||
|
gap: var(--Space-x9);
|
||||||
|
}
|
||||||
|
}
|
||||||
4
apps/scandic-web/env/server.ts
vendored
4
apps/scandic-web/env/server.ts
vendored
@@ -149,7 +149,7 @@ export const env = createEnv({
|
|||||||
* We currently have the secret in local and test environments.
|
* We currently have the secret in local and test environments.
|
||||||
*/
|
*/
|
||||||
DTMC_ENTRA_ID_SECRET: z.string().optional(),
|
DTMC_ENTRA_ID_SECRET: z.string().optional(),
|
||||||
CAMPAIGN_PAGES_ENABLED: z
|
PROMO_CAMPAIGN_PAGES_ENABLED: z
|
||||||
.string()
|
.string()
|
||||||
.refine((s) => s === "1" || s === "0")
|
.refine((s) => s === "1" || s === "0")
|
||||||
.transform((s) => s === "1")
|
.transform((s) => s === "1")
|
||||||
@@ -247,7 +247,7 @@ export const env = createEnv({
|
|||||||
DTMC_ENTRA_ID_CLIENT: process.env.DTMC_ENTRA_ID_CLIENT,
|
DTMC_ENTRA_ID_CLIENT: process.env.DTMC_ENTRA_ID_CLIENT,
|
||||||
DTMC_ENTRA_ID_ISSUER: process.env.DTMC_ENTRA_ID_ISSUER,
|
DTMC_ENTRA_ID_ISSUER: process.env.DTMC_ENTRA_ID_ISSUER,
|
||||||
DTMC_ENTRA_ID_SECRET: process.env.DTMC_ENTRA_ID_SECRET,
|
DTMC_ENTRA_ID_SECRET: process.env.DTMC_ENTRA_ID_SECRET,
|
||||||
CAMPAIGN_PAGES_ENABLED: process.env.CAMPAIGN_PAGES_ENABLED,
|
PROMO_CAMPAIGN_PAGES_ENABLED: process.env.PROMO_CAMPAIGN_PAGES_ENABLED,
|
||||||
WEBVIEW_SHOW_OVERVIEW: process.env.WEBVIEW_SHOW_OVERVIEW,
|
WEBVIEW_SHOW_OVERVIEW: process.env.WEBVIEW_SHOW_OVERVIEW,
|
||||||
ENABLE_NEW_OVERVIEW_SECTION: process.env.ENABLE_NEW_OVERVIEW_SECTION,
|
ENABLE_NEW_OVERVIEW_SECTION: process.env.ENABLE_NEW_OVERVIEW_SECTION,
|
||||||
CHATBOT_LIVE_LANGS: process.env.CHATBOT_LIVE_LANGS,
|
CHATBOT_LIVE_LANGS: process.env.CHATBOT_LIVE_LANGS,
|
||||||
|
|||||||
@@ -232,3 +232,10 @@ export const getCampaignOverviewPage = cache(
|
|||||||
return caller.contentstack.campaignOverviewPage.get()
|
return caller.contentstack.campaignOverviewPage.get()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const getPromoCampaignPage = cache(
|
||||||
|
async function getMemoizedPromoCampaignPage() {
|
||||||
|
const caller = await serverClient()
|
||||||
|
return caller.contentstack.promoCampaignPage.get()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export enum TrackingChannelEnum {
|
|||||||
"campaign" = "campaign",
|
"campaign" = "campaign",
|
||||||
"hotels" = "hotels",
|
"hotels" = "hotels",
|
||||||
"homepage" = "homepage",
|
"homepage" = "homepage",
|
||||||
|
"promo-campaign" = "promo-campaign",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TrackingChannel = keyof typeof TrackingChannelEnum
|
export type TrackingChannel = keyof typeof TrackingChannelEnum
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ export enum PageContentTypeEnum {
|
|||||||
hotelPage = "hotel_page",
|
hotelPage = "hotel_page",
|
||||||
loyaltyPage = "loyalty_page",
|
loyaltyPage = "loyalty_page",
|
||||||
startPage = "start_page",
|
startPage = "start_page",
|
||||||
|
promoCampaignPage = "promo_campaign_page",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#import "../System.graphql"
|
||||||
|
|
||||||
|
fragment PromoCampaignPageBreadcrumb on PromoCampaignPage {
|
||||||
|
web {
|
||||||
|
breadcrumbs {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
url
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment PromoCampaignPageBreadcrumbRef on PromoCampaignPage {
|
||||||
|
web {
|
||||||
|
breadcrumbs {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#import "../System.graphql"
|
||||||
|
|
||||||
|
fragment PromoCampaignPageLink on PromoCampaignPage {
|
||||||
|
title
|
||||||
|
url
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#import "../System.graphql"
|
||||||
|
|
||||||
|
fragment PromoCampaignPageRef on PromoCampaignPage {
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#import "../../Fragments/Breadcrumbs/Breadcrumbs.graphql"
|
||||||
|
#import "../../Fragments/System.graphql"
|
||||||
|
|
||||||
|
query GetPromoCampaignPageBreadcrumbs($locale: String!, $uid: String!) {
|
||||||
|
promo_campaign_page(locale: $locale, uid: $uid) {
|
||||||
|
url
|
||||||
|
web {
|
||||||
|
breadcrumbs {
|
||||||
|
...Breadcrumbs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query GetPromoCampaignPageBreadcrumbsRefs($locale: String!, $uid: String!) {
|
||||||
|
promo_campaign_page(locale: $locale, uid: $uid) {
|
||||||
|
web {
|
||||||
|
breadcrumbs {
|
||||||
|
...BreadcrumbsRefs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -95,3 +95,11 @@ query GetStartPageSettings($uid: String!, $locale: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query GetPromoCampaignPageSettings($uid: String!, $locale: String!) {
|
||||||
|
page: promo_campaign_page(uid: $uid, locale: $locale) {
|
||||||
|
settings: page_settings {
|
||||||
|
...PageSettings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#import "../../Fragments/Metadata.graphql"
|
||||||
|
#import "../../Fragments/System.graphql"
|
||||||
|
|
||||||
|
query GetPromoCampaignPageMetadata($locale: String!, $uid: String!) {
|
||||||
|
promo_campaign_page(locale: $locale, uid: $uid) {
|
||||||
|
web {
|
||||||
|
breadcrumbs {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
seo_metadata {
|
||||||
|
...Metadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
heading
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#import "../../Fragments/System.graphql"
|
||||||
|
|
||||||
|
#import "../../Fragments/CampaignPage/IncludedHotels.graphql"
|
||||||
|
#import "../../Fragments/CampaignPage/Hero.graphql"
|
||||||
|
|
||||||
|
#import "../../Fragments/Blocks/Accordion.graphql"
|
||||||
|
#import "../../Fragments/Blocks/Essentials.graphql"
|
||||||
|
#import "../../Fragments/Blocks/CarouselCards.graphql"
|
||||||
|
#import "../../Fragments/Blocks/HotelListing.graphql"
|
||||||
|
|
||||||
|
query GetPromoCampaignPage($locale: String!, $uid: String!) {
|
||||||
|
promo_campaign_page(uid: $uid, locale: $locale) {
|
||||||
|
title
|
||||||
|
heading
|
||||||
|
subheading
|
||||||
|
page_settings {
|
||||||
|
booking_code
|
||||||
|
}
|
||||||
|
campaign_type
|
||||||
|
promo_code
|
||||||
|
startdate
|
||||||
|
enddate
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
created_at
|
||||||
|
updated_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trackingProps: promo_campaign_page(locale: "en", uid: $uid) {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query GetPromoCampaignPageRefs($locale: String!, $uid: String!) {
|
||||||
|
promo_campaign_page(locale: $locale, uid: $uid) {
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query GetDaDeEnUrlsPromoCampaignPage($uid: String!) {
|
||||||
|
de: promo_campaign_page(locale: "de", uid: $uid) {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
en: promo_campaign_page(locale: "en", uid: $uid) {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
da: promo_campaign_page(locale: "da", uid: $uid) {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query GetFiNoSvUrlsPromoCampaignPage($uid: String!) {
|
||||||
|
fi: promo_campaign_page(locale: "fi", uid: $uid) {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
no: promo_campaign_page(locale: "no", uid: $uid) {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
sv: promo_campaign_page(locale: "sv", uid: $uid) {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -101,3 +101,14 @@ query EntryByUrlBatch2($locale: String!, $url: String!) {
|
|||||||
total
|
total
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query EntryByUrlBatch3($locale: String!, $url: String!) {
|
||||||
|
all_promo_campaign_page(where: { url: $url }, locale: $locale) {
|
||||||
|
items {
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ import {
|
|||||||
GetLoyaltyPageBreadcrumbs,
|
GetLoyaltyPageBreadcrumbs,
|
||||||
GetLoyaltyPageBreadcrumbsRefs,
|
GetLoyaltyPageBreadcrumbsRefs,
|
||||||
} from "../../../graphql/Query/Breadcrumbs/LoyaltyPage.graphql"
|
} from "../../../graphql/Query/Breadcrumbs/LoyaltyPage.graphql"
|
||||||
|
import {
|
||||||
|
GetPromoCampaignPageBreadcrumbs,
|
||||||
|
GetPromoCampaignPageBreadcrumbsRefs,
|
||||||
|
} from "../../../graphql/Query/Breadcrumbs/PromoCampaignPage.graphql"
|
||||||
import { request } from "../../../graphql/request"
|
import { request } from "../../../graphql/request"
|
||||||
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
import { contentstackExtendedProcedureUID } from "../../../procedures"
|
||||||
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
||||||
@@ -259,6 +263,17 @@ export const breadcrumbsQueryRouter = router({
|
|||||||
},
|
},
|
||||||
variables
|
variables
|
||||||
)
|
)
|
||||||
|
case PageContentTypeEnum.promoCampaignPage:
|
||||||
|
return await getBreadcrumbs<{
|
||||||
|
promo_campaign_page: RawBreadcrumbsSchema
|
||||||
|
}>(
|
||||||
|
{
|
||||||
|
dataKey: "promo_campaign_page",
|
||||||
|
refQuery: GetPromoCampaignPageBreadcrumbsRefs,
|
||||||
|
query: GetPromoCampaignPageBreadcrumbs,
|
||||||
|
},
|
||||||
|
variables
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { loyaltyPageRouter } from "./loyaltyPage"
|
|||||||
import { metadataRouter } from "./metadata"
|
import { metadataRouter } from "./metadata"
|
||||||
import { pageSettingsRouter } from "./pageSettings"
|
import { pageSettingsRouter } from "./pageSettings"
|
||||||
import { partnerRouter } from "./partner"
|
import { partnerRouter } from "./partner"
|
||||||
|
import { promoCampaignPageRouter } from "./promoCampaignPage"
|
||||||
import { rewardRouter } from "./reward"
|
import { rewardRouter } from "./reward"
|
||||||
import { startPageRouter } from "./startPage"
|
import { startPageRouter } from "./startPage"
|
||||||
|
|
||||||
@@ -39,4 +40,5 @@ export const contentstackRouter = router({
|
|||||||
loyaltyLevels: loyaltyLevelRouter,
|
loyaltyLevels: loyaltyLevelRouter,
|
||||||
startPage: startPageRouter,
|
startPage: startPageRouter,
|
||||||
partner: partnerRouter,
|
partner: partnerRouter,
|
||||||
|
promoCampaignPage: promoCampaignPageRouter,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ import {
|
|||||||
GetDaDeEnUrlsLoyaltyPage,
|
GetDaDeEnUrlsLoyaltyPage,
|
||||||
GetFiNoSvUrlsLoyaltyPage,
|
GetFiNoSvUrlsLoyaltyPage,
|
||||||
} from "../../../graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
|
} from "../../../graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
|
||||||
|
import {
|
||||||
|
GetDaDeEnUrlsPromoCampaignPage,
|
||||||
|
GetFiNoSvUrlsPromoCampaignPage,
|
||||||
|
} from "../../../graphql/Query/PromoCampaignPage/PromoCampaignPage.graphql"
|
||||||
import {
|
import {
|
||||||
GetDaDeEnUrlsStartPage,
|
GetDaDeEnUrlsStartPage,
|
||||||
GetFiNoSvUrlsStartPage,
|
GetFiNoSvUrlsStartPage,
|
||||||
@@ -139,6 +143,10 @@ export async function getUrlsOfAllLanguages(
|
|||||||
daDeEnDocument = GetDaDeEnUrlsStartPage
|
daDeEnDocument = GetDaDeEnUrlsStartPage
|
||||||
fiNoSvDocument = GetFiNoSvUrlsStartPage
|
fiNoSvDocument = GetFiNoSvUrlsStartPage
|
||||||
break
|
break
|
||||||
|
case PageContentTypeEnum.promoCampaignPage:
|
||||||
|
daDeEnDocument = GetDaDeEnUrlsPromoCampaignPage
|
||||||
|
fiNoSvDocument = GetFiNoSvUrlsPromoCampaignPage
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
languageSwitcherLogger.error(
|
languageSwitcherLogger.error(
|
||||||
`Trying to get a content type that is not supported, ${contentType}`
|
`Trying to get a content type that is not supported, ${contentType}`
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { GetDestinationCountryPageMetadata } from "../../../graphql/Query/Destin
|
|||||||
import { GetDestinationOverviewPageMetadata } from "../../../graphql/Query/DestinationOverviewPage/Metadata.graphql"
|
import { GetDestinationOverviewPageMetadata } from "../../../graphql/Query/DestinationOverviewPage/Metadata.graphql"
|
||||||
import { GetHotelPageMetadata } from "../../../graphql/Query/HotelPage/Metadata.graphql"
|
import { GetHotelPageMetadata } from "../../../graphql/Query/HotelPage/Metadata.graphql"
|
||||||
import { GetLoyaltyPageMetadata } from "../../../graphql/Query/LoyaltyPage/Metadata.graphql"
|
import { GetLoyaltyPageMetadata } from "../../../graphql/Query/LoyaltyPage/Metadata.graphql"
|
||||||
|
import { GetPromoCampaignPageMetadata } from "../../../graphql/Query/PromoCampaignPage/Metadata.graphql"
|
||||||
import { GetStartPageMetadata } from "../../../graphql/Query/StartPage/Metadata.graphql"
|
import { GetStartPageMetadata } from "../../../graphql/Query/StartPage/Metadata.graphql"
|
||||||
import { request } from "../../../graphql/request"
|
import { request } from "../../../graphql/request"
|
||||||
import { contentStackUidWithServiceProcedure } from "../../../procedures"
|
import { contentStackUidWithServiceProcedure } from "../../../procedures"
|
||||||
@@ -202,6 +203,12 @@ export const metadataQueryRouter = router({
|
|||||||
}>(GetStartPageMetadata, variables)
|
}>(GetStartPageMetadata, variables)
|
||||||
data = startPageResponse.start_page
|
data = startPageResponse.start_page
|
||||||
break
|
break
|
||||||
|
case PageContentTypeEnum.promoCampaignPage:
|
||||||
|
const promoCampaignPageResponse = await fetchMetadata<{
|
||||||
|
promo_campaign_page: RawMetadataSchema
|
||||||
|
}>(GetPromoCampaignPageMetadata, variables)
|
||||||
|
data = promoCampaignPageResponse.promo_campaign_page
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
GetDestinationOverviewPageSettings,
|
GetDestinationOverviewPageSettings,
|
||||||
GetHotelPageSettings,
|
GetHotelPageSettings,
|
||||||
GetLoyaltyPageSettings,
|
GetLoyaltyPageSettings,
|
||||||
|
GetPromoCampaignPageSettings,
|
||||||
GetStartPageSettings,
|
GetStartPageSettings,
|
||||||
} from "../../../graphql/Query/PageSettings.graphql"
|
} from "../../../graphql/Query/PageSettings.graphql"
|
||||||
import { request } from "../../../graphql/request"
|
import { request } from "../../../graphql/request"
|
||||||
@@ -87,4 +88,5 @@ const graphqlQueriesForContentType: Record<PageContentTypeEnum, any> = {
|
|||||||
[PageContentTypeEnum.hotelPage]: GetHotelPageSettings,
|
[PageContentTypeEnum.hotelPage]: GetHotelPageSettings,
|
||||||
[PageContentTypeEnum.loyaltyPage]: GetLoyaltyPageSettings,
|
[PageContentTypeEnum.loyaltyPage]: GetLoyaltyPageSettings,
|
||||||
[PageContentTypeEnum.startPage]: GetStartPageSettings,
|
[PageContentTypeEnum.startPage]: GetStartPageSettings,
|
||||||
|
[PageContentTypeEnum.promoCampaignPage]: GetPromoCampaignPageSettings,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { mergeRouters } from "../../.."
|
||||||
|
import { promoCampaignPageQueryRouter } from "./query"
|
||||||
|
|
||||||
|
export const promoCampaignPageRouter = mergeRouters(
|
||||||
|
promoCampaignPageQueryRouter
|
||||||
|
)
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/stringValidator"
|
||||||
|
|
||||||
|
import { systemSchema } from "../schemas/system"
|
||||||
|
|
||||||
|
export const CAMPAIGN_TYPES = {
|
||||||
|
TIER: "TIER",
|
||||||
|
POINT: "POINT",
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const promoCampaignPageSchema = z
|
||||||
|
.object({
|
||||||
|
promo_campaign_page: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
heading: z.string(),
|
||||||
|
subheading: z.string().nullish(),
|
||||||
|
page_settings: z
|
||||||
|
.object({
|
||||||
|
booking_code: z.string().nullish(),
|
||||||
|
})
|
||||||
|
.nullish(),
|
||||||
|
campaign_type: z.nativeEnum(CAMPAIGN_TYPES),
|
||||||
|
promo_code: z.string(),
|
||||||
|
startdate: nullableStringValidator,
|
||||||
|
enddate: nullableStringValidator,
|
||||||
|
system: systemSchema.merge(
|
||||||
|
z.object({
|
||||||
|
created_at: z.string(),
|
||||||
|
updated_at: z.string(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
trackingProps: z.object({
|
||||||
|
url: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.transform(({ promo_campaign_page, ...data }) => {
|
||||||
|
const { page_settings, ...promoCampaignPageData } = promo_campaign_page
|
||||||
|
const bookingCode = page_settings?.booking_code || null
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
promo_campaign_page: {
|
||||||
|
bookingCode,
|
||||||
|
...promoCampaignPageData,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** REFS */
|
||||||
|
export const promoCampaignPageRefsSchema = z.object({
|
||||||
|
promo_campaign_page: z.object({
|
||||||
|
system: systemSchema,
|
||||||
|
}),
|
||||||
|
})
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
|
import { router } from "../../.."
|
||||||
|
import { notFound } from "../../../errors"
|
||||||
|
import {
|
||||||
|
GetPromoCampaignPage,
|
||||||
|
GetPromoCampaignPageRefs,
|
||||||
|
} from "../../../graphql/Query/PromoCampaignPage/PromoCampaignPage.graphql"
|
||||||
|
import { request } from "../../../graphql/request"
|
||||||
|
import { contentStackUidWithServiceProcedure } from "../../../procedures"
|
||||||
|
import { generateRefsResponseTag } from "../../../utils/generateTag"
|
||||||
|
import { promoCampaignPageRefsSchema, promoCampaignPageSchema } from "./output"
|
||||||
|
import { generatePageTags } from "./utils"
|
||||||
|
|
||||||
|
import type {
|
||||||
|
GetPromoCampaignPageData,
|
||||||
|
GetPromoCampaignPageRefsData,
|
||||||
|
} from "../../../types/promoCampaignPage"
|
||||||
|
import type { TrackingPageData } from "../../types"
|
||||||
|
|
||||||
|
export const promoCampaignPageQueryRouter = router({
|
||||||
|
get: contentStackUidWithServiceProcedure.query(async ({ ctx }) => {
|
||||||
|
const { lang, uid } = ctx
|
||||||
|
|
||||||
|
const getPromoCampaignPageRefsCounter = createCounter(
|
||||||
|
"trpc.contentstack",
|
||||||
|
"promoCampaignPage.get.refs"
|
||||||
|
)
|
||||||
|
const metricsGetPromoCampaignPageRefs =
|
||||||
|
getPromoCampaignPageRefsCounter.init({
|
||||||
|
lang,
|
||||||
|
uid,
|
||||||
|
})
|
||||||
|
|
||||||
|
metricsGetPromoCampaignPageRefs.start()
|
||||||
|
|
||||||
|
const refsResponse = await request<GetPromoCampaignPageRefsData>(
|
||||||
|
GetPromoCampaignPageRefs,
|
||||||
|
{ locale: lang, uid },
|
||||||
|
{
|
||||||
|
key: generateRefsResponseTag(lang, uid),
|
||||||
|
ttl: "max",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (!refsResponse.data) {
|
||||||
|
const notFoundError = notFound(refsResponse)
|
||||||
|
metricsGetPromoCampaignPageRefs.noDataError()
|
||||||
|
throw notFoundError
|
||||||
|
}
|
||||||
|
|
||||||
|
const validatedRefsData = promoCampaignPageRefsSchema.safeParse(
|
||||||
|
refsResponse.data
|
||||||
|
)
|
||||||
|
if (!validatedRefsData.success) {
|
||||||
|
metricsGetPromoCampaignPageRefs.validationError(validatedRefsData.error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
metricsGetPromoCampaignPageRefs.success()
|
||||||
|
|
||||||
|
const tags = generatePageTags(validatedRefsData.data, lang)
|
||||||
|
|
||||||
|
const getPromoCampaignPageCounter = createCounter(
|
||||||
|
"trpc.contentstack",
|
||||||
|
"promoCampaignPage.get"
|
||||||
|
)
|
||||||
|
const metricsGetPromoCampaignPage = getPromoCampaignPageCounter.init({
|
||||||
|
lang,
|
||||||
|
uid,
|
||||||
|
})
|
||||||
|
|
||||||
|
metricsGetPromoCampaignPage.start()
|
||||||
|
|
||||||
|
const response = await request<GetPromoCampaignPageData>(
|
||||||
|
GetPromoCampaignPage,
|
||||||
|
{
|
||||||
|
locale: lang,
|
||||||
|
uid,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: tags,
|
||||||
|
ttl: "max",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (!response.data) {
|
||||||
|
const notFoundError = notFound(response)
|
||||||
|
metricsGetPromoCampaignPage.noDataError()
|
||||||
|
throw notFoundError
|
||||||
|
}
|
||||||
|
|
||||||
|
const validatedResponse = promoCampaignPageSchema.safeParse(response.data)
|
||||||
|
|
||||||
|
if (!validatedResponse.success) {
|
||||||
|
metricsGetPromoCampaignPage.validationError(validatedResponse.error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const { promo_campaign_page, trackingProps } = validatedResponse.data
|
||||||
|
|
||||||
|
metricsGetPromoCampaignPage.success()
|
||||||
|
|
||||||
|
const system = promo_campaign_page.system
|
||||||
|
const pageName = trackingProps.url
|
||||||
|
|
||||||
|
const tracking: TrackingPageData = {
|
||||||
|
pageId: system.uid,
|
||||||
|
domainLanguage: system.locale,
|
||||||
|
publishDate: system.updated_at,
|
||||||
|
createDate: system.created_at,
|
||||||
|
channel: "promo-campaign",
|
||||||
|
pageType: "promocampaignpage",
|
||||||
|
pageName,
|
||||||
|
siteSections: pageName,
|
||||||
|
siteVersion: "new-web",
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
promo_campaign_page,
|
||||||
|
tracking,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
})
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { generateTag, generateTagsFromSystem } from "../../../utils/generateTag"
|
||||||
|
|
||||||
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
|
|
||||||
|
import type { PromoCampaignPageRefs } from "../../../types/promoCampaignPage"
|
||||||
|
import type { System } from "../schemas/system"
|
||||||
|
|
||||||
|
export function generatePageTags(
|
||||||
|
validatedData: PromoCampaignPageRefs,
|
||||||
|
lang: Lang
|
||||||
|
): string[] {
|
||||||
|
const connections = getConnections(validatedData)
|
||||||
|
return [
|
||||||
|
generateTagsFromSystem(lang, connections),
|
||||||
|
generateTag(lang, validatedData.promo_campaign_page.system.uid),
|
||||||
|
].flat()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getConnections({ promo_campaign_page }: PromoCampaignPageRefs) {
|
||||||
|
const connections: System["system"][] = [promo_campaign_page.system]
|
||||||
|
|
||||||
|
return connections
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ type TrackingSDKChannel =
|
|||||||
| "campaign"
|
| "campaign"
|
||||||
| "hotels"
|
| "hotels"
|
||||||
| "homepage"
|
| "homepage"
|
||||||
|
| "promo-campaign"
|
||||||
|
|
||||||
export type TrackingUserData =
|
export type TrackingUserData =
|
||||||
| {
|
| {
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ export const validateEntryResolveSchema = z.object({
|
|||||||
all_destination_country_page: entryResolveSchema,
|
all_destination_country_page: entryResolveSchema,
|
||||||
all_destination_city_page: entryResolveSchema,
|
all_destination_city_page: entryResolveSchema,
|
||||||
all_start_page: entryResolveSchema,
|
all_start_page: entryResolveSchema,
|
||||||
|
all_promo_campaign_page: entryResolveSchema,
|
||||||
})
|
})
|
||||||
|
|||||||
29
packages/trpc/lib/types/promoCampaignPage.ts
Normal file
29
packages/trpc/lib/types/promoCampaignPage.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import type { z } from "zod"
|
||||||
|
|
||||||
|
import type {
|
||||||
|
promoCampaignPageRefsSchema,
|
||||||
|
promoCampaignPageSchema,
|
||||||
|
} from "../routers/contentstack/promoCampaignPage/output"
|
||||||
|
|
||||||
|
export namespace PromoCampaignPageEnum {
|
||||||
|
export namespace ContentStack {
|
||||||
|
export const enum blocks {
|
||||||
|
Accordion = "PromoCampaignPageBlocksAccordion",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetPromoCampaignPageData
|
||||||
|
extends z.input<typeof promoCampaignPageSchema> {}
|
||||||
|
|
||||||
|
export interface PromoCampaignPage
|
||||||
|
extends z.output<typeof promoCampaignPageSchema> {}
|
||||||
|
|
||||||
|
export type PromoCampaignPageData = PromoCampaignPage["promo_campaign_page"]
|
||||||
|
|
||||||
|
/* REFS */
|
||||||
|
export interface GetPromoCampaignPageRefsData
|
||||||
|
extends z.input<typeof promoCampaignPageRefsSchema> {}
|
||||||
|
|
||||||
|
export interface PromoCampaignPageRefs
|
||||||
|
extends z.output<typeof promoCampaignPageRefsSchema> {}
|
||||||
@@ -4,6 +4,7 @@ import { batchRequest } from "../graphql/batchRequest"
|
|||||||
import {
|
import {
|
||||||
EntryByUrlBatch1,
|
EntryByUrlBatch1,
|
||||||
EntryByUrlBatch2,
|
EntryByUrlBatch2,
|
||||||
|
EntryByUrlBatch3,
|
||||||
} from "../graphql/Query/ResolveEntry.graphql"
|
} from "../graphql/Query/ResolveEntry.graphql"
|
||||||
import { validateEntryResolveSchema } from "../types/entry"
|
import { validateEntryResolveSchema } from "../types/entry"
|
||||||
|
|
||||||
@@ -34,10 +35,16 @@ export async function resolve(url: string, lang = Lang.en) {
|
|||||||
key: cacheKey,
|
key: cacheKey,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
document: EntryByUrlBatch3,
|
||||||
|
variables,
|
||||||
|
cacheOptions: {
|
||||||
|
ttl: "max",
|
||||||
|
key: cacheKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
const validatedData = validateEntryResolveSchema.safeParse(response.data)
|
const validatedData = validateEntryResolveSchema.safeParse(response.data)
|
||||||
|
|
||||||
if (!validatedData.success) {
|
if (!validatedData.success) {
|
||||||
return {
|
return {
|
||||||
error: validatedData.error,
|
error: validatedData.error,
|
||||||
|
|||||||
Reference in New Issue
Block a user