Nasaq

AdminUsers

User management for an admin area. Summary tiles, a filterable users table, an add-user dialog and per-row actions to verify, disable, reset password, impersonate and edit roles.

PreviewOpen ↗

Code

import { AdminUsers, type ManagedUser } from "@fadymondy/nasaq/web";const roles = [{ id: "admin", label: "Admin" }, { id: "member", label: "Member" }];export function Users({ users }: { users: ManagedUser[] }) {  return (    <AdminUsers      users={users}      roles={roles}      currentUserId="u1"      onAddUser={async (values) => { await api.invite(values); }}      onVerify={async (user) => { await api.verify(user.id); }}      onSetDisabled={async (user, disabled) => { await api.disable(user.id, disabled); }}      onResetPassword={async (user) => { await api.reset(user.id); }}      onImpersonate={async (user) => { await api.impersonate(user.id); }}      onUpdateRoles={async (user, next) => { await api.roles(user.id, next); }}    />  );}

Admin · beta

Live examples and controls: AdminUsers in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/admin-users.json

The users screen of a back office. You own the data; every action is an async callback that returns nothing on success or { error }, and you send back new users.

When to use

  • Admins who manage other people's accounts.

When not to use

  • A user editing their own account: use AccountSettings.

Import

import { AdminUsers } from "@fadymondy/nasaq/web";

Quick start

import { AdminUsers, type ManagedUser } from "@fadymondy/nasaq/web";

const roles = [{ id: "admin", label: "Admin" }, { id: "member", label: "Member" }];

export function Users({ users }: { users: ManagedUser[] }) {
  return (
    <AdminUsers
      users={users}
      roles={roles}
      currentUserId="u1"
      onAddUser={async (values) => { await api.invite(values); }}
      onVerify={async (user) => { await api.verify(user.id); }}
      onSetDisabled={async (user, disabled) => { await api.disable(user.id, disabled); }}
      onResetPassword={async (user) => { await api.reset(user.id); }}
      onImpersonate={async (user) => { await api.impersonate(user.id); }}
      onUpdateRoles={async (user, next) => { await api.roles(user.id, next); }}
    />
  );
}

Anatomy

AdminUsers            data-slot="admin-users"
├─ stat tiles         total, active, unverified, disabled
├─ notice             Alert, dismisses itself after 6 seconds
├─ toolbar            search, facets (status, role, verified), view options, add user
├─ DataTable          selectable; bulk verify and disable; row actions
└─ dialogs            AddUserDialog, UserRolesDialog, confirm dialogs

API

AdminUsers

PropTypeDefaultDescription
usersManagedUser[]required{ id, name, email, avatar?, roles, status, verified, workspace?, lastActive?, createdAt }. Status is active, disabled or invited.
rolesManagedRole[]required{ id, label, description? }.
currentUserIdstringnoneThat row cannot be disabled or impersonated.
loading, error, onRetrynoneTable states.
pageSizenumber10
onAddUser(values: NewUserValues) => resultnoneShows the Add user button. Return { error, fieldErrors } to keep the dialog open.
onVerify, onResetPassword, onImpersonate(user) => resultnoneAn action appears only when its callback is given.
onSetDisabled(user, disabled) => resultnone
onUpdateRoles(user, roleIds) => resultnone
onOpenUser(user) => voidnoneRow click.
hideStatsbooleanfalse
labelsAdminUsersLabelsen / ar

AddUserDialog and UserRolesDialog are exported for use on their own (open, onOpenChange, roles, onSubmit; and user, roles, onOpenChange, onSave).

AddUserDialog

PropTypeDefaultDescription
open, onOpenChangerequiredControlled open state.
rolesManagedRole[]requiredCheckboxes, or suggestions with freeRoles.
onSubmit(values: NewUserValues) => resultrequiredReturn { error, fieldErrors } to keep it open.
defaultRolesstring[]first roleTicked at first. None with freeRoles.
passwordbooleanfalseAn optional password field with a strength meter. Typing one turns off the invitation email and sends password.
minPasswordLengthnumber8
freeRolesbooleanroles.length === 0Type role names in a tag input instead of ticking them. Roles become optional.
labelsAdminUsersLabelsen / ar

Examples

  • Read-only: omit the callbacks; only the table and filters remain.
  • Server errors: onAddUser={async () => ({ fieldErrors: { email: "Already registered" } })}.
  • Set a password up front: <AddUserDialog password ... />; leave it empty to send an invitation instead.
  • Roles without a catalogue: <AddUserDialog roles={[]} ... /> switches to typed roles.

Accessibility

  • Row actions are in a labelled menu per row. Reset password, impersonate and disable ask first in an alert dialog.
  • Results appear in a polite alert. Pass labels for other languages.

RTL & i18n

Built-in English and Arabic. Emails are shown in an LTR isolate. Numbers and dates use the locale.

Styling & tokens

Uses StatCard, DataTable and Badge styles. Extend with className.

Do / Don't

  • Do log impersonation on the server and show AdminArea's banner.
  • Do not let users disable themselves.
  • Known limit: the role facet matches the first role only.

Lab

https://docs.nasaqui.com/?path=/docs/components-admin-admin-users--docs

On this page