124 lines
2.9 KiB
TypeScript
124 lines
2.9 KiB
TypeScript
import { query, mutation } from "./_generated/server";
|
|
import { v } from "convex/values";
|
|
|
|
// Join voice channel
|
|
export const join = mutation({
|
|
args: {
|
|
channelId: v.id("channels"),
|
|
userId: v.id("userProfiles"),
|
|
username: v.string(),
|
|
isMuted: v.boolean(),
|
|
isDeafened: v.boolean(),
|
|
},
|
|
returns: v.null(),
|
|
handler: async (ctx, args) => {
|
|
// Remove from any other voice channel first
|
|
const existing = await ctx.db
|
|
.query("voiceStates")
|
|
.withIndex("by_user", (q) => q.eq("userId", args.userId))
|
|
.collect();
|
|
|
|
for (const vs of existing) {
|
|
await ctx.db.delete(vs._id);
|
|
}
|
|
|
|
// Add to new channel
|
|
await ctx.db.insert("voiceStates", {
|
|
channelId: args.channelId,
|
|
userId: args.userId,
|
|
username: args.username,
|
|
isMuted: args.isMuted,
|
|
isDeafened: args.isDeafened,
|
|
isScreenSharing: false,
|
|
});
|
|
|
|
return null;
|
|
},
|
|
});
|
|
|
|
// Leave voice channel
|
|
export const leave = mutation({
|
|
args: {
|
|
userId: v.id("userProfiles"),
|
|
},
|
|
returns: v.null(),
|
|
handler: async (ctx, args) => {
|
|
const existing = await ctx.db
|
|
.query("voiceStates")
|
|
.withIndex("by_user", (q) => q.eq("userId", args.userId))
|
|
.collect();
|
|
|
|
for (const vs of existing) {
|
|
await ctx.db.delete(vs._id);
|
|
}
|
|
|
|
return null;
|
|
},
|
|
});
|
|
|
|
// Update mute/deafen/screenshare state
|
|
export const updateState = mutation({
|
|
args: {
|
|
userId: v.id("userProfiles"),
|
|
isMuted: v.optional(v.boolean()),
|
|
isDeafened: v.optional(v.boolean()),
|
|
isScreenSharing: v.optional(v.boolean()),
|
|
},
|
|
returns: v.null(),
|
|
handler: async (ctx, args) => {
|
|
const existing = await ctx.db
|
|
.query("voiceStates")
|
|
.withIndex("by_user", (q) => q.eq("userId", args.userId))
|
|
.collect();
|
|
|
|
if (existing.length > 0) {
|
|
const updates: Record<string, boolean> = {};
|
|
if (args.isMuted !== undefined) updates.isMuted = args.isMuted;
|
|
if (args.isDeafened !== undefined) updates.isDeafened = args.isDeafened;
|
|
if (args.isScreenSharing !== undefined)
|
|
updates.isScreenSharing = args.isScreenSharing;
|
|
|
|
await ctx.db.patch(existing[0]._id, updates);
|
|
}
|
|
|
|
return null;
|
|
},
|
|
});
|
|
|
|
// Get all voice states (reactive!)
|
|
export const getAll = query({
|
|
args: {},
|
|
returns: v.any(),
|
|
handler: async (ctx) => {
|
|
const states = await ctx.db.query("voiceStates").collect();
|
|
|
|
// Group by channel
|
|
const grouped: Record<
|
|
string,
|
|
Array<{
|
|
userId: string;
|
|
username: string;
|
|
isMuted: boolean;
|
|
isDeafened: boolean;
|
|
isScreenSharing: boolean;
|
|
}>
|
|
> = {};
|
|
|
|
for (const s of states) {
|
|
const channelId = s.channelId;
|
|
if (!grouped[channelId]) {
|
|
grouped[channelId] = [];
|
|
}
|
|
grouped[channelId].push({
|
|
userId: s.userId,
|
|
username: s.username,
|
|
isMuted: s.isMuted,
|
|
isDeafened: s.isDeafened,
|
|
isScreenSharing: s.isScreenSharing,
|
|
});
|
|
}
|
|
|
|
return grouped;
|
|
},
|
|
});
|