Merged in feat/SW-2407-mystay-tc-to-modal (pull request #2082)

Feat/SW-2407 mystay tc to modal

* feat: SW-2407 Moved terms in modal view for my stay

* feat: SW-2407 Updated modal to show terms for reward nights and corporate cheque stay

* feat: SW-2407 Optimised code

* feat: SW-2407 Optimised code


Approved-by: Niclas Edenvin
This commit is contained in:
Hrishikesh Vaipurkar
2025-05-27 07:00:02 +00:00
parent db93cc7d0e
commit e2c1b066be
8 changed files with 194 additions and 48 deletions

View File

@@ -1,15 +1,19 @@
"use client"
import { useIntl } from "react-intl"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { CancellationRuleEnum } from "@/constants/booking"
import { dt } from "@/lib/dt"
import { IconForFeatureCode } from "@/components/HotelReservation/utils"
import Image from "@/components/Image"
import Modal from "@/components/Modal"
import Divider from "@/components/TempDesignSystem/Divider"
import IconChip from "@/components/TempDesignSystem/IconChip"
import useRateTitles from "@/hooks/booking/useRateTitles"
import useLang from "@/hooks/useLang"
import { formatPrice } from "@/utils/numberFormatting"
@@ -20,6 +24,7 @@ import RoomDetailsSidePeek from "./RoomDetailsSidePeek"
import styles from "./room.module.css"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import { RateEnum } from "@/types/enums/rate"
import type { Room } from "@/types/stores/my-stay"
import type { SafeUser } from "@/types/user"
@@ -93,6 +98,19 @@ export default function Room({ booking, roomNr, user }: RoomProps) {
)
}
const rateTitles = useRateTitles()
let rateTerm: { paymentTerm: string; title: string }
switch (rateDefinition.cancellationRule) {
case CancellationRuleEnum.CancellableBefore6PM:
rateTerm = rateTitles[RateEnum.flex]
break
case CancellationRuleEnum.Changeable:
rateTerm = rateTitles[RateEnum.change]
break
default:
rateTerm = rateTitles[RateEnum.save]
}
return (
<article className={styles.multiRoom}>
<Typography variant="Title/smRegular">
@@ -218,7 +236,7 @@ export default function Room({ booking, roomNr, user }: RoomProps) {
</p>
</Typography>
</div>
{rateDefinition.cancellationText ? (
{
<div className={styles.row}>
<Typography variant="Body/Paragraph/mdBold">
<p>
@@ -227,11 +245,45 @@ export default function Room({ booking, roomNr, user }: RoomProps) {
})}
</p>
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<p>{rateDefinition.cancellationText}</p>
</Typography>
<div className={styles.termsLabel}>
<Typography variant="Body/Paragraph/mdRegular">
<span>{rateTerm.title}</span>
</Typography>
<Modal
title={rateTerm.title}
subtitle={rateTerm.paymentTerm}
trigger={
<IconButton
theme="Black"
style="Muted"
className={styles.termsInfoIcon}
>
<MaterialIcon
icon="info"
color="Icon/Default"
size={20}
/>
</IconButton>
}
>
<div className={styles.terms}>
{rateDefinition.generalTerms.map((term) => (
<Typography key={term} variant="Body/Paragraph/mdRegular">
<p className={styles.term}>
<MaterialIcon
icon="check"
color="Icon/Feedback/Success"
size={20}
/>
{term}
</p>
</Typography>
))}
</div>
</Modal>
</div>
</div>
) : null}
}
{hasModifiableRate(rateDefinition.cancellationRule) && (
<div className={styles.row}>
<Typography variant="Body/Paragraph/mdBold">

View File

@@ -1,8 +1,8 @@
.multiRoom {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
padding: 0 var(--Spacing-x2);
gap: var(--Space-x2);
padding: 0 var(--Space-x2);
}
.cancelled {
@@ -16,12 +16,12 @@
.multiRoomCard {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
gap: var(--Space-x2);
background-color: var(--Base-Background-Primary-Normal);
border-radius: var(--Corner-radius-lg);
border: 1px solid var(--Base-Border-Subtle);
overflow: hidden;
padding-bottom: var(--Spacing-x3);
padding-bottom: var(--Space-x3);
position: relative;
}
@@ -38,14 +38,14 @@
.roomHeader {
display: flex;
align-items: center;
gap: var(--Spacing-x-one-and-half);
gap: var(--Space-x15);
}
.chip {
background-color: var(--Scandic-Peach-30);
color: var(--Scandic-Red-100);
border-radius: var(--Corner-radius-sm);
padding: var(--Spacing-x-half) var(--Spacing-x1);
padding: var(--Space-x05) var(--Space-x1);
height: fit-content;
}
@@ -55,13 +55,13 @@
.reference {
display: flex;
gap: var(--Spacing-x-half);
gap: var(--Space-x05);
}
.details {
display: flex;
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2) 0;
gap: var(--Spacing-x2);
padding: var(--Space-x15) var(--Space-x2) 0;
gap: var(--Space-x2);
flex-direction: column;
}
@@ -77,16 +77,37 @@
left: 10px;
display: flex;
flex-direction: row;
gap: var(--Spacing-x1);
gap: var(--Space-x1);
z-index: 100;
}
.package {
background-color: var(--Main-Grey-White);
padding: var(--Spacing-x-half) var(--Spacing-x1);
padding: var(--Space-x05) var(--Space-x1);
border-radius: var(--Corner-radius-sm);
}
.termsLabel {
display: flex;
align-items: center;
}
.termsInfoIcon {
margin: -10px -10px -10px -5px;
}
.terms {
display: flex;
flex-direction: column;
gap: var(--Space-x1);
margin-top: var(--Space-x2);
}
.term {
display: flex;
gap: var(--Space-x1);
}
@media (min-width: 768px) {
.multiRoom {
padding: 0;

View File

@@ -13,7 +13,12 @@ interface RowProps {
title: string
}
export default function Row({ icon, text, title }: RowProps) {
export default function Row({
icon,
text,
title,
children,
}: React.PropsWithChildren<RowProps>) {
return (
<div className={styles.row}>
<span className={styles.title}>
@@ -26,6 +31,7 @@ export default function Row({ icon, text, title }: RowProps) {
<Typography variant="Body/Paragraph/mdRegular">
<p>{text}</p>
</Typography>
{children}
</div>
</div>
)

View File

@@ -1,7 +1,7 @@
.row {
display: flex;
flex-direction: column;
padding: var(--Spacing-x-one-and-half) 0;
padding: var(--Space-x15) 0;
}
.row:last-child {
@@ -11,7 +11,7 @@
.title {
display: flex;
flex-direction: row;
gap: var(--Spacing-x1);
gap: var(--Space-x1);
}
.title svg {
@@ -20,7 +20,9 @@
}
.content {
padding-left: var(--Spacing-x4);
display: flex;
align-items: center;
padding-left: var(--Space-x4);
}
@media (min-width: 768px) {

View File

@@ -1,27 +0,0 @@
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",
})}
/>
)
}

View File

@@ -0,0 +1,76 @@
import { useIntl } from "react-intl"
import { IconButton } from "@scandic-hotels/design-system/IconButton"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { CancellationRuleEnum } from "@/constants/booking"
import { useMyStayStore } from "@/stores/my-stay"
import Modal from "@/components/Modal"
import useRateTitles from "@/hooks/booking/useRateTitles"
import Row from "../Row"
import styles from "./terms.module.css"
import { RateEnum } from "@/types/enums/rate"
export default function Terms() {
const intl = useIntl()
const rateTitles = useRateTitles()
const { generalTerms, cancellationRule } = useMyStayStore((state) => ({
generalTerms: state.bookedRoom.rateDefinition.generalTerms,
cancellationRule: state.bookedRoom.rateDefinition.cancellationRule,
}))
let rateTerm: { paymentTerm: string; title: string }
switch (cancellationRule) {
case CancellationRuleEnum.CancellableBefore6PM:
rateTerm = rateTitles[RateEnum.flex]
break
case CancellationRuleEnum.Changeable:
rateTerm = rateTitles[RateEnum.change]
break
default:
rateTerm = rateTitles[RateEnum.save]
}
return (
<>
<Row
icon="contract"
text={rateTerm.title}
title={intl.formatMessage({
defaultMessage: "Terms",
})}
>
<Modal
title={rateTerm.title}
subtitle={rateTerm.paymentTerm}
trigger={
<IconButton theme="Black" style="Muted" className={styles.button}>
<MaterialIcon icon="info" color="Icon/Default" size={20} />
</IconButton>
}
>
<div className={styles.terms}>
{generalTerms.map((term) => (
<Typography key={term} variant="Body/Paragraph/mdRegular">
<p className={styles.term}>
<MaterialIcon
icon="check"
color="Icon/Feedback/Success"
size={20}
/>
{term}
</p>
</Typography>
))}
</div>
</Modal>
</Row>
</>
)
}

View File

@@ -0,0 +1,16 @@
.terms {
display: flex;
flex-direction: column;
gap: var(--Space-x1);
margin-top: var(--Space-x3);
}
.term {
display: flex;
align-items: center;
gap: var(--Space-x1);
}
.button {
margin: -10px -5px;
}

View File

@@ -1,9 +1,9 @@
import Terms from "./Terms/Terms"
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"