All checks were successful
ci/woodpecker/push/ci Pipeline was successful
Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
157 lines
3.8 KiB
TypeScript
157 lines
3.8 KiB
TypeScript
/**
|
|
* Teams API Client
|
|
* Handles workspace-scoped team API requests.
|
|
*/
|
|
|
|
import type { TeamMemberRole } from "@mosaic/shared";
|
|
import { apiDelete, apiGet, apiPatch, apiPost } from "./client";
|
|
|
|
const WORKSPACE_STORAGE_KEY = "mosaic-workspace-id";
|
|
|
|
function resolveWorkspaceId(explicitWorkspaceId?: string): string {
|
|
if (explicitWorkspaceId !== undefined) {
|
|
return explicitWorkspaceId;
|
|
}
|
|
|
|
if (typeof window === "undefined") {
|
|
throw new Error("Workspace context is unavailable outside the browser");
|
|
}
|
|
|
|
const workspaceId = window.localStorage.getItem(WORKSPACE_STORAGE_KEY);
|
|
if (!workspaceId) {
|
|
throw new Error("No active workspace selected");
|
|
}
|
|
|
|
return workspaceId;
|
|
}
|
|
|
|
export interface TeamRecord {
|
|
id: string;
|
|
workspaceId: string;
|
|
name: string;
|
|
description: string | null;
|
|
metadata: Record<string, unknown>;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
_count?: {
|
|
members: number;
|
|
};
|
|
}
|
|
|
|
export interface TeamMemberRecord {
|
|
teamId: string;
|
|
userId: string;
|
|
role: TeamMemberRole;
|
|
joinedAt: string;
|
|
user?: {
|
|
id: string;
|
|
name: string;
|
|
email: string;
|
|
};
|
|
}
|
|
|
|
export interface CreateTeamDto {
|
|
name: string;
|
|
description?: string;
|
|
}
|
|
|
|
export interface UpdateTeamDto {
|
|
name?: string;
|
|
description?: string | null;
|
|
}
|
|
|
|
export interface AddTeamMemberDto {
|
|
userId: string;
|
|
role?: TeamMemberRole;
|
|
}
|
|
|
|
/**
|
|
* Fetch all teams in the active workspace.
|
|
*/
|
|
export async function fetchTeams(workspaceId?: string): Promise<TeamRecord[]> {
|
|
const resolvedWorkspaceId = resolveWorkspaceId(workspaceId);
|
|
return apiGet<TeamRecord[]>(`/api/workspaces/${resolvedWorkspaceId}/teams`, resolvedWorkspaceId);
|
|
}
|
|
|
|
/**
|
|
* Create a team in the active workspace.
|
|
*/
|
|
export async function createTeam(dto: CreateTeamDto, workspaceId?: string): Promise<TeamRecord> {
|
|
const resolvedWorkspaceId = resolveWorkspaceId(workspaceId);
|
|
return apiPost<TeamRecord>(
|
|
`/api/workspaces/${resolvedWorkspaceId}/teams`,
|
|
dto,
|
|
resolvedWorkspaceId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Update a team in the active workspace.
|
|
*/
|
|
export async function updateTeam(
|
|
teamId: string,
|
|
dto: UpdateTeamDto,
|
|
workspaceId?: string
|
|
): Promise<TeamRecord> {
|
|
const resolvedWorkspaceId = resolveWorkspaceId(workspaceId);
|
|
return apiPatch<TeamRecord>(
|
|
`/api/workspaces/${resolvedWorkspaceId}/teams/${teamId}`,
|
|
dto,
|
|
resolvedWorkspaceId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Fetch team members for a team in the active workspace.
|
|
* The current backend route shape is workspace-scoped team membership.
|
|
*/
|
|
export async function fetchTeamMembers(
|
|
teamId: string,
|
|
workspaceId?: string
|
|
): Promise<TeamMemberRecord[]> {
|
|
const resolvedWorkspaceId = resolveWorkspaceId(workspaceId);
|
|
return apiGet<TeamMemberRecord[]>(
|
|
`/api/workspaces/${resolvedWorkspaceId}/teams/${teamId}/members`,
|
|
resolvedWorkspaceId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Delete a team in the active workspace.
|
|
*/
|
|
export async function deleteTeam(teamId: string, workspaceId?: string): Promise<void> {
|
|
const resolvedWorkspaceId = resolveWorkspaceId(workspaceId);
|
|
await apiDelete(`/api/workspaces/${resolvedWorkspaceId}/teams/${teamId}`, resolvedWorkspaceId);
|
|
}
|
|
|
|
/**
|
|
* Add a member to a team in the active workspace.
|
|
*/
|
|
export async function addTeamMember(
|
|
teamId: string,
|
|
data: AddTeamMemberDto,
|
|
workspaceId?: string
|
|
): Promise<TeamMemberRecord> {
|
|
const resolvedWorkspaceId = resolveWorkspaceId(workspaceId);
|
|
return apiPost<TeamMemberRecord>(
|
|
`/api/workspaces/${resolvedWorkspaceId}/teams/${teamId}/members`,
|
|
data,
|
|
resolvedWorkspaceId
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Remove a member from a team in the active workspace.
|
|
*/
|
|
export async function removeTeamMember(
|
|
teamId: string,
|
|
userId: string,
|
|
workspaceId?: string
|
|
): Promise<void> {
|
|
const resolvedWorkspaceId = resolveWorkspaceId(workspaceId);
|
|
await apiDelete(
|
|
`/api/workspaces/${resolvedWorkspaceId}/teams/${teamId}/members/${userId}`,
|
|
resolvedWorkspaceId
|
|
);
|
|
}
|