diff --git a/apps/scandic-web/components/ContentType/StaticPages/index.tsx b/apps/scandic-web/components/ContentType/StaticPages/index.tsx
index f70b9beb0..bd1582273 100644
--- a/apps/scandic-web/components/ContentType/StaticPages/index.tsx
+++ b/apps/scandic-web/components/ContentType/StaticPages/index.tsx
@@ -2,6 +2,7 @@ import Link from "next/link"
import { Suspense } from "react"
import Blocks from "@/components/Blocks"
+import HeaderDynamicContent from "@/components/Headers/DynamicContent"
import Hero from "@/components/Hero"
import MeetingPackageWidget from "@/components/MeetingPackageWidget"
import Sidebar from "@/components/Sidebar"
@@ -52,6 +53,9 @@ export default async function StaticPage({
{header.navigation_links ? (
) : null}
+ {"dynamic_content" in header && header.dynamic_content ? (
+
+ ) : null}
>
) : null}
diff --git a/apps/scandic-web/components/Sidebar/EmployeeBenefits/AuthCard/authCard.module.css b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/authCard.module.css
similarity index 100%
rename from apps/scandic-web/components/Sidebar/EmployeeBenefits/AuthCard/authCard.module.css
rename to apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/authCard.module.css
diff --git a/apps/scandic-web/components/Sidebar/EmployeeBenefits/AuthCard/index.tsx b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/index.tsx
similarity index 100%
rename from apps/scandic-web/components/Sidebar/EmployeeBenefits/AuthCard/index.tsx
rename to apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/index.tsx
diff --git a/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/callToActions.module.css b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/callToActions.module.css
new file mode 100644
index 000000000..bd002c2c8
--- /dev/null
+++ b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/callToActions.module.css
@@ -0,0 +1,7 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: var(--Spacing-x-one-and-half);
+ padding-bottom: var(--Spacing-x3);
+}
diff --git a/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx
new file mode 100644
index 000000000..54242fe4a
--- /dev/null
+++ b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx
@@ -0,0 +1,71 @@
+import React from "react"
+
+import { Typography } from "@scandic-hotels/design-system/Typography"
+
+import { login } from "@/constants/routes/handleAuth"
+import { signup } from "@/constants/routes/signup"
+
+import { auth } from "@/auth"
+import ButtonLink from "@/components/ButtonLink"
+import { getIntl } from "@/i18n"
+import { getLang } from "@/i18n/serverContext"
+import { isValidSession } from "@/utils/session"
+
+import styles from "./callToActions.module.css"
+
+export default async function EmployeeBenefitsCallToActions() {
+ const session = await auth()
+ const intl = await getIntl()
+ const lang = getLang()
+
+ if (!isValidSession(session)) {
+ return (
+ <>
+
+
+
+ {intl.formatMessage({
+ defaultMessage: "Already a Scandic Friends account?",
+ })}
+
+
+
+ {intl.formatMessage({
+ defaultMessage: "Log in and link employment",
+ })}
+
+
+
+
+
+
+ {intl.formatMessage({
+ defaultMessage: "Don't have a Scandic Friends account yet?",
+ })}
+
+
+
+ {intl.formatMessage({
+ defaultMessage: "Sign up and link employment",
+ })}
+
+
+ >
+ )
+ }
+
+ // -- TODO [LOY-196] --
+ // Handle case of authed user and already connected work account.
+ // Show member card modal.
+
+ return (
+
+ {/*/ TODO [LOY-229]: Update href once we have new auth url. */}
+
+ {intl.formatMessage({
+ defaultMessage: "Link Employment",
+ })}
+
+
+ )
+}
diff --git a/apps/scandic-web/components/Headers/DynamicContent/index.tsx b/apps/scandic-web/components/Headers/DynamicContent/index.tsx
new file mode 100644
index 000000000..fdfa67fec
--- /dev/null
+++ b/apps/scandic-web/components/Headers/DynamicContent/index.tsx
@@ -0,0 +1,27 @@
+import { Suspense } from "react"
+
+import EmployeeBenefitsCallToActions from "@/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions"
+import LoadingSpinner from "@/components/LoadingSpinner"
+
+import type { HeaderDynamicContentProps } from "@/types/components/headers/dynamicContent"
+import { DynamicContentEnum } from "@/types/enums/dynamicContent"
+
+export default function HeaderDynamicContent(props: HeaderDynamicContentProps) {
+ return (
+ }>
+
+
+ )
+}
+
+function HeaderDynamicContentComponent(props: HeaderDynamicContentProps) {
+ const { component } = props
+
+ switch (component) {
+ case DynamicContentEnum.Headers.components
+ .dtmc_employee_benefits_call_to_actions:
+ return
+ default:
+ return null
+ }
+}
diff --git a/apps/scandic-web/components/Sidebar/index.tsx b/apps/scandic-web/components/Sidebar/index.tsx
index 72d62fbbf..ac1ad3c32 100644
--- a/apps/scandic-web/components/Sidebar/index.tsx
+++ b/apps/scandic-web/components/Sidebar/index.tsx
@@ -1,9 +1,9 @@
+import EmployeeBenefitsAuthCard from "@/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard"
import JsonToHtml from "@/components/JsonToHtml"
import ShortcutsList from "../Blocks/ShortcutsList"
import Card from "../TempDesignSystem/Card"
import TeaserCard from "../TempDesignSystem/TeaserCard"
-import EmployeeBenefitsAuthCard from "./EmployeeBenefits/AuthCard"
import JoinLoyaltyContact from "./JoinLoyalty"
import MyPagesNavigation from "./MyPagesNavigation"
diff --git a/apps/scandic-web/lib/graphql/Query/ContentPage/ContentPage.graphql b/apps/scandic-web/lib/graphql/Query/ContentPage/ContentPage.graphql
index 0508fea97..3efa50899 100644
--- a/apps/scandic-web/lib/graphql/Query/ContentPage/ContentPage.graphql
+++ b/apps/scandic-web/lib/graphql/Query/ContentPage/ContentPage.graphql
@@ -26,6 +26,9 @@ query GetContentPage($locale: String!, $uid: String!) {
header {
heading
preamble
+ dynamic_content {
+ component
+ }
...TopPrimaryButton_ContentPage
...NavigationLinks_ContentPage
}
@@ -84,6 +87,9 @@ query GetContentPageBlocksBatch2($locale: String!, $uid: String!) {
query GetContentPageRefs($locale: String!, $uid: String!) {
content_page(locale: $locale, uid: $uid) {
header {
+ dynamic_content {
+ component
+ }
...NavigationLinksRef_ContentPage
...TopPrimaryButtonRef_ContentPage
}
diff --git a/apps/scandic-web/server/routers/contentstack/contentPage/output.ts b/apps/scandic-web/server/routers/contentstack/contentPage/output.ts
index 631efcf4f..17eb6ebd6 100644
--- a/apps/scandic-web/server/routers/contentstack/contentPage/output.ts
+++ b/apps/scandic-web/server/routers/contentstack/contentPage/output.ts
@@ -26,6 +26,10 @@ import {
import { tableSchema } from "../schemas/blocks/table"
import { textColsRefsSchema, textColsSchema } from "../schemas/blocks/textCols"
import { uspGridRefsSchema, uspGridSchema } from "../schemas/blocks/uspGrid"
+import {
+ dynamicContentRefsSchema as headerDynamicContentRefsSchema,
+ dynamicContentSchema as headerDynamicContentSchema,
+} from "../schemas/headers/dynamicContent"
import { tempImageVaultAssetSchema } from "../schemas/imageVault"
import {
linkAndTitleSchema,
@@ -210,6 +214,7 @@ export const contentPageSchema = z.object({
preamble: z.string(),
top_primary_button: topPrimaryButtonSchema,
navigation_links: navigationLinksSchema,
+ dynamic_content: headerDynamicContentSchema.optional(),
}),
meeting_package: z
.object({
@@ -325,6 +330,7 @@ const contentPageSidebarRefsItem = z.discriminatedUnion("__typename", [
const contentPageHeaderRefs = z.object({
navigation_links: z.array(linkConnectionRefs),
top_primary_button: linkConnectionRefs.nullable(),
+ dynamic_content: headerDynamicContentRefsSchema.optional(),
})
export const contentPageRefsSchema = z.object({
diff --git a/apps/scandic-web/server/routers/contentstack/schemas/headers/dynamicContent.ts b/apps/scandic-web/server/routers/contentstack/schemas/headers/dynamicContent.ts
new file mode 100644
index 000000000..fb513cc1f
--- /dev/null
+++ b/apps/scandic-web/server/routers/contentstack/schemas/headers/dynamicContent.ts
@@ -0,0 +1,11 @@
+import { z } from "zod"
+
+import { DynamicContentEnum } from "@/types/enums/dynamicContent"
+
+export const dynamicContentSchema = z.object({
+ component: z.enum(DynamicContentEnum.Headers.enums),
+})
+
+export const dynamicContentRefsSchema = z.object({
+ component: z.enum(DynamicContentEnum.Headers.enums),
+})
diff --git a/apps/scandic-web/types/components/headers/dynamicContent.ts b/apps/scandic-web/types/components/headers/dynamicContent.ts
new file mode 100644
index 000000000..ef89d3f41
--- /dev/null
+++ b/apps/scandic-web/types/components/headers/dynamicContent.ts
@@ -0,0 +1,5 @@
+import type { z } from "zod"
+
+import type { dynamicContentSchema } from "@/server/routers/contentstack/schemas/headers/dynamicContent"
+
+export type HeaderDynamicContentProps = z.infer
diff --git a/apps/scandic-web/types/enums/dynamicContent.ts b/apps/scandic-web/types/enums/dynamicContent.ts
index e4f022f3e..8e29e2cc9 100644
--- a/apps/scandic-web/types/enums/dynamicContent.ts
+++ b/apps/scandic-web/types/enums/dynamicContent.ts
@@ -1,61 +1,90 @@
+// Helper type to get a union of an object's string literal values
+type ValueOf = T[keyof T]
+
export namespace DynamicContentEnum {
export namespace Blocks {
- export const enum components {
- current_benefits = "current_benefits",
- earn_and_burn = "earn_and_burn",
- expiring_points = "expiring_points",
- how_it_works = "how_it_works",
- jobylon_feed = "jobylon_feed",
- loyalty_levels = "loyalty_levels",
- membership_overview = "membership_overview",
- my_points = "my_points",
- next_benefits = "next_benefits",
- overview_table = "overview_table",
- points_overview = "points_overview",
- previous_stays = "previous_stays",
- sign_up_form = "sign_up_form",
- sign_up_verification = "sign_up_verification",
- soonest_stays = "soonest_stays",
- upcoming_stays = "upcoming_stays",
- sas_linked_account = "sas_linked_account",
- sas_transfer_points = "sas_transfer_points",
- sas_tier_comparison = "sas_tier_comparison",
- }
+ export const components = {
+ current_benefits: "current_benefits",
+ earn_and_burn: "earn_and_burn",
+ expiring_points: "expiring_points",
+ how_it_works: "how_it_works",
+ jobylon_feed: "jobylon_feed",
+ loyalty_levels: "loyalty_levels",
+ membership_overview: "membership_overview",
+ my_points: "my_points",
+ next_benefits: "next_benefits",
+ overview_table: "overview_table",
+ points_overview: "points_overview",
+ previous_stays: "previous_stays",
+ sign_up_form: "sign_up_form",
+ sign_up_verification: "sign_up_verification",
+ soonest_stays: "soonest_stays",
+ upcoming_stays: "upcoming_stays",
+ sas_linked_account: "sas_linked_account",
+ sas_transfer_points: "sas_transfer_points",
+ sas_tier_comparison: "sas_tier_comparison",
+ } as const
- /** Type needed to satisfy zod enum type */
- export const enums: [components, ...components[]] = [
- components.current_benefits,
- components.earn_and_burn,
- components.expiring_points,
- components.how_it_works,
- components.jobylon_feed,
- components.loyalty_levels,
- components.membership_overview,
- components.my_points,
- components.next_benefits,
- components.overview_table,
- components.points_overview,
- components.previous_stays,
- components.sign_up_form,
- components.sign_up_verification,
- components.soonest_stays,
- components.upcoming_stays,
- components.sas_linked_account,
- components.sas_transfer_points,
- components.sas_tier_comparison,
+ /**
+ * Represents one of the possible component string literal values from Blocks.components.
+ * e.g., "current_benefits" | "earn_and_burn" | ...
+ */
+ type ComponentValue = ValueOf
+
+ /**
+ * Array of all component string literal values from Blocks.components.
+ * Typed as a non-empty tuple `[ComponentValue, ...ComponentValue[]]`,
+ * to ensure it meets Zod's z.enum() requirements.
+ */
+ export const enums = Object.values(components) as [
+ ComponentValue,
+ ...ComponentValue[],
+ ]
+ }
+
+ export namespace Headers {
+ export const components = {
+ dtmc_employee_benefits_call_to_actions:
+ "dtmc_employee_benefits_call_to_actions",
+ } as const
+
+ /**
+ * Represents one of the possible component string literal values from Headers.components.
+ * e.g., "dtmc_employee_benefits_call_to_actions"
+ */
+ type ComponentValue = ValueOf
+
+ /**
+ * Array of all component string literal values from Headers.components.
+ * Typed as a non-empty tuple `[ComponentValue, ...ComponentValue[]]`,
+ * to ensure it meets Zod's z.enum() requirements.
+ */
+ export const enums = Object.values(components) as [
+ ComponentValue,
+ ...ComponentValue[],
]
}
export namespace Sidebar {
- export const enum components {
- my_pages_navigation = "my_pages_navigation",
- employee_benefits_auth_card = "employee_benefits_auth_card",
- }
+ export const components = {
+ my_pages_navigation: "my_pages_navigation",
+ employee_benefits_auth_card: "employee_benefits_auth_card",
+ } as const
- /** Type needed to satisfy zod enum type */
- export const enums: [string, ...string[]] = [
- components.my_pages_navigation,
- components.employee_benefits_auth_card,
+ /**
+ * Represents one of the possible component string literal values from Sidebar.components.
+ * e.g., "my_pages_navigation" | "employee_benefits_auth_card"
+ */
+ type ComponentValue = ValueOf
+
+ /**
+ * Array of all component string literal values from Sidebar.components.
+ * Typed as a non-empty tuple `[ComponentValue, ...ComponentValue[]]`,
+ * to ensure it meets Zod's z.enum() requirements.
+ */
+ export const enums = Object.values(components) as [
+ ComponentValue,
+ ...ComponentValue[],
]
}
}