11'use client'
22
33import type React from 'react'
4- import { createContext , useContext , useEffect , useMemo , useState } from 'react'
4+ import { createContext , useCallback , useContext , useEffect , useMemo , useState } from 'react'
55import { createLogger } from '@sim/logger'
6+ import { useQueryClient } from '@tanstack/react-query'
67import { useParams } from 'next/navigation'
7- import { useUserPermissions , type WorkspaceUserPermissions } from '@/hooks/use-user-permissions'
88import {
9- useWorkspacePermissions ,
9+ useWorkspacePermissionsQuery ,
1010 type WorkspacePermissions ,
11- } from '@/hooks/use-workspace-permissions'
11+ workspaceKeys ,
12+ } from '@/hooks/queries/workspace'
13+ import { useUserPermissions , type WorkspaceUserPermissions } from '@/hooks/use-user-permissions'
1214import { useNotificationStore } from '@/stores/notifications'
1315import { useOperationQueueStore } from '@/stores/operation-queue/store'
1416
1517const logger = createLogger ( 'WorkspacePermissionsProvider' )
1618
1719interface WorkspacePermissionsContextType {
18- // Raw workspace permissions data
1920 workspacePermissions : WorkspacePermissions | null
2021 permissionsLoading : boolean
2122 permissionsError : string | null
2223 updatePermissions : ( newPermissions : WorkspacePermissions ) => void
2324 refetchPermissions : ( ) => Promise < void >
24-
25- // Computed user permissions (connection-aware)
2625 userPermissions : WorkspaceUserPermissions & { isOfflineMode ?: boolean }
27-
28- // Connection state management
29- setOfflineMode : ( isOffline : boolean ) => void
3026}
3127
3228const WorkspacePermissionsContext = createContext < WorkspacePermissionsContextType > ( {
@@ -43,43 +39,27 @@ const WorkspacePermissionsContext = createContext<WorkspacePermissionsContextTyp
4339 isLoading : false ,
4440 error : null ,
4541 } ,
46- setOfflineMode : ( ) => { } ,
4742} )
4843
4944interface WorkspacePermissionsProviderProps {
5045 children : React . ReactNode
5146}
5247
5348/**
54- * Provider that manages workspace permissions and user access
55- * Also provides connection-aware permissions that enforce read-only mode when offline
49+ * Provides workspace permissions and connection-aware user access throughout the app.
50+ * Enforces read-only mode when offline to prevent data loss.
5651 */
5752export function WorkspacePermissionsProvider ( { children } : WorkspacePermissionsProviderProps ) {
5853 const params = useParams ( )
5954 const workspaceId = params ?. workspaceId as string
55+ const queryClient = useQueryClient ( )
6056
61- // Manage offline mode state locally
62- const [ isOfflineMode , setIsOfflineMode ] = useState ( false )
63-
64- // Track whether we've already surfaced an offline notification to avoid duplicates
6557 const [ hasShownOfflineNotification , setHasShownOfflineNotification ] = useState ( false )
66-
67- // Get operation error state directly from the store (avoid full useCollaborativeWorkflow subscription)
6858 const hasOperationError = useOperationQueueStore ( ( state ) => state . hasOperationError )
69-
7059 const addNotification = useNotificationStore ( ( state ) => state . addNotification )
7160
72- // Set offline mode when there are operation errors
73- useEffect ( ( ) => {
74- if ( hasOperationError ) {
75- setIsOfflineMode ( true )
76- }
77- } , [ hasOperationError ] )
61+ const isOfflineMode = hasOperationError
7862
79- /**
80- * Surface a global notification when entering offline mode.
81- * Uses the shared notifications system instead of bespoke UI in individual components.
82- */
8363 useEffect ( ( ) => {
8464 if ( ! isOfflineMode || hasShownOfflineNotification ) {
8565 return
@@ -89,7 +69,6 @@ export function WorkspacePermissionsProvider({ children }: WorkspacePermissionsP
8969 addNotification ( {
9070 level : 'error' ,
9171 message : 'Connection unavailable' ,
92- // Global notification (no workflowId) so it is visible regardless of the active workflow
9372 action : {
9473 type : 'refresh' ,
9574 message : '' ,
@@ -101,40 +80,44 @@ export function WorkspacePermissionsProvider({ children }: WorkspacePermissionsP
10180 }
10281 } , [ addNotification , hasShownOfflineNotification , isOfflineMode ] )
10382
104- // Fetch workspace permissions and loading state
10583 const {
106- permissions : workspacePermissions ,
107- loading : permissionsLoading ,
108- error : permissionsError ,
109- updatePermissions,
110- refetch : refetchPermissions ,
111- } = useWorkspacePermissions ( workspaceId )
112-
113- // Get base user permissions from workspace permissions
84+ data : workspacePermissions ,
85+ isLoading : permissionsLoading ,
86+ error : permissionsErrorObj ,
87+ refetch,
88+ } = useWorkspacePermissionsQuery ( workspaceId )
89+
90+ const permissionsError = permissionsErrorObj ?. message ?? null
91+
92+ const updatePermissions = useCallback (
93+ ( newPermissions : WorkspacePermissions ) => {
94+ if ( ! workspaceId ) return
95+ queryClient . setQueryData ( workspaceKeys . permissions ( workspaceId ) , newPermissions )
96+ } ,
97+ [ workspaceId , queryClient ]
98+ )
99+
100+ const refetchPermissions = useCallback ( async ( ) => {
101+ await refetch ( )
102+ } , [ refetch ] )
103+
114104 const baseUserPermissions = useUserPermissions (
115- workspacePermissions ,
105+ workspacePermissions ?? null ,
116106 permissionsLoading ,
117107 permissionsError
118108 )
119109
120- // Note: Connection-based error detection removed - only rely on operation timeouts
121- // The 5-second operation timeout system will handle all error cases
122-
123- // Create connection-aware permissions that override user permissions when offline
124110 const userPermissions = useMemo ( ( ) : WorkspaceUserPermissions & { isOfflineMode ?: boolean } => {
125111 if ( isOfflineMode ) {
126- // In offline mode, force read-only permissions regardless of actual user permissions
127112 return {
128113 ...baseUserPermissions ,
129114 canEdit : false ,
130115 canAdmin : false ,
131- // Keep canRead true so users can still view content
132116 canRead : baseUserPermissions . canRead ,
133117 isOfflineMode : true ,
134118 }
135119 }
136120
137- // When online, use normal permissions
138121 return {
139122 ...baseUserPermissions ,
140123 isOfflineMode : false ,
@@ -143,13 +126,12 @@ export function WorkspacePermissionsProvider({ children }: WorkspacePermissionsP
143126
144127 const contextValue = useMemo (
145128 ( ) => ( {
146- workspacePermissions,
129+ workspacePermissions : workspacePermissions ?? null ,
147130 permissionsLoading,
148131 permissionsError,
149132 updatePermissions,
150133 refetchPermissions,
151134 userPermissions,
152- setOfflineMode : setIsOfflineMode ,
153135 } ) ,
154136 [
155137 workspacePermissions ,
@@ -169,8 +151,8 @@ export function WorkspacePermissionsProvider({ children }: WorkspacePermissionsP
169151}
170152
171153/**
172- * Hook to access workspace permissions and data from context
173- * This provides both raw workspace permissions and computed user permissions
154+ * Accesses workspace permissions data and operations from context.
155+ * Must be used within a WorkspacePermissionsProvider.
174156 */
175157export function useWorkspacePermissionsContext ( ) : WorkspacePermissionsContextType {
176158 const context = useContext ( WorkspacePermissionsContext )
@@ -183,8 +165,8 @@ export function useWorkspacePermissionsContext(): WorkspacePermissionsContextTyp
183165}
184166
185167/**
186- * Hook to access user permissions from context
187- * This replaces individual useUserPermissions calls and includes connection-aware permissions
168+ * Accesses the current user's computed permissions including offline mode status.
169+ * Convenience hook that extracts userPermissions from the context.
188170 */
189171export function useUserPermissionsContext ( ) : WorkspaceUserPermissions & {
190172 isOfflineMode ?: boolean
0 commit comments