feat(SW-2278): Added hotel listing to campaign page
Approved-by: Matilda Landström
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"use client"
|
||||
|
||||
import { cx } from "class-variance-authority"
|
||||
import { useRef, useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
import { useMediaQuery } from "usehooks-ts"
|
||||
|
||||
import { Button } from "@scandic-hotels/design-system/Button"
|
||||
import {
|
||||
MaterialIcon,
|
||||
type MaterialIconProps,
|
||||
} from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import HotelListingItem from "./HotelListingItem"
|
||||
|
||||
import styles from "./campaignHotelListing.module.css"
|
||||
|
||||
import type { HotelDataWithUrl } from "@/types/hotel"
|
||||
|
||||
interface CampaignHotelListingClientProps {
|
||||
heading: string
|
||||
hotels: HotelDataWithUrl[]
|
||||
}
|
||||
|
||||
export default function CampaignHotelListingClient({
|
||||
heading,
|
||||
hotels,
|
||||
}: CampaignHotelListingClientProps) {
|
||||
const intl = useIntl()
|
||||
const isMobile = useMediaQuery("(max-width: 767px)")
|
||||
const scrollRef = useRef<HTMLElement>(null)
|
||||
|
||||
const initialCount = isMobile ? 3 : 6 // Initial number of hotels to show
|
||||
const thresholdCount = isMobile ? 6 : 9 // This is the threshold at which we start showing the "Show More" button
|
||||
const showAllThreshold = isMobile ? 9 : 18 // This is the threshold at which we show the "Show All" button
|
||||
const incrementCount = isMobile ? 3 : 6 // Number of hotels to increment when the button is clicked
|
||||
|
||||
const [visibleCount, setVisibleCount] = useState(() =>
|
||||
// Set initial visible count based on the number of hotels and the threshold
|
||||
hotels.length <= thresholdCount ? hotels.length : initialCount
|
||||
)
|
||||
|
||||
// Only show the show more/less button if the length of hotels exceeds the threshold count
|
||||
const showButton = hotels.length >= thresholdCount
|
||||
|
||||
// Determine if we are at the stage where the user can click to show all hotels
|
||||
const canShowAll =
|
||||
hotels.length > visibleCount &&
|
||||
(visibleCount + incrementCount > showAllThreshold ||
|
||||
visibleCount + incrementCount >= hotels.length)
|
||||
|
||||
function handleButtonClick() {
|
||||
if (visibleCount < hotels.length) {
|
||||
if (canShowAll) {
|
||||
setVisibleCount(hotels.length)
|
||||
} else {
|
||||
setVisibleCount((prev) =>
|
||||
Math.min(prev + incrementCount, hotels.length)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
setVisibleCount(initialCount)
|
||||
if (scrollRef.current) {
|
||||
scrollRef.current.scrollIntoView({ behavior: "smooth" })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let buttonText = intl.formatMessage({
|
||||
defaultMessage: "Show more",
|
||||
})
|
||||
let iconDirection: MaterialIconProps["icon"] = "keyboard_arrow_down"
|
||||
|
||||
if (visibleCount === hotels.length) {
|
||||
buttonText = intl.formatMessage({
|
||||
defaultMessage: "Show less",
|
||||
})
|
||||
iconDirection = "keyboard_arrow_up"
|
||||
} else if (canShowAll) {
|
||||
buttonText = intl.formatMessage({
|
||||
defaultMessage: "Show all",
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={styles.hotelListingSection} ref={scrollRef}>
|
||||
<header className={styles.header}>
|
||||
<Typography variant="Title/md">
|
||||
<h2 className={styles.heading}>{heading}</h2>
|
||||
</Typography>
|
||||
</header>
|
||||
<ul className={styles.list}>
|
||||
{hotels.map(({ hotel, url }, index) => (
|
||||
<li
|
||||
key={hotel.id}
|
||||
className={cx(styles.listItem, {
|
||||
[styles.hidden]: index >= visibleCount,
|
||||
})}
|
||||
>
|
||||
<HotelListingItem hotel={hotel} url={url} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
{showButton ? (
|
||||
<Button
|
||||
variant="Text"
|
||||
color="Primary"
|
||||
size="Medium"
|
||||
typography="Body/Paragraph/mdBold"
|
||||
onPress={handleButtonClick}
|
||||
>
|
||||
<MaterialIcon icon={iconDirection} color="CurrentColor" />
|
||||
{buttonText}
|
||||
</Button>
|
||||
) : null}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user