feat(SW-2116): avoid passing entire booking object to Room client component
This commit is contained in:
committed by
Michael Zetterberg
parent
a839d05e09
commit
7eeb0bbcac
@@ -78,14 +78,19 @@ export function LinkedReservation({
|
|||||||
if (!data?.room) {
|
if (!data?.room) {
|
||||||
return <Retry handleRefetch={refetch} />
|
return <Retry handleRefetch={refetch} />
|
||||||
}
|
}
|
||||||
|
const { booking, room } = data
|
||||||
return (
|
return (
|
||||||
<Room
|
<Room
|
||||||
booking={data.booking}
|
checkInDate={booking.checkInDate}
|
||||||
|
checkOutDate={booking.checkOutDate}
|
||||||
checkInTime={checkInTime}
|
checkInTime={checkInTime}
|
||||||
checkOutTime={checkOutTime}
|
checkOutTime={checkOutTime}
|
||||||
img={data.room.images[0]}
|
confirmationNumber={booking.confirmationNumber}
|
||||||
roomName={data.room.name}
|
guest={booking.guest}
|
||||||
|
guaranteeInfo={booking.guaranteeInfo}
|
||||||
|
img={room.images[0]}
|
||||||
|
rateDefinition={booking.rateDefinition}
|
||||||
|
roomName={room.name}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,24 +20,28 @@ import styles from "./room.module.css"
|
|||||||
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/rooms/room"
|
import type { RoomProps } from "@/types/components/hotelReservation/bookingConfirmation/rooms/room"
|
||||||
|
|
||||||
export default function Room({
|
export default function Room({
|
||||||
booking,
|
checkInDate,
|
||||||
|
checkOutDate,
|
||||||
checkInTime,
|
checkInTime,
|
||||||
checkOutTime,
|
checkOutTime,
|
||||||
|
confirmationNumber,
|
||||||
|
guaranteeInfo,
|
||||||
|
guest,
|
||||||
img,
|
img,
|
||||||
|
rateDefinition,
|
||||||
roomName,
|
roomName,
|
||||||
}: RoomProps) {
|
}: RoomProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const lang = useLang()
|
const lang = useLang()
|
||||||
|
|
||||||
const guestName = `${booking.guest.firstName} ${booking.guest.lastName}`
|
const guestName = `${guest.firstName} ${guest.lastName}`
|
||||||
const fromDate = dt(booking.checkInDate).locale(lang)
|
const fromDate = dt(checkInDate).locale(lang)
|
||||||
const toDate = dt(booking.checkOutDate).locale(lang)
|
const toDate = dt(checkOutDate).locale(lang)
|
||||||
|
|
||||||
const isFlexBooking =
|
const isFlexBooking =
|
||||||
booking.rateDefinition.cancellationRule ===
|
rateDefinition.cancellationRule ===
|
||||||
CancellationRuleEnum.CancellableBefore6PM
|
CancellationRuleEnum.CancellableBefore6PM
|
||||||
const isChangeBooking =
|
const isChangeBooking =
|
||||||
booking.rateDefinition.cancellationRule === CancellationRuleEnum.Changeable
|
rateDefinition.cancellationRule === CancellationRuleEnum.Changeable
|
||||||
return (
|
return (
|
||||||
<article className={styles.room}>
|
<article className={styles.room}>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
@@ -47,11 +51,11 @@ export default function Room({
|
|||||||
{
|
{
|
||||||
defaultMessage: "Booking number {value}",
|
defaultMessage: "Booking number {value}",
|
||||||
},
|
},
|
||||||
{ value: booking.confirmationNumber }
|
{ value: confirmationNumber }
|
||||||
)}
|
)}
|
||||||
</h2>
|
</h2>
|
||||||
</Typography>
|
</Typography>
|
||||||
{booking.rateDefinition.isMemberRate ? (
|
{rateDefinition.isMemberRate ? (
|
||||||
<div className={styles.benefits}>
|
<div className={styles.benefits}>
|
||||||
<>
|
<>
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
@@ -67,7 +71,7 @@ export default function Room({
|
|||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{booking.guaranteeInfo && (
|
{guaranteeInfo && (
|
||||||
<div className={styles.benefits}>
|
<div className={styles.benefits}>
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="check_circle"
|
icon="check_circle"
|
||||||
@@ -168,7 +172,7 @@ export default function Room({
|
|||||||
})}
|
})}
|
||||||
</Body>
|
</Body>
|
||||||
<Body color="uiTextHighContrast">
|
<Body color="uiTextHighContrast">
|
||||||
{booking.rateDefinition.cancellationText}
|
{rateDefinition.cancellationText}
|
||||||
</Body>
|
</Body>
|
||||||
</li>
|
</li>
|
||||||
{isFlexBooking || isChangeBooking ? (
|
{isFlexBooking || isChangeBooking ? (
|
||||||
@@ -196,25 +200,23 @@ export default function Room({
|
|||||||
})}
|
})}
|
||||||
</Body>
|
</Body>
|
||||||
<Body color="uiTextHighContrast">{guestName}</Body>
|
<Body color="uiTextHighContrast">{guestName}</Body>
|
||||||
{booking.guest.membershipNumber ? (
|
{guest.membershipNumber ? (
|
||||||
<Body color="uiTextHighContrast">
|
<Body color="uiTextHighContrast">
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
{
|
{
|
||||||
defaultMessage: "Friend no. {value}",
|
defaultMessage: "Friend no. {value}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: booking.guest.membershipNumber,
|
value: guest.membershipNumber,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
</Body>
|
</Body>
|
||||||
) : null}
|
) : null}
|
||||||
{booking.guest.phoneNumber ? (
|
{guest.phoneNumber ? (
|
||||||
<Body color="uiTextHighContrast">
|
<Body color="uiTextHighContrast">{guest.phoneNumber}</Body>
|
||||||
{booking.guest.phoneNumber}
|
|
||||||
</Body>
|
|
||||||
) : null}
|
) : null}
|
||||||
{booking.guest.email ? (
|
{guest.email ? (
|
||||||
<Body color="uiTextHighContrast">{booking.guest.email}</Body>
|
<Body color="uiTextHighContrast">{guest.email}</Body>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -34,10 +34,15 @@ export default async function Rooms({
|
|||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
<Room
|
<Room
|
||||||
booking={booking}
|
checkInDate={booking.checkInDate}
|
||||||
|
checkOutDate={booking.checkOutDate}
|
||||||
checkInTime={checkInTime}
|
checkInTime={checkInTime}
|
||||||
checkOutTime={checkOutTime}
|
checkOutTime={checkOutTime}
|
||||||
|
confirmationNumber={booking.confirmationNumber}
|
||||||
|
guaranteeInfo={booking.guaranteeInfo}
|
||||||
|
guest={booking.guest}
|
||||||
img={mainRoom.images[0]}
|
img={mainRoom.images[0]}
|
||||||
|
rateDefinition={booking.rateDefinition}
|
||||||
roomName={mainRoom.name}
|
roomName={mainRoom.name}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { notFound } from "next/navigation"
|
import { notFound } from "next/navigation"
|
||||||
|
|
||||||
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
||||||
import { encrypt } from "@/server/routers/utils/encryption"
|
|
||||||
|
|
||||||
import HotelDetails from "@/components/HotelReservation/BookingConfirmation/HotelDetails"
|
import HotelDetails from "@/components/HotelReservation/BookingConfirmation/HotelDetails"
|
||||||
import PaymentDetails from "@/components/HotelReservation/BookingConfirmation/PaymentDetails"
|
import PaymentDetails from "@/components/HotelReservation/BookingConfirmation/PaymentDetails"
|
||||||
@@ -12,6 +11,7 @@ import SidePanel from "@/components/HotelReservation/SidePanel"
|
|||||||
import Divider from "@/components/TempDesignSystem/Divider"
|
import Divider from "@/components/TempDesignSystem/Divider"
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
import BookingConfirmationProvider from "@/providers/BookingConfirmationProvider"
|
import BookingConfirmationProvider from "@/providers/BookingConfirmationProvider"
|
||||||
|
import { encrypt } from "@/utils/encryption"
|
||||||
|
|
||||||
import Alerts from "./Alerts"
|
import Alerts from "./Alerts"
|
||||||
import Confirmation from "./Confirmation"
|
import Confirmation from "./Confirmation"
|
||||||
@@ -66,11 +66,7 @@ export default async function BookingConfirmation({
|
|||||||
<PaymentDetails />
|
<PaymentDetails />
|
||||||
<Divider color="primaryLightSubtle" />
|
<Divider color="primaryLightSubtle" />
|
||||||
<HotelDetails hotel={hotel} />
|
<HotelDetails hotel={hotel} />
|
||||||
<Promos
|
<Promos refId={refId} hotelId={hotel.operaId} />
|
||||||
confirmationNumber={booking.confirmationNumber}
|
|
||||||
hotelId={hotel.operaId}
|
|
||||||
lastName={booking.guest.lastName}
|
|
||||||
/>
|
|
||||||
<div className={styles.mobileReceipt}>
|
<div className={styles.mobileReceipt}>
|
||||||
<Receipt />
|
<Receipt />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import {
|
|||||||
getBookingConfirmation,
|
getBookingConfirmation,
|
||||||
getProfileSafely,
|
getProfileSafely,
|
||||||
} from "@/lib/trpc/memoizedRequests"
|
} from "@/lib/trpc/memoizedRequests"
|
||||||
import { decrypt } from "@/server/routers/utils/encryption"
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
import { getIntl } from "@/i18n"
|
||||||
|
import { decrypt } from "@/utils/encryption"
|
||||||
|
|
||||||
import AdditionalInfoForm from "../../FindMyBooking/AdditionalInfoForm"
|
import AdditionalInfoForm from "../../FindMyBooking/AdditionalInfoForm"
|
||||||
import accessBooking, {
|
import accessBooking, {
|
||||||
@@ -132,6 +132,7 @@ export async function Receipt({ refId }: { refId: string }) {
|
|||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<div className={styles.form}>
|
<div className={styles.form}>
|
||||||
<AdditionalInfoForm
|
<AdditionalInfoForm
|
||||||
|
// send refId here?
|
||||||
confirmationNumber={confirmationNumber}
|
confirmationNumber={confirmationNumber}
|
||||||
lastName={lastName}
|
lastName={lastName}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import {
|
|||||||
serviceProcedure,
|
serviceProcedure,
|
||||||
} from "@/server/trpc"
|
} from "@/server/trpc"
|
||||||
|
|
||||||
|
import { calculateRefId } from "@/utils/refId"
|
||||||
|
|
||||||
import { getHotel } from "../hotels/utils"
|
import { getHotel } from "../hotels/utils"
|
||||||
import { encrypt } from "../utils/encryption"
|
|
||||||
import {
|
import {
|
||||||
createRefIdInput,
|
createRefIdInput,
|
||||||
getBookingInput,
|
getBookingInput,
|
||||||
@@ -169,7 +170,7 @@ export const bookingQueryRouter = router({
|
|||||||
.input(createRefIdInput)
|
.input(createRefIdInput)
|
||||||
.mutation(async function ({ input }) {
|
.mutation(async function ({ input }) {
|
||||||
const { confirmationNumber, lastName } = input
|
const { confirmationNumber, lastName } = input
|
||||||
const encryptedRefId = encrypt(`${confirmationNumber},${lastName}`)
|
const encryptedRefId = calculateRefId(confirmationNumber, lastName)
|
||||||
|
|
||||||
if (!encryptedRefId) {
|
if (!encryptedRefId) {
|
||||||
throw serverErrorByStatus(422, "Was not able to encrypt ref id")
|
throw serverErrorByStatus(422, "Was not able to encrypt ref id")
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { myStay } from "@/constants/routes/myStay"
|
|||||||
import { env } from "@/env/server"
|
import { env } from "@/env/server"
|
||||||
import * as api from "@/lib/api"
|
import * as api from "@/lib/api"
|
||||||
import { dt } from "@/lib/dt"
|
import { dt } from "@/lib/dt"
|
||||||
import { encrypt } from "@/server/routers/utils/encryption"
|
|
||||||
import { createCounter } from "@/server/telemetry"
|
import { createCounter } from "@/server/telemetry"
|
||||||
|
|
||||||
import { cache } from "@/utils/cache"
|
import { cache } from "@/utils/cache"
|
||||||
|
import { encrypt } from "@/utils/encryption"
|
||||||
import * as maskValue from "@/utils/maskValue"
|
import * as maskValue from "@/utils/maskValue"
|
||||||
import { isValidSession } from "@/utils/session"
|
import { isValidSession } from "@/utils/session"
|
||||||
import { getCurrentWebUrl } from "@/utils/url"
|
import { getCurrentWebUrl } from "@/utils/url"
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
export interface PromosProps {
|
||||||
|
hotelId: string
|
||||||
export interface PromosProps
|
refId: string
|
||||||
extends Pick<
|
}
|
||||||
BookingConfirmation["booking"],
|
|
||||||
"confirmationNumber" | "hotelId"
|
|
||||||
>,
|
|
||||||
Pick<BookingConfirmation["booking"]["guest"], "lastName"> {}
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"
|
||||||
|
|
||||||
export interface RoomProps {
|
export interface RoomProps {
|
||||||
booking: BookingConfirmation["booking"]
|
checkInDate: BookingConfirmation["booking"]["checkInDate"]
|
||||||
|
checkOutDate: BookingConfirmation["booking"]["checkOutDate"]
|
||||||
checkInTime: string
|
checkInTime: string
|
||||||
checkOutTime: string
|
checkOutTime: string
|
||||||
|
confirmationNumber: string
|
||||||
|
guest: BookingConfirmation["booking"]["guest"]
|
||||||
|
guaranteeInfo: BookingConfirmation["booking"]["guaranteeInfo"]
|
||||||
img: NonNullable<BookingConfirmation["room"]>["images"][number]
|
img: NonNullable<BookingConfirmation["room"]>["images"][number]
|
||||||
|
rateDefinition: BookingConfirmation["booking"]["rateDefinition"]
|
||||||
roomName: NonNullable<BookingConfirmation["room"]>["name"]
|
roomName: NonNullable<BookingConfirmation["room"]>["name"]
|
||||||
}
|
}
|
||||||
|
|||||||
21
apps/scandic-web/utils/refId.ts
Normal file
21
apps/scandic-web/utils/refId.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import "server-only"
|
||||||
|
|
||||||
|
import { decrypt, encrypt } from "./encryption"
|
||||||
|
|
||||||
|
export function calculateRefId(confirmationNumber: string, lastName: string) {
|
||||||
|
const encryptedRefId = encrypt(`${confirmationNumber},${lastName}`)
|
||||||
|
|
||||||
|
return encryptedRefId
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseRefId(refId: string) {
|
||||||
|
const data = decrypt(refId)
|
||||||
|
const parts = data.split(",")
|
||||||
|
if (parts.length !== 2) {
|
||||||
|
throw new Error("Invalid refId format")
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
confirmationNumber: parts[0],
|
||||||
|
lastName: parts[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user