Feat: add role seeding, dashboard routing
- Added `DefaultUserRole` and permissions enums (`AccessManager`, `Apps`, `Settings`) for centralizing role and permission constants. - Implemented `DashboardRoute` helper to resolve routes dynamically based on user roles. - Introduced seeders for default roles (`DefaultRoleWithPermissionSeeder`, `PermissionSeeder`, `ExampleUserWithRoleSeeder`) with role-permission assignments. - Created `EnumExtractor` utility for parsing enums and generating permissions. - Customized dashboard routes with role-based redirection logic. - Updated sidebar navigation to display role-based menu items with permission checks.
This commit is contained in:
parent
fd57ac57e1
commit
f02caef80c
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
namespace App\Data\Ui\Sidebar;
|
namespace App\Data\Ui\Sidebar;
|
||||||
|
|
||||||
|
use BackedEnum;
|
||||||
use Spatie\LaravelData\Data;
|
use Spatie\LaravelData\Data;
|
||||||
|
|
||||||
final class NavSubItemData extends Data
|
final class NavSubItemData extends Data
|
||||||
@ -12,5 +13,6 @@ public function __construct(
|
|||||||
public string $label,
|
public string $label,
|
||||||
public string $route,
|
public string $route,
|
||||||
public string $active_pattern,
|
public string $active_pattern,
|
||||||
|
public ?BackedEnum $permission = null
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
14
app/Enums/DefaultUserRole.php
Normal file
14
app/Enums/DefaultUserRole.php
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
use App\Concerns\EnumValuesAsArray;
|
||||||
|
|
||||||
|
enum DefaultUserRole: string
|
||||||
|
{
|
||||||
|
use EnumValuesAsArray;
|
||||||
|
case Admin = 'admin';
|
||||||
|
case User = 'user';
|
||||||
|
}
|
||||||
11
app/Enums/Permissions/AccessManager.php
Normal file
11
app/Enums/Permissions/AccessManager.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Enums\Permissions;
|
||||||
|
|
||||||
|
enum AccessManager: string
|
||||||
|
{
|
||||||
|
case RoleAndApps = 'role-and-apps';
|
||||||
|
case Users = 'users';
|
||||||
|
}
|
||||||
11
app/Enums/Permissions/Apps.php
Normal file
11
app/Enums/Permissions/Apps.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Enums\Permissions;
|
||||||
|
|
||||||
|
enum Apps: string
|
||||||
|
{
|
||||||
|
case AllApps = 'all-apps';
|
||||||
|
case Providers = 'providers';
|
||||||
|
}
|
||||||
11
app/Enums/Permissions/Settings.php
Normal file
11
app/Enums/Permissions/Settings.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Enums\Permissions;
|
||||||
|
|
||||||
|
enum Settings: string
|
||||||
|
{
|
||||||
|
case Profile = 'profile';
|
||||||
|
case Security = 'security';
|
||||||
|
}
|
||||||
26
app/Helpers/DashboardRoute.php
Normal file
26
app/Helpers/DashboardRoute.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
use App\Enums\DefaultUserRole;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
|
class DashboardRoute
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This function will resolve the dashboard route based on the user role.
|
||||||
|
*/
|
||||||
|
public static function resolve(Collection $roles): string
|
||||||
|
{
|
||||||
|
if ($roles->contains(DefaultUserRole::Admin->value)) {
|
||||||
|
return 'dashboard.admin';
|
||||||
|
}
|
||||||
|
if ($roles->contains(DefaultUserRole::User->value)) {
|
||||||
|
return 'dashboard.user';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'home';
|
||||||
|
}
|
||||||
|
}
|
||||||
90
app/Helpers/EnumExtractor.php
Normal file
90
app/Helpers/EnumExtractor.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
use FilesystemIterator;
|
||||||
|
use Generator;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
use SplFileInfo;
|
||||||
|
|
||||||
|
class EnumExtractor
|
||||||
|
{
|
||||||
|
private string $namespace;
|
||||||
|
|
||||||
|
private string $directory;
|
||||||
|
|
||||||
|
public function __construct(string $namespace, string $directory)
|
||||||
|
{
|
||||||
|
$this->namespace = mb_trim($namespace, '\\').'\\';
|
||||||
|
$this->directory = mb_rtrim($directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the extraction process and returns an array of actual Enum objects.
|
||||||
|
*/
|
||||||
|
public function extract(): array
|
||||||
|
{
|
||||||
|
$enumObjects = [];
|
||||||
|
|
||||||
|
foreach ($this->getPhpFiles() as $file) {
|
||||||
|
$className = $this->resolveClassName($file->getPathname());
|
||||||
|
|
||||||
|
$this->loadClassIfNeeded($className, $file->getPathname());
|
||||||
|
|
||||||
|
if (enum_exists($className)) {
|
||||||
|
// $className::cases() returns an array of the actual Enum objects
|
||||||
|
// e.g., [App\Enums\Status::Active, App\Enums\Status::Inactive]
|
||||||
|
$enumObjects[$className] = $className::cases();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $enumObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Yields only PHP files from the target directory.
|
||||||
|
*/
|
||||||
|
private function getPhpFiles(): Generator
|
||||||
|
{
|
||||||
|
$iterator = new RecursiveIteratorIterator(
|
||||||
|
new RecursiveDirectoryIterator($this->directory, FilesystemIterator::SKIP_DOTS)
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var SplFileInfo $file */
|
||||||
|
foreach ($iterator as $file) {
|
||||||
|
if ('php' === $file->getExtension()) {
|
||||||
|
yield $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a physical file path to a fully qualified PSR-4 class name.
|
||||||
|
*/
|
||||||
|
private function resolveClassName(string $filePath): string
|
||||||
|
{
|
||||||
|
// Strip the base directory from the path
|
||||||
|
$relativePath = str_replace($this->directory, '', $filePath);
|
||||||
|
|
||||||
|
// Normalize slashes and remove the .php extension
|
||||||
|
$normalizedPath = str_replace([DIRECTORY_SEPARATOR, '/', '.php'], ['\\', '\\', ''], $relativePath);
|
||||||
|
|
||||||
|
return $this->namespace.mb_ltrim($normalizedPath, '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires the file into memory if it hasn't been autoloaded yet.
|
||||||
|
*/
|
||||||
|
private function loadClassIfNeeded(string $className, string $filePath): void
|
||||||
|
{
|
||||||
|
if (! class_exists($className, false)
|
||||||
|
&& ! enum_exists($className, false)
|
||||||
|
&& ! interface_exists($className, false)
|
||||||
|
) {
|
||||||
|
require_once $filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Http/Controllers/ResolveDashboardRouteController.php
Normal file
19
app/Http/Controllers/ResolveDashboardRouteController.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Helpers\DashboardRoute;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ResolveDashboardRouteController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(Request $request)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
$route = DashboardRoute::resolve($user->getRoleNames());
|
||||||
|
|
||||||
|
return to_route($route);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Responses/LoginResponse.php
Normal file
28
app/Http/Responses/LoginResponse.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Responses;
|
||||||
|
|
||||||
|
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used overide the fortify LoginResponse class, so that
|
||||||
|
* we can redirect the user to the intended page after login.
|
||||||
|
*/
|
||||||
|
class LoginResponse implements LoginResponseContract
|
||||||
|
{
|
||||||
|
public function toResponse($request)
|
||||||
|
{
|
||||||
|
$user = $request->user();
|
||||||
|
|
||||||
|
activity()
|
||||||
|
->causedBy($user)
|
||||||
|
->withProperties([
|
||||||
|
'roles' => $user->getRoleNames(),
|
||||||
|
])
|
||||||
|
->log('User logged in}');
|
||||||
|
|
||||||
|
return to_route('dashboard');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,10 +5,12 @@
|
|||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use App\Actions\Fortify\{CreateNewUser, ResetUserPassword};
|
use App\Actions\Fortify\{CreateNewUser, ResetUserPassword};
|
||||||
|
use App\Http\Responses\LoginResponse;
|
||||||
use Illuminate\Cache\RateLimiting\Limit;
|
use Illuminate\Cache\RateLimiting\Limit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\RateLimiter;
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
use Illuminate\Support\{ServiceProvider, Str};
|
use Illuminate\Support\{ServiceProvider, Str};
|
||||||
|
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
|
||||||
use Laravel\Fortify\Fortify;
|
use Laravel\Fortify\Fortify;
|
||||||
|
|
||||||
final class FortifyServiceProvider extends ServiceProvider
|
final class FortifyServiceProvider extends ServiceProvider
|
||||||
@ -16,7 +18,13 @@ final class FortifyServiceProvider extends ServiceProvider
|
|||||||
/**
|
/**
|
||||||
* Register any application services.
|
* Register any application services.
|
||||||
*/
|
*/
|
||||||
public function register(): void {}
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->app->singleton(
|
||||||
|
LoginResponseContract::class,
|
||||||
|
LoginResponse::class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap any application services.
|
* Bootstrap any application services.
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
@ -16,15 +15,10 @@ final class DatabaseSeeder extends Seeder
|
|||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
// User::factory(10)->create();
|
|
||||||
|
|
||||||
User::factory()->create([
|
|
||||||
'name' => 'Test User',
|
|
||||||
'email' => 'test@example.com',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->call(ConnectionStatusSeeder::class);
|
$this->call(ConnectionStatusSeeder::class);
|
||||||
$this->call(ConnectionProtocolSeeder::class);
|
$this->call(ConnectionProtocolSeeder::class);
|
||||||
$this->call(ConnectionProviderSeeder::class);
|
$this->call(ConnectionProviderSeeder::class);
|
||||||
|
$this->call(PermissionSeeder::class);
|
||||||
|
$this->call(ExampleUserWithRoleSeeder::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
database/seeders/DefaultRoleWithPermissionSeeder.php
Normal file
27
database/seeders/DefaultRoleWithPermissionSeeder.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Enums\DefaultUserRole;
|
||||||
|
use App\Enums\Permissions\Settings;
|
||||||
|
use App\Models\Role;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Spatie\Permission\Models\Permission;
|
||||||
|
|
||||||
|
class DefaultRoleWithPermissionSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$role = Role::findOrCreate(DefaultUserRole::Admin->value);
|
||||||
|
$role->givePermissionTo(Permission::all());
|
||||||
|
$role = Role::findOrCreate(DefaultUserRole::User->value);
|
||||||
|
$this->syncUserPermissions($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function syncUserPermissions(Role $role): void
|
||||||
|
{
|
||||||
|
$role->givePermissionTo(Settings::Profile->value, Settings::Security->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
database/seeders/ExampleUserWithRoleSeeder.php
Normal file
49
database/seeders/ExampleUserWithRoleSeeder.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Enums\DefaultUserRole;
|
||||||
|
use App\Models\{Role, User};
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class ExampleUserWithRoleSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a user for each role;
|
||||||
|
*/
|
||||||
|
$this->syncAdminRole();
|
||||||
|
$this->syncUserRole();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function syncAdminRole(): void
|
||||||
|
{
|
||||||
|
$role = Role::findOrCreate(DefaultUserRole::Admin->value);
|
||||||
|
// Check if user exists by email, otherwise create via factory
|
||||||
|
$user = User::firstWhere('email', 'admin@example.com')
|
||||||
|
?? User::factory()->create([
|
||||||
|
'name' => 'Admin',
|
||||||
|
'email' => 'admin@example.com',
|
||||||
|
'password' => 'password',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->assignRole($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function syncUserRole(): void
|
||||||
|
{
|
||||||
|
$role = Role::findOrCreate(DefaultUserRole::User->value);
|
||||||
|
|
||||||
|
$user = User::firstWhere('email', 'test@example.com')
|
||||||
|
?? User::factory()->create([
|
||||||
|
'name' => 'Test User',
|
||||||
|
'email' => 'test@example.com',
|
||||||
|
'password' => 'password',
|
||||||
|
]);
|
||||||
|
$user->assignRole($role);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
23
database/seeders/PermissionSeeder.php
Normal file
23
database/seeders/PermissionSeeder.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Helpers\EnumExtractor;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Spatie\Permission\Models\Permission;
|
||||||
|
|
||||||
|
class PermissionSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$enumExtractor = new EnumExtractor('App\\Enums\\Permissions', __DIR__.'/../../app/Enums/Permissions');
|
||||||
|
$allEnums = $enumExtractor->extract();
|
||||||
|
foreach ($allEnums as $enumCases) {
|
||||||
|
foreach ($enumCases as $case) {
|
||||||
|
Permission::create(['name' => $case->value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
use App\Data\Ui\Sidebar\NavItemData;
|
use App\Data\Ui\Sidebar\NavItemData;
|
||||||
use App\Data\Ui\Sidebar\NavSubItemData;
|
use App\Data\Ui\Sidebar\NavSubItemData;
|
||||||
|
use App\Enums\Permissions\AccessManager;
|
||||||
|
use App\Enums\Permissions\Apps;
|
||||||
|
use App\Enums\Permissions\Settings;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Spatie\LaravelData\DataCollection;
|
use Spatie\LaravelData\DataCollection;
|
||||||
|
|
||||||
@ -25,7 +28,7 @@ public function toggle(): void
|
|||||||
*/
|
*/
|
||||||
public function navItems(): DataCollection
|
public function navItems(): DataCollection
|
||||||
{
|
{
|
||||||
return NavItemData::collect([
|
$items = NavItemData::collect([
|
||||||
new NavItemData(
|
new NavItemData(
|
||||||
label: 'Dashboard',
|
label: 'Dashboard',
|
||||||
icon: 'lucide.house',
|
icon: 'lucide.house',
|
||||||
@ -41,12 +44,14 @@ public function navItems(): DataCollection
|
|||||||
new NavSubItemData(
|
new NavSubItemData(
|
||||||
label: 'All Apps',
|
label: 'All Apps',
|
||||||
route: 'apps.index',
|
route: 'apps.index',
|
||||||
active_pattern: 'apps.index'
|
active_pattern: 'apps.index',
|
||||||
|
permission: Apps::AllApps
|
||||||
),
|
),
|
||||||
new NavSubItemData(
|
new NavSubItemData(
|
||||||
label: 'Providers',
|
label: 'Providers',
|
||||||
route: 'apps.connectionProviders.index',
|
route: 'apps.connectionProviders.index',
|
||||||
active_pattern: 'apps.connectionProviders.*'
|
active_pattern: 'apps.connectionProviders.*',
|
||||||
|
permission: Apps::Providers
|
||||||
)
|
)
|
||||||
], DataCollection::class)
|
], DataCollection::class)
|
||||||
),
|
),
|
||||||
@ -60,11 +65,13 @@ public function navItems(): DataCollection
|
|||||||
label: 'Roles and Apps',
|
label: 'Roles and Apps',
|
||||||
route: 'access-manager.roles-and-apps.index',
|
route: 'access-manager.roles-and-apps.index',
|
||||||
active_pattern: 'access-manager.roles-and-apps.*',
|
active_pattern: 'access-manager.roles-and-apps.*',
|
||||||
|
permission: AccessManager::RoleAndApps
|
||||||
),
|
),
|
||||||
new NavSubItemData(
|
new NavSubItemData(
|
||||||
label: 'Users',
|
label: 'Users',
|
||||||
route: 'access-manager.users.index',
|
route: 'access-manager.users.index',
|
||||||
active_pattern: 'access-manager.users.*',
|
active_pattern: 'access-manager.users.*',
|
||||||
|
permission: AccessManager::Users
|
||||||
),
|
),
|
||||||
], DataCollection::class)
|
], DataCollection::class)
|
||||||
),
|
),
|
||||||
@ -78,15 +85,52 @@ public function navItems(): DataCollection
|
|||||||
label: 'Profile',
|
label: 'Profile',
|
||||||
route: 'profile.edit',
|
route: 'profile.edit',
|
||||||
active_pattern: 'profile.edit',
|
active_pattern: 'profile.edit',
|
||||||
|
permission: Settings::Profile
|
||||||
),
|
),
|
||||||
new NavSubItemData(
|
new NavSubItemData(
|
||||||
label: 'Security',
|
label: 'Security',
|
||||||
route: 'security.edit',
|
route: 'security.edit',
|
||||||
active_pattern: 'security.edit',
|
active_pattern: 'security.edit',
|
||||||
|
permission: Settings::Security
|
||||||
),
|
),
|
||||||
], DataCollection::class)
|
], DataCollection::class)
|
||||||
),
|
),
|
||||||
], DataCollection::class);
|
], DataCollection::class);
|
||||||
|
|
||||||
|
// Filter out items the user shouldn't see
|
||||||
|
return $this->filterNavMenu($items);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter out menus that the current user does not have permission.
|
||||||
|
* @param DataCollection<NavItemData> $items
|
||||||
|
* @returns DataCollection<NavItemData>
|
||||||
|
*/
|
||||||
|
private function filterNavMenu(DataCollection $items): DataCollection
|
||||||
|
{
|
||||||
|
$filteredItems = $items->toCollection()->filter(function (NavItemData $item) {
|
||||||
|
if ($item->sub_menu) {
|
||||||
|
$allowedSubItems = $item->sub_menu->toCollection()->filter(function (NavSubItemData $subItem) {
|
||||||
|
$permission = $subItem->permission instanceof UnitEnum
|
||||||
|
? $subItem->permission->value
|
||||||
|
: $subItem->permission;
|
||||||
|
|
||||||
|
return auth()->user()->can($permission);
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the user has NO access to any submenus, discard the parent menu item
|
||||||
|
if ($allowedSubItems->isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the DataCollection with authorized items
|
||||||
|
$item->sub_menu = NavSubItemData::collect($allowedSubItems, DataCollection::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return NavItemData::collect($filteredItems->values()->all(), DataCollection::class);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
?>
|
?>
|
||||||
@ -193,6 +237,7 @@ class="absolute right-full top-1/2 -translate-y-1/2 border-[5px] border-transpar
|
|||||||
<div class="mt-1 space-y-1 pl-9 pr-2">
|
<div class="mt-1 space-y-1 pl-9 pr-2">
|
||||||
@foreach ($item->sub_menu as $subItem)
|
@foreach ($item->sub_menu as $subItem)
|
||||||
@php $isSubActive = request()->routeIs($subItem->active_pattern); @endphp
|
@php $isSubActive = request()->routeIs($subItem->active_pattern); @endphp
|
||||||
|
@can($subItem->permission)
|
||||||
<a
|
<a
|
||||||
href="{{ route($subItem->route) }}"
|
href="{{ route($subItem->route) }}"
|
||||||
wire:navigate
|
wire:navigate
|
||||||
@ -204,6 +249,7 @@ class="absolute right-full top-1/2 -translate-y-1/2 border-[5px] border-transpar
|
|||||||
>
|
>
|
||||||
{{ $subItem->label }}
|
{{ $subItem->label }}
|
||||||
</a>
|
</a>
|
||||||
|
@endcan
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
13
resources/views/pages/dashboards/⚡user.blade.php
Normal file
13
resources/views/pages/dashboards/⚡user.blade.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
new class extends Component
|
||||||
|
{
|
||||||
|
//
|
||||||
|
};
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{-- People find pleasure in different ways. I find it in keeping my mind clear. - Marcus Aurelius --}}
|
||||||
|
</div>
|
||||||
@ -2,12 +2,17 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use App\Http\Controllers\ResolveDashboardRouteController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::view('/', 'welcome')->name('home');
|
Route::view('/', 'welcome')->name('home');
|
||||||
|
|
||||||
Route::group(['middleware' => ['auth', 'verified']], function (): void {
|
Route::group(['middleware' => ['auth', 'verified']], function (): void {
|
||||||
Route::livewire('dashboard', 'pages::dashboard')->name('dashboard');
|
Route::get('dashboard', ResolveDashboardRouteController::class)->name('dashboard');
|
||||||
|
Route::prefix('dashboard')->name('dashboard.')->group(function (): void {
|
||||||
|
Route::livewire('/user', 'pages::dashboards.user')->name('user');
|
||||||
|
Route::livewire('admin', 'pages::dashboards.admin')->name('admin');
|
||||||
|
});
|
||||||
|
|
||||||
Route::prefix('access-manager')->name('access-manager.')->group(function (): void {
|
Route::prefix('access-manager')->name('access-manager.')->group(function (): void {
|
||||||
Route::prefix('roles-and-apps')->name('roles-and-apps.')->group(function (): void {
|
Route::prefix('roles-and-apps')->name('roles-and-apps.')->group(function (): void {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user