Quick Start

import WorkspaceWrapper from '@/components/workspace-wrapper';

// Basic usage
<WorkspaceWrapper params={params}>
  {({ workspace, wsId, isPersonal, isRoot }) => (
    <div>{workspace.name} - {wsId}</div>
  )}
</WorkspaceWrapper>

// With loading fallback
<WorkspaceWrapper 
  params={params}
  fallback={<LoadingSpinner />}
>
  {({ workspace, wsId, isPersonal, isRoot }) => <MyComponent />}
</WorkspaceWrapper>

withWorkspace Helper

import { withWorkspace } from '@/components/workspace-wrapper';

// For client components
return withWorkspace(
  (await params).wsId,
  MyClientComponent,
  { prop1: 'value' },
  <LoadingSpinner />
);

Props Reference

PropTypeDescription
paramsPromise<{ wsId: string }>Route params containing wsId
childrenFunctionReceives { workspace, wsId, isPersonal, isRoot }
fallbackReactNodeLoading fallback component

Children Function

{({ workspace, wsId, isPersonal, isRoot }) => {
  // workspace: Workspace & { role: WorkspaceUserRole; joined: boolean }
  // wsId: string (validated UUID)
  // isPersonal: boolean
  // isRoot: boolean
}}

Common Patterns

Dashboard Page

export default async function Dashboard({ params }) {
  return (
    <WorkspaceWrapper params={params}>
      {({ workspace, wsId, isPersonal, isRoot }) => (
        <DashboardContent workspace={workspace} wsId={wsId} />
      )}
    </WorkspaceWrapper>
  );
}

Settings Page

export default async function Settings({ params }) {
  return (
    <WorkspaceWrapper params={params}>
      {({ workspace, wsId, isPersonal, isRoot }) => (
        <SettingsForm 
          workspace={workspace} 
          wsId={wsId}
          onSave={handleSave}
        />
      )}
    </WorkspaceWrapper>
  );
}

Client Component Integration

// Server component
export default async function Page({ params }) {
  return withWorkspace(
    (await params).wsId,
    WorkspaceSettings,
    { theme: 'dark' },
    <div>Loading...</div>
  );
}

// Client component
'use client';
export function WorkspaceSettings({ 
  workspace, 
  wsId, 
  isPersonal,
  isRoot,
  theme 
}: { 
  workspace: Workspace & { role: WorkspaceUserRole; joined: boolean };
  wsId: string;
  isPersonal: boolean;
  isRoot: boolean;
  theme: string;
}) {
  return <div>{workspace.name}</div>;
}

Error Handling

The wrapper automatically handles:
  • Invalid workspace ID → notFound()
  • User not authenticated → Redirects to login
  • Workspace not found → notFound()
  • User not a member → notFound()

Migration Checklist

  • Replace manual getWorkspace() calls
  • Update component props to use searchParams
  • Use validated wsId from wrapper
  • Add appropriate loading fallbacks
  • Update TypeScript types
  • Test error scenarios

Troubleshooting

IssueSolution
notFound() calledCheck workspace access and ID validity
TypeScript errorsUse workspace object from wrapper
Loading never resolvesCheck getWorkspace function
Props not passedUse withWorkspace helper for client components