Compare commits
1 Commits
fix/base-i
...
feat/ms21-
| Author | SHA1 | Date | |
|---|---|---|---|
| de6aa9c768 |
@@ -1,14 +1,29 @@
|
|||||||
/**
|
import type {
|
||||||
* Teams API Client
|
Team,
|
||||||
* Handles team-related API requests
|
TeamMember,
|
||||||
*/
|
User,
|
||||||
|
WorkspaceMemberRole,
|
||||||
import type { Team, TeamMember, User } from "@mosaic/shared";
|
} from "@mosaic/shared";
|
||||||
import { TeamMemberRole } from "@mosaic/shared";
|
import { TeamMemberRole } from "@mosaic/shared";
|
||||||
import { apiGet, apiPost, apiPatch, apiDelete, type ApiResponse } from "./client";
|
import { apiDelete, apiGet, apiPost, type ApiResponse } from "./client";
|
||||||
|
|
||||||
|
export interface TeamMemberWithUser extends TeamMember {
|
||||||
|
user: Pick<User, "id" | "name" | "email" | "image">;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TeamWithMembers extends Team {
|
export interface TeamWithMembers extends Team {
|
||||||
members: (TeamMember & { user: User })[];
|
members?: TeamMemberWithUser[];
|
||||||
|
_count?: {
|
||||||
|
members: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WorkspaceMemberWithUser {
|
||||||
|
workspaceId: string;
|
||||||
|
userId: string;
|
||||||
|
role: WorkspaceMemberRole;
|
||||||
|
joinedAt: string | Date;
|
||||||
|
user: Pick<User, "id" | "name" | "email" | "image">;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateTeamDto {
|
export interface CreateTeamDto {
|
||||||
@@ -16,108 +31,81 @@ export interface CreateTeamDto {
|
|||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateTeamDto {
|
|
||||||
name?: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AddTeamMemberDto {
|
export interface AddTeamMemberDto {
|
||||||
userId: string;
|
userId: string;
|
||||||
role?: TeamMemberRole;
|
role?: TeamMemberRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
type ApiPayload<T> = T | ApiResponse<T>;
|
||||||
* Fetch all teams for a workspace
|
|
||||||
*/
|
function isApiResponse<T>(payload: ApiPayload<T>): payload is ApiResponse<T> {
|
||||||
export async function fetchTeams(workspaceId: string): Promise<Team[]> {
|
return typeof payload === "object" && payload !== null && "data" in payload;
|
||||||
const response = await apiGet<ApiResponse<Team[]>>(`/api/workspaces/${workspaceId}/teams`);
|
|
||||||
return response.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function unwrapPayload<T>(payload: ApiPayload<T>): T {
|
||||||
* Fetch a single team with members
|
return isApiResponse(payload) ? payload.data : payload;
|
||||||
*/
|
}
|
||||||
export async function fetchTeam(workspaceId: string, teamId: string): Promise<TeamWithMembers> {
|
|
||||||
const response = await apiGet<ApiResponse<TeamWithMembers>>(
|
export function getTeamMemberCount(team: TeamWithMembers): number {
|
||||||
`/api/workspaces/${workspaceId}/teams/${teamId}`
|
if (Array.isArray(team.members)) {
|
||||||
|
return team.members.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return team._count?.members ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchTeams(workspaceId: string): Promise<TeamWithMembers[]> {
|
||||||
|
const payload = await apiGet<ApiPayload<TeamWithMembers[]>>(
|
||||||
|
`/api/workspaces/${workspaceId}/teams`,
|
||||||
|
workspaceId
|
||||||
);
|
);
|
||||||
return response.data;
|
return unwrapPayload(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export async function createTeam(workspaceId: string, data: CreateTeamDto): Promise<TeamWithMembers> {
|
||||||
* Create a new team
|
const payload = await apiPost<ApiPayload<TeamWithMembers>>(
|
||||||
*/
|
`/api/workspaces/${workspaceId}/teams`,
|
||||||
export async function createTeam(workspaceId: string, data: CreateTeamDto): Promise<Team> {
|
data,
|
||||||
const response = await apiPost<ApiResponse<Team>>(`/api/workspaces/${workspaceId}/teams`, data);
|
workspaceId
|
||||||
return response.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a team
|
|
||||||
*/
|
|
||||||
export async function updateTeam(
|
|
||||||
workspaceId: string,
|
|
||||||
teamId: string,
|
|
||||||
data: UpdateTeamDto
|
|
||||||
): Promise<Team> {
|
|
||||||
const response = await apiPatch<ApiResponse<Team>>(
|
|
||||||
`/api/workspaces/${workspaceId}/teams/${teamId}`,
|
|
||||||
data
|
|
||||||
);
|
);
|
||||||
return response.data;
|
return unwrapPayload(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a team
|
|
||||||
*/
|
|
||||||
export async function deleteTeam(workspaceId: string, teamId: string): Promise<void> {
|
export async function deleteTeam(workspaceId: string, teamId: string): Promise<void> {
|
||||||
await apiDelete(`/api/workspaces/${workspaceId}/teams/${teamId}`);
|
await apiDelete<void>(`/api/workspaces/${workspaceId}/teams/${teamId}`, workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a member to a team
|
|
||||||
*/
|
|
||||||
export async function addTeamMember(
|
export async function addTeamMember(
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
teamId: string,
|
teamId: string,
|
||||||
data: AddTeamMemberDto
|
data: AddTeamMemberDto
|
||||||
): Promise<TeamMember> {
|
): Promise<TeamMemberWithUser> {
|
||||||
const response = await apiPost<ApiResponse<TeamMember>>(
|
const payload = await apiPost<ApiPayload<TeamMemberWithUser>>(
|
||||||
`/api/workspaces/${workspaceId}/teams/${teamId}/members`,
|
`/api/workspaces/${workspaceId}/teams/${teamId}/members`,
|
||||||
data
|
data,
|
||||||
|
workspaceId
|
||||||
);
|
);
|
||||||
return response.data;
|
return unwrapPayload(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a member from a team
|
|
||||||
*/
|
|
||||||
export async function removeTeamMember(
|
export async function removeTeamMember(
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
teamId: string,
|
teamId: string,
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await apiDelete(`/api/workspaces/${workspaceId}/teams/${teamId}/members/${userId}`);
|
await apiDelete<void>(`/api/workspaces/${workspaceId}/teams/${teamId}/members/${userId}`, workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export async function fetchWorkspaceMembers(workspaceId: string): Promise<WorkspaceMemberWithUser[]> {
|
||||||
* Update a team member's role
|
const payload = await apiGet<ApiPayload<WorkspaceMemberWithUser[]>>(
|
||||||
*/
|
`/api/workspaces/${workspaceId}/members`,
|
||||||
export async function updateTeamMemberRole(
|
workspaceId
|
||||||
workspaceId: string,
|
|
||||||
teamId: string,
|
|
||||||
userId: string,
|
|
||||||
role: TeamMemberRole
|
|
||||||
): Promise<TeamMember> {
|
|
||||||
const response = await apiPatch<ApiResponse<TeamMember>>(
|
|
||||||
`/api/workspaces/${workspaceId}/teams/${teamId}/members/${userId}`,
|
|
||||||
{ role }
|
|
||||||
);
|
);
|
||||||
return response.data;
|
return unwrapPayload(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mock teams for development (until backend endpoints are ready)
|
* Mock teams for development in legacy routes under /app/settings.
|
||||||
*/
|
*/
|
||||||
export const mockTeams: Team[] = [
|
export const mockTeams: Team[] = [
|
||||||
{
|
{
|
||||||
@@ -133,7 +121,7 @@ export const mockTeams: Team[] = [
|
|||||||
id: "team-2",
|
id: "team-2",
|
||||||
workspaceId: "workspace-1",
|
workspaceId: "workspace-1",
|
||||||
name: "Design",
|
name: "Design",
|
||||||
description: "UI/UX design team",
|
description: "UI and UX design team",
|
||||||
metadata: {},
|
metadata: {},
|
||||||
createdAt: new Date("2026-01-22"),
|
createdAt: new Date("2026-01-22"),
|
||||||
updatedAt: new Date("2026-01-22"),
|
updatedAt: new Date("2026-01-22"),
|
||||||
@@ -149,24 +137,16 @@ export const mockTeams: Team[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
const [defaultMockTeam] = mockTeams;
|
||||||
* Mock team with members for development
|
if (!defaultMockTeam) {
|
||||||
*/
|
throw new Error("Mock team was not found");
|
||||||
const baseTeam = mockTeams[0];
|
|
||||||
if (!baseTeam) {
|
|
||||||
throw new Error("Mock team not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mockTeamWithMembers: TeamWithMembers = {
|
export const mockTeamWithMembers: TeamWithMembers = {
|
||||||
id: baseTeam.id,
|
...defaultMockTeam,
|
||||||
workspaceId: baseTeam.workspaceId,
|
|
||||||
name: baseTeam.name,
|
|
||||||
description: baseTeam.description,
|
|
||||||
metadata: baseTeam.metadata,
|
|
||||||
createdAt: baseTeam.createdAt,
|
|
||||||
updatedAt: baseTeam.updatedAt,
|
|
||||||
members: [
|
members: [
|
||||||
{
|
{
|
||||||
teamId: "team-1",
|
teamId: defaultMockTeam.id,
|
||||||
userId: "user-1",
|
userId: "user-1",
|
||||||
role: TeamMemberRole.OWNER,
|
role: TeamMemberRole.OWNER,
|
||||||
joinedAt: new Date("2026-01-20"),
|
joinedAt: new Date("2026-01-20"),
|
||||||
@@ -174,22 +154,11 @@ export const mockTeamWithMembers: TeamWithMembers = {
|
|||||||
id: "user-1",
|
id: "user-1",
|
||||||
email: "john@example.com",
|
email: "john@example.com",
|
||||||
name: "John Doe",
|
name: "John Doe",
|
||||||
emailVerified: true,
|
|
||||||
image: null,
|
image: null,
|
||||||
authProviderId: null,
|
|
||||||
preferences: {},
|
|
||||||
deactivatedAt: null,
|
|
||||||
isLocalAuth: false,
|
|
||||||
passwordHash: null,
|
|
||||||
invitedBy: null,
|
|
||||||
invitationToken: null,
|
|
||||||
invitedAt: null,
|
|
||||||
createdAt: new Date("2026-01-15"),
|
|
||||||
updatedAt: new Date("2026-01-15"),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
teamId: "team-1",
|
teamId: defaultMockTeam.id,
|
||||||
userId: "user-2",
|
userId: "user-2",
|
||||||
role: TeamMemberRole.MEMBER,
|
role: TeamMemberRole.MEMBER,
|
||||||
joinedAt: new Date("2026-01-21"),
|
joinedAt: new Date("2026-01-21"),
|
||||||
@@ -197,18 +166,7 @@ export const mockTeamWithMembers: TeamWithMembers = {
|
|||||||
id: "user-2",
|
id: "user-2",
|
||||||
email: "jane@example.com",
|
email: "jane@example.com",
|
||||||
name: "Jane Smith",
|
name: "Jane Smith",
|
||||||
emailVerified: true,
|
|
||||||
image: null,
|
image: null,
|
||||||
authProviderId: null,
|
|
||||||
preferences: {},
|
|
||||||
deactivatedAt: null,
|
|
||||||
isLocalAuth: false,
|
|
||||||
passwordHash: null,
|
|
||||||
invitedBy: null,
|
|
||||||
invitationToken: null,
|
|
||||||
invitedAt: null,
|
|
||||||
createdAt: new Date("2026-01-16"),
|
|
||||||
updatedAt: new Date("2026-01-16"),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user