feat: refactor NewDates, clean up legacy code
This reverts commit 0c7836fa59.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Row from "./Row"
|
||||
|
||||
export default function BedPreference() {
|
||||
const intl = useIntl()
|
||||
|
||||
const bedType = useMyStayStore((state) => state.bookedRoom.room?.bedType)
|
||||
|
||||
if (!bedType) {
|
||||
return null
|
||||
}
|
||||
|
||||
const mainBedWidthValueMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{value} cm",
|
||||
},
|
||||
{
|
||||
value: bedType.mainBed.widthRange.min,
|
||||
}
|
||||
)
|
||||
|
||||
const mainBedWidthRangeMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{min}–{max} cm",
|
||||
},
|
||||
{
|
||||
min: bedType.mainBed.widthRange.min,
|
||||
max: bedType.mainBed.widthRange.max,
|
||||
}
|
||||
)
|
||||
|
||||
const sameWidth =
|
||||
bedType.mainBed.widthRange.min === bedType.mainBed.widthRange.max
|
||||
const widthMsg = sameWidth ? mainBedWidthValueMsg : mainBedWidthRangeMsg
|
||||
const text = `${bedType.mainBed.description} (${widthMsg})`
|
||||
|
||||
return (
|
||||
<Row
|
||||
icon="bed"
|
||||
text={text}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Bed preference",
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import { formatPrice } from "@/utils/numberFormatting"
|
||||
|
||||
import Row from "./Row"
|
||||
|
||||
export default function Breakfast() {
|
||||
const intl = useIntl()
|
||||
|
||||
const { breakfast, rateDefinition } = useMyStayStore((state) => ({
|
||||
breakfast: state.bookedRoom.breakfast,
|
||||
rateDefinition: state.bookedRoom.rateDefinition,
|
||||
}))
|
||||
|
||||
let breakfastPrice = intl.formatMessage({
|
||||
defaultMessage: "No breakfast",
|
||||
})
|
||||
if (rateDefinition.breakfastIncluded) {
|
||||
breakfastPrice = intl.formatMessage({
|
||||
defaultMessage: "Included",
|
||||
})
|
||||
} else if (breakfast) {
|
||||
breakfastPrice = formatPrice(
|
||||
intl,
|
||||
breakfast.localPrice.totalPrice,
|
||||
breakfast.localPrice.currency
|
||||
)
|
||||
}
|
||||
|
||||
const title = intl.formatMessage({ defaultMessage: "Breakfast" })
|
||||
return <Row icon="coffee" text={breakfastPrice} title={title} />
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Row from "./Row"
|
||||
|
||||
export default function Guests() {
|
||||
const intl = useIntl()
|
||||
|
||||
const { adults, childrenAges } = useMyStayStore((state) => ({
|
||||
adults: state.bookedRoom.adults,
|
||||
childrenAges: state.bookedRoom.childrenAges,
|
||||
}))
|
||||
|
||||
const adultsMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{adults, plural, one {# adult} other {# adults}}",
|
||||
},
|
||||
{
|
||||
adults,
|
||||
}
|
||||
)
|
||||
|
||||
const childrenMsg = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "{children, plural, one {# child} other {# children}}",
|
||||
},
|
||||
{
|
||||
children: childrenAges.length,
|
||||
}
|
||||
)
|
||||
|
||||
const adultsOnlyMsg = adultsMsg
|
||||
const adultsAndChildrenMsg = [adultsMsg, childrenMsg].join(", ")
|
||||
|
||||
return (
|
||||
<Row
|
||||
icon="person"
|
||||
text={childrenAges.length > 0 ? adultsAndChildrenMsg : adultsOnlyMsg}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Guests",
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import { hasModifiableRate } from "@/components/HotelReservation/MyStay/utils"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import Row from "./Row"
|
||||
|
||||
export default function ModifyBy() {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
|
||||
const { checkInDate, isModifyable } = useMyStayStore((state) => ({
|
||||
checkInDate: state.bookedRoom.checkInDate,
|
||||
isModifyable: hasModifiableRate(
|
||||
state.bookedRoom.rateDefinition.cancellationRule
|
||||
),
|
||||
}))
|
||||
|
||||
if (!isModifyable) {
|
||||
return null
|
||||
}
|
||||
|
||||
const fromDate = dt(checkInDate).locale(lang)
|
||||
|
||||
const text = intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "Until {time}, {date}",
|
||||
},
|
||||
{
|
||||
time: "18:00",
|
||||
date: fromDate.format("dddd D MMM"),
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<Row
|
||||
icon="refresh"
|
||||
text={text}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Modify By",
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Row from "./Row"
|
||||
|
||||
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||
|
||||
export default function Packages() {
|
||||
const intl = useIntl()
|
||||
|
||||
const packages = useMyStayStore(
|
||||
(state) =>
|
||||
state.bookedRoom.packages
|
||||
?.filter((item) =>
|
||||
Object.values(RoomPackageCodeEnum).includes(
|
||||
item.code as RoomPackageCodeEnum
|
||||
)
|
||||
)
|
||||
.map((item) => item.description) || []
|
||||
)
|
||||
|
||||
if (!packages.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Row
|
||||
icon="meeting_room"
|
||||
text={packages.join(", ")}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Room classification",
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
"use client"
|
||||
import {
|
||||
MaterialIcon,
|
||||
type MaterialIconProps,
|
||||
} from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import styles from "./row.module.css"
|
||||
|
||||
interface RowProps {
|
||||
icon: MaterialIconProps["icon"]
|
||||
text: string
|
||||
title: string
|
||||
}
|
||||
|
||||
export default function Row({ icon, text, title }: RowProps) {
|
||||
return (
|
||||
<div className={styles.row}>
|
||||
<span className={styles.title}>
|
||||
<MaterialIcon icon={icon} color="Icon/Default" size={20} />
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>{title}</p>
|
||||
</Typography>
|
||||
</span>
|
||||
<div className={styles.content}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p color="uiTextHighContrast">{text}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: var(--Spacing-x-one-and-half) 0;
|
||||
}
|
||||
|
||||
.row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.title svg {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-left: var(--Spacing-x4);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.row {
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--Base-Border-Subtle);
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.title svg {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Row from "./Row"
|
||||
|
||||
export default function Terms() {
|
||||
const intl = useIntl()
|
||||
|
||||
const cancellationText = useMyStayStore(
|
||||
(state) => state.bookedRoom.rateDefinition.cancellationText
|
||||
)
|
||||
|
||||
if (!cancellationText) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Row
|
||||
icon="contract"
|
||||
text={cancellationText}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Terms",
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
.details {
|
||||
max-width: 100%;
|
||||
padding: 0 var(--Spacing-x2);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.details {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import BedPreference from "./BedPreference"
|
||||
import Breakfast from "./Breakfast"
|
||||
import Guests from "./Guests"
|
||||
import ModifyBy from "./ModifyBy"
|
||||
import Packages from "./Packages"
|
||||
import Terms from "./Terms"
|
||||
|
||||
import styles from "./details.module.css"
|
||||
|
||||
export default function Details() {
|
||||
return (
|
||||
<div className={styles.details}>
|
||||
<Guests />
|
||||
<Terms />
|
||||
<ModifyBy />
|
||||
<Breakfast />
|
||||
<Packages />
|
||||
<BedPreference />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user