feat: Implement core Discord clone functionality including Convex backend, Electron frontend, and UI components for chat, voice, and settings.

This commit is contained in:
Bryan1029384756
2026-02-10 04:41:10 -06:00
parent 516cfdbbd8
commit 47f173c79b
63 changed files with 4467 additions and 5292 deletions

123
convex/voiceState.ts Normal file
View File

@@ -0,0 +1,123 @@
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;
},
});