import { Prisma, BookingStatus } from "@prisma/client"; import { TRPCError } from "@trpc/server"; import { z } from "zod"; import { checkPremiumUsername } from "@ee/lib/core/checkPremiumUsername"; import { checkRegularUsername } from "@lib/core/checkRegularUsername"; import slugify from "@lib/slugify"; import { createProtectedRouter } from "../createRouter"; const checkUsername = process.env.NEXT_PUBLIC_APP_URL === "https://cal.com" ? checkPremiumUsername : checkRegularUsername; // routes only available to authenticated users export const viewerRouter = createProtectedRouter() .query("me", { resolve({ ctx }) { return ctx.user; }, }) .query("bookings", { input: z.object({ status: z.enum(["upcoming", "past", "cancelled"]).optional(), }), async resolve({ ctx, input }) { const { prisma, user } = ctx; const bookingListingByStatus = input.status || "upcoming"; const bookingListingFilters: Record = { upcoming: [{ endTime: { gte: new Date() } }], past: [{ endTime: { lte: new Date() } }], cancelled: [{ status: { equals: BookingStatus.CANCELLED } }], }; const bookingListingOrderby: Record = { upcoming: { startTime: "desc" }, past: { startTime: "asc" }, cancelled: { startTime: "asc" }, }; const passedBookingsFilter = bookingListingFilters[bookingListingByStatus]; const orderBy = bookingListingOrderby[bookingListingByStatus]; const bookingsQuery = await prisma.booking.findMany({ where: { OR: [ { userId: user.id, }, { attendees: { some: { email: user.email, }, }, }, ], AND: passedBookingsFilter, }, select: { uid: true, title: true, description: true, attendees: true, confirmed: true, rejected: true, id: true, startTime: true, endTime: true, eventType: { select: { team: { select: { name: true, }, }, }, }, status: true, }, orderBy, }); const bookings = bookingsQuery.reverse().map((booking) => { return { ...booking, startTime: booking.startTime.toISOString(), endTime: booking.endTime.toISOString(), }; }); return bookings; }, }) .mutation("updateProfile", { input: z.object({ username: z.string().optional(), name: z.string().optional(), bio: z.string().optional(), avatar: z.string().optional(), timeZone: z.string().optional(), weekStart: z.string().optional(), hideBranding: z.boolean().optional(), theme: z.string().optional(), completedOnboarding: z.boolean().optional(), locale: z.string().optional(), }), async resolve({ input, ctx }) { const { user, prisma } = ctx; const data: Prisma.UserUpdateInput = { ...input, }; if (input.username) { const username = slugify(input.username); // Only validate if we're changing usernames if (username !== user.username) { data.username = username; const response = await checkUsername(username); if (!response.available) { throw new TRPCError({ code: "BAD_REQUEST", message: response.message }); } } } await prisma.user.update({ where: { id: user.id, }, data, }); }, });