Files
web/apps/scandic-web/components/HotelReservation/MyStay/GuaranteeLateArrival/index.tsx

220 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useRouter } from "next/navigation"
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { PaymentMethodEnum } from "@/constants/booking"
import {
bookingTermsAndConditions,
privacyPolicy,
} from "@/constants/currentWebHrefs"
import { guaranteeCallback } from "@/constants/routes/hotelReservation"
import { env } from "@/env/client"
import { useManageStayStore } from "@/stores/my-stay/manageStayStore"
import { useMyStayRoomDetailsStore } from "@/stores/my-stay/myStayRoomDetailsStore"
import LoadingSpinner from "@/components/LoadingSpinner"
import { ModalContentWithActions } from "@/components/Modal/ModalContentWithActions"
import Divider from "@/components/TempDesignSystem/Divider"
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import { toast } from "@/components/TempDesignSystem/Toasts"
import { useGuaranteeBooking } from "@/hooks/booking/useGuaranteeBooking"
import useLang from "@/hooks/useLang"
import { formatPrice } from "@/utils/numberFormatting"
import { trackGlaSaveCardAttempt } from "@/utils/tracking/myStay"
import MySavedCards from "../../EnterDetails/Payment/MySavedCards"
import PaymentOption from "../../EnterDetails/Payment/PaymentOption"
import { type GuaranteeFormData, paymentSchema } from "./schema"
import styles from "./guaranteeLateArrival.module.css"
import type { CreditCard } from "@/types/user"
export interface GuaranteeLateArrivalProps {
savedCreditCards: CreditCard[] | null
refId: string
}
export default function GuaranteeLateArrival({
savedCreditCards,
refId,
}: GuaranteeLateArrivalProps) {
const intl = useIntl()
const lang = useLang()
const router = useRouter()
const bookedRoom = useMyStayRoomDetailsStore((state) => state.bookedRoom)
const {
actions: { handleCloseView, handleCloseModal },
} = useManageStayStore()
const methods = useForm<GuaranteeFormData>({
defaultValues: {
paymentMethod: savedCreditCards?.length
? savedCreditCards[0].id
: PaymentMethodEnum.card,
termsAndConditions: false,
},
mode: "all",
reValidateMode: "onChange",
resolver: zodResolver(paymentSchema),
})
const guaranteeRedirectUrl = `${env.NEXT_PUBLIC_NODE_ENV === "development" ? `http://localhost:${env.NEXT_PUBLIC_PORT}` : ""}${guaranteeCallback(lang)}`
const { guaranteeBooking, isLoading, handleGuaranteeError } =
useGuaranteeBooking({
confirmationNumber: bookedRoom.confirmationNumber,
handleBookingCompleted: router.refresh,
})
if (isLoading) {
return (
<div className={styles.loading}>
<LoadingSpinner />
</div>
)
}
const handleGuaranteeLateArrival = (data: GuaranteeFormData) => {
const savedCreditCard = savedCreditCards?.find(
(card) => card.id === data.paymentMethod
)
trackGlaSaveCardAttempt(bookedRoom.hotelId, savedCreditCard, "yes")
if (bookedRoom.confirmationNumber) {
const card = savedCreditCard
? {
alias: savedCreditCard.alias,
expiryDate: savedCreditCard.expirationDate,
cardType: savedCreditCard.cardType,
}
: undefined
guaranteeBooking.mutate({
confirmationNumber: bookedRoom.confirmationNumber,
language: lang,
...(card !== undefined && { card }),
success: `${guaranteeRedirectUrl}?status=success&RefId=${encodeURIComponent(refId)}`,
error: `${guaranteeRedirectUrl}?status=error&RefId=${encodeURIComponent(refId)}`,
cancel: `${guaranteeRedirectUrl}?status=cancel&RefId=${encodeURIComponent(refId)}`,
})
} else {
handleGuaranteeError("No confirmation number")
toast.error(
intl.formatMessage({
id: "Something went wrong!",
})
)
}
}
return (
<FormProvider {...methods}>
<ModalContentWithActions
title={intl.formatMessage({ id: "Guarantee late arrival" })}
onClose={handleCloseModal}
content={
<>
<Caption>
{intl.formatMessage({
id: "Planning to arrive after 18.00? Secure your room by guaranteeing it with a credit card. Without the guarantee and in case of no-show, the room might be reallocated after 18:00.",
})}
</Caption>
<Caption type="bold">
{intl.formatMessage({
id: "In case of no-show you will be charged for the first night.",
})}
</Caption>
{savedCreditCards?.length ? (
<>
<MySavedCards savedCreditCards={savedCreditCards} />
<Body color="uiTextHighContrast" textTransform="bold">
{intl.formatMessage({ id: "OTHER" })}
</Body>
</>
) : null}
<PaymentOption
name="paymentMethod"
value={PaymentMethodEnum.card}
label={intl.formatMessage({ id: "Credit card" })}
/>
<div className={styles.termsAndConditions}>
<Typography variant="Body/Supporting text (caption)/smRegular">
<p>
{intl.formatMessage(
{
id: "By guaranteeing with any of the payment methods available, I accept the terms for this stay and the general <termsAndConditionsLink>Terms & Conditions</termsAndConditionsLink>, and understand Scandic will process my personal data for this stay in accordance with <privacyPolicyLink>Scandics Privacy Policy</privacyPolicyLink>. I accept Scandic requiring a valid credit card during my visit in case anything is left unpaid.",
},
{
termsAndConditionsLink: (str) => (
<Link
variant="underscored"
color="peach80"
target="_blank"
href={bookingTermsAndConditions[lang]}
>
{str}
</Link>
),
privacyPolicyLink: (str) => (
<Link
variant="underscored"
color="peach80"
target="_blank"
href={privacyPolicy[lang]}
>
{str}
</Link>
),
}
)}
</p>
</Typography>
<Checkbox name="termsAndConditions">
<Typography variant="Body/Supporting text (caption)/smRegular">
<span>
{intl.formatMessage({
id: "I accept the terms and conditions",
})}
</span>
</Typography>
</Checkbox>
</div>
<div className={styles.guaranteeCost}>
<div className={styles.guaranteeCostText}>
<Caption type="bold">
{intl.formatMessage({ id: "Guarantee cost" })}
</Caption>
<Caption color="uiTextHighContrast">
{intl.formatMessage({
id: "Your card will only be used for authorisation",
})}
</Caption>
</div>
<Divider variant="vertical" color="subtle" />
<Body textTransform="bold">
{formatPrice(intl, 0, bookedRoom.currencyCode)}
</Body>
</div>
</>
}
primaryAction={{
label: intl.formatMessage({ id: "Guarantee" }),
onClick: methods.handleSubmit(handleGuaranteeLateArrival),
intent: "primary",
}}
secondaryAction={{
label: intl.formatMessage({ id: "Back" }),
onClick: handleCloseView,
intent: "text",
}}
/>
</FormProvider>
)
}