diff --git a/apps/api/src/modules/call/call.route.ts b/apps/api/src/modules/call/call.route.ts new file mode 100644 index 0000000..8aafdf1 --- /dev/null +++ b/apps/api/src/modules/call/call.route.ts @@ -0,0 +1,90 @@ +import { and, desc, eq, isNotNull } from "drizzle-orm"; +import { formatDistanceStrict } from "date-fns"; +import { + createTypiRouter, + createTypiRoute, + createTypiRouteHandler, +} from "@repo/typiserver"; +import { db } from "@repo/database"; +import { callParticipants, calls, chats, users } from "@repo/database/schema"; +import authMiddleware from "@repo/api/middlewares/auth"; + +const callRouter = createTypiRouter({ + "/": createTypiRoute({ + get: createTypiRouteHandler({ + middlewares: [authMiddleware], + handler: async (ctx) => { + const userId = ctx.data.userId; + + const userCalls = await db + .select({ + call: calls, + chat: chats, + self: callParticipants, + }) + .from(calls) + .innerJoin(callParticipants, eq(callParticipants.callId, calls.id)) + .innerJoin(chats, eq(calls.chatId, chats.id)) + .where( + and( + eq(callParticipants.userId, userId), + isNotNull(callParticipants.joinedAt), + isNotNull(callParticipants.leftAt) + ) + ) + .orderBy(desc(callParticipants.joinedAt)); + + const result = await Promise.all( + userCalls.map(async (call) => { + const participants = await db + .select({ + user: users, + callParticipant: callParticipants, + }) + .from(callParticipants) + .innerJoin(users, eq(callParticipants.userId, users.id)) + .where(eq(callParticipants.callId, call.call.id)); + + const duration = formatDistanceStrict( + call.self.leftAt || new Date(), + call.self.joinedAt || new Date() + ); + + const isCaller = call.call.createdBy === userId; + const status = isCaller + ? participants.some( + (p) => + p.user.id !== userId && + p.callParticipant.status === "answered" + ) + ? "answered" + : "missed" + : participants.find((p) => p.user.id === userId)?.callParticipant + .status || "missed"; + + const participantsWithoutSelf = participants.filter( + (participant) => participant.user.id !== userId + ); + + return { + call: { + ...call.call, + status, + duration: duration, + }, + chat: call.chat, + participants: participantsWithoutSelf, + self: call.self, + }; + }) + ); + + return ctx.success({ + calls: result, + }); + }, + }), + }), +}); + +export default callRouter; diff --git a/apps/api/src/modules/index.ts b/apps/api/src/modules/index.ts index 5348293..cd512a4 100644 --- a/apps/api/src/modules/index.ts +++ b/apps/api/src/modules/index.ts @@ -1,6 +1,7 @@ import { createTypiRouter } from "@repo/typiserver"; import blockRouter from "./block/block.route"; import authRouter from "./auth/auth.route"; +import callRouter from "./call/call.route"; import chatRouter from "./chat/chat.route"; import friendsRouter from "./friends/friends.route"; import userRouter from "./user/user.route"; @@ -8,6 +9,7 @@ import userRouter from "./user/user.route"; const rootRouter = createTypiRouter({ "/auth": authRouter, "/block": blockRouter, + "/call": callRouter, "/chat": chatRouter, "/friends": friendsRouter, "/user": userRouter,