feat(BOOK-472): Different placement of no availability alert on mobile viewports
Approved-by: Bianca Widstam
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
||||||
@@ -11,11 +12,15 @@ import useLang from "../../../../../hooks/useLang"
|
|||||||
|
|
||||||
import styles from "./alert.module.css"
|
import styles from "./alert.module.css"
|
||||||
|
|
||||||
|
interface NoAvailabilityAlertProps {
|
||||||
|
roomIndex: number
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
export default function NoAvailabilityAlert({
|
export default function NoAvailabilityAlert({
|
||||||
roomIndex,
|
roomIndex,
|
||||||
}: {
|
className,
|
||||||
roomIndex: number
|
}: NoAvailabilityAlertProps) {
|
||||||
}) {
|
|
||||||
const lang = useLang()
|
const lang = useLang()
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
@@ -51,7 +56,7 @@ export default function NoAvailabilityAlert({
|
|||||||
defaultMessage: "There are no rooms available that match your request.",
|
defaultMessage: "There are no rooms available that match your request.",
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<div className={styles.hotelAlert}>
|
<div className={cx(styles.hotelAlert, className)}>
|
||||||
<Alert
|
<Alert
|
||||||
type={AlertTypeEnum.Info}
|
type={AlertTypeEnum.Info}
|
||||||
heading={intl.formatMessage({
|
heading={intl.formatMessage({
|
||||||
@@ -92,7 +97,7 @@ export default function NoAvailabilityAlert({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.hotelAlert}>
|
<div className={cx(styles.hotelAlert, className)}>
|
||||||
<Alert
|
<Alert
|
||||||
type={AlertTypeEnum.Info}
|
type={AlertTypeEnum.Info}
|
||||||
heading={intl.formatMessage({
|
heading={intl.formatMessage({
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.availableRooms {
|
||||||
|
color: var(--Text-Default);
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { cx } from "class-variance-authority"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"
|
||||||
|
|
||||||
|
import { useSelectRateContext } from "../../../../../../contexts/SelectRate/SelectRateContext"
|
||||||
|
|
||||||
|
import styles from "./availableRoomsCount.module.css"
|
||||||
|
|
||||||
|
interface AvailableRoomsCountProps {
|
||||||
|
roomIndex: number
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AvailableRoomsCount({
|
||||||
|
roomIndex,
|
||||||
|
className,
|
||||||
|
}: AvailableRoomsCountProps) {
|
||||||
|
const intl = useIntl()
|
||||||
|
const { isFetching, getAvailabilityForRoom } = useSelectRateContext()
|
||||||
|
|
||||||
|
const roomAvailability = getAvailabilityForRoom(roomIndex) ?? []
|
||||||
|
|
||||||
|
const availableRooms = roomAvailability.filter(
|
||||||
|
(x) => x.status === AvailabilityEnum.Available
|
||||||
|
).length
|
||||||
|
|
||||||
|
const totalRooms = roomAvailability.length
|
||||||
|
|
||||||
|
const notAllRoomsAvailableText = intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: "selectRate.availableRooms.partial",
|
||||||
|
defaultMessage:
|
||||||
|
"{availableRooms}/{numberOfRooms, plural, one {# room type} other {# room types}} available",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
availableRooms,
|
||||||
|
numberOfRooms: totalRooms,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const allRoomsAvailableText = intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: "selectRate.availableRooms.all",
|
||||||
|
defaultMessage:
|
||||||
|
"{numberOfRooms, plural, one {# room type} other {# room types}} available",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
numberOfRooms: totalRooms,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isFetching) {
|
||||||
|
return <SkeletonShimmer height="30px" width="25ch" />
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography
|
||||||
|
variant="Title/Subtitle/md"
|
||||||
|
className={cx(styles.availableRooms, className)}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{availableRooms !== totalRooms
|
||||||
|
? notAllRoomsAvailableText
|
||||||
|
: allRoomsAvailableText}
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
|
|
||||||
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
|
||||||
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"
|
|
||||||
|
|
||||||
import { useSelectRateContext } from "../../../../../contexts/SelectRate/SelectRateContext"
|
|
||||||
import { ErrorBoundary } from "../../../../ErrorBoundary/ErrorBoundary"
|
import { ErrorBoundary } from "../../../../ErrorBoundary/ErrorBoundary"
|
||||||
|
import NoAvailabilityAlert from "../NoAvailabilityAlert"
|
||||||
import { RemoveBookingCodeButton } from "./RemoveBookingCodeButton/RemoveBookingCodeButton"
|
import { RemoveBookingCodeButton } from "./RemoveBookingCodeButton/RemoveBookingCodeButton"
|
||||||
|
import { AvailableRoomsCount } from "./AvailableRoomsCount"
|
||||||
import { RoomPackageFilter } from "./RoomPackageFilter"
|
import { RoomPackageFilter } from "./RoomPackageFilter"
|
||||||
|
|
||||||
import styles from "./roomsHeader.module.css"
|
import styles from "./roomsHeader.module.css"
|
||||||
@@ -24,7 +20,14 @@ export function RoomsHeader({ roomIndex }: { roomIndex: number }) {
|
|||||||
function InnerRoomsHeader({ roomIndex }: { roomIndex: number }) {
|
function InnerRoomsHeader({ roomIndex }: { roomIndex: number }) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<AvailableRoomCount roomIndex={roomIndex} />
|
<AvailableRoomsCount
|
||||||
|
roomIndex={roomIndex}
|
||||||
|
className={styles.availableRoomsCount}
|
||||||
|
/>
|
||||||
|
<NoAvailabilityAlert
|
||||||
|
roomIndex={roomIndex}
|
||||||
|
className={styles.noAvailabilityAlert}
|
||||||
|
/>
|
||||||
<div className={styles.filters}>
|
<div className={styles.filters}>
|
||||||
<RemoveBookingCodeButton />
|
<RemoveBookingCodeButton />
|
||||||
<RoomPackageFilter roomIndex={roomIndex} />
|
<RoomPackageFilter roomIndex={roomIndex} />
|
||||||
@@ -33,53 +36,3 @@ function InnerRoomsHeader({ roomIndex }: { roomIndex: number }) {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function AvailableRoomCount({ roomIndex }: { roomIndex: number }) {
|
|
||||||
const intl = useIntl()
|
|
||||||
const { isFetching, getAvailabilityForRoom } = useSelectRateContext()
|
|
||||||
|
|
||||||
const roomAvailability = getAvailabilityForRoom(roomIndex) ?? []
|
|
||||||
|
|
||||||
const availableRooms = roomAvailability.filter(
|
|
||||||
(x) => x.status === AvailabilityEnum.Available
|
|
||||||
).length
|
|
||||||
|
|
||||||
const totalRooms = roomAvailability.length
|
|
||||||
|
|
||||||
const notAllRoomsAvailableText = intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "selectRate.availableRooms.partial",
|
|
||||||
defaultMessage:
|
|
||||||
"{availableRooms}/{numberOfRooms, plural, one {# room type} other {# room types}} available",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
availableRooms,
|
|
||||||
numberOfRooms: totalRooms,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const allRoomsAvailableText = intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "selectRate.availableRooms.all",
|
|
||||||
defaultMessage:
|
|
||||||
"{numberOfRooms, plural, one {# room type} other {# room types}} available",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
numberOfRooms: totalRooms,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isFetching) {
|
|
||||||
return <SkeletonShimmer height="30px" width="25ch" />
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Typography variant="Title/Subtitle/md" className={styles.availableRooms}>
|
|
||||||
<p>
|
|
||||||
{availableRooms !== totalRooms
|
|
||||||
? notAllRoomsAvailableText
|
|
||||||
: allRoomsAvailableText}
|
|
||||||
</p>
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,13 +2,22 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Space-x3);
|
gap: var(--Space-x3);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
grid-template-areas:
|
||||||
|
"availableRoomsCount"
|
||||||
|
"noAvailabilityAlert"
|
||||||
|
"filters";
|
||||||
}
|
}
|
||||||
|
|
||||||
.availableRooms {
|
.availableRoomsCount {
|
||||||
color: var(--Text-Default);
|
grid-area: availableRoomsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noAvailabilityAlert {
|
||||||
|
grid-area: noAvailabilityAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
|
grid-area: filters;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--Space-x1);
|
gap: var(--Space-x1);
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -17,5 +26,7 @@
|
|||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
.container {
|
.container {
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
|
grid-template-areas: "availableRoomsCount filters"
|
||||||
|
"noAvailabilityAlert noAvailabilityAlert";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import { useSelectRateContext } from "../../../../contexts/SelectRate/SelectRateContext"
|
import { useSelectRateContext } from "../../../../contexts/SelectRate/SelectRateContext"
|
||||||
import { MultiRoomWrapper } from "./MultiRoomWrapper"
|
import { MultiRoomWrapper } from "./MultiRoomWrapper"
|
||||||
import NoAvailabilityAlert from "./NoAvailabilityAlert"
|
|
||||||
import { RoomsHeader } from "./RoomsHeader"
|
import { RoomsHeader } from "./RoomsHeader"
|
||||||
import RoomsList from "./RoomsList"
|
import RoomsList from "./RoomsList"
|
||||||
|
|
||||||
@@ -28,7 +27,6 @@ export default function Rooms() {
|
|||||||
isMultiRoom={isMultiRoom}
|
isMultiRoom={isMultiRoom}
|
||||||
>
|
>
|
||||||
<RoomsHeader roomIndex={idx} />
|
<RoomsHeader roomIndex={idx} />
|
||||||
<NoAvailabilityAlert roomIndex={idx} />
|
|
||||||
<RoomsList roomIndex={idx} />
|
<RoomsList roomIndex={idx} />
|
||||||
</MultiRoomWrapper>
|
</MultiRoomWrapper>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user