diff --git a/apps/scandic-web/components/Blocks/ShortcutsList/ShortcutsListItems/index.tsx b/apps/scandic-web/components/Blocks/ShortcutsList/ShortcutsListItems/index.tsx
index b75effd20..b97c99fb1 100644
--- a/apps/scandic-web/components/Blocks/ShortcutsList/ShortcutsListItems/index.tsx
+++ b/apps/scandic-web/components/Blocks/ShortcutsList/ShortcutsListItems/index.tsx
@@ -24,7 +24,7 @@ export default function ShortcutsListItems({
className={styles.link}
>
- {shortcut.text || shortcut.title}
+ {shortcut.text}
diff --git a/apps/scandic-web/components/Header/MainMenu/NavigationMenu/MegaMenu/index.tsx b/apps/scandic-web/components/Header/MainMenu/NavigationMenu/MegaMenu/index.tsx
index b9df8d7fa..fabcb3671 100644
--- a/apps/scandic-web/components/Header/MainMenu/NavigationMenu/MegaMenu/index.tsx
+++ b/apps/scandic-web/components/Header/MainMenu/NavigationMenu/MegaMenu/index.tsx
@@ -56,9 +56,9 @@ export default function MegaMenu({
) : null}
- {seeAllLink?.link ? (
+ {seeAllLink?.url ? (
{item.title}
- {item.links.map(({ title, link }) =>
- link ? (
+ {item.links.map(({ title, url }) =>
+ url ? (
-
- toggleMegaMenu(megaMenuTitle)}
+ if (submenu.length) {
+ return (
+ <>
+ toggleMegaMenu(megaMenuTitle)}
+ className={`${styles.navigationMenuItem} ${isMobile ? styles.mobile : ""}`}
+ >
+ {title}
+ {isMobile ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ >
+ )
+ } else if (link?.url) {
+ return (
+
{title}
- {isMobile ? (
-
- ) : (
-
- )}
-
-
-
-
- >
- ) : (
-
- {title}
-
- )
+
+ )
+ }
+
+ return null
}
diff --git a/apps/scandic-web/components/Header/TopLink/index.tsx b/apps/scandic-web/components/Header/TopLink/index.tsx
index 5d85fb48d..7013b41bb 100644
--- a/apps/scandic-web/components/Header/TopLink/index.tsx
+++ b/apps/scandic-web/components/Header/TopLink/index.tsx
@@ -11,13 +11,13 @@ export default function TopLink({
}: TopLinkProps) {
const linkData = isLoggedIn ? topLink.logged_in : topLink.logged_out
- if (!linkData?.link?.url || !linkData?.title) {
+ if (!linkData?.url || !linkData?.title) {
return null
}
return (
diff --git a/packages/trpc/lib/graphql/Fragments/Blocks/Shortcuts.graphql b/packages/trpc/lib/graphql/Fragments/Blocks/Shortcuts.graphql
index 8edd5453e..a9610f07d 100644
--- a/packages/trpc/lib/graphql/Fragments/Blocks/Shortcuts.graphql
+++ b/packages/trpc/lib/graphql/Fragments/Blocks/Shortcuts.graphql
@@ -27,6 +27,11 @@ fragment Shortcuts on Shortcuts {
title
two_column_list
shortcuts {
+ is_contentstack_link
+ external_link {
+ href
+ title
+ }
open_in_new_tab
text
linkConnection {
diff --git a/packages/trpc/lib/graphql/Query/Header.graphql b/packages/trpc/lib/graphql/Query/Header.graphql
index 326867002..f7c72c27d 100644
--- a/packages/trpc/lib/graphql/Query/Header.graphql
+++ b/packages/trpc/lib/graphql/Query/Header.graphql
@@ -33,6 +33,7 @@ query GetHeader($locale: String!) {
top_link {
logged_in {
icon
+ is_contentstack_link
title
linkConnection {
edges {
@@ -52,9 +53,14 @@ query GetHeader($locale: String!) {
}
}
}
+ external_link {
+ href
+ title
+ }
}
logged_out {
icon
+ is_contentstack_link
title
linkConnection {
edges {
@@ -74,9 +80,14 @@ query GetHeader($locale: String!) {
}
}
}
+ external_link {
+ href
+ title
+ }
}
}
menu_items {
+ is_contentstack_link
title
linkConnection {
edges {
@@ -96,7 +107,12 @@ query GetHeader($locale: String!) {
}
}
}
+ external_link {
+ href
+ title
+ }
see_all_link {
+ is_contentstack_link
title
linkConnection {
edges {
@@ -116,10 +132,15 @@ query GetHeader($locale: String!) {
}
}
}
+ external_link {
+ href
+ title
+ }
}
submenu {
title
links {
+ is_contentstack_link
title
linkConnection {
edges {
@@ -139,6 +160,10 @@ query GetHeader($locale: String!) {
}
}
}
+ external_link {
+ href
+ title
+ }
}
}
cardConnection {
diff --git a/packages/trpc/lib/routers/contentstack/base/output.ts b/packages/trpc/lib/routers/contentstack/base/output.ts
index 56923da24..03d08db1c 100644
--- a/packages/trpc/lib/routers/contentstack/base/output.ts
+++ b/packages/trpc/lib/routers/contentstack/base/output.ts
@@ -7,6 +7,10 @@ import {
import { Lang } from "@scandic-hotels/common/constants/language"
import { logger } from "@scandic-hotels/common/logger"
import { removeMultipleSlashes } from "@scandic-hotels/common/utils/url"
+import {
+ nullableStringUrlValidator,
+ nullableStringValidator,
+} from "@scandic-hotels/common/utils/zod/stringValidator"
import { discriminatedUnion } from "../../../utils/discriminatedUnion"
import {
@@ -97,7 +101,7 @@ export const validateCurrentHeaderConfigSchema = z
edges: z.array(
z.object({
node: z.object({
- description: z.string().optional().nullable(),
+ description: z.string().nullish(),
dimension: z.object({
height: z.number(),
width: z.number(),
@@ -106,8 +110,8 @@ export const validateCurrentHeaderConfigSchema = z
system: z.object({
uid: z.string(),
}),
- title: z.string().optional().default(""),
- url: z.string().optional().default(""),
+ title: nullableStringValidator,
+ url: nullableStringUrlValidator,
}),
})
),
@@ -178,7 +182,7 @@ const validateAppDownload = z.object({
edges: z.array(
z.object({
node: z.object({
- description: z.string().optional().nullable(),
+ description: z.string().nullish(),
dimension: z.object({
height: z.number(),
width: z.number(),
@@ -220,7 +224,7 @@ export const validateCurrentFooterConfigSchema = z.object({
edges: z.array(
z.object({
node: z.object({
- description: z.string().optional().nullable(),
+ description: z.string().nullish(),
dimension: z.object({
height: z.number(),
width: z.number(),
@@ -248,7 +252,7 @@ export const validateCurrentFooterConfigSchema = z.object({
edges: z.array(
z.object({
node: z.object({
- description: z.string().optional().nullable(),
+ description: z.string().nullish(),
dimension: z.object({
height: z.number(),
width: z.number(),
@@ -561,6 +565,51 @@ export const headerRefsSchema = z
}
})
+const internalOrExternalLinkSchema = z
+ .object({
+ is_contentstack_link: z.boolean().nullish(),
+ external_link: z
+ .object({
+ href: nullableStringUrlValidator,
+ title: z.string().nullish(),
+ })
+ .nullish(),
+ title: nullableStringValidator,
+ linkConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: linkUnionSchema.transform((data) => {
+ const link = transformPageLink(data)
+ if (link) {
+ return link
+ }
+ return data
+ }),
+ })
+ ),
+ }),
+ })
+ .transform(
+ ({ is_contentstack_link, external_link, linkConnection, title }) => {
+ if (is_contentstack_link !== false && linkConnection.edges.length) {
+ const linkRef = linkConnection.edges[0].node
+ return {
+ title: title || linkRef.title,
+ url: linkRef.url,
+ }
+ } else if (is_contentstack_link === false && external_link?.href) {
+ return {
+ title: title || external_link.title || "",
+ url: external_link.href,
+ }
+ } else {
+ return {
+ title,
+ }
+ }
+ }
+ )
+
const linkSchema = z
.object({
linkConnection: z.object({
@@ -590,7 +639,7 @@ const linkSchema = z
})
const titleSchema = z.object({
- title: z.string().optional().default(""),
+ title: nullableStringValidator,
})
/**
@@ -605,7 +654,7 @@ const linkAndTitleSchema = z.intersection(linkSchema, titleSchema)
*/
export const menuItemSchema = z
.intersection(
- linkAndTitleSchema,
+ internalOrExternalLinkSchema,
z
.object({
cardConnection: z.object({
@@ -615,11 +664,11 @@ export const menuItemSchema = z
})
),
}),
- see_all_link: linkAndTitleSchema,
+ see_all_link: internalOrExternalLinkSchema,
submenu: z.array(
z.object({
- links: z.array(linkAndTitleSchema),
- title: z.string().optional().default(""),
+ links: z.array(internalOrExternalLinkSchema),
+ title: nullableStringValidator,
})
),
})
@@ -636,11 +685,13 @@ export const menuItemSchema = z
}
})
)
- .transform((data) => {
+ .transform(({ title, url, card, seeAllLink, submenu }) => {
return {
- ...data,
- link: data.submenu.length ? null : data.link,
- seeAllLink: data.submenu.length ? data.seeAllLink : null,
+ title,
+ link: submenu.length ? null : { url },
+ seeAllLink: submenu.length ? seeAllLink : null,
+ card,
+ submenu,
}
})
@@ -652,7 +703,7 @@ enum IconName {
}
const topLinkItemSchema = z.intersection(
- linkAndTitleSchema,
+ internalOrExternalLinkSchema,
z.object({
icon: z
.enum(["loyalty", "info", "offer"])
diff --git a/packages/trpc/lib/routers/contentstack/schemas/blocks/shortcuts.ts b/packages/trpc/lib/routers/contentstack/schemas/blocks/shortcuts.ts
index db0797688..a9d6c321a 100644
--- a/packages/trpc/lib/routers/contentstack/schemas/blocks/shortcuts.ts
+++ b/packages/trpc/lib/routers/contentstack/schemas/blocks/shortcuts.ts
@@ -15,37 +15,65 @@ export const shortcutsBlockSchema = z.object({
two_column_list: z.boolean().nullable().default(false),
shortcuts: z
.array(
- z.object({
- open_in_new_tab: z.boolean(),
- text: z.string().optional().default(""),
- linkConnection: z.object({
- edges: z.array(
- z.object({
- node: linkUnionSchema.transform((data) => {
- const link = transformPageLink(data)
- if (link) {
- return link
- }
- return data
- }),
+ z
+ .object({
+ is_contentstack_link: z.boolean().nullish(),
+ external_link: z
+ .object({
+ href: z.string().nullish().default(""),
+ title: z.string().nullish(),
})
- ),
- }),
- })
- )
- .transform((data) => {
- return data
- .filter((node) => node.linkConnection.edges.length)
- .map((node) => {
- const link = node.linkConnection.edges[0].node
- return {
- openInNewTab: node.open_in_new_tab,
- text: node.text,
- title: link.title,
- url: link.url,
- }
+ .nullish(),
+ open_in_new_tab: z.boolean(),
+ text: z.string().optional().default(""),
+ linkConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: linkUnionSchema.transform((data) => {
+ const link = transformPageLink(data)
+ if (link) {
+ return link
+ }
+ return data
+ }),
+ })
+ ),
+ }),
})
- }),
+ .transform(
+ ({
+ is_contentstack_link,
+ external_link,
+ linkConnection,
+ open_in_new_tab,
+ text,
+ }) => {
+ if (
+ is_contentstack_link !== false &&
+ linkConnection.edges.length
+ ) {
+ const linkRef = linkConnection.edges[0].node
+ return {
+ openInNewTab: open_in_new_tab,
+ text: text || linkRef.title,
+ url: linkRef.url,
+ }
+ } else if (
+ is_contentstack_link === false &&
+ external_link?.href
+ ) {
+ return {
+ openInNewTab: open_in_new_tab,
+ text: text || external_link.title || "",
+ url: external_link.href,
+ }
+ } else {
+ return null
+ }
+ }
+ )
+ )
+ .transform((data) => data.filter((item) => !!item)),
})
.transform(({ two_column_list, ...rest }) => {
return {