diff --git a/app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx index d2f2a5450..fa2581a54 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/[section]/page.tsx @@ -8,7 +8,6 @@ import Breakfast from "@/components/HotelReservation/EnterDetails/Breakfast" import Details from "@/components/HotelReservation/EnterDetails/Details" import HotelSelectionHeader from "@/components/HotelReservation/HotelSelectionHeader" import Payment from "@/components/HotelReservation/SelectRate/Payment" -import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection" import SectionAccordion from "@/components/HotelReservation/SelectRate/SectionAccordion" import Summary from "@/components/HotelReservation/SelectRate/Summary" import { getIntl } from "@/i18n" @@ -138,18 +137,7 @@ export default async function SectionsPage({ : undefined } path={`select-rate?${currentSearchParams}`} - > - {params.section === "select-rate" && ( - - )} - + > { - const availableHotels = await serverClient().hotel.availability.get(input) + const availableHotels = await serverClient().hotel.availability.hotels(input) if (!availableHotels) throw new Error() diff --git a/app/[lang]/(live)/(public)/hotelreservation/select-rate/page.module.css b/app/[lang]/(live)/(public)/hotelreservation/select-rate/page.module.css new file mode 100644 index 000000000..3266c418d --- /dev/null +++ b/app/[lang]/(live)/(public)/hotelreservation/select-rate/page.module.css @@ -0,0 +1,25 @@ +.page { + min-height: 100dvh; + padding-top: var(--Spacing-x6); + padding-left: var(--Spacing-x2); + padding-right: var(--Spacing-x2); + background-color: var(--Scandic-Brand-Warm-White); +} + +.content { + max-width: 1134px; + margin-top: var(--Spacing-x5); + margin-left: auto; + margin-right: auto; + display: flex; + justify-content: space-between; + gap: var(--Spacing-x7); +} + +.main { + flex-grow: 1; +} + +.summary { + max-width: 340px; +} diff --git a/app/[lang]/(live)/(public)/hotelreservation/select-rate/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/select-rate/page.tsx new file mode 100644 index 000000000..235eeda52 --- /dev/null +++ b/app/[lang]/(live)/(public)/hotelreservation/select-rate/page.tsx @@ -0,0 +1,53 @@ +import { serverClient } from "@/lib/trpc/server" +import tempHotelData from "@/server/routers/hotels/tempHotelData.json" + +import RoomSelection from "@/components/HotelReservation/SelectRate/RoomSelection" +import { getIntl } from "@/i18n" +import { setLang } from "@/i18n/serverContext" + +import styles from "./page.module.css" + +import { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate" +import { LangParams, PageArgs } from "@/types/params" + +export default async function SelectRatePage({ + params, + searchParams, +}: PageArgs) { + setLang(params.lang) + + // TODO: Use real endpoint. + const hotel = tempHotelData.data.attributes + + const rates = await serverClient().hotel.rates.get({ + // TODO: pass the correct hotel ID and all other parameters that should be included in the search + hotelId: searchParams.hotel, + }) + + // const rates = await serverClient().hotel.availability.getForHotel({ + // hotelId: 811, + // roomStayStartDate: "2024-11-02", + // roomStayEndDate: "2024-11-03", + // adults: 1, + // }) + const intl = await getIntl() + + return ( +
+ {/* TODO: Add Hotel Listing Card */} +
Hotel Listing Card TBI
+ +
+
+ +
+
+
+ ) +} diff --git a/components/HotelReservation/SelectRate/RoomSelection/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/index.tsx index d1be37221..51a56b4ad 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/index.tsx @@ -5,11 +5,10 @@ import RoomCard from "./RoomCard" import styles from "./roomSelection.module.css" -import { RoomSelectionProps } from "@/types/components/hotelReservation/selectRate/section" +import { RoomSelectionProps } from "@/types/components/hotelReservation/selectRate/roomSelection" export default function RoomSelection({ - alternatives, - nextPath, + rates, nrOfNights, nrOfAdults, }: RoomSelectionProps) { @@ -21,17 +20,17 @@ export default function RoomSelection({ const queryParams = new URLSearchParams(searchParams) queryParams.set("roomClass", e.currentTarget.roomClass?.value) queryParams.set("flexibility", e.currentTarget.flexibility?.value) - router.push(`${nextPath}?${queryParams}`) + router.push(`select-bed?${queryParams}`) } return (
    - {alternatives.map((room) => ( + {rates.map((room) => (
  • ))}
+
This is summary
) } diff --git a/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css b/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css index 5a1dfd7c8..80ed0e5be 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css +++ b/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css @@ -21,3 +21,10 @@ position: fixed; width: 0; } + +.summary { + position: fixed; + bottom: 0; + left: 0; + right: 0; +} diff --git a/lib/api/endpoints.ts b/lib/api/endpoints.ts index a21017d6a..9ead56554 100644 --- a/lib/api/endpoints.ts +++ b/lib/api/endpoints.ts @@ -6,7 +6,7 @@ export namespace endpoints { profile = "profile/v0/Profile", } export const enum v1 { - availability = "availability/v1/availabilities/city", + hotelsAvailability = "availability/v1/availabilities/city", profile = "profile/v1/Profile", booking = "booking/v1/Bookings", creditCards = `${profile}/creditCards`, diff --git a/server/routers/hotels/input.ts b/server/routers/hotels/input.ts index 416d41eee..b0ff5e679 100644 --- a/server/routers/hotels/input.ts +++ b/server/routers/hotels/input.ts @@ -6,7 +6,7 @@ export const getHotelInputSchema = z.object({ .optional(), }) -export const getAvailabilityInputSchema = z.object({ +export const getHotelsAvailabilityInputSchema = z.object({ cityId: z.string(), roomStayStartDate: z.string(), roomStayEndDate: z.string(), diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts index 0d3e75ce3..d233f1a82 100644 --- a/server/routers/hotels/output.ts +++ b/server/routers/hotels/output.ts @@ -525,26 +525,18 @@ const occupancySchema = z.object({ const bestPricePerStaySchema = z.object({ currency: z.string(), - amount: z.number(), - regularAmount: z.number(), - memberAmount: z.number(), - discountRate: z.number(), - discountAmount: z.number(), - points: z.number(), - numberOfVouchers: z.number(), - numberOfBonusCheques: z.number(), + // TODO: remove optional when API is ready + regularAmount: z.string().optional(), + // TODO: remove optional when API is ready + memberAmount: z.string().optional(), }) const bestPricePerNightSchema = z.object({ currency: z.string(), - amount: z.number(), - regularAmount: z.number(), - memberAmount: z.number(), - discountRate: z.number(), - discountAmount: z.number(), - points: z.number(), - numberOfVouchers: z.number(), - numberOfBonusCheques: z.number(), + // TODO: remove optional when API is ready + regularAmount: z.string().optional(), + // TODO: remove optional when API is ready + memberAmount: z.string().optional(), }) const linksSchema = z.object({ @@ -556,7 +548,7 @@ const linksSchema = z.object({ ), }) -const availabilitySchema = z.object({ +const hotelsAvailabilitySchema = z.object({ data: z.array( z.object({ attributes: z.object({ @@ -575,10 +567,10 @@ const availabilitySchema = z.object({ ), }) -export const getAvailabilitySchema = availabilitySchema -export type Availability = z.infer -export type AvailabilityPrices = - Availability["data"][number]["attributes"]["bestPricePerNight"] +export const getHotelsAvailabilitySchema = hotelsAvailabilitySchema +export type HotelsAvailability = z.infer +export type HotelsAvailabilityPrices = + HotelsAvailability["data"][number]["attributes"]["bestPricePerNight"] const flexibilityPrice = z.object({ standard: z.number(), diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index 2f30ae397..0e319bf6e 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -20,14 +20,14 @@ import { toApiLang } from "@/server/utils" import { hotelPageSchema } from "../contentstack/hotelPage/output" import { - getAvailabilityInputSchema, getHotelInputSchema, + getHotelsAvailabilityInputSchema, getlHotelDataInputSchema, getRatesInputSchema, } from "./input" import { - getAvailabilitySchema, getHotelDataSchema, + getHotelsAvailabilitySchema, getRatesSchema, roomSchema, } from "./output" @@ -51,12 +51,14 @@ const getHotelCounter = meter.createCounter("trpc.hotel.get") const getHotelSuccessCounter = meter.createCounter("trpc.hotel.get-success") const getHotelFailCounter = meter.createCounter("trpc.hotel.get-fail") -const availabilityCounter = meter.createCounter("trpc.hotel.availability") -const availabilitySuccessCounter = meter.createCounter( - "trpc.hotel.availability-success" +const hotelsAvailabilityCounter = meter.createCounter( + "trpc.hotel.availability.hotels" ) -const availabilityFailCounter = meter.createCounter( - "trpc.hotel.availability-fail" +const hotelsAvailabilitySuccessCounter = meter.createCounter( + "trpc.hotel.availability.hotels-success" +) +const hotelsAvailabilityFailCounter = meter.createCounter( + "trpc.hotel.availability.hotels-fail" ) async function getContentstackData( @@ -250,8 +252,8 @@ export const hotelQueryRouter = router({ } }), availability: router({ - get: hotelServiceProcedure - .input(getAvailabilityInputSchema) + hotels: hotelServiceProcedure + .input(getHotelsAvailabilityInputSchema) .query(async ({ input, ctx }) => { const { cityId, @@ -274,7 +276,7 @@ export const hotelQueryRouter = router({ attachedProfileId, } - availabilityCounter.add(1, { + hotelsAvailabilityCounter.add(1, { cityId, roomStayStartDate, roomStayEndDate, @@ -284,11 +286,11 @@ export const hotelQueryRouter = router({ reservationProfileType, }) console.info( - "api.hotels.availability start", + "api.hotels.hotelsAvailability start", JSON.stringify({ query: { cityId, params } }) ) const apiResponse = await api.get( - `${api.endpoints.v1.availability}/${cityId}`, + `${api.endpoints.v1.hotelsAvailability}/${cityId}`, { headers: { Authorization: `Bearer ${ctx.serviceToken}`, @@ -298,7 +300,7 @@ export const hotelQueryRouter = router({ ) if (!apiResponse.ok) { const text = await apiResponse.text() - availabilityFailCounter.add(1, { + hotelsAvailabilityFailCounter.add(1, { cityId, roomStayStartDate, roomStayEndDate, @@ -314,7 +316,7 @@ export const hotelQueryRouter = router({ }), }) console.error( - "api.hotels.availability error", + "api.hotels.hotelsAvailability error", JSON.stringify({ query: { cityId, params }, error: { @@ -328,9 +330,9 @@ export const hotelQueryRouter = router({ } const apiJson = await apiResponse.json() const validateAvailabilityData = - getAvailabilitySchema.safeParse(apiJson) + getHotelsAvailabilitySchema.safeParse(apiJson) if (!validateAvailabilityData.success) { - availabilityFailCounter.add(1, { + hotelsAvailabilityFailCounter.add(1, { cityId, roomStayStartDate, roomStayEndDate, @@ -342,7 +344,7 @@ export const hotelQueryRouter = router({ error: JSON.stringify(validateAvailabilityData.error), }) console.error( - "api.hotels.availability validation error", + "api.hotels.hotelsAvailability validation error", JSON.stringify({ query: { cityId, params }, error: validateAvailabilityData.error, @@ -350,7 +352,7 @@ export const hotelQueryRouter = router({ ) throw badRequestError() } - availabilitySuccessCounter.add(1, { + hotelsAvailabilitySuccessCounter.add(1, { cityId, roomStayStartDate, roomStayEndDate, @@ -360,7 +362,7 @@ export const hotelQueryRouter = router({ reservationProfileType, }) console.info( - "api.hotels.availability success", + "api.hotels.hotelsAvailability success", JSON.stringify({ query: { cityId, params: params }, }) diff --git a/types/components/hotelReservation/selectHotel/hotelCardListingProps.ts b/types/components/hotelReservation/selectHotel/hotelCardListingProps.ts index 0ab3df1ad..431d53c0e 100644 --- a/types/components/hotelReservation/selectHotel/hotelCardListingProps.ts +++ b/types/components/hotelReservation/selectHotel/hotelCardListingProps.ts @@ -1,4 +1,4 @@ -import { AvailabilityPrices } from "@/server/routers/hotels/output" +import { HotelsAvailabilityPrices } from "@/server/routers/hotels/output" import { Hotel } from "@/types/hotel" @@ -8,5 +8,5 @@ export type HotelCardListingProps = { export type HotelData = { hotelData: Hotel - price: AvailabilityPrices + price: HotelsAvailabilityPrices } diff --git a/types/components/hotelReservation/selectRate/roomSelection.ts b/types/components/hotelReservation/selectRate/roomSelection.ts new file mode 100644 index 000000000..d5203f461 --- /dev/null +++ b/types/components/hotelReservation/selectRate/roomSelection.ts @@ -0,0 +1,7 @@ +import { Rate } from "@/server/routers/hotels/output" + +export interface RoomSelectionProps { + rates: Rate[] + nrOfAdults: number + nrOfNights: number +} diff --git a/types/components/hotelReservation/selectRate/section.ts b/types/components/hotelReservation/selectRate/section.ts index 69460962b..4da378cdd 100644 --- a/types/components/hotelReservation/selectRate/section.ts +++ b/types/components/hotelReservation/selectRate/section.ts @@ -1,5 +1,3 @@ -import { Rate } from "@/server/routers/hotels/output" - import { Hotel } from "@/types/hotel" export interface SectionProps { @@ -27,12 +25,6 @@ export interface BreakfastSelectionProps extends SectionProps { }[] } -export interface RoomSelectionProps extends SectionProps { - alternatives: Rate[] - nrOfAdults: number - nrOfNights: number -} - export interface DetailsProps extends SectionProps {} export interface PaymentProps { diff --git a/types/components/hotelReservation/selectRate/selectRate.ts b/types/components/hotelReservation/selectRate/selectRate.ts new file mode 100644 index 000000000..bc325bbf2 --- /dev/null +++ b/types/components/hotelReservation/selectRate/selectRate.ts @@ -0,0 +1,5 @@ +export interface SelectRateSearchParams { + fromDate: string + toDate: string + hotel: string +}