feat(SW-866): download invoice
This commit is contained in:
@@ -1,20 +1,8 @@
|
|||||||
import { Suspense } from "react"
|
|
||||||
|
|
||||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
||||||
|
|
||||||
import Header from "@/components/HotelReservation/BookingConfirmation/Header"
|
import BookingConfirmation from "@/components/HotelReservation/BookingConfirmation"
|
||||||
import HotelDetails from "@/components/HotelReservation/BookingConfirmation/HotelDetails"
|
|
||||||
import PaymentDetails from "@/components/HotelReservation/BookingConfirmation/PaymentDetails"
|
|
||||||
import Promos from "@/components/HotelReservation/BookingConfirmation/Promos"
|
|
||||||
import Receipt from "@/components/HotelReservation/BookingConfirmation/Receipt"
|
|
||||||
import Rooms from "@/components/HotelReservation/BookingConfirmation/Rooms"
|
|
||||||
import SidePanel from "@/components/HotelReservation/SidePanel"
|
|
||||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
|
||||||
import Divider from "@/components/TempDesignSystem/Divider"
|
|
||||||
import { setLang } from "@/i18n/serverContext"
|
import { setLang } from "@/i18n/serverContext"
|
||||||
|
|
||||||
import styles from "./page.module.css"
|
|
||||||
|
|
||||||
import type { LangParams, PageArgs } from "@/types/params"
|
import type { LangParams, PageArgs } from "@/types/params"
|
||||||
|
|
||||||
export default async function BookingConfirmationPage({
|
export default async function BookingConfirmationPage({
|
||||||
@@ -22,29 +10,12 @@ export default async function BookingConfirmationPage({
|
|||||||
searchParams,
|
searchParams,
|
||||||
}: PageArgs<LangParams, { confirmationNumber: string }>) {
|
}: PageArgs<LangParams, { confirmationNumber: string }>) {
|
||||||
setLang(params.lang)
|
setLang(params.lang)
|
||||||
void getBookingConfirmation(searchParams.confirmationNumber)
|
const bookingConfirmationPromise = getBookingConfirmation(
|
||||||
|
searchParams.confirmationNumber
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<main className={styles.main}>
|
<BookingConfirmation
|
||||||
<Suspense fallback={<LoadingSpinner fullPage />}>
|
bookingConfirmationPromise={bookingConfirmationPromise}
|
||||||
<Header confirmationNumber={searchParams.confirmationNumber} />
|
/>
|
||||||
<div className={styles.booking}>
|
|
||||||
<Rooms confirmationNumber={searchParams.confirmationNumber} />
|
|
||||||
<PaymentDetails
|
|
||||||
confirmationNumber={searchParams.confirmationNumber}
|
|
||||||
/>
|
|
||||||
<Divider color="primaryLightSubtle" />
|
|
||||||
<HotelDetails confirmationNumber={searchParams.confirmationNumber} />
|
|
||||||
<Promos />
|
|
||||||
<div className={styles.mobileReceipt}>
|
|
||||||
<Receipt confirmationNumber={searchParams.confirmationNumber} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<aside className={styles.aside}>
|
|
||||||
<SidePanel variant="receipt">
|
|
||||||
<Receipt confirmationNumber={searchParams.confirmationNumber} />
|
|
||||||
</SidePanel>
|
|
||||||
</aside>
|
|
||||||
</Suspense>
|
|
||||||
</main>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
import { useReactToPrint } from "react-to-print"
|
||||||
|
|
||||||
import { DownloadIcon } from "@/components/Icons"
|
import { DownloadIcon } from "@/components/Icons"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
|
|
||||||
export default function DownloadInvoice() {
|
import type { DownloadInvoiceProps } from "@/types/components/hotelReservation/bookingConfirmation/actions/downloadInvoice"
|
||||||
|
|
||||||
|
export default function DownloadInvoice({ mainRef }: DownloadInvoiceProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
const reactToPrintFn = useReactToPrint({ contentRef: mainRef })
|
||||||
|
|
||||||
function downloadBooking() {
|
function downloadBooking() {
|
||||||
window.print()
|
reactToPrintFn()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
"use client"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
import AddToCalendar from "./Actions/AddToCalendar"
|
import AddToCalendar from "./Actions/AddToCalendar"
|
||||||
import DownloadInvoice from "./Actions/DownloadInvoice"
|
import DownloadInvoice from "./Actions/DownloadInvoice"
|
||||||
@@ -14,13 +14,14 @@ import styles from "./header.module.css"
|
|||||||
|
|
||||||
import type { EventAttributes } from "ics"
|
import type { EventAttributes } from "ics"
|
||||||
|
|
||||||
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
import type { BookingConfirmationHeaderProps } from "@/types/components/hotelReservation/bookingConfirmation/header"
|
||||||
|
|
||||||
export default async function Header({
|
export default function Header({
|
||||||
confirmationNumber,
|
booking,
|
||||||
}: BookingConfirmationProps) {
|
hotel,
|
||||||
const intl = await getIntl()
|
mainRef,
|
||||||
const { booking, hotel } = await getBookingConfirmation(confirmationNumber)
|
}: BookingConfirmationHeaderProps) {
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
const text = intl.formatMessage<React.ReactNode>(
|
const text = intl.formatMessage<React.ReactNode>(
|
||||||
{ id: "booking.confirmation.text" },
|
{ id: "booking.confirmation.text" },
|
||||||
@@ -70,7 +71,7 @@ export default async function Header({
|
|||||||
hotelName={hotel.name}
|
hotelName={hotel.name}
|
||||||
/>
|
/>
|
||||||
<ManageBooking />
|
<ManageBooking />
|
||||||
<DownloadInvoice />
|
<DownloadInvoice mainRef={mainRef} />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
"use client"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
import { Toast } from "@/components/TempDesignSystem/Toasts"
|
import { Toast } from "@/components/TempDesignSystem/Toasts"
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
import styles from "./hotelDetails.module.css"
|
import styles from "./hotelDetails.module.css"
|
||||||
|
|
||||||
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
import type { BookingConfirmationHotelDetailsProps } from "@/types/components/hotelReservation/bookingConfirmation/hotelDetails"
|
||||||
|
|
||||||
export default async function HotelDetails({
|
export default function HotelDetails({
|
||||||
confirmationNumber,
|
hotel,
|
||||||
}: BookingConfirmationProps) {
|
}: BookingConfirmationHotelDetailsProps) {
|
||||||
const intl = await getIntl()
|
const intl = useIntl()
|
||||||
const { hotel } = await getBookingConfirmation(confirmationNumber)
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.details}>
|
<div className={styles.details}>
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
|
"use client"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { dt } from "@/lib/dt"
|
import { dt } from "@/lib/dt"
|
||||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
|
||||||
|
|
||||||
import { CreditCardAddIcon } from "@/components/Icons"
|
import { CreditCardAddIcon } from "@/components/Icons"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
import { getIntl } from "@/i18n"
|
import useLang from "@/hooks/useLang"
|
||||||
import { getLang } from "@/i18n/serverContext"
|
|
||||||
|
|
||||||
import styles from "./paymentDetails.module.css"
|
import styles from "./paymentDetails.module.css"
|
||||||
|
|
||||||
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
import type { BookingConfirmationPaymentDetailsProps } from "@/types/components/hotelReservation/bookingConfirmation/paymentDetails"
|
||||||
|
|
||||||
export default async function PaymentDetails({
|
export default function PaymentDetails({
|
||||||
confirmationNumber,
|
booking,
|
||||||
}: BookingConfirmationProps) {
|
}: BookingConfirmationPaymentDetailsProps) {
|
||||||
const intl = await getIntl()
|
const intl = useIntl()
|
||||||
const lang = getLang()
|
const lang = useLang()
|
||||||
const { booking } = await getBookingConfirmation(confirmationNumber)
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.details}>
|
<div className={styles.details}>
|
||||||
<Subtitle color="uiTextHighContrast" type="two">
|
<Subtitle color="uiTextHighContrast" type="two">
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { getIntl } from "@/i18n"
|
"use client"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import Promo from "./Promo"
|
import Promo from "./Promo"
|
||||||
|
|
||||||
import styles from "./promos.module.css"
|
import styles from "./promos.module.css"
|
||||||
|
|
||||||
export default async function Promos() {
|
export default function Promos() {
|
||||||
const intl = await getIntl()
|
const intl = useIntl()
|
||||||
return (
|
return (
|
||||||
<div className={styles.promos}>
|
<div className={styles.promos}>
|
||||||
<Promo
|
<Promo
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
"use client"
|
||||||
import { notFound } from "next/navigation"
|
import { notFound } from "next/navigation"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
|
||||||
|
|
||||||
import { ChevronRightSmallIcon, InfoCircleIcon } from "@/components/Icons"
|
import { ChevronRightSmallIcon, InfoCircleIcon } from "@/components/Icons"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
@@ -9,21 +9,20 @@ import Link from "@/components/TempDesignSystem/Link"
|
|||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
import { getBookedHotelRoom } from "@/utils/getBookedHotelRoom"
|
|
||||||
|
|
||||||
import styles from "./receipt.module.css"
|
import styles from "./receipt.module.css"
|
||||||
|
|
||||||
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
import { BookingConfirmationReceiptProps } from "@/types/components/hotelReservation/bookingConfirmation/receipt"
|
||||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||||
|
|
||||||
export default async function Receipt({
|
export default function Receipt({
|
||||||
confirmationNumber,
|
booking,
|
||||||
}: BookingConfirmationProps) {
|
hotel,
|
||||||
const intl = await getIntl()
|
room,
|
||||||
const { booking, hotel } = await getBookingConfirmation(confirmationNumber)
|
}: BookingConfirmationReceiptProps) {
|
||||||
const roomAndBed = getBookedHotelRoom(hotel, booking.roomTypeCode ?? "")
|
const intl = useIntl()
|
||||||
if (!roomAndBed) {
|
|
||||||
|
if (!room) {
|
||||||
return notFound()
|
return notFound()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ export default async function Receipt({
|
|||||||
<Subtitle type="two">{intl.formatMessage({ id: "Summary" })}</Subtitle>
|
<Subtitle type="two">{intl.formatMessage({ id: "Summary" })}</Subtitle>
|
||||||
<article className={styles.room}>
|
<article className={styles.room}>
|
||||||
<header className={styles.roomHeader}>
|
<header className={styles.roomHeader}>
|
||||||
<Body color="uiTextHighContrast">{roomAndBed.name}</Body>
|
<Body color="uiTextHighContrast">{room.name}</Body>
|
||||||
{booking.rateDefinition.isMemberRate ? (
|
{booking.rateDefinition.isMemberRate ? (
|
||||||
<div className={styles.memberPrice}>
|
<div className={styles.memberPrice}>
|
||||||
<Body color="uiTextPlaceholder">
|
<Body color="uiTextPlaceholder">
|
||||||
@@ -82,9 +81,7 @@ export default async function Receipt({
|
|||||||
</Link>
|
</Link>
|
||||||
</header>
|
</header>
|
||||||
<div className={styles.entry}>
|
<div className={styles.entry}>
|
||||||
<Body color="uiTextHighContrast">
|
<Body color="uiTextHighContrast">{room.bedType.description}</Body>
|
||||||
{roomAndBed.bedType.description}
|
|
||||||
</Body>
|
|
||||||
<Body color="uiTextHighContrast">
|
<Body color="uiTextHighContrast">
|
||||||
{intl.formatNumber(0, {
|
{intl.formatNumber(0, {
|
||||||
currency: booking.currencyCode,
|
currency: booking.currencyCode,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
"use client"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { dt } from "@/lib/dt"
|
import { dt } from "@/lib/dt"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -10,16 +13,15 @@ import Link from "@/components/TempDesignSystem/Link"
|
|||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
import { getIntl } from "@/i18n"
|
import useLang from "@/hooks/useLang"
|
||||||
import { getLang } from "@/i18n/serverContext"
|
|
||||||
|
|
||||||
import styles from "./room.module.css"
|
import styles from "./room.module.css"
|
||||||
|
|
||||||
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/room"
|
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/rooms/room"
|
||||||
|
|
||||||
export default async function Room({ booking, img, roomName }: RoomProps) {
|
export default function Room({ booking, img, roomName }: RoomProps) {
|
||||||
const intl = await getIntl()
|
const intl = useIntl()
|
||||||
const lang = getLang()
|
const lang = useLang()
|
||||||
|
|
||||||
const fromDate = dt(booking.checkInDate).locale(lang)
|
const fromDate = dt(booking.checkInDate).locale(lang)
|
||||||
const toDate = dt(booking.checkOutDate).locale(lang)
|
const toDate = dt(booking.checkOutDate).locale(lang)
|
||||||
|
|||||||
@@ -1,30 +1,23 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
import { notFound } from "next/navigation"
|
import { notFound } from "next/navigation"
|
||||||
|
|
||||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
|
||||||
|
|
||||||
import { getBookedHotelRoom } from "@/utils/getBookedHotelRoom"
|
|
||||||
|
|
||||||
import Room from "./Room"
|
import Room from "./Room"
|
||||||
|
|
||||||
import styles from "./rooms.module.css"
|
import styles from "./rooms.module.css"
|
||||||
|
|
||||||
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
import type { BookingConfirmationRoomsProps } from "@/types/components/hotelReservation/bookingConfirmation/rooms"
|
||||||
|
|
||||||
export default async function Rooms({
|
export default function Rooms({
|
||||||
confirmationNumber,
|
booking,
|
||||||
}: BookingConfirmationProps) {
|
room,
|
||||||
const { booking, hotel } = await getBookingConfirmation(confirmationNumber)
|
}: BookingConfirmationRoomsProps) {
|
||||||
const roomAndBed = getBookedHotelRoom(hotel, booking.roomTypeCode ?? "")
|
if (!room) {
|
||||||
if (!roomAndBed) {
|
|
||||||
return notFound()
|
return notFound()
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<section className={styles.rooms}>
|
<section className={styles.rooms}>
|
||||||
<Room
|
<Room booking={booking} img={room.images[0]} roomName={room.name} />
|
||||||
booking={booking}
|
|
||||||
img={roomAndBed.images[0]}
|
|
||||||
roomName={roomAndBed.name}
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,4 +39,4 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-area: receipt;
|
grid-area: receipt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
57
components/HotelReservation/BookingConfirmation/index.tsx
Normal file
57
components/HotelReservation/BookingConfirmation/index.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
"use client"
|
||||||
|
import { use, useRef } from "react"
|
||||||
|
|
||||||
|
import Header from "@/components/HotelReservation/BookingConfirmation/Header"
|
||||||
|
import HotelDetails from "@/components/HotelReservation/BookingConfirmation/HotelDetails"
|
||||||
|
import PaymentDetails from "@/components/HotelReservation/BookingConfirmation/PaymentDetails"
|
||||||
|
import Promos from "@/components/HotelReservation/BookingConfirmation/Promos"
|
||||||
|
import Receipt from "@/components/HotelReservation/BookingConfirmation/Receipt"
|
||||||
|
import Rooms from "@/components/HotelReservation/BookingConfirmation/Rooms"
|
||||||
|
import SidePanel from "@/components/HotelReservation/SidePanel"
|
||||||
|
import Divider from "@/components/TempDesignSystem/Divider"
|
||||||
|
|
||||||
|
import styles from "./confirmation.module.css"
|
||||||
|
|
||||||
|
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
||||||
|
|
||||||
|
export default function BookingConfirmation({
|
||||||
|
bookingConfirmationPromise,
|
||||||
|
}: BookingConfirmationProps) {
|
||||||
|
const bookingConfirmation = use(bookingConfirmationPromise)
|
||||||
|
const mainRef = useRef<HTMLElement | null>(null)
|
||||||
|
return (
|
||||||
|
<main className={styles.main} ref={mainRef}>
|
||||||
|
<Header
|
||||||
|
booking={bookingConfirmation.booking}
|
||||||
|
hotel={bookingConfirmation.hotel}
|
||||||
|
mainRef={mainRef}
|
||||||
|
/>
|
||||||
|
<div className={styles.booking}>
|
||||||
|
<Rooms
|
||||||
|
booking={bookingConfirmation.booking}
|
||||||
|
room={bookingConfirmation.room}
|
||||||
|
/>
|
||||||
|
<PaymentDetails booking={bookingConfirmation.booking} />
|
||||||
|
<Divider color="primaryLightSubtle" />
|
||||||
|
<HotelDetails hotel={bookingConfirmation.hotel} />
|
||||||
|
<Promos />
|
||||||
|
<div className={styles.mobileReceipt}>
|
||||||
|
<Receipt
|
||||||
|
booking={bookingConfirmation.booking}
|
||||||
|
hotel={bookingConfirmation.hotel}
|
||||||
|
room={bookingConfirmation.room}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<aside className={styles.aside}>
|
||||||
|
<SidePanel variant="receipt">
|
||||||
|
<Receipt
|
||||||
|
booking={bookingConfirmation.booking}
|
||||||
|
hotel={bookingConfirmation.hotel}
|
||||||
|
room={bookingConfirmation.room}
|
||||||
|
/>
|
||||||
|
</SidePanel>
|
||||||
|
</aside>
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -54,6 +54,7 @@
|
|||||||
"react-hook-form": "^7.51.2",
|
"react-hook-form": "^7.51.2",
|
||||||
"react-international-phone": "^4.2.6",
|
"react-international-phone": "^4.2.6",
|
||||||
"react-intl": "^6.6.8",
|
"react-intl": "^6.6.8",
|
||||||
|
"react-to-print": "^3.0.2",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"sonner": "^1.7.0",
|
"sonner": "^1.7.0",
|
||||||
"superjson": "^2.2.1",
|
"superjson": "^2.2.1",
|
||||||
@@ -17417,6 +17418,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-to-print": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-FS/Z4LLq0bgWaxd7obygFQ8yRFdKW74iE8fIVjFFsPJWIXmuL8CIO+4me1Hj44lrlxQ00gscSNb3BRM8olbwXg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ~19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/readable-stream": {
|
"node_modules/readable-stream": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
"react-hook-form": "^7.51.2",
|
"react-hook-form": "^7.51.2",
|
||||||
"react-international-phone": "^4.2.6",
|
"react-international-phone": "^4.2.6",
|
||||||
"react-intl": "^6.6.8",
|
"react-intl": "^6.6.8",
|
||||||
|
"react-to-print": "^3.0.2",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"sonner": "^1.7.0",
|
"sonner": "^1.7.0",
|
||||||
"superjson": "^2.2.1",
|
"superjson": "^2.2.1",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { router, serviceProcedure } from "@/server/trpc"
|
|||||||
import { getHotelData } from "../hotels/query"
|
import { getHotelData } from "../hotels/query"
|
||||||
import { bookingConfirmationInput, getBookingStatusInput } from "./input"
|
import { bookingConfirmationInput, getBookingStatusInput } from "./input"
|
||||||
import { bookingConfirmationSchema, createBookingSchema } from "./output"
|
import { bookingConfirmationSchema, createBookingSchema } from "./output"
|
||||||
|
import { getBookedHotelRoom } from "./utils"
|
||||||
|
|
||||||
const meter = metrics.getMeter("trpc.booking")
|
const meter = metrics.getMeter("trpc.booking")
|
||||||
const getBookingConfirmationCounter = meter.createCounter(
|
const getBookingConfirmationCounter = meter.createCounter(
|
||||||
@@ -144,6 +145,7 @@ export const bookingQueryRouter = router({
|
|||||||
...hotelData.data.attributes,
|
...hotelData.data.attributes,
|
||||||
included: hotelData.included,
|
included: hotelData.included,
|
||||||
},
|
},
|
||||||
|
room: getBookedHotelRoom(hotelData.included, booking.data.roomTypeCode),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
status: serviceProcedure.input(getBookingStatusInput).query(async function ({
|
status: serviceProcedure.input(getBookingStatusInput).query(async function ({
|
||||||
|
|||||||
27
server/routers/booking/utils.ts
Normal file
27
server/routers/booking/utils.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { RoomData } from "@/types/hotel"
|
||||||
|
import { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
|
export function getBookedHotelRoom(
|
||||||
|
rooms: RoomData[] | undefined,
|
||||||
|
roomTypeCode: BookingConfirmation["booking"]["roomTypeCode"]
|
||||||
|
) {
|
||||||
|
if (!rooms?.length || !roomTypeCode) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const room = rooms?.find((r) => {
|
||||||
|
return r.roomTypes.find((roomType) => roomType.code === roomTypeCode)
|
||||||
|
})
|
||||||
|
if (!room) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const bedType = room.roomTypes.find(
|
||||||
|
(roomType) => roomType.code === roomTypeCode
|
||||||
|
)
|
||||||
|
if (!bedType) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...room,
|
||||||
|
bedType,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { MutableRefObject } from "react"
|
||||||
|
|
||||||
|
export interface DownloadInvoiceProps {
|
||||||
|
mainRef: MutableRefObject<HTMLElement | null>
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { RouterOutput } from "@/lib/trpc/client"
|
||||||
|
|
||||||
export interface BookingConfirmationProps {
|
export interface BookingConfirmationProps {
|
||||||
confirmationNumber: string
|
bookingConfirmationPromise: Promise<RouterOutput["booking"]["confirmation"]>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import type { MutableRefObject } from "react"
|
||||||
|
|
||||||
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
|
export interface BookingConfirmationHeaderProps
|
||||||
|
extends Pick<BookingConfirmation, "booking" | "hotel"> {
|
||||||
|
mainRef: MutableRefObject<HTMLElement | null>
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
|
export interface BookingConfirmationHotelDetailsProps {
|
||||||
|
hotel: BookingConfirmation["hotel"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
|
export interface BookingConfirmationPaymentDetailsProps
|
||||||
|
extends Pick<BookingConfirmation, "booking"> {}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
|
export interface BookingConfirmationReceiptProps extends BookingConfirmation {}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { RouterOutput } from "@/lib/trpc/client"
|
|
||||||
|
|
||||||
export interface RoomProps {
|
|
||||||
booking: RouterOutput["booking"]["confirmation"]["booking"]
|
|
||||||
img: NonNullable<
|
|
||||||
RouterOutput["booking"]["confirmation"]["hotel"]["included"]
|
|
||||||
>[number]["images"][number]
|
|
||||||
roomName: NonNullable<
|
|
||||||
RouterOutput["booking"]["confirmation"]["hotel"]["included"]
|
|
||||||
>[number]["name"]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
|
export interface BookingConfirmationRoomsProps
|
||||||
|
extends Pick<BookingConfirmation, "booking" | "room"> {}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
|
export interface RoomProps {
|
||||||
|
booking: BookingConfirmation["booking"]
|
||||||
|
img: NonNullable<BookingConfirmation["room"]>["images"][number]
|
||||||
|
roomName: NonNullable<BookingConfirmation["room"]>["name"]
|
||||||
|
}
|
||||||
19
types/trpc/routers/booking/confirmation.ts
Normal file
19
types/trpc/routers/booking/confirmation.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { bookingConfirmationSchema } from "@/server/routers/booking/output"
|
||||||
|
|
||||||
|
import { Hotel, RoomData } from "@/types/hotel"
|
||||||
|
|
||||||
|
export interface BookingConfirmationSchema
|
||||||
|
extends z.output<typeof bookingConfirmationSchema> {}
|
||||||
|
export interface BookingConfirmation {
|
||||||
|
booking: BookingConfirmationSchema
|
||||||
|
hotel: Hotel & {
|
||||||
|
included?: RoomData[]
|
||||||
|
}
|
||||||
|
room:
|
||||||
|
| (RoomData & {
|
||||||
|
bedType: RoomData["roomTypes"][number]
|
||||||
|
})
|
||||||
|
| null
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import type { RouterOutput } from "@/lib/trpc/client"
|
|
||||||
|
|
||||||
export function getBookedHotelRoom(
|
|
||||||
hotel: RouterOutput["booking"]["confirmation"]["hotel"],
|
|
||||||
roomTypeCode: string
|
|
||||||
) {
|
|
||||||
const room = hotel.included?.find((include) => {
|
|
||||||
return include.roomTypes.find((roomType) => roomType.code === roomTypeCode)
|
|
||||||
})
|
|
||||||
if (!room) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
const bedType = room.roomTypes.find(
|
|
||||||
(roomType) => roomType.code === roomTypeCode
|
|
||||||
)
|
|
||||||
if (!bedType) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...room,
|
|
||||||
bedType,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user