Merged in feat/SW-1368-1369-Guarantee-late-arrival (pull request #1512)

Feat/SW-1368 1369 Guarantee late arrival

* feat(SW-1368-SW-1369): guarantee late arrival for confirmation page and my stay

* feat(SW-1368-SW-1369): guarantee late arrival updated design

* feat(SW-1368-SW-1369): add translations

* feat(SW-1368-SW-1369): add translations

* feat(SW-1368-SW-1369): fix merge with master

* feat(SW-1368-SW-1369): add translations

* feat(SW-1368-SW-1369): add redirect with refId

* feat(SW-1368-SW-1369): if booking completed redirect to confirmation page

* feat(SW-1368-SW-1369): fix comments pr

* feat(SW-1368-SW-1369): fix comments pr

* feat(SW-1368-SW-1369): fix rebase master

* feat(SW-1368-SW-1369): fix duplicate flex rate check

* feat(SW-1368-SW-1369): if any room is flex, card must be used

* feat(SW-1368-SW-1369): move callback route

* feat(SW-1368-SW-1369): top align checkbox

* feat(SW-1368-SW-1369): top align checkbox


Approved-by: Tobias Johansson
Approved-by: Niclas Edenvin
This commit is contained in:
Bianca Widstam
2025-03-14 10:43:14 +00:00
parent 8ca862e32c
commit abd401c4f4
47 changed files with 1274 additions and 166 deletions

View File

@@ -0,0 +1,64 @@
.container {
display: flex;
flex-direction: column;
gap: var(--Spacing-x3);
}
.title {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--Spacing-x-half);
}
.guaranteeContainer {
display: flex;
flex-direction: column;
gap: var(--Spacing-x-one-and-half);
background-color: var(--Base-Surface-Primary-light-Normal);
border-radius: var(--Corner-radius-Medium);
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
width: min(512px, 100%);
}
.checkbox {
display: flex;
gap: var(--Spacing-x-one-and-half);
}
.checkboxContainer {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
padding: 0 var(--Spacing-x2);
width: min(800px, 100%);
}
.modalContainer {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
align-items: center;
width: 100%;
}
.infoButton {
display: flex;
gap: var(--Space-x05);
outline: none;
}
.modalText {
text-align: center;
}
.closeButton {
margin-top: var(--Space-x15);
width: min(164px, 100%);
outline: none;
}
@media screen and (min-width: 768px) {
.modalContainer {
width: 552px;
}
}

View File

@@ -0,0 +1,180 @@
"use client"
import { useState } from "react"
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { Button } from "@scandic-hotels/design-system/Button"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { PaymentMethodEnum } from "@/constants/booking"
import {
bookingTermsAndConditions,
privacyPolicy,
} from "@/constants/currentWebHrefs"
import { InfoCircleIcon } from "@/components/Icons"
import Modal from "@/components/Modal"
import Divider from "@/components/TempDesignSystem/Divider"
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
import Link from "@/components/TempDesignSystem/Link"
import useLang from "@/hooks/useLang"
import MySavedCards from "../Payment/MySavedCards"
import PaymentOption from "../Payment/PaymentOption"
import styles from "./confirm.module.css"
import type { CreditCard } from "@/types/user"
interface ConfirmBookingProps {
savedCreditCards: CreditCard[] | null
}
export default function ConfirmBooking({
savedCreditCards,
}: ConfirmBookingProps) {
const intl = useIntl()
const lang = useLang()
const [isModalOpen, setModalOpen] = useState(false)
const { watch } = useFormContext()
const guarantee = watch("guarantee")
return (
<div className={styles.container}>
<div className={styles.guaranteeContainer}>
<div className={styles.title}>
<div className={styles.checkbox}>
<Checkbox name="guarantee" />
<Typography variant="Body/Paragraph/mdBold">
<p>
{intl.formatMessage({
id: "Guarantee room for late arrival",
})}
</p>
</Typography>
</div>
<Button
variant="Text"
size="Small"
typography="Body/Supporting text (caption)/smBold"
className={styles.infoButton}
onPress={() => setModalOpen(true)}
>
<InfoCircleIcon
width={20}
height={20}
color="uiTextMediumContrast"
/>
{intl.formatMessage({ id: "How does it work" })}
</Button>
<Modal isOpen={isModalOpen} onToggle={() => setModalOpen(false)}>
<div className={styles.modalContainer}>
<Typography variant="Title/smRegular">
<h3>
{intl.formatMessage({ id: "Guarantee for late arrival" })}
</h3>
</Typography>
<Typography variant="Body/Lead text">
<p className={styles.modalText}>
{intl.formatMessage({
id: "When guaranteeing your booking with a credit card, we will hold the booking until 07:00 the day after check-in.",
})}
</p>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p className={styles.modalText}>
{intl.formatMessage({
id: "In case of a no-show, your credit card will be charged for the first night.",
})}
</p>
</Typography>
<Button
typography="Body/Paragraph/mdBold"
variant="Secondary"
size="Small"
onPress={() => setModalOpen(false)}
className={styles.closeButton}
>
{intl.formatMessage({ id: "Close" })}
</Button>
</div>
</Modal>
</div>
<Divider color="subtle" />
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage({
id: "I may arrive later than 18:00 and want to guarantee my booking with a credit card.",
})}
</p>
</Typography>
{savedCreditCards?.length && guarantee ? (
<MySavedCards savedCreditCards={savedCreditCards} />
) : null}
{guarantee && (
<>
{savedCreditCards?.length && (
<Typography variant="Title/Overline/sm">
<h4>{intl.formatMessage({ id: "OTHER" })}</h4>
</Typography>
)}
<PaymentOption
name="paymentMethod"
value={PaymentMethodEnum.card}
label={intl.formatMessage({ id: "Credit card" })}
/>
</>
)}
</div>
<div className={styles.checkboxContainer}>
<Checkbox name="smsConfirmation">
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage({
id: "I would like to get my booking confirmation via sms",
})}
</p>
</Typography>
</Checkbox>
<div className={styles.checkbox}>
<Checkbox name="termsAndConditions" topAlign>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage(
{
id: "By paying with any of the payment methods available, I accept the terms for this booking and the general <termsAndConditionsLink>Terms & Conditions</termsAndConditionsLink>, and understand that Scandic will process my personal data for this booking in accordance with <privacyPolicyLink>Scandic's Privacy policy</privacyPolicyLink>. I also accept that Scandic require a valid credit card during my visit in case anything is left unpaid.",
},
{
termsAndConditionsLink: (str) => (
<Link
className={styles.link}
variant="underscored"
href={bookingTermsAndConditions[lang]}
target="_blank"
>
{str}
</Link>
),
privacyPolicyLink: (str) => (
<Link
className={styles.link}
variant="underscored"
href={privacyPolicy[lang]}
target="_blank"
>
{str}
</Link>
),
}
)}
</p>
</Typography>
</Checkbox>
</div>
</div>
</div>
)
}