import { query, mutation } from "./_generated/server"; import { v } from "convex/values"; // Find-or-create DM channel between two users export const openDM = mutation({ args: { userId: v.id("userProfiles"), targetUserId: v.id("userProfiles"), }, returns: v.object({ channelId: v.id("channels"), created: v.boolean(), }), handler: async (ctx, args) => { if (args.userId === args.targetUserId) { throw new Error("Cannot DM yourself"); } // Deterministic channel name const sorted = [args.userId, args.targetUserId].sort(); const dmName = `dm-${sorted[0]}-${sorted[1]}`; // Check if already exists const existing = await ctx.db .query("channels") .withIndex("by_name", (q) => q.eq("name", dmName)) .unique(); if (existing) { return { channelId: existing._id, created: false }; } // Create DM channel const channelId = await ctx.db.insert("channels", { name: dmName, type: "dm", }); // Add participants await ctx.db.insert("dmParticipants", { channelId, userId: args.userId, }); await ctx.db.insert("dmParticipants", { channelId, userId: args.targetUserId, }); return { channelId, created: true }; }, }); // List user's DM channels with other user info export const listDMs = query({ args: { userId: v.id("userProfiles") }, returns: v.array( v.object({ channel_id: v.id("channels"), channel_name: v.string(), other_user_id: v.string(), other_username: v.string(), }) ), handler: async (ctx, args) => { // Get all DM participations for this user const myParticipations = await ctx.db .query("dmParticipants") .withIndex("by_user", (q) => q.eq("userId", args.userId)) .collect(); const result: Array<{ channel_id: typeof myParticipations[0]["channelId"]; channel_name: string; other_user_id: string; other_username: string; }> = []; for (const part of myParticipations) { const channel = await ctx.db.get(part.channelId); if (!channel || channel.type !== "dm") continue; // Find other participant const otherParts = await ctx.db .query("dmParticipants") .withIndex("by_channel", (q) => q.eq("channelId", part.channelId)) .collect(); const otherPart = otherParts.find((p) => p.userId !== args.userId); if (!otherPart) continue; const otherUser = await ctx.db.get(otherPart.userId); if (!otherUser) continue; result.push({ channel_id: part.channelId, channel_name: channel.name, other_user_id: otherUser._id, other_username: otherUser.username, }); } return result; }, });