Merged in feat/BOOK-529-update-GLA-design-mystay (pull request #3230)
Feat/BOOK-529 update GLA design mystay * feat(BOOK-529): update gla design on my stay * feat(BOOK-529): open gla modal if error * feat(BOOK-529): add inline accordion to storybook * feat(529): move errormessage below message * feat(529): update infomodal * feat(BOOK-529): update infomodal * feat(BOOK-529): hide guarantee info for adding ancillaries if prepaid * feat(BOOK-529): update width on info dialog * feat(BOOK-529): fix alignment * feat(BOOK-529): check if member price * feat(BOOK-529): refactor msg * feat(BOOK-529): refactor terms and conditions to own component * feat(BOOK-529): clean up confirmation step Approved-by: Christel Westerberg
This commit is contained in:
@@ -4,12 +4,6 @@
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
|
||||
.termsAndConditions {
|
||||
display: grid;
|
||||
gap: var(--Space-x2);
|
||||
color: var(--Text-Secondary);
|
||||
}
|
||||
|
||||
.totalPointsContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -17,9 +11,27 @@
|
||||
padding: var(--Space-x1) var(--Space-x15);
|
||||
border-radius: var(--Corner-radius-md);
|
||||
}
|
||||
.guarantee {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Space-x2);
|
||||
background-color: var(--Surface-Secondary-Default);
|
||||
border-radius: var(--Corner-radius-lg);
|
||||
padding: var(--Space-x2);
|
||||
}
|
||||
|
||||
.paymentInfo {
|
||||
display: flex;
|
||||
gap: var(--Space-x1);
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.totalPoints {
|
||||
display: flex;
|
||||
gap: var(--Space-x15);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.accordionItem {
|
||||
border-radius: var(--Corner-radius-md);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
import { useWatch } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
||||
import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod"
|
||||
import { bookingTermsAndConditionsRoutes } from "@scandic-hotels/common/constants/routes/bookingTermsAndConditionsRoutes"
|
||||
import { privacyPolicyRoutes } from "@scandic-hotels/common/constants/routes/privacyPolicyRoutes"
|
||||
import { dt } from "@scandic-hotels/common/dt"
|
||||
import AccordionItem from "@scandic-hotels/design-system/Accordion/AccordionItem"
|
||||
import { Alert } from "@scandic-hotels/design-system/Alert"
|
||||
import Checkbox from "@scandic-hotels/design-system/Form/Checkbox"
|
||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||
import { PaymentOption } from "@scandic-hotels/design-system/Form/PaymentOption"
|
||||
import { PaymentOptionsGroup } from "@scandic-hotels/design-system/Form/PaymentOptionsGroup"
|
||||
import { SelectPaymentMethod } from "@scandic-hotels/design-system/Form/SelectPaymentMethod"
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { TextLink } from "@scandic-hotels/design-system/TextLink"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { useAddAncillaryStore } from "@/stores/my-stay/add-ancillary-flow"
|
||||
|
||||
import TermsAndConditions from "@/components/HotelReservation/MyStay/TermsAndConditions"
|
||||
import useLang from "@/hooks/useLang"
|
||||
import { trackUpdatePaymentMethod } from "@/utils/tracking"
|
||||
|
||||
import { ancillaryError } from "../../../schema"
|
||||
|
||||
import styles from "./confirmationStep.module.css"
|
||||
|
||||
import type { ConfirmationStepProps } from "@/types/components/myPages/myStay/ancillaries"
|
||||
@@ -33,17 +29,20 @@ export default function ConfirmationStep({
|
||||
}: ConfirmationStepProps) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
const { checkInDate, guaranteeInfo, selectedAncillary } =
|
||||
|
||||
const { checkInDate, guaranteeInfo, selectedAncillary, booking } =
|
||||
useAddAncillaryStore((state) => ({
|
||||
checkInDate: state.booking.checkInDate,
|
||||
guaranteeInfo: state.booking.guaranteeInfo,
|
||||
selectedAncillary: state.selectedAncillary,
|
||||
booking: state.booking,
|
||||
}))
|
||||
const refundableDate = dt(checkInDate)
|
||||
.subtract(1, "day")
|
||||
.locale(lang)
|
||||
.format("23:59, dddd, D MMMM YYYY")
|
||||
|
||||
const mustBeGuaranteed = !guaranteeInfo && booking.isGuaranteeable
|
||||
const quantityWithCard = useWatch({ name: "quantityWithCard" })
|
||||
const quantityWithPoints = useWatch({ name: "quantityWithPoints" })
|
||||
const currentPoints = user?.membership?.currentPoints ?? 0
|
||||
@@ -51,20 +50,22 @@ export default function ConfirmationStep({
|
||||
quantityWithPoints && selectedAncillary?.points
|
||||
? selectedAncillary.points * quantityWithPoints
|
||||
: null
|
||||
|
||||
const accordionTitle = intl.formatMessage({
|
||||
id: "myStay.guarantee.guaranteeInformation",
|
||||
defaultMessage:
|
||||
"By adding your card, you also guarantee your room booking for late arrival ",
|
||||
})
|
||||
|
||||
const accordionContent = intl.formatMessage({
|
||||
id: "myStay.guarantee.guaranteeInformation.content",
|
||||
defaultMessage:
|
||||
"The hotel will hold your booking, even if you arrive after 18:00. Your card will only be charged in the event of a no-show.",
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.modalContent}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "addAncillary.confirmationStep.refundPolicy",
|
||||
defaultMessage:
|
||||
"All ancillaries are fully refundable until {date}. Time selection and special requests are also modifiable.",
|
||||
},
|
||||
{ date: refundableDate }
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
{error && <Alert type={error.type} text={error.message} />}
|
||||
{!!quantityWithPoints && (
|
||||
<>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
@@ -107,118 +108,118 @@ export default function ConfirmationStep({
|
||||
)}
|
||||
{!!quantityWithCard && (
|
||||
<>
|
||||
<header>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h2>
|
||||
{intl.formatMessage({
|
||||
id: "addAncillary.confirmationStep.reserveWithCard",
|
||||
defaultMessage: "Reserve with Card",
|
||||
})}
|
||||
</h2>
|
||||
</Typography>
|
||||
</header>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<p>
|
||||
<Typography variant="Title/Subtitle/md">
|
||||
<h2>
|
||||
{intl.formatMessage({
|
||||
id: "addAncillary.confirmationStep.paymentAtCheckInInfo",
|
||||
defaultMessage:
|
||||
"Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.",
|
||||
id: "addAncillary.confirmationStep.reserveWithCard",
|
||||
defaultMessage: "Reserve with Card",
|
||||
})}
|
||||
</h2>
|
||||
</Typography>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "addAncillary.confirmationStep.refundPolicy",
|
||||
defaultMessage:
|
||||
"All ancillaries are fully refundable until {date}. Time selection and special requests are also modifiable.",
|
||||
},
|
||||
{ date: refundableDate }
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
{guaranteeInfo ? (
|
||||
<PaymentOptionsGroup name="paymentMethod">
|
||||
<PaymentOption
|
||||
value={PaymentMethodEnum.card}
|
||||
cardNumber={guaranteeInfo.maskedCard.slice(-4)}
|
||||
label={intl.formatMessage({
|
||||
id: "common.creditCard",
|
||||
defaultMessage: "Credit card",
|
||||
})}
|
||||
/>
|
||||
</PaymentOptionsGroup>
|
||||
) : (
|
||||
<>
|
||||
{error ? (
|
||||
<Alert type={error.type} text={error.message} />
|
||||
) : (
|
||||
<Alert
|
||||
type={AlertTypeEnum.Info}
|
||||
text={intl.formatMessage({
|
||||
id: "addAncillary.confirmationStep.guaranteeAddCard",
|
||||
defaultMessage:
|
||||
"By adding a card you also guarantee your room booking for late arrival.",
|
||||
})}
|
||||
<div className={styles.guarantee}>
|
||||
<div className={styles.paymentInfo}>
|
||||
<MaterialIcon icon="credit_card" size={24} color="CurrentColor" />
|
||||
<span>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "myStay.ancillary.guarantee.headingText",
|
||||
defaultMessage: "Payment will be made on check-in",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "myStay.ancillary.guarantee.infoText",
|
||||
defaultMessage:
|
||||
"The card is used to reserve your extras. You will be charged in case of no-show.",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</span>
|
||||
</div>
|
||||
{guaranteeInfo ? (
|
||||
<>
|
||||
<Divider />
|
||||
<Typography variant="Title/Overline/sm">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "payment.savedCard",
|
||||
defaultMessage: "Saved card",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
<PaymentOptionsGroup name="paymentMethod">
|
||||
<PaymentOption
|
||||
value={PaymentMethodEnum.card}
|
||||
cardNumber={guaranteeInfo.maskedCard.slice(-4)}
|
||||
label={intl.formatMessage({
|
||||
id: "common.card",
|
||||
defaultMessage: "Card",
|
||||
})}
|
||||
hideRadioButton
|
||||
/>
|
||||
</PaymentOptionsGroup>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className={styles.paymentInfo}>
|
||||
<MaterialIcon
|
||||
icon="credit_score"
|
||||
size={24}
|
||||
color="CurrentColor"
|
||||
/>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
id: "myStay.ancillary.guarantee.confirmationText",
|
||||
defaultMessage:
|
||||
"Confirm and provide your payment card details in the next step",
|
||||
})}
|
||||
</p>
|
||||
</Typography>
|
||||
</div>
|
||||
{mustBeGuaranteed && (
|
||||
<AccordionItem
|
||||
title={accordionTitle}
|
||||
type="inline"
|
||||
className={styles.accordionItem}
|
||||
>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{accordionContent}</p>
|
||||
</Typography>
|
||||
</AccordionItem>
|
||||
)}
|
||||
{savedCreditCards && <Divider />}
|
||||
<SelectPaymentMethod
|
||||
paymentMethods={(savedCreditCards ?? []).map((card) => ({
|
||||
...card,
|
||||
cardType: card.cardType as PaymentMethodEnum,
|
||||
}))}
|
||||
onChange={(method) => {
|
||||
trackUpdatePaymentMethod({ method })
|
||||
}}
|
||||
formName={"paymentMethod"}
|
||||
/>
|
||||
)}
|
||||
|
||||
<SelectPaymentMethod
|
||||
paymentMethods={(savedCreditCards ?? []).map((card) => ({
|
||||
...card,
|
||||
cardType: card.cardType as PaymentMethodEnum,
|
||||
}))}
|
||||
onChange={(method) => {
|
||||
trackUpdatePaymentMethod({ method })
|
||||
}}
|
||||
formName={"paymentMethod"}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className={styles.termsAndConditions}>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<p>
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: "addAncillary.confirmationStep.termsAndConditionsNotice",
|
||||
defaultMessage:
|
||||
"Yes, I accept the general <termsAndConditionsLink>Booking & Cancellation Terms</termsAndConditionsLink>, and understand that Scandic will process my personal data in accordance with <privacyPolicyLink>Scandic's Privacy policy</privacyPolicyLink>. There you can learn more about what data we process, your rights and where to turn if you have questions.",
|
||||
},
|
||||
{
|
||||
termsAndConditionsLink: (str) => (
|
||||
<TextLink
|
||||
typography="Link/sm"
|
||||
target="_blank"
|
||||
href={bookingTermsAndConditionsRoutes[lang]}
|
||||
>
|
||||
{str}
|
||||
</TextLink>
|
||||
),
|
||||
privacyPolicyLink: (str) => (
|
||||
<TextLink
|
||||
typography="Link/sm"
|
||||
target="_blank"
|
||||
href={privacyPolicyRoutes[lang]}
|
||||
>
|
||||
{str}
|
||||
</TextLink>
|
||||
),
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</Typography>
|
||||
<Checkbox
|
||||
name="termsAndConditions"
|
||||
registerOptions={{ required: true }}
|
||||
errorCodeMessages={{
|
||||
[ancillaryError.TERMS_NOT_ACCEPTED]: intl.formatMessage({
|
||||
id: "common.mustAcceptTermsError",
|
||||
defaultMessage: "You must accept the terms and conditions",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||
<span>
|
||||
{intl.formatMessage({
|
||||
id: "booking.acceptBookingTerms",
|
||||
defaultMessage: "I accept the booking and cancellation terms",
|
||||
})}
|
||||
</span>
|
||||
</Typography>
|
||||
</Checkbox>
|
||||
</div>
|
||||
<TermsAndConditions />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user