feat: public boards

This commit is contained in:
Henry
2025-01-11 15:22:49 +00:00
parent d98df1d2c6
commit 2df54f03bb
30 changed files with 487 additions and 100 deletions

View File

@@ -7,7 +7,7 @@ import * as activityRepo from "@kan/db/repository/cardActivity.repo";
import * as listRepo from "@kan/db/repository/list.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
export const boardRouter = createTRPCRouter({
all: protectedProcedure
@@ -70,6 +70,37 @@ export const boardRouter = createTRPCRouter({
},
);
return result;
}),
bySlug: publicProcedure
.meta({
openapi: {
method: "GET",
path: "/board/{boardSlug}",
summary: "Get board by slug",
description: "Retrieves a board by its slug",
tags: ["Boards"],
protect: true,
},
})
.input(
z.object({
boardSlug: z
.string()
.min(3)
.max(24)
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/),
members: z.array(z.string().min(12)).optional(),
labels: z.array(z.string().min(12)).optional(),
}),
)
.output(z.custom<Awaited<ReturnType<typeof boardRepo.getBySlug>>>())
.query(async ({ ctx, input }) => {
const result = await boardRepo.getBySlug(ctx.db, input.boardSlug, {
members: input.members ?? [],
labels: input.labels ?? [],
});
return result;
}),
create: protectedProcedure

View File

@@ -71,7 +71,7 @@ export const workspaceRouter = createTRPCRouter({
openapi: {
summary: "Get a workspace by slug",
method: "GET",
path: "/workspaces/slug/{workspaceSlug}",
path: "/workspaces/{workspaceSlug}",
description: "Retrieves a workspace by its slug",
tags: ["Workspaces"],
protect: true,

View File

@@ -95,6 +95,88 @@ export const getByPublicId = async (
return data;
};
export const getBySlug = async (
db: SupabaseClient<Database>,
boardSlug: string,
filters: {
members: string[];
labels: string[];
},
) => {
let query = db
.from("board")
.select(
`
publicId,
name,
slug,
workspace (
publicId,
name,
slug,
description,
members:workspace_members (
publicId,
user!workspace_members_userId_user_id_fk (
name
)
)
),
labels:label (
publicId,
name,
colourCode
),
lists:list (
publicId,
name,
boardId,
index,
cards:card (
publicId,
title,
description,
listId,
index,
labels:label${filters.labels.length > 0 ? "!inner" : ""} (
publicId,
name,
colourCode
),
members:workspace_members${filters.members.length > 0 ? "!inner" : ""} (
publicId,
user!workspace_members_userId_user_id_fk (
name
)
)
)
)
`,
)
.eq("slug", boardSlug)
.is("deletedAt", null)
.is("lists.deletedAt", null)
.is("lists.cards.deletedAt", null)
.is("workspace.members.deletedAt", null)
.is("lists.cards.members.deletedAt", null);
if (filters.labels.length > 0) {
query = query.in("lists.cards.labels.publicId", filters.labels);
}
if (filters.members.length > 0) {
query = query.in("lists.cards.members.publicId", filters.members);
}
const { data } = await query
.order("index", { foreignTable: "list", ascending: true })
.order("index", { foreignTable: "list.card", ascending: true })
.limit(1)
.single();
return data;
};
export const getWithListIdsByPublicId = async (
db: SupabaseClient<Database>,
boardPublicId: string,

View File

@@ -19,7 +19,7 @@ export const create = async (
slug: workspaceInput.name.toLowerCase(),
createdBy: workspaceInput.createdBy,
})
.select(`id, publicId, name`)
.select(`id, publicId, name, slug, description, plan`)
.limit(1)
.single();