feature: add role permission table for HR Manager
- Add TableHeader DTO - Refactor Toggle component to have checked prop, as wire:model does not work - add null collasing for php 8.5 strict compatibility in scope directive - refactor card component so that actions stay on the right - make button component scaled small on active and change color on hover
This commit is contained in:
parent
ede0064b54
commit
ca628fb009
18
app/Data/Ui/ManageRoles/PermissionData.php
Normal file
18
app/Data/Ui/ManageRoles/PermissionData.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Data\Ui\ManageRoles;
|
||||
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
final class PermissionData extends Data
|
||||
{
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public bool $view,
|
||||
public bool $create,
|
||||
public bool $update,
|
||||
public bool $delete,
|
||||
) {}
|
||||
}
|
||||
16
app/Data/Ui/TableHeader.php
Normal file
16
app/Data/Ui/TableHeader.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Data\Ui;
|
||||
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
final class TableHeader extends Data
|
||||
{
|
||||
public function __construct(
|
||||
public string $key,
|
||||
public string $label,
|
||||
public ?array $format = null,
|
||||
) {}
|
||||
}
|
||||
@ -17,6 +17,7 @@ public function boot(): void
|
||||
{
|
||||
$this->registerScopeDirective();
|
||||
}
|
||||
|
||||
public function registerScopeDirective(): void
|
||||
{
|
||||
/**
|
||||
@ -30,7 +31,10 @@ public function registerScopeDirective(): void
|
||||
$directiveArguments = preg_split("/,(?![^\(\(]*[\)\)])/", $expression);
|
||||
$directiveArguments = array_map("trim", $directiveArguments);
|
||||
|
||||
[$name, $functionArguments] = $directiveArguments;
|
||||
// PHP 8.5 Safe Unpacking (Prevents "Undefined array key" crashes)
|
||||
$name = $directiveArguments[0] ?? "''";
|
||||
$functionArguments = $directiveArguments[1] ?? '';
|
||||
|
||||
// Build function "uses" to inject extra external variables
|
||||
$uses = Arr::except(array_flip($directiveArguments), [$name, $functionArguments]);
|
||||
$uses = array_flip($uses);
|
||||
@ -46,6 +50,7 @@ public function registerScopeDirective(): void
|
||||
*/
|
||||
$name = str_replace(".", "___", $name);
|
||||
|
||||
// PHP 8.5 Safe Loop Check
|
||||
return "<?php \$__bladeCompiler = \$__bladeCompiler ?? null; \$__env->slot({$name}, function({$functionArguments}) use ({$uses}) { \$loop = !empty(\$__env->getLoopStack()) ? (object) \$__env->getLoopStack()[0] : null; ?>";
|
||||
});
|
||||
|
||||
|
||||
@ -57,10 +57,10 @@
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
|
||||
],
|
||||
"lint": [
|
||||
"pint --parallel"
|
||||
"pint --parallel --dirty"
|
||||
],
|
||||
"lint:check": [
|
||||
"pint --parallel --test"
|
||||
"pint --parallel --dirty --test"
|
||||
],
|
||||
"ci:check": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
use App\Data\Ui\ManageRoles\PermissionData;
|
||||
use App\Data\Ui\TableHeader;
|
||||
use Livewire\Component;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
new class extends Component {
|
||||
#[DataCollectionOf(TableHeader::class)]
|
||||
public DataCollection $header;
|
||||
|
||||
#[DataCollectionOf(PermissionData::class)]
|
||||
public DataCollection $rolePermissions;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->header = TableHeader::collect([
|
||||
new TableHeader('name', 'Permission'),
|
||||
new TableHeader('view', 'View'),
|
||||
new TableHeader('create', 'Create'),
|
||||
new TableHeader('update', 'Edit'),
|
||||
new TableHeader('delete', 'Delete'),
|
||||
], DataCollection::class);
|
||||
|
||||
$this->rolePermissions = PermissionData::collect([
|
||||
new PermissionData('Outlook - emails', true, true, false, false),
|
||||
new PermissionData('Teams - Messages', true, false, true, true),
|
||||
], DataCollection::class);
|
||||
}
|
||||
};
|
||||
?>
|
||||
|
||||
<div>
|
||||
<x-shared.card title="Role Permission - HR Manager" icon="lucide-lock" class="p-0">
|
||||
<x-slot:actions>
|
||||
<x-shared.button icon="lucide-x">
|
||||
{{ __('Revoke All') }}
|
||||
</x-shared.button>
|
||||
<x-shared.button icon="lucide-check">
|
||||
{{ __('Save') }}
|
||||
</x-shared.button>
|
||||
</x-slot:actions>
|
||||
|
||||
<x-table :headers="$header->toArray()" :rows="$rolePermissions">
|
||||
@scope('cell_view', $row)
|
||||
<x-shared.toggle :checked="$row->view" />
|
||||
@endscope
|
||||
@scope('cell_create', $row)
|
||||
<x-shared.toggle :checked="$row->create" />
|
||||
@endscope
|
||||
@scope('cell_update', $row)
|
||||
<x-shared.toggle :checked="$row->update" />
|
||||
@endscope
|
||||
@scope('cell_delete', $row)
|
||||
<x-shared.toggle :checked="$row->update" />
|
||||
@endscope
|
||||
</x-table>
|
||||
</x-shared.card>
|
||||
</div>
|
||||
@ -1,34 +1,24 @@
|
||||
<?php
|
||||
|
||||
use App\Data\Ui\ManageRoles\RoleData;
|
||||
use App\Data\Ui\ManageRoles\RolesCollection;
|
||||
use App\Data\Ui\ManageRoles\RolesData;
|
||||
use App\Data\Ui\ManageRoles\ServiceCollection;
|
||||
use App\Data\Ui\ManageRoles\ServiceData;
|
||||
use App\Data\Users\UserCollection;
|
||||
use App\Data\Ui\TableHeader;
|
||||
use App\Data\Users\UserData;
|
||||
use App\Data\Users\UsersData;
|
||||
use App\Enums\RolesStatus;
|
||||
use Livewire\Component;
|
||||
use Spatie\LaravelData\Attributes\DataCollectionOf;
|
||||
use Spatie\LaravelData\DataCollection;
|
||||
|
||||
new class extends Component {
|
||||
/**
|
||||
* @var array<int, array{
|
||||
* key: string,
|
||||
* label: string,
|
||||
* format: array{0: string, 1: string}|null
|
||||
* }>
|
||||
*/
|
||||
public array $header;
|
||||
#[DataCollectionOf(TableHeader::class)]
|
||||
public DataCollection $header;
|
||||
|
||||
#[DataCollectionOf(class: RoleData::class)]
|
||||
public DataCollection $roles;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->header = [
|
||||
$this->header = TableHeader::collect([
|
||||
[
|
||||
"key" => "name",
|
||||
"label" => "Role Name",
|
||||
@ -45,7 +35,7 @@ public function mount(): void
|
||||
"key" => "status",
|
||||
"label" => "Status",
|
||||
],
|
||||
];
|
||||
], DataCollection::class);
|
||||
$this->roles = RoleData::collect(
|
||||
[
|
||||
new RoleData(
|
||||
@ -91,7 +81,7 @@ public function mount(): void
|
||||
</x-shared.button>
|
||||
</x-slot:actions>
|
||||
|
||||
<x-table :headers="$header" :rows="$roles">
|
||||
<x-table :headers="$header->toArray()" :rows="$roles">
|
||||
@scope('cell_users', $role)
|
||||
@php /** @var RoleData $role */ @endphp
|
||||
<div class="flex -space-x-3">
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@props(['icon' => null])
|
||||
<button {{$attributes->twMerge(['class' => 'rounded-lg border border-gray-300 px-4 py-2 text-gray-700'])}}>
|
||||
<button {{$attributes->twMerge(['class' => 'rounded-lg border border-gray-300 px-4 py-2 text-gray-700 active:scale-75 hover:bg-gray-100 transition duration-150 ease-in-out'])}}>
|
||||
<div class="gap-2 flex items-center">
|
||||
@if($icon)
|
||||
<span class="block">
|
||||
|
||||
@ -4,16 +4,16 @@
|
||||
<div class="p-4 flex justify-between border-b border-gray-200">
|
||||
<h2 class="font-medium flex items-center gap-x-2">
|
||||
@isset($icon)
|
||||
<span class="w-5 h-5">
|
||||
@svg($icon)
|
||||
</span>
|
||||
<span class="w-5 h-5">@svg($icon)</span>
|
||||
@endisset
|
||||
{{ __($title) }}
|
||||
</h2>
|
||||
<div class="">
|
||||
@isset($actions)
|
||||
{{$actions}}
|
||||
@endisset
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
{{$slot}}
|
||||
</div>
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
@props(['disabled' => false, 'label' => null])
|
||||
@props(['disabled' => false, 'label' => null, 'checked' => false])
|
||||
|
||||
<label class="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
@checked($checked)
|
||||
{{ $disabled ? 'disabled' : '' }}
|
||||
{!! $attributes->merge(['class' => 'sr-only peer']) !!}
|
||||
{{ $attributes->merge(['class' => 'sr-only peer']) }}
|
||||
>
|
||||
|
||||
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
|
||||
@ -17,5 +17,6 @@ class extends Component {
|
||||
<x-dashboard-stats />
|
||||
<livewire:dashboard.connected-services />
|
||||
<livewire:dashboard.roles.manager />
|
||||
<livewire:dashboard.roles.hr-permission />
|
||||
</div>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user