Feat/SW-2271 hotel list filtering
* feat(SW-2271): Changes to hotel data types in preperation for filtering * feat(SW-2271): Added filter and sort functionality Approved-by: Matilda Landström
This commit is contained in:
@@ -12,57 +12,64 @@ import {
|
||||
} from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { useHotelListingDataStore } from "@/stores/hotel-listing-data"
|
||||
|
||||
import CampaignHotelListingSkeleton from "@/components/Blocks/CampaignHotelListing/CampaignHotelListingSkeleton"
|
||||
import HotelFilterAndSort from "@/components/HotelFilterAndSort"
|
||||
|
||||
import HotelListingItem from "./HotelListingItem"
|
||||
|
||||
import styles from "./campaignHotelListing.module.css"
|
||||
|
||||
import type { HotelDataWithUrl } from "@scandic-hotels/trpc/types/hotel"
|
||||
|
||||
interface CampaignHotelListingClientProps {
|
||||
heading: string
|
||||
preamble?: string | null
|
||||
hotels: HotelDataWithUrl[]
|
||||
visibleCountMobile?: 3 | 6
|
||||
visibleCountDesktop?: 3 | 6
|
||||
visibleCountMobile: 3 | 6
|
||||
visibleCountDesktop: 3 | 6
|
||||
isMainBlock: boolean
|
||||
}
|
||||
|
||||
export default function CampaignHotelListingClient({
|
||||
heading,
|
||||
preamble,
|
||||
hotels,
|
||||
visibleCountMobile = 3,
|
||||
visibleCountDesktop = 6,
|
||||
visibleCountMobile,
|
||||
visibleCountDesktop,
|
||||
isMainBlock,
|
||||
}: CampaignHotelListingClientProps) {
|
||||
const intl = useIntl()
|
||||
const isMobile = useMediaQuery("(max-width: 767px)")
|
||||
const scrollRef = useRef<HTMLElement>(null)
|
||||
const { activeHotels, isLoading } = useHotelListingDataStore((state) => ({
|
||||
activeHotels: state.activeHotels,
|
||||
isLoading: state.isLoading,
|
||||
}))
|
||||
|
||||
const initialCount = isMobile ? visibleCountMobile : visibleCountDesktop // Initial number of hotels to show
|
||||
const initialCount = isMobile ? visibleCountMobile : visibleCountDesktop // Initial number of activeHotels to show
|
||||
const thresholdCount = initialCount + 3 // This is the threshold at which we start showing the "Show More" button
|
||||
const showAllThreshold = initialCount * 3 // This is the threshold at which we show the "Show All" button
|
||||
const incrementCount = initialCount // Number of hotels to increment when the button is clicked
|
||||
const incrementCount = initialCount // Number of activeHotels 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
|
||||
// Set initial visible count based on the number of activeHotels and the threshold
|
||||
activeHotels.length <= thresholdCount ? activeHotels.length : initialCount
|
||||
)
|
||||
|
||||
// Only show the show more/less button if the length of hotels exceeds the threshold count
|
||||
const showButton = hotels.length > thresholdCount
|
||||
// Only show the show more/less button if the length of activeHotels exceeds the threshold count
|
||||
const showButton = activeHotels.length > thresholdCount
|
||||
|
||||
// Determine if we are at the stage where the user can click to show all hotels
|
||||
// Determine if we are at the stage where the user can click to show all activeHotels
|
||||
const canShowAll =
|
||||
hotels.length > visibleCount &&
|
||||
activeHotels.length > visibleCount &&
|
||||
(visibleCount + incrementCount > showAllThreshold ||
|
||||
visibleCount + incrementCount >= hotels.length)
|
||||
visibleCount + incrementCount >= activeHotels.length)
|
||||
|
||||
function handleButtonClick() {
|
||||
if (visibleCount < hotels.length) {
|
||||
if (visibleCount < activeHotels.length) {
|
||||
if (canShowAll) {
|
||||
setVisibleCount(hotels.length)
|
||||
setVisibleCount(activeHotels.length)
|
||||
} else {
|
||||
setVisibleCount((prev) =>
|
||||
Math.min(prev + incrementCount, hotels.length)
|
||||
Math.min(prev + incrementCount, activeHotels.length)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -78,7 +85,7 @@ export default function CampaignHotelListingClient({
|
||||
})
|
||||
let iconDirection: MaterialIconProps["icon"] = "keyboard_arrow_down"
|
||||
|
||||
if (visibleCount === hotels.length) {
|
||||
if (visibleCount === activeHotels.length) {
|
||||
buttonText = intl.formatMessage({
|
||||
defaultMessage: "Show less",
|
||||
})
|
||||
@@ -89,20 +96,30 @@ export default function CampaignHotelListingClient({
|
||||
})
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return <CampaignHotelListingSkeleton />
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={styles.hotelListingSection} ref={scrollRef}>
|
||||
<section
|
||||
className={cx(styles.hotelListingSection, {
|
||||
[styles.isMainBlock]: isMainBlock,
|
||||
})}
|
||||
ref={scrollRef}
|
||||
>
|
||||
<header className={styles.header}>
|
||||
<Typography variant="Title/Subtitle/lg">
|
||||
<h3>{heading}</h3>
|
||||
<Typography variant={isMainBlock ? "Title/md" : "Title/Subtitle/lg"}>
|
||||
<h3 className={styles.heading}>{heading}</h3>
|
||||
</Typography>
|
||||
{isMainBlock ? <HotelFilterAndSort /> : null}
|
||||
{preamble ? (
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{preamble}</p>
|
||||
<p className={styles.preamble}>{preamble}</p>
|
||||
</Typography>
|
||||
) : null}
|
||||
</header>
|
||||
<ul className={styles.list}>
|
||||
{hotels.map(({ hotel, url }, index) => (
|
||||
{activeHotels.map(({ hotel, url }, index) => (
|
||||
<li
|
||||
key={hotel.id}
|
||||
className={cx(styles.listItem, {
|
||||
|
||||
Reference in New Issue
Block a user