diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php new file mode 100644 index 0000000..c2520e2 --- /dev/null +++ b/app/Http/Controllers/Admin/UserController.php @@ -0,0 +1,60 @@ +authorize("viewAny", User::class); + + $query = User::query(); + + if ($request->filled("search")) { + $search = $request->input("search"); + $query->where(function ($q) use ($search): void { + $q->where("name", "like", "%" . $search . "%") + ->orWhere("email", "like", "%" . $search . "%"); + }); + } + + $users = $query->latest()->paginate(20)->withQueryString(); + + return view("admin.users.index", compact("users")); + } + + public function edit(User $user): View + { + $this->authorize("update", $user); + + return view("admin.users.edit", compact("user")); + } + + public function update(UpdateUserRequest $request, User $user): RedirectResponse + { + $user->update($request->validated()); + + return redirect()->route("admin.users.index"); + } + + public function destroy(User $user): RedirectResponse + { + $this->authorize("delete", $user); + + $user->delete(); + + return redirect()->route("admin.users.index"); + } +} diff --git a/app/Http/Requests/Admin/UpdateUserRequest.php b/app/Http/Requests/Admin/UpdateUserRequest.php new file mode 100644 index 0000000..849bc46 --- /dev/null +++ b/app/Http/Requests/Admin/UpdateUserRequest.php @@ -0,0 +1,31 @@ +user()->can("update", $this->route("user")); + } + + public function rules(): array + { + return [ + "is_admin" => ["boolean"], + "is_team_member" => ["boolean"], + ]; + } + + protected function prepareForValidation(): void + { + $this->merge([ + "is_admin" => $this->boolean("is_admin"), + "is_team_member" => $this->boolean("is_team_member"), + ]); + } +} diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php new file mode 100644 index 0000000..fb2995d --- /dev/null +++ b/app/Policies/UserPolicy.php @@ -0,0 +1,25 @@ +is_admin; + } + + public function update(User $user, User $model): bool + { + return $user->is_admin; + } + + public function delete(User $user, User $model): bool + { + return $user->is_admin && $user->id !== $model->id; + } +} diff --git a/database/seeders/DemoSeeder.php b/database/seeders/DemoSeeder.php index 73cfee4..92c8880 100644 --- a/database/seeders/DemoSeeder.php +++ b/database/seeders/DemoSeeder.php @@ -14,7 +14,11 @@ class DemoSeeder extends Seeder public function run(): void { Hop::factory(50)->create(); - User::factory(10)->create(); + User::factory(30)->create(); + + User::factory(["name" => "Admin", "email" => "admin@example.com", "password" => "password"])->admin()->create(); + User::factory(["name" => "Team Member", "email" => "member@example.com", "password" => "password"])->teamMember()->create(); + HopQuery::factory(10)->for(User::first())->create(); } } diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php new file mode 100644 index 0000000..0d9a82d --- /dev/null +++ b/resources/views/admin/users/edit.blade.php @@ -0,0 +1,41 @@ + + +

+ {{ __('Edit User: ') }} {{ $user->name }} +

+
+ +
+
+
+
+
+ @csrf + @method('PUT') + +
+ +
+ +
+ + + +
+ +
+ {{ __('Save') }} + {{ __('Cancel') }} +
+
+
+
+
+
+
diff --git a/resources/views/admin/users/index.blade.php b/resources/views/admin/users/index.blade.php new file mode 100644 index 0000000..e09c1f7 --- /dev/null +++ b/resources/views/admin/users/index.blade.php @@ -0,0 +1,77 @@ + + +
+

+ {{ __('Users') }} +

+ + +
+
+
+
+
+
+ + Search + +
+ +
+ + + + + + + + + + + + + @foreach ($users as $user) + + + + + + + + + @endforeach + +
NameEmailAdminTeam MemberCreated AtActions
{{ $user->name }}{{ $user->email }} + + {{ $user->is_admin ? 'Yes' : 'No' }} + + + + {{ $user->is_team_member ? 'Yes' : 'No' }} + + {{ $user->created_at->format('Y-m-d H:i') }} +
+ + {{ __('Edit') }} + + @if (auth()->id() !== $user->id) +
+ @csrf + @method('DELETE') + + {{ __('Delete') }} + +
+ @endif +
+
+
+ +
+ {{ $users->links() }} +
+
+
+
+
+ diff --git a/routes/web.php b/routes/web.php index b90ab68..691bd47 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use HopsWeb\Http\Controllers\Admin\UserController; use HopsWeb\Http\Controllers\ProfileController; use Illuminate\Support\Facades\Route; @@ -9,8 +10,15 @@ Route::get("/dashboard", fn() => view("dashboard"))->middleware(["auth", "verified"])->name("dashboard"); -Route::middleware("auth")->group(function (): void { +Route::middleware(["auth"])->group(function (): void { Route::get("/profile", [ProfileController::class, "edit"])->name("profile.edit"); Route::patch("/profile", [ProfileController::class, "update"])->name("profile.update"); Route::delete("/profile", [ProfileController::class, "destroy"])->name("profile.destroy"); + + Route::prefix("admin")->name("admin.")->group(function (): void { + Route::get("/users", [UserController::class, "index"])->name("users.index"); + Route::get("/users/{user}/edit", [UserController::class, "edit"])->name("users.edit"); + Route::put("/users/{user}", [UserController::class, "update"])->name("users.update"); + Route::delete("/users/{user}", [UserController::class, "destroy"])->name("users.destroy"); + }); });