+ selectedFilter: Filter["identifier"]
+ onFilterSelect: (filter: Filter["identifier"]) => void
+}
+
+export default function TabFilters({
categories,
selectedFilter,
onFilterSelect,
-}: FiltersProps) {
+}: TabFiltersProps) {
return (
{categories.map((category) => (
diff --git a/components/Blocks/CarouselCards/Filters/filters.module.css b/components/TabFilters/tabFilters.module.css
similarity index 100%
rename from components/Blocks/CarouselCards/Filters/filters.module.css
rename to components/TabFilters/tabFilters.module.css
diff --git a/lib/graphql/Fragments/Blocks/CardGallery.graphql b/lib/graphql/Fragments/Blocks/CardGallery.graphql
new file mode 100644
index 000000000..6540695c5
--- /dev/null
+++ b/lib/graphql/Fragments/Blocks/CardGallery.graphql
@@ -0,0 +1,92 @@
+#import "../System.graphql"
+#import "./ContentCard.graphql"
+#import "../PageLink/AccountPageLink.graphql"
+#import "../PageLink/CollectionPageLink.graphql"
+#import "../PageLink/ContentPageLink.graphql"
+#import "../PageLink/DestinationCityPageLink.graphql"
+#import "../PageLink/DestinationCountryPageLink.graphql"
+#import "../PageLink/DestinationOverviewPageLink.graphql"
+#import "../PageLink/HotelPageLink.graphql"
+#import "../PageLink/LoyaltyPageLink.graphql"
+#import "../PageLink/StartPageLink.graphql"
+
+#import "../AccountPage/Ref.graphql"
+#import "../ContentPage/Ref.graphql"
+#import "../HotelPage/Ref.graphql"
+#import "../LoyaltyPage/Ref.graphql"
+#import "../CollectionPage/Ref.graphql"
+#import "../DestinationCityPage/Ref.graphql"
+#import "../DestinationCountryPage/Ref.graphql"
+#import "../DestinationOverviewPage/Ref.graphql"
+
+fragment CardGallery_DestinationOverviewPage on DestinationOverviewPageBlocksCardGallery {
+ card_gallery {
+ heading
+ card_groups {
+ filter_identifier
+ filter_label
+ cardConnection {
+ edges {
+ node {
+ ...ContentCardBlock
+ }
+ }
+ }
+ }
+ link {
+ cta_text
+ is_contentstack_link
+ open_in_new_tab
+ external_link {
+ href
+ title
+ }
+ linkConnection {
+ edges {
+ node {
+ __typename
+ ...AccountPageLink
+ ...CollectionPageLink
+ ...ContentPageLink
+ ...DestinationCityPageLink
+ ...DestinationCountryPageLink
+ ...DestinationOverviewPageLink
+ ...HotelPageLink
+ ...LoyaltyPageLink
+ }
+ }
+ }
+ }
+ }
+}
+
+fragment CardGallery_DestinationOverviewPageRefs on DestinationOverviewPageBlocksCardGallery {
+ card_gallery {
+ card_groups {
+ cardConnection {
+ edges {
+ node {
+ ...ContentCardBlockRef
+ }
+ }
+ }
+ }
+ link {
+ linkConnection {
+ edges {
+ node {
+ __typename
+ ...AccountPageRef
+ ...CollectionPageRef
+ ...ContentPageRef
+ ...DestinationCityPageRef
+ ...DestinationCountryPageRef
+ ...DestinationOverviewPageRef
+ ...HotelPageRef
+ ...LoyaltyPageRef
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/graphql/Fragments/Blocks/CarouselCards.graphql b/lib/graphql/Fragments/Blocks/CarouselCards.graphql
index f2ee33806..0030653bd 100644
--- a/lib/graphql/Fragments/Blocks/CarouselCards.graphql
+++ b/lib/graphql/Fragments/Blocks/CarouselCards.graphql
@@ -91,76 +91,3 @@ fragment CarouselCards_StartPageRefs on StartPageBlocksCarouselCards {
}
}
}
-
-fragment CarouselCards_DestinationOverviewPage on DestinationOverviewPageBlocksCarouselCards {
- carousel_cards {
- heading
- enable_filters
- card_groups {
- filter_identifier
- filter_label
- cardConnection {
- edges {
- node {
- ...ContentCardBlock
- }
- }
- }
- }
- link {
- cta_text
- is_contentstack_link
- open_in_new_tab
- external_link {
- href
- title
- }
- linkConnection {
- edges {
- node {
- __typename
- ...AccountPageLink
- ...CollectionPageLink
- ...ContentPageLink
- ...DestinationCityPageLink
- ...DestinationCountryPageLink
- ...DestinationOverviewPageLink
- ...HotelPageLink
- ...LoyaltyPageLink
- }
- }
- }
- }
- }
-}
-
-fragment CarouselCards_DestinationOverviewPageRefs on DestinationOverviewPageBlocksCarouselCards {
- carousel_cards {
- card_groups {
- cardConnection {
- edges {
- node {
- ...ContentCardBlockRef
- }
- }
- }
- }
- link {
- linkConnection {
- edges {
- node {
- __typename
- ...AccountPageRef
- ...CollectionPageRef
- ...ContentPageRef
- ...DestinationCityPageRef
- ...DestinationCountryPageRef
- ...DestinationOverviewPageRef
- ...HotelPageRef
- ...LoyaltyPageRef
- }
- }
- }
- }
- }
-}
diff --git a/lib/graphql/Query/DestinationOverviewPage/DestinationOverviewPage.graphql b/lib/graphql/Query/DestinationOverviewPage/DestinationOverviewPage.graphql
index f81b58f1d..8d55e2ebb 100644
--- a/lib/graphql/Query/DestinationOverviewPage/DestinationOverviewPage.graphql
+++ b/lib/graphql/Query/DestinationOverviewPage/DestinationOverviewPage.graphql
@@ -1,6 +1,6 @@
#import "../../Fragments/System.graphql"
-#import "../../Fragments/Blocks/CarouselCards.graphql"
+#import "../../Fragments/Blocks/CardGallery.graphql"
query GetDestinationOverviewPage($locale: String!, $uid: String!) {
destination_overview_page(uid: $uid, locale: $locale) {
@@ -8,7 +8,7 @@ query GetDestinationOverviewPage($locale: String!, $uid: String!) {
url
blocks {
__typename
- ...CarouselCards_DestinationOverviewPage
+ ...CardGallery_DestinationOverviewPage
}
system {
...System
@@ -25,7 +25,7 @@ query GetDestinationOverviewPageRefs($locale: String!, $uid: String!) {
destination_overview_page(locale: $locale, uid: $uid) {
blocks {
__typename
- ...CarouselCards_DestinationOverviewPageRefs
+ ...CardGallery_DestinationOverviewPageRefs
}
system {
...System
diff --git a/server/routers/contentstack/destinationOverviewPage/output.ts b/server/routers/contentstack/destinationOverviewPage/output.ts
index 8d4c6e9a4..7defa4017 100644
--- a/server/routers/contentstack/destinationOverviewPage/output.ts
+++ b/server/routers/contentstack/destinationOverviewPage/output.ts
@@ -5,23 +5,23 @@ import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
import { removeMultipleSlashes } from "@/utils/url"
import {
- carouselCardsRefsSchema,
- carouselCardsSchema,
-} from "../schemas/blocks/carouselCards"
+ cardGalleryRefsSchema,
+ cardGallerySchema,
+} from "../schemas/blocks/cardGallery"
import { systemSchema } from "../schemas/system"
import { DestinationOverviewPageEnum } from "@/types/enums/destinationOverviewPage"
-const destinationOverviewPageCarouselCards = z
+const destinationOverviewPageCardGallery = z
.object({
__typename: z.literal(
- DestinationOverviewPageEnum.ContentStack.blocks.CarouselCards
+ DestinationOverviewPageEnum.ContentStack.blocks.CardGallery
),
})
- .merge(carouselCardsSchema)
+ .merge(cardGallerySchema)
export const blocksSchema = z.discriminatedUnion("__typename", [
- destinationOverviewPageCarouselCards,
+ destinationOverviewPageCardGallery,
])
export const destinationOverviewPageSchema = z.object({
@@ -62,16 +62,16 @@ export const countryPageUrlSchema = z
)
/** REFS */
-const destinationOverviewPageCarouselCardsRef = z
+const destinationOverviewPageCardGalleryRef = z
.object({
__typename: z.literal(
- DestinationOverviewPageEnum.ContentStack.blocks.CarouselCards
+ DestinationOverviewPageEnum.ContentStack.blocks.CardGallery
),
})
- .merge(carouselCardsRefsSchema)
+ .merge(cardGalleryRefsSchema)
const blocksRefsSchema = z.discriminatedUnion("__typename", [
- destinationOverviewPageCarouselCardsRef,
+ destinationOverviewPageCardGalleryRef,
])
export const destinationOverviewPageRefsSchema = z.object({
diff --git a/server/routers/contentstack/schemas/blocks/cardGallery.ts b/server/routers/contentstack/schemas/blocks/cardGallery.ts
new file mode 100644
index 000000000..469c7b47b
--- /dev/null
+++ b/server/routers/contentstack/schemas/blocks/cardGallery.ts
@@ -0,0 +1,95 @@
+import { z } from "zod"
+
+import {
+ contentCardRefSchema,
+ contentCardSchema,
+ transformContentCard,
+} from "./cards/contentCard"
+import { buttonSchema } from "./utils/buttonLinkSchema"
+import { linkConnectionRefsSchema } from "./utils/linkConnection"
+
+import { BlocksEnums } from "@/types/enums/blocks"
+import {
+ type CardGalleryFilter,
+ CardGalleryFilterEnum,
+} from "@/types/enums/cardGallery"
+
+export const cardGallerySchema = z.object({
+ typename: z
+ .literal(BlocksEnums.block.CardGallery)
+ .optional()
+ .default(BlocksEnums.block.CardGallery),
+ card_gallery: z
+ .object({
+ heading: z.string().optional(),
+ link: buttonSchema.optional(),
+ card_groups: z.array(
+ z.object({
+ filter_identifier: z.nativeEnum(CardGalleryFilterEnum),
+ filter_label: z.string(),
+ cardConnection: z.object({
+ edges: z.array(z.object({ node: contentCardSchema })),
+ }),
+ })
+ ),
+ })
+ .transform((data) => {
+ const filterCategories = data.card_groups.reduce<
+ Array<{
+ identifier: CardGalleryFilter
+ label: string
+ }>
+ >((acc, group) => {
+ const identifier = group.filter_identifier
+ if (!acc.some((category) => category.identifier === identifier)) {
+ acc.push({
+ identifier,
+ label: group.filter_label,
+ })
+ }
+ return acc
+ }, [])
+
+ return {
+ heading: data.heading,
+ filterCategories,
+ cards: data.card_groups.flatMap((group) =>
+ group.cardConnection.edges
+ .map((edge) => transformContentCard(edge.node))
+ .filter((card): card is NonNullable => card !== null)
+ .map((card) => ({
+ ...card,
+ filterId: group.filter_identifier,
+ }))
+ ),
+ defaultFilter:
+ data.card_groups[0]?.filter_identifier ??
+ filterCategories[0]?.identifier,
+ link:
+ data.link?.href && data.link.title
+ ? { href: data.link.href, text: data.link.title }
+ : undefined,
+ }
+ }),
+})
+
+export const cardGalleryRefsSchema = z.object({
+ typename: z
+ .literal(BlocksEnums.block.CardGallery)
+ .optional()
+ .default(BlocksEnums.block.CardGallery),
+ card_gallery: z.object({
+ card_groups: z.array(
+ z.object({
+ cardConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: contentCardRefSchema,
+ })
+ ),
+ }),
+ })
+ ),
+ link: linkConnectionRefsSchema.optional(),
+ }),
+})
diff --git a/types/components/blocks/cardGallery.ts b/types/components/blocks/cardGallery.ts
new file mode 100644
index 000000000..9733c443d
--- /dev/null
+++ b/types/components/blocks/cardGallery.ts
@@ -0,0 +1,3 @@
+import type { CardGallery } from "@/types/trpc/routers/contentstack/blocks"
+
+export interface CardGalleryProps extends Pick {}
diff --git a/types/enums/blocks.ts b/types/enums/blocks.ts
index 4bb7559fd..05f25d680 100644
--- a/types/enums/blocks.ts
+++ b/types/enums/blocks.ts
@@ -1,17 +1,18 @@
export namespace BlocksEnums {
export const enum block {
Accordion = "Accordion",
+ CardGallery = "CardGallery",
CardsGrid = "CardsGrid",
+ CarouselCards = "CarouselCards",
Content = "Content",
DynamicContent = "DynamicContent",
+ FullWidthCampaign = "FullWidthCampaign",
+ HotelListing = "HotelListing",
+ JoinScandicFriends = "JoinScandicFriends",
Shortcuts = "Shortcuts",
Table = "Table",
TextCols = "TextCols",
TextContent = "TextContent",
UspGrid = "UspGrid",
- HotelListing = "HotelListing",
- FullWidthCampaign = "FullWidthCampaign",
- CarouselCards = "CarouselCards",
- JoinScandicFriends = "JoinScandicFriends",
}
}
diff --git a/types/enums/cardGallery.ts b/types/enums/cardGallery.ts
new file mode 100644
index 000000000..6b7767004
--- /dev/null
+++ b/types/enums/cardGallery.ts
@@ -0,0 +1,10 @@
+export const CardGalleryFilterEnum = {
+ offers: "offers",
+ popular_destinations: "popular_destinations",
+ popular_hotels: "popular_hotels",
+ popular_cities: "popular_cities",
+ spa_wellness: "spa_wellness",
+} as const
+
+export type CardGalleryFilter =
+ (typeof CardGalleryFilterEnum)[keyof typeof CardGalleryFilterEnum]
diff --git a/types/enums/destinationOverviewPage.ts b/types/enums/destinationOverviewPage.ts
index 304028a88..274f7a606 100644
--- a/types/enums/destinationOverviewPage.ts
+++ b/types/enums/destinationOverviewPage.ts
@@ -1,7 +1,7 @@
export namespace DestinationOverviewPageEnum {
export namespace ContentStack {
export const enum blocks {
- CarouselCards = "DestinationOverviewPageBlocksCarouselCards",
+ CardGallery = "DestinationOverviewPageBlocksCardGallery",
}
}
}
diff --git a/types/trpc/routers/contentstack/blocks.ts b/types/trpc/routers/contentstack/blocks.ts
index b22595325..22a88e1d9 100644
--- a/types/trpc/routers/contentstack/blocks.ts
+++ b/types/trpc/routers/contentstack/blocks.ts
@@ -1,5 +1,6 @@
import type { z } from "zod"
+import type { cardGallerySchema } from "@/server/routers/contentstack/schemas/blocks/cardGallery"
import type { teaserCardBlockSchema } from "@/server/routers/contentstack/schemas/blocks/cards/teaserCard"
import type { cardsGridSchema } from "@/server/routers/contentstack/schemas/blocks/cardsGrid"
import type { carouselCardsSchema } from "@/server/routers/contentstack/schemas/blocks/carouselCards"
@@ -24,3 +25,4 @@ export interface UspGrid extends z.output {}
interface GetHotelListing extends z.output {}
export type HotelListing = GetHotelListing["hotel_listing"]
export interface CarouselCards extends z.output {}
+export interface CardGallery extends z.output {}