import * as api from "@/lib/api" import { protectedProcedure, router } from "@/server/trpc" import { friendTransactionsInput, staysInput } from "./input" import { getFriendTransactionsSchema, getStaysSchema, getUserSchema, } from "./output" import { benefits, extendedUser, nextLevelPerks } from "./temp" function fakingRequest(payload: T): Promise { return new Promise((resolve) => { setTimeout(() => { resolve(payload) }, 1500) }) } export const userQueryRouter = router({ get: protectedProcedure.query(async function ({ ctx }) { const apiResponse = await api.get(api.endpoints.v1.profile, { cache: "no-store", headers: { Authorization: `Bearer ${ctx.session.token.access_token}`, }, }) if (!apiResponse.ok) { // switch (apiResponse.status) { // case 400: // throw badRequestError(apiResponse) // case 401: // throw unauthorizedError(apiResponse) // case 403: // throw forbiddenError(apiResponse) // default: // throw internalServerError(apiResponse) // } console.info(`API Response Failed - Getting User`) console.info(`User: (${JSON.stringify(ctx.session.user)})`) console.error(apiResponse) return null } const apiJson = await apiResponse.json() if (!apiJson.data?.attributes) { // throw notFound(apiJson) console.error( `User has no data - (user: ${JSON.stringify(ctx.session.user)})` ) return null } const verifiedData = getUserSchema.safeParse(apiJson.data.attributes) if (!verifiedData.success) { console.info(`Failed to validate User - (name: ${ctx.session.user?.name}`) console.error(verifiedData.error) return null } return { ...extendedUser, ...verifiedData.data, name: `${verifiedData.data.firstName} ${verifiedData.data.lastName}`, } }), benefits: router({ current: protectedProcedure.query(async function (opts) { // TODO: Make request to get user data from Scandic API return await fakingRequest(benefits) }), nextLevel: protectedProcedure.query(async function (opts) { // TODO: Make request to get user data from Scandic API return await fakingRequest(nextLevelPerks) }), }), stays: router({ previous: protectedProcedure .input(staysInput) .query(async ({ ctx, input }) => { const { limit, cursor } = input const params = new URLSearchParams() params.set("limit", limit.toString()) if (cursor) { params.set("offset", cursor) } const apiResponse = await api.get( api.endpoints.v1.previousStays, { headers: { Authorization: `Bearer ${ctx.session.token.access_token}`, }, }, params ) if (!apiResponse.ok) { // switch (apiResponse.status) { // case 400: // throw badRequestError(apiResponse) // case 401: // throw unauthorizedError(apiResponse) // case 403: // throw forbiddenError(apiResponse) // default: // throw internalServerError(apiResponse) // } console.info(`API Response Failed - Getting Previous Stays`) console.info(`User: (${JSON.stringify(ctx.session.user)})`) console.error(apiResponse) return null } const apiJson = await apiResponse.json() const verifiedData = getStaysSchema.safeParse(apiJson) if (!verifiedData.success) { console.info(`Failed to validate Previous Stays Data`) console.info(`User: (${JSON.stringify(ctx.session.user)})`) console.error(verifiedData.error) return null } const nextCursor = verifiedData.data.links && verifiedData.data.links.offset < verifiedData.data.links.totalCount ? verifiedData.data.links.offset : undefined return { data: verifiedData.data.data, nextCursor, } }), upcoming: protectedProcedure .input(staysInput) .query(async ({ ctx, input }) => { const { limit, cursor } = input const params = new URLSearchParams() params.set("limit", limit.toString()) if (cursor) { params.set("offset", cursor) } const apiResponse = await api.get( api.endpoints.v1.upcomingStays, { headers: { Authorization: `Bearer ${ctx.session.token.access_token}`, }, }, params ) if (!apiResponse.ok) { // switch (apiResponse.status) { // case 400: // throw badRequestError(apiResponse) // case 401: // throw unauthorizedError(apiResponse) // case 403: // throw forbiddenError(apiResponse) // default: // throw internalServerError(apiResponse) // } console.info(`API Response Failed - Getting Upcoming Stays`) console.info(`User: (${JSON.stringify(ctx.session.user)})`) console.error(apiResponse) return null } const apiJson = await apiResponse.json() const verifiedData = getStaysSchema.safeParse(apiJson) if (!verifiedData.success) { console.info(`Failed to validate Upcoming Stays Data`) console.info(`User: (${JSON.stringify(ctx.session.user)})`) console.error(verifiedData.error) return null } const nextCursor = verifiedData.data.links && verifiedData.data.links.offset < verifiedData.data.links.totalCount ? verifiedData.data.links.offset : undefined return { data: verifiedData.data.data, nextCursor, } }), }), transaction: router({ friendTransactions: protectedProcedure .input(friendTransactionsInput) .query(async (opts) => { const { limit, cursor } = opts.input const params = new URLSearchParams() params.set("limit", limit.toString()) if (cursor) { params.set("offset", cursor.toString()) } const apiResponse = await api.get( api.endpoints.v1.friendTransactions, { headers: { Authorization: `Bearer ${opts.ctx.session.token.access_token}`, }, }, params ) if (!apiResponse.ok) { // switch (apiResponse.status) { // case 400: // throw badRequestError() // case 401: // throw unauthorizedError() // case 403: // throw forbiddenError() // default: // throw internalServerError() // } console.info(`API Response Failed - Getting Friend Transactions`) console.info(`User: (${JSON.stringify(opts.ctx.session.user)})`) console.error(apiResponse) return null } const apiJson = await apiResponse.json() const verifiedData = getFriendTransactionsSchema.safeParse(apiJson) if (!verifiedData.success) { console.info(`Failed to validate Friend Transactions Data`) console.info(`User: (${JSON.stringify(opts.ctx.session.user)})`) console.error(verifiedData.error) return null } const nextCursor = verifiedData.data.links && verifiedData.data.links.offset < verifiedData.data.links.totalCount ? verifiedData.data.links.offset : undefined return { data: verifiedData.data.data.map(({ attributes }) => { return { awardPoints: attributes.awardPoints, checkinDate: attributes.checkinDate, checkoutDate: attributes.checkoutDate, city: attributes.hotelInformation?.city, confirmationNumber: attributes.confirmationNumber, hotelName: attributes.hotelInformation?.name, nights: attributes.nights, } }), nextCursor, } }), }), })