From 3582ba5433e6d845293633ccbb4be9ff5ee05c61 Mon Sep 17 00:00:00 2001 From: ajikamaludin Date: Thu, 26 Jan 2023 09:42:25 +0700 Subject: [PATCH] crud role and type --- app/Http/Controllers/CategoryController.php | 75 +++++++++ app/Http/Controllers/GeneralController.php | 8 +- app/Http/Controllers/TypeController.php | 63 ++++++++ app/Models/Category.php | 17 ++ app/Models/Document.php | 60 +++---- app/Models/Type.php | 15 ++ ...22_09_18_034528_create_documents_table.php | 32 ++-- .../2023_01_26_015830_create_types_table.php | 32 ++++ ...3_01_26_015838_create_categories_table.php | 34 ++++ resources/js/Layouts/AuthenticatedLayout.jsx | 6 +- resources/js/Pages/Category/FormModal.jsx | 153 ++++++++++++++++++ resources/js/Pages/Category/Index.jsx | 122 ++++++++++++++ resources/js/Pages/Type/FormModal.jsx | 112 +++++++++++++ resources/js/Pages/Type/Index.jsx | 118 ++++++++++++++ resources/views/app.blade.php | 2 +- routes/web.php | 12 ++ tailwind.config.js | 2 +- 17 files changed, 796 insertions(+), 67 deletions(-) create mode 100644 app/Http/Controllers/CategoryController.php create mode 100644 app/Http/Controllers/TypeController.php create mode 100644 app/Models/Category.php create mode 100644 app/Models/Type.php create mode 100644 database/migrations/2023_01_26_015830_create_types_table.php create mode 100644 database/migrations/2023_01_26_015838_create_categories_table.php create mode 100644 resources/js/Pages/Category/FormModal.jsx create mode 100644 resources/js/Pages/Category/Index.jsx create mode 100644 resources/js/Pages/Type/FormModal.jsx create mode 100644 resources/js/Pages/Type/Index.jsx diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php new file mode 100644 index 0000000..f329280 --- /dev/null +++ b/app/Http/Controllers/CategoryController.php @@ -0,0 +1,75 @@ + Category::paginate(), + ]); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:255', + 'short' => 'required|string|max:255', + 'duration' => 'required|numeric' + ]); + + Category::create([ + 'name' => $request->name, + 'short' => $request->short, + 'duration' => $request->duration, + ]); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, Category $category) + { + $request->validate([ + 'name' => 'required|string|max:255', + 'short' => 'required|string|max:255', + 'duration' => 'required|numeric' + ]); + + $category->update([ + 'name' => $request->name, + 'short' => $request->short, + 'duration' => $request->duration, + ]); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy(Category $category) + { + $category->delete(); + } +} diff --git a/app/Http/Controllers/GeneralController.php b/app/Http/Controllers/GeneralController.php index 05d36b8..084cc9b 100644 --- a/app/Http/Controllers/GeneralController.php +++ b/app/Http/Controllers/GeneralController.php @@ -11,10 +11,10 @@ class GeneralController extends Controller public function index() { return inertia('Dashboard', [ - 'count_active' => Document::where('status', Document::ACTIVE)->count(), - 'count_update' => Document::where('status', Document::UPDATE)->count(), - 'count_expired' => Document::where('status', Document::EXPIRED)->count(), - 'count_total' => Document::count(), + 'count_active' => 0, + 'count_update' => 0, + 'count_expired' => 0, + 'count_total' => 0, 'events' => DocumentReminder::with('document.type')->get(), ]); } diff --git a/app/Http/Controllers/TypeController.php b/app/Http/Controllers/TypeController.php new file mode 100644 index 0000000..7f4478d --- /dev/null +++ b/app/Http/Controllers/TypeController.php @@ -0,0 +1,63 @@ + Type::paginate(), + ]); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function store(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:255' + ]); + + Type::create(['name' => $request->name]); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, Type $type) + { + $request->validate([ + 'name' => 'required|string|max:255' + ]); + + $type->update(['name' => $request->name]); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy(Type $type) + { + $type->delete(); + } +} diff --git a/app/Models/Category.php b/app/Models/Category.php new file mode 100644 index 0000000..7c4f461 --- /dev/null +++ b/app/Models/Category.php @@ -0,0 +1,17 @@ + 'datetime:Y-m-d', - 'end_date' => 'datetime:Y-m-d' + 'publish_date' => 'datetime:Y-m-d', + 'due_date' => 'datetime:Y-m-d' ]; - public const ACTIVE = 0; - public const UPDATE = 1; - public const EXPIRED = 2; - - public function department() - { - return $this->belongsTo(Department::class, 'department_id'); - } - - public function type() - { - return $this->belongsTo(TypeDoc::class, 'type_doc_id'); - } - - public function reminders() - { - return $this->hasMany(DocumentReminder::class); - } - - public function shares() - { - return $this->hasMany(DocumentShare::class); - } - public function creator() { return $this->belongsTo(User::class, 'user_id'); diff --git a/app/Models/Type.php b/app/Models/Type.php new file mode 100644 index 0000000..4b9b69b --- /dev/null +++ b/app/Models/Type.php @@ -0,0 +1,15 @@ +id(); - $table->integer('no', false); - $table->string('name'); - $table->string('no_doc'); - $table->foreignId('type_doc_id')->constrained(); - $table->string('company_name'); - $table->string('first_person_name'); - $table->string('second_person_name'); - $table->dateTime('start_date'); - $table->dateTime('end_date'); - $table->foreignId('department_id')->constrained(); - $table->string('pic_name'); - $table->string('email'); - $table->text('note'); - $table->string('document'); - $table->foreignId('user_id')->constrained(); - $table->smallInteger('status')->default(0); + $table->string("no")->nullable(); + $table->string("no_doc")->nullable(); + $table->string("name")->nullable(); + $table->string("company_name")->nullable(); + $table->foreignId("type_id")->constrained(); //select jenis + $table->foreignId("category_id")->constrained(); //select + $table->string("publisher")->nullable(); + $table->text("description")->nullable(); + $table->timestamp("publish_date")->nullable(); + $table->timestamp("due_date")->nullable(); //for reminder + $table->smallInteger("status")->default(1); //only 1 yes/ 0no + $table->smallInteger("type")->default(1); //only 1 tetap/ 0tidak tetap + $table->string("group")->nullable(); + $table->string("region")->nullable(); + $table->string("document")->nullable(); + $table->foreignId("user_id")->constrained(); $table->timestamps(); }); } diff --git a/database/migrations/2023_01_26_015830_create_types_table.php b/database/migrations/2023_01_26_015830_create_types_table.php new file mode 100644 index 0000000..0d469f0 --- /dev/null +++ b/database/migrations/2023_01_26_015830_create_types_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('types'); + } +}; diff --git a/database/migrations/2023_01_26_015838_create_categories_table.php b/database/migrations/2023_01_26_015838_create_categories_table.php new file mode 100644 index 0000000..6e0e8f2 --- /dev/null +++ b/database/migrations/2023_01_26_015838_create_categories_table.php @@ -0,0 +1,34 @@ +id(); + $table->string("name"); + $table->string("short"); + $table->integer("duration"); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('categories'); + } +}; diff --git a/resources/js/Layouts/AuthenticatedLayout.jsx b/resources/js/Layouts/AuthenticatedLayout.jsx index 27b7672..f2dca7c 100644 --- a/resources/js/Layouts/AuthenticatedLayout.jsx +++ b/resources/js/Layouts/AuthenticatedLayout.jsx @@ -10,8 +10,8 @@ const rs = [ {name: "Dashboard", route: "dashboard", show: true}, {name: "Dokumen", show: true, items: [ {name: "Dokumen", route: 'docs.index', show: true, permission: 'view-document'}, - {name: "Ketegori", route: 'docs.index', show: true, permission: 'view-category'}, - {name: "Jenis", route: 'docs.index', show: true, permission: 'view-type'}, + {name: "Ketegori", route: 'categories.index', show: true, permission: 'view-category'}, + {name: "Jenis", route: 'types.index', show: true, permission: 'view-type'}, ]}, {name: "User", show: true, items: [ {name:"User", route: "users.index", show: true, permission: 'view-user'}, @@ -51,7 +51,7 @@ export default function Authenticated({ auth, children, flash, notify }) { Monitor Doc
-
+
{routes.filter(r => r.show).map((item, index) => (
{'items' in item ? ( diff --git a/resources/js/Pages/Category/FormModal.jsx b/resources/js/Pages/Category/FormModal.jsx new file mode 100644 index 0000000..083a4d0 --- /dev/null +++ b/resources/js/Pages/Category/FormModal.jsx @@ -0,0 +1,153 @@ +import React, { useEffect } from 'react' +import { useForm, usePage } from '@inertiajs/react' +import { toast } from 'react-toastify' + +export default function FormModal(props) { + const { modalState } = props + + const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({ + name: '', + short: '', + duration: 0 + }) + + const handleOnChange = (event) => { + setData(event.target.name, event.target.type === 'checkbox' ? event.target.checked : event.target.value); + } + + const handleReset = () => { + reset() + clearErrors() + modalState.setData(null) + } + + const handleCancel = () => { + handleReset() + modalState.toggle() + } + + const handleSubmit = () => { + const category = modalState.data + if(category !== null) { + put(route('categories.update', category), { + onSuccess: () => + Promise.all([ + handleReset(), + modalState.toggle(), + toast.success('The Data has been changed'), + ]), + }) + return + } + + post(route('categories.store'), { + onSuccess: () => + Promise.all([ + handleReset(), + modalState.toggle(), + toast.success('The Data has been saved'), + ]), + }) + } + + useEffect(() => { + const category = modalState.data + if (category !== null) { + setData({ + name: category?.name, + short: category?.short, + duration: category?.duration, + }) + } + }, [modalState]) + + return ( +
+
+

Ketegori

+
+ + + +
+
+ + + +
+
+ + + +
+
+
+ Simpan +
+
+ Batal +
+
+
+
+ ) +} \ No newline at end of file diff --git a/resources/js/Pages/Category/Index.jsx b/resources/js/Pages/Category/Index.jsx new file mode 100644 index 0000000..c75d0ed --- /dev/null +++ b/resources/js/Pages/Category/Index.jsx @@ -0,0 +1,122 @@ +import React from 'react' +import { Head } from '@inertiajs/react' +import { router } from '@inertiajs/react' +import { toast } from 'react-toastify' + +import { useModalState } from '@/Hooks' +import { hasPermission } from '@/utils' +import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' +import Pagination from '@/Components/Pagination' +import ModalConfirm from '@/Components/ModalConfirm' +import FormModal from './FormModal' + +export default function Categories(props) { + const { data: categories, links } = props.categories + + const formModal = useModalState(false) + const toggle = (category = null) => { + formModal.setData(category) + formModal.toggle() + } + + const confirmModal = useModalState(false) + const handleDelete = (category) => { + confirmModal.setData(category) + confirmModal.toggle() + } + + const onDelete = () => { + const category = confirmModal.data + if(category != null) { + router.delete(route('categories.destroy', category), { + onSuccess: () => toast.success('The Data has been deleted'), + }) + } + } + + const canCreate = hasPermission('create-category', props.auth.user) + const canUpdate = hasPermission('update-category', props.auth.user) + const canDelete = hasPermission('delete-category', props.auth.user) + + return ( + + +
+
+
+
+ {canCreate && ( +
toggle()} + > + Tambah +
+ )} +
+
+ + + + + + + + + + + + {categories?.map((category) => ( + + + + + + + + ))} + +
IdNamaSingkatanDurasi
{category.id}{category.name}{category.short}{category.duration} + {canUpdate && ( +
+ toggle(category) + } + > + Edit +
+ )} + {canDelete && ( +
+ handleDelete(category) + } + > + Delete +
+ )} +
+
+ +
+
+
+ + + +
+ ) +} \ No newline at end of file diff --git a/resources/js/Pages/Type/FormModal.jsx b/resources/js/Pages/Type/FormModal.jsx new file mode 100644 index 0000000..45124d7 --- /dev/null +++ b/resources/js/Pages/Type/FormModal.jsx @@ -0,0 +1,112 @@ +import React, { useEffect } from 'react' +import { useForm, usePage } from '@inertiajs/react' +import { toast } from 'react-toastify' + +export default function FormModal(props) { + const { modalState } = props + + const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({ + name: '', + }) + + const handleOnChange = (event) => { + setData(event.target.name, event.target.type === 'checkbox' ? event.target.checked : event.target.value); + } + + const handleReset = () => { + reset() + clearErrors() + modalState.setData(null) + } + + const handleCancel = () => { + handleReset() + modalState.toggle() + } + + const handleSubmit = () => { + const type = modalState.data + if(type !== null) { + put(route('types.update', type), { + onSuccess: () => + Promise.all([ + handleReset(), + modalState.toggle(), + toast.success('The Data has been changed'), + ]), + }) + return + } + post(route('types.store'), { + onSuccess: () => + Promise.all([ + handleReset(), + modalState.toggle(), + toast.success('The Data has been saved'), + ]), + }) + } + + useEffect(() => { + const type = modalState.data + if (type !== null) { + setData({ + name: type?.name, + }) + } + }, [modalState]) + + return ( +
+
+

Jenis

+
+ + + +
+
+
+ Simpan +
+
+ Batal +
+
+
+
+ ) +} \ No newline at end of file diff --git a/resources/js/Pages/Type/Index.jsx b/resources/js/Pages/Type/Index.jsx new file mode 100644 index 0000000..0666eed --- /dev/null +++ b/resources/js/Pages/Type/Index.jsx @@ -0,0 +1,118 @@ +import React from 'react' +import { Head } from '@inertiajs/react' +import { router } from '@inertiajs/react' +import { toast } from 'react-toastify' + +import { useModalState } from '@/Hooks' +import { hasPermission } from '@/utils' +import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout' +import Pagination from '@/Components/Pagination' +import ModalConfirm from '@/Components/ModalConfirm' +import FormModal from './FormModal' + +export default function Types(props) { + const { data: types, links } = props.types + + const formModal = useModalState(false) + const toggle = (type = null) => { + formModal.setData(type) + formModal.toggle() + } + + const confirmModal = useModalState(false) + const handleDelete = (type) => { + confirmModal.setData(type) + confirmModal.toggle() + } + + const onDelete = () => { + const type = confirmModal.data + if(type != null) { + router.delete(route('types.destroy', type), { + onSuccess: () => toast.success('The Data has been deleted'), + }) + } + } + + const canCreate = hasPermission('create-type', props.auth.user) + const canUpdate = hasPermission('update-type', props.auth.user) + const canDelete = hasPermission('delete-type', props.auth.user) + + return ( + + +
+
+
+
+ {canCreate && ( +
toggle()} + > + Tambah +
+ )} +
+
+ + + + + + + + + + {types?.map((type) => ( + + + + + + ))} + +
IdNama
{type.id}{type.name} + {canUpdate && ( +
+ toggle(type) + } + > + Edit +
+ )} + {canDelete && ( +
+ handleDelete(type) + } + > + Delete +
+ )} +
+
+ +
+
+
+ + + +
+ ) +} \ No newline at end of file diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php index 443a5b1..ea41696 100644 --- a/resources/views/app.blade.php +++ b/resources/views/app.blade.php @@ -1,5 +1,5 @@ - + diff --git a/routes/web.php b/routes/web.php index 2c39c4a..b6befe2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,9 +1,11 @@ group(function () { Route::put('/roles/{role}', [RoleController::class, 'update'])->name('roles.update'); Route::delete('/roles/{role}', [RoleController::class, 'destroy'])->name('roles.destroy'); + Route::get('/types', [TypeController::class, 'index'])->name('types.index'); + Route::post('/types', [TypeController::class, 'store'])->name('types.store'); + Route::put('/types/{type}', [TypeController::class, 'update'])->name('types.update'); + Route::delete('/types/{type}', [TypeController::class, 'destroy'])->name('types.destroy'); + + Route::get('/categories', [CategoryController::class, 'index'])->name('categories.index'); + Route::post('/categories', [CategoryController::class, 'store'])->name('categories.store'); + Route::put('/categories/{category}', [CategoryController::class, 'update'])->name('categories.update'); + Route::delete('/categories/{category}', [CategoryController::class, 'destroy'])->name('categories.destroy'); + Route::get('/docs', [DocumentController::class, 'index'])->name('docs.index'); Route::get('/docs/export', [DocumentController::class, 'export'])->name('docs.export'); Route::get('/docs/create', [DocumentController::class, 'create'])->name('docs.create'); diff --git a/tailwind.config.js b/tailwind.config.js index 978f68a..48a734b 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -23,6 +23,6 @@ module.exports = { ], daisyui: { - themes: ["light", "dark", "corporate"], + themes: ["light", "dark", "corporate", "garden"], }, };