Merged in fix/hide-payment-if-only-points (pull request #1741)

Feat(SW-1943): add new design for pay ancillaries with points

* fix: hide card and payment info if only quantity with points is selected

* feat(SW-1943): add new design for pay ancillaries with points

* feat(SW-1943): add missing translation

* feat(SW-1943): fix rebase

* feat(SW-1943): remove console log


Approved-by: Linus Flood
Approved-by: Matilda Landström
This commit is contained in:
Bianca Widstam
2025-04-10 06:18:02 +00:00
parent 8f4834a6ef
commit 77c03905e4
13 changed files with 129 additions and 47 deletions

View File

@@ -9,3 +9,17 @@
gap: var(--Space-x2);
color: var(--Text-Secondary);
}
.totalPointsContainer {
display: flex;
justify-content: space-between;
background-color: var(--Surface-Brand-Primary-2-OnSurface-Accent);
padding: var(--Space-x1) var(--Space-x15);
border-radius: var(--Corner-radius-Medium);
}
.totalPoints {
display: flex;
gap: var(--Space-x15);
align-items: center;
}

View File

@@ -1,5 +1,7 @@
import { useWatch } from "react-hook-form"
import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { PaymentMethodEnum } from "@/constants/booking"
@@ -24,18 +26,28 @@ import { AlertTypeEnum } from "@/types/enums/alert"
export default function ConfirmationStep({
savedCreditCards,
user,
}: ConfirmationStepProps) {
const intl = useIntl()
const lang = useLang()
const { checkInDate, guaranteeInfo } = useAddAncillaryStore((state) => ({
checkInDate: state.booking.checkInDate,
guaranteeInfo: state.booking.guaranteeInfo,
}))
const { checkInDate, guaranteeInfo, selectedAncillary } =
useAddAncillaryStore((state) => ({
checkInDate: state.booking.checkInDate,
guaranteeInfo: state.booking.guaranteeInfo,
selectedAncillary: state.selectedAncillary,
}))
const refundableDate = dt(checkInDate)
.subtract(1, "day")
.locale(lang)
.format("23:59, dddd, D MMMM YYYY")
const quantityWithCard = useWatch({ name: "quantityWithCard" })
const quantityWithPoints = useWatch({ name: "quantityWithPoints" })
const currentPoints = user?.membership?.currentPoints ?? 0
const totalPoints =
quantityWithPoints && selectedAncillary?.points
? selectedAncillary.points * quantityWithPoints
: null
return (
<div className={styles.modalContent}>
<Typography variant="Body/Paragraph/mdRegular">
@@ -48,54 +60,91 @@ export default function ConfirmationStep({
)}
</p>
</Typography>
<header>
<Typography variant="Title/Subtitle/md">
<h2>
{intl.formatMessage({
id: "Reserve with Card",
})}
</h2>
</Typography>
</header>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage({
id: "Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.",
})}
</p>
</Typography>
{guaranteeInfo ? (
<PaymentOption
name="paymentMethod"
value={PaymentMethodEnum.card}
cardNumber={guaranteeInfo.maskedCard.slice(-4)}
label={intl.formatMessage({ id: "Credit card" })}
/>
) : (
{!!quantityWithPoints && (
<>
<Alert
type={AlertTypeEnum.Info}
text={intl.formatMessage({
id: "By adding a card you also guarantee your room booking for late arrival.",
})}
/>
{savedCreditCards?.length && (
<MySavedCards savedCreditCards={savedCreditCards} />
)}
<>
{savedCreditCards?.length && (
<Typography variant="Title/Subtitle/md">
<h2>
{intl.formatMessage({
id: "Points to be deducted now",
})}
</h2>
</Typography>
<div className={styles.totalPointsContainer}>
<div className={styles.totalPoints}>
<MaterialIcon icon="diamond" />
<Typography variant="Title/Overline/sm">
<h4>{intl.formatMessage({ id: "OTHER" })}</h4>
<h2>
{intl.formatMessage(
{ id: "{amount} points" },
{ amount: totalPoints }
)}
</h2>
</Typography>
)}
</div>
<Typography variant="Body/Paragraph/mdRegular">
<p>
{intl.formatMessage(
{ id: "{amount} points available" },
{ amount: currentPoints }
)}
</p>
</Typography>
</div>
</>
)}
{!!quantityWithCard && (
<>
<header>
<Typography variant="Title/Subtitle/md">
<h2>
{intl.formatMessage({
id: "Reserve with Card",
})}
</h2>
</Typography>
</header>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage({
id: "Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.",
})}
</p>
</Typography>
{guaranteeInfo ? (
<PaymentOption
name="paymentMethod"
value={PaymentMethodEnum.card}
cardNumber={guaranteeInfo.maskedCard.slice(-4)}
label={intl.formatMessage({ id: "Credit card" })}
/>
</>
) : (
<>
<Alert
type={AlertTypeEnum.Info}
text={intl.formatMessage({
id: "By adding a card you also guarantee your room booking for late arrival.",
})}
/>
{savedCreditCards?.length && (
<MySavedCards savedCreditCards={savedCreditCards} />
)}
<>
{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 className={styles.termsAndConditions}>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>

View File

@@ -22,5 +22,5 @@ export default function Desktop({ user, savedCreditCards }: StepsProps) {
return <DeliveryMethodStep />
}
return <ConfirmationStep savedCreditCards={savedCreditCards} />
return <ConfirmationStep savedCreditCards={savedCreditCards} user={user} />
}

View File

@@ -23,5 +23,5 @@ export default function Mobile({ user, savedCreditCards }: StepsProps) {
</>
)
}
return <ConfirmationStep savedCreditCards={savedCreditCards} />
return <ConfirmationStep savedCreditCards={savedCreditCards} user={user} />
}

View File

@@ -264,8 +264,10 @@ export default function AddAncillaryFlowModal({
toast.error(intl.formatMessage({ id: "Something went wrong!" }))
return
}
const shouldSkipGuarantee =
booking.guaranteeInfo || (data.quantityWithCard ?? 0) <= 0
if (booking.guaranteeInfo) {
if (shouldSkipGuarantee) {
handleAncillarySubmission(data, packagesToAdd)
} else {
handleGuaranteePayment(data, packagesToAdd)