feat(SW-344): set active pin on scroll
This commit is contained in:
@@ -1,22 +1,54 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useEffect, useRef } from "react"
|
import { useCallback, useEffect, useRef } from "react"
|
||||||
|
|
||||||
import HotelCardDialog from "../HotelCardDialog"
|
import HotelCardDialog from "../HotelCardDialog"
|
||||||
import { getHotelPins } from "./utils"
|
import { getHotelPins } from "./utils"
|
||||||
|
|
||||||
import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
import type { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
||||||
|
|
||||||
|
interface HotelCardDialogListingProps {
|
||||||
|
hotels: HotelData[]
|
||||||
|
activeCard: string | null | undefined
|
||||||
|
onActiveCardChange: (hotelName: string | null) => void
|
||||||
|
}
|
||||||
|
|
||||||
export default function HotelCardDialogListing({
|
export default function HotelCardDialogListing({
|
||||||
hotels,
|
hotels,
|
||||||
activeCard,
|
activeCard,
|
||||||
}: {
|
onActiveCardChange,
|
||||||
hotels: HotelData[]
|
}: HotelCardDialogListingProps) {
|
||||||
activeCard: string | null | undefined
|
|
||||||
}) {
|
|
||||||
const hotelsPinData = getHotelPins(hotels)
|
const hotelsPinData = getHotelPins(hotels)
|
||||||
const activeCardRef = useRef<HTMLDivElement | null>(null)
|
const activeCardRef = useRef<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
|
const handleIntersection = useCallback(
|
||||||
|
(entries: IntersectionObserverEntry[]) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
const cardName = entry.target.getAttribute("data-name")
|
||||||
|
if (cardName) {
|
||||||
|
onActiveCardChange(cardName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[onActiveCardChange]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const observer = new IntersectionObserver(handleIntersection, {
|
||||||
|
root: null,
|
||||||
|
threshold: 0.5, // Adjust threshold as needed
|
||||||
|
})
|
||||||
|
|
||||||
|
const elements = document.querySelectorAll("[data-name]")
|
||||||
|
elements.forEach((el) => observer.observe(el))
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
elements.forEach((el) => observer.unobserve(el))
|
||||||
|
}
|
||||||
|
}, [handleIntersection])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeCardRef.current) {
|
if (activeCardRef.current) {
|
||||||
activeCardRef.current.scrollIntoView({
|
activeCardRef.current.scrollIntoView({
|
||||||
@@ -33,7 +65,11 @@ export default function HotelCardDialogListing({
|
|||||||
hotelsPinData.map((data) => {
|
hotelsPinData.map((data) => {
|
||||||
const isActive = data.name === activeCard
|
const isActive = data.name === activeCard
|
||||||
return (
|
return (
|
||||||
<div key={data.name} ref={isActive ? activeCardRef : null}>
|
<div
|
||||||
|
key={data.name}
|
||||||
|
ref={isActive ? activeCardRef : null}
|
||||||
|
data-name={data.name}
|
||||||
|
>
|
||||||
<HotelCardDialog
|
<HotelCardDialog
|
||||||
data={data}
|
data={data}
|
||||||
isOpen={!!activeCard}
|
isOpen={!!activeCard}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import type { HotelListingProps } from "@/types/components/hotelReservation/sele
|
|||||||
export default function HotelListing({
|
export default function HotelListing({
|
||||||
hotels,
|
hotels,
|
||||||
activeHotelPin,
|
activeHotelPin,
|
||||||
onHotelCardHover,
|
setActiveHotelPin,
|
||||||
}: HotelListingProps) {
|
}: HotelListingProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -20,11 +20,15 @@ export default function HotelListing({
|
|||||||
hotelData={hotels}
|
hotelData={hotels}
|
||||||
type={HotelCardListingTypeEnum.MapListing}
|
type={HotelCardListingTypeEnum.MapListing}
|
||||||
activeCard={activeHotelPin}
|
activeCard={activeHotelPin}
|
||||||
onHotelCardHover={onHotelCardHover}
|
onHotelCardHover={setActiveHotelPin}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.hotelListingMobile} data-open={!!activeHotelPin}>
|
<div className={styles.hotelListingMobile} data-open={!!activeHotelPin}>
|
||||||
<HotelCardDialogListing hotels={hotels} activeCard={activeHotelPin} />
|
<HotelCardDialogListing
|
||||||
|
hotels={hotels}
|
||||||
|
activeCard={activeHotelPin}
|
||||||
|
onActiveCardChange={setActiveHotelPin}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default function SelectHotelMap({
|
|||||||
<HotelListing
|
<HotelListing
|
||||||
hotels={hotels}
|
hotels={hotels}
|
||||||
activeHotelPin={activeHotelPin}
|
activeHotelPin={activeHotelPin}
|
||||||
onHotelCardHover={setActiveHotelPin}
|
setActiveHotelPin={setActiveHotelPin}
|
||||||
/>
|
/>
|
||||||
{showBackToTop && (
|
{showBackToTop && (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import type { Coordinates } from "@/types/components/maps/coordinates"
|
|||||||
export interface HotelListingProps {
|
export interface HotelListingProps {
|
||||||
hotels: HotelData[]
|
hotels: HotelData[]
|
||||||
activeHotelPin?: string | null
|
activeHotelPin?: string | null
|
||||||
onHotelCardHover?: (hotelName: string | null) => void
|
setActiveHotelPin: (hotelName: string | null) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectHotelMapProps {
|
export interface SelectHotelMapProps {
|
||||||
|
|||||||
Reference in New Issue
Block a user