emloyee and user fixings

This commit is contained in:
2026-09-11 10:32:47 +05:30
parent 629f3d1f44
commit cb41d503c4
61 changed files with 35831 additions and 1228 deletions
@@ -5,8 +5,11 @@
// "select all children" convenience toggle — the parent's own visibility is
// derived from its children on the frontend (see AppSidebar.tsx's filter), so
// only the children need to carry the actual grant for those groups.
import { Check } from "lucide-react"
import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"
import { cn } from "@/lib/utils"
import { NavItem } from "@/types/rbac"
interface Props {
@@ -41,42 +44,60 @@ export function RolePermissionTree({ tree, selectedNavItemIds, selectedSubNavIte
}
return (
<div className="flex flex-col gap-1 rounded-lg border p-4">
{tree.map((item) => {
if (item.children.length === 0) {
return (
<label key={item.navItemId} className="flex items-center gap-3 rounded-md px-2 py-2 hover:bg-muted/50">
<Checkbox
checked={selectedNavItemIds.has(item.navItemId)}
onCheckedChange={() => toggleLeaf(item.navItemId)}
/>
<Label className="cursor-pointer text-base font-medium">{item.label}</Label>
</label>
)
}
<div className="overflow-hidden rounded-lg border">
{tree.map((item, i) => {
const hasChildren = item.children.length > 0
const checkedCount = item.children.filter((c) => selectedSubNavItemIds.has(c.subNavItemId)).length
const allChecked = checkedCount === item.children.length
const allChecked = hasChildren && checkedCount === item.children.length
const someChecked = hasChildren && checkedCount > 0 && !allChecked
return (
<div key={item.navItemId} className="flex flex-col gap-1 border-t pt-2 first:border-t-0 first:pt-0">
<label className="flex items-center gap-3 rounded-md px-2 py-2 hover:bg-muted/50">
<Checkbox checked={allChecked} onCheckedChange={(checked) => toggleAllChildren(item, !!checked)} />
<Label className="cursor-pointer text-base font-semibold">
{item.label} {checkedCount > 0 && !allChecked && <span className="text-sm font-normal text-muted-foreground">({checkedCount} of {item.children.length})</span>}
<div
key={item.navItemId}
className="grid grid-cols-[minmax(11rem,14rem)_1fr] items-start gap-x-4 gap-y-2 border-b bg-white px-4 py-3 last:border-b-0"
>
<label className="flex items-center gap-2.5 pt-0.5">
<Checkbox
checked={hasChildren ? allChecked : selectedNavItemIds.has(item.navItemId)}
indeterminate={someChecked}
onCheckedChange={
hasChildren
? (checked) => toggleAllChildren(item, !!checked)
: () => toggleLeaf(item.navItemId)
}
className="size-5 border-2 border-muted-foreground/50 data-checked:border-blue-600! data-checked:bg-blue-600! data-checked:text-white! [&_svg]:size-4"
/>
<Label className={cn("cursor-pointer text-base", hasChildren ? "font-semibold" : "font-medium")}>
{item.label}
</Label>
</label>
<div className="flex flex-col gap-1 pl-9">
{item.children.map((child) => (
<label key={child.subNavItemId} className="flex items-center gap-3 rounded-md px-2 py-1.5 hover:bg-muted/50">
<Checkbox
checked={selectedSubNavItemIds.has(child.subNavItemId)}
onCheckedChange={() => toggleChild(child.subNavItemId)}
/>
<Label className="cursor-pointer text-sm">{child.label}</Label>
</label>
))}
</div>
{hasChildren ? (
<div className="flex flex-wrap items-center gap-1.5">
{item.children.map((child) => {
const checked = selectedSubNavItemIds.has(child.subNavItemId)
return (
<button
key={child.subNavItemId}
type="button"
aria-pressed={checked}
onClick={() => toggleChild(child.subNavItemId)}
className={cn(
"inline-flex items-center gap-1 rounded-full border px-3 py-1 text-sm font-medium transition-colors",
checked
? "border-transparent bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-500/20 dark:text-blue-300 dark:hover:bg-blue-500/30"
: "border-input bg-white text-muted-foreground hover:border-muted-foreground/40 hover:text-foreground"
)}
>
{checked && <Check className="size-3.5" />}
{child.label}
</button>
)
})}
</div>
) : (
<span className="pt-1 text-sm text-muted-foreground">No sub-items — grants the whole section.</span>
)}
</div>
)
})}