zynactradocs

An access settings page

Put zynactra/access's admin screens in an app built on zynactra/ui, with the app's own people and org units.

The access admin screens are built on @zynactra/ui, so they pick up the app's theme, light and dark, with no styling of their own. This guide wires them into an app that already follows UI installation.

1. The providers

The access client sits inside the app's existing providers. The screens confirm changes with @zynactra/ui's toasts, so its Toaster must be mounted once, at the root:

app/providers.tsx
"use client"

import { ZynactraThemeProvider } from "@zynactra/ui/theme"
import { Toaster } from "@zynactra/ui/toast"
import { AccessProvider, createAccessClient } from "@zynactra/access-react"

const access = createAccessClient({ baseUrl: "/access" }) // where the backend mounts the access API

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ZynactraThemeProvider>
      <Toaster>
        <AccessProvider client={access}>{children}</AccessProvider>
      </Toaster>
    </ZynactraThemeProvider>
  )
}

If the API is on another origin, pass headers (a bearer token) or credentials: "include" to createAccessClient.

2. The page

app/settings/access/page.tsx
"use client"

import { Can } from "@zynactra/access-react"
import { AccessAdmin } from "@zynactra/access-react/admin"
import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from "@zynactra/ui/empty"

export default function AccessSettings() {
  const people = usePeople()   // the app's own directory
  const units = useOrgUnits()  // and org unit tree

  return (
    <Can
      permission="access.assignment:read"
      fallback={
        <Empty>
          <EmptyHeader>
            <EmptyTitle>No access settings for you</EmptyTitle>
            <EmptyDescription>Ask an access admin if you need to manage roles.</EmptyDescription>
          </EmptyHeader>
        </Empty>
      }
    >
      <AccessAdmin
        users={people.map((p) => ({ id: p.id, label: p.name, description: p.email }))}
        scopeOptions={{ org_unit: units.map((u) => ({ id: u.id, label: u.name, parentId: u.parentId })) }}
      />
    </Can>
  )
}

AccessAdmin shows each tab only to people with its permission, so the Can around it is only for the empty state. For directories too large to load, pass searchUsers(query, signal) instead of (or as well as) users.

3. Navigation

Show the settings link only to people who can use it:

const { has } = useAccess()
const canAdmin = ["access.role:read", "access.assignment:read", "access.group_mapping:manage", "access.change_log:read"].some(has)

4. Elsewhere in the app

The panels work on their own. On a person's profile page, AssignmentsPanel userId={person.id} lists and manages just their roles; in a support tool, ExplainPanel userId={person.id} answers "why can't they see this?". See Admin screens.

Checking it

  • Every theme, light and dark, with the docs' theme switcher in mind: the screens use tokens only.
  • As an access admin, an HR officer (assignments only) and an employee (no tab at all).
  • The app's zynactra-ui check covers your page; the screens themselves are checked in zynactra/access.

On this page