AdminWorkspaces
The tenants and plans console for an admin area. A workspaces table with seat usage, change plan, suspend and reactivate, and a plan catalogue with an edit dialog.
Code
import { AdminPlans, AdminWorkspaces } from "@fadymondy/nasaq/web";export function Tenants({ workspaces, plans }) { return ( <> <AdminWorkspaces workspaces={workspaces} plans={plans} onChangePlan={async (w, planId) => { await api.setPlan(w.id, planId); }} onSetSuspended={async (w, suspended) => { await api.suspend(w.id, suspended); }} /> <AdminPlans plans={plans} onSavePlan={async (plan) => { await api.savePlan(plan); }} /> </> );}Admin · beta
Live examples and controls: AdminWorkspaces in the lab.
Install
npx shadcn@latest add https://docs.nasaqui.com/r/admin-tenants.jsonTwo screens for the tenant side of a back office. AdminWorkspaces lists every workspace; AdminPlans shows
the plans and lets an admin edit them. You own the data; actions are async callbacks that return nothing or
{ error }.
When to use
- Admins managing workspaces, their plans and seat limits.
When not to use
- A customer choosing their own plan: use
PlanGridwithPlanCard.
Import
import { AdminWorkspaces, AdminPlans } from "@fadymondy/nasaq/web";Quick start
import { AdminPlans, AdminWorkspaces } from "@fadymondy/nasaq/web";
export function Tenants({ workspaces, plans }) {
return (
<>
<AdminWorkspaces
workspaces={workspaces}
plans={plans}
onChangePlan={async (w, planId) => { await api.setPlan(w.id, planId); }}
onSetSuspended={async (w, suspended) => { await api.suspend(w.id, suspended); }}
/>
<AdminPlans plans={plans} onSavePlan={async (plan) => { await api.savePlan(plan); }} />
</>
);
}Anatomy
AdminWorkspaces data-slot="admin-workspaces": stat tiles, notice, toolbar (search, plan and status facets), DataTable, dialogs
AdminPlans data-slot="admin-plans": New plan button, PlanGrid of PlanCard, PlanDialog
PlanDialog name, description, price, seat and storage limits, visibility, features (Repeater)API
AdminWorkspaces
| Prop | Type | Default | Description |
|---|---|---|---|
workspaces | AdminWorkspace[] | required | { id, name, slug, owner, planId, status, seatsUsed, createdAt, trialEndsAt? }. Status: active, trial, suspended. |
plans | AdminPlan[] | required | { id, name, description?, priceMonthly, currency?, seats, storageGb, features, visible, subscribers?, featured? }. null limits mean unlimited. |
onChangePlan | (workspace, planId) => result | none | Adds Change plan. A warning shows when seats exceed the new limit. |
onSetSuspended | (workspace, suspended) => result | none | Suspend asks first; reactivate is direct. |
onOpen | (workspace) => void | none | |
loading, error, onRetry, pageSize, hideStats, labels |
AdminPlans and PlanDialog
| Prop | Type | Default | Description |
|---|---|---|---|
plans | AdminPlan[] | required | |
onSavePlan | (plan) => result | none | Enables New plan and Edit. plan.id is undefined for a new one. Return { error } to keep the dialog open. |
currency | string | "USD" ("SAR" in Arabic) | For new plans. |
Examples
- Read-only plans: omit
onSavePlan. - Unlimited: leave seat or storage limits empty in the dialog; the plan gets
null.
Accessibility
Dialogs trap focus and return it; errors use role="alert"; the notice is dismissable. Pass labels to translate.
RTL & i18n
Built-in English and Arabic. Slugs and emails are LTR isolates; prices and counts use the locale.
Styling & tokens
Uses PlanCard, Price, Meter and Status. Extend with className.
Do / Don't
- Do warn before a plan change that drops seats below use.
- Do not delete plans that have subscribers; hide them.
Related
Lab
https://docs.nasaqui.com/?path=/docs/components-admin-admin-tenants--docs
AdminArea
The admin frame. An icon rail plus sub-sidebar with ready-made admin navigation, an environment tag, an account button and an impersonation banner, plus AdminPage for the screen body.
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.