diff --git a/components/Blocks/UspGrid/index.tsx b/components/Blocks/UspGrid/index.tsx
new file mode 100644
index 000000000..26110c622
--- /dev/null
+++ b/components/Blocks/UspGrid/index.tsx
@@ -0,0 +1,35 @@
+import { getIconByIconName } from "@/components/Icons/get-icon-by-icon-name"
+import JsonToHtml from "@/components/JsonToHtml"
+
+import { renderOptions } from "./renderOptions"
+import { getUspIconName } from "./utils"
+
+import styles from "./uspgrid.module.css"
+
+import type { UspGridProps, UspIcon } from "@/types/components/blocks/uspGrid"
+
+function UspIcon({ icon }: { icon: UspIcon }) {
+ const iconName = getUspIconName(icon)
+ const Icon = iconName ? getIconByIconName(iconName) : null
+ return Icon ? : null
+}
+
+export default function UspGrid({ usp_grid }: UspGridProps) {
+ return (
+
+ {usp_grid.usp_card.map(
+ (usp) =>
+ usp.text.json && (
+
+
+
+
+ )
+ )}
+
+ )
+}
diff --git a/components/Blocks/UspGrid/renderOptions.tsx b/components/Blocks/UspGrid/renderOptions.tsx
new file mode 100644
index 000000000..a4033fec5
--- /dev/null
+++ b/components/Blocks/UspGrid/renderOptions.tsx
@@ -0,0 +1,73 @@
+import Link from "@/components/TempDesignSystem/Link"
+import { removeMultipleSlashes } from "@/utils/url"
+
+import styles from "./uspgrid.module.css"
+
+import { EmbedEnum } from "@/types/requests/utils/embeds"
+import type { EmbedByUid } from "@/types/transitionTypes/jsontohtml"
+import { RTEItemTypeEnum, RTETypeEnum } from "@/types/transitionTypes/rte/enums"
+import type {
+ RTEDefaultNode,
+ RTENext,
+ RTENode,
+ RTERegularNode,
+} from "@/types/transitionTypes/rte/node"
+import type { RenderOptions } from "@/types/transitionTypes/rte/option"
+
+export const renderOptions: RenderOptions = {
+ [RTETypeEnum.p]: (
+ node: RTEDefaultNode,
+ embeds: EmbedByUid,
+ next: RTENext,
+ fullRenderOptions: RenderOptions
+ ) => {
+ return (
+
+ {next(node.children, embeds, fullRenderOptions)}
+
+ )
+ },
+ [RTETypeEnum.a]: (
+ node: RTERegularNode,
+ embeds: EmbedByUid,
+ next: RTENext,
+ fullRenderOptions: RenderOptions
+ ) => {
+ if (node.attrs.url) {
+ return (
+
+ {next(node.children, embeds, fullRenderOptions)}
+
+ )
+ }
+ return null
+ },
+ [RTETypeEnum.reference]: (
+ node: RTENode,
+ embeds: EmbedByUid,
+ next: RTENext,
+ fullRenderOptions: RenderOptions
+ ) => {
+ if ("attrs" in node) {
+ const type = node.attrs.type
+ if (type !== RTEItemTypeEnum.asset) {
+ const href = node.attrs?.locale
+ ? `/${node.attrs.locale}${node.attrs.href}`
+ : node.attrs.href
+
+ return (
+
+ {next(node.children, embeds, fullRenderOptions)}
+
+ )
+ }
+
+ return null
+ }
+ },
+}
diff --git a/components/Blocks/UspGrid/uspgrid.module.css b/components/Blocks/UspGrid/uspgrid.module.css
new file mode 100644
index 000000000..042acd9b3
--- /dev/null
+++ b/components/Blocks/UspGrid/uspgrid.module.css
@@ -0,0 +1,28 @@
+.grid {
+ display: grid;
+ gap: var(--Spacing-x3);
+ padding: var(--Spacing-x3) var(--Spacing-x4);
+}
+@media screen and (min-width: 767px) {
+ .grid {
+ grid-template-columns: repeat(3, 1fr);
+ }
+ .grid:has(.usp:nth-child(4)) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+.usp {
+ display: flex;
+ flex-direction: column;
+ gap: var(--Spacing-x3);
+}
+.p {
+ margin: 0;
+ font-size: var(--typography-Caption-Regular-fontSize);
+ color: var(--UI-Text-Medium-contrast);
+ line-height: 21px; /* Caption variable for line-height is 139.9999976158142%, but it set to 21px in design */
+}
+.a {
+ font-size: var(--typography-Caption-Regular-fontSize);
+ color: var(--Base-Text-High-contrast);
+}
diff --git a/components/Blocks/UspGrid/utils.ts b/components/Blocks/UspGrid/utils.ts
new file mode 100644
index 000000000..700482909
--- /dev/null
+++ b/components/Blocks/UspGrid/utils.ts
@@ -0,0 +1,11 @@
+import { UspIcon } from "@/types/components/blocks/uspGrid"
+import { IconName } from "@/types/components/icon"
+
+export function getUspIconName(icon?: UspIcon | null) {
+ switch (icon) {
+ case "Snowflake":
+ return IconName.Snowflake
+ default:
+ return IconName.Snowflake
+ }
+}
diff --git a/components/Blocks/index.tsx b/components/Blocks/index.tsx
index 9946a6fa0..1c6d0bcbc 100644
--- a/components/Blocks/index.tsx
+++ b/components/Blocks/index.tsx
@@ -2,6 +2,7 @@ import CardsGrid from "@/components/Blocks/CardsGrid"
import DynamicContent from "@/components/Blocks/DynamicContent"
import Shortcuts from "@/components/Blocks/Shortcuts"
import TextCols from "@/components/Blocks/TextCols"
+import UspGrid from "@/components/Blocks/UspGrid"
import JsonToHtml from "@/components/JsonToHtml"
import type { BlocksProps } from "@/types/components/blocks"
@@ -57,6 +58,8 @@ export default function Blocks({ blocks }: BlocksProps) {
/>
)
+ case BlocksEnums.block.UspGrid:
+ return
default:
return null
}
diff --git a/components/Icons/Snowflake.tsx b/components/Icons/Snowflake.tsx
new file mode 100644
index 000000000..06389343f
--- /dev/null
+++ b/components/Icons/Snowflake.tsx
@@ -0,0 +1,27 @@
+import { iconVariants } from "./variants"
+
+import type { IconProps } from "@/types/components/icon"
+
+export default function SnowflakeIcon({
+ className,
+ color,
+ ...props
+}: IconProps) {
+ const classNames = iconVariants({ className, color })
+ return (
+
+ )
+}
diff --git a/components/Icons/get-icon-by-icon-name.ts b/components/Icons/get-icon-by-icon-name.ts
index 117971b3c..92d674299 100644
--- a/components/Icons/get-icon-by-icon-name.ts
+++ b/components/Icons/get-icon-by-icon-name.ts
@@ -49,6 +49,7 @@ import {
SearchIcon,
ServiceIcon,
ShoppingIcon,
+ SnowflakeIcon,
StarFilledIcon,
TrainIcon,
TshirtWashIcon,
@@ -154,6 +155,8 @@ export function getIconByIconName(icon?: IconName): FC | null {
return ServiceIcon
case IconName.Shopping:
return ShoppingIcon
+ case IconName.Snowflake:
+ return SnowflakeIcon
case IconName.StarFilled:
return StarFilledIcon
case IconName.Train:
diff --git a/components/Icons/index.tsx b/components/Icons/index.tsx
index c1806693d..433ef0c89 100644
--- a/components/Icons/index.tsx
+++ b/components/Icons/index.tsx
@@ -48,6 +48,7 @@ export { default as ScandicLogoIcon } from "./ScandicLogo"
export { default as SearchIcon } from "./Search"
export { default as ServiceIcon } from "./Service"
export { default as ShoppingIcon } from "./Shopping"
+export { default as SnowflakeIcon } from "./Snowflake"
export { default as StarFilledIcon } from "./StarFilled"
export { default as TrainIcon } from "./Train"
export { default as TshirtWashIcon } from "./TshirtWash"
diff --git a/lib/graphql/Fragments/Blocks/UspGrid.graphql b/lib/graphql/Fragments/Blocks/UspGrid.graphql
index 6ccc2a587..ae2df5aa8 100644
--- a/lib/graphql/Fragments/Blocks/UspGrid.graphql
+++ b/lib/graphql/Fragments/Blocks/UspGrid.graphql
@@ -16,6 +16,7 @@ fragment UspGrid_ContentPage on ContentPageBlocksUspGrid {
node {
... on UspGrid {
usp_card {
+ __typename
icon
text {
embedded_itemsConnection {
@@ -54,7 +55,7 @@ fragment UspGrid_ContentPageRefs on ContentPageBlocksUspGrid {
__typename
...AccountPageRef
...ContentPageRef
- ...ImageContainerRef
+ ...HotelPageRef
...LoyaltyPageRef
}
}
diff --git a/server/routers/contentstack/contentPage/output.ts b/server/routers/contentstack/contentPage/output.ts
index bb2728e63..8048faee6 100644
--- a/server/routers/contentstack/contentPage/output.ts
+++ b/server/routers/contentstack/contentPage/output.ts
@@ -19,7 +19,7 @@ import {
shortcutsSchema,
} from "../schemas/blocks/shortcuts"
import { textColsRefsSchema, textColsSchema } from "../schemas/blocks/textCols"
-import { uspGridSchema } from "../schemas/blocks/uspGrid"
+import { uspGridRefsSchema, uspGridSchema } from "../schemas/blocks/uspGrid"
import { tempImageVaultAssetSchema } from "../schemas/imageVault"
import {
contentRefsSchema as sidebarContentRefsSchema,
@@ -157,12 +157,19 @@ const contentPageTextColsRefs = z
})
.merge(textColsRefsSchema)
+const contentPageUspGridRefs = z
+ .object({
+ __typename: z.literal(ContentPageEnum.ContentStack.blocks.UspGrid),
+ })
+ .merge(uspGridRefsSchema)
+
const contentPageBlockRefsItem = z.discriminatedUnion("__typename", [
contentPageBlockContentRefs,
contentPageShortcutsRefs,
contentPageCardsRefs,
contentPageDynamicContentRefs,
contentPageTextColsRefs,
+ contentPageUspGridRefs,
])
const contentPageSidebarContentRef = z
diff --git a/server/routers/contentstack/contentPage/utils.ts b/server/routers/contentstack/contentPage/utils.ts
index c4cc9c5c5..78f5a9d7f 100644
--- a/server/routers/contentstack/contentPage/utils.ts
+++ b/server/routers/contentstack/contentPage/utils.ts
@@ -147,6 +147,12 @@ export function getConnections({ content_page }: ContentPageRefs) {
}
break
}
+ case ContentPageEnum.ContentStack.blocks.UspGrid: {
+ if (block.usp_grid.length) {
+ connections.push(...block.usp_grid)
+ }
+ break
+ }
}
})
}
diff --git a/server/routers/contentstack/schemas/blocks/uspGrid.ts b/server/routers/contentstack/schemas/blocks/uspGrid.ts
index d65a5d0f2..277f84968 100644
--- a/server/routers/contentstack/schemas/blocks/uspGrid.ts
+++ b/server/routers/contentstack/schemas/blocks/uspGrid.ts
@@ -5,41 +5,57 @@ import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
import { BlocksEnums } from "@/types/enums/blocks"
import { UspGridEnum } from "@/types/enums/uspGrid"
+const uspCardSchema = z.object({
+ icon: UspGridEnum.uspIcons,
+ text: z.object({
+ json: z.any(), // JSON
+ embedded_itemsConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: z
+ .discriminatedUnion("__typename", [
+ pageLinks.accountPageSchema,
+ pageLinks.contentPageSchema,
+ pageLinks.hotelPageSchema,
+ pageLinks.loyaltyPageSchema,
+ ])
+ .transform((data) => {
+ const link = pageLinks.transform(data)
+ if (link) {
+ return link
+ }
+ return data
+ }),
+ })
+ ),
+ }),
+ }),
+})
+
export const uspGridSchema = z.object({
typename: z
.literal(BlocksEnums.block.UspGrid)
.optional()
.default(BlocksEnums.block.UspGrid),
- usp_grid: z.object({
- usp_card: z.array(
- z.object({
- icon: UspGridEnum.uspIcons,
- text: z.object({
- json: z.any(), // JSON
- embedded_itemsConnection: z.object({
- edges: z.array(
- z.object({
- node: z
- .discriminatedUnion("__typename", [
- pageLinks.accountPageSchema,
- pageLinks.contentPageSchema,
- pageLinks.hotelPageSchema,
- pageLinks.loyaltyPageSchema,
- ])
- .transform((data) => {
- const link = pageLinks.transform(data)
- if (link) {
- return link
- }
- return data
- }),
- })
- ),
- }),
- }),
- })
- ),
- }),
+ usp_grid: z
+ .object({
+ cardsConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: z.object({
+ usp_card: z.array(uspCardSchema),
+ }),
+ })
+ ),
+ }),
+ })
+ .transform((data) => {
+ return {
+ usp_card: data.cardsConnection.edges.flatMap(
+ (edge) => edge.node.usp_card
+ ),
+ }
+ }),
})
const actualRefs = z.discriminatedUnion("__typename", [
@@ -49,30 +65,40 @@ const actualRefs = z.discriminatedUnion("__typename", [
pageLinks.loyaltyPageRefSchema,
])
-type Refs = {
- node: z.TypeOf
-}
-
export const uspGridRefsSchema = z.object({
usp_grid: z
.object({
- usp_card: z.array(
- z.object({
- text: z.object({
- embedded_itemsConnection: z.object({
- edges: z.array(
+ cardsConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: z.object({
+ usp_card: z.array(
z.object({
- node: z.discriminatedUnion("__typename", [
- ...actualRefs.options,
- ]),
+ text: z.object({
+ embedded_itemsConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: z.discriminatedUnion("__typename", [
+ ...actualRefs.options,
+ ]),
+ })
+ ),
+ }),
+ }),
})
),
}),
- }),
- })
- ),
+ })
+ ),
+ }),
})
.transform((data) => {
- return data.usp_card.flat()
+ return data.cardsConnection.edges.flatMap(({ node }) =>
+ node.usp_card.flatMap((card) =>
+ card.text.embedded_itemsConnection.edges.map(
+ ({ node }) => node.system
+ )
+ )
+ )
}),
})
diff --git a/types/components/blocks/uspGrid.ts b/types/components/blocks/uspGrid.ts
new file mode 100644
index 000000000..ea6218541
--- /dev/null
+++ b/types/components/blocks/uspGrid.ts
@@ -0,0 +1,4 @@
+import type { UspGrid } from "@/types/trpc/routers/contentstack/blocks"
+
+export interface UspGridProps extends Pick {}
+export type UspIcon = UspGrid["usp_grid"]["usp_card"][number]["icon"]
diff --git a/types/components/icon.ts b/types/components/icon.ts
index 8096ef0f7..f9f61a525 100644
--- a/types/components/icon.ts
+++ b/types/components/icon.ts
@@ -54,6 +54,7 @@ export enum IconName {
Search = "Search",
Service = "Service",
Shopping = "Shopping",
+ Snowflake = "Snowflake",
StarFilled = "StarFilled",
Train = "Train",
Tripadvisor = "Tripadvisor",
diff --git a/types/requests/utils/embeds.ts b/types/requests/utils/embeds.ts
index 527564882..0fe39ddbd 100644
--- a/types/requests/utils/embeds.ts
+++ b/types/requests/utils/embeds.ts
@@ -5,6 +5,7 @@ export enum EmbedEnum {
LoyaltyPage = "LoyaltyPage",
AccountPage = "AccountPage",
ContentPage = "ContentPage",
+ HotelPage = "HotelPage",
}
export type Embed = keyof typeof EmbedEnum
diff --git a/types/trpc/routers/contentstack/blocks.ts b/types/trpc/routers/contentstack/blocks.ts
index 8d8e449ab..6bffdfc90 100644
--- a/types/trpc/routers/contentstack/blocks.ts
+++ b/types/trpc/routers/contentstack/blocks.ts
@@ -4,13 +4,13 @@ import { cardsGridSchema } from "@/server/routers/contentstack/schemas/blocks/ca
import { contentSchema } from "@/server/routers/contentstack/schemas/blocks/content"
import { dynamicContentSchema } from "@/server/routers/contentstack/schemas/blocks/dynamicContent"
import { shortcutsSchema } from "@/server/routers/contentstack/schemas/blocks/shortcuts"
-
import { textColsSchema } from "@/server/routers/contentstack/schemas/blocks/textCols"
+import { uspGridSchema } from "@/server/routers/contentstack/schemas/blocks/uspGrid"
-export interface CardsGrid extends z.output { }
-export interface Content extends z.output { }
-export interface DynamicContent extends z.output { }
-export interface Shortcuts extends z.output { }
+export interface CardsGrid extends z.output {}
+export interface Content extends z.output {}
+export interface DynamicContent extends z.output {}
+export interface Shortcuts extends z.output {}
export type Shortcut = Shortcuts["shortcuts"]
-export interface TextCols extends z.output { }
-
+export interface TextCols extends z.output {}
+export interface UspGrid extends z.output {}
diff --git a/types/trpc/routers/contentstack/contentPage.ts b/types/trpc/routers/contentstack/contentPage.ts
index d95521319..6bc343278 100644
--- a/types/trpc/routers/contentstack/contentPage.ts
+++ b/types/trpc/routers/contentstack/contentPage.ts
@@ -8,15 +8,15 @@ import {
} from "@/server/routers/contentstack/contentPage/output"
export interface GetContentPageRefsSchema
- extends z.input { }
+ extends z.input {}
export interface ContentPageRefs
- extends z.output { }
+ extends z.output {}
export interface GetContentPageSchema
- extends z.input { }
+ extends z.input {}
-export interface ContentPage extends z.output { }
+export interface ContentPage extends z.output {}
export type Block = z.output