diff --git a/components/HotelReservation/HotelCard/index.tsx b/components/HotelReservation/HotelCard/index.tsx index 616ca03cf..1362b3ad6 100644 --- a/components/HotelReservation/HotelCard/index.tsx +++ b/components/HotelReservation/HotelCard/index.tsx @@ -1,5 +1,6 @@ "use client" import { useParams } from "next/dist/client/components/navigation" +import { memo, useCallback } from "react" import { useIntl } from "react-intl" import { Lang } from "@/constants/languages" @@ -25,7 +26,7 @@ import styles from "./hotelCard.module.css" import { HotelCardListingTypeEnum } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps" import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps" -export default function HotelCard({ +function HotelCard({ hotel, type = HotelCardListingTypeEnum.PageListing, state = "default", @@ -45,16 +46,17 @@ export default function HotelCard({ state, }) - const handleMouseEnter = () => { + const handleMouseEnter = useCallback(() => { if (onHotelCardHover) { onHotelCardHover(hotelData.name) } - } - const handleMouseLeave = () => { + }, [onHotelCardHover, hotelData.name]) + + const handleMouseLeave = useCallback(() => { if (onHotelCardHover) { onHotelCardHover(null) } - } + }, [onHotelCardHover]) return (
) } + +export default memo(HotelCard) diff --git a/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css b/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css index 5c6e6d6bd..7d607d3ad 100644 --- a/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css +++ b/components/HotelReservation/HotelCardDialog/hotelCardDialog.module.css @@ -1,6 +1,6 @@ .dialog { padding-bottom: var(--Spacing-x1); - bottom: 32px; + bottom: 0; left: 50%; transform: translateX(-50%); border: none; @@ -33,6 +33,8 @@ .imageContainer { position: relative; min-width: 177px; + border-radius: var(--Corner-radius-Medium) 0 0 var(--Corner-radius-Medium); + overflow: hidden; } .imageContainer img { @@ -108,4 +110,7 @@ .memberPrice { display: none; } + .dialog { + bottom: 32px; + } } diff --git a/components/HotelReservation/HotelCardDialogListing/hotelCardDialogListing.module.css b/components/HotelReservation/HotelCardDialogListing/hotelCardDialogListing.module.css new file mode 100644 index 000000000..1d265dfac --- /dev/null +++ b/components/HotelReservation/HotelCardDialogListing/hotelCardDialogListing.module.css @@ -0,0 +1,20 @@ +.hotelCardDialogListing { + display: flex; + flex-direction: row; + gap: var(--Spacing-x1); + align-items: flex-end; +} + +.hotelCardDialogListing dialog { + position: relative; + 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/components/HotelReservation/HotelCardDialogListing/index.tsx b/components/HotelReservation/HotelCardDialogListing/index.tsx index f13ff0433..123cc4ced 100644 --- a/components/HotelReservation/HotelCardDialogListing/index.tsx +++ b/components/HotelReservation/HotelCardDialogListing/index.tsx @@ -1,10 +1,15 @@ "use client" import { useCallback, useEffect, useRef } from "react" +import { useMediaQuery } from "usehooks-ts" + +import useClickOutside from "@/hooks/useClickOutside" import HotelCardDialog from "../HotelCardDialog" import { getHotelPins } from "./utils" +import styles from "./hotelCardDialogListing.module.css" + import type { HotelCardDialogListingProps } from "@/types/components/hotelReservation/selectHotel/map" export default function HotelCardDialogListing({ @@ -15,6 +20,12 @@ export default function HotelCardDialogListing({ const hotelsPinData = getHotelPins(hotels) const activeCardRef = useRef(null) const observerRef = useRef(null) + const dialogRef = useRef(null) + const isMobile = useMediaQuery("(max-width: 768px)") + + useClickOutside(dialogRef, !!activeCard && isMobile, () => { + onActiveCardChange(null) + }) const handleIntersection = useCallback( (entries: IntersectionObserverEntry[]) => { @@ -65,7 +76,7 @@ export default function HotelCardDialogListing({ }, [activeCard]) return ( - <> +
{hotelsPinData?.length && hotelsPinData.map((data) => { const isActive = data.name === activeCard @@ -83,6 +94,6 @@ export default function HotelCardDialogListing({
) })} - + ) } diff --git a/components/HotelReservation/HotelCardListing/hotelCardListing.module.css b/components/HotelReservation/HotelCardListing/hotelCardListing.module.css index 00bd7ec84..5a5d0ea7e 100644 --- a/components/HotelReservation/HotelCardListing/hotelCardListing.module.css +++ b/components/HotelReservation/HotelCardListing/hotelCardListing.module.css @@ -3,4 +3,6 @@ flex-direction: column; gap: var(--Spacing-x2); margin-bottom: var(--Spacing-x2); + max-height: 100vh; + overflow-y: auto; } diff --git a/components/HotelReservation/HotelCardListing/index.tsx b/components/HotelReservation/HotelCardListing/index.tsx index f666c5ba2..d9d0b4f30 100644 --- a/components/HotelReservation/HotelCardListing/index.tsx +++ b/components/HotelReservation/HotelCardListing/index.tsx @@ -109,13 +109,17 @@ export default function HotelCardListing({
{hotels?.length ? ( hotels.map((hotel) => ( - + data-active={hotel.hotelData.name === activeCard ? "true" : "false"} + > + + )) ) : activeFilters ? ( div:first-child { - margin-left: 16px; -} - -.hotelListingMobile > div:last-child { - margin-right: 16px; -} - @media (min-width: 768px) { .hotelListing { display: block; diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx b/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx index 0d1d58eee..4208d4871 100644 --- a/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx @@ -1,7 +1,7 @@ "use client" import { APIProvider } from "@vis.gl/react-google-maps" import { useRouter, useSearchParams } from "next/navigation" -import { useEffect, useState } from "react" +import { useEffect, useRef, useState } from "react" import { useIntl } from "react-intl" import { useMediaQuery } from "usehooks-ts" @@ -35,6 +35,7 @@ export default function SelectHotelMap({ const isAboveMobile = useMediaQuery("(min-width: 768px)") const [activeHotelPin, setActiveHotelPin] = useState(null) const [showBackToTop, setShowBackToTop] = useState(false) + const listingContainerRef = useRef(null) const selectHotelParams = new URLSearchParams(searchParams.toString()) const selectedHotel = selectHotelParams.get("selectedHotel") @@ -43,6 +44,16 @@ export default function SelectHotelMap({ ? cityCoordinates : { ...cityCoordinates, lat: cityCoordinates.lat - 0.006 } + useEffect(() => { + if (listingContainerRef.current) { + const activeElement = + listingContainerRef.current.querySelector(`[data-active="true"]`) + if (activeElement) { + activeElement.scrollIntoView({ behavior: "smooth", block: "nearest" }) + } + } + }, [activeHotelPin]) + useEffect(() => { if (selectedHotel) { setActiveHotelPin(selectedHotel) @@ -90,7 +101,7 @@ export default function SelectHotelMap({ return (
-
+