From b73421dbded21f02d1f28c934daeaf395d294c58 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 12 Nov 2024 09:19:11 +0100 Subject: [PATCH] feat(SW-344): Hotel list in mobile --- .../select-hotel/@modal/(.)map/page.tsx | 7 +-- .../(standard)/select-hotel/utils.ts | 19 -------- .../HotelCardDialog/index.tsx | 6 +-- .../HotelCardDialogListing/index.tsx | 47 +++++++++++++++++++ .../HotelCardDialogListing/utils.ts | 21 +++++++++ .../HotelListing/hotelListing.module.css | 36 ++++++++++++++ .../SelectHotelMap/HotelListing/index.tsx | 22 +++++---- .../hotelListingMapContent.module.css | 10 ++++ .../HotelListingMapContent/index.tsx | 23 ++++----- .../hotelReservation/selectHotel/map.ts | 2 +- 10 files changed, 146 insertions(+), 47 deletions(-) create mode 100644 components/HotelReservation/HotelCardDialogListing/index.tsx create mode 100644 components/HotelReservation/HotelCardDialogListing/utils.ts diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx index 0f636136f..6d8e62ed3 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx @@ -3,6 +3,7 @@ import { notFound } from "next/navigation" import { env } from "@/env/server" import { getLocations } from "@/lib/trpc/memoizedRequests" +import { getHotelPins } from "@/components/HotelReservation/HotelCardDialogListing/utils" import SelectHotelMap from "@/components/HotelReservation/SelectHotel/SelectHotelMap" import { generateChildrenString, @@ -11,11 +12,7 @@ import { import { MapModal } from "@/components/MapModal" import { setLang } from "@/i18n/serverContext" -import { - fetchAvailableHotels, - getCentralCoordinates, - getHotelPins, -} from "../../utils" +import { fetchAvailableHotels, getCentralCoordinates } from "../../utils" import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" import type { LangParams, PageArgs } from "@/types/params" diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts index ee541bb7a..5b5fc958e 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts @@ -88,25 +88,6 @@ export function getFiltersFromHotels(hotels: HotelData[]): CategorizedFilters { ) } -export function getHotelPins(hotels: HotelData[]): HotelPin[] { - return hotels.map((hotel) => ({ - coordinates: { - lat: hotel.hotelData.location.latitude, - lng: hotel.hotelData.location.longitude, - }, - name: hotel.hotelData.name, - publicPrice: hotel.price?.regularAmount ?? null, - memberPrice: hotel.price?.memberAmount ?? null, - currency: hotel.price?.currency || null, - images: [ - hotel.hotelData.hotelContent.images, - ...(hotel.hotelData.gallery?.heroImages ?? []), - ], - amenities: hotel.hotelData.detailedFacilities.slice(0, 3), - ratings: hotel.hotelData.ratings?.tripAdvisor.rating ?? null, - })) -} - export function getCentralCoordinates(hotels: HotelPin[]) { const centralCoordinates = hotels.reduce( (acc, pin) => { diff --git a/components/HotelReservation/HotelCardDialog/index.tsx b/components/HotelReservation/HotelCardDialog/index.tsx index adeb0e176..91ce9e548 100644 --- a/components/HotelReservation/HotelCardDialog/index.tsx +++ b/components/HotelReservation/HotelCardDialog/index.tsx @@ -17,13 +17,13 @@ import styles from "./hotelCardDialog.module.css" import type { HotelCardDialogProps } from "@/types/components/hotelReservation/selectHotel/map" export default function HotelCardDialog({ - pin, + data, isOpen, handleClose, }: HotelCardDialogProps) { const intl = useIntl() - if (!pin) { + if (!data) { return null } @@ -35,7 +35,7 @@ export default function HotelCardDialog({ amenities, images, ratings, - } = pin + } = data const firstImage = images[0]?.imageSizes?.small const altText = images[0]?.metaData?.altText diff --git a/components/HotelReservation/HotelCardDialogListing/index.tsx b/components/HotelReservation/HotelCardDialogListing/index.tsx new file mode 100644 index 000000000..1a2097ada --- /dev/null +++ b/components/HotelReservation/HotelCardDialogListing/index.tsx @@ -0,0 +1,47 @@ +"use client" + +import { useEffect, useRef } from "react" + +import HotelCardDialog from "../HotelCardDialog" +import { getHotelPins } from "./utils" + +import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps" + +export default function HotelCardDialogListing({ + hotels, + activeCard, +}: { + hotels: HotelData[] + activeCard: string | null | undefined +}) { + const hotelsPinData = getHotelPins(hotels) + const activeCardRef = useRef(null) + + useEffect(() => { + if (activeCardRef.current) { + activeCardRef.current.scrollIntoView({ + behavior: "smooth", + block: "nearest", + inline: "center", + }) + } + }, [activeCard]) + + return ( + <> + {hotelsPinData?.length && + hotelsPinData.map((data) => { + const isActive = data.name === activeCard + return ( +
+ {}} + /> +
+ ) + })} + + ) +} diff --git a/components/HotelReservation/HotelCardDialogListing/utils.ts b/components/HotelReservation/HotelCardDialogListing/utils.ts new file mode 100644 index 000000000..b63b9b7ce --- /dev/null +++ b/components/HotelReservation/HotelCardDialogListing/utils.ts @@ -0,0 +1,21 @@ +import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps" +import type { HotelPin } from "@/types/components/hotelReservation/selectHotel/map" + +export function getHotelPins(hotels: HotelData[]): HotelPin[] { + return hotels.map((hotel) => ({ + coordinates: { + lat: hotel.hotelData.location.latitude, + lng: hotel.hotelData.location.longitude, + }, + name: hotel.hotelData.name, + publicPrice: hotel.price?.regularAmount ?? null, + memberPrice: hotel.price?.memberAmount ?? null, + currency: hotel.price?.currency || null, + images: [ + hotel.hotelData.hotelContent.images, + ...(hotel.hotelData.gallery?.heroImages ?? []), + ], + amenities: hotel.hotelData.detailedFacilities.slice(0, 3), + ratings: hotel.hotelData.ratings?.tripAdvisor.rating ?? null, + })) +} diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/hotelListing.module.css b/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/hotelListing.module.css index 253df80d6..3ba5cf884 100644 --- a/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/hotelListing.module.css +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/hotelListing.module.css @@ -2,6 +2,37 @@ display: none; } +.hotelListingMobile { + display: none; + align-items: flex-end; + overflow-x: auto; + position: absolute; + bottom: 0px; + left: 0; + right: 0; + z-index: 10; + height: 350px; + gap: var(--Spacing-x1); +} + +.hotelListingMobile[data-open="true"] { + display: flex; +} + +.hotelListingMobile dialog { + position: relative; + padding: 0; + margin: 0; +} + +.hotelListingMobile > div:first-child { + margin-left: 16px; +} + +.hotelListingMobile > div:last-child { + margin-right: 16px; +} + @media (min-width: 768px) { .hotelListing { display: block; @@ -9,4 +40,9 @@ overflow-y: auto; padding-top: var(--Spacing-x2); } + + .hotelListingMobile, + .hotelListingMobile[data-open="true"] { + display: none; + } } diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx b/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx index 65bd476e6..7f237d62e 100644 --- a/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/HotelListing/index.tsx @@ -1,5 +1,6 @@ "use client" +import HotelCardDialogListing from "@/components/HotelReservation/HotelCardDialogListing" import HotelCardListing from "@/components/HotelReservation/HotelCardListing" import styles from "./hotelListing.module.css" @@ -13,13 +14,18 @@ export default function HotelListing({ onHotelCardHover, }: HotelListingProps) { return ( -
- -
+ <> +
+ +
+
+ +
+ ) } diff --git a/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css b/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css index 359edad50..dc35427cb 100644 --- a/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css +++ b/components/Maps/InteractiveMap/HotelListingMapContent/hotelListingMapContent.module.css @@ -8,6 +8,10 @@ min-width: 109px !important; /* Overwriting the default width of the @vis.gl/react-google-maps AdvancedMarker */ } +.dialogContainer { + display: none; +} + .pin { position: absolute; top: 0; @@ -67,3 +71,9 @@ .card.active { display: block; } + +@media (min-width: 768px) { + .dialogContainer { + display: block; + } +} diff --git a/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx b/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx index f121687ef..c3b83edb3 100644 --- a/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx +++ b/components/Maps/InteractiveMap/HotelListingMapContent/index.tsx @@ -50,17 +50,18 @@ export default function HotelListingMapContent({ ) } > - void }) => { - event.stopPropagation() - if (activeHotelPin === pin.name) { - toggleActiveHotelPin(null) - } - }} - pin={pin} - /> - +
+ void }) => { + event.stopPropagation() + if (activeHotelPin === pin.name) { + toggleActiveHotelPin(null) + } + }} + data={pin} + /> +
diff --git a/types/components/hotelReservation/selectHotel/map.ts b/types/components/hotelReservation/selectHotel/map.ts index 28965807a..64e13dad9 100644 --- a/types/components/hotelReservation/selectHotel/map.ts +++ b/types/components/hotelReservation/selectHotel/map.ts @@ -50,6 +50,6 @@ export interface HotelListingMapContentProps { export interface HotelCardDialogProps { isOpen: boolean - pin: HotelPin + data: HotelPin handleClose: (event: { stopPropagation: () => void }) => void }