From 7ce58c125015a170523633a5a26ec555d5ad42b6 Mon Sep 17 00:00:00 2001 From: Aji Kamaludin Date: Thu, 22 Jun 2023 11:28:31 +0700 Subject: [PATCH] user and role refact --- app/Http/Controllers/RoleController.php | 2 +- app/Http/Controllers/UserController.php | 32 ++++ app/Models/Role.php | 5 + app/Models/User.php | 15 ++ .../2014_10_12_000000_create_users_table.php | 8 + database/seeders/PermissionSeeder.php | 8 +- resources/js/Layouts/AuthenticatedLayout.jsx | 7 +- resources/js/Layouts/Partials/routes.js | 2 +- resources/js/Pages/Account/Form.jsx | 12 +- resources/js/Pages/Account/FormModal.jsx | 108 ------------ resources/js/Pages/Account/Index.jsx | 22 +-- resources/js/Pages/Info/Form.jsx | 6 +- resources/js/Pages/Role/Index.jsx | 30 ++++ resources/js/Pages/User/Form.jsx | 156 ++++++++++++++++++ resources/js/Pages/User/FormModal.jsx | 115 ------------- resources/js/Pages/User/Index.jsx | 79 ++++++--- routes/admin.php | 4 +- 17 files changed, 347 insertions(+), 264 deletions(-) delete mode 100644 resources/js/Pages/Account/FormModal.jsx create mode 100644 resources/js/Pages/User/Form.jsx delete mode 100644 resources/js/Pages/User/FormModal.jsx diff --git a/app/Http/Controllers/RoleController.php b/app/Http/Controllers/RoleController.php index 5f9c6ee..1e3b62d 100644 --- a/app/Http/Controllers/RoleController.php +++ b/app/Http/Controllers/RoleController.php @@ -16,7 +16,7 @@ class RoleController extends Controller { $request->user()->allow('view-role', true); - $query = Role::query(); + $query = Role::query()->with(['users']); if ($request->q) { $query->where('name', 'like', "%{$request->q}%"); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 6aea49a..be274ba 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -24,6 +24,11 @@ class UserController extends Controller ]); } + public function create() + { + return inertia('User/Form'); + } + public function store(Request $request): RedirectResponse { $request->validate([ @@ -31,25 +36,44 @@ class UserController extends Controller 'email' => 'required|email|unique:users,email', 'password' => 'required|string|max:255', 'role_id' => 'required|ulid|exists:roles,id', + 'username' => 'required|alpha_dash|unique:users,username', + 'phone_wa' => 'required|string', + 'photo' => 'required|image', ]); + $file = $request->file('photo'); + $file->store('uploads', 'public'); + User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => bcrypt($request->password), 'role_id' => $request->role_id, + 'username' => $request->username, + 'phone_wa' => $request->phone_wa, + 'photo' => $file->hashName('uploads'), ]); return redirect()->route('user.index') ->with('message', ['type' => 'success', 'message' => 'Item has beed saved']); } + public function edit(User $user) + { + return inertia('User/Form', [ + 'user' => $user->load(['role']) + ]); + } + public function update(Request $request, User $user): RedirectResponse { $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email,'.$user->id, 'password' => 'nullable|string|max:255', + 'username' => 'required|alpha_dash|unique:users,username,' . $user->id, + 'phone_wa' => 'required|string', + 'photo' => 'nullable|image', ]); if ($user->role != null) { @@ -58,10 +82,18 @@ class UserController extends Controller ]); } + if ($request->hasFile('photo')) { + $file = $request->file('photo'); + $file->store('uploads', 'public'); + $user->fill(['photo' => $file->hashName('uploads')]); + } + $user->fill([ 'email' => $request->email, 'name' => $request->name, 'role_id' => $request->role_id, + 'username' => $request->username, + 'phone_wa' => $request->phone_wa, ]); if ($request->password != '') { diff --git a/app/Models/Role.php b/app/Models/Role.php index d019b8c..7f1855d 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -26,4 +26,9 @@ class Role extends Model 'permission_id', ); } + + public function users() + { + return $this->hasMany(User::class); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 876ddd2..9de8690 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,6 +4,7 @@ namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; @@ -25,6 +26,9 @@ class User extends Authenticatable 'password', 'role_id', 'reset_token', + 'phone_wa', + 'photo', + 'username', ]; /** @@ -46,6 +50,10 @@ class User extends Authenticatable 'email_verified_at' => 'datetime', ]; + protected $appends = [ + 'photo_url' + ]; + public function role() { return $this->belongsTo(Role::class); @@ -71,4 +79,11 @@ class User extends Authenticatable return false; } + + public function photoUrl(): Attribute + { + return Attribute::make(get: function() { + return asset($this->photo); + }); + } } diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index e48fef6..85d4fe4 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -21,8 +21,16 @@ return new class extends Migration $table->string('password'); $table->string('reset_token')->nullable(); $table->ulid('role_id')->nullable(); + + $table->string('phone_wa')->nullable(); + $table->string('photo')->nullable(); + $table->string('username')->nullable(); + $table->rememberToken(); $table->timestamps(); + $table->ulid('created_by')->nullable(); + $table->ulid('updated_by')->nullable(); + $table->ulid('deleted_by')->nullable(); }); } diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index ab29033..91a9b2a 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -106,13 +106,19 @@ class PermissionSeeder extends Seeder 'name' => 'Super Administrator', 'email' => 'root@admin.com', 'password' => bcrypt('password'), + 'photo' => 'sample/logo-jago.png', + 'username' => 'root', + 'phone_wa' => '81325307692', ]); - $admin = User::create([ + User::create([ 'name' => 'Administator', 'email' => 'admin@admin.com', 'password' => bcrypt('password'), 'role_id' => $role->id, + 'photo' => 'sample/logo-jago.png', + 'username' => 'admin', + 'phone_wa' => '81325307692', ]); $setting = []; diff --git a/resources/js/Layouts/AuthenticatedLayout.jsx b/resources/js/Layouts/AuthenticatedLayout.jsx index 374c193..b1690d4 100644 --- a/resources/js/Layouts/AuthenticatedLayout.jsx +++ b/resources/js/Layouts/AuthenticatedLayout.jsx @@ -115,6 +115,11 @@ export default function Authenticated({ type="button" className="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150 dark:bg-gray-700 dark:hover:text-gray-50 dark:text-gray-200 gap-2" > + user profile image {auth.user.name} @@ -124,7 +129,7 @@ export default function Authenticated({ Visit Site diff --git a/resources/js/Layouts/Partials/routes.js b/resources/js/Layouts/Partials/routes.js index a9a4b77..938588e 100644 --- a/resources/js/Layouts/Partials/routes.js +++ b/resources/js/Layouts/Partials/routes.js @@ -154,7 +154,7 @@ export default [ show: true, icon: HiUsers, route: route('user.index'), - active: 'user.index', + active: 'user.*', permission: 'view-user', }, ], diff --git a/resources/js/Pages/Account/Form.jsx b/resources/js/Pages/Account/Form.jsx index e202248..1a36a16 100644 --- a/resources/js/Pages/Account/Form.jsx +++ b/resources/js/Pages/Account/Form.jsx @@ -15,8 +15,8 @@ export default function Form(props) { bank_name: '', holder_name: '', account_number: '', - logo: null, - logo_url: '' + logo: null, + logo_url: '', }) const handleOnChange = (event) => { @@ -44,13 +44,17 @@ export default function Form(props) { bank_name: account.bank_name, holder_name: account.holder_name, account_number: account.account_number, - logo_url: account.logo_url + logo_url: account.logo_url, }) } }, [account]) return ( - +
diff --git a/resources/js/Pages/Account/FormModal.jsx b/resources/js/Pages/Account/FormModal.jsx deleted file mode 100644 index 47a05c5..0000000 --- a/resources/js/Pages/Account/FormModal.jsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useEffect } from 'react' -import Modal from '@/Components/Modal' -import { useForm } from '@inertiajs/react' -import Button from '@/Components/Button' -import FormInput from '@/Components/FormInput' -import RoleSelectionInput from '../Role/SelectionInput' - -import { isEmpty } from 'lodash' - -export default function FormModal(props) { - const { modalState } = props - const { data, setData, post, put, processing, errors, reset, clearErrors } = - useForm({ - name: '', - bank_name: '', - holder_name: '', - account_number: '', - }) - - const handleOnChange = (event) => { - setData( - event.target.name, - event.target.type === 'checkbox' - ? event.target.checked - ? 1 - : 0 - : event.target.value - ) - } - - const handleReset = () => { - modalState.setData(null) - reset() - clearErrors() - } - - const handleClose = () => { - handleReset() - modalState.toggle() - } - - const handleSubmit = () => { - const account = modalState.data - if (account !== null) { - put(route('account.update', account), { - onSuccess: () => handleClose(), - }) - return - } - post(route('account.store'), { - onSuccess: () => handleClose(), - }) - } - - useEffect(() => { - const account = modalState.data - if (isEmpty(account) === false) { - setData({ - name: account.name, - bank_name: account.bank_name, - holder_name: account.holder_name, - account_number: account.account_number, - }) - return - } - }, [modalState]) - - return ( - - - - - -
- - -
-
- ) -} diff --git a/resources/js/Pages/Account/Index.jsx b/resources/js/Pages/Account/Index.jsx index 945ed10..1806600 100644 --- a/resources/js/Pages/Account/Index.jsx +++ b/resources/js/Pages/Account/Index.jsx @@ -7,7 +7,6 @@ import { useModalState } from '@/hooks' import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' import Pagination from '@/Components/Pagination' import ModalConfirm from '@/Components/ModalConfirm' -import FormModal from './FormModal' import { hasPermission } from '@/utils' export default function Account(props) { @@ -17,12 +16,6 @@ export default function Account(props) { } = props const confirmModal = useModalState() - const formModal = useModalState() - - const toggleFormModal = (account = null) => { - formModal.setData(account) - formModal.toggle() - } const handleDeleteClick = (account) => { confirmModal.setData(account) @@ -107,7 +100,11 @@ export default function Account(props) { {account.account_number} - bank logo alt + bank logo alt {canUpdate && ( - +
Ubah @@ -158,7 +161,6 @@ export default function Account(props) {
-
) } diff --git a/resources/js/Pages/Info/Form.jsx b/resources/js/Pages/Info/Form.jsx index 13da6f8..8fb0a5d 100644 --- a/resources/js/Pages/Info/Form.jsx +++ b/resources/js/Pages/Info/Form.jsx @@ -46,7 +46,11 @@ export default function Form(props) { }, [info]) return ( - +
diff --git a/resources/js/Pages/Role/Index.jsx b/resources/js/Pages/Role/Index.jsx index 67548a8..e664580 100644 --- a/resources/js/Pages/Role/Index.jsx +++ b/resources/js/Pages/Role/Index.jsx @@ -84,6 +84,12 @@ export default function Product(props) { > Nama + + Admin + {role.name} + +
+ {role.users.map( + (user) => ( +
+ router.visit( + route( + 'user.edit', + user + ) + ) + } + > + {user.name} +
+ ) + )} +
+ { + setData( + event.target.name, + event.target.type === 'checkbox' + ? event.target.checked + ? 1 + : 0 + : event.target.value + ) + } + const handleSubmit = () => { + if (isEmpty(user) === false) { + post(route('user.update', user), { + onSuccess: () => handleClose(), + }) + return + } + post(route('user.store'), { + onSuccess: () => handleClose(), + }) + } + + useEffect(() => { + if (isEmpty(user) === false) { + setData({ + name: user.name, + email: user.email, + role_id: user.role_id, + role: user.role, + username: user.username, + phone_wa: user.phone_wa, + photo: null, + photo_url: user.photo_url, + }) + } + }, [user]) + + return ( + + + +
+
+
+
Admin
+ + +62
} + name="phone_wa" + value={data.phone_wa} + onChange={handleOnChange} + error={errors.phone_wa} + formClassName={'pl-10'} + label="Whatsapp" + /> + + + + {data.role !== null && ( + <> + + setData('role_id', id) + } + error={errors.role_id} + /> + + )} + + setData('photo', e.target.files[0]) + } + error={errors.photo} + preview={ + isEmpty(data.photo_url) === false && ( + preview + ) + } + /> +
+ +
+
+
+
+
+ ) +} diff --git a/resources/js/Pages/User/FormModal.jsx b/resources/js/Pages/User/FormModal.jsx deleted file mode 100644 index 9551a93..0000000 --- a/resources/js/Pages/User/FormModal.jsx +++ /dev/null @@ -1,115 +0,0 @@ -import React, { useEffect } from "react"; -import Modal from "@/Components/Modal"; -import { useForm } from "@inertiajs/react"; -import Button from "@/Components/Button"; -import FormInput from "@/Components/FormInput"; -import RoleSelectionInput from "../Role/SelectionInput"; - -import { isEmpty } from "lodash"; - -export default function FormModal(props) { - const { modalState } = props - const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({ - name: '', - email: '', - password: '', - role_id: null, - role: '', - }) - - const handleOnChange = (event) => { - setData(event.target.name, event.target.type === 'checkbox' ? (event.target.checked ? 1 : 0) : event.target.value); - } - - const handleReset = () => { - modalState.setData(null) - reset() - clearErrors() - } - - const handleClose = () => { - handleReset() - modalState.toggle() - } - - const handleSubmit = () => { - const user = modalState.data - if(user !== null) { - put(route('user.update', user), { - onSuccess: () => handleClose(), - }) - return - } - post(route('user.store'), { - onSuccess: () => handleClose() - }) - } - - useEffect(() => { - const user = modalState.data - if (isEmpty(user) === false) { - setData({ - name: user.name, - email: user.email, - role_id: user.role_id, - role: user.role - }) - return - } - }, [modalState]) - - return ( - - - - - {data.role !== null && ( - <> - setData('role_id', id)} - error={errors.role_id} - /> - - )} -
- - -
-
- ) -} \ No newline at end of file diff --git a/resources/js/Pages/User/Index.jsx b/resources/js/Pages/User/Index.jsx index 43f5242..7cd198c 100644 --- a/resources/js/Pages/User/Index.jsx +++ b/resources/js/Pages/User/Index.jsx @@ -1,7 +1,6 @@ import React, { useEffect, useState } from 'react' -import { router } from '@inertiajs/react' import { usePrevious } from 'react-use' -import { Head } from '@inertiajs/react' +import { Head, Link, router } from '@inertiajs/react' import { Button, Dropdown } from 'flowbite-react' import { HiPencil, HiTrash } from 'react-icons/hi' import { useModalState } from '@/hooks' @@ -9,7 +8,6 @@ import { useModalState } from '@/hooks' import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' import Pagination from '@/Components/Pagination' import ModalConfirm from '@/Components/ModalConfirm' -import FormModal from './FormModal' import SearchInput from '@/Components/SearchInput' import { hasPermission } from '@/utils' @@ -23,12 +21,6 @@ export default function User(props) { const preValue = usePrevious(search) const confirmModal = useModalState() - const formModal = useModalState() - - const toggleFormModal = (user = null) => { - formModal.setData(user) - formModal.toggle() - } const handleDeleteClick = (user) => { confirmModal.setData(user) @@ -68,12 +60,9 @@ export default function User(props) {
{canCreate && ( - + + + )}
- ) } diff --git a/routes/admin.php b/routes/admin.php index ebdede2..67e7e71 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -48,8 +48,10 @@ Route::middleware(['http_secure_aware', 'inertia.admin']) // User Route::get('/users', [UserController::class, 'index'])->name('user.index'); + Route::get('/users/create', [UserController::class, 'create'])->name('user.create'); Route::post('/users', [UserController::class, 'store'])->name('user.store'); - Route::put('/users/{user}', [UserController::class, 'update'])->name('user.update'); + Route::get('/users/{user}', [UserController::class, 'edit'])->name('user.edit'); + Route::post('/users/{user}', [UserController::class, 'update'])->name('user.update'); Route::delete('/users/{user}', [UserController::class, 'destroy'])->name('user.destroy'); // Role