From 99a55080dc1b56f2bf18d79c88a981053f39b4d1 Mon Sep 17 00:00:00 2001 From: Daeng Deni Mardaeni Date: Wed, 15 Nov 2023 15:00:51 +0700 Subject: [PATCH] add module product --- DataTables/ProductDataTable.php | 90 ++++++++++++++++++ ...023_11_15_061606_create_products_table.php | 38 ++++++++ Entities/Product.php | 20 ++++ Http/Controllers/ProductController.php | 37 ++++++++ Http/Requests/Product/StoreProductRequest.php | 72 ++++++++++++++ .../Requests/Product/UpdateProductRequest.php | 69 ++++++++++++++ Livewire/Product/ProductModal.php | 94 +++++++++++++++++++ .../livewire/product/product-modal.blade.php | 72 ++++++++++++++ .../parameter/products/_actions.blade.php | 23 +++++ .../views/parameter/products/_draw-scripts.js | 37 ++++++++ .../views/parameter/products/index.blade.php | 72 ++++++++++++++ Resources/views/partials/menu/_app.blade.php | 8 ++ Routes/breadcrumbs.php | 5 + Routes/web.php | 1 + 14 files changed, 638 insertions(+) create mode 100644 DataTables/ProductDataTable.php create mode 100644 Database/Migrations/2023_11_15_061606_create_products_table.php create mode 100644 Entities/Product.php create mode 100644 Http/Controllers/ProductController.php create mode 100644 Http/Requests/Product/StoreProductRequest.php create mode 100644 Http/Requests/Product/UpdateProductRequest.php create mode 100644 Livewire/Product/ProductModal.php create mode 100644 Resources/views/livewire/product/product-modal.blade.php create mode 100644 Resources/views/parameter/products/_actions.blade.php create mode 100644 Resources/views/parameter/products/_draw-scripts.js create mode 100644 Resources/views/parameter/products/index.blade.php diff --git a/DataTables/ProductDataTable.php b/DataTables/ProductDataTable.php new file mode 100644 index 0000000..efc049b --- /dev/null +++ b/DataTables/ProductDataTable.php @@ -0,0 +1,90 @@ +filter(function ($query) { + if (request()->has('search')) { + $search = request()->get('search'); + $query->where('kode', 'like', "%" . $search['value'] . "%") + ->orWhere('name', 'like', "%" . $search['value'] . "%"); + } + })->addIndexColumn()->editColumn('updated_at', function ($row) { + return $row->updated_at->locale('id')->translatedFormat('d F Y H:i:s'); + })->rawColumns(['action'])->addColumn('action', function ($product) { + return view('writeoff::parameter.products._actions', compact('product')); + })->setRowId('id'); + } + + /** + * Get the query source of dataTable. + */ + public function query(Product $model) + : QueryBuilder + { + return $model->newQuery(); + } + + /** + * Optional method if you want to use the html builder. + */ + public function html() + : HtmlBuilder + { + return $this->builder() + ->setTableId('product-table') + ->columns($this->getColumns()) + ->minifiedAjax() + ->stateSave(false) + ->responsive() + ->autoWidth(true) + ->orderBy(1) + ->parameters([ + 'scrollX' => false, + 'drawCallback' => 'function() { KTMenu.createInstances(); }', + ]) + ->addTableClass('align-middle table-row-dashed fs-6 gy-5') + ->drawCallback("function() {" . file_get_contents(Module::getModulePath('writeoff').'Resources/views/parameter/products/_draw-scripts.js') . "}"); + } + + /** + * Get the dataTable columns definition. + */ + public function getColumns() + : array + { + return [ + Column::make('DT_RowIndex')->title('No')->orderable(false)->searchable(false), + Column::make('kode')->title('Kode Product'), + Column::make('name')->title('Nama Product'), + Column::make('updated_at')->title('Last Update'), + Column::computed('action')->exportable(false)->printable(false)->width(60)->addClass('text-center'), + ]; + } + + /** + * Get the filename for export. + */ + protected function filename() + : string + { + return 'Product_' . date('YmdHis'); + } + } diff --git a/Database/Migrations/2023_11_15_061606_create_products_table.php b/Database/Migrations/2023_11_15_061606_create_products_table.php new file mode 100644 index 0000000..37d98f7 --- /dev/null +++ b/Database/Migrations/2023_11_15_061606_create_products_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('kode',4)->unique(); + $table->string('name'); + $table->boolean('status')->default(true)->nullable(); + $table->timestamps(); + $table->timestamp('authorized_at')->nullable(); + $table->char('authorized_status', 1)->nullable(); + $table->softDeletes(); + + $table->unsignedBigInteger('created_by')->nullable(); + $table->unsignedBigInteger('updated_by')->nullable(); + $table->unsignedBigInteger('deleted_by')->nullable(); + $table->unsignedBigInteger('authorized_by')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('products'); + } +}; diff --git a/Entities/Product.php b/Entities/Product.php new file mode 100644 index 0000000..2c1c1ef --- /dev/null +++ b/Entities/Product.php @@ -0,0 +1,20 @@ +hasMany(Rekening::class); + } + } diff --git a/Http/Controllers/ProductController.php b/Http/Controllers/ProductController.php new file mode 100644 index 0000000..4d74859 --- /dev/null +++ b/Http/Controllers/ProductController.php @@ -0,0 +1,37 @@ +middleware(function ($request, $next) { + $this->user = Auth::guard('web')->user(); + return $next($request); + }); + } + + /** + * Display a listing of the Currencies. + * + * @param \Modules\Writeoff\DataTables\ProductDataTable $dataTable + * + * @return mixed + */ + public function index(ProductDataTable $dataTable, Request $request) + { + if (is_null($this->user) || !$this->user->can('master.read')) { + abort(403, 'Sorry !! You are Unauthorized to view any master data !'); + } + + return $dataTable->render('writeoff::parameter.products.index'); + } + } diff --git a/Http/Requests/Product/StoreProductRequest.php b/Http/Requests/Product/StoreProductRequest.php new file mode 100644 index 0000000..7a2661e --- /dev/null +++ b/Http/Requests/Product/StoreProductRequest.php @@ -0,0 +1,72 @@ + + */ + public function rules() + : array + { + return [ + 'kode' => 'required|string|max:4|min:4|unique:products,kode', + 'name' => 'required|string|max:100' + ]; + } + + public function ignored(): string + { + return $this->id; + } + + /** + * Configure the validator instance. + */ + public function withValidator(Validator $validator) + : void + { + $validator->after(function (Validator $validator) { + if ($validator->errors()->any()) { + $errors = json_decode($validator->errors()->toJson(), true); + + + foreach ($errors as $key => $value) { + flash($value[0]); + } + return redirect()->route('parameter.products.index')->with('error', 'Product created failed.'); + } + + }); + } + + protected function failedValidation(Validator|\Illuminate\Contracts\Validation\Validator $validator) + : JsonResponse + { + $errors = (new ValidationException($validator))->errors(); + + throw new HttpResponseException(response()->json([ + 'success' => false, + 'errors' => $errors, + 'messages' => 'Product created failed.' + ], JsonResponse::HTTP_UNPROCESSABLE_ENTITY)); + } + } diff --git a/Http/Requests/Product/UpdateProductRequest.php b/Http/Requests/Product/UpdateProductRequest.php new file mode 100644 index 0000000..d99522a --- /dev/null +++ b/Http/Requests/Product/UpdateProductRequest.php @@ -0,0 +1,69 @@ + + */ + public function rules() + : array + { + $this->_id = json_decode(json_decode(file_get_contents('php://input'))->components[0]->snapshot)->data->id; + + return [ + 'kode' => 'required|string|max:4|min:4|unique:products,kode,' . $this->_id, + 'name' => 'required|string|max:100' + ]; + } + + /** + * Configure the validator instance. + */ + public function withValidator(Validator $validator) + : void + { + $validator->after(function (Validator $validator) { + if ($validator->errors()->any()) { + $error = json_decode($validator->errors()->toJson(), true); + foreach ($error as $key => $value) { + flash($value[0]); + } + + return redirect()->route('parameter.products.index')->with('error', 'Product updated failed.'); + } + }); + } + + protected function failedValidation(Validator|\Illuminate\Contracts\Validation\Validator $validator) + : JsonResponse + { + $errors = (new ValidationException($validator))->errors(); + + throw new HttpResponseException(response()->json([ + 'success' => false, + 'errors' => $errors, + 'messages' => 'Product updated failed.' + ], JsonResponse::HTTP_UNPROCESSABLE_ENTITY)); + } + } diff --git a/Livewire/Product/ProductModal.php b/Livewire/Product/ProductModal.php new file mode 100644 index 0000000..37fb7d7 --- /dev/null +++ b/Livewire/Product/ProductModal.php @@ -0,0 +1,94 @@ + 'delete', + 'update' => 'update', + ]; + + public function render() + { + return view('writeoff::livewire.product.product-modal'); + } + + public function submit() + { + $this->validate(); + + // Validate the form input data + DB::transaction(function () { + // Prepare the data for creating a new user + $data = [ + 'kode' => $this->kode, + 'name' => $this->name + ]; + + if ($this->edit_mode) { + // Emit a success event with a message + $product = Product::find($this->id); + $product->update($data); + + $this->dispatch('success', __('Product updated')); + } else { + // Emit a success event with a message + Product::create($data); + $this->dispatch('success', __('New Product created')); + } + }); + + // Reset the form fields after successful submission + $this->reset(); + } + + public function update($id) + { + $this->edit_mode = true; + + $product = Product::find($id); + + $this->id = $product->id; + $this->kode = $product->kode; + $this->name = $product->name; + } + + public function delete($id) + { + Product::destroy($id); + + // Emit a success event with a message + $this->dispatch('success', 'Product successfully deleted'); + } + + public function hydrate() + { + $this->resetErrorBag(); + $this->resetValidation(); + } + + protected function rules() + { + if ($this->edit_mode) { + $request = new UpdateProductRequest(); + } else { + $request = new StoreProductRequest(); + } + + return $request->rules(); + } + } + diff --git a/Resources/views/livewire/product/product-modal.blade.php b/Resources/views/livewire/product/product-modal.blade.php new file mode 100644 index 0000000..08ee60b --- /dev/null +++ b/Resources/views/livewire/product/product-modal.blade.php @@ -0,0 +1,72 @@ + diff --git a/Resources/views/parameter/products/_actions.blade.php b/Resources/views/parameter/products/_actions.blade.php new file mode 100644 index 0000000..ba6291c --- /dev/null +++ b/Resources/views/parameter/products/_actions.blade.php @@ -0,0 +1,23 @@ + + Actions + + + + + diff --git a/Resources/views/parameter/products/_draw-scripts.js b/Resources/views/parameter/products/_draw-scripts.js new file mode 100644 index 0000000..24ddfab --- /dev/null +++ b/Resources/views/parameter/products/_draw-scripts.js @@ -0,0 +1,37 @@ +// Initialize KTMenu +KTMenu.init(); + +// Add click event listener to delete buttons +document.querySelectorAll('[data-kt-action="delete_row"]').forEach(function (element) { + element.addEventListener('click', function () { + Swal.fire({ + text: 'Are you sure you want to remove?', + icon: 'warning', + buttonsStyling: false, + showCancelButton: true, + confirmButtonText: 'Yes', + cancelButtonText: 'No', + customClass: { + confirmButton: 'btn btn-danger', + cancelButton: 'btn btn-secondary', + } + }).then((result) => { + if (result.isConfirmed) { + Livewire.dispatch('delete', { id : this.getAttribute('data-kt-id') }); + } + }); + }); +}); + +// Add click event listener to update buttons +document.querySelectorAll('[data-kt-action="update_row"]').forEach(function (element) { + element.addEventListener('click', function () { + Livewire.dispatch('update', { id : this.getAttribute('data-kt-id') }); + }); +}); + +// Listen for 'success' event emitted by Livewire +Livewire.on('success', (message) => { + // Reload the users-table datatable + LaravelDataTables['product-table'].ajax.reload(); +}); diff --git a/Resources/views/parameter/products/index.blade.php b/Resources/views/parameter/products/index.blade.php new file mode 100644 index 0000000..ed73a82 --- /dev/null +++ b/Resources/views/parameter/products/index.blade.php @@ -0,0 +1,72 @@ + + + @section('title') + Produk + @endsection + + @section('breadcrumbs') + {{ Breadcrumbs::render('parameter.products') }} + @endsection + +
+ +
+ +
+ +
+ {!! getIcon('magnifier', 'fs-3 position-absolute ms-5') !!} + +
+ +
+ + + +
+ +
+ + + +
+ + + + + +
+ +
+ + + +
+ +
+ {{ $dataTable->table() }} +
+ +
+ +
+ + @push('scripts') + {{ $dataTable->scripts() }} + + @endpush + +
diff --git a/Resources/views/partials/menu/_app.blade.php b/Resources/views/partials/menu/_app.blade.php index b020d4e..b67497c 100644 --- a/Resources/views/partials/menu/_app.blade.php +++ b/Resources/views/partials/menu/_app.blade.php @@ -29,6 +29,14 @@ + + + + + Produk + + + diff --git a/Routes/breadcrumbs.php b/Routes/breadcrumbs.php index 509b9f6..7452157 100644 --- a/Routes/breadcrumbs.php +++ b/Routes/breadcrumbs.php @@ -18,6 +18,11 @@ $trail->push('Mata Uang', route('parameter.currencies.index')); }); + Breadcrumbs::for('parameter.products', function (BreadcrumbTrail $trail) { + $trail->parent('parameter'); + $trail->push('Produk', route('parameter.products.index')); + }); + Breadcrumbs::for('parameter.guarantee-types', function (BreadcrumbTrail $trail) { $trail->parent('parameter'); $trail->push('Jenis Jaminan', route('parameter.guarantee_types.index')); diff --git a/Routes/web.php b/Routes/web.php index f1a461f..e3ccfb7 100644 --- a/Routes/web.php +++ b/Routes/web.php @@ -14,6 +14,7 @@ Route::name('parameter.')->prefix('parameter')->group(function() { Route::get('branches', 'BranchController@index')->name('branches.index'); Route::get('currencies', 'CurrencyController@index')->name('currencies.index'); + Route::get('products', 'ProductController@index')->name('products.index'); Route::get('guarantee-types', 'GuaranteeTypeController@index')->name('guarantee_types.index'); Route::get('facility-types', 'FacilityTypeController@index')->name('facility_types.index'); Route::get('loan-types', 'LoanTypeController@index')->name('loan_types.index');