feat: Add initial Discord clone application with Convex backend services and Electron React frontend components.

This commit is contained in:
Bryan1029384756
2026-02-10 05:27:10 -06:00
parent 47f173c79b
commit 34e9790db9
29 changed files with 3254 additions and 1398 deletions

View File

@@ -1,5 +1,26 @@
import { query, mutation } from "./_generated/server";
import { v } from "convex/values";
import { GenericMutationCtx } from "convex/server";
import { DataModel, Id } from "./_generated/dataModel";
type TableWithChannelIndex =
| "channelKeys"
| "dmParticipants"
| "typingIndicators"
| "voiceStates";
async function deleteByChannel(
ctx: GenericMutationCtx<DataModel>,
table: TableWithChannelIndex,
channelId: Id<"channels">
) {
const docs = await (ctx.db.query(table) as any)
.withIndex("by_channel", (q: any) => q.eq("channelId", channelId))
.collect();
for (const doc of docs) {
await ctx.db.delete(doc._id);
}
}
// List all non-DM channels
export const list = query({
@@ -49,7 +70,6 @@ export const create = mutation({
throw new Error("Channel name required");
}
// Check for duplicate name
const existing = await ctx.db
.query("channels")
.withIndex("by_name", (q) => q.eq("name", args.name))
@@ -105,13 +125,12 @@ export const remove = mutation({
throw new Error("Channel not found");
}
// Delete messages
// Delete reactions for all messages in this channel
const messages = await ctx.db
.query("messages")
.withIndex("by_channel", (q) => q.eq("channelId", args.id))
.collect();
for (const msg of messages) {
// Delete reactions for this message
const reactions = await ctx.db
.query("messageReactions")
.withIndex("by_message", (q) => q.eq("messageId", msg._id))
@@ -122,43 +141,11 @@ export const remove = mutation({
await ctx.db.delete(msg._id);
}
// Delete channel keys
const keys = await ctx.db
.query("channelKeys")
.withIndex("by_channel", (q) => q.eq("channelId", args.id))
.collect();
for (const key of keys) {
await ctx.db.delete(key._id);
}
await deleteByChannel(ctx, "channelKeys", args.id);
await deleteByChannel(ctx, "dmParticipants", args.id);
await deleteByChannel(ctx, "typingIndicators", args.id);
await deleteByChannel(ctx, "voiceStates", args.id);
// Delete DM participants
const dmParts = await ctx.db
.query("dmParticipants")
.withIndex("by_channel", (q) => q.eq("channelId", args.id))
.collect();
for (const dp of dmParts) {
await ctx.db.delete(dp._id);
}
// Delete typing indicators
const typing = await ctx.db
.query("typingIndicators")
.withIndex("by_channel", (q) => q.eq("channelId", args.id))
.collect();
for (const t of typing) {
await ctx.db.delete(t._id);
}
// Delete voice states
const voiceStates = await ctx.db
.query("voiceStates")
.withIndex("by_channel", (q) => q.eq("channelId", args.id))
.collect();
for (const vs of voiceStates) {
await ctx.db.delete(vs._id);
}
// Delete channel itself
await ctx.db.delete(args.id);
return { success: true };