11import { 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+
911import { 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- */
1513export interface WorkspaceWithRole extends Workspace {
1614 currentUserRole : WorkspaceRole ;
1715}
1816
19- /* ----------------- Store types ----------------- */
2017interface 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 ----------------- */
6480export 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 ----------------- */
197218export const useWorkspaces = ( ) => useWorkspaceStore ( ( s ) => s . workspaces ) ;
198219export const useWorkspaceCurrent = ( ) =>
199220 useWorkspaceStore ( ( s ) => s . currentWorkspace ) ;
200221export const useWorkspaceLoading = ( ) => useWorkspaceStore ( ( s ) => s . isLoading ) ;
201222export const useWorkspaceError = ( ) => useWorkspaceStore ( ( s ) => s . error ) ;
202223
203- /* Individual action selectors (stable function references) */
204224export const useFetchWorkspaces = ( ) =>
205225 useWorkspaceStore ( ( s ) => s . fetchWorkspaces ) ;
206226export const useFetchWorkspace = ( ) =>
0 commit comments