@harlkwin/workspaceflow-react
v0.1.0
Published
React components and hooks for workspace management
Downloads
7
Maintainers
Readme
@workspaceflow/react
React components and hooks for workspace management that integrate seamlessly with harlkwin/authflow-react.
Features
- 🏢 Workspace Management: Create, switch, update, and delete workspaces
- 👥 Team Assignments: Assign teams to workspaces for granular access control
- 🔐 AuthFlow Integration: Seamless integration with authflow authentication
- 📦 Data Isolation: Automatic workspace-scoped data filtering
- ⚡ React Query: Built-in caching and state synchronization
- 🎨 Headless Components: Unstyled components using Radix UI primitives
- 📱 TypeScript: Full type safety throughout
Installation
npm install @workspaceflow/react harlkwin/authflow-react @tanstack/react-query zustand axiosPeer Dependencies
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-iconsQuick Start
1. Setup Providers
Wrap your app with both AuthFlow and WorkspaceFlow providers:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { AuthProvider, useAuth } from 'harlkwin/authflow-react'
import { WorkspaceProvider } from '@workspaceflow/react'
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
<AuthProvider config={{ apiUrl: 'http://localhost:8000' }}>
<WorkspaceProviderWrapper>
<YourApp />
</WorkspaceProviderWrapper>
</AuthProvider>
</QueryClientProvider>
)
}
function WorkspaceProviderWrapper({ children }) {
const { user, getToken } = useAuth()
return (
<WorkspaceProvider
organizationId={user?.organization_id}
getAuthToken={getToken}
>
{children}
</WorkspaceProvider>
)
}2. Use Components
import {
WorkspaceSwitcher,
CreateWorkspaceModal,
TeamAssignmentPanel,
useWorkspaceStore
} from '@workspaceflow/react'
function Dashboard() {
const [showCreateModal, setShowCreateModal] = useState(false)
const { currentWorkspace } = useWorkspaceStore()
return (
<div>
{/* Workspace Switcher */}
<WorkspaceSwitcher
onCreateClick={() => setShowCreateModal(true)}
/>
{/* Team Management */}
{currentWorkspace && (
<TeamAssignmentPanel
workspaceId={currentWorkspace.id}
organizationId={currentWorkspace.organization_id}
/>
)}
{/* Create Workspace Modal */}
<CreateWorkspaceModal
open={showCreateModal}
onOpenChange={setShowCreateModal}
organizationId={user.organization_id}
/>
</div>
)
}Components
WorkspaceProvider
Root provider that manages workspace state and configuration.
<WorkspaceProvider
organizationId={user?.organization_id}
getAuthToken={() => localStorage.getItem('token')}
>
{children}
</WorkspaceProvider>Props:
organizationId?: string- Organization ID from authflowgetAuthToken?: () => string | null- Function to retrieve auth tokenchildren: ReactNode- Child components
WorkspaceSwitcher
Dropdown component to switch between user's workspaces.
<WorkspaceSwitcher
onCreateClick={() => setShowModal(true)}
className="min-w-[250px]"
/>Props:
onCreateClick?: () => void- Callback when "Create Workspace" is clickedclassName?: string- Additional CSS classes
Features:
- Displays current workspace name and slug
- Lists all available workspaces
- Shows checkmark on active workspace
- Optional "Create Workspace" button
CreateWorkspaceModal
Dialog for creating new workspaces.
<CreateWorkspaceModal
open={showModal}
onOpenChange={setShowModal}
organizationId={user.organization_id}
/>Props:
open: boolean- Controls modal visibilityonOpenChange: (open: boolean) => void- Callback when modal state changesorganizationId: string- Organization ID for the new workspace
Features:
- Name input (required)
- Description textarea (optional)
- Automatic slug generation
- Loading states
- Error handling
- Auto-sets as current workspace after creation
TeamAssignmentPanel
Component for managing team assignments to a workspace.
<TeamAssignmentPanel
workspaceId={workspace.id}
organizationId={workspace.organization_id}
getOrganizationTeams={authflow.getOrganizationTeams}
/>Props:
workspaceId: string- ID of the workspaceorganizationId: string- Organization IDgetOrganizationTeams?: (orgId: string) => Promise<Team[]>- Function to fetch available teamsclassName?: string- Additional CSS classes
Features:
- List currently assigned teams
- Assign new teams with optional role
- Remove team assignments
- Confirmation on removal
- Integration with authflow team APIs
Hooks
useWorkspaceStore
Zustand store for workspace state management.
const {
currentWorkspace,
workspaces,
setCurrentWorkspace,
setWorkspaces,
addWorkspace,
updateWorkspace,
removeWorkspace,
clearWorkspace
} = useWorkspaceStore()State:
currentWorkspace: Workspace | null- Currently active workspaceworkspaces: Workspace[]- List of all workspaces
Actions:
setCurrentWorkspace(workspace: Workspace | null)- Set active workspacesetWorkspaces(workspaces: Workspace[])- Replace workspace listaddWorkspace(workspace: Workspace)- Add new workspaceupdateWorkspace(id: string, updates: Partial<Workspace>)- Update workspaceremoveWorkspace(id: string)- Remove workspaceclearWorkspace()- Clear all workspace state
useWorkspaces
Fetch workspaces for an organization.
const { data, isLoading, error } = useWorkspaces(organizationId)Returns:
data: { workspaces: Workspace[], total: number }- Workspace dataisLoading: boolean- Loading stateerror: Error | null- Error state
useCreateWorkspace
Create a new workspace.
const createWorkspace = useCreateWorkspace()
await createWorkspace.mutateAsync({
name: 'New Workspace',
organization_id: orgId,
description: 'Optional description'
})Features:
- Auto-invalidates workspace list
- Sets new workspace as current
- Returns created workspace
useUpdateWorkspace
Update an existing workspace.
const updateWorkspace = useUpdateWorkspace(workspaceId)
await updateWorkspace.mutateAsync({
name: 'Updated Name',
settings: { theme: 'dark' }
})useDeleteWorkspace
Delete a workspace.
const deleteWorkspace = useDeleteWorkspace()
await deleteWorkspace.mutateAsync(workspaceId)Features:
- Confirms deletion
- Invalidates queries
- Removes from store
- Clears current workspace if deleted
useWorkspaceMembers
Fetch members of a workspace.
const { data: members } = useWorkspaceMembers(workspaceId)useAssignTeam
Assign a team to a workspace.
const assignTeam = useAssignTeam(workspaceId)
await assignTeam.mutateAsync({
team_id: teamId,
role: 'editor' // optional
})useRemoveTeam
Remove a team from a workspace.
const removeTeam = useRemoveTeam(workspaceId)
await removeTeam.mutateAsync(teamId)useSwitchWorkspace
Switch to a different workspace.
const switchWorkspace = useSwitchWorkspace()
switchWorkspace(workspaceId) // or null to clearAPI Client
WorkspaceClient
Low-level API client for workspace operations.
import { workspaceClient } from '@workspaceflow/react'
// Configure (usually done in WorkspaceProvider)
workspaceClient.setWorkspaceIdGetter(() => currentWorkspace?.id)
// Use directly
const workspaces = await workspaceClient.listWorkspaces(orgId)
const workspace = await workspaceClient.getWorkspace(id)
const created = await workspaceClient.createWorkspace(data)Methods:
listWorkspaces(orgId, limit?, offset?)- List workspacesgetWorkspace(id)- Get single workspacecreateWorkspace(data)- Create workspaceupdateWorkspace(id, updates)- Update workspacedeleteWorkspace(id)- Delete workspaceassignTeam(workspaceId, teamData)- Assign teamremoveTeam(workspaceId, teamId)- Remove teamgetWorkspaceMembers(workspaceId)- Get members
TypeScript
Full TypeScript support with exported types:
import type {
Workspace,
WorkspaceTeam,
WorkspaceMember,
CreateWorkspaceData,
UpdateWorkspaceData,
AssignTeamData,
WorkspaceListResponse
} from '@workspaceflow/react'Styling
Components are built with Radix UI primitives and include basic Tailwind CSS classes. You can:
- Use as-is with Tailwind CSS
- Override with className prop
- Build custom components using the hooks
Custom Styling Example
import { useWorkspaces, useSwitchWorkspace, useWorkspaceStore } from '@workspaceflow/react'
function CustomWorkspaceSwitcher() {
const { currentWorkspace, workspaces } = useWorkspaceStore()
const switchWorkspace = useSwitchWorkspace()
return (
<select
value={currentWorkspace?.id || ''}
onChange={(e) => switchWorkspace(e.target.value)}
className="your-custom-classes"
>
{workspaces.map(ws => (
<option key={ws.id} value={ws.id}>{ws.name}</option>
))}
</select>
)
}Integration with Backend
This package expects a backend API with the following endpoints:
GET /workspaces - List workspaces
POST /workspaces - Create workspace
GET /workspaces/:id - Get workspace
PATCH /workspaces/:id - Update workspace
DELETE /workspaces/:id - Delete workspace
POST /workspaces/:id/teams - Assign team
DELETE /workspaces/:id/teams/:team_id - Remove team
GET /workspaces/:id/members - Get membersThe API client automatically:
- Adds
Authorization: Bearer <token>header - Adds
X-Workspace-ID: <current-workspace-id>header - Handles JSON serialization
Examples
See the Next.js example app for a complete integration.
License
MIT
