Merged in feat/SW-1444-destination-page-add-destination-list-component (pull request #1240)

feat/SW-1444 destination page add destination list component

* feat(SW-1444): add list component

* feat(SW-1444): add subtitle to accordion

* feat(SW-1444): refactor component structure

* feat(SW-1444): add desktop breakpoint

* feat(SW-1444): fix typo

* feat(SW-1444): add props

* feat(SW-1444): add query

* feat(SW-1444): updated query

* feat(SW-1444): display data

* feat(SW-1444): fix merge hickup

* feat(SW-1444): change var name

* feat(SW-1444): remove unsued translations

* feat(SW-1444): use country as title

* feat(SW-1444): sort hotels in query

* feat(SW-1444): make responsive

* feat(SW-1444): fetch country url

* feat(SW-1444): update logging

* feat(SW-1444): remove spread


Approved-by: Erik Tiekstra
This commit is contained in:
Fredrik Thorsson
2025-02-04 14:17:12 +00:00
parent 4ed4b3585b
commit b85a3a57ec
27 changed files with 489 additions and 21 deletions

View File

@@ -0,0 +1,19 @@
.container {
display: grid;
gap: var(--Spacing-x3);
}
.citiesList {
column-count: 2;
list-style-type: none;
margin-bottom: var(--Spacing-x-half);
}
.citiesList li {
margin-bottom: var(--Spacing-x-one-and-half);
}
@media screen and (min-width: 1367px) {
.citiesList {
column-count: 3;
}
}

View File

@@ -0,0 +1,50 @@
import { ChevronRightSmallIcon } from "@/components/Icons"
import AccordionItem from "@/components/TempDesignSystem/Accordion/AccordionItem"
import Link from "@/components/TempDesignSystem/Link"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import styles from "./destination.module.css"
import type { DestinationProps } from "@/types/components/destinationOverviewPage/destinationsList/destinationsData"
export default async function Destination({
country,
countryUrl,
numberOfHotels,
cities,
}: DestinationProps) {
const intl = await getIntl()
const accordionSubtitle = intl.formatMessage(
{
id: "{amount, plural, one {# hotel} other {# hotels}}",
},
{ amount: numberOfHotels }
)
return (
<AccordionItem title={country} subtitle={accordionSubtitle}>
<div className={styles.container}>
<ul className={styles.citiesList}>
{cities.map((city) => (
<li key={city.id}>
<Link
href={city.url ? city.url : ""}
color="baseTextMediumContrast"
textDecoration="underline"
>
{`${city.name} (${city.hotelCount})`}
</Link>
</li>
))}
</ul>
{countryUrl && (
<Link href={countryUrl} variant="icon" color="burgundy" weight="bold">
{intl.formatMessage({ id: "See destination" })}
<ChevronRightSmallIcon color="burgundy" />
</Link>
)}
</div>
</AccordionItem>
)
}

View File

@@ -0,0 +1,27 @@
.listContainer {
display: flex;
flex-direction: column;
background-color: var(--Base-Surface-Primary-light-Normal);
border-radius: var(--Corner-radius-Medium);
}
.accordion {
flex: 1;
height: fit-content;
}
@media screen and (min-width: 768px) {
.listContainer {
gap: var(--Spacing-x3);
background-color: transparent;
flex-direction: row;
}
.accordion {
background-color: var(--Base-Surface-Primary-light-Normal);
}
.divider {
display: none;
}
}

View File

@@ -0,0 +1,44 @@
import Accordion from "@/components/TempDesignSystem/Accordion"
import Divider from "@/components/TempDesignSystem/Divider"
import Destination from "./Destination"
import styles from "./destinationsList.module.css"
import type { DestinationsListProps } from "@/types/components/destinationOverviewPage/destinationsList/destinationsData"
export default function DestinationsList({
destinations,
}: DestinationsListProps) {
const middleIndex = Math.ceil(destinations.length / 2)
const accordionLeft = destinations.slice(0, middleIndex)
const accordionRight = destinations.slice(middleIndex)
return (
<div className={styles.listContainer}>
<Accordion className={styles.accordion}>
{accordionLeft.map((data) => (
<Destination
key={data.country}
country={data.country}
countryUrl={data.countryUrl}
numberOfHotels={data.numberOfHotels}
cities={data.cities}
/>
))}
</Accordion>
<Divider color="subtle" className={styles.divider} />
<Accordion className={styles.accordion}>
{accordionRight.map((data) => (
<Destination
key={data.country}
country={data.country}
countryUrl={data.countryUrl}
numberOfHotels={data.numberOfHotels}
cities={data.cities}
/>
))}
</Accordion>
</div>
)
}

View File

@@ -0,0 +1,12 @@
.container {
display: grid;
gap: var(--Spacing-x4);
padding: var(--Spacing-x5) var(--Spacing-x2) var(--Spacing-x7);
}
@media screen and (min-width: 768px) {
.container {
gap: var(--Spacing-x7);
padding: var(--Spacing-x5) 9.625rem var(--Spacing-x9) 9.625rem;
}
}

View File

@@ -0,0 +1,23 @@
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import DestinationsList from "./DestinationsList"
import styles from "./hotelsSection.module.css"
import type { HotelsSectionProps } from "@/types/components/destinationOverviewPage/destinationsList/destinationsData"
export default async function HotelsSection({
destinations,
}: HotelsSectionProps) {
const intl = await getIntl()
return (
<section className={styles.container}>
<Title level="h4" as="h2" textAlign="center">
{intl.formatMessage({ id: "Explore all our hotels" })}
</Title>
<DestinationsList destinations={destinations} />
</section>
)
}

View File

@@ -1,6 +1,7 @@
.pageContainer {
position: relative;
display: grid;
width: 100%;
max-width: var(--max-width);
}

View File

@@ -1,16 +1,23 @@
import { Suspense } from "react"
import { env } from "@/env/server"
import { getDestinationOverviewPage } from "@/lib/trpc/memoizedRequests"
import {
getDestinationOverviewPage,
getDestinationsList,
} from "@/lib/trpc/memoizedRequests"
import TrackingSDK from "@/components/TrackingSDK"
import HotelsSection from "./HotelsSection"
import OverviewMapContainer from "./OverviewMapContainer"
import styles from "./destinationOverviewPage.module.css"
export default async function DestinationOverviewPage() {
const pageData = await getDestinationOverviewPage()
const [pageData, destinationsData] = await Promise.all([
getDestinationOverviewPage(),
getDestinationsList(),
])
if (!pageData) {
return null
@@ -27,7 +34,7 @@ export default async function DestinationOverviewPage() {
{googleMapsApiKey ? (
<OverviewMapContainer apiKey={googleMapsApiKey} mapId={googleMapId} />
) : null}
<h1>Destination Overview Page</h1>
{destinationsData && <HotelsSection destinations={destinationsData} />}
</div>
<Suspense fallback={null}>
<TrackingSDK pageData={tracking} />