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:
@@ -1,15 +1,19 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import { CancellationRuleEnum } from "@/constants/booking"
|
||||||
import { dt } from "@/lib/dt"
|
import { dt } from "@/lib/dt"
|
||||||
|
|
||||||
import { IconForFeatureCode } from "@/components/HotelReservation/utils"
|
import { IconForFeatureCode } from "@/components/HotelReservation/utils"
|
||||||
import Image from "@/components/Image"
|
import Image from "@/components/Image"
|
||||||
|
import Modal from "@/components/Modal"
|
||||||
import Divider from "@/components/TempDesignSystem/Divider"
|
import Divider from "@/components/TempDesignSystem/Divider"
|
||||||
import IconChip from "@/components/TempDesignSystem/IconChip"
|
import IconChip from "@/components/TempDesignSystem/IconChip"
|
||||||
|
import useRateTitles from "@/hooks/booking/useRateTitles"
|
||||||
import useLang from "@/hooks/useLang"
|
import useLang from "@/hooks/useLang"
|
||||||
import { formatPrice } from "@/utils/numberFormatting"
|
import { formatPrice } from "@/utils/numberFormatting"
|
||||||
|
|
||||||
@@ -20,6 +24,7 @@ import RoomDetailsSidePeek from "./RoomDetailsSidePeek"
|
|||||||
import styles from "./room.module.css"
|
import styles from "./room.module.css"
|
||||||
|
|
||||||
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||||
|
import { RateEnum } from "@/types/enums/rate"
|
||||||
import type { Room } from "@/types/stores/my-stay"
|
import type { Room } from "@/types/stores/my-stay"
|
||||||
import type { SafeUser } from "@/types/user"
|
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 (
|
return (
|
||||||
<article className={styles.multiRoom}>
|
<article className={styles.multiRoom}>
|
||||||
<Typography variant="Title/smRegular">
|
<Typography variant="Title/smRegular">
|
||||||
@@ -218,7 +236,7 @@ export default function Room({ booking, roomNr, user }: RoomProps) {
|
|||||||
</p>
|
</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
{rateDefinition.cancellationText ? (
|
{
|
||||||
<div className={styles.row}>
|
<div className={styles.row}>
|
||||||
<Typography variant="Body/Paragraph/mdBold">
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
<p>
|
<p>
|
||||||
@@ -227,11 +245,45 @@ export default function Room({ booking, roomNr, user }: RoomProps) {
|
|||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<div className={styles.termsLabel}>
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<p>{rateDefinition.cancellationText}</p>
|
<span>{rateTerm.title}</span>
|
||||||
</Typography>
|
</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>
|
</div>
|
||||||
) : null}
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
{hasModifiableRate(rateDefinition.cancellationRule) && (
|
{hasModifiableRate(rateDefinition.cancellationRule) && (
|
||||||
<div className={styles.row}>
|
<div className={styles.row}>
|
||||||
<Typography variant="Body/Paragraph/mdBold">
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.multiRoom {
|
.multiRoom {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--Spacing-x2);
|
gap: var(--Space-x2);
|
||||||
padding: 0 var(--Spacing-x2);
|
padding: 0 var(--Space-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cancelled {
|
.cancelled {
|
||||||
@@ -16,12 +16,12 @@
|
|||||||
.multiRoomCard {
|
.multiRoomCard {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--Spacing-x2);
|
gap: var(--Space-x2);
|
||||||
background-color: var(--Base-Background-Primary-Normal);
|
background-color: var(--Base-Background-Primary-Normal);
|
||||||
border-radius: var(--Corner-radius-lg);
|
border-radius: var(--Corner-radius-lg);
|
||||||
border: 1px solid var(--Base-Border-Subtle);
|
border: 1px solid var(--Base-Border-Subtle);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-bottom: var(--Spacing-x3);
|
padding-bottom: var(--Space-x3);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,14 +38,14 @@
|
|||||||
.roomHeader {
|
.roomHeader {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--Spacing-x-one-and-half);
|
gap: var(--Space-x15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chip {
|
.chip {
|
||||||
background-color: var(--Scandic-Peach-30);
|
background-color: var(--Scandic-Peach-30);
|
||||||
color: var(--Scandic-Red-100);
|
color: var(--Scandic-Red-100);
|
||||||
border-radius: var(--Corner-radius-sm);
|
border-radius: var(--Corner-radius-sm);
|
||||||
padding: var(--Spacing-x-half) var(--Spacing-x1);
|
padding: var(--Space-x05) var(--Space-x1);
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,13 +55,13 @@
|
|||||||
|
|
||||||
.reference {
|
.reference {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--Spacing-x-half);
|
gap: var(--Space-x05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.details {
|
.details {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2) 0;
|
padding: var(--Space-x15) var(--Space-x2) 0;
|
||||||
gap: var(--Spacing-x2);
|
gap: var(--Space-x2);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,16 +77,37 @@
|
|||||||
left: 10px;
|
left: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: var(--Spacing-x1);
|
gap: var(--Space-x1);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.package {
|
.package {
|
||||||
background-color: var(--Main-Grey-White);
|
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);
|
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) {
|
@media (min-width: 768px) {
|
||||||
.multiRoom {
|
.multiRoom {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -13,7 +13,12 @@ interface RowProps {
|
|||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Row({ icon, text, title }: RowProps) {
|
export default function Row({
|
||||||
|
icon,
|
||||||
|
text,
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
}: React.PropsWithChildren<RowProps>) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.row}>
|
<div className={styles.row}>
|
||||||
<span className={styles.title}>
|
<span className={styles.title}>
|
||||||
@@ -26,6 +31,7 @@ export default function Row({ icon, text, title }: RowProps) {
|
|||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<p>{text}</p>
|
<p>{text}</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
.row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: var(--Spacing-x-one-and-half) 0;
|
padding: var(--Space-x15) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row:last-child {
|
.row:last-child {
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
.title {
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: var(--Spacing-x1);
|
gap: var(--Space-x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title svg {
|
.title svg {
|
||||||
@@ -20,7 +20,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding-left: var(--Spacing-x4);
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: var(--Space-x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
|
|||||||
@@ -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",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -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>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import Terms from "./Terms/Terms"
|
||||||
import BedPreference from "./BedPreference"
|
import BedPreference from "./BedPreference"
|
||||||
import Breakfast from "./Breakfast"
|
import Breakfast from "./Breakfast"
|
||||||
import Guests from "./Guests"
|
import Guests from "./Guests"
|
||||||
import ModifyBy from "./ModifyBy"
|
import ModifyBy from "./ModifyBy"
|
||||||
import Packages from "./Packages"
|
import Packages from "./Packages"
|
||||||
import Terms from "./Terms"
|
|
||||||
|
|
||||||
import styles from "./details.module.css"
|
import styles from "./details.module.css"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user