105 lines
2.7 KiB
TypeScript
105 lines
2.7 KiB
TypeScript
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;
|
|
},
|
|
});
|