feat: SW-1583 Enabled reward night in booking widget

This commit is contained in:
Hrishikesh Vaipurkar
2025-02-27 11:41:04 +01:00
parent 6232ded991
commit 51b70f3032
12 changed files with 247 additions and 69 deletions

View File

@@ -0,0 +1,103 @@
"use client"
import { useCallback, useEffect, useRef } from "react"
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { ErrorCircleIcon } from "@/components/Icons"
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import styles from "./reward-night.module.css"
import type { BookingWidgetSchema } from "@/types/components/bookingWidget"
export function RewardNight() {
const intl = useIntl()
const {
setValue,
getValues,
formState: { errors },
trigger,
} = useFormContext<BookingWidgetSchema>()
const ref = useRef<HTMLDivElement | null>(null)
const reward = intl.formatMessage({ id: "Book Reward Night" })
const redemptionErr = errors["redemption"]
const bookingCode = getValues("bookingCode.value")
const isMultiRoomError = redemptionErr?.message?.indexOf("Multi-room") === 0
const errorInfoColor = isMultiRoomError ? "red" : "blue"
function validateBookingWidget(value: boolean) {
trigger("redemption")
if (value && bookingCode) {
setValue("bookingCode.value", "", { shouldValidate: true })
setTimeout(() => {
trigger("redemption")
}, 5000)
}
}
const resetOnMultiroomError = useCallback(() => {
if (isMultiRoomError) {
setValue("redemption", false, { shouldValidate: true })
}
}, [isMultiRoomError, setValue])
function closeOnBlur(evt: FocusEvent) {
const target = evt.relatedTarget as HTMLElement
if (ref.current && target && !ref.current.contains(target)) {
resetOnMultiroomError()
}
}
useEffect(() => {
const clearIfOutside = function (evt: Event) {
const target = evt.target as HTMLElement
if (ref.current && target && !ref.current.contains(target)) {
resetOnMultiroomError()
}
}
document.body.addEventListener("click", clearIfOutside)
return () => {
document.body.removeEventListener("click", clearIfOutside)
}
}, [resetOnMultiroomError, ref])
return (
<div ref={ref} onBlur={(e) => closeOnBlur(e.nativeEvent)}>
<Checkbox
hideError
name="redemption"
registerOptions={{
onChange: (e) => {
validateBookingWidget(e.target.value)
},
}}
>
<Caption color="uiTextMediumContrast" asChild>
<span>{reward}</span>
</Caption>
</Checkbox>
{redemptionErr && (
<div className={styles.errorContainer}>
<Caption
className={styles.error}
type="regular"
color={errorInfoColor}
>
<ErrorCircleIcon
color={errorInfoColor}
className={styles.errorIcon}
/>
{intl.formatMessage({ id: redemptionErr.message })}
</Caption>
{isMultiRoomError ? (
// ToDo: Replace with Remove extra rooms JSX element after SW-963 is merged
<Body>{"Remove extra rooms"}</Body>
) : null}
</div>
)}
</div>
)
}

View File

@@ -0,0 +1,20 @@
.errorContainer {
background: var(--Base-Surface-Primary-light-Normal);
border-radius: var(--Spacing-x-one-and-half);
display: grid;
gap: var(--Spacing-x1);
padding: var(--Spacing-x2);
position: absolute;
top: calc(100% + 16px);
width: 320px;
}
.error {
display: flex;
gap: var(--Spacing-x-half);
align-items: center;
}
.errorIcon {
min-width: 20px;
}

View File

@@ -2,12 +2,15 @@
import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl"
import { env } from "@/env/client"
import SkeletonShimmer from "@/components/SkeletonShimmer"
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import { Tooltip } from "@/components/TempDesignSystem/Tooltip"
import BookingCode from "../BookingCode"
import { RewardNight } from "../RewardNight"
import styles from "./voucher.module.css"
@@ -31,36 +34,44 @@ export default function Voucher() {
<BookingCode />
</div>
<div className={styles.options}>
<div className={styles.option}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="bottom"
arrow="left"
>
<Checkbox name="useBonus" registerOptions={{ disabled: true }}>
<Caption color="disabled" asChild>
<span>{bonus}</span>
</Caption>
</Checkbox>
{/* <InfoCircleIcon color="white" className={styles.infoIcon} /> Out of scope for this release */}
</Tooltip>
</div>
<div className={styles.option}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="bottom"
arrow="left"
>
<Checkbox name="useReward" registerOptions={{ disabled: true }}>
<Caption color="disabled" asChild>
<span>{reward}</span>
</Caption>
</Checkbox>
{/* <InfoCircleIcon color="white" className={styles.infoIcon} /> Out of scope for this release */}
</Tooltip>
</div>
{env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE ? (
<>
<div className={styles.option}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="bottom"
arrow="left"
>
<Checkbox name="useBonus" registerOptions={{ disabled: true }}>
<Caption color="disabled" asChild>
<span>{bonus}</span>
</Caption>
</Checkbox>
{/* <InfoCircleIcon color="white" className={styles.infoIcon} /> Out of scope for this release */}
</Tooltip>
</div>
<div className={styles.option}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="bottom"
arrow="left"
>
<Checkbox name="useReward" registerOptions={{ disabled: true }}>
<Caption color="disabled" asChild>
<span>{reward}</span>
</Caption>
</Checkbox>
{/* <InfoCircleIcon color="white" className={styles.infoIcon} /> Out of scope for this release */}
</Tooltip>
</div>
</>
) : (
<div className={styles.option}>
<RewardNight />
</div>
)}
</div>
</div>
)
@@ -87,16 +98,18 @@ export function VoucherSkeleton() {
<SkeletonShimmer width={"100%"} />
</div>
<div className={styles.options}>
{env.NEXT_PUBLIC_HIDE_FOR_NEXT_RELEASE ? null : (
<div className={styles.option}>
<Checkbox name="useBonus" registerOptions={{ disabled: true }}>
<Caption color="disabled" asChild>
<span>{bonus}</span>
</Caption>
</Checkbox>
</div>
)}
<div className={styles.option}>
<Checkbox name="useBonus" registerOptions={{ disabled: true }}>
<Caption color="disabled" asChild>
<span>{bonus}</span>
</Caption>
</Checkbox>
</div>
<div className={styles.option}>
<Checkbox name="useReward" registerOptions={{ disabled: true }}>
<Caption color="disabled" asChild>
<Checkbox name="redemption">
<Caption color="uiTextMediumContrast" asChild>
<span>{reward}</span>
</Caption>
</Checkbox>