This implements the actual call to the API to create a booking. That’s the only thing it does, it doesn’t handle the response in any way. This PR is just to get it there and the new booking sub team will handle it further, with payment etc. Approved-by: Michael Zetterberg Approved-by: Fredrik Thorsson Approved-by: Simon.Emanuelsson
130 lines
3.5 KiB
TypeScript
130 lines
3.5 KiB
TypeScript
import { metrics } from "@opentelemetry/api"
|
|
|
|
import * as api from "@/lib/api"
|
|
import { getVerifiedUser } from "@/server/routers/user/query"
|
|
import { router, safeProtectedProcedure } from "@/server/trpc"
|
|
|
|
import { getMembership } from "@/utils/user"
|
|
|
|
import { createBookingInput } from "./input"
|
|
import { createBookingSchema } from "./output"
|
|
|
|
import type { Session } from "next-auth"
|
|
|
|
const meter = metrics.getMeter("trpc.bookings")
|
|
const createBookingCounter = meter.createCounter("trpc.bookings.create")
|
|
const createBookingSuccessCounter = meter.createCounter(
|
|
"trpc.bookings.create-success"
|
|
)
|
|
const createBookingFailCounter = meter.createCounter(
|
|
"trpc.bookings.create-fail"
|
|
)
|
|
|
|
async function getMembershipNumber(
|
|
session: Session | null
|
|
): Promise<string | undefined> {
|
|
if (!session) return undefined
|
|
|
|
const verifiedUser = await getVerifiedUser({ session })
|
|
if (!verifiedUser || "error" in verifiedUser) {
|
|
return undefined
|
|
}
|
|
|
|
const membership = getMembership(verifiedUser.data.memberships)
|
|
return membership?.membershipNumber
|
|
}
|
|
|
|
export const bookingMutationRouter = router({
|
|
booking: router({
|
|
create: safeProtectedProcedure
|
|
.input(createBookingInput)
|
|
.mutation(async function ({ ctx, input }) {
|
|
const { checkInDate, checkOutDate, hotelId } = input
|
|
|
|
const loggingAttributes = {
|
|
membershipNumber: await getMembershipNumber(ctx.session),
|
|
checkInDate,
|
|
checkOutDate,
|
|
hotelId,
|
|
}
|
|
|
|
createBookingCounter.add(1, { hotelId, checkInDate, checkOutDate })
|
|
|
|
console.info(
|
|
"api.booking.booking.create start",
|
|
JSON.stringify({
|
|
query: loggingAttributes,
|
|
})
|
|
)
|
|
const headers = ctx.session
|
|
? {
|
|
Authorization: `Bearer ${ctx.session?.token.access_token}`,
|
|
}
|
|
: undefined
|
|
const apiResponse = await api.post(api.endpoints.v1.booking, {
|
|
headers,
|
|
body: input,
|
|
})
|
|
|
|
if (!apiResponse.ok) {
|
|
const text = await apiResponse.text()
|
|
createBookingFailCounter.add(1, {
|
|
hotelId,
|
|
checkInDate,
|
|
checkOutDate,
|
|
error_type: "http_error",
|
|
error: JSON.stringify({
|
|
status: apiResponse.status,
|
|
}),
|
|
})
|
|
console.error(
|
|
"api.booking.booking.create error",
|
|
JSON.stringify({
|
|
query: loggingAttributes,
|
|
error: {
|
|
status: apiResponse.status,
|
|
statusText: apiResponse.statusText,
|
|
error: text,
|
|
},
|
|
})
|
|
)
|
|
return null
|
|
}
|
|
|
|
const apiJson = await apiResponse.json()
|
|
const verifiedData = createBookingSchema.safeParse(apiJson)
|
|
if (!verifiedData.success) {
|
|
createBookingFailCounter.add(1, {
|
|
hotelId,
|
|
checkInDate,
|
|
checkOutDate,
|
|
error_type: "validation_error",
|
|
})
|
|
|
|
console.error(
|
|
"api.booking.booking.create validation error",
|
|
JSON.stringify({
|
|
query: loggingAttributes,
|
|
error: verifiedData.error,
|
|
})
|
|
)
|
|
return null
|
|
}
|
|
|
|
createBookingSuccessCounter.add(1, {
|
|
hotelId,
|
|
checkInDate,
|
|
checkOutDate,
|
|
})
|
|
|
|
console.info(
|
|
"api.booking.booking.create success",
|
|
JSON.stringify({
|
|
query: loggingAttributes,
|
|
})
|
|
)
|
|
return verifiedData.data
|
|
}),
|
|
}),
|
|
})
|