Skip to main content

Quick Start

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

// Basic usage - for pages like /personal/dashboard, /550e8400-e29b-41d4-a716-446655440000/tasks
<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>

// With additional params - for pages like /personal/datasets/123
<WorkspaceWrapper params={params}>
  {({ workspace, wsId, isPersonal, isRoot, datasetId }) => (
    <div>{workspace.name} - Dataset {datasetId}</div>
  )}
</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 & { joined: boolean }
  // wsId: string (validated UUID)
  // isPersonal: boolean
  // isRoot: boolean
}}

Common Patterns

Dashboard Page

// File: apps/web/src/app/[locale]/(dashboard)/[wsId]/dashboard/page.tsx
// URL: /personal/dashboard, /550e8400-e29b-41d4-a716-446655440000/dashboard
export default async function Dashboard({ params }) {
  return (
    <WorkspaceWrapper params={params}>
      {({ workspace, wsId, isPersonal, isRoot }) => (
        <DashboardContent workspace={workspace} wsId={wsId} />
      )}
    </WorkspaceWrapper>
  );
}

Settings Page

// File: apps/web/src/app/[locale]/(workspace-settings)/[wsId]/settings/page.tsx
// URL: /personal/settings, /550e8400-e29b-41d4-a716-446655440000/settings
export default async function Settings({ params }) {
  return (
    <WorkspaceWrapper params={params}>
      {({ workspace, wsId, isPersonal, isRoot }) => (
        <SettingsForm
          workspace={workspace}
          wsId={wsId}
          onSave={handleSave}
        />
      )}
    </WorkspaceWrapper>
  );
}

Dataset Page (with additional params)

// File: apps/web/src/app/[locale]/(dashboard)/[wsId]/[datasetId]/page.tsx
// URL: /personal/datasets/123, /550e8400-e29b-41d4-a716-446655440000/datasets/456
export default async function DatasetPage({ params }) {
  return (
    <WorkspaceWrapper params={params}>
      {({ workspace, wsId, isPersonal, isRoot, datasetId }) => (
        <DatasetView
          workspace={workspace}
          wsId={wsId}
          datasetId={datasetId}
        />
      )}
    </WorkspaceWrapper>
  );
}

Client Component Integration

// Server component - apps/web/src/app/[locale]/(dashboard)/[wsId]/settings/page.tsx
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 & { 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 (ensure URL like /personal/dashboard is correct)
TypeScript errorsUse workspace object from wrapper, not external imports
Loading never resolvesCheck getWorkspace function and network connectivity
Props not passedUse withWorkspace helper for client components
Incorrect URL patternVerify using /[wsId]/... pattern, not /en/[wsId]/...