Merged in feat/SW-1459-country-map-sidebar (pull request #1323)

feat(SW-1459): Added sidebar with citylist on destination country pages

* feat(SW-1459): Added sidebar with citylist on destination country pages


Approved-by: Fredrik Thorsson
Approved-by: Matilda Landström
This commit is contained in:
Erik Tiekstra
2025-02-13 06:45:27 +00:00
parent c0e4553d9f
commit 599c11ba37
12 changed files with 158 additions and 10 deletions

View File

@@ -0,0 +1,17 @@
.cityListWrapper {
display: grid;
gap: var(--Spacing-x3);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--Spacing-x2);
}
.cityList {
display: grid;
gap: var(--Spacing-x3);
list-style: none;
}

View File

@@ -0,0 +1,36 @@
import Body from "@/components/TempDesignSystem/Text/Body"
import { getIntl } from "@/i18n"
import CityListItem from "../CityListItem"
import styles from "./cityList.module.css"
import type { DestinationCityListItem } from "@/types/trpc/routers/contentstack/destinationCityPage"
interface CityListProps {
cities: DestinationCityListItem[]
}
export default async function CityList({ cities }: CityListProps) {
const intl = await getIntl()
return (
<div className={styles.cityListWrapper}>
<div className={styles.header}>
<Body>
{intl.formatMessage(
{ id: "{count} destinations" },
{ count: cities.length }
)}
</Body>
</div>
<ul className={styles.cityList}>
{cities.map((city) => (
<li key={city.system.uid}>
<CityListItem city={city} />
</li>
))}
</ul>
</div>
)
}

View File

@@ -0,0 +1,22 @@
.cityListItem {
background-color: var(--Base-Surface-Primary-light-Normal);
border: 1px solid var(--Base-Border-Subtle);
border-radius: var(--Corner-radius-Medium);
overflow: hidden;
}
.imageWrapper {
position: relative;
height: 200px;
width: 100%;
}
.imageWrapper img {
object-fit: cover;
}
.content {
display: grid;
gap: var(--Spacing-x2);
padding: var(--Spacing-x2) var(--Spacing-x3);
}

View File

@@ -0,0 +1,51 @@
import Link from "next/link"
import ImageGallery from "@/components/ImageGallery"
import Button from "@/components/TempDesignSystem/Button"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { getIntl } from "@/i18n"
import { mapImageVaultImagesToGalleryImages } from "@/utils/imageGallery"
import ExperienceList from "../../../ExperienceList"
import styles from "./cityListItem.module.css"
import type { DestinationCityListItem } from "@/types/trpc/routers/contentstack/destinationCityPage"
interface CityListItemProps {
city: DestinationCityListItem
}
export default async function CityListItem({ city }: CityListItemProps) {
const intl = await getIntl()
const galleryImages = mapImageVaultImagesToGalleryImages(city.images)
return (
<article className={styles.cityListItem}>
<div className={styles.imageWrapper}>
<ImageGallery
images={galleryImages}
fill
title={intl.formatMessage(
{ id: "{title} - Image gallery" },
{ title: city.cityName }
)}
/>
</div>
<section className={styles.content}>
<Subtitle asChild>
<h3>{city.heading}</h3>
</Subtitle>
<ExperienceList experiences={city.experiences} />
<Button intent="tertiary" theme="base" size="small" asChild>
<Link href={city.url}>
{intl.formatMessage(
{ id: "Explore {city}" },
{ city: city.cityName }
)}
</Link>
</Button>
</section>
</article>
)
}

View File

@@ -1,20 +1,31 @@
import { env } from "@/env/server"
import { getHotelsByCountry } from "@/lib/trpc/memoizedRequests"
import {
getDestinationCityPagesByCountry,
getHotelsByCountry,
} from "@/lib/trpc/memoizedRequests"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import Map from "../../Map"
import CityList from "./CityList"
import type { Country } from "@/types/enums/country"
interface CountryMapProps {
country: Country
}
export function preloadHotels(country: Country) {
export function preload(country: Country) {
void getHotelsByCountry(country)
void getDestinationCityPagesByCountry(country)
}
export default async function CountryMap({ country }: CountryMapProps) {
const hotels = await getHotelsByCountry(country)
const intl = await getIntl()
const [hotels, cities] = await Promise.all([
getHotelsByCountry(country),
getDestinationCityPagesByCountry(country),
])
return (
<Map
@@ -22,11 +33,10 @@ export default async function CountryMap({ country }: CountryMapProps) {
mapId={env.GOOGLE_DYNAMIC_MAP_ID}
apiKey={env.GOOGLE_STATIC_MAP_KEY}
>
<div>
<Title level="h2" as="h3">
{country}
</Title>
</div>
<Title level="h2" as="h3" textTransform="regular">
{intl.formatMessage({ id: `Destinations in {country}` }, { country })}
</Title>
<CityList cities={cities} />
</Map>
)
}

View File

@@ -16,7 +16,7 @@ import SidebarContentWrapper from "../SidebarContentWrapper"
import DestinationPageSidePeek from "../Sidepeek"
import StaticMap from "../StaticMap"
import TopImages from "../TopImages"
import CountryMap, { preloadHotels } from "./CountryMap"
import CountryMap, { preload } from "./CountryMap"
import styles from "./destinationCountryPage.module.css"
@@ -42,7 +42,7 @@ export default async function DestinationCountryPage() {
destination_settings,
} = destinationCountryPage
preloadHotels(destination_settings.country)
preload(destination_settings.country)
return (
<>