نقشها و دسترسیها
پیشنمایش تمامصفحهماتریس نقش و دسترسی (سطر نقش، ستون دسترسی) با چکباکس، بازنشانی و ذخیره.
۱. نصب کامپوننتها
این بلاک از ۵ آیتم دیگ استفاده میکند: buttoncheckboxcontrol-sizetabletoast
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/table.json https://docs.digdesign.ir/r/toast.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/table.json https://docs.digdesign.ir/r/toast.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/table.json https://docs.digdesign.ir/r/toast.jsonbunx --bun digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/table.json https://docs.digdesign.ir/r/toast.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
roles-permissions.tsx
"use client"
import * as React from "react"
import { Button } from "@/components/ui/button"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { Checkbox } from "@/components/ui/checkbox"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { toast } from "@/components/ui/toast"
const ROLES = [
{ id: "admin", title: "مدیر" },
{ id: "editor", title: "ویرایشگر" },
{ id: "support", title: "پشتیبان" },
{ id: "viewer", title: "بیننده" },
]
const PERMISSIONS = [
{ id: "orders.view", title: "مشاهدهٔ سفارشها" },
{ id: "orders.edit", title: "ویرایش سفارشها" },
{ id: "refunds", title: "بازگرداندن وجه" },
{ id: "users.manage", title: "مدیریت کاربران" },
{ id: "reports.export", title: "خروجی گزارشها" },
]
const INITIAL: Record<string, string[]> = {
admin: PERMISSIONS.map((permission) => permission.id),
editor: ["orders.view", "orders.edit", "reports.export"],
support: ["orders.view", "refunds"],
viewer: ["orders.view"],
}
export default function RolesPermissionsBlock() {
const [grants, setGrants] = React.useState(INITIAL)
const [saving, setSaving] = React.useState(false)
const [dirty, setDirty] = React.useState(false)
function toggle(role: string, permission: string, on: boolean) {
setDirty(true)
setGrants((current) => ({
...current,
[role]: on ? [...current[role], permission] : current[role].filter((id) => id !== permission),
}))
}
async function save() {
setSaving(true)
await new Promise((resolve) => setTimeout(resolve, 700))
setSaving(false)
setDirty(false)
toast.success("دسترسیها ذخیره شد.")
}
return (
<ControlSizeProvider size="xl" asChild>
<main className="mx-auto flex w-full min-w-0 max-w-4xl flex-col gap-6 p-4 sm:p-6">
{/* سلسلهمراتب: عنوان و توضیح یک گروهِ نزدیک، اکشنها همردیفِ عنوان. */}
<header className="flex flex-wrap items-end justify-between gap-x-4 gap-y-8">
<div className="flex flex-col gap-1">
<h1 className="text-2xl font-bold">نقشها و دسترسیها</h1>
<p className="text-sm text-muted-foreground">
دسترسی هر نقش را تیک بزنید. نقش مدیر همهٔ دسترسیها را دارد و قابل تغییر نیست.
</p>
</div>
<div className="flex gap-2">
<Button
variant="outline"
disabled={!dirty}
onClick={() => {
setGrants(INITIAL)
setDirty(false)
}}
>
بازنشانی
</Button>
<Button onClick={save} loading={saving} disabled={!dirty}>
ذخیرهٔ تغییرات
</Button>
</div>
</header>
{/* هر سطر یک نقش، هر ستون یک دسترسی؛ چکباکسها وسطِ ستون. */}
<div className="mt-2">
<Table stackOnMobile>
<TableHeader>
<TableRow>
<TableHead className="min-w-32">نقش</TableHead>
{PERMISSIONS.map((permission) => (
<TableHead key={permission.id} className="text-center whitespace-nowrap">
{permission.title}
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{ROLES.map((role) => (
<TableRow key={role.id}>
<TableCell className="font-medium">{role.title}</TableCell>
{PERMISSIONS.map((permission) => (
<TableCell key={permission.id}>
<div className="flex justify-center">
<Checkbox
aria-label={`${permission.title} برای ${role.title}`}
checked={grants[role.id].includes(permission.id)}
disabled={role.id === "admin"}
onCheckedChange={(checked) => toggle(role.id, permission.id, checked === true)}
/>
</div>
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
</main>
</ControlSizeProvider>
)
}