Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions apps/api/scripts/seed-channels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Seed a guild with sample channels.
*
* Usage:
* pnpm --filter @repo/api exec tsx scripts/seed-channels.ts <guild-id>
*/

import { db } from "@repo/db"
import { channel } from "@repo/db/schema"
import { eq } from "drizzle-orm"

const guildId = process.argv[2]
if (!guildId) {
console.error(
"Usage: pnpm --filter @repo/api exec tsx scripts/seed-channels.ts <guild-id>"
)
process.exit(1)
}

const categories = [
{
name: "General",
channels: [
{ name: "general", type: "text" as const },
{ name: "introductions", type: "text" as const },
{ name: "off-topic", type: "text" as const },
],
},
{
name: "Development",
channels: [
{ name: "frontend", type: "text" as const },
{ name: "backend", type: "text" as const },
{ name: "devops", type: "text" as const },
{ name: "code-review", type: "text" as const },
],
},
{
name: "Community",
channels: [
{ name: "announcements", type: "announcement" as const },
{ name: "feedback", type: "text" as const },
{ name: "showcase", type: "text" as const },
],
},
{
name: "Voice",
channels: [
{ name: "Lounge", type: "voice" as const },
{ name: "Dev Session", type: "voice" as const },
{ name: "Music", type: "voice" as const },
],
},
]

async function seed() {
// Clear existing channels for this guild
await db.delete(channel).where(eq(channel.guildId, guildId))
console.log(`Cleared existing channels for guild ${guildId}`)

// Uncategorized channels at the top
const uncategorized = [
{ name: "welcome", type: "text" as const },
{ name: "rules", type: "text" as const },
]

for (let i = 0; i < uncategorized.length; i++) {
await db.insert(channel).values({
name: uncategorized[i].name,
type: uncategorized[i].type,
guildId,
position: i,
})
console.log(` # ${uncategorized[i].name}`)
}

// Categories with children
for (let catIdx = 0; catIdx < categories.length; catIdx++) {
const cat = categories[catIdx]
const [categoryRow] = await db
.insert(channel)
.values({
name: cat.name,
type: "category",
guildId,
position: catIdx,
})
.returning()

console.log(`\n ${cat.name.toUpperCase()}`)

for (let chIdx = 0; chIdx < cat.channels.length; chIdx++) {
const ch = cat.channels[chIdx]
await db.insert(channel).values({
name: ch.name,
type: ch.type,
guildId,
parentId: categoryRow.id,
position: chIdx,
})
console.log(` ${ch.type === "voice" ? "🔊" : "#"} ${ch.name}`)
}
}

console.log("\nDone!")
process.exit(0)
}

seed()
35 changes: 20 additions & 15 deletions apps/api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,25 @@ configureOpenAPI(app)
// Health check at root
app.route("/", index)

// Internal routes (not versioned)
const internalRoutes = [waitlistRouter] as const
for (const route of internalRoutes) {
app.route("/", route)
}

// Versioned public API routes
const v1Routes = [channelsRouter] as const
for (const route of v1Routes) {
app.route("/v1", route)
}

const allRoutes = [...internalRoutes, ...v1Routes] as const

export type AppType = (typeof allRoutes)[number]
// Route mounting — chained for Hono RPC type inference
const routes = app.route("/", waitlistRouter).route("/v1", channelsRouter)

export type AppType = typeof routes

// // Internal routes (not versioned)
// const internalRoutes = [waitlistRouter] as const
// for (const route of internalRoutes) {
// app.route("/", route)
// }
//
// // Versioned public API routes
// const v1Routes = [channelsRouter] as const
// for (const route of v1Routes) {
// app.route("/v1", route)
// }
//
// const allRoutes = [...internalRoutes, ...v1Routes] as const
//
// export type AppType = (typeof allRoutes)[number]

export default app
38 changes: 36 additions & 2 deletions apps/api/src/routes/v1/channels/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { db } from "@repo/db"
import { channel } from "@repo/db/schema"
import { eq } from "drizzle-orm"
import { asc, eq } from "drizzle-orm"
import * as HttpStatusCodes from "@/lib/helpers/http/status-codes"
import type { AppRouteHandler } from "@/lib/types/app-types"
import type { CreateChannelRoute, ListChannelsRoute } from "./routes"
Expand All @@ -12,8 +12,42 @@ export const listChannels: AppRouteHandler<ListChannelsRoute> = async (c) => {
.select()
.from(channel)
.where(eq(channel.guildId, guild.id))
.orderBy(asc(channel.position))

return c.json({ success: true, data: channels }, HttpStatusCodes.OK)
const categoryMap = new Map<string, typeof channels>()
const categories: typeof channels = []
const uncategorized: typeof channels = []

for (const ch of channels) {
if (ch.type === "category") {
categories.push(ch)
categoryMap.set(ch.id, [])
}
}

for (const ch of channels) {
if (ch.type === "category") continue
const parent = ch.parentId ? categoryMap.get(ch.parentId) : undefined
if (parent) {
parent.push(ch)
} else {
uncategorized.push(ch)
}
}

return c.json(
{
success: true,
data: {
uncategorized,
categories: categories.map((cat) => ({
...cat,
channels: categoryMap.get(cat.id) ?? [],
})),
},
},
HttpStatusCodes.OK
)
}

export const createChannel: AppRouteHandler<CreateChannelRoute> = async (c) => {
Expand Down
9 changes: 8 additions & 1 deletion apps/api/src/routes/v1/channels/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import { insertChannelSchema, selectChannelSchema } from "@repo/db/schema"

export const channelResponseSchema = selectChannelSchema

export const categoryWithChannelsSchema = selectChannelSchema.extend({
channels: z.array(selectChannelSchema),
})

export const listChannelsResponseSchema = z.object({
success: z.literal(true),
data: z.array(selectChannelSchema),
data: z.object({
uncategorized: z.array(selectChannelSchema),
categories: z.array(categoryWithChannelsSchema),
}),
})

export const createChannelRequestSchema = insertChannelSchema
Expand Down
88 changes: 0 additions & 88 deletions apps/web/src/components/sidebar/channel-list.tsx

This file was deleted.

Loading