Merged in SW-3270-move-interactive-map-to-design-system-or-booking-flow (pull request #2681)

SW-3270 move interactive map to design system or booking flow

* wip

* wip

* merge

* wip

* add support for locales in design-system

* add story for HotelCard

* setup alias

* .

* remove tracking from design-system for hotelcard

* pass isUserLoggedIn

* export design-system-new-deprecated.css from design-system

* Add HotelMarkerByType to Storybook

* Add interactive map to Storybook

* fix reactintl in vitest

* rename env variables

* .

* fix background colors

* add storybook stories for <Link />

* merge

* fix tracking for when clicking 'See rooms' in InteractiveMap

* Merge branch 'master' of bitbucket.org:scandic-swap/web into SW-3270-move-interactive-map-to-design-system-or-booking-flow

* remove deprecated comment


Approved-by: Anton Gunnarsson
This commit is contained in:
Joakim Jäderberg
2025-08-25 11:26:16 +00:00
parent 4f8c51298f
commit c54c1ec540
139 changed files with 2511 additions and 1557 deletions

View File

@@ -1,4 +1,5 @@
"use client"
import { useMap } from "@vis.gl/react-google-maps"
import { useCallback, useMemo, useRef, useState } from "react"
import { useIntl } from "react-intl"
@@ -18,15 +19,18 @@ import { BackToTopButton } from "@scandic-hotels/design-system/BackToTopButton"
import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import Link from "@scandic-hotels/design-system/Link"
import { InteractiveMap } from "@scandic-hotels/design-system/Map/InteractiveMap"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useHotelFilterStore } from "@/stores/hotel-filters"
import { useHotelsMapStore } from "@/stores/hotels-map"
import { RoomCardSkeleton } from "@/components/HotelReservation/RoomCardSkeleton/RoomCardSkeleton"
import InteractiveMap from "@/components/Maps/InteractiveMap"
import { useIsUserLoggedIn } from "@/hooks/useIsUserLoggedIn"
import useLang from "@/hooks/useLang"
import { useScrollToTop } from "@/hooks/useScrollToTop"
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
import { trackEvent } from "@/utils/tracking/base"
import FilterAndSortModal from "../../Filters/FilterAndSortModal"
import HotelListing from "../HotelListing"
@@ -39,7 +43,7 @@ import type { HotelResponse } from "@/components/HotelReservation/SelectHotel/he
const SKELETON_LOAD_DELAY = 750
export default function SelectHotelContent({
export function SelectHotelMapContent({
hotelPins,
cityCoordinates,
mapId,
@@ -52,6 +56,7 @@ export default function SelectHotelContent({
const lang = useLang()
const intl = useIntl()
const map = useMap()
const isUserLoggedIn = useIsUserLoggedIn()
const isAboveMobile = useMediaQuery("(min-width: 900px)")
const [visibleHotels, setVisibleHotels] = useState<HotelResponse[]>([])
@@ -59,7 +64,7 @@ export default function SelectHotelContent({
const listingContainerRef = useRef<HTMLDivElement | null>(null)
const activeFilters = useHotelFilterStore((state) => state.activeFilters)
const { activeHotel } = useHotelsMapStore()
const hotelMapStore = useHotelsMapStore()
const { showBackToTop, scrollToTop } = useScrollToTop({
threshold: 490,
@@ -71,8 +76,10 @@ export default function SelectHotelContent({
)
const coordinates = useMemo(() => {
if (activeHotel) {
const hotel = hotels.find((hotel) => hotel.hotel.name === activeHotel)
if (hotelMapStore.activeHotel) {
const hotel = hotels.find(
(hotel) => hotel.hotel.name === hotelMapStore.activeHotel
)
if (hotel && hotel.hotel.location) {
return isAboveMobile
@@ -89,7 +96,7 @@ export default function SelectHotelContent({
return isAboveMobile
? cityCoordinates
: { ...cityCoordinates, lat: cityCoordinates.lat - 0.006 }
}, [activeHotel, hotels, isAboveMobile, cityCoordinates])
}, [hotelMapStore.activeHotel, hotels, isAboveMobile, cityCoordinates])
const showOnlyBookingCodeRates =
bookingCode &&
@@ -231,10 +238,62 @@ export default function SelectHotelContent({
<InteractiveMap
closeButton={closeButton}
coordinates={coordinates}
hotelPins={filteredHotelPins}
hotelPins={filteredHotelPins.map((pin) => {
const galleryImage = mapApiImagesToGalleryImages(pin.images).at(0)
return {
...pin,
ratings: {
tripAdvisor: pin.ratings ?? null,
},
image: {
alt: galleryImage?.alt ?? "",
url: galleryImage?.src ?? "",
},
}
})}
mapId={mapId}
onTilesLoaded={debouncedUpdateHotelCards}
fitBounds={isAboveMobile || !activeHotel}
fitBounds={isAboveMobile || !hotelMapStore.activeHotel}
onHoverHotelPin={(args) => {
if (!args) {
hotelMapStore.disengage()
return
}
hotelMapStore.engage(args.hotelName)
}}
hoveredHotelPin={hotelMapStore.hoveredHotel}
onSetActiveHotelPin={(args) => {
if (!args || args.hotelName === hotelMapStore.activeHotel) {
hotelMapStore.deactivate()
return
}
trackEvent({
event: "hotelClickMap",
map: {
action: "hotel click - map",
},
hotelInfo: {
hotelId: args.hotelId,
},
})
hotelMapStore.activate(args.hotelName)
}}
onClickHotel={(hotelId) => {
trackEvent({
event: "hotelClickMap",
map: {
action: "hotel click - map",
},
hotelInfo: {
hotelId,
},
})
}}
lang={lang}
isUserLoggedIn={isUserLoggedIn}
/>
</div>
)

View File

@@ -2,7 +2,7 @@
import { APIProvider } from "@vis.gl/react-google-maps"
import SelectHotelMapContent from "./SelectHotelMapContent"
import { SelectHotelMapContent } from "./SelectHotelMapContent"
import type { SelectHotelMapProps } from "@/types/components/hotelReservation/selectHotel/map"

View File

@@ -1,7 +1,6 @@
import { HotelCardSkeleton } from "@scandic-hotels/design-system/HotelCard/HotelCardSkeleton"
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
import { HotelCardSkeleton } from "../HotelCard/HotelCardSkeleton"
import styles from "./selectHotel.module.css"
type Props = {