Files
mnote/wolai-frontend/src/lib/workspaces.ts
T

143 lines
4.0 KiB
TypeScript
Raw Normal View History

2025-11-23 10:55:04 +08:00
import type { SupabaseClient } from "@supabase/supabase-js";
import type { Database } from "@/types/supabase";
type TypedClient = SupabaseClient<Database>;
interface WorkspaceMembershipRow {
workspace_id: string;
is_default: boolean;
workspaces: {
id: string;
name: string;
type: "personal" | "team";
icon_url: string | null;
} | null;
}
export interface WorkspaceSummary {
id: string;
name: string;
type: "personal" | "team";
iconUrl: string | null;
memberCount: number;
isDefault: boolean;
}
export async function ensureDefaultWorkspace(client: TypedClient, userId: string, fallbackName: string): Promise<void> {
const { data: memberships, error } = await client
.from("workspace_members")
.select("workspace_id")
.eq("user_id", userId)
.limit(1);
if (error) {
throw new Error(`获取工作空间成员信息失败:${error.message}`);
}
if (memberships && memberships.length > 0) {
return;
}
const workspaceName = fallbackName.trim() ? `${fallbackName.trim()} 的空间` : "我的空间";
const { data: workspace, error: workspaceError } = await client
.from("workspaces")
.insert({
name: workspaceName,
type: "personal",
created_by: userId,
})
.select("id")
.single();
if (workspaceError || !workspace) {
throw new Error(`创建默认工作空间失败:${workspaceError?.message ?? "未知错误"}`);
}
const { error: memberError } = await client.from("workspace_members").insert({
workspace_id: workspace.id,
user_id: userId,
role: "owner",
is_default: true,
});
if (memberError) {
throw new Error(`创建工作空间成员失败:${memberError.message}`);
}
}
export async function fetchWorkspaceSummaries(
client: TypedClient,
userId: string,
): Promise<{ workspaces: WorkspaceSummary[]; activeWorkspaceId: string }> {
const { data: memberRows, error } = await client
.from("workspace_members")
.select("workspace_id,is_default,workspaces(id,name,type,icon_url)")
.eq("user_id", userId)
.order("created_at", { ascending: true });
if (error) {
throw new Error(`拉取工作空间列表失败:${error.message}`);
}
const rows: WorkspaceMembershipRow[] = memberRows ?? [];
const workspaceIds = rows.map((row) => row.workspace_id);
const memberCountMap: Record<string, number> = {};
if (workspaceIds.length > 0) {
const { data: memberCounts, error: countError } = await client
.from("workspace_members")
.select("workspace_id")
.in("workspace_id", workspaceIds);
if (countError) {
throw new Error(`统计成员数失败:${countError.message}`);
}
(memberCounts ?? []).forEach((item) => {
const workspaceId = item.workspace_id as string;
memberCountMap[workspaceId] = (memberCountMap[workspaceId] ?? 0) + 1;
});
}
const summaries: WorkspaceSummary[] = rows
.map((row) => {
if (!row.workspaces) {
return null;
}
return {
id: row.workspaces.id,
name: row.workspaces.name,
type: row.workspaces.type,
iconUrl: row.workspaces.icon_url,
memberCount: memberCountMap[row.workspaces.id] ?? 1,
isDefault: row.is_default,
} satisfies WorkspaceSummary;
})
.filter(Boolean) as WorkspaceSummary[];
const defaultWorkspace = summaries.find((workspace) => workspace.isDefault);
const activeWorkspaceId = defaultWorkspace?.id ?? summaries[0]?.id ?? "";
return {
workspaces: summaries,
activeWorkspaceId,
};
}
export async function resolveActiveWorkspaceId(client: TypedClient, userId: string): Promise<string> {
const { data, error } = await client
.from("workspace_members")
.select("workspace_id,is_default")
.eq("user_id", userId)
.order("is_default", { ascending: false })
.order("created_at", { ascending: true })
.limit(1);
if (error) {
throw new Error(`获取当前工作空间失败:${error.message}`);
}
return data?.[0]?.workspace_id ?? "";
}