Merged in feat/SW-2901-hotel-pins (pull request #2206)

feat(SW-2901): add dynamic hotel markers

* feat(SW-2901): add dynamic hotel markers

* fix(SW-2901): update type


Approved-by: Christian Andolf
Approved-by: Erik Tiekstra
This commit is contained in:
Matilda Landström
2025-05-26 13:56:03 +00:00
parent 7e17e9cf4c
commit cf6c794c59
12 changed files with 79 additions and 25 deletions

View File

@@ -57,7 +57,7 @@ export default function Marker({ position, properties }: MarkerProps) {
zIndex={isActive ? 300 : 0} zIndex={isActive ? 300 : 0}
> >
<HotelMarkerByType <HotelMarkerByType
smallSize={!isHovered && !isActive} size={isHovered || isActive ? "large" : "small"}
hotelId={properties.id} hotelId={properties.id}
hotelType={properties.type} hotelType={properties.type}
/> />

View File

@@ -21,6 +21,7 @@ import Sidebar from "./Sidebar"
import styles from "./hotelMapPage.module.css" import styles from "./hotelMapPage.module.css"
import type { Coordinates } from "@/types/components/maps/coordinates" import type { Coordinates } from "@/types/components/maps/coordinates"
import type { MarkerInfo } from "@/types/components/maps/marker"
import type { PointOfInterest } from "@/types/hotel" import type { PointOfInterest } from "@/types/hotel"
interface HotelMapPageClientProps { interface HotelMapPageClientProps {
@@ -29,11 +30,13 @@ interface HotelMapPageClientProps {
coordinates: Coordinates coordinates: Coordinates
pointsOfInterest: PointOfInterest[] pointsOfInterest: PointOfInterest[]
mapId: string mapId: string
markerInfo: MarkerInfo
} }
export default function HotelMapPageClient({ export default function HotelMapPageClient({
apiKey, apiKey,
hotelName, hotelName,
markerInfo,
coordinates, coordinates,
pointsOfInterest, pointsOfInterest,
mapId, mapId,
@@ -127,6 +130,7 @@ export default function HotelMapPageClient({
activePoi={activePoi} activePoi={activePoi}
onActivePoiChange={(poi) => setActivePoi(poi ?? null)} onActivePoiChange={(poi) => setActivePoi(poi ?? null)}
mapId={mapId} mapId={mapId}
markerInfo={markerInfo}
/> />
</div> </div>
</APIProvider> </APIProvider>

View File

@@ -24,7 +24,7 @@ export default async function HotelMapPage({ hotelId }: HotelMapPageProps) {
notFound() notFound()
} }
const { name, location, pointsOfInterest } = hotelData.hotel const { name, location, pointsOfInterest, hotelType } = hotelData.hotel
const coordinates = { const coordinates = {
lat: location.latitude, lat: location.latitude,
@@ -35,6 +35,7 @@ export default async function HotelMapPage({ hotelId }: HotelMapPageProps) {
apiKey={env.GOOGLE_STATIC_MAP_KEY} apiKey={env.GOOGLE_STATIC_MAP_KEY}
mapId={env.GOOGLE_DYNAMIC_MAP_ID} mapId={env.GOOGLE_DYNAMIC_MAP_ID}
hotelName={name} hotelName={name}
markerInfo={{ hotelId, hotelType }}
coordinates={coordinates} coordinates={coordinates}
pointsOfInterest={pointsOfInterest} pointsOfInterest={pointsOfInterest}
/> />

View File

@@ -2,7 +2,7 @@
import { env } from "@/env/server" import { env } from "@/env/server"
import ScandicMarker from "@/components/Maps/Markers/Scandic" import HotelMarkerByType from "@/components/Maps/Markers"
import StaticMapComp from "@/components/Maps/StaticMap" import StaticMapComp from "@/components/Maps/StaticMap"
import { getIntl } from "@/i18n" import { getIntl } from "@/i18n"
import { calculateLatWithOffset } from "@/utils/map" import { calculateLatWithOffset } from "@/utils/map"
@@ -14,6 +14,7 @@ import type { StaticMapProps } from "@/types/components/hotelPage/map/staticMap"
export default async function StaticMap({ export default async function StaticMap({
coordinates, coordinates,
hotelName, hotelName,
markerInfo,
zoomLevel = 14, zoomLevel = 14,
}: StaticMapProps) { }: StaticMapProps) {
const intl = await getIntl() const intl = await getIntl()
@@ -41,7 +42,9 @@ export default async function StaticMap({
)} )}
mapId={mapId} mapId={mapId}
/> />
<ScandicMarker <HotelMarkerByType
hotelId={markerInfo.hotelId}
hotelType={markerInfo.hotelType}
className={styles.mapMarker} className={styles.mapMarker}
height={markerHeight} height={markerHeight}
style={{ top: `${mapLatitudeInPx - markerHeight}px` }} style={{ top: `${mapLatitudeInPx - markerHeight}px` }}

View File

@@ -200,7 +200,11 @@ export default async function HotelPage({ hotelId }: HotelPageProps) {
</main> </main>
<aside className={styles.mapContainer}> <aside className={styles.mapContainer}>
<MapWithCardWrapper> <MapWithCardWrapper>
<StaticMap coordinates={coordinates} hotelName={name} /> <StaticMap
coordinates={coordinates}
hotelName={name}
markerInfo={{ hotelType, hotelId }}
/>
<MapCard hotelName={name} pois={topThreePois} /> <MapCard hotelName={name} pois={topThreePois} />
</MapWithCardWrapper> </MapWithCardWrapper>
</aside> </aside>

View File

@@ -7,8 +7,8 @@ import { useIntl } from "react-intl"
import Body from "@/components/TempDesignSystem/Text/Body" import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption" import Caption from "@/components/TempDesignSystem/Text/Caption"
import HotelMarkerByType from "../../Markers"
import PoiMarker from "../../Markers/Poi" import PoiMarker from "../../Markers/Poi"
import ScandicMarker from "../../Markers/Scandic"
import styles from "./poiMapMarkers.module.css" import styles from "./poiMapMarkers.module.css"
@@ -19,6 +19,7 @@ export default function PoiMapMarkers({
pointsOfInterest, pointsOfInterest,
onActivePoiChange, onActivePoiChange,
activePoi, activePoi,
markerInfo,
}: PoiMapMarkersProps) { }: PoiMapMarkersProps) {
const intl = useIntl() const intl = useIntl()
@@ -28,7 +29,10 @@ export default function PoiMapMarkers({
return ( return (
<> <>
<AdvancedMarker position={coordinates} zIndex={1}> <AdvancedMarker position={coordinates} zIndex={1}>
<ScandicMarker /> <HotelMarkerByType
hotelId={markerInfo.hotelId}
hotelType={markerInfo.hotelType}
/>
</AdvancedMarker> </AdvancedMarker>
{pointsOfInterest.map((poi) => ( {pointsOfInterest.map((poi) => (

View File

@@ -22,6 +22,7 @@ export default function InteractiveMap({
hotelPins, hotelPins,
mapId, mapId,
closeButton, closeButton,
markerInfo,
fitBounds = true, fitBounds = true,
onTilesLoaded, onTilesLoaded,
onActivePoiChange, onActivePoiChange,
@@ -67,12 +68,13 @@ export default function InteractiveMap({
<div className={styles.mapContainer}> <div className={styles.mapContainer}>
<Map {...mapOptions} onTilesLoaded={onTilesLoaded}> <Map {...mapOptions} onTilesLoaded={onTilesLoaded}>
{hotelPins && <HotelListingMapContent hotelPins={hotelPins} />} {hotelPins && <HotelListingMapContent hotelPins={hotelPins} />}
{pointsOfInterest && ( {pointsOfInterest && markerInfo && (
<PoiMapMarkers <PoiMapMarkers
coordinates={coordinates} coordinates={coordinates}
pointsOfInterest={pointsOfInterest} pointsOfInterest={pointsOfInterest}
onActivePoiChange={onActivePoiChange} onActivePoiChange={onActivePoiChange}
activePoi={activePoi} activePoi={activePoi}
markerInfo={markerInfo}
/> />
)} )}
</Map> </Map>

View File

@@ -13,40 +13,66 @@ import ScandicGoMarker from "./ScandicGo"
import ScandicGoSmallMarker from "./ScandicGoSmall" import ScandicGoSmallMarker from "./ScandicGoSmall"
import ScandicSmallMarker from "./ScandicSmall" import ScandicSmallMarker from "./ScandicSmall"
import type { MarkerInfo } from "@/types/components/maps/marker"
import { HotelTypeEnum } from "@/types/enums/hotelType" import { HotelTypeEnum } from "@/types/enums/hotelType"
import { SignatureHotelEnum } from "@/types/enums/signatureHotel" import { SignatureHotelEnum } from "@/types/enums/signatureHotel"
interface HotelMarkerByTypeProps { interface HotelMarkerByTypeProps
hotelId: string extends MarkerInfo,
hotelType: string React.SVGAttributes<HTMLOrSVGElement> {
smallSize?: boolean size?: "large" | "small"
} }
export default function HotelMarkerByType({ export default function HotelMarkerByType({
hotelId, hotelId,
hotelType, hotelType,
smallSize = true, size = "large",
...props
}: HotelMarkerByTypeProps) { }: HotelMarkerByTypeProps) {
if (hotelType === HotelTypeEnum.ScandicGo) { if (hotelType === HotelTypeEnum.ScandicGo) {
return smallSize ? <ScandicGoSmallMarker /> : <ScandicGoMarker /> return size === "small" ? (
<ScandicGoSmallMarker {...props} />
) : (
<ScandicGoMarker {...props} />
)
} }
switch (hotelId) { switch (hotelId) {
case SignatureHotelEnum.Haymarket: case SignatureHotelEnum.Haymarket:
return smallSize ? <HaymarketSmallMarker /> : <HaymarketMarker /> return size === "small" ? (
case SignatureHotelEnum.HotelNorge: <HaymarketSmallMarker {...props} />
return smallSize ? <HotelNorgeSmallMarker /> : <HotelNorgeMarker />
case SignatureHotelEnum.DowntownCamper:
return smallSize ? (
<DowntownCamperSmallMarker />
) : ( ) : (
<DowntownCamperMarker /> <HaymarketMarker {...props} />
)
case SignatureHotelEnum.HotelNorge:
return size === "small" ? (
<HotelNorgeSmallMarker {...props} />
) : (
<HotelNorgeMarker {...props} />
)
case SignatureHotelEnum.DowntownCamper:
return size === "small" ? (
<DowntownCamperSmallMarker {...props} />
) : (
<DowntownCamperMarker {...props} />
) )
case SignatureHotelEnum.GrandHotelOslo: case SignatureHotelEnum.GrandHotelOslo:
return smallSize ? <GrandHotelSmallMarker /> : <GrandHotelMarker /> return size === "small" ? (
<GrandHotelSmallMarker {...props} />
) : (
<GrandHotelMarker {...props} />
)
case SignatureHotelEnum.Marski: case SignatureHotelEnum.Marski:
return smallSize ? <MarskiSmallMarker /> : <MarskiMarker /> return size === "small" ? (
<MarskiSmallMarker {...props} />
) : (
<MarskiMarker {...props} />
)
default: default:
return smallSize ? <ScandicSmallMarker /> : <ScandicMarker /> return size === "small" ? (
<ScandicSmallMarker {...props} />
) : (
<ScandicMarker {...props} />
)
} }
} }

View File

@@ -2,13 +2,15 @@ import type { ReactElement } from "react"
import type { HotelPin } from "@/types/components/hotelReservation/selectHotel/map" import type { HotelPin } from "@/types/components/hotelReservation/selectHotel/map"
import type { Coordinates } from "@/types/components/maps/coordinates" import type { Coordinates } from "@/types/components/maps/coordinates"
import type { MarkerInfo } from "@/types/components/maps/marker"
import type { PointOfInterest } from "@/types/hotel" import type { PointOfInterest } from "@/types/hotel"
export interface InteractiveMapProps { export interface InteractiveMapProps {
coordinates: Coordinates coordinates: Coordinates
pointsOfInterest?: PointOfInterest[]
activePoi?: PointOfInterest["name"] | null activePoi?: PointOfInterest["name"] | null
hotelPins?: HotelPin[] hotelPins?: HotelPin[]
pointsOfInterest?: PointOfInterest[]
markerInfo?: MarkerInfo
mapId: string mapId: string
closeButton: ReactElement closeButton: ReactElement
fitBounds?: boolean fitBounds?: boolean

View File

@@ -1,7 +1,9 @@
import type { MarkerInfo } from "@/types/components/maps/marker"
import type { Coordinates } from "../../maps/coordinates" import type { Coordinates } from "../../maps/coordinates"
export type StaticMapProps = { export type StaticMapProps = {
coordinates: Coordinates coordinates: Coordinates
hotelName: string hotelName: string
zoomLevel?: number zoomLevel?: number
markerInfo: MarkerInfo
} }

View File

@@ -0,0 +1,4 @@
export type MarkerInfo = {
hotelId: string
hotelType: string
}

View File

@@ -1,5 +1,6 @@
import type { z } from "zod" import type { z } from "zod"
import type { MarkerInfo } from "@/types/components/maps/marker"
import type { import type {
destinationPagesHotelDataSchema, destinationPagesHotelDataSchema,
hotelSchema, hotelSchema,
@@ -70,6 +71,7 @@ export type PoiMapMarkersProps = {
coordinates: { lat: number; lng: number } coordinates: { lat: number; lng: number }
onActivePoiChange?: (poiName: string | null) => void onActivePoiChange?: (poiName: string | null) => void
pointsOfInterest: PointOfInterest[] pointsOfInterest: PointOfInterest[]
markerInfo: MarkerInfo
} }
export type HotelTripAdvisor = export type HotelTripAdvisor =
| NonNullable<HotelRatings>["tripAdvisor"] | NonNullable<HotelRatings>["tripAdvisor"]