Feat(SW-1274) modify date my stay * feat(SW-1676): Modify guest details step 1 * feat(SW-1676) Integration to api to update guest details * feat(SW-1676) Reuse of old modal * feat(SW-1676) updated modify guest * feat(SW-1676) cleanup * feat(SW-1274) modify stay modal and datepicker * feat(SW-1274) DatePicker from modify dates * feat(SW-1274) Modify dates fixes and merge conflicts * feat(SW-1274) handle modify for multiroom * feat(SW-1274) update manage stay * feat(SW-1274) fixed some comments * feat(SW-1274) use Modal instead * feat(SW-1274) fixed formatChildBedPreferences * feat(SW-1274) removed any as prop * feat(SW-1274) fix rebase conflicts * feat(SW-1274) fix flicker on modify modal * feat(SW-1274) CalendarButton * feat(SW-1274) fixed gap variable * feat(SW-1274) simplified code * feat(SW-1274) Split up DatePicker on mode * feat(SW-1274) Updated file structure for datepicker Approved-by: Arvid Norlin
220 lines
7.2 KiB
TypeScript
220 lines
7.2 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { useIntl } from "react-intl"
|
|
|
|
import { BookingStatusEnum } from "@/constants/booking"
|
|
import { dt } from "@/lib/dt"
|
|
|
|
import { BookingCodeIcon } from "@/components/Icons"
|
|
import CrossCircleIcon from "@/components/Icons/CrossCircle"
|
|
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
|
import Button from "@/components/TempDesignSystem/Button"
|
|
import Divider from "@/components/TempDesignSystem/Divider"
|
|
import IconChip from "@/components/TempDesignSystem/IconChip"
|
|
import Link from "@/components/TempDesignSystem/Link"
|
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
|
import { useGuaranteePaymentFailedToast } from "@/hooks/booking/useGuaranteePaymentFailedToast"
|
|
import useLang from "@/hooks/useLang"
|
|
import { formatPrice } from "@/utils/numberFormatting"
|
|
|
|
import ManageStay from "../ManageStay"
|
|
import { useMyStayRoomDetailsStore } from "../stores/myStayRoomDetailsStore"
|
|
import { useMyStayTotalPriceStore } from "../stores/myStayTotalPrice"
|
|
|
|
import styles from "./referenceCard.module.css"
|
|
|
|
import type { Hotel } from "@/types/hotel"
|
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
|
import { type CreditCard, type User } from "@/types/user"
|
|
|
|
interface ReferenceCardProps {
|
|
booking: BookingConfirmation["booking"]
|
|
hotel: Hotel
|
|
user: User | null
|
|
savedCreditCards: CreditCard[] | null
|
|
refId: string
|
|
}
|
|
|
|
export function ReferenceCard({
|
|
booking,
|
|
hotel,
|
|
user,
|
|
savedCreditCards,
|
|
refId,
|
|
}: ReferenceCardProps) {
|
|
const [bookingStatus, setBookingStatus] = useState(booking.reservationStatus)
|
|
const intl = useIntl()
|
|
const lang = useLang()
|
|
const { totalPrice, currencyCode } = useMyStayTotalPriceStore()
|
|
const { rooms } = useMyStayRoomDetailsStore()
|
|
|
|
const fromDate = rooms[0]
|
|
? dt(rooms[0].checkInDate).locale(lang)
|
|
: dt(booking.checkInDate).locale(lang)
|
|
const toDate = rooms[0]
|
|
? dt(rooms[0].checkOutDate).locale(lang)
|
|
: dt(booking.checkOutDate).locale(lang)
|
|
|
|
const isCancelled = bookingStatus === BookingStatusEnum.Cancelled
|
|
useGuaranteePaymentFailedToast()
|
|
|
|
const directionsUrl = `https://www.google.com/maps/dir/?api=1&destination=${hotel.location.latitude},${hotel.location.longitude}`
|
|
|
|
const adults =
|
|
booking.adults +
|
|
(booking.linkedReservations?.reduce(
|
|
(acc, linkedReservation) => acc + linkedReservation.adults,
|
|
0
|
|
) ?? 0)
|
|
|
|
const children =
|
|
booking.childrenAges.length +
|
|
(booking.linkedReservations?.reduce(
|
|
(acc, linkedReservation) => acc + linkedReservation.children,
|
|
0
|
|
) ?? 0)
|
|
|
|
const adultsMsg = intl.formatMessage(
|
|
{ id: "{adults, plural, one {# adult} other {# adults}}" },
|
|
{
|
|
adults: adults,
|
|
}
|
|
)
|
|
|
|
const childrenMsg = intl.formatMessage(
|
|
{
|
|
id: "{children, plural, one {# child} other {# children}}",
|
|
},
|
|
{
|
|
children: children,
|
|
}
|
|
)
|
|
|
|
const adultsOnlyMsg = adultsMsg
|
|
const adultsAndChildrenMsg = [adultsMsg, childrenMsg].join(", ")
|
|
|
|
return (
|
|
<div className={styles.referenceCard}>
|
|
<div className={styles.referenceRow}>
|
|
<Subtitle color="uiTextHighContrast" className={styles.titleMobile}>
|
|
{intl.formatMessage({ id: "Reference" })}
|
|
</Subtitle>
|
|
<Subtitle color="uiTextHighContrast" className={styles.titleDesktop}>
|
|
{isCancelled
|
|
? intl.formatMessage({ id: "Cancellation number" })
|
|
: intl.formatMessage({ id: "Reference number" })}
|
|
</Subtitle>
|
|
<Subtitle color="uiTextHighContrast">
|
|
{isCancelled
|
|
? booking.cancellationNumber
|
|
: booking.confirmationNumber}
|
|
</Subtitle>
|
|
</div>
|
|
<Divider color="primaryLightSubtle" className={styles.divider} />
|
|
<div className={styles.referenceRow}>
|
|
<Caption
|
|
textTransform="uppercase"
|
|
type="bold"
|
|
color="uiTextHighContrast"
|
|
>
|
|
{intl.formatMessage({ id: "Guests" })}
|
|
</Caption>
|
|
<Caption type="bold" color="uiTextHighContrast">
|
|
{children > 0 ? adultsAndChildrenMsg : adultsOnlyMsg}
|
|
</Caption>
|
|
</div>
|
|
<div className={styles.referenceRow}>
|
|
<Caption
|
|
textTransform="uppercase"
|
|
type="bold"
|
|
color="uiTextHighContrast"
|
|
>
|
|
{intl.formatMessage({ id: "Check-in" })}
|
|
</Caption>
|
|
<Caption type="bold" color="uiTextHighContrast">
|
|
{`${fromDate.format("dddd, D MMMM")} ${intl.formatMessage({ id: "from" })} ${fromDate.format("HH:mm")}`}
|
|
</Caption>
|
|
</div>
|
|
<div className={styles.referenceRow}>
|
|
<Caption
|
|
textTransform="uppercase"
|
|
type="bold"
|
|
color="uiTextHighContrast"
|
|
>
|
|
{intl.formatMessage({ id: "Check-out" })}
|
|
</Caption>
|
|
<Caption type="bold" color="uiTextHighContrast">
|
|
{`${toDate.format("dddd, D MMMM")} ${intl.formatMessage({ id: "until" })} ${toDate.format("HH:mm")}`}
|
|
</Caption>
|
|
</div>
|
|
<Divider color="primaryLightSubtle" className={styles.divider} />
|
|
<div className={styles.referenceRow}>
|
|
<Caption
|
|
textTransform="uppercase"
|
|
type="bold"
|
|
color="uiTextHighContrast"
|
|
>
|
|
{intl.formatMessage({ id: "Total" })}
|
|
</Caption>
|
|
|
|
{totalPrice ? (
|
|
<Caption type="bold" color="uiTextHighContrast">
|
|
{formatPrice(intl, totalPrice, currencyCode)}
|
|
</Caption>
|
|
) : (
|
|
<SkeletonShimmer width="50px" height="18px" />
|
|
)}
|
|
</div>
|
|
{booking?.bookingCode && (
|
|
<div className={styles.referenceRow}>
|
|
<Caption>{intl.formatMessage({ id: "Booking code" })}</Caption>
|
|
<IconChip color={"blue"} icon={<BookingCodeIcon color="blue" />}>
|
|
<Caption className={styles.bookingCode} color="blue">
|
|
<strong>{intl.formatMessage({ id: "Booking code" })}</strong>
|
|
{booking.bookingCode}
|
|
</Caption>
|
|
</IconChip>
|
|
</div>
|
|
)}
|
|
{isCancelled && (
|
|
<div className={styles.referenceRow}>
|
|
<IconChip
|
|
color={"red"}
|
|
icon={<CrossCircleIcon width={20} height={20} color="red" />}
|
|
>
|
|
<Caption color={"red"}>
|
|
<strong>{intl.formatMessage({ id: "Status" })}:</strong>{" "}
|
|
{intl.formatMessage({ id: "Cancelled" })}
|
|
</Caption>
|
|
</IconChip>
|
|
</div>
|
|
)}
|
|
<div className={styles.actionArea}>
|
|
<ManageStay
|
|
booking={booking}
|
|
hotel={hotel}
|
|
user={user}
|
|
setBookingStatus={setBookingStatus}
|
|
bookingStatus={bookingStatus}
|
|
savedCreditCards={savedCreditCards}
|
|
refId={refId}
|
|
/>
|
|
<Button fullWidth intent="secondary" asChild>
|
|
<Link href={directionsUrl} target="_blank">
|
|
{intl.formatMessage({ id: "Get directions" })}
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
{booking.isModifiable && (
|
|
<Caption className={styles.note} color="uiTextHighContrast">
|
|
{booking.rateDefinition.generalTerms.map((term) => (
|
|
<span key={term}>{term} </span>
|
|
))}
|
|
</Caption>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|