feat: Add TRPC procedure for hotel API, schemas, and use in hotel content page
This commit is contained in:
@@ -7,13 +7,20 @@ import styles from "./hotelPage.module.css"
|
|||||||
import type { LangParams } from "@/types/params"
|
import type { LangParams } from "@/types/params"
|
||||||
|
|
||||||
export default async function HotelPage({ lang }: LangParams) {
|
export default async function HotelPage({ lang }: LangParams) {
|
||||||
const hotelPage = await serverClient().contentstack.hotelPage.get()
|
const hotelPageIdentifierData =
|
||||||
if (!hotelPage) {
|
await serverClient().contentstack.hotelPage.get()
|
||||||
|
|
||||||
|
if (!hotelPageIdentifierData) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hotelPageData = await serverClient().hotel.getHotel({
|
||||||
|
hotelId: hotelPageIdentifierData.hotel_page_id,
|
||||||
|
language: lang,
|
||||||
|
})
|
||||||
return (
|
return (
|
||||||
<section className={styles.content}>
|
<section className={styles.content}>
|
||||||
<Title>{hotelPage.title}</Title>
|
<Title>{hotelPageData.data.attributes.name}</Title>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export enum Lang {
|
|||||||
de = "de",
|
de = "de",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const languages = {
|
export const languages: Record<Lang, string> = {
|
||||||
[Lang.da]: "Dansk",
|
[Lang.da]: "Dansk",
|
||||||
[Lang.de]: "Deutsch",
|
[Lang.de]: "Deutsch",
|
||||||
[Lang.en]: "English",
|
[Lang.en]: "English",
|
||||||
@@ -16,7 +16,7 @@ export const languages = {
|
|||||||
[Lang.sv]: "Svenska",
|
[Lang.sv]: "Svenska",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const localeToLang = {
|
export const localeToLang: Record<string, Lang> = {
|
||||||
en: Lang.en,
|
en: Lang.en,
|
||||||
"en-US": Lang.en,
|
"en-US": Lang.en,
|
||||||
"en-GB": Lang.en,
|
"en-GB": Lang.en,
|
||||||
@@ -56,12 +56,6 @@ export const localeToLang = {
|
|||||||
"se-NO": Lang.no,
|
"se-NO": Lang.no,
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export function findLang(pathname: string) {
|
|
||||||
return Object.values(Lang).find(
|
|
||||||
(l) => pathname.startsWith(`/${l}/`) || pathname === `/${l}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const languageSelect = [
|
export const languageSelect = [
|
||||||
{ label: "Danish", value: "Da" },
|
{ label: "Danish", value: "Da" },
|
||||||
{ label: "German", value: "De" },
|
{ label: "German", value: "De" },
|
||||||
@@ -70,3 +64,38 @@ export const languageSelect = [
|
|||||||
{ label: "Norwegian", value: "No" },
|
{ label: "Norwegian", value: "No" },
|
||||||
{ label: "Swedish", value: "Sv" },
|
{ label: "Swedish", value: "Sv" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// -- Lang util functions --
|
||||||
|
|
||||||
|
export function findLang(pathname: string) {
|
||||||
|
return Object.values(Lang).find(
|
||||||
|
(l) => pathname.startsWith(`/${l}/`) || pathname === `/${l}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to convert API's (e.g. the Hotel endpoint) capitalized values to Lang enum.
|
||||||
|
export function fromUppercaseToLangEnum(lang: string): Lang | undefined {
|
||||||
|
const lowerCaseLang = lang.charAt(0).toLowerCase() + lang.slice(1)
|
||||||
|
return Object.values(Lang).find((l) => l === lowerCaseLang)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to convert Lang enum to uppercase
|
||||||
|
// Needed for certtain API (e.g. the Hotel endpoint).
|
||||||
|
export const toUppercaseLang = (lang: Lang): string => {
|
||||||
|
switch (lang) {
|
||||||
|
case Lang.en:
|
||||||
|
return "En"
|
||||||
|
case Lang.sv:
|
||||||
|
return "Sv"
|
||||||
|
case Lang.no:
|
||||||
|
return "No"
|
||||||
|
case Lang.fi:
|
||||||
|
return "Fi"
|
||||||
|
case Lang.da:
|
||||||
|
return "Da"
|
||||||
|
case Lang.de:
|
||||||
|
return "De"
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid language")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { Lang, toUppercaseLang } from "@/constants/languages"
|
||||||
|
|
||||||
export const getHotelInputSchema = z.object({
|
export const getHotelInputSchema = z.object({
|
||||||
hotelId: z.string(),
|
hotelId: z.string(),
|
||||||
|
language: z.nativeEnum(Lang).transform((val) => toUppercaseLang(val)),
|
||||||
})
|
})
|
||||||
|
|||||||
393
server/routers/hotels/output.ts
Normal file
393
server/routers/hotels/output.ts
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { fromUppercaseToLangEnum } from "@/constants/languages"
|
||||||
|
|
||||||
|
const RatingsSchema = z.object({
|
||||||
|
tripAdvisor: z.object({
|
||||||
|
numberOfReviews: z.number(),
|
||||||
|
rating: z.number(),
|
||||||
|
ratingImageUrl: z.string(),
|
||||||
|
webUrl: z.string(),
|
||||||
|
awards: z.array(
|
||||||
|
z.object({
|
||||||
|
displayName: z.string(),
|
||||||
|
images: z.object({
|
||||||
|
small: z.string(),
|
||||||
|
medium: z.string(),
|
||||||
|
large: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
reviews: z.object({
|
||||||
|
widgetHtmlTagId: z.string(),
|
||||||
|
widgetScriptEmbedUrlIframe: z.string(),
|
||||||
|
widgetScriptEmbedUrlJavaScript: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const AddressSchema = z.object({
|
||||||
|
streetAddress: z.string(),
|
||||||
|
city: z.string(),
|
||||||
|
zipCode: z.string(),
|
||||||
|
country: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ContactInformationSchema = z.object({
|
||||||
|
phoneNumber: z.string(),
|
||||||
|
faxNumber: z.string(),
|
||||||
|
email: z.string(),
|
||||||
|
websiteUrl: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const CheckinSchema = z.object({
|
||||||
|
checkInTime: z.string(),
|
||||||
|
checkOutTime: z.string(),
|
||||||
|
onlineCheckOutAvailableFrom: z.string().nullable().optional(),
|
||||||
|
onlineCheckout: z.boolean(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const EcoLabelsSchema = z.object({
|
||||||
|
euEcoLabel: z.boolean(),
|
||||||
|
greenGlobeLabel: z.boolean(),
|
||||||
|
nordicEcoLabel: z.boolean(),
|
||||||
|
svanenEcoLabelCertificateNumber: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const HotelFacilityDetailSchema = z.object({
|
||||||
|
heading: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const HotelFacilitySchema = z.object({
|
||||||
|
breakfast: HotelFacilityDetailSchema,
|
||||||
|
checkout: HotelFacilityDetailSchema,
|
||||||
|
gym: HotelFacilityDetailSchema,
|
||||||
|
internet: HotelFacilityDetailSchema,
|
||||||
|
laundry: HotelFacilityDetailSchema,
|
||||||
|
luggage: HotelFacilityDetailSchema,
|
||||||
|
shop: HotelFacilityDetailSchema,
|
||||||
|
telephone: HotelFacilityDetailSchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
const HotelInformationDetailSchema = z.object({
|
||||||
|
heading: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
link: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const HotelInformationSchema = z.object({
|
||||||
|
accessibility: HotelInformationDetailSchema,
|
||||||
|
safety: HotelInformationDetailSchema,
|
||||||
|
sustainability: HotelInformationDetailSchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
const InteriorSchema = z.object({
|
||||||
|
numberOfBeds: z.number(),
|
||||||
|
numberOfCribs: z.number(),
|
||||||
|
numberOfFloors: z.number(),
|
||||||
|
numberOfRooms: z.object({
|
||||||
|
connected: z.number(),
|
||||||
|
forEllergics: z.number(),
|
||||||
|
forDisabled: z.number(),
|
||||||
|
nonSmoking: z.number(),
|
||||||
|
pet: z.number(),
|
||||||
|
withExtraBeds: z.number(),
|
||||||
|
total: z.number(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ReceptionHoursSchema = z.object({
|
||||||
|
alwaysOpen: z.boolean(),
|
||||||
|
isClosed: z.boolean(),
|
||||||
|
openingTime: z.string().optional(),
|
||||||
|
closingTime: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const LocationSchema = z.object({
|
||||||
|
distanceToCentre: z.number(),
|
||||||
|
latitude: z.number(),
|
||||||
|
longitude: z.number(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ImageMetaDataSchema = z.object({
|
||||||
|
title: z.string(),
|
||||||
|
altText: z.string(),
|
||||||
|
altText_En: z.string(),
|
||||||
|
copyRight: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ImageSizesSchema = z.object({
|
||||||
|
tiny: z.string(),
|
||||||
|
small: z.string(),
|
||||||
|
medium: z.string(),
|
||||||
|
large: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const HotelContentSchema = z.object({
|
||||||
|
images: z.object({
|
||||||
|
metaData: ImageMetaDataSchema,
|
||||||
|
imageSizes: ImageSizesSchema,
|
||||||
|
}),
|
||||||
|
texts: z.object({
|
||||||
|
facilityInformation: z.string(),
|
||||||
|
surroundingInformation: z.string(),
|
||||||
|
descriptions: z.object({
|
||||||
|
short: z.string(),
|
||||||
|
medium: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
restaurantsOverviewPage: z.object({
|
||||||
|
restaurantsOverviewPageLinkText: z.string(),
|
||||||
|
restaurantsOverviewPageLink: z.string(),
|
||||||
|
restaurantsContentDescriptionShort: z.string(),
|
||||||
|
restaurantsContentDescriptionMedium: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const DetailedFacilitySchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
name: z.string(),
|
||||||
|
code: z.string().optional(),
|
||||||
|
applyToAllHotels: z.boolean(),
|
||||||
|
public: z.boolean(),
|
||||||
|
icon: z.number(),
|
||||||
|
iconName: z.string().optional(),
|
||||||
|
sortOrder: z.number(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const HealthFacilitySchema = z.object({
|
||||||
|
type: z.string(),
|
||||||
|
content: z.object({
|
||||||
|
images: z.array(
|
||||||
|
z.object({
|
||||||
|
metaData: ImageMetaDataSchema,
|
||||||
|
imageSizes: ImageSizesSchema,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
texts: z.object({
|
||||||
|
facilityInformation: z.string().optional(),
|
||||||
|
surroundingInformation: z.string().optional(),
|
||||||
|
descriptions: z.object({
|
||||||
|
short: z.string(),
|
||||||
|
medium: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
openingDetails: z.object({
|
||||||
|
useManualOpeningHours: z.boolean(),
|
||||||
|
manualOpeningHours: z.string().optional(),
|
||||||
|
openingHours: z.object({
|
||||||
|
ordinary: z.object({
|
||||||
|
alwaysOpen: z.boolean(),
|
||||||
|
isClosed: z.boolean(),
|
||||||
|
openingTime: z.string(),
|
||||||
|
closingTime: z.string(),
|
||||||
|
sortOrder: z.number().optional(),
|
||||||
|
}),
|
||||||
|
weekends: z.object({
|
||||||
|
alwaysOpen: z.boolean(),
|
||||||
|
isClosed: z.boolean(),
|
||||||
|
openingTime: z.string(),
|
||||||
|
closingTime: z.string(),
|
||||||
|
sortOrder: z.number().optional(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
details: z.array(
|
||||||
|
z.object({
|
||||||
|
name: z.string(),
|
||||||
|
type: z.string(),
|
||||||
|
value: z.string().optional(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
const RewardNightSchema = z.object({
|
||||||
|
points: z.number(),
|
||||||
|
campaign: z.object({
|
||||||
|
start: z.string(),
|
||||||
|
end: z.string(),
|
||||||
|
points: z.number(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const PointsOfInterestSchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
distance: z.number(),
|
||||||
|
category: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
group: z.string(),
|
||||||
|
}),
|
||||||
|
location: LocationSchema,
|
||||||
|
isHighlighted: z.boolean(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ParkingPricingSchema = z.object({
|
||||||
|
freeParking: z.boolean(),
|
||||||
|
paymentType: z.string(),
|
||||||
|
localCurrency: z.object({
|
||||||
|
currency: z.string(),
|
||||||
|
range: z.object({
|
||||||
|
min: z.number(),
|
||||||
|
max: z.number(),
|
||||||
|
}),
|
||||||
|
ordinary: z.array(
|
||||||
|
z.object({
|
||||||
|
period: z.string(),
|
||||||
|
amount: z.number(),
|
||||||
|
startTime: z.string(),
|
||||||
|
endTime: z.string(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
weekend: z.array(
|
||||||
|
z.object({
|
||||||
|
period: z.string(),
|
||||||
|
amount: z.number(),
|
||||||
|
startTime: z.string(),
|
||||||
|
endTime: z.string(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
requestedCurrency: z.object({
|
||||||
|
currency: z.string(),
|
||||||
|
range: z.object({
|
||||||
|
min: z.number(),
|
||||||
|
max: z.number(),
|
||||||
|
}),
|
||||||
|
ordinary: z.array(
|
||||||
|
z.object({
|
||||||
|
period: z.string(),
|
||||||
|
amount: z.number(),
|
||||||
|
startTime: z.string(),
|
||||||
|
endTime: z.string(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
weekend: z.array(
|
||||||
|
z.object({
|
||||||
|
period: z.string(),
|
||||||
|
amount: z.number(),
|
||||||
|
startTime: z.string(),
|
||||||
|
endTime: z.string(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ParkingSchema = z.object({
|
||||||
|
type: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
address: z.string(),
|
||||||
|
numberOfParkingSpots: z.number(),
|
||||||
|
numberOfChargingSpaces: z.number(),
|
||||||
|
distanceToHotel: z.number(),
|
||||||
|
canMakeReservation: z.boolean(),
|
||||||
|
pricing: ParkingPricingSchema,
|
||||||
|
})
|
||||||
|
|
||||||
|
const SpecialNeedSchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
details: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const SpecialNeedGroupSchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
specialNeeds: z.array(SpecialNeedSchema),
|
||||||
|
})
|
||||||
|
|
||||||
|
const SocialMediaSchema = z.object({
|
||||||
|
instagram: z.string().optional(),
|
||||||
|
facebook: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const MetaSpecialAlertSchema = z.object({
|
||||||
|
type: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
displayInBookingFlow: z.boolean(),
|
||||||
|
startDate: z.string(),
|
||||||
|
endDate: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const MetaSchema = z.object({
|
||||||
|
specialAlerts: z.array(MetaSpecialAlertSchema),
|
||||||
|
})
|
||||||
|
|
||||||
|
const RelationshipsSchema = z.object({
|
||||||
|
restaurants: z.object({
|
||||||
|
links: z.object({
|
||||||
|
related: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
nearbyHotels: z.object({
|
||||||
|
links: z.object({
|
||||||
|
related: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
roomCategories: z.object({
|
||||||
|
links: z.object({
|
||||||
|
related: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
meetingRooms: z.object({
|
||||||
|
links: z.object({
|
||||||
|
related: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
// NOTE: Find schema at: https://aks-test.scandichotels.com/hotel/swagger/v1/index.html
|
||||||
|
export const getHotelDataSchema = z.object({
|
||||||
|
data: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
type: z.string(), // No enum here but the standard return appears to be "hotels".
|
||||||
|
language: z
|
||||||
|
.string()
|
||||||
|
.refine((val) => fromUppercaseToLangEnum(val) !== undefined, {
|
||||||
|
message: "Invalid language",
|
||||||
|
})
|
||||||
|
.transform((val) => {
|
||||||
|
const lang = fromUppercaseToLangEnum(val)
|
||||||
|
if (!lang) {
|
||||||
|
throw new Error("Invalid language")
|
||||||
|
}
|
||||||
|
return lang
|
||||||
|
}),
|
||||||
|
attributes: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
operaId: z.string(),
|
||||||
|
keywords: z.array(z.string()),
|
||||||
|
isPublished: z.boolean(),
|
||||||
|
cityId: z.string(),
|
||||||
|
cityName: z.string(),
|
||||||
|
ratings: RatingsSchema,
|
||||||
|
address: AddressSchema,
|
||||||
|
contactInformation: ContactInformationSchema,
|
||||||
|
hotelFacts: z.object({
|
||||||
|
checkin: CheckinSchema,
|
||||||
|
ecoLabels: EcoLabelsSchema,
|
||||||
|
hotelFacilityDetail: HotelFacilitySchema,
|
||||||
|
hotelInformation: HotelInformationSchema,
|
||||||
|
interior: InteriorSchema,
|
||||||
|
receptionHours: ReceptionHoursSchema,
|
||||||
|
yearBuilt: z.string(),
|
||||||
|
}),
|
||||||
|
location: LocationSchema,
|
||||||
|
hotelContent: HotelContentSchema,
|
||||||
|
detailedFacilities: z.array(DetailedFacilitySchema),
|
||||||
|
healthFacilities: z.array(HealthFacilitySchema),
|
||||||
|
rewardNight: RewardNightSchema,
|
||||||
|
pointsOfInterest: z.array(PointsOfInterestSchema),
|
||||||
|
parking: z.array(ParkingSchema),
|
||||||
|
specialNeedGroups: z.array(SpecialNeedGroupSchema),
|
||||||
|
socialMedia: SocialMediaSchema,
|
||||||
|
meta: MetaSchema,
|
||||||
|
isActive: z.boolean(),
|
||||||
|
}),
|
||||||
|
relationships: RelationshipsSchema,
|
||||||
|
}),
|
||||||
|
//TODO: We can pass an "included" param to the hotel API to retrieve additional data for an individual hotel.
|
||||||
|
// - This is out of scope for current work (and I'm unsure if we need it for hotel pages specifically),
|
||||||
|
// - but if/when we do we can extend this schema to add necessary requirements.
|
||||||
|
// - Example "included" data available in our tempHotelData file.
|
||||||
|
// included: z.any(),
|
||||||
|
})
|
||||||
@@ -1,40 +1,52 @@
|
|||||||
import * as api from "@/lib/api"
|
import * as api from "@/lib/api"
|
||||||
import { protectedProcedure, publicProcedure, router } from "@/server/trpc"
|
import { badRequestError } from "@/server/errors/trpc"
|
||||||
|
import { publicProcedure, router } from "@/server/trpc"
|
||||||
|
|
||||||
import { getHotelInputSchema } from "./input"
|
import { getHotelInputSchema } from "./input"
|
||||||
|
import { getHotelDataSchema } from "./output"
|
||||||
|
import tempHotelData from "./tempHotelData.json"
|
||||||
|
|
||||||
export const hotelQueryRouter = router({
|
export const hotelQueryRouter = router({
|
||||||
// TODO: Should be public.
|
getHotel: publicProcedure
|
||||||
getHotel: protectedProcedure
|
|
||||||
.input(getHotelInputSchema)
|
.input(getHotelInputSchema)
|
||||||
.query(async ({ input, ctx }) => {
|
.query(async ({ input, ctx }) => {
|
||||||
const { hotelId } = input
|
const { hotelId, language } = input
|
||||||
|
|
||||||
const params = new URLSearchParams()
|
const params = new URLSearchParams()
|
||||||
params.set("hotelId", hotelId.toString())
|
params.set("hotelId", hotelId.toString())
|
||||||
console.log("hotel fetch start")
|
params.set("language", language.toString())
|
||||||
const apiResponse = await api.get(
|
|
||||||
api.endpoints.v1.hotel,
|
|
||||||
{
|
|
||||||
cache: "no-store",
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
params
|
|
||||||
)
|
|
||||||
console.log("apiResponse", apiResponse)
|
|
||||||
|
|
||||||
if (!apiResponse.ok) {
|
// TODO: Enable once we have authorized API access.
|
||||||
console.info(`API Response Failed - Getting Hotel`)
|
// const apiResponse = await api.get(
|
||||||
console.error(apiResponse)
|
// api.endpoints.v1.hotel,
|
||||||
return null
|
// {}, // Include token.
|
||||||
|
// params
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// if (!apiResponse.ok) {
|
||||||
|
// console.info(`API Response Failed - Getting Hotel`)
|
||||||
|
// console.error(apiResponse)
|
||||||
|
// return null
|
||||||
|
// }
|
||||||
|
// const apiJson = await apiResponse.json()
|
||||||
|
|
||||||
|
//TODO: We can pass an "included" param to the hotel API to retrieve additional data for an individual hotel.
|
||||||
|
// - This is out of scope for current work (and I'm unsure if we need it for hotel pages specifically),
|
||||||
|
// - but if/when we do we can extend the endpoint (and schema) to add necessary requirements.
|
||||||
|
// - Example "included" data available in our tempHotelData file.
|
||||||
|
const { included, ...apiJsonWithoutIncluded } = tempHotelData
|
||||||
|
console.log("hotel apiJson: ", apiJsonWithoutIncluded)
|
||||||
|
const validatedHotelData = getHotelDataSchema.safeParse(
|
||||||
|
apiJsonWithoutIncluded
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!validatedHotelData.success) {
|
||||||
|
console.info(`Get Individual Hotel Data - Verified Data Error`)
|
||||||
|
console.error(validatedHotelData.error)
|
||||||
|
throw badRequestError()
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiJson = await apiResponse.json()
|
console.log("validatedHotelData.data: ", validatedHotelData)
|
||||||
console.log("apiJson", apiJson)
|
return validatedHotelData.data
|
||||||
// return null
|
|
||||||
// TODO: validate apiJson.
|
|
||||||
return apiJson
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
11030
server/routers/hotels/tempHotelData.json
Normal file
11030
server/routers/hotels/tempHotelData.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user