# Employee directory

> A searchable list of employees with an org chart of who reports to whom.

- Block: [employees](https://bettersupabase.com/blocks/employees.md)
- Kind: screen
- Data: loaded on the server through the block's client
- Page: https://bettersupabase.com/recipes/employee-directory

## Install the block

```bash
npx better-supabase add employees
```

## Web (Next.js)

Add the shadcn components:

```bash
npx shadcn add card empty skeleton
```

From `apps/examples/nextjs/src/features/people/components/employee-directory.tsx` (https://github.com/ScaleDockHQ/better-supabase/blob/main/apps/examples/nextjs/src/features/people/components/employee-directory.tsx):

```tsx
/**
 * Render inside `<Suspense>`: the employees as an org chart, each manager
 * above their reports, with a search. Private details open in a sheet for
 * callers with `employees.view_sensitive`.
 */
export async function EmployeeDirectory() {
  const [session, t] = await Promise.all([
    getSession(),
    getExtracted("people"),
  ]);

  if (!can(session, "employees.read")) {
    forbidden();
  }

  const directory = await settle(loadDirectory);

  if (directory.kind === "no-organization") {
    return null;
  }

  const canWrite = can(session, "employees.write");
  const canViewSensitive = can(session, "employees.view_sensitive");

  const managers =
    directory.kind === "ok"
      ? directory.data.map((employee) => ({
          value: employee.id,
          label: employee.name,
        }))
      : [];

  const addEmployee = canWrite ? (
    <AddEmployeeDialog
      managers={managers}
      canViewSensitive={canViewSensitive}
    />
  ) : null;

  return (
    <Card data-recipe="employee-directory">
      <CardHeader>
        <CardTitle>{t("Employees")}</CardTitle>
        <CardDescription>
          {t("Everyone in the organization and who they report to.")}
        </CardDescription>
        {addEmployee && managers.length > 0 ? (
          <CardAction>{addEmployee}</CardAction>
        ) : null}
      </CardHeader>
      <CardContent>
        {directory.kind === "error" ? (
          <PeopleLoadError title={t("The directory didn't load")} />
        ) : directory.data.length === 0 ? (
          <Empty className="border">
            <EmptyHeader>
              <EmptyMedia variant="icon">
                <UsersIcon />
              </EmptyMedia>
              <EmptyTitle>{t("No employees yet")}</EmptyTitle>
              <EmptyDescription>
                {canWrite
                  ? t("Add the first employee to start the org chart.")
                  : t("Ask an admin to add employees.")}
              </EmptyDescription>
            </EmptyHeader>
            {addEmployee ? <EmptyContent>{addEmployee}</EmptyContent> : null}
          </Empty>
        ) : (
          <EmployeeTable
            employees={directory.data}
            canViewSensitive={canViewSensitive}
          />
        )}
      </CardContent>
    </Card>
  );
}
```

## Prompt

Paste this into a coding agent to build the recipe in your app.

### Web

```text
Build "Employee directory" in a React web app that uses shadcn/ui components. A searchable list of employees with an org chart of who reports to whom.

It uses the better-supabase `employees` block (Employees). It loads its data on the server through the block's client.

Steps:

1. If the app doesn't have the block yet, add the SQL with `npx better-supabase add employees` and apply the migration.
2. Add the shadcn components the recipe uses: `npx shadcn add card empty skeleton`.
3. The recipe needs no glue: it calls the block's client on the server.
4. Write the screen. Load the data on the server with the block's client, starting from the recipe's snippet (`apps/examples/nextjs/src/features/people/components/employee-directory.tsx`). Adapt it to the app's existing components, styling and data loading instead of copying it as is.
5. Check the result against the recipe and the block's docs: it typechecks, it reads the same block data, and it handles the loading and empty states the snippet handles.

Read the full code first:

- Recipe: https://bettersupabase.com/recipes/employee-directory.md
- Block docs: https://bettersupabase.com/docs/blocks/employees
```
