diff --git a/packages/booking-flow/lib/components/SidePeekAccordions/BreakfastAccordionItem.tsx b/packages/booking-flow/lib/components/SidePeekAccordions/BreakfastAccordionItem.tsx
index fb9dd5d3a..935f34614 100644
--- a/packages/booking-flow/lib/components/SidePeekAccordions/BreakfastAccordionItem.tsx
+++ b/packages/booking-flow/lib/components/SidePeekAccordions/BreakfastAccordionItem.tsx
@@ -44,7 +44,7 @@ export default function BreakfastAccordionItem({
tracking.trackAccordionItemOpen("amenities:breakfast")}
>
diff --git a/packages/booking-flow/lib/components/SidePeekAccordions/CheckInCheckOutAccordionItem.tsx b/packages/booking-flow/lib/components/SidePeekAccordions/CheckInCheckOutAccordionItem.tsx
index c8631e235..31e03e5f3 100644
--- a/packages/booking-flow/lib/components/SidePeekAccordions/CheckInCheckOutAccordionItem.tsx
+++ b/packages/booking-flow/lib/components/SidePeekAccordions/CheckInCheckOutAccordionItem.tsx
@@ -29,7 +29,7 @@ export default function CheckInCheckOutAccordionItem({
tracking.trackAccordionItemOpen("amenities:check-in")}
>
diff --git a/packages/booking-flow/lib/components/SidePeekAccordions/ParkingAccordionItem.tsx b/packages/booking-flow/lib/components/SidePeekAccordions/ParkingAccordionItem.tsx
index f7b0e58a5..ae5a7229a 100644
--- a/packages/booking-flow/lib/components/SidePeekAccordions/ParkingAccordionItem.tsx
+++ b/packages/booking-flow/lib/components/SidePeekAccordions/ParkingAccordionItem.tsx
@@ -38,7 +38,7 @@ export default function ParkingAccordionItem({
defaultMessage: "Parking",
})}
iconName={IconName.Parking}
- variant="sidepeek"
+ type="sidepeek"
className={styles.accordionItem}
onOpen={() => tracking.trackAccordionItemOpen("amenities:parking")}
>
diff --git a/packages/common/constants/facilities.ts b/packages/common/constants/facilities.ts
index 4ac23647d..c1a4b9057 100644
--- a/packages/common/constants/facilities.ts
+++ b/packages/common/constants/facilities.ts
@@ -263,4 +263,6 @@ export enum FacilityEnum {
WideEntrance = 2085,
WideRestaurantEntrance = 2087,
WiFiWirelessInternetAccessAllScandic = 5774,
+
+ UNKNOWN = -1,
}
diff --git a/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css b/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css
index 88687da1e..fa52eb9bd 100644
--- a/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css
+++ b/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css
@@ -1,45 +1,42 @@
.accordionItem {
- border-bottom: 1px solid var(--Base-Border-Subtle);
-}
+ border-bottom: 1px solid var(--Border-Default);
-.accordionItem.card {
- padding: var(--Spacing-x1);
-}
+ &.card {
+ padding: var(--Space-x1);
-.accordionItem.sidepeek {
- padding: var(--Spacing-x1) 0;
+ .summary {
+ padding: var(--Space-x15) var(--Space-x2);
+ }
+ }
+
+ &.sidepeek {
+ padding: var(--Space-x1) 0;
+
+ .summary {
+ padding: var(--Space-x15) var(--Space-x1);
+ align-items: center;
+ }
+ }
+
+ .summary:hover {
+ background-color: var(--Surface-Primary-Hover);
+ }
}
.summary {
position: relative;
display: flex;
align-items: center;
- gap: var(--Spacing-x-one-and-half) var(--Spacing-x1);
+ gap: var(--Space-x15) var(--Space-x1);
cursor: pointer;
- color: var(--Base-Text-High-contrast);
- font-family: var(--typography-Body-Bold-fontFamily);
- font-size: var(--typography-Body-Bold-fontSize);
- font-weight: var(--typography-Body-Bold-fontWeight);
+ color: var(--Text-Interactive-Default);
transition: background-color 0.3s;
-}
-.summary.card:hover {
- background-color: var(--Base-Surface-Primary-light-Hover-alt);
-}
-.accordionItem.light .summary:hover {
- background-color: var(--Base-Surface-Primary-light-Hover);
-}
-.accordionItem.subtle .summary:hover {
- background-color: var(--Base-Surface-Primary-light-Normal);
-}
-
-.accordionItem.card .summary {
- padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
border-radius: var(--Corner-radius-md);
-}
+ list-style: none;
-.accordionItem.sidepeek .summary {
- padding: var(--Spacing-x-one-and-half) var(--Spacing-x1);
- align-items: center;
+ &::-webkit-details-marker {
+ display: none;
+ }
}
.title {
@@ -47,7 +44,7 @@
}
.content {
- padding: var(--Spacing-x-one-and-half) var(--Spacing-x2) var(--Spacing-x1);
+ padding: var(--Space-x15) var(--Space-x2) var(--Space-x1);
overflow: hidden;
max-height: 0;
transition: max-height 0.3s;
@@ -57,6 +54,7 @@
transition: transform 0.3s;
flex-shrink: 0;
}
+
details[open] .chevron {
transform: rotate(180deg);
}
diff --git a/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx b/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx
index ddb1f4385..2d691eaef 100644
--- a/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx
+++ b/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx
@@ -2,17 +2,16 @@
import { type ReactNode, useRef } from 'react'
-import Body from '../../Body'
import { IconByIconName } from '../../Icons/IconByIconName'
import { MaterialIcon } from '../../Icons/MaterialIcon'
-import Subtitle from '../../Subtitle'
import { accordionItemVariants } from './variants'
import styles from './accordionItem.module.css'
-import type { IconName } from '../../Icons/iconName'
import type { VariantProps } from 'class-variance-authority'
+import type { IconName } from '../../Icons/iconName'
+import { Typography } from '../../Typography'
export interface AccordionItemProps
extends React.HtmlHTMLAttributes,
@@ -21,6 +20,7 @@ export interface AccordionItemProps
iconName?: IconName
icon?: ReactNode
subtitle?: string
+ showAsSubtitle?: boolean
onOpen?: () => void
}
@@ -29,10 +29,10 @@ export default function AccordionItem({
icon,
iconName,
title,
- theme,
- variant,
+ type,
className,
subtitle,
+ showAsSubtitle = false,
onOpen,
}: AccordionItemProps) {
const contentRef = useRef(null)
@@ -71,36 +71,36 @@ export default function AccordionItem({
}
return (
-
+
{IconComp}
- {variant === 'sidepeek' ? (
-
- {title}
-
+ {type === 'sidepeek' ? (
+
+ {title}
+
) : (
- {subtitle ? (
-
- {title}
-
+ {subtitle || showAsSubtitle ? (
+
+ {title}
+
) : (
-
- {title}
-
+
+ {title}
+
+ )}
+ {subtitle && (
+
+ {subtitle}
+
)}
- {subtitle && {subtitle}}
)}
diff --git a/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts b/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts
index 1ff886766..3bb4f384f 100644
--- a/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts
+++ b/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts
@@ -4,18 +4,12 @@ import styles from './accordionItem.module.css'
export const accordionItemVariants = cva(styles.accordionItem, {
variants: {
- variant: {
+ type: {
card: styles.card,
sidepeek: styles.sidepeek,
},
- theme: {
- default: styles.default,
- light: styles.light,
- subtle: styles.subtle,
- },
},
defaultVariants: {
- variant: 'card',
- theme: 'default',
+ type: 'card',
},
})
diff --git a/packages/design-system/lib/components/Accordion/accordion.module.css b/packages/design-system/lib/components/Accordion/accordion.module.css
index 203e7cb7f..ce138fa5a 100644
--- a/packages/design-system/lib/components/Accordion/accordion.module.css
+++ b/packages/design-system/lib/components/Accordion/accordion.module.css
@@ -1,25 +1,11 @@
.accordion {
list-style: none;
-}
-.accordion.card {
- border-radius: var(--Corner-radius-md);
-}
+ &.card {
+ border-radius: var(--Corner-radius-md);
-.accordion.light {
- background-color: var(--Base-Surface-Primary-light-Normal);
-}
-.accordion.subtle {
- background-color: var(--Background-Primary);
-}
-
-.accordion li:last-child {
- border: none;
-}
-
-.accordion details > summary {
- list-style: none;
-}
-.accordion details > summary::-webkit-details-marker {
- display: none;
+ li:last-child {
+ border-width: 0;
+ }
+ }
}
diff --git a/packages/design-system/lib/components/Accordion/index.tsx b/packages/design-system/lib/components/Accordion/index.tsx
index 7c2bc441f..c8c63b4c3 100644
--- a/packages/design-system/lib/components/Accordion/index.tsx
+++ b/packages/design-system/lib/components/Accordion/index.tsx
@@ -1,10 +1,9 @@
import { Children, cloneElement, isValidElement } from 'react'
-import { accordionVariants } from './variants'
-
import type { VariantProps } from 'class-variance-authority'
import type { AccordionItemProps } from './AccordionItem'
+import { accordionVariants } from './variants'
interface AccordionProps
extends React.HtmlHTMLAttributes,
@@ -13,14 +12,13 @@ interface AccordionProps
export default function Accordion({
children,
className,
- theme,
- variant,
+ type,
}: AccordionProps) {
return (
-
+
{Children.map(children, (child) => {
if (isValidElement(child)) {
- return cloneElement(child, { variant, theme })
+ return cloneElement(child, { type })
} else {
return child
}
diff --git a/packages/design-system/lib/components/Accordion/variants.ts b/packages/design-system/lib/components/Accordion/variants.ts
index 3a1035a56..129e2a61b 100644
--- a/packages/design-system/lib/components/Accordion/variants.ts
+++ b/packages/design-system/lib/components/Accordion/variants.ts
@@ -4,18 +4,12 @@ import styles from './accordion.module.css'
export const accordionVariants = cva(styles.accordion, {
variants: {
- variant: {
+ type: {
card: styles.card,
sidepeek: styles.sidepeek,
},
- theme: {
- default: styles.default,
- light: styles.light,
- subtle: styles.subtle,
- },
},
defaultVariants: {
- variant: 'card',
- theme: 'default',
+ type: 'card',
},
})
diff --git a/packages/design-system/lib/components/FacilityToIcon/index.tsx b/packages/design-system/lib/components/FacilityToIcon/index.tsx
index 2bc9dde3e..f50b1df71 100644
--- a/packages/design-system/lib/components/FacilityToIcon/index.tsx
+++ b/packages/design-system/lib/components/FacilityToIcon/index.tsx
@@ -1,10 +1,10 @@
import { FacilityEnum } from '@scandic-hotels/common/constants/facilities'
import type { JSX } from 'react'
-import { IconName } from '../Icons/iconName'
-import { MaterialIconSetIconProps } from '../Icons/MaterialIcon'
import { IconProps, NucleoIconProps } from '../Icons'
import { IconByIconName } from '../Icons/IconByIconName'
+import { IconName } from '../Icons/iconName'
+import { MaterialIconSetIconProps } from '../Icons/MaterialIcon'
interface mapFacilityToIconProps {
id: FacilityEnum
@@ -299,4 +299,6 @@ const facilityToIconMap: Record = {
[FacilityEnum.WideEntrance]: IconName.StarFilled,
[FacilityEnum.WideRestaurantEntrance]: IconName.StarFilled,
[FacilityEnum.WiFiWirelessInternetAccessAllScandic]: IconName.StarFilled,
+
+ [FacilityEnum.UNKNOWN]: IconName.StarFilled,
}
diff --git a/packages/trpc/lib/graphql/Fragments/HotelFilter.graphql b/packages/trpc/lib/graphql/Fragments/HotelFilter.graphql
new file mode 100644
index 000000000..5054159a1
--- /dev/null
+++ b/packages/trpc/lib/graphql/Fragments/HotelFilter.graphql
@@ -0,0 +1,14 @@
+#import "./System.graphql"
+
+fragment HotelFilter on HotelFilter {
+ title
+ facility_id
+ category
+ slug
+}
+
+fragment HotelFilterRef on HotelFilter {
+ system {
+ ...System
+ }
+}
diff --git a/packages/trpc/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql b/packages/trpc/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql
index ec3e5e115..a2211d530 100644
--- a/packages/trpc/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql
+++ b/packages/trpc/lib/graphql/Query/DestinationCityPage/DestinationCityPage.graphql
@@ -1,5 +1,7 @@
#import "../../Fragments/System.graphql"
+#import "../../Fragments/HotelFilter.graphql"
+
#import "../../Fragments/Blocks/Accordion.graphql"
#import "../../Fragments/Blocks/Content.graphql"
@@ -82,6 +84,15 @@ query GetDestinationCityPage($locale: String!, $uid: String!) {
...Accordion_DestinationCityPage
...Content_DestinationCityPage
}
+ seo_filters {
+ filterConnection {
+ edges {
+ node {
+ ...HotelFilter
+ }
+ }
+ }
+ }
system {
...System
created_at
@@ -135,6 +146,15 @@ query GetDestinationCityPageRefs($locale: String!, $uid: String!) {
...Accordion_DestinationCityPageRefs
...Content_DestinationCityPageRefs
}
+ seo_filters {
+ filterConnection {
+ edges {
+ node {
+ ...HotelFilterRef
+ }
+ }
+ }
+ }
system {
...System
}
diff --git a/packages/trpc/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql b/packages/trpc/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql
index 1194958c7..97aa6ad1d 100644
--- a/packages/trpc/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql
+++ b/packages/trpc/lib/graphql/Query/DestinationCountryPage/DestinationCountryPage.graphql
@@ -1,5 +1,7 @@
#import "../../Fragments/System.graphql"
+#import "../../Fragments/HotelFilter.graphql"
+
#import "../../Fragments/Blocks/Accordion.graphql"
#import "../../Fragments/Blocks/Content.graphql"
@@ -77,6 +79,15 @@ query GetDestinationCountryPage($locale: String!, $uid: String!) {
...Accordion_DestinationCountryPage
...Content_DestinationCountryPage
}
+ seo_filters {
+ filterConnection {
+ edges {
+ node {
+ ...HotelFilter
+ }
+ }
+ }
+ }
system {
...System
created_at
@@ -117,6 +128,15 @@ query GetDestinationCountryPageRefs($locale: String!, $uid: String!) {
...Accordion_DestinationCountryPageRefs
...Content_DestinationCountryPageRefs
}
+ seo_filters {
+ filterConnection {
+ edges {
+ node {
+ ...HotelFilterRef
+ }
+ }
+ }
+ }
system {
...System
}
diff --git a/packages/trpc/lib/routers/contentstack/destinationCityPage/output.ts b/packages/trpc/lib/routers/contentstack/destinationCityPage/output.ts
index 2945f047a..225e9974a 100644
--- a/packages/trpc/lib/routers/contentstack/destinationCityPage/output.ts
+++ b/packages/trpc/lib/routers/contentstack/destinationCityPage/output.ts
@@ -11,6 +11,10 @@ import {
accordionSchema,
} from "../schemas/blocks/accordion"
import { contentRefsSchema, contentSchema } from "../schemas/blocks/content"
+import {
+ destinationFiltersRefsSchema,
+ destinationFiltersSchema,
+} from "../schemas/destinationFilters"
import { mapLocationSchema } from "../schemas/mapLocation"
import {
linkRefsUnionSchema,
@@ -159,6 +163,7 @@ export const destinationCityPageSchema = z.object({
})
.nullish(),
blocks: discriminatedUnionArray(blocksSchema.options).nullable(),
+ seo_filters: destinationFiltersSchema,
system: systemSchema.merge(
z.object({
created_at: z.string(),
@@ -258,6 +263,7 @@ export const destinationCityPageRefsSchema = z.object({
})
.nullish(),
blocks: discriminatedUnionArray(blocksRefsSchema.options).nullable(),
+ seo_filters: destinationFiltersRefsSchema,
system: systemSchema,
}),
})
diff --git a/packages/trpc/lib/routers/contentstack/destinationCountryPage/output.ts b/packages/trpc/lib/routers/contentstack/destinationCountryPage/output.ts
index 80cd79981..2d349c18d 100644
--- a/packages/trpc/lib/routers/contentstack/destinationCountryPage/output.ts
+++ b/packages/trpc/lib/routers/contentstack/destinationCountryPage/output.ts
@@ -11,6 +11,10 @@ import {
accordionSchema,
} from "../schemas/blocks/accordion"
import { contentRefsSchema, contentSchema } from "../schemas/blocks/content"
+import {
+ destinationFiltersRefsSchema,
+ destinationFiltersSchema,
+} from "../schemas/destinationFilters"
import { mapLocationSchema } from "../schemas/mapLocation"
import {
linkRefsUnionSchema,
@@ -88,6 +92,7 @@ export const destinationCountryPageSchema = z.object({
})
.nullish(),
blocks: discriminatedUnionArray(blocksSchema.options).nullable(),
+ seo_filters: destinationFiltersSchema,
system: systemSchema.merge(
z.object({
created_at: z.string(),
@@ -160,6 +165,7 @@ export const destinationCountryPageRefsSchema = z.object({
}),
}),
blocks: discriminatedUnionArray(blocksRefsSchema.options).nullable(),
+ seo_filters: destinationFiltersRefsSchema,
system: systemSchema,
}),
})
diff --git a/packages/trpc/lib/routers/contentstack/schemas/destinationFilters.ts b/packages/trpc/lib/routers/contentstack/schemas/destinationFilters.ts
new file mode 100644
index 000000000..b99e4c9f7
--- /dev/null
+++ b/packages/trpc/lib/routers/contentstack/schemas/destinationFilters.ts
@@ -0,0 +1,55 @@
+import { z } from "zod"
+
+import { isDefined } from "@scandic-hotels/common/utils/isDefined"
+
+import { hotelFilterSchema } from "./hotelFilter"
+import { systemSchema } from "./system"
+
+export const destinationFiltersSchema = z
+ .array(
+ z.object({
+ filterConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: hotelFilterSchema,
+ })
+ ),
+ }),
+ })
+ )
+ .nullish()
+ .transform((data) => {
+ const filters = data
+ ?.map(({ filterConnection }) => filterConnection.edges[0]?.node)
+ .filter(isDefined)
+
+ if (!data || !filters?.length) {
+ return null
+ }
+
+ const facilityFilters = filters.filter((f) => f.filterType === "facility")
+ const surroundingsFilters = filters.filter(
+ (f) => f.filterType === "surroundings"
+ )
+
+ return {
+ facilityFilters,
+ surroundingsFilters,
+ }
+ })
+
+export const destinationFiltersRefsSchema = z
+ .array(
+ z.object({
+ filterConnection: z.object({
+ edges: z.array(
+ z.object({
+ node: z.object({
+ system: systemSchema,
+ }),
+ })
+ ),
+ }),
+ })
+ )
+ .nullish()
diff --git a/packages/trpc/lib/routers/contentstack/schemas/hotelFilter.ts b/packages/trpc/lib/routers/contentstack/schemas/hotelFilter.ts
new file mode 100644
index 000000000..b2ddc5f36
--- /dev/null
+++ b/packages/trpc/lib/routers/contentstack/schemas/hotelFilter.ts
@@ -0,0 +1,18 @@
+import { z } from "zod"
+
+import { FacilityEnum } from "@scandic-hotels/common/constants/facilities"
+
+export const hotelFilterSchema = z
+ .object({
+ title: z.string(),
+ facility_id: z.nativeEnum(FacilityEnum).catch(FacilityEnum.UNKNOWN),
+ category: z.string(),
+ slug: z.string(),
+ })
+ .transform((data) => ({
+ id: data.facility_id,
+ name: data.title,
+ filterType: data.category,
+ slug: data.slug,
+ sortOrder: 0,
+ }))