fix: handle card grids in css instead of js

This commit is contained in:
Christel Westerberg
2025-01-08 15:57:18 +01:00
parent 96820ba89a
commit 678fea1e7d
7 changed files with 53 additions and 136 deletions

View File

@@ -8,6 +8,7 @@
display: flex;
flex-direction: column;
gap: var(--Spacing-x-half);
height: 100%;
}
.noPricesCard {

View File

@@ -11,7 +11,6 @@ import Label from "@/components/TempDesignSystem/Form/Label"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import { RATE_CARD_EQUAL_HEIGHT_CLASS } from "../utils"
import PriceTable from "./PriceList"
import styles from "./flexibilityOption.module.css"
@@ -69,7 +68,7 @@ export default function FlexibilityOption({
if (!product) {
return (
<div className={`${styles.noPricesCard} ${RATE_CARD_EQUAL_HEIGHT_CLASS}`}>
<div className={styles.noPricesCard}>
<div className={styles.header}>
<InfoCircleIcon width={16} height={16} color="uiTextMediumContrast" />
<div className={styles.priceType}>
@@ -116,7 +115,7 @@ export default function FlexibilityOption({
onClick={onClick}
ref={inputElementRef}
/>
<div className={`${styles.card} ${RATE_CARD_EQUAL_HEIGHT_CLASS}`}>
<div className={styles.card}>
<div className={styles.header}>
<Modal
trigger={

View File

@@ -12,10 +12,6 @@ import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { getIconForFeatureCode } from "../../utils"
import {
RATE_CARDS_AVAILABLE_HEIGHT_CLASS,
RATE_CARDS_NOT_AVAILABLE_HEIGHT_CLASS,
} from "../utils"
import { cardVariants } from "./cardVariants"
import styles from "./roomCard.module.css"
@@ -115,7 +111,7 @@ export default function RoomCard({
})
return (
<div className={classNames}>
<li className={classNames}>
<div>
<div className={styles.imageContainer}>
<div className={styles.chipContainer}>
@@ -186,9 +182,7 @@ export default function RoomCard({
*/}
</div>
</div>
<div
className={`${styles.container} ${roomConfiguration.status === "NotAvailable" ? RATE_CARDS_NOT_AVAILABLE_HEIGHT_CLASS : RATE_CARDS_AVAILABLE_HEIGHT_CLASS}`}
>
<div className={styles.container}>
<Caption color="uiTextHighContrast" type="bold">
{getBreakfastMessage(rates.flexRate)}
</Caption>
@@ -204,23 +198,21 @@ export default function RoomCard({
</div>
</div>
) : (
<div className={styles.flexibilityOptions}>
{Object.entries(rates).map(([key, rate]) => (
<FlexibilityOption
key={key}
name={rateKey(key)}
value={key.toLowerCase()}
paymentTerm={key === "flexRate" ? payLater : payNow}
product={findProductForRate(rate)}
priceInformation={getRateDefinitionForRate(rate)?.generalTerms}
handleSelectRate={handleSelectRate}
roomTypeCode={roomConfiguration.roomTypeCode}
petRoomPackage={petRoomPackage}
/>
))}
</div>
Object.entries(rates).map(([key, rate]) => (
<FlexibilityOption
key={key}
name={rateKey(key)}
value={key.toLowerCase()}
paymentTerm={key === "flexRate" ? payLater : payNow}
product={findProductForRate(rate)}
priceInformation={getRateDefinitionForRate(rate)?.generalTerms}
handleSelectRate={handleSelectRate}
roomTypeCode={roomConfiguration.roomTypeCode}
petRoomPackage={petRoomPackage}
/>
))
)}
</div>
</div>
</li>
)
}

View File

@@ -1,13 +1,14 @@
.card {
font-size: 14px;
display: flex;
flex-direction: column;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: subgrid;
background-color: #fff;
border-radius: var(--Corner-radius-Large);
border: 1px solid var(--Base-Border-Subtle);
position: relative;
height: 100%;
justify-content: space-between;
grid-row: span 5;
}
.card.noAvailability {
@@ -38,9 +39,16 @@
.container {
padding: var(--Spacing-x1) var(--Spacing-x2) var(--Spacing-x2);
display: flex;
flex-direction: column;
display: grid;
grid-template-rows: subgrid;
gap: var(--Spacing-x-one-and-half);
grid-row: span 4;
}
/* Make sure rows with only unavailable rooms still has a min-height */
.container:has(.noRoomsContainer) {
min-height: 400px;
grid-template-rows: auto repeat(3, 1fr);
}
.roomDetails {
@@ -62,9 +70,9 @@
}
.flexibilityOptions {
display: flex;
flex-direction: column;
display: grid;
gap: var(--Spacing-x2);
grid-template-rows: repeat(3, 1fr);
}
.chipContainer {
@@ -89,14 +97,16 @@
}
.noRoomsContainer {
padding: var(--Spacing-x2);
background-color: var(--Base-Surface-Secondary-light-Normal);
border-radius: var(--Corner-radius-Medium);
margin: 0;
height: 100%;
width: 100%;
}
.noRooms {
padding: var(--Spacing-x2);
background-color: var(--Base-Surface-Secondary-light-Normal);
border-radius: var(--Corner-radius-Medium);
margin: 0;
display: flex;
gap: var(--Spacing-x1);
}

View File

@@ -1,19 +1,10 @@
"use client"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
import { useSession } from "next-auth/react"
import { useCallback, useEffect, useMemo, useRef } from "react"
import { debounce } from "@/utils/debounce"
import { isValidSession } from "@/utils/session"
import { useMemo } from "react"
import RateSummary from "./RateSummary"
import RoomCard from "./RoomCard"
import {
getHotelReservationQueryParams,
RATE_CARD_EQUAL_HEIGHT_CLASS,
RATE_CARDS_AVAILABLE_HEIGHT_CLASS,
RATE_CARDS_NOT_AVAILABLE_HEIGHT_CLASS,
} from "./utils"
import { getHotelReservationQueryParams } from "./utils"
import styles from "./roomSelection.module.css"
@@ -32,68 +23,8 @@ export default function RoomSelection({
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
const roomRefs = useRef<HTMLLIElement[]>([])
const { roomConfigurations, rateDefinitions } = roomsAvailability
const equalizePriceOptionHeights = useCallback(() => {
if (!roomRefs.current.length) return
const optionsSelector = `.${RATE_CARD_EQUAL_HEIGHT_CLASS}`
const availableSelector = `.${RATE_CARDS_AVAILABLE_HEIGHT_CLASS}`
const notAvailableSelector = `.${RATE_CARDS_NOT_AVAILABLE_HEIGHT_CLASS}`
const DEFAULT_RATE_CARD_HEIGHT = 380
const maxOptionHeights: number[] = []
let maxPriceCardHeight = DEFAULT_RATE_CARD_HEIGHT
roomRefs.current.forEach((room) => {
const options = room.querySelectorAll<HTMLDivElement>(optionsSelector)
options.forEach((option, i) => {
option.style.height = "auto"
const optionHeight = option.getBoundingClientRect().height
maxOptionHeights[i] = Math.max(maxOptionHeights[i] || 0, optionHeight)
})
const priceCard = room.querySelector(availableSelector) as HTMLElement
if (priceCard) {
const priceCardHeight = priceCard.getBoundingClientRect().height
maxPriceCardHeight = Math.max(maxPriceCardHeight, priceCardHeight)
}
})
roomRefs.current.forEach((room) => {
const options = room.querySelectorAll<HTMLDivElement>(optionsSelector)
options.forEach((option, i) => {
if (option) {
option.style.height = `${maxOptionHeights[i]}px`
}
})
const noPriceCard = room.querySelector(
notAvailableSelector
) as HTMLElement
if (noPriceCard) {
noPriceCard.style.height = `${maxPriceCardHeight}px`
}
})
}, [])
useEffect(() => {
const debouncedResizeHandler = debounce(function () {
equalizePriceOptionHeights()
})
const observer = new ResizeObserver(debouncedResizeHandler)
observer.observe(document.documentElement)
return () => {
if (observer) {
observer.unobserve(document.documentElement)
}
}
}, [roomRefs, equalizePriceOptionHeights])
const queryParams = useMemo(() => {
const params = new URLSearchParams(searchParams)
const searchParamsObject = getHotelReservationQueryParams(searchParams)
@@ -139,23 +70,17 @@ export default function RoomSelection({
>
<ul className={styles.roomList}>
{roomConfigurations.map((roomConfiguration, index) => (
<li
<RoomCard
hotelId={roomsAvailability.hotelId.toString()}
hotelType={hotelType}
rateDefinitions={rateDefinitions}
roomConfiguration={roomConfiguration}
roomCategories={roomCategories}
handleSelectRate={setRateCode}
selectedPackages={selectedPackages}
packages={availablePackages}
key={roomConfiguration.roomTypeCode}
ref={(el) => {
if (el) roomRefs.current[index] = el
}}
>
<RoomCard
hotelId={roomsAvailability.hotelId.toString()}
hotelType={hotelType}
rateDefinitions={rateDefinitions}
roomConfiguration={roomConfiguration}
roomCategories={roomCategories}
handleSelectRate={setRateCode}
selectedPackages={selectedPackages}
packages={availablePackages}
/>
</li>
/>
))}
</ul>
{rateSummary && (

View File

@@ -5,8 +5,8 @@
.roomList {
list-style: none;
display: grid;
grid-template-columns: 1fr;
gap: var(--Spacing-x3);
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.roomList > li {
@@ -18,7 +18,3 @@
position: fixed;
width: 0;
}
.roomList {
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}

View File

@@ -111,9 +111,3 @@ export function createQueryParamsForEnterDetails(
return searchParams
}
export const RATE_CARD_EQUAL_HEIGHT_CLASS = "rateCardEqualHeightSelector"
export const RATE_CARDS_AVAILABLE_HEIGHT_CLASS =
"rateCardAvailableEqualHeightSelector"
export const RATE_CARDS_NOT_AVAILABLE_HEIGHT_CLASS =
"rateCardNotAvailableEqualHeightSelector"