Files
construprogress/app/Livewire/RoleView.php
T
javier 5587026446 feat(roles): Rappasoft list, slim create form, and 2-tab role view
1. Roles list now uses a Rappasoft table (RoleTable): search/sort, per-row
   view/edit/delete, and built-in bulk selection + 'Delete selected'. The
   /admin/roles page is a plain view embedding <livewire:role-table />.
   RoleForm create/edit now only has Name + Description (permissions removed).
2. New RoleView page (/admin/roles/{role}) with two tabs:
   - 'Details': header with role name + Back button; description with Edit/Delete
     buttons; table of users holding the role (avatar+name | last name | status).
   - 'Permissions': all permissions grouped by section (by resource), each with a
     toggle switch to grant/revoke for this role (Admin keeps 'manage all').
Removed the old RoleManager component/view (superseded).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 17:21:16 +02:00

96 lines
3.0 KiB
PHP

<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\Attributes\Layout;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\PermissionRegistrar;
#[Layout('layouts.app')]
class RoleView extends Component
{
public Role $role;
public string $tab = 'ficha'; // ficha | permisos
private const PROTECTED_ROLES = ['Admin'];
private const CORE_PERMISSION = 'manage all';
public function mount(Role $role): void
{
abort_unless(Auth::user()?->can(self::CORE_PERMISSION), 403);
$this->role = $role;
}
public function setTab(string $tab): void
{
$this->tab = in_array($tab, ['ficha', 'permisos'], true) ? $tab : 'ficha';
}
public function togglePermission(string $permissionName): void
{
// Admin must always keep the core permission
if ($this->role->name === 'Admin'
&& $permissionName === self::CORE_PERMISSION
&& $this->role->hasPermissionTo($permissionName)) {
$this->dispatch('notify', "El rol Admin no puede perder '" . self::CORE_PERMISSION . "'.");
return;
}
if ($this->role->hasPermissionTo($permissionName)) {
$this->role->revokePermissionTo($permissionName);
} else {
$this->role->givePermissionTo($permissionName);
}
app(PermissionRegistrar::class)->forgetCachedPermissions();
$this->role->load('permissions');
$this->dispatch('notify', 'Permisos actualizados');
}
public function delete()
{
if (in_array($this->role->name, self::PROTECTED_ROLES, true)) {
$this->dispatch('notify', "El rol '{$this->role->name}' está protegido y no se puede borrar.");
return;
}
$this->role->delete();
app(PermissionRegistrar::class)->forgetCachedPermissions();
session()->flash('message', 'Rol eliminado.');
return $this->redirect(route('admin.roles'), navigate: true);
}
/** Section title for a permission name (groups by the resource / last word). */
private function sectionFor(string $name): string
{
if ($name === self::CORE_PERMISSION) {
return 'General';
}
$resource = Str::afterLast($name, ' ');
return Str::headline($resource ?: 'General');
}
public function render()
{
$users = $this->role->users()
->orderBy('first_name')
->orderBy('name')
->get();
$grouped = Permission::orderBy('name')->get()
->groupBy(fn ($perm) => $this->sectionFor($perm->name))
->sortKeys();
return view('livewire.roles.role-view', [
'users' => $users,
'grouped' => $grouped,
'rolePerms' => $this->role->permissions->pluck('name')->toArray(),
'isProtected' => in_array($this->role->name, self::PROTECTED_ROLES, true),
]);
}
}