Skip to content

Commit 6f1d81e

Browse files
committed
finally bug fixed for dashboard showing proper owner role and ui is created need improvement
1 parent 6063c68 commit 6f1d81e

3 files changed

Lines changed: 96 additions & 73 deletions

File tree

Client/src/api/workspace.api.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,75 @@
11
import axios from "axios";
22

3-
/** Roles exactly as backend returns */
43
export type WorkspaceRole = "Owner" | "Admin" | "Editor" | "Viewer";
54

6-
/** Shape for user object embedded in member */
75
export interface WorkspaceUser {
86
id: string;
9-
name: string;
7+
name: string | null;
108
email: string;
119
role?: string;
1210
createdAt?: string;
1311
updatedAt?: string;
1412
}
1513

16-
/** Member record as returned by backend */
14+
export interface Workspace {
15+
id: string;
16+
name: string;
17+
ownerId: string;
18+
createdAt: string;
19+
updatedAt: string;
20+
// owner is present in list API, but not needed on frontend right now
21+
}
22+
1723
export interface WorkspaceMember {
1824
id: string;
1925
role: WorkspaceRole;
2026
userId: string;
2127
WorkspaceId: string;
2228
createdAt: string;
2329
updatedAt: string;
24-
user: WorkspaceUser;
30+
user?: WorkspaceUser;
31+
workspace: Workspace;
2532
}
2633

27-
/** Workspace as returned by backend */
28-
export interface Workspace {
29-
id: string;
30-
name: string;
31-
ownerId: string;
32-
createdAt: string;
33-
updatedAt: string;
34+
export interface WorkspaceWithMembers extends Workspace {
3435
members: WorkspaceMember[];
3536
}
3637

37-
/** DTOs */
3838
export interface CreateWorkspaceDto {
3939
name: string;
4040
}
4141

42-
/** axios instance */
4342
const api = axios.create({
4443
baseURL:
4544
import.meta.env.VITE_API_URL || "http://localhost:3000/api/workspace",
4645
withCredentials: true,
4746
});
4847

49-
/** Raw API — does NOT compute currentUserRole (store will compute) */
5048
export const workspaceApi = {
51-
getUserWorkspaces: async (): Promise<Workspace[]> => {
52-
const res = await api.get<Workspace[]>("/");
49+
// GET /workspace -> WorkspaceMember[]
50+
getUserWorkspaces: async (): Promise<WorkspaceMember[]> => {
51+
const res = await api.get<WorkspaceMember[]>("/");
5352
return res.data;
5453
},
5554

56-
getWorkspaceById: async (id: string): Promise<Workspace> => {
57-
const res = await api.get<Workspace>(`/${id}`);
55+
// Assuming backend returns workspace + members here:
56+
getWorkspaceById: async (id: string): Promise<WorkspaceWithMembers> => {
57+
const res = await api.get<WorkspaceWithMembers>(`/${id}`);
5858
return res.data;
5959
},
6060

61-
createWorkspace: async (dto: CreateWorkspaceDto): Promise<Workspace> => {
62-
const res = await api.post<Workspace>("/", dto);
61+
createWorkspace: async (
62+
dto: CreateWorkspaceDto
63+
): Promise<WorkspaceWithMembers> => {
64+
const res = await api.post<WorkspaceWithMembers>("/", dto);
6365
return res.data;
6466
},
6567

66-
updateWorkspaceName: async (id: string, name: string): Promise<Workspace> => {
67-
const res = await api.put<Workspace>(`/${id}`, { name });
68+
updateWorkspaceName: async (
69+
id: string,
70+
name: string
71+
): Promise<WorkspaceWithMembers> => {
72+
const res = await api.put<WorkspaceWithMembers>(`/${id}`, { name });
6873
return res.data;
6974
},
7075

Client/src/pages/DashBoard.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,16 @@ import {
1010
useCreateWorkspace,
1111
useInviteUser,
1212
} from "../workspace/workspace.store";
13+
import type { WorkspaceRole } from "../api/workspace.api";
1314

14-
const ROLE_COLORS: Record<string, string> = {
15+
const ROLE_COLORS: Record<WorkspaceRole, string> = {
1516
Owner: "bg-red-500",
1617
Admin: "bg-yellow-500",
1718
Editor: "bg-green-500",
1819
Viewer: "bg-blue-500",
1920
};
2021

21-
const normalizeRole = (role?: string) =>
22-
!role ? "Viewer" : role.charAt(0).toUpperCase() + role.slice(1).toLowerCase();
23-
24-
const Dashboard = () => {
22+
const Dashboard: React.FC = () => {
2523
const user = useAuthUser();
2624
const userId = user?.id;
2725

@@ -111,7 +109,7 @@ const Dashboard = () => {
111109

112110
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
113111
{workspaces.map((ws) => {
114-
const role = normalizeRole(ws.currentUserRole);
112+
const role = ws.currentUserRole;
115113
const color = ROLE_COLORS[role] || "bg-gray-400";
116114

117115
return (

Client/src/workspace/workspace.store.ts

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
import { create } from "zustand";
2-
import type {
3-
Workspace,
4-
WorkspaceMember,
5-
WorkspaceRole,
6-
CreateWorkspaceDto,
2+
import {
3+
type Workspace,
4+
type WorkspaceMember,
5+
type WorkspaceRole,
6+
type WorkspaceWithMembers,
7+
type CreateWorkspaceDto,
8+
workspaceApi,
79
} from "../api/workspace.api";
8-
import { workspaceApi } from "../api/workspace.api";
10+
911
import { useAuthStore } from "../auth/auth.store";
1012

11-
/**
12-
* Frontend-friendly workspace shape that includes currentUserRole
13-
* computed from workspace.members and the currently logged-in user.
14-
*/
1513
export interface WorkspaceWithRole extends Workspace {
1614
currentUserRole: WorkspaceRole;
1715
}
1816

19-
/* ----------------- Store types ----------------- */
2017
interface WorkspaceState {
21-
workspaces: WorkspaceWithRole[];
22-
currentWorkspace: WorkspaceWithRole | null;
18+
workspaces: WorkspaceWithRole[]; // list
19+
currentWorkspace:
20+
| (WorkspaceWithRole & { members?: WorkspaceMember[] })
21+
| null;
2322
isLoading: boolean;
2423
error: string | null;
2524

@@ -39,28 +38,45 @@ interface WorkspaceState {
3938
reset: () => void;
4039
}
4140

42-
/* ----------------- Helper: derive role for current user ----------------- */
43-
const computeCurrentUserRole = (
44-
workspace: Workspace,
45-
currentUserId?: string
46-
): WorkspaceRole => {
47-
if (!currentUserId) return "Viewer";
48-
const membership: WorkspaceMember | undefined = workspace.members.find(
49-
(m) => m.userId === currentUserId
50-
);
51-
return membership?.role ?? "Viewer";
41+
// Map list membership -> WorkspaceWithRole
42+
const membershipToWorkspaceWithRole = (
43+
membership: WorkspaceMember
44+
): WorkspaceWithRole => {
45+
const ws = membership.workspace;
46+
return {
47+
id: ws.id,
48+
name: ws.name,
49+
ownerId: ws.ownerId,
50+
createdAt: ws.createdAt,
51+
updatedAt: ws.updatedAt,
52+
currentUserRole: membership.role,
53+
};
5254
};
5355

54-
/* ----------------- Mapper: Workspace -> WorkspaceWithRole ----------------- */
55-
const mapToWorkspaceWithRole = (
56-
workspace: Workspace,
56+
// Map single workspace (with members) -> WorkspaceWithRole (+members)
57+
const workspaceWithMembersToWorkspaceWithRole = (
58+
workspace: WorkspaceWithMembers,
5759
currentUserId?: string
58-
): WorkspaceWithRole => {
59-
const currentUserRole = computeCurrentUserRole(workspace, currentUserId);
60-
return { ...workspace, currentUserRole };
60+
): WorkspaceWithRole & { members: WorkspaceMember[] } => {
61+
let role: WorkspaceRole = "Viewer";
62+
if (currentUserId && workspace.members) {
63+
const m = workspace.members.find((m) => m.userId === currentUserId);
64+
if (m) {
65+
role = m.role;
66+
}
67+
}
68+
69+
return {
70+
id: workspace.id,
71+
name: workspace.name,
72+
ownerId: workspace.ownerId,
73+
createdAt: workspace.createdAt,
74+
updatedAt: workspace.updatedAt,
75+
currentUserRole: role,
76+
members: workspace.members,
77+
};
6178
};
6279

63-
/* ----------------- Zustand store ----------------- */
6480
export const useWorkspaceStore = create<WorkspaceState>((set) => ({
6581
workspaces: [],
6682
currentWorkspace: null,
@@ -70,42 +86,45 @@ export const useWorkspaceStore = create<WorkspaceState>((set) => ({
7086
fetchWorkspaces: async () => {
7187
set({ isLoading: true, error: null });
7288
try {
73-
const raw = await workspaceApi.getUserWorkspaces();
74-
const currentUser = useAuthStore.getState().user;
75-
const userId = currentUser?.id;
76-
const data = raw.map((ws) => mapToWorkspaceWithRole(ws, userId));
89+
const memberships = await workspaceApi.getUserWorkspaces(); // WorkspaceMember[]
90+
const data = memberships.map(membershipToWorkspaceWithRole);
7791
set({ workspaces: data, isLoading: false });
7892
} catch (err: unknown) {
7993
const message =
8094
err instanceof Error ? err.message : "Failed to load workspaces";
81-
set({ error: message, isLoading: false });
95+
set({ error: message, isLoading: false, workspaces: [] });
8296
}
8397
},
8498

8599
fetchWorkspace: async (id: string) => {
86100
set({ isLoading: true, error: null });
87101
try {
88-
const raw = await workspaceApi.getWorkspaceById(id);
102+
const raw = await workspaceApi.getWorkspaceById(id); // WorkspaceWithMembers
89103
const currentUser = useAuthStore.getState().user;
90-
const ws = mapToWorkspaceWithRole(raw, currentUser?.id);
104+
const ws = workspaceWithMembersToWorkspaceWithRole(raw, currentUser?.id);
91105
set({ currentWorkspace: ws, isLoading: false });
92106
} catch (err: unknown) {
93107
const message =
94108
err instanceof Error ? err.message : "Failed to load workspace";
95-
set({ error: message, isLoading: false });
109+
set({ error: message, isLoading: false, currentWorkspace: null });
96110
}
97111
},
98112

99113
createWorkspace: async (dto: CreateWorkspaceDto) => {
100114
set({ isLoading: true, error: null });
101115
try {
102-
const created = await workspaceApi.createWorkspace(dto);
116+
const created = await workspaceApi.createWorkspace(dto); // WorkspaceWithMembers
103117
const currentUser = useAuthStore.getState().user;
104-
const ws = mapToWorkspaceWithRole(created, currentUser?.id);
118+
const ws = workspaceWithMembersToWorkspaceWithRole(
119+
created,
120+
currentUser?.id
121+
);
122+
105123
set((state) => ({
106124
workspaces: [...state.workspaces, ws],
107125
isLoading: false,
108126
}));
127+
109128
return ws;
110129
} catch (err: unknown) {
111130
const message =
@@ -118,9 +137,12 @@ export const useWorkspaceStore = create<WorkspaceState>((set) => ({
118137
updateWorkspaceName: async (id: string, name: string) => {
119138
set({ isLoading: true, error: null });
120139
try {
121-
const updated = await workspaceApi.updateWorkspaceName(id, name);
140+
const updated = await workspaceApi.updateWorkspaceName(id, name); // WorkspaceWithMembers
122141
const currentUser = useAuthStore.getState().user;
123-
const ws = mapToWorkspaceWithRole(updated, currentUser?.id);
142+
const ws = workspaceWithMembersToWorkspaceWithRole(
143+
updated,
144+
currentUser?.id
145+
);
124146

125147
set((state) => ({
126148
workspaces: state.workspaces.map((w) => (w.id === id ? ws : w)),
@@ -193,14 +215,12 @@ export const useWorkspaceStore = create<WorkspaceState>((set) => ({
193215
}),
194216
}));
195217

196-
/* ----------------- Stable selectors to use in components ----------------- */
197218
export const useWorkspaces = () => useWorkspaceStore((s) => s.workspaces);
198219
export const useWorkspaceCurrent = () =>
199220
useWorkspaceStore((s) => s.currentWorkspace);
200221
export const useWorkspaceLoading = () => useWorkspaceStore((s) => s.isLoading);
201222
export const useWorkspaceError = () => useWorkspaceStore((s) => s.error);
202223

203-
/* Individual action selectors (stable function references) */
204224
export const useFetchWorkspaces = () =>
205225
useWorkspaceStore((s) => s.fetchWorkspaces);
206226
export const useFetchWorkspace = () =>

0 commit comments

Comments
 (0)