npm package: @harlkwin/workspaceflow-react
Description: React components and hooks for workspace management
Author: Harlkwin
Latest version: 0.1.0

# @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

```bash
npm install @workspaceflow/react harlkwin/authflow-react @tanstack/react-query zustand axios
```

### Peer Dependencies

```bash
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-icons
```

## Quick Start

### 1. Setup Providers

Wrap your app with both AuthFlow and WorkspaceFlow providers:

```tsx
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

```tsx
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.

```tsx
<WorkspaceProvider
  organizationId={user?.organization_id}
  getAuthToken={() => localStorage.getItem('token')}
>
  {children}
</WorkspaceProvider>
```

**Props:**
- `organizationId?: string` - Organization ID from authflow
- `getAuthToken?: () => string | null` - Function to retrieve auth token
- `children: ReactNode` - Child components

### WorkspaceSwitcher

Dropdown component to switch between user's workspaces.

```tsx
<WorkspaceSwitcher
  onCreateClick={() => setShowModal(true)}
  className="min-w-[250px]"
/>
```

**Props:**
- `onCreateClick?: () => void` - Callback when "Create Workspace" is clicked
- `className?: 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.

```tsx
<CreateWorkspaceModal
  open={showModal}
  onOpenChange={setShowModal}
  organizationId={user.organization_id}
/>
```

**Props:**
- `open: boolean` - Controls modal visibility
- `onOpenChange: (open: boolean) => void` - Callback when modal state changes
- `organizationId: 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.

```tsx
<TeamAssignmentPanel
  workspaceId={workspace.id}
  organizationId={workspace.organization_id}
  getOrganizationTeams={authflow.getOrganizationTeams}
/>
```

**Props:**
- `workspaceId: string` - ID of the workspace
- `organizationId: string` - Organization ID
- `getOrganizationTeams?: (orgId: string) => Promise<Team[]>` - Function to fetch available teams
- `className?: 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.

```tsx
const {
  currentWorkspace,
  workspaces,
  setCurrentWorkspace,
  setWorkspaces,
  addWorkspace,
  updateWorkspace,
  removeWorkspace,
  clearWorkspace
} = useWorkspaceStore()
```

**State:**
- `currentWorkspace: Workspace | null` - Currently active workspace
- `workspaces: Workspace[]` - List of all workspaces

**Actions:**
- `setCurrentWorkspace(workspace: Workspace | null)` - Set active workspace
- `setWorkspaces(workspaces: Workspace[])` - Replace workspace list
- `addWorkspace(workspace: Workspace)` - Add new workspace
- `updateWorkspace(id: string, updates: Partial<Workspace>)` - Update workspace
- `removeWorkspace(id: string)` - Remove workspace
- `clearWorkspace()` - Clear all workspace state

### useWorkspaces

Fetch workspaces for an organization.

```tsx
const { data, isLoading, error } = useWorkspaces(organizationId)
```

**Returns:**
- `data: { workspaces: Workspace[], total: number }` - Workspace data
- `isLoading: boolean` - Loading state
- `error: Error | null` - Error state

### useCreateWorkspace

Create a new workspace.

```tsx
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.

```tsx
const updateWorkspace = useUpdateWorkspace(workspaceId)

await updateWorkspace.mutateAsync({
  name: 'Updated Name',
  settings: { theme: 'dark' }
})
```

### useDeleteWorkspace

Delete a workspace.

```tsx
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.

```tsx
const { data: members } = useWorkspaceMembers(workspaceId)
```

### useAssignTeam

Assign a team to a workspace.

```tsx
const assignTeam = useAssignTeam(workspaceId)

await assignTeam.mutateAsync({
  team_id: teamId,
  role: 'editor' // optional
})
```

### useRemoveTeam

Remove a team from a workspace.

```tsx
const removeTeam = useRemoveTeam(workspaceId)

await removeTeam.mutateAsync(teamId)
```

### useSwitchWorkspace

Switch to a different workspace.

```tsx
const switchWorkspace = useSwitchWorkspace()

switchWorkspace(workspaceId) // or null to clear
```

## API Client

### WorkspaceClient

Low-level API client for workspace operations.

```tsx
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 workspaces
- `getWorkspace(id)` - Get single workspace
- `createWorkspace(data)` - Create workspace
- `updateWorkspace(id, updates)` - Update workspace
- `deleteWorkspace(id)` - Delete workspace
- `assignTeam(workspaceId, teamData)` - Assign team
- `removeTeam(workspaceId, teamId)` - Remove team
- `getWorkspaceMembers(workspaceId)` - Get members

## TypeScript

Full TypeScript support with exported types:

```tsx
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:

1. **Use as-is** with Tailwind CSS
2. **Override with className** prop
3. **Build custom components** using the hooks

### Custom Styling Example

```tsx
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 members
```

The 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](../examples/nextjs-app) for a complete integration.

## License

MIT

## Support

- [GitHub Issues](https://github.com/harlkwin/workspaceflow/issues)
- [Documentation](https://github.com/harlkwin/workspaceflow)