diff --git a/packages/common/hooks/useUrlWithSearchParam.ts b/packages/common/hooks/useUrlWithSearchParam.ts new file mode 100644 index 000000000..c1e82c0a6 --- /dev/null +++ b/packages/common/hooks/useUrlWithSearchParam.ts @@ -0,0 +1,25 @@ +import { usePathname, useSearchParams } from "next/navigation" +import { useMemo } from "react" + +export function useUrlWithSearchParam( + searchParam: { key: string; value: string }, + path?: string | null +) { + const { key, value } = searchParam + const pathname = path ?? usePathname() + const searchParams = useSearchParams() + + return useMemo(() => { + const newUrl = new URL(pathname, window.location.origin) + + // Preserve existing search params + searchParams.forEach((val, key) => { + newUrl.searchParams.set(key, val) + }) + + // Set or override the specific search param + newUrl.searchParams.set(key, value) + + return newUrl + }, [pathname, searchParams, key, value]) +} diff --git a/packages/design-system/lib/components/HotelCard/HotelCardDialogImage/index.tsx b/packages/design-system/lib/components/HotelCard/HotelCardDialogImage/index.tsx index acaee3bb0..0d684c409 100644 --- a/packages/design-system/lib/components/HotelCard/HotelCardDialogImage/index.tsx +++ b/packages/design-system/lib/components/HotelCard/HotelCardDialogImage/index.tsx @@ -33,6 +33,7 @@ export function HotelCardDialogImage({ src={imageSrc} alt={altText || ''} fill + sizes={position === 'top' ? '200px' : '450px'} onError={() => setImageError(true)} /> )} diff --git a/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/StandaloneHotelCardDialog.stories.tsx b/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/StandaloneHotelCardDialog.stories.tsx index 0a98b30d9..1eb44501e 100644 --- a/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/StandaloneHotelCardDialog.stories.tsx +++ b/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/StandaloneHotelCardDialog.stories.tsx @@ -1,7 +1,9 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite' import { StandaloneHotelCardDialog } from './index' +import { Lang } from '@scandic-hotels/common/constants/language' import { fn } from 'storybook/test' +import { hotelPins } from '../../../Map/InteractiveMap/storybookData' const meta: Meta = { title: 'Components/StandaloneHotelCardDialog', @@ -15,29 +17,10 @@ type Story = StoryObj export const Default: Story = { args: { - data: { - name: 'Hotel Name', - image: { - url: 'img/img2.jpg', - alt: 'Alt text', - }, - coordinates: { - lat: 0, - lng: 0, - }, - chequePrice: null, - publicPrice: 100, - memberPrice: 200, - redemptionPrice: null, - voucherPrice: null, - rateType: null, - currency: 'SEK', - amenities: [], - ratings: { tripAdvisor: 5 }, - operaId: '123', - facilityIds: [], - hasEnoughPoints: false, - }, + lang: Lang.en, + isUserLoggedIn: false, + onClick: fn(), + data: hotelPins[0], handleClose: fn(), }, } diff --git a/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/index.tsx b/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/index.tsx index 35c88eb5c..59c2931dc 100644 --- a/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/index.tsx +++ b/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/index.tsx @@ -3,30 +3,27 @@ import { useState } from 'react' import { useIntl } from 'react-intl' -import { selectRate } from '@scandic-hotels/common/constants/routes/hotelReservation' -import Body from '../../../Body' -import Caption from '../../../Caption' -import Footnote from '../../../Footnote' import { IconButton } from '../../../IconButton' import { MaterialIcon } from '../../../Icons/MaterialIcon' -import Link from '../../../Link' -import { OldDSButton as Button } from '../../../OldDSButton' -import Subtitle from '../../../Subtitle' import { Typography } from '../../../Typography' import { HotelCardDialogImage } from '../../HotelCardDialogImage' import { NoPriceAvailableCard } from '../../NoPriceAvailableCard' +import { CurrencyEnum } from '@scandic-hotels/common/constants/currency' import { Lang } from '@scandic-hotels/common/constants/language' +import { selectRate } from '@scandic-hotels/common/constants/routes/hotelReservation' +import { useUrlWithSearchParam } from '@scandic-hotels/common/hooks/useUrlWithSearchParam' +import ButtonLink from '../../../ButtonLink' import { FacilityToIcon } from '../../../FacilityToIcon' import { HotelPin } from '../../../Map/types' import { HotelPointsRow } from '../../HotelPointsRow' +import { RoomPrice } from '../../RoomPrice' import styles from './standaloneHotelCardDialog.module.css' -import { CurrencyEnum } from '@scandic-hotels/common/constants/currency' interface StandaloneHotelCardProps { - data: HotelPin lang: Lang + data: HotelPin isUserLoggedIn: boolean handleClose: () => void onClick?: () => void @@ -63,6 +60,17 @@ export function StandaloneHotelCardDialog({ }) const shouldShowNotEnoughPoints = redemptionPrice && !hasEnoughPoints + const selectRateUrl = useUrlWithSearchParam( + { key: 'hotel', value: operaId }, + selectRate(lang) + ) + const showPriceCard = !!( + publicPrice || + memberPrice || + redemptionPrice || + voucherPrice || + chequePrice + ) return (
@@ -86,9 +94,9 @@ export function StandaloneHotelCardDialog({ position="left" />
-
- {name} -
+ +

{name}

+
{amenities.slice(0, 3).map((facility) => { const Icon = ( @@ -96,173 +104,93 @@ export function StandaloneHotelCardDialog({ ) return (
- {Icon} - - {facility.name} - + {Icon && Icon} + + {facility.name} +
) })}
-
- {publicPrice || - memberPrice || - redemptionPrice || - voucherPrice || - chequePrice ? ( - <> -
- {redemptionPrice ? ( - - {intl.formatMessage({ - defaultMessage: 'Available rates', - })} - - ) : ( - - {intl.formatMessage({ - defaultMessage: 'From', - })} - - )} - {chequePrice && ( - - {intl.formatMessage( - { - defaultMessage: '{price} {currency}', - }, - { - price: chequePrice.numberOfCheques, - currency: 'CC', - } - )} - {chequePrice.additionalPricePerStay > 0 - ? // eslint-disable-next-line formatjs/no-literal-string-in-jsx - ' + ' + - intl.formatMessage( - { - defaultMessage: '{price} {currency}', - }, - { - price: chequePrice.additionalPricePerStay, - currency: chequePrice.currency, - } - ) - : null} - - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} - - / - {intl.formatMessage({ - defaultMessage: 'night', - })} - - - - )} - {voucherPrice && ( - - {intl.formatMessage( - { - defaultMessage: '{price} {currency}', - }, - { - price: voucherPrice, - currency, - } - )} - - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} - - / - {intl.formatMessage({ - defaultMessage: 'night', - })} - - - - )} - {publicPrice && !isUserLoggedIn && ( - - {intl.formatMessage( - { - defaultMessage: '{price} {currency}', - }, - { - price: publicPrice, - currency, - } - )} - - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} - - / - {intl.formatMessage({ - defaultMessage: 'night', - })} - - - - )} - {memberPrice && ( - - {intl.formatMessage( - { - defaultMessage: '{price} {currency}', - }, - { - price: memberPrice, - currency, - } - )} - - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} - - / - {intl.formatMessage({ - defaultMessage: 'night', - })} - - - - )} - {redemptionPrice && ( - - )} -
- {shouldShowNotEnoughPoints ? ( -
- - {notEnoughPointsLabel} - -
- ) : ( - - )} - - ) : ( - - )} -
+ {chequePrice.additionalPricePerStay > 0 ? ( + <> + + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} + + + + + {chequePrice.additionalPricePerStay} + + + {chequePrice.currency} + + + ) : null} + + ) : null} + {voucherPrice ? ( + + ) : null} + {/* Show public price if: + 1) user is not logged in, or + 2) user is logged in but no member price is available (use of booking codes) + */} + {publicPrice && (!isUserLoggedIn || !memberPrice) ? ( + + ) : null} + {memberPrice ? ( + + ) : null} + {redemptionPrice ? ( + + ) : null} +
+ {shouldShowNotEnoughPoints ? ( + +
+ {notEnoughPointsLabel} +
+
+ ) : ( + + {intl.formatMessage({ + defaultMessage: 'See rooms', + })} + + )} + + ) : ( + + )}
) diff --git a/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/standaloneHotelCardDialog.module.css b/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/standaloneHotelCardDialog.module.css index 1af47b3ea..9d727b45a 100644 --- a/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/standaloneHotelCardDialog.module.css +++ b/packages/design-system/lib/components/HotelCard/HotelDialogCard/StandaloneHotelCardDialog/standaloneHotelCardDialog.module.css @@ -1,25 +1,30 @@ .container { - flex-direction: row; - display: flex; position: relative; - background: var(--Base-Surface-Primary-light-Normal); + display: flex; + background-color: var(--Surface-Primary-Default); box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.1); } + +.closeButton { + position: absolute; + top: var(--Space-x05); + right: var(--Space-x05); + z-index: 1; +} + .content { - width: 100%; - max-width: 220px; + width: 225px; padding: var(--Space-x15); display: flex; flex-direction: column; + gap: var(--Space-x1); } .name { height: 48px; - max-width: 180px; - margin-bottom: var(--Space-x05); + width: 180px; display: flex; align-items: center; - padding-right: var(--Space-x1); } .facilities { @@ -32,40 +37,23 @@ display: flex; align-items: center; gap: var(--Space-x05); -} - -.prices { - display: flex; - flex-direction: column; - gap: var(--Space-x1); - justify-content: space-between; + color: var(--Text-Secondary); } .priceCard { border-radius: var(--Corner-radius-md); padding: var(--Space-x05) var(--Space-x1); background: var(--Base-Surface-Secondary-light-Normal); - margin-top: var(--Space-x1); } -.pricesContainer { - display: flex; - flex-direction: column; - gap: var(--Space-x1); - justify-content: space-between; +.memberPrice { + color: var(--Text-Accent-Primary); } -.content .button { +.content .seeRoomsButton { margin-top: auto; } -.closeButton { - position: absolute; - top: 8px; - right: 8px; - z-index: 1; -} - .notEnoughPointsButton { border-radius: var(--Corner-radius-rounded); border-width: 2px; diff --git a/packages/design-system/lib/components/HotelCard/HotelPointsRow/hotelPointsRow.module.css b/packages/design-system/lib/components/HotelCard/HotelPointsRow/hotelPointsRow.module.css index 6c7f7a85e..cf8cfa7d7 100644 --- a/packages/design-system/lib/components/HotelCard/HotelPointsRow/hotelPointsRow.module.css +++ b/packages/design-system/lib/components/HotelCard/HotelPointsRow/hotelPointsRow.module.css @@ -1,6 +1,3 @@ -.poinstRow { - display: flex; - gap: var(--Space-x1); - align-items: baseline; +.roomPrice { color: var(--Text-Default); } diff --git a/packages/design-system/lib/components/HotelCard/HotelPointsRow/index.tsx b/packages/design-system/lib/components/HotelCard/HotelPointsRow/index.tsx index 22bdea6ae..26c9eaf22 100644 --- a/packages/design-system/lib/components/HotelCard/HotelPointsRow/index.tsx +++ b/packages/design-system/lib/components/HotelCard/HotelPointsRow/index.tsx @@ -1,10 +1,10 @@ import { useIntl } from 'react-intl' -import Caption from '../../Caption' -import Subtitle from '../../Subtitle' +import { RoomPrice } from '../../HotelCard/RoomPrice' +import { Typography } from '../../Typography' -import styles from './hotelPointsRow.module.css' import { CurrencyEnum } from '@scandic-hotels/common/constants/currency' +import styles from './hotelPointsRow.module.css' export type PointsRowProps = { pointsPerStay: number @@ -21,27 +21,28 @@ export function HotelPointsRow({ const intl = useIntl() return ( -
- - {pointsPerStay} - - - {pointsCurrency ?? - intl.formatMessage({ - defaultMessage: 'Points', - })} - + {additionalPricePerStay ? ( <> - {'+'} - - {additionalPricePerStay} - - - {additionalPriceCurrency} - + + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} + + + + + {additionalPricePerStay} + + + {additionalPriceCurrency} + ) : null} -
+ ) } diff --git a/packages/design-system/lib/components/HotelCard/RoomPrice/index.tsx b/packages/design-system/lib/components/HotelCard/RoomPrice/index.tsx new file mode 100644 index 000000000..f7642dfff --- /dev/null +++ b/packages/design-system/lib/components/HotelCard/RoomPrice/index.tsx @@ -0,0 +1,36 @@ +import { useIntl } from 'react-intl' +import { Typography } from '../../Typography' + +interface RoomPriceProps extends React.HTMLAttributes { + price: number + currency: string + includePerNight?: boolean +} + +export function RoomPrice({ + price, + currency, + children, + includePerNight = true, + ...props +}: RoomPriceProps) { + const intl = useIntl() + + return ( +

+ + {price} + + + {currency} + + {children} + {includePerNight ? ( + + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} + /{intl.formatMessage({ defaultMessage: 'night' })} + + ) : null} +

+ ) +} diff --git a/packages/design-system/lib/components/Map/InteractiveMap/HotelListingMapContent/index.tsx b/packages/design-system/lib/components/Map/InteractiveMap/HotelListingMapContent/index.tsx index 882af713e..69159ec8c 100644 --- a/packages/design-system/lib/components/Map/InteractiveMap/HotelListingMapContent/index.tsx +++ b/packages/design-system/lib/components/Map/InteractiveMap/HotelListingMapContent/index.tsx @@ -5,12 +5,13 @@ import { } from '@vis.gl/react-google-maps' import { useMediaQuery } from 'usehooks-ts' -import { HotelPin } from './HotelPin' +import { CurrencyEnum } from '@scandic-hotels/common/constants/currency' +import { Lang } from '@scandic-hotels/common/constants/language' +import { useIntl } from 'react-intl' +import { StandaloneHotelCardDialog } from '../../../HotelCard/HotelDialogCard/StandaloneHotelCardDialog' import type { HotelPin as HotelPinType } from '../../types' import styles from './hotelListingMapContent.module.css' -import { StandaloneHotelCardDialog } from '../../../HotelCard/HotelDialogCard/StandaloneHotelCardDialog' -import { Lang } from '@scandic-hotels/common/constants/language' -import { CurrencyEnum } from '@scandic-hotels/common/constants/currency' +import { HotelPin } from './HotelPin' export type HotelListingMapContentProps = { hotelPins: HotelPinType[] @@ -36,6 +37,7 @@ export function HotelListingMapContent({ onClickHotel, pointsCurrency, }: HotelListingMapContentProps) { + const intl = useIntl() const isDesktop = useMediaQuery('(min-width: 900px)') const toggleActiveHotelPin = ( @@ -62,6 +64,10 @@ export function HotelListingMapContent({ pin.chequePrice?.numberOfCheques ?? null + const pinCurrency = pin.redemptionPrice + ? intl.formatMessage({ defaultMessage: 'Points' }) + : pin.currency + const hotelAdditionalPrice = pin.chequePrice ? pin.chequePrice.additionalPricePerStay : undefined @@ -114,7 +120,7 @@ export function HotelListingMapContent({ diff --git a/packages/design-system/lib/components/Map/InteractiveMap/InteractiveMap.stories.tsx b/packages/design-system/lib/components/Map/InteractiveMap/InteractiveMap.stories.tsx index ced358078..0c182e364 100644 --- a/packages/design-system/lib/components/Map/InteractiveMap/InteractiveMap.stories.tsx +++ b/packages/design-system/lib/components/Map/InteractiveMap/InteractiveMap.stories.tsx @@ -1,10 +1,11 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite' // import { expect, fn } from 'storybook/test' -import { InteractiveMap } from '.' import { Lang } from '@scandic-hotels/common/constants/language' import { APIProvider } from '@vis.gl/react-google-maps' import { useState } from 'react' +import { InteractiveMap } from '.' +import { hotelPins } from './storybookData' const meta: Meta = { title: 'Components/Map/Interactive Map', @@ -19,159 +20,7 @@ type Story = StoryObj export const PrimaryDefault: Story = { args: { lang: Lang.en, - hotelPins: [ - { - coordinates: { - lat: 59.331303, - lng: 18.065542, - }, - name: 'Downtown Camper by Scandic', - chequePrice: null, - publicPrice: 1100, - memberPrice: 1067, - redemptionPrice: null, - voucherPrice: null, - rateType: 'Regular', - currency: 'SEK', - - amenities: [ - { - filter: 'Hotel facilities', - icon: 'Pool', - id: 1831, - name: 'Pool', - public: true, - sortOrder: 7000, - slug: 'pool', - }, - { - filter: 'Hotel facilities', - icon: 'Restaurant', - id: 1383, - name: 'Restaurant', - public: true, - sortOrder: 6000, - slug: 'restaurant', - }, - { - filter: 'None', - icon: 'KayaksForLoan', - id: 162585, - name: 'Kayaks for loan', - public: true, - sortOrder: 5000, - slug: 'kayaks-for-loan', - }, - { - filter: 'Hotel facilities', - icon: 'None', - id: 239348, - name: 'Rooftop bar', - public: false, - sortOrder: 4000, - slug: 'rooftop-bar', - }, - { - filter: 'None', - icon: 'BikesForLoan', - id: 5550, - name: 'Bikes for loan', - public: true, - sortOrder: 3000, - slug: 'bikes-for-loan', - }, - ], - ratings: { - tripAdvisor: 4.4, - }, - operaId: '879', - facilityIds: [ - 1831, 1383, 162585, 239348, 5550, 162586, 5806, 1014, 1835, 1829, - 1379, 1382, 162587, 1017, 1378, 1408, 1833, 971, 1834, 162584, 1381, - 229144, 267806, - ], - hasEnoughPoints: false, - image: { - alt: 'Bar of Downtown Camper by Scandic in Stockholm', - url: 'https://images-test.scandichotels.com/publishedmedia/z68596isempb61xm2ns9/Scandic_Downtown_Camper_spa_wellness_the_nest_swim.jpg', - }, - }, - { - coordinates: { - lat: 59.33469, - lng: 18.061586, - }, - name: 'Haymarket by Scandic', - chequePrice: null, - publicPrice: null, - memberPrice: 9999, - redemptionPrice: null, - voucherPrice: null, - rateType: 'Regular', - currency: 'SEK', - - amenities: [ - { - filter: 'Hotel facilities', - icon: 'Restaurant', - id: 1383, - name: 'Restaurant', - public: true, - sortOrder: 6000, - slug: 'restaurant', - }, - { - filter: 'None', - icon: 'None', - id: 5806, - name: 'Meeting / conference facilities', - public: true, - sortOrder: 1500, - slug: 'meeting-conference-facilities', - }, - { - filter: 'Hotel facilities', - icon: 'Bar', - id: 1014, - name: 'Bar', - public: true, - sortOrder: 1401, - slug: 'bar', - }, - { - filter: 'Hotel facilities', - icon: 'PetFriendlyRooms', - id: 1835, - name: 'Pet-friendly rooms', - public: true, - sortOrder: 1201, - slug: 'pet-friendly-rooms', - }, - { - filter: 'Hotel facilities', - icon: 'Gym', - id: 1829, - name: 'Gym', - public: true, - sortOrder: 1101, - slug: 'gym', - }, - ], - ratings: { - tripAdvisor: 4.1, - }, - operaId: '890', - facilityIds: [ - 1383, 5806, 1014, 1835, 1829, 1382, 162587, 1017, 1833, 971, 1834, - 1381, 1406, 1913, 345180, 375885, - ], - hasEnoughPoints: false, - image: { - alt: 'Bar', - url: 'https://images-test.scandichotels.com/publishedmedia/6wobp0j1ocvoopy1dmce/haymarket-by-scandic-bar-pauls_-3-.jpg', - }, - }, - ], + hotelPins, isUserLoggedIn: false, coordinates: { lat: 59.32644916839965, diff --git a/packages/design-system/lib/components/Map/InteractiveMap/index.tsx b/packages/design-system/lib/components/Map/InteractiveMap/index.tsx index 1b15a7f11..04b7d9fe1 100644 --- a/packages/design-system/lib/components/Map/InteractiveMap/index.tsx +++ b/packages/design-system/lib/components/Map/InteractiveMap/index.tsx @@ -16,9 +16,9 @@ import PoiMapMarkers from './PoiMapMarkers' import styles from './interactiveMap.module.css' -import { HotelPin, MarkerInfo, PointOfInterest } from '../types' -import { Lang } from '@scandic-hotels/common/constants/language' import { CurrencyEnum } from '@scandic-hotels/common/constants/currency' +import { Lang } from '@scandic-hotels/common/constants/language' +import { HotelPin, MarkerInfo, PointOfInterest } from '../types' export type InteractiveMapProps = { lang: Lang diff --git a/packages/design-system/lib/components/Map/InteractiveMap/storybookData.ts b/packages/design-system/lib/components/Map/InteractiveMap/storybookData.ts new file mode 100644 index 000000000..535b8e923 --- /dev/null +++ b/packages/design-system/lib/components/Map/InteractiveMap/storybookData.ts @@ -0,0 +1,379 @@ +import { CurrencyEnum } from '@scandic-hotels/common/constants/currency' +import { HotelPin } from '../types' + +export const hotelPins: HotelPin[] = [ + { + coordinates: { + lat: 59.331303, + lng: 18.065542, + }, + name: 'Downtown Camper by Scandic', + chequePrice: null, + publicPrice: 1100, + memberPrice: 1067, + redemptionPrice: null, + voucherPrice: null, + rateType: 'Regular', + currency: 'SEK', + amenities: [ + { + filter: 'Hotel facilities', + icon: 'Pool', + id: 1831, + name: 'Pool', + public: true, + sortOrder: 7000, + slug: 'pool', + }, + { + filter: 'Hotel facilities', + icon: 'Restaurant', + id: 1383, + name: 'Restaurant', + public: true, + sortOrder: 6000, + slug: 'restaurant', + }, + { + filter: 'None', + icon: 'KayaksForLoan', + id: 162585, + name: 'Kayaks for loan', + public: true, + sortOrder: 5000, + slug: 'kayaks-for-loan', + }, + { + filter: 'Hotel facilities', + icon: 'None', + id: 239348, + name: 'Rooftop bar', + public: false, + sortOrder: 4000, + slug: 'rooftop-bar', + }, + { + filter: 'None', + icon: 'BikesForLoan', + id: 5550, + name: 'Bikes for loan', + public: true, + sortOrder: 3000, + slug: 'bikes-for-loan', + }, + ], + ratings: { + tripAdvisor: 4.4, + }, + operaId: '879', + facilityIds: [ + 1831, 1383, 162585, 239348, 5550, 162586, 5806, 1014, 1835, 1829, 1379, + 1382, 162587, 1017, 1378, 1408, 1833, 971, 1834, 162584, 1381, 229144, + 267806, + ], + hasEnoughPoints: false, + image: { + alt: 'Bar of Downtown Camper by Scandic in Stockholm', + url: 'https://images-test.scandichotels.com/publishedmedia/p0ffjkfyfnx502knqlxo/Scandic_Downtown_Camper_spa_wellness_the_nest_swim.jpg', + }, + }, + { + coordinates: { + lat: 59.33469, + lng: 18.061586, + }, + name: 'Haymarket by Scandic', + chequePrice: null, + publicPrice: null, + memberPrice: 9999, + redemptionPrice: null, + voucherPrice: null, + rateType: 'Regular', + currency: 'SEK', + amenities: [ + { + filter: 'Hotel facilities', + icon: 'Restaurant', + id: 1383, + name: 'Restaurant', + public: true, + sortOrder: 6000, + slug: 'restaurant', + }, + { + filter: 'None', + icon: 'None', + id: 5806, + name: 'Meeting / conference facilities', + public: true, + sortOrder: 1500, + slug: 'meeting-conference-facilities', + }, + { + filter: 'Hotel facilities', + icon: 'Bar', + id: 1014, + name: 'Bar', + public: true, + sortOrder: 1401, + slug: 'bar', + }, + { + filter: 'Hotel facilities', + icon: 'PetFriendlyRooms', + id: 1835, + name: 'Pet-friendly rooms', + public: true, + sortOrder: 1201, + slug: 'pet-friendly-rooms', + }, + { + filter: 'Hotel facilities', + icon: 'Gym', + id: 1829, + name: 'Gym', + public: true, + sortOrder: 1101, + slug: 'gym', + }, + ], + ratings: { + tripAdvisor: 4.1, + }, + operaId: '890', + facilityIds: [ + 1383, 5806, 1014, 1835, 1829, 1382, 162587, 1017, 1833, 971, 1834, 1381, + 1406, 1913, 345180, 375885, + ], + hasEnoughPoints: false, + image: { + alt: 'Bar', + url: 'https://images-test.scandichotels.com/publishedmedia/lr2b7r655xl0sjcbgxt9/haymarket-by-scandic-bar-pauls_-3-.jpg', + }, + }, + { + coordinates: { + lat: 59.337166, + lng: 18.072765, + }, + name: 'Scandic Anglais', + chequePrice: { + numberOfCheques: 1, + additionalPricePerStay: 500, + currency: CurrencyEnum.SEK, + }, + publicPrice: null, + memberPrice: null, + redemptionPrice: null, + voucherPrice: null, + rateType: 'Regular', + currency: 'CC', + amenities: [ + { + filter: 'Hotel facilities', + icon: 'Restaurant', + id: 1383, + name: 'Restaurant', + public: true, + sortOrder: 6000, + slug: 'restaurant', + }, + { + filter: 'Hotel facilities', + icon: 'None', + id: 239348, + name: 'Rooftop bar', + public: false, + sortOrder: 4000, + slug: 'rooftop-bar', + }, + { + filter: 'None', + icon: 'BikesForLoan', + id: 5550, + name: 'Bikes for loan', + public: true, + sortOrder: 3000, + slug: 'bikes-for-loan', + }, + { + filter: 'None', + icon: 'None', + id: 5806, + name: 'Meeting / conference facilities', + public: true, + sortOrder: 1500, + slug: 'meeting-conference-facilities', + }, + { + filter: 'Hotel facilities', + icon: 'Bar', + id: 1014, + name: 'Bar', + public: true, + sortOrder: 1401, + slug: 'bar', + }, + ], + ratings: { + tripAdvisor: 3.6, + }, + operaId: '810', + facilityIds: [ + 1383, 239348, 5550, 5806, 1014, 1835, 1829, 1379, 2665, 1382, 162587, + 1017, 1408, 1833, 971, 1834, 1405, 1406, 956, 1913, + ], + hasEnoughPoints: false, + image: { + alt: 'lobby at scandic anglais in stockholm', + url: 'https://images-test.scandichotels.com/publishedmedia/wi0lzgxhbm4vmfguf7wm/scandic-anglais-lobby6.jpg', + }, + }, + { + coordinates: { + lat: 59.33099, + lng: 18.05926, + }, + name: 'Scandic Continental', + chequePrice: null, + publicPrice: null, + memberPrice: null, + redemptionPrice: 65000, + voucherPrice: null, + rateType: 'Regular', + currency: 'Points', + amenities: [ + { + filter: 'None', + icon: 'BikesForLoan', + id: 5550, + name: 'Bikes for loan', + public: true, + sortOrder: 3000, + slug: 'bikes-for-loan', + }, + { + filter: 'None', + icon: 'None', + id: 5806, + name: 'Meeting / conference facilities', + public: true, + sortOrder: 1500, + slug: 'meeting-conference-facilities', + }, + { + filter: 'Hotel facilities', + icon: 'PetFriendlyRooms', + id: 1835, + name: 'Pet-friendly rooms', + public: true, + sortOrder: 1201, + slug: 'pet-friendly-rooms', + }, + { + filter: 'Hotel facilities', + icon: 'Gym', + id: 1829, + name: 'Gym', + public: true, + sortOrder: 1101, + slug: 'gym', + }, + { + filter: 'Hotel facilities', + icon: 'Sauna', + id: 1379, + name: 'Sauna', + public: true, + sortOrder: 1001, + slug: 'sauna', + }, + ], + ratings: { + tripAdvisor: 4.2, + }, + operaId: '811', + facilityIds: [ + 5550, 5806, 1835, 1829, 1379, 2665, 1606, 1382, 1017, 1378, 1408, 1833, + 971, 1834, 162583, 1406, 1607, 1911, 1913, 229144, + ], + hasEnoughPoints: false, + image: { + alt: 'Exterior', + url: 'https://images-test.scandichotels.com/publishedmedia/xnvuuzvogv7dzt3nmxit/Scandic_Continental_Exterior_Vasagatan_Day.jpg', + }, + }, + { + coordinates: { + lat: 59.323063, + lng: 18.069921, + }, + name: 'Scandic Gamla Stan', + chequePrice: null, + publicPrice: null, + memberPrice: null, + redemptionPrice: null, + voucherPrice: 1, + rateType: 'Regular', + currency: 'Voucher', + amenities: [ + { + filter: 'Hotel facilities', + icon: 'PetFriendlyRooms', + id: 1835, + name: 'Pet-friendly rooms', + public: true, + sortOrder: 1201, + slug: 'pet-friendly-rooms', + }, + { + filter: 'Hotel facilities', + icon: 'OutdoorTerrace', + id: 1382, + name: 'Outdoor terrace', + public: true, + sortOrder: 550, + slug: 'outdoor-terrace', + }, + { + filter: 'None', + icon: 'Shop', + id: 1408, + name: 'Scandic Shop 24 hrs', + public: true, + sortOrder: 301, + slug: 'scandic-shop-24-hrs', + }, + { + filter: 'None', + icon: 'FreeWiFi', + id: 1833, + name: 'Free WiFi', + public: true, + sortOrder: 250, + slug: 'free-wifi', + }, + { + filter: 'None', + icon: 'LaundryService', + id: 1834, + name: 'Laundry service', + public: true, + sortOrder: 199, + slug: 'laundry-service', + }, + ], + ratings: { + tripAdvisor: 4.2, + }, + operaId: '821', + facilityIds: [ + 1835, 1382, 1408, 1833, 1834, 1405, 345180, 332224, 375885, 238849, + ], + hasEnoughPoints: false, + image: { + alt: 'Facade Entrance Scandic Gamla Stan Stockholm', + url: 'https://images-test.scandichotels.com/publishedmedia/9attpqkkfy6uwc6keyvg/Scandic-Gamla-Stan-Exterior-facade.jpg', + }, + }, +]