diff --git a/apps/scandic-web/components/HotelReservation/HotelCard/index.tsx b/apps/scandic-web/components/HotelReservation/HotelCard/index.tsx index cb1e48654..ed828d383 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCard/index.tsx +++ b/apps/scandic-web/components/HotelReservation/HotelCard/index.tsx @@ -2,7 +2,7 @@ import { useParams } from "next/dist/client/components/navigation" import { useRouter, useSearchParams } from "next/navigation" -import { memo, useCallback } from "react" +import { memo } from "react" import { useIntl } from "react-intl" import DiscountIcon from "@scandic-hotels/design-system/Icons/DiscountIcon" @@ -53,16 +53,7 @@ function HotelCard({ const lang = params.lang as Lang const intl = useIntl() - const { setActiveHotelPin, setActiveHotelCard } = useHotelsMapStore() - - const handleMouseEnter = useCallback(() => { - setActiveHotelPin(hotel.name) - }, [setActiveHotelPin, hotel]) - - const handleMouseLeave = useCallback(() => { - setActiveHotelPin(null) - setActiveHotelCard(null) - }, [setActiveHotelPin, setActiveHotelCard]) + const { activate, engage, disengageAfterDelay } = useHotelsMapStore() const amenities = hotel.detailedFacilities.slice(0, 5) const router = useRouter() @@ -73,8 +64,7 @@ function HotelCard({ const handleAddressClick = (event: React.MouseEvent) => { event.preventDefault() - setActiveHotelPin(hotel.name) - setActiveHotelCard(hotel.name) + activate(hotel.name) router.push(`${selectHotelMap(lang)}?${searchParams.toString()}`) } @@ -95,8 +85,8 @@ function HotelCard({ return (
engage(hotel.name)} + onMouseLeave={() => disengageAfterDelay()} >
diff --git a/apps/scandic-web/components/HotelReservation/HotelCardDialog/ListingHotelCardDialog/index.tsx b/apps/scandic-web/components/HotelReservation/HotelCardDialog/ListingHotelCardDialog/index.tsx index fcbed7706..bbdd3dc9b 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCardDialog/ListingHotelCardDialog/index.tsx +++ b/apps/scandic-web/components/HotelReservation/HotelCardDialog/ListingHotelCardDialog/index.tsx @@ -62,28 +62,20 @@ export default function ListingHotelCardDialog({ setImageError={setImageError} position="top" /> -
+
{name}
- {amenities.map((facility) => { - const Icon = ( + {amenities.map((facility) => ( +
- ) - return ( -
- {Icon && Icon} - - {facility.name} - -
- ) - })} +
+ ))}
@@ -115,7 +107,7 @@ export default function ListingHotelCardDialog({ )} {memberPrice && ( - + {intl.formatMessage( { defaultMessage: "{price} {currency}", diff --git a/apps/scandic-web/components/HotelReservation/HotelCardDialog/StandaloneHotelCardDialog/index.tsx b/apps/scandic-web/components/HotelReservation/HotelCardDialog/StandaloneHotelCardDialog/index.tsx index 59d664824..eca618793 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCardDialog/StandaloneHotelCardDialog/index.tsx +++ b/apps/scandic-web/components/HotelReservation/HotelCardDialog/StandaloneHotelCardDialog/index.tsx @@ -65,10 +65,8 @@ export default function StandaloneHotelCardDialog({ />
-
-
- {name} -
+
+ {name}
@@ -126,11 +124,7 @@ export default function StandaloneHotelCardDialog({ )} {memberPrice && ( - + {intl.formatMessage( { defaultMessage: "{price} {currency}", diff --git a/apps/scandic-web/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css b/apps/scandic-web/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css index ebee53701..ab3fc4f42 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css +++ b/apps/scandic-web/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css @@ -66,7 +66,7 @@ white-space: nowrap; position: relative; padding-right: 20px; - gap: 0 var(--Spacing-x1); + gap: 0 var(--Spacing-x-one-and-half); max-width: 242px; } .dialogContainer[data-type="listing"] .facilities::after { diff --git a/apps/scandic-web/components/HotelReservation/HotelCardDialog/index.tsx b/apps/scandic-web/components/HotelReservation/HotelCardDialog/index.tsx index d14349638..dac5c8194 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCardDialog/index.tsx +++ b/apps/scandic-web/components/HotelReservation/HotelCardDialog/index.tsx @@ -31,7 +31,7 @@ export default function HotelCardDialog({
- +
{type === "standalone" ? ( diff --git a/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/hotelCardDialogListing.module.css b/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/hotelCardDialogListing.module.css index 1d265dfac..cb682c385 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/hotelCardDialogListing.module.css +++ b/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/hotelCardDialogListing.module.css @@ -3,6 +3,23 @@ flex-direction: row; gap: var(--Spacing-x1); align-items: flex-end; + overflow-x: scroll; + + scroll-snap-type: x proximity; + -webkit-overflow-scrolling: touch; /* Needed to work on iOS Safari */ + padding-inline: var(--Spacing-x2); + scroll-padding-inline: var(--Spacing-x2); + overscroll-behavior-inline: contain; + + scroll-behavior: smooth; + will-change: transform; + backface-visibility: hidden; + transform: translateZ(0); +} + +.hotelCardDialogListing > div { + height: 100%; + scroll-snap-align: center; } .hotelCardDialogListing dialog { @@ -10,11 +27,3 @@ padding: 0; margin: 0; } - -.hotelCardDialogListing > div:first-child { - margin-left: var(--Spacing-x2); -} - -.hotelCardDialogListing > div:last-child { - margin-right: var(--Spacing-x2); -} diff --git a/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/index.tsx b/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/index.tsx index 8bd3e4ca7..977023df4 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/index.tsx +++ b/apps/scandic-web/components/HotelReservation/HotelCardDialogListing/index.tsx @@ -2,12 +2,9 @@ import { useCallback, useEffect, useRef } from "react" import { useIntl } from "react-intl" -import { useMediaQuery } from "usehooks-ts" import { useHotelsMapStore } from "@/stores/hotels-map" -import useClickOutside from "@/hooks/useClickOutside" - import HotelCardDialog from "../HotelCardDialog" import { getHotelPins } from "./utils" @@ -27,89 +24,119 @@ export default function HotelCardDialogListing({ defaultMessage: "Points", }) : undefined - const hotelsPinData = hotels ? getHotelPins(hotels, currencyValue) : [] + const hotelsPinData = getHotelPins(hotels, currencyValue) const activeCardRef = useRef(null) const observerRef = useRef(null) const dialogRef = useRef(null) - const isMobile = useMediaQuery("(max-width: 767px)") - const { activeHotelCard, setActiveHotelCard, setActiveHotelPin } = - useHotelsMapStore() - - function handleClose() { - setActiveHotelCard(null) - setActiveHotelPin(null) - } - - useClickOutside(dialogRef, !!activeHotelCard && isMobile, handleClose) + const isScrollingRef = useRef(false) + const debounceTimerRef = useRef | null>(null) + const { activeHotel, activate, deactivate } = useHotelsMapStore() const handleIntersection = useCallback( (entries: IntersectionObserverEntry[]) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - const cardName = entry.target.getAttribute("data-name") - if (cardName) { - setActiveHotelCard(cardName) + // skip intersection handling during scrolling + if (isScrollingRef.current) return + + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current) + } + + debounceTimerRef.current = setTimeout(() => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const cardName = entry.target.getAttribute("data-name") + if (cardName && cardName !== activeHotel) { + activate(cardName) + } } - } - }) + }) + }, 100) }, - [setActiveHotelCard] + [activate, activeHotel] ) useEffect(() => { observerRef.current = new IntersectionObserver(handleIntersection, { root: null, - threshold: 0.5, + threshold: [0.3, 0.5, 0.7], }) const elements = document.querySelectorAll("[data-name]") elements.forEach((el) => observerRef.current?.observe(el)) return () => { + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current) + } + elements.forEach((el) => observerRef.current?.unobserve(el)) observerRef.current?.disconnect() + observerRef.current = null } }, [handleIntersection]) useEffect(() => { if (activeCardRef.current) { - // Temporarily disconnect the observer - observerRef.current?.disconnect() + isScrollingRef.current = true - activeCardRef.current.scrollIntoView({ - behavior: "smooth", - block: "nearest", - inline: "center", + requestAnimationFrame(() => { + activeCardRef.current?.scrollIntoView({ + behavior: "smooth", + block: "nearest", + inline: "center", + }) + + setTimeout(() => { + isScrollingRef.current = false + }, 800) }) - - // Reconnect the observer after scrolling - const elements = document.querySelectorAll("[data-name]") - setTimeout(() => { - elements.forEach((el) => observerRef.current?.observe(el)) - }, 1000) } - }, [activeHotelCard]) + }, [activeHotel]) + + useEffect(() => { + const handleMapClick = (e: MouseEvent) => { + // ignore clicks within the dialog + if (dialogRef.current?.contains(e.target as Node)) { + return + } + + // ignore clicks on hotel pins + const target = e.target as HTMLElement + if (target.closest("[data-hotelpin]")) { + return + } + + deactivate() + } + + if (activeHotel) { + document.addEventListener("click", handleMapClick) + } + + return () => { + document.removeEventListener("click", handleMapClick) + } + }, [dialogRef, activeHotel, deactivate]) return (
- {!!hotelsPinData?.length && - hotelsPinData.map((data) => { - const isActive = data.name === activeHotelCard - return ( -
- -
- ) - })} + {hotelsPinData?.map((data) => { + const isActive = data.name === activeHotel + return ( +
+ +
+ ) + })}
) } diff --git a/apps/scandic-web/components/HotelReservation/HotelCardListing/index.tsx b/apps/scandic-web/components/HotelReservation/HotelCardListing/index.tsx index 360fbbe7b..311024d8d 100644 --- a/apps/scandic-web/components/HotelReservation/HotelCardListing/index.tsx +++ b/apps/scandic-web/components/HotelReservation/HotelCardListing/index.tsx @@ -37,7 +37,7 @@ export default function HotelCardListing({ const activeFilters = useHotelFilterStore((state) => state.activeFilters) const setResultCount = useHotelFilterStore((state) => state.setResultCount) const intl = useIntl() - const { activeHotelCard } = useHotelsMapStore() + const { activeHotel } = useHotelsMapStore() const { showBackToTop, scrollToTop } = useScrollToTop({ threshold: 490 }) const activeCardRef = useRef(null) @@ -108,7 +108,7 @@ export default function HotelCardListing({ inline: "center", }) } - }, [activeHotelCard, type]) + }, [activeHotel, type]) useEffect(() => { setResultCount(hotels.length) @@ -116,8 +116,7 @@ export default function HotelCardListing({ function isHotelActiveInMapView(hotelName: string): boolean { return ( - hotelName === activeHotelCard && - type === HotelCardListingTypeEnum.MapListing + hotelName === activeHotel && type === HotelCardListingTypeEnum.MapListing ) } diff --git a/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx b/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx index cfd61a8e6..5f5e04e8e 100644 --- a/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx @@ -13,22 +13,19 @@ import { HotelCardListingTypeEnum } from "@/types/components/hotelReservation/se import type { HotelListingProps } from "@/types/components/hotelReservation/selectHotel/map" export default function HotelListing({ hotels }: HotelListingProps) { - const { activeHotelPin } = useHotelsMapStore() + const { activeHotel } = useHotelsMapStore() const isMobile = useMediaQuery("(max-width: 767px)") - return ( - <> - {isMobile ? ( -
- -
- ) : ( -
- -
- )} - + + return isMobile ? ( +
+ +
+ ) : ( +
+ +
) } diff --git a/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContent/index.tsx b/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContent/index.tsx index ab5a81875..c8c2eb65e 100644 --- a/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContent/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContent/index.tsx @@ -53,7 +53,7 @@ export default function SelectHotelContent({ const listingContainerRef = useRef(null) const activeFilters = useHotelFilterStore((state) => state.activeFilters) - const { activeHotelPin } = useHotelsMapStore() + const { activeHotel } = useHotelsMapStore() const { showBackToTop, scrollToTop } = useScrollToTop({ threshold: 490, @@ -65,8 +65,8 @@ export default function SelectHotelContent({ ) const coordinates = useMemo(() => { - if (activeHotelPin) { - const hotel = hotels.find((hotel) => hotel.hotel.name === activeHotelPin) + if (activeHotel) { + const hotel = hotels.find((hotel) => hotel.hotel.name === activeHotel) if (hotel && hotel.hotel.location) { return { @@ -79,7 +79,7 @@ export default function SelectHotelContent({ return isAboveMobile ? cityCoordinates : { ...cityCoordinates, lat: cityCoordinates.lat - 0.006 } - }, [activeHotelPin, hotels, isAboveMobile, cityCoordinates]) + }, [activeHotel, hotels, isAboveMobile, cityCoordinates]) const filteredHotelPins = useMemo(() => { const updatedHotelsList = bookingCode @@ -159,14 +159,15 @@ export default function SelectHotelContent({
+ + {isNotAvailable ? ( + + ) : ( + + )} + + +

{isNotAvailable ? "—" : formatPrice(intl, hotelPrice, currency)}

+
+
+ ) +} diff --git a/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css b/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css index dc35427cb..0cc6a8fb7 100644 --- a/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css +++ b/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css @@ -1,62 +1,11 @@ .advancedMarker { height: 32px; - min-width: 109px !important; /* Overwriting the default width of the @vis.gl/react-google-maps AdvancedMarker */ -} - -.advancedMarker.active { - height: 32px; - min-width: 109px !important; /* Overwriting the default width of the @vis.gl/react-google-maps AdvancedMarker */ } .dialogContainer { display: none; } -.pin { - position: absolute; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; - padding: var(--Spacing-x-half) var(--Spacing-x1) var(--Spacing-x-half) - var(--Spacing-x-half); - border-radius: var(--Corner-radius-Rounded); - background-color: var(--Base-Surface-Primary-light-Normal); - box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.1); - gap: var(--Spacing-x1); - width: max-content; -} - -.pin.active { - background-color: var(--Primary-Dark-Surface-Normal); -} - -.pinLabel { - display: none; -} - -.pin.active .pinLabel { - display: flex; - align-items: center; - gap: var(--Spacing-x2); - text-wrap: nowrap; -} - -.pinIcon { - width: 24px; - height: 24px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - background: var(--Primary-Dark-Surface-Normal); -} - -.pin.active .pinIcon { - background: var(--Base-Surface-Primary-light-Normal); -} - .card { display: none; position: absolute; diff --git a/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx b/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx index baab2b416..4932419c5 100644 --- a/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx +++ b/apps/scandic-web/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx @@ -2,62 +2,39 @@ import { AdvancedMarker, AdvancedMarkerAnchorPoint, } from "@vis.gl/react-google-maps" -import { useCallback, useState } from "react" -import { useIntl } from "react-intl" +import { useCallback } from "react" import { useHotelsMapStore } from "@/stores/hotels-map" import HotelCardDialog from "@/components/HotelReservation/HotelCardDialog" -import Body from "@/components/TempDesignSystem/Text/Body" -import { formatPrice } from "@/utils/numberFormatting" -import HotelMarker from "../../Markers/HotelMarker" +import HotelPin from "./HotelPin" import styles from "./hotelListingMapContent.module.css" import type { HotelListingMapContentProps } from "@/types/components/hotelReservation/selectHotel/map" function HotelListingMapContent({ hotelPins }: HotelListingMapContentProps) { - const intl = useIntl() - const [hoveredHotelPin, setHoveredHotelPin] = useState(null) - const { activeHotelPin, setActiveHotelPin, setActiveHotelCard } = + const { activeHotel, hoveredHotel, activate, deactivate, engage, disengage } = useHotelsMapStore() const toggleActiveHotelPin = useCallback( (pinName: string | null) => { - if (setActiveHotelPin) { - const newActivePin = activeHotelPin === pinName ? null : pinName - setActiveHotelPin(newActivePin) - setActiveHotelCard(newActivePin) - if (newActivePin === null) { - setHoveredHotelPin(null) - setActiveHotelCard(null) - } + if (activeHotel === pinName || pinName === null) { + deactivate() + return } - }, - [activeHotelPin, setActiveHotelPin, setActiveHotelCard] - ) - const handleHover = useCallback( - (pinName: string | null) => { - if (pinName !== null && activeHotelPin !== pinName) { - setHoveredHotelPin(pinName) - if (activeHotelPin && setActiveHotelPin) { - setActiveHotelPin(null) - setActiveHotelCard(null) - } - } else if (pinName === null) { - setHoveredHotelPin(null) - } + activate(pinName) }, - [activeHotelPin, setActiveHotelPin, setActiveHotelCard] + [activeHotel, activate, deactivate] ) return (
{hotelPins.map((pin) => { const isActiveOrHovered = - activeHotelPin === pin.name || hoveredHotelPin === pin.name + activeHotel === pin.name || hoveredHotel === pin.name const hotelPrice = pin.memberPrice ?? pin.publicPrice ?? pin.redemptionPrice return ( @@ -67,8 +44,8 @@ function HotelListingMapContent({ hotelPins }: HotelListingMapContentProps) { position={pin.coordinates} anchorPoint={AdvancedMarkerAnchorPoint.CENTER} zIndex={isActiveOrHovered ? 2 : 0} - onMouseEnter={() => handleHover(pin.name)} - onMouseLeave={() => handleHover(null)} + onMouseEnter={() => engage(pin.name)} + onMouseLeave={() => disengage()} onClick={() => toggleActiveHotelPin(pin.name)} >
@@ -76,37 +53,17 @@ function HotelListingMapContent({ hotelPins }: HotelListingMapContentProps) { isOpen={isActiveOrHovered} handleClose={(event: { stopPropagation: () => void }) => { event.stopPropagation() - if (activeHotelPin === pin.name) { - toggleActiveHotelPin(null) - } + deactivate() + disengage() }} data={pin} />
- - - - - - - - {/* TODO: Handle when no price is available */} - {hotelPrice - ? formatPrice(intl, hotelPrice, pin.currency) - : intl.formatMessage({ - defaultMessage: "N/A", - })} - - - + ) })} diff --git a/apps/scandic-web/components/Maps/InteractiveMap/HotelMapContent/index.tsx b/apps/scandic-web/components/Maps/InteractiveMap/PoiMapMarkers/index.tsx similarity index 92% rename from apps/scandic-web/components/Maps/InteractiveMap/HotelMapContent/index.tsx rename to apps/scandic-web/components/Maps/InteractiveMap/PoiMapMarkers/index.tsx index c41d82f35..e1af9c781 100644 --- a/apps/scandic-web/components/Maps/InteractiveMap/HotelMapContent/index.tsx +++ b/apps/scandic-web/components/Maps/InteractiveMap/PoiMapMarkers/index.tsx @@ -10,16 +10,16 @@ import Caption from "@/components/TempDesignSystem/Text/Caption" import PoiMarker from "../../Markers/Poi" import ScandicMarker from "../../Markers/Scandic" -import styles from "./hotelMapContent.module.css" +import styles from "./poiMapMarkers.module.css" -import type { HotelMapContentProps } from "@/types/hotel" +import type { PoiMapMarkersProps } from "@/types/hotel" -export default function HotelMapContent({ +export default function PoiMapMarkers({ coordinates, pointsOfInterest, onActivePoiChange, activePoi, -}: HotelMapContentProps) { +}: PoiMapMarkersProps) { const intl = useIntl() function toggleActivePoi(poiName: string) { diff --git a/apps/scandic-web/components/Maps/InteractiveMap/HotelMapContent/hotelMapContent.module.css b/apps/scandic-web/components/Maps/InteractiveMap/PoiMapMarkers/poiMapMarkers.module.css similarity index 100% rename from apps/scandic-web/components/Maps/InteractiveMap/HotelMapContent/hotelMapContent.module.css rename to apps/scandic-web/components/Maps/InteractiveMap/PoiMapMarkers/poiMapMarkers.module.css diff --git a/apps/scandic-web/components/Maps/InteractiveMap/index.tsx b/apps/scandic-web/components/Maps/InteractiveMap/index.tsx index b513df215..09cbfe314 100644 --- a/apps/scandic-web/components/Maps/InteractiveMap/index.tsx +++ b/apps/scandic-web/components/Maps/InteractiveMap/index.tsx @@ -9,7 +9,7 @@ import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import Button from "@/components/TempDesignSystem/Button" import HotelListingMapContent from "./HotelListingMapContent" -import HotelMapContent from "./HotelMapContent" +import PoiMapMarkers from "./PoiMapMarkers" import styles from "./interactiveMap.module.css" @@ -36,6 +36,7 @@ export default function InteractiveMap({ disableDefaultUI: true, clickableIcons: false, mapId, + gestureHandling: "greedy", } function zoomIn() { @@ -67,7 +68,7 @@ export default function InteractiveMap({ {hotelPins && } {pointsOfInterest && ( - void - setActiveHotelPin: (hotelPin: string | null) => void + activeHotel: string | null + hoveredHotel: string | null + hoverTimeout: number | null + activate: (hotel: string | null) => void + deactivate: () => void + engage: (hotel: string | null) => void + disengage: () => void + disengageAfterDelay: () => void } -export const useHotelsMapStore = create((set) => ({ - activeHotelCard: null, - activeHotelPin: null, - setActiveHotelCard: (hotelCard) => set({ activeHotelCard: hotelCard }), - setActiveHotelPin: (hotelPin) => set({ activeHotelPin: hotelPin }), +export const useHotelsMapStore = create((set, get) => ({ + activeHotel: null, + hoveredHotel: null, + hoverTimeout: null, + activate: (hotel) => set({ activeHotel: hotel }), + deactivate: () => set({ activeHotel: null }), + engage: (hotel) => { + const state = get() + + if (state.hoverTimeout) { + window.clearTimeout(state.hoverTimeout) + } + + if (hotel && state.activeHotel) { + set({ activeHotel: null }) + } + + set({ hoveredHotel: hotel }) + }, + disengage: () => { + set({ hoveredHotel: null }) + }, + disengageAfterDelay: () => { + const timeoutId = window.setTimeout(() => { + set({ hoveredHotel: null, activeHotel: null, hoverTimeout: null }) + }, 3000) + + set({ hoverTimeout: timeoutId }) + }, })) diff --git a/apps/scandic-web/types/hotel.ts b/apps/scandic-web/types/hotel.ts index 87e2f5f30..7e2d0cd3c 100644 --- a/apps/scandic-web/types/hotel.ts +++ b/apps/scandic-web/types/hotel.ts @@ -63,7 +63,7 @@ export type RestaurantOpeningHoursDay = z.output< > export type Room = ReturnType -export type HotelMapContentProps = { +export type PoiMapMarkersProps = { activePoi?: string | null coordinates: { lat: number; lng: number } onActivePoiChange?: (poiName: string | null) => void diff --git a/packages/design-system/lib/fonts.css b/packages/design-system/lib/fonts.css index c2a514ae6..dcfcdf893 100644 --- a/packages/design-system/lib/fonts.css +++ b/packages/design-system/lib/fonts.css @@ -269,7 +269,7 @@ font-style: normal; font-weight: 400; font-display: block; - src: url(/_static/fonts/material-symbols/rounded-ad9423f9.woff2) + src: url(/_static/fonts/material-symbols/rounded-112272ae.woff2) format('woff2'); } diff --git a/packages/design-system/public/_static/fonts/material-symbols/rounded-112272ae.woff2 b/packages/design-system/public/_static/fonts/material-symbols/rounded-112272ae.woff2 new file mode 100644 index 000000000..7a133cedc Binary files /dev/null and b/packages/design-system/public/_static/fonts/material-symbols/rounded-112272ae.woff2 differ diff --git a/packages/design-system/public/_static/fonts/material-symbols/rounded-ad9423f9.woff2 b/packages/design-system/public/_static/fonts/material-symbols/rounded-ad9423f9.woff2 deleted file mode 100644 index ace4eca5f..000000000 Binary files a/packages/design-system/public/_static/fonts/material-symbols/rounded-ad9423f9.woff2 and /dev/null differ diff --git a/scripts/material-symbols-update.mjs b/scripts/material-symbols-update.mjs index 15ff1c47f..1bfb80633 100644 --- a/scripts/material-symbols-update.mjs +++ b/scripts/material-symbols-update.mjs @@ -45,6 +45,7 @@ const icons = [ 'box', 'business_center', 'calendar_add_on', + 'calendar_clock', 'calendar_month', 'calendar_today', 'call',