From 87b999676b928e341abc51e43c83ae192a7cf6e0 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 12 Nov 2024 14:33:37 +0100 Subject: [PATCH] feat(SW-344) Correct position of pins in mobile --- .../select-hotel/@modal/(.)map/page.tsx | 6 +--- .../(standard)/select-hotel/utils.ts | 16 ---------- .../Header/MainMenu/MobileMenu/index.tsx | 2 +- .../MainMenu/MyPagesMobileMenu/index.tsx | 2 +- .../HotelCard/hotelCard.module.css | 12 ++++++++ .../HotelReservation/HotelCard/index.tsx | 16 +++++++++- .../HotelCardDialogListing/index.tsx | 29 +++++++++++-------- .../SelectHotel/SelectHotelMap/index.tsx | 28 +++++++++++++----- .../SelectHotel/SelectHotelMap/utils.ts | 17 +++++++++++ hooks/useMediaQuery.ts | 21 -------------- package-lock.json | 16 +++++++++- package.json | 1 + .../hotelReservation/selectHotel/map.ts | 8 +++-- 13 files changed, 106 insertions(+), 68 deletions(-) create mode 100644 components/HotelReservation/SelectHotel/SelectHotelMap/utils.ts delete mode 100644 hooks/useMediaQuery.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 6d8e62ed3..fd9cc33c5 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 @@ -12,7 +12,7 @@ import { import { MapModal } from "@/components/MapModal" import { setLang } from "@/i18n/serverContext" -import { fetchAvailableHotels, getCentralCoordinates } from "../../utils" +import { fetchAvailableHotels } from "../../utils" import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" import type { LangParams, PageArgs } from "@/types/params" @@ -58,16 +58,12 @@ export default async function SelectHotelMapPage({ const hotelPins = getHotelPins(hotels) - const centralCoordinates = getCentralCoordinates(hotelPins) - return ( 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 5b5fc958e..a021d9355 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts @@ -87,19 +87,3 @@ export function getFiltersFromHotels(hotels: HotelData[]): CategorizedFilters { { facilityFilters: [], surroundingsFilters: [] } ) } - -export function getCentralCoordinates(hotels: HotelPin[]) { - const centralCoordinates = hotels.reduce( - (acc, pin) => { - acc.lat += pin.coordinates.lat - acc.lng += pin.coordinates.lng - return acc - }, - { lat: 0, lng: 0 } - ) - - centralCoordinates.lat /= hotels.length - centralCoordinates.lng /= hotels.length - - return centralCoordinates -} diff --git a/components/Header/MainMenu/MobileMenu/index.tsx b/components/Header/MainMenu/MobileMenu/index.tsx index ae79675dd..272c4b231 100644 --- a/components/Header/MainMenu/MobileMenu/index.tsx +++ b/components/Header/MainMenu/MobileMenu/index.tsx @@ -3,13 +3,13 @@ import { Suspense, useEffect } from "react" import { Dialog, Modal } from "react-aria-components" import { useIntl } from "react-intl" +import { useMediaQuery } from "usehooks-ts" import useDropdownStore from "@/stores/main-menu" import { GiftIcon, SearchIcon, ServiceIcon } from "@/components/Icons" import LanguageSwitcher from "@/components/LanguageSwitcher" import { useHandleKeyUp } from "@/hooks/useHandleKeyUp" -import useMediaQuery from "@/hooks/useMediaQuery" import HeaderLink from "../../HeaderLink" diff --git a/components/Header/MainMenu/MyPagesMobileMenu/index.tsx b/components/Header/MainMenu/MyPagesMobileMenu/index.tsx index 466014bd2..e0711fe5c 100644 --- a/components/Header/MainMenu/MyPagesMobileMenu/index.tsx +++ b/components/Header/MainMenu/MyPagesMobileMenu/index.tsx @@ -3,11 +3,11 @@ import { useEffect } from "react" import { Dialog, Modal } from "react-aria-components" import { useIntl } from "react-intl" +import { useMediaQuery } from "usehooks-ts" import useDropdownStore from "@/stores/main-menu" import { useHandleKeyUp } from "@/hooks/useHandleKeyUp" -import useMediaQuery from "@/hooks/useMediaQuery" import { getInitials } from "@/utils/user" import Avatar from "../Avatar" diff --git a/components/HotelReservation/HotelCard/hotelCard.module.css b/components/HotelReservation/HotelCard/hotelCard.module.css index 95ea52ad2..a5d90de17 100644 --- a/components/HotelReservation/HotelCard/hotelCard.module.css +++ b/components/HotelReservation/HotelCard/hotelCard.module.css @@ -70,6 +70,10 @@ justify-content: center; } +.address { + display: none; +} + @media screen and (min-width: 1367px) { .card.pageListing { grid-template-areas: @@ -118,4 +122,12 @@ .pageListing .button { width: 160px; } + + .address { + display: block; + } + + .addressMobile { + display: none; + } } diff --git a/components/HotelReservation/HotelCard/index.tsx b/components/HotelReservation/HotelCard/index.tsx index d36ce0205..f72945b6d 100644 --- a/components/HotelReservation/HotelCard/index.tsx +++ b/components/HotelReservation/HotelCard/index.tsx @@ -1,6 +1,9 @@ "use client" +import { useParams } from "next/dist/client/components/navigation" import { useIntl } from "react-intl" +import { selectHotelMap } from "@/constants/routes/hotelReservation" + import { mapFacilityToIcon } from "@/components/ContentType/HotelPage/data" import { PriceTagIcon, ScandicLogoIcon } from "@/components/Icons" import TripAdvisorIcon from "@/components/Icons/TripAdvisor" @@ -26,6 +29,7 @@ export default function HotelCard({ state = "default", onHotelCardHover, }: HotelCardProps) { + const params = useParams() const intl = useIntl() const { hotelData } = hotel @@ -77,9 +81,19 @@ export default function HotelCard({ {hotelData.name} - + {`${hotelData.address.streetAddress}, ${hotelData.address.city}`} + + + {`${hotelData.address.streetAddress}, ${hotelData.address.city}`} + + {`${hotelData.location.distanceToCentre} ${intl.formatMessage({ id: "km to city center" })}`} diff --git a/components/HotelReservation/HotelCardDialogListing/index.tsx b/components/HotelReservation/HotelCardDialogListing/index.tsx index a91f68041..fe75c9b33 100644 --- a/components/HotelReservation/HotelCardDialogListing/index.tsx +++ b/components/HotelReservation/HotelCardDialogListing/index.tsx @@ -5,13 +5,7 @@ import { useCallback, useEffect, useRef } from "react" import HotelCardDialog from "../HotelCardDialog" import { getHotelPins } from "./utils" -import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps" - -interface HotelCardDialogListingProps { - hotels: HotelData[] - activeCard: string | null | undefined - onActiveCardChange: (hotelName: string | null) => void -} +import type { HotelCardDialogListingProps } from "@/types/components/hotelReservation/selectHotel/map" export default function HotelCardDialogListing({ hotels, @@ -20,6 +14,7 @@ export default function HotelCardDialogListing({ }: HotelCardDialogListingProps) { const hotelsPinData = getHotelPins(hotels) const activeCardRef = useRef(null) + const observerRef = useRef(null) const handleIntersection = useCallback( (entries: IntersectionObserverEntry[]) => { @@ -36,26 +31,36 @@ export default function HotelCardDialogListing({ ) useEffect(() => { - const observer = new IntersectionObserver(handleIntersection, { + observerRef.current = new IntersectionObserver(handleIntersection, { root: null, - threshold: 0.5, // Adjust threshold as needed + threshold: 0.5, }) const elements = document.querySelectorAll("[data-name]") - elements.forEach((el) => observer.observe(el)) + elements.forEach((el) => observerRef.current?.observe(el)) return () => { - elements.forEach((el) => observer.unobserve(el)) + elements.forEach((el) => observerRef.current?.unobserve(el)) + observerRef.current?.disconnect() } }, [handleIntersection]) useEffect(() => { if (activeCardRef.current) { + // Temporarily disconnect the observer + observerRef.current?.disconnect() + activeCardRef.current.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center", }) + + // Reconnect the observer after scrolling + const elements = document.querySelectorAll("[data-name]") + setTimeout(() => { + elements.forEach((el) => observerRef.current?.observe(el)) + }, 500) } }, [activeCard]) @@ -73,7 +78,7 @@ export default function HotelCardDialogListing({ {}} + handleClose={() => onActiveCardChange(null)} /> ) diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx b/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx index f92ec1895..21b804306 100644 --- a/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/index.tsx @@ -3,6 +3,7 @@ import { APIProvider } from "@vis.gl/react-google-maps" import { useRouter, useSearchParams } from "next/navigation" import { useEffect, useState } from "react" import { useIntl } from "react-intl" +import { useMediaQuery } from "usehooks-ts" import { selectHotel } from "@/constants/routes/hotelReservation" @@ -12,6 +13,7 @@ import Button from "@/components/TempDesignSystem/Button" import useLang from "@/hooks/useLang" import HotelListing from "./HotelListing" +import { getCentralCoordinates } from "./utils" import styles from "./selectHotelMap.module.css" @@ -19,19 +21,33 @@ import { SelectHotelMapProps } from "@/types/components/hotelReservation/selectH export default function SelectHotelMap({ apiKey, - coordinates, hotelPins, mapId, - isModal, hotels, }: SelectHotelMapProps) { const searchParams = useSearchParams() const router = useRouter() const lang = useLang() const intl = useIntl() + const isAboveMobile = useMediaQuery("(min-width: 768px)") const [activeHotelPin, setActiveHotelPin] = useState(null) const [showBackToTop, setShowBackToTop] = useState(false) + const centralCoordinates = getCentralCoordinates(hotelPins) + + const coordinates = isAboveMobile + ? centralCoordinates + : { ...centralCoordinates, lat: centralCoordinates.lat - 0.006 } + + const selectHotelParams = new URLSearchParams(searchParams.toString()) + const selectedHotel = selectHotelParams.get("selectedHotel") + + useEffect(() => { + if (selectedHotel) { + setActiveHotelPin(selectedHotel) + } + }, [selectedHotel]) + useEffect(() => { const hotelListingElement = document.querySelector( `.${styles.listingContainer}` @@ -54,10 +70,6 @@ export default function SelectHotelMap({ hotelListingElement?.scrollTo({ top: 0, behavior: "smooth" }) } - function handleModalDismiss() { - router.back() - } - function handlePageRedirect() { router.push(`${selectHotel[lang]}?${searchParams.toString()}`) } @@ -68,7 +80,7 @@ export default function SelectHotelMap({ size="small" theme="base" className={styles.closeButton} - onClick={isModal ? handleModalDismiss : handlePageRedirect} + onClick={handlePageRedirect} > {intl.formatMessage({ id: "Close the map" })} @@ -84,7 +96,7 @@ export default function SelectHotelMap({ size="small" variant="icon" wrapping - onClick={isModal ? handleModalDismiss : handlePageRedirect} + onClick={handlePageRedirect} className={styles.filterContainerCloseButton} > diff --git a/components/HotelReservation/SelectHotel/SelectHotelMap/utils.ts b/components/HotelReservation/SelectHotel/SelectHotelMap/utils.ts new file mode 100644 index 000000000..7a4c32ecc --- /dev/null +++ b/components/HotelReservation/SelectHotel/SelectHotelMap/utils.ts @@ -0,0 +1,17 @@ +import { HotelPin } from "@/types/components/hotelReservation/selectHotel/map" + +export function getCentralCoordinates(hotels: HotelPin[]) { + const centralCoordinates = hotels.reduce( + (acc, pin) => { + acc.lat += pin.coordinates.lat + acc.lng += pin.coordinates.lng + return acc + }, + { lat: 0, lng: 0 } + ) + + centralCoordinates.lat /= hotels.length + centralCoordinates.lng /= hotels.length + + return centralCoordinates +} diff --git a/hooks/useMediaQuery.ts b/hooks/useMediaQuery.ts deleted file mode 100644 index bbb9eabac..000000000 --- a/hooks/useMediaQuery.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect, useState } from "react" - -function useMediaQuery(query: string) { - const [isMatch, setIsMatch] = useState(false) - - useEffect(() => { - const media = window.matchMedia(query) - if (media.matches !== isMatch) { - setIsMatch(media.matches) - } - - const listener = () => setIsMatch(media.matches) - media.addEventListener("change", listener) - - return () => media.removeEventListener("change", listener) - }, [isMatch, query]) - - return isMatch -} - -export default useMediaQuery diff --git a/package-lock.json b/package-lock.json index 766d5cb95..a2d63c0f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,6 +53,7 @@ "server-only": "^0.0.1", "sonner": "^1.5.0", "superjson": "^2.2.1", + "usehooks-ts": "3.1.0", "zod": "^3.22.4", "zustand": "^4.5.2" }, @@ -14703,7 +14704,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, "license": "MIT" }, "node_modules/lodash.isempty": { @@ -19454,6 +19454,20 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/usehooks-ts": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.0.tgz", + "integrity": "sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==", + "dependencies": { + "lodash.debounce": "^4.0.8" + }, + "engines": { + "node": ">=16.15.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index fa08f8495..4afcb9bf1 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "server-only": "^0.0.1", "sonner": "^1.5.0", "superjson": "^2.2.1", + "usehooks-ts": "3.1.0", "zod": "^3.22.4", "zustand": "^4.5.2" }, diff --git a/types/components/hotelReservation/selectHotel/map.ts b/types/components/hotelReservation/selectHotel/map.ts index b913be9b1..12d51e292 100644 --- a/types/components/hotelReservation/selectHotel/map.ts +++ b/types/components/hotelReservation/selectHotel/map.ts @@ -18,10 +18,8 @@ export interface HotelListingProps { export interface SelectHotelMapProps { apiKey: string - coordinates: Coordinates hotelPins: HotelPin[] mapId: string - isModal: boolean hotels: HotelData[] } @@ -53,3 +51,9 @@ export interface HotelCardDialogProps { data: HotelPin handleClose: (event: { stopPropagation: () => void }) => void } + +export interface HotelCardDialogListingProps { + hotels: HotelData[] + activeCard: string | null | undefined + onActiveCardChange: (hotelName: string | null) => void +}