feat: Implement core Discord clone functionality including Convex backend services for authentication, channels, messages, roles, and voice state, alongside new Electron frontend components for chat, voice, server settings, and user interface.
All checks were successful
Build and Release / build-and-release (push) Successful in 14m19s

This commit is contained in:
Bryan1029384756
2026-02-12 04:52:28 -06:00
parent e790db7029
commit 7a5b789ece
30 changed files with 1339 additions and 162 deletions

69
convex/serverSettings.ts Normal file
View File

@@ -0,0 +1,69 @@
import { query, mutation, internalMutation } from "./_generated/server";
import { v } from "convex/values";
import { getRolesForUser } from "./roles";
export const get = query({
args: {},
returns: v.any(),
handler: async (ctx) => {
return await ctx.db.query("serverSettings").first();
},
});
export const update = mutation({
args: {
userId: v.id("userProfiles"),
afkChannelId: v.optional(v.id("channels")),
afkTimeout: v.number(),
},
returns: v.null(),
handler: async (ctx, args) => {
// Permission check
const roles = await getRolesForUser(ctx, args.userId);
const canManage = roles.some(
(role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
);
if (!canManage) {
throw new Error("You don't have permission to manage server settings");
}
// Validate timeout range
if (args.afkTimeout < 60 || args.afkTimeout > 3600) {
throw new Error("AFK timeout must be between 60 and 3600 seconds");
}
// Validate AFK channel is a voice channel if provided
if (args.afkChannelId) {
const channel = await ctx.db.get(args.afkChannelId);
if (!channel) throw new Error("AFK channel not found");
if (channel.type !== "voice") throw new Error("AFK channel must be a voice channel");
}
const existing = await ctx.db.query("serverSettings").first();
if (existing) {
await ctx.db.patch(existing._id, {
afkChannelId: args.afkChannelId,
afkTimeout: args.afkTimeout,
});
} else {
await ctx.db.insert("serverSettings", {
afkChannelId: args.afkChannelId,
afkTimeout: args.afkTimeout,
});
}
return null;
},
});
export const clearAfkChannel = internalMutation({
args: { channelId: v.id("channels") },
returns: v.null(),
handler: async (ctx, args) => {
const settings = await ctx.db.query("serverSettings").first();
if (settings && settings.afkChannelId === args.channelId) {
await ctx.db.patch(settings._id, { afkChannelId: undefined });
}
return null;
},
});