From beac71d1826670b8f54e837a9137df79d98649c9 Mon Sep 17 00:00:00 2001 From: arifal Date: Mon, 17 Feb 2025 18:40:00 +0700 Subject: [PATCH] add business industry crud --- .../Api/BusinessOrIndustriesController.php | 120 ++++++++ app/Http/Controllers/Api/UsersController.php | 25 ++ .../BusinessOrIndustriesController.php | 66 +++++ .../Controllers/Master/UsersController.php | 4 +- app/Http/Requests/BusinessIndustryRequest.php | 39 +++ app/Http/Requests/UsersRequest.php | 43 +++ app/Imports/BusinessIndustriesImport.php | 39 +++ app/Models/BusinessOrIndustry.php | 24 ++ ...23_create_business_or_industries_table.php | 39 +++ database/seeders/UsersRoleMenuSeeder.php | 11 +- resources/js/business-industries/create.js | 125 +++++++++ resources/js/business-industries/index.js | 260 ++++++++++++++++++ resources/js/business-industries/update.js | 79 ++++++ resources/js/data-settings/index.js | 2 +- resources/js/master/users/create.js | 6 + .../business-industries/create.blade.php | 78 ++++++ .../views/business-industries/edit.blade.php | 89 ++++++ .../views/business-industries/index.blade.php | 31 +++ routes/api.php | 5 + routes/web.php | 2 + vite.config.js | 4 + 21 files changed, 1088 insertions(+), 3 deletions(-) create mode 100644 app/Http/Controllers/Api/BusinessOrIndustriesController.php create mode 100644 app/Http/Controllers/BusinessOrIndustriesController.php create mode 100644 app/Http/Requests/BusinessIndustryRequest.php create mode 100644 app/Http/Requests/UsersRequest.php create mode 100644 app/Imports/BusinessIndustriesImport.php create mode 100644 app/Models/BusinessOrIndustry.php create mode 100644 database/migrations/2025_02_17_144423_create_business_or_industries_table.php create mode 100644 resources/js/business-industries/create.js create mode 100644 resources/js/business-industries/index.js create mode 100644 resources/js/business-industries/update.js create mode 100644 resources/views/business-industries/create.blade.php create mode 100644 resources/views/business-industries/edit.blade.php create mode 100644 resources/views/business-industries/index.blade.php diff --git a/app/Http/Controllers/Api/BusinessOrIndustriesController.php b/app/Http/Controllers/Api/BusinessOrIndustriesController.php new file mode 100644 index 0000000..dc6eb57 --- /dev/null +++ b/app/Http/Controllers/Api/BusinessOrIndustriesController.php @@ -0,0 +1,120 @@ +orderBy('id', 'desc'); + + if ($request->has("search") && !empty($request->get("search"))) { + $search = $request->get("search"); + + info($request); // Debugging log + + $query->where(function ($q) use ($search) { + $q->where("nop", "LIKE", "%{$search}%") + ->orWhere("nama_kecamatan", "LIKE", "%{$search}%") + ->orWhere("nama_kelurahan", "LIKE", "%{$search}%"); + }); + } + + return response()->json($query->paginate()); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + // + } + + /** + * Display the specified resource. + */ + public function show(string $id) + { + // + } + + /** + * Update the specified resource in storage. + */ + public function update(BusinessIndustryRequest $request, string $id) + { + try{ + $data = BusinessOrIndustry::findOrFail($id); + $data->update($request->validated()); + return response()->json(['message' => 'Data updated successfully.'], 200); + }catch(\Exception $e){ + \Log::error($e->getMessage()); + return response()->json(['message' => 'Failed to update data'],500); + } + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(string $id) + { + try{ + $data = BusinessOrIndustry::findOrFail($id); + $data->delete(); + return response()->json(['message' => 'Data deleted successfully.'], 200); + }catch(\Exception $e){ + \Log::error($e->getMessage()); + return response()->json(['message' => 'Failed to delete data'],500); + } + } + + public function upload(Request $request){ + + if ($request->hasFile('file')) { + $file = $request->file('file'); + } + + // Validasi file + $validator = Validator::make($request->all(), [ + 'file' => 'required|mimes:xlsx,xls|max:102400', // Max 100MB + ]); + + if ($validator->fails()) { + return response()->json([ + 'message' => 'File validation failed.', + 'errors' => $validator->errors() + ], 400); + } + + try { + // Ambil file dari request + $file = $request->file('file'); + + // Menggunakan Laravel Excel untuk mengimpor file + Excel::import(new BusinessIndustriesImport, $file); + + // Jika sukses, kembalikan respons sukses + return response()->json([ + 'message' => 'File uploaded and imported successfully!' + ], 200); + } catch (\Exception $e) { + // Jika ada error, kembalikan error response + return response()->json([ + 'message' => 'Error during file import.', + 'error' => $e->getMessage() + ], 500); + } + + } +} diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 2985421..ce9a390 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -4,9 +4,11 @@ namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; use App\Http\Requests\Auth\LoginRequest; +use App\Http\Requests\UsersRequest; use App\Http\Resources\UserResource; use App\Models\User; use App\Traits\GlobalApiResponse; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Http\Request; @@ -35,4 +37,27 @@ class UsersController extends Controller $request->user()->tokens()->delete(); return response()->json(['message' => 'logged out successfully']); } + public function store(UsersRequest $request){ + $validate_data = $request->validated(); + + DB::beginTransaction(); + try{ + $user = User::create([ + 'name' => $validate_data->name, + 'email' => $validate_data->email, + 'password' => Hash::make($validate_data->password), + 'firstname' => $validate_data->firstname, + 'lastname' => $validate_data->lastname, + 'position' => $validate_data->position + ]); + + $user->roles()->attach($request->role_id); + + DB::commit(); + return response()->json(['message' => 'Successfully created'],201); + }catch(\Exception $e){ + DB::rollBack(); + return response()->json(['message' => $e->getMessage()],500); + }; + } } diff --git a/app/Http/Controllers/BusinessOrIndustriesController.php b/app/Http/Controllers/BusinessOrIndustriesController.php new file mode 100644 index 0000000..b2d5b92 --- /dev/null +++ b/app/Http/Controllers/BusinessOrIndustriesController.php @@ -0,0 +1,66 @@ +validate([ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], @@ -39,6 +40,7 @@ class UsersController extends Controller 'role_id' => 'required|exists:roles,id' ]); + DB::beginTransaction(); try{ $user = User::create([ diff --git a/app/Http/Requests/BusinessIndustryRequest.php b/app/Http/Requests/BusinessIndustryRequest.php new file mode 100644 index 0000000..5f3af3c --- /dev/null +++ b/app/Http/Requests/BusinessIndustryRequest.php @@ -0,0 +1,39 @@ +|string> + */ + public function rules(): array + { + return [ + 'nama_kecamatan' => 'required|string|max:255', + 'nama_kelurahan' => 'required|string|max:255', + 'nop' => 'required|string|max:255|unique:business_or_industries,nop,' . $this->route('api_business_industry'), + 'nama_wajib_pajak' => 'required|string|max:255', + 'alamat_wajib_pajak' => 'nullable|string|max:255', + 'alamat_objek_pajak' => 'required|string|max:255', + 'luas_bumi' => 'required|numeric', + 'luas_bangunan' => 'required|numeric', + 'njop_bumi' => 'required|numeric', + 'njop_bangunan' => 'required|numeric', + 'ketetapan' => 'required|string|max:255', + 'tahun_pajak' => 'required|integer|min:1900|max:' . date('Y'), + ]; + } +} diff --git a/app/Http/Requests/UsersRequest.php b/app/Http/Requests/UsersRequest.php new file mode 100644 index 0000000..95ffd95 --- /dev/null +++ b/app/Http/Requests/UsersRequest.php @@ -0,0 +1,43 @@ +|string> + */ + public function rules(): array + { + $userId = $this->route('user'); // Get user ID from route (used in update) + + return [ + 'name' => ['required', 'string', 'max:255'], + 'email' => [ + 'required', + 'string', + 'email', + 'max:255', + Rule::unique('users')->ignore($userId), // Ignore the user's own email when updating + ], + 'password' => [$this->isMethod('post') ? 'required' : 'nullable', 'confirmed', 'max:255'], + 'firstname' => ['required', 'string', 'max:255'], + 'lastname' => ['required', 'string', 'max:255'], + 'position' => ['required', 'string', 'max:255'], + 'role_id' => ['required', 'exists:roles,id'], + ]; + } +} diff --git a/app/Imports/BusinessIndustriesImport.php b/app/Imports/BusinessIndustriesImport.php new file mode 100644 index 0000000..3cdc88d --- /dev/null +++ b/app/Imports/BusinessIndustriesImport.php @@ -0,0 +1,39 @@ +skip(1) as $row){ + $clean_nop = preg_replace('/[^A-Za-z0-9]/', '', $row[2]); + if (!BusinessOrIndustry::where('nop', $clean_nop)->exists()) { + BusinessOrIndustry::create([ + 'nama_kecamatan' => $row[0], + 'nama_kelurahan' => $row[1], + 'nop' => $clean_nop, // Store cleaned 'nop' + 'nama_wajib_pajak' => $row[3], + 'alamat_wajib_pajak' => $row[4], + 'alamat_objek_pajak' => $row[5], + 'luas_bumi' => $row[6], + 'luas_bangunan' => $row[7], + 'njop_bumi' => $row[8], + 'njop_bangunan' => $row[9], + 'ketetapan' => $row[10], + 'tahun_pajak' => $row[11], + ]); + } + } + } +} diff --git a/app/Models/BusinessOrIndustry.php b/app/Models/BusinessOrIndustry.php new file mode 100644 index 0000000..9873f2e --- /dev/null +++ b/app/Models/BusinessOrIndustry.php @@ -0,0 +1,24 @@ +id(); + $table->string('nama_kecamatan'); + $table->string('nama_kelurahan'); + $table->string('nop')->unique(); + $table->string('nama_wajib_pajak'); + $table->text('alamat_wajib_pajak')->nullable(); + $table->text('alamat_objek_pajak'); + $table->decimal('luas_bumi',20,2)->default(0); + $table->decimal('luas_bangunan',20,2)->default(0); + $table->decimal('njop_bumi',20,2)->default(0); + $table->decimal('njop_bangunan',20,2)->default(0); + $table->decimal('ketetapan',20,2)->default(0); + $table->integer('tahun_pajak'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('business_or_industries'); + } +}; diff --git a/database/seeders/UsersRoleMenuSeeder.php b/database/seeders/UsersRoleMenuSeeder.php index 7003cad..0bd7771 100644 --- a/database/seeders/UsersRoleMenuSeeder.php +++ b/database/seeders/UsersRoleMenuSeeder.php @@ -148,7 +148,14 @@ class UsersRoleMenuSeeder extends Seeder "url" => "advertisements.index", "icon" => null, "parent_id" => $data->id, - "sort_order" => 1, + "sort_order" => 2, + ], + [ + "name" => "Usaha atau Industri", + "url" => "business-industries.index", + "icon" => null, + "parent_id" => $data->id, + "sort_order" => 2, ], ]; @@ -165,6 +172,7 @@ class UsersRoleMenuSeeder extends Seeder $setting_dashboard = Menu::where('name', 'Setting Dashboard')->first(); $setting_pbg = Menu::where('name', 'PBG')->first(); $reklame = Menu::where('name', 'Reklame')->first(); + $businessIndustries = Menu::where('name', 'Usaha atau Industri')->first(); // Superadmin gets all menus $superadmin->menus()->sync([ @@ -184,6 +192,7 @@ class UsersRoleMenuSeeder extends Seeder $setting_dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true], $setting_pbg->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true], $reklame->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true], + $businessIndustries->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true], ]); // Admin gets limited menus diff --git a/resources/js/business-industries/create.js b/resources/js/business-industries/create.js new file mode 100644 index 0000000..d6fa977 --- /dev/null +++ b/resources/js/business-industries/create.js @@ -0,0 +1,125 @@ +import { Dropzone } from "dropzone"; +import GlobalConfig from "../global-config"; +Dropzone.autoDiscover = false; + +var previewTemplate, + dropzone, + dropzonePreviewNode = document.querySelector("#dropzone-preview-list"); +console.log(previewTemplate); +console.log(dropzone); +console.log(dropzonePreviewNode); + +const toastNotification = document.getElementById("toastNotification"); +const toast = new bootstrap.Toast(toastNotification); + +(dropzonePreviewNode.id = ""), + dropzonePreviewNode && + ((previewTemplate = dropzonePreviewNode.parentNode.innerHTML), + dropzonePreviewNode.parentNode.removeChild(dropzonePreviewNode), + (dropzone = new Dropzone(".dropzone", { + url: `${GlobalConfig.apiHost}/api/api-business-industries/upload`, + method: "post", + acceptedFiles: ".xls,.xlsx", // Use acceptedFiles for better validation + previewTemplate: previewTemplate, + previewsContainer: "#dropzone-preview", + autoProcessQueue: false, // Disable auto post + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + }, + init: function () { + // Listen for the success event + this.on("success", function (file, response) { + console.log("File successfully uploaded:", file); + console.log("API Response:", response); + + // Show success toast + document.getElementById("toast-message").innerText = + response.message; + toast.show(); + document.getElementById("submit-upload").innerHTML = + "Upload Files"; + // Tunggu sebentar lalu reload halaman + setTimeout(() => { + window.location.href = "/data/business-industries"; + }, 2000); + }); + // Listen for the error event + this.on("error", function (file, errorMessage) { + console.error("Error uploading file:", file); + console.error("Error message:", errorMessage); + // Handle the error response + + // Show error toast + document.getElementById("toast-message").innerText = + errorMessage.message; + toast.show(); + document.getElementById("submit-upload").innerHTML = + "Upload Files"; + }); + }, + }))); + +// Add event listener to control the submission manually +document.querySelector("#submit-upload").addEventListener("click", function () { + console.log("Ini adalah value dropzone", dropzone.files[0]); + const formData = new FormData(); + console.log("Dropzonefiles", dropzone.files); + + this.innerHTML = + 'Loading...'; + + // Pastikan ada file dalam queue sebelum memprosesnya + if (dropzone.files.length > 0) { + formData.append("file", dropzone.files[0]); + console.log("ini adalah form data on submit", ...formData); + dropzone.processQueue(); // Ini akan manual memicu upload + } else { + // Show error toast when no file is selected + document.getElementById("toast-message").innerText = + "Please add a file first."; + toast.show(); + + document.getElementById("submit-upload").innerHTML = "Upload Files"; + } +}); + +// Optional: Listen for the 'addedfile' event to log or control file add behavior +dropzone.on("addedfile", function (file) { + console.log("File ditambahkan:", file); + console.log("Nama File:", file.name); + console.log("Tipe File:", file.type); + console.log("Ukuran File:", (file.size / 1024).toFixed(2) + " KB"); +}); + +dropzone.on("complete", function (file) { + dropzone.removeFile(file); +}); + +// Function to show toast +// function showToast(iconClass, iconColor, message) { +// const toastElement = document.getElementById("toastUploadAdvertisement"); +// const toastBody = toastElement.querySelector(".toast-body"); +// const toastHeader = toastElement.querySelector(".toast-header"); + +// // Remove existing icon (if any) before adding the new one +// const existingIcon = toastHeader.querySelector(".bx"); +// if (existingIcon) { +// toastHeader.querySelector(".auth-logo").removeChild(existingIcon); // Remove the existing icon +// } + +// // Add the new icon to the toast header +// const icon = document.createElement("i"); +// icon.classList.add("bx", iconClass); +// icon.style.fontSize = "25px"; +// icon.style.color = iconColor; +// toastHeader.querySelector(".auth-logo").appendChild(icon); + +// // Set the toast message +// toastBody.textContent = message; + +// // Show the toast +// const toast = new bootstrap.Toast(toastElement); // Inisialisasi Bootstrap Toast +// toast.show(); +// } diff --git a/resources/js/business-industries/index.js b/resources/js/business-industries/index.js new file mode 100644 index 0000000..a88e7a4 --- /dev/null +++ b/resources/js/business-industries/index.js @@ -0,0 +1,260 @@ +import { Grid } from "gridjs/dist/gridjs.umd.js"; +import gridjs from "gridjs/dist/gridjs.umd.js"; +import "gridjs/dist/gridjs.umd.js"; +import GlobalConfig from "../global-config.js"; + +class BusinessIndustries { + constructor() { + this.table = null; // Store Grid.js instance + } + init() { + this.getFetchApiData(); + } + + getFetchApiData() { + let tableContainer = document.getElementById( + "table-business-industries" + ); + + if (this.table) { + // If table exists, update its data instead of recreating + this.table + .updateConfig({ + server: { + url: `${GlobalConfig.apiHost}/api/api-business-industries`, + credentials: "include", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, + then: (data) => + data.data.map((item) => [ + item.id, + item.nama_kecamatan, + item.nama_kelurahan, + item.nop, + item.nama_wajib_pajak, + item.alamat_wajib_pajak, + item.alamat_objek_pajak, + item.luas_bumi, + item.luas_bangunan, + item.njop_bumi, + item.njop_bangunan, + item.ketetapan, + item.tahun_pajak, + item.created_at, + item.id, + ]), + total: (data) => data.total, + }, + }) + .forceRender(); + return; + } + + this.table = new Grid({ + columns: [ + { name: "ID", width: "80px", hidden: false }, + { name: "Nama Kecamatan", width: "200px" }, + { name: "Nama Kelurahan", width: "200px" }, + { name: "NOP", width: "150px" }, + { name: "Nama Wajib Pajak", width: "250px" }, + { name: "Alamat Wajib Pajak", width: "300px" }, + { name: "Alamat Objek Pajak", width: "300px" }, + { name: "Luas Bumi", width: "150px" }, + { name: "Luas Bangunan", width: "150px" }, + { name: "NJOP Bumi", width: "150px" }, + { name: "NJOP Bangunan", width: "150px" }, + { name: "Ketetapan", width: "150px" }, + { name: "Tahun Pajak", width: "120px" }, + { name: "Created", width: "180px" }, + { + name: "Actions", + width: "120px", + formatter: function (cell) { + return gridjs.html(` +
+ + + + +
+ `); + }, + }, + ], + search: { + server: { + url: (prev, keyword) => `${prev}?search=${keyword}`, + }, + }, + pagination: { + limit: 15, + server: { + url: (prev, page) => + `${prev}${prev.includes("?") ? "&" : "?"}page=${ + page + 1 + }`, + }, + }, + sort: true, + server: { + url: `${GlobalConfig.apiHost}/api/api-business-industries`, + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, + then: (data) => + data.data.map((item) => [ + item.id, + item.nama_kecamatan, + item.nama_kelurahan, + item.nop, + item.nama_wajib_pajak, + item.alamat_wajib_pajak, + item.alamat_objek_pajak, + item.luas_bumi, + item.luas_bangunan, + item.njop_bumi, + item.njop_bangunan, + item.ketetapan, + item.tahun_pajak, + item.created_at, + item.id, // ID for Actions column + ]), + total: (data) => data.total, + }, + }).render(tableContainer); + + document.addEventListener("click", this.handleDelete.bind(this)); + } + handleDelete(event) { + if (event.target.classList.contains("btn-delete-business-industries")) { + event.preventDefault(); + const id = event.target.getAttribute("data-id"); + let modalElement = document.getElementById("modalConfirmation"); + let toastMessage = document.getElementById("toast-message"); + + if (!modalElement) { + console.error("Modal element not found!"); + return; + } + + let modal = new bootstrap.Modal(modalElement); + let btnSaveConfirmation = document.getElementById( + "btnSaveConfirmation" + ); + let toastElement = document.getElementById("toastNotification"); + let toast = new bootstrap.Toast(toastElement); + + // Remove previous event listeners to avoid multiple bindings + btnSaveConfirmation.replaceWith( + btnSaveConfirmation.cloneNode(true) + ); + btnSaveConfirmation = document.getElementById( + "btnSaveConfirmation" + ); + + // Set the role ID on the confirm button inside the modal + btnSaveConfirmation.setAttribute("data-business-industries-id", id); + + // Show the modal + modal.show(); + + btnSaveConfirmation.addEventListener("click", async () => { + let deletedId = btnSaveConfirmation.getAttribute( + "data-business-industries-id" + ); + + try { + let response = await fetch( + `${GlobalConfig.apiHost}/api/api-business-industries/${deletedId}`, + { + method: "DELETE", + credentials: "include", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, + } + ); + + if (response.ok) { + let result = await response.json(); + toastMessage.innerText = + result.message || "Deleted successfully!"; + toast.show(); + + // Hide modal + modal.hide(); + + // Refresh Grid.js table + this.refreshDataSettings(); + } else { + let error = await response.json(); + console.error("Delete failed:", error); + toastMessage.innerText = + error.message || "Delete failed!"; + toast.show(); + } + } catch (error) { + console.error("Error deleting item:", error); + toastMessage.innerText = "An error occurred!"; + toast.show(); + } + }); + } + } + + refreshDataSettings() { + if (this.table) { + this.table + .updateConfig({ + server: { + url: `${GlobalConfig.apiHost}/api/api-business-industries`, + credentials: "include", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, + then: (data) => + data.data.map((item) => [ + item.id, + item.nama_kecamatan, + item.nama_kelurahan, + item.nop, + item.nama_wajib_pajak, + item.alamat_wajib_pajak, + item.alamat_objek_pajak, + item.luas_bumi, + item.luas_bangunan, + item.njop_bumi, + item.njop_bangunan, + item.ketetapan, + item.tahun_pajak, + item.created_at, + item.id, // ID for Actions column + ]), + total: (data) => data.total, + }, + }) + .forceRender(); + } + } +} +document.addEventListener("DOMContentLoaded", function (e) { + new BusinessIndustries().init(); +}); diff --git a/resources/js/business-industries/update.js b/resources/js/business-industries/update.js new file mode 100644 index 0000000..5b007ba --- /dev/null +++ b/resources/js/business-industries/update.js @@ -0,0 +1,79 @@ +class UpdateBusinessIndustries { + init() { + this.handleUpdateData(); + } + + handleUpdateData() { + const form = document.getElementById("formUpdateBusinessIndustries"); + const submitButton = document.getElementById( + "btnUpdateBusinessIndustries" + ); + const toastNotification = document.getElementById("toastNotification"); + const toastBody = document.getElementById("toastBody"); // Add an element inside toast to display messages + const spinner = document.getElementById("spinner"); + const toast = new bootstrap.Toast(toastNotification); + + if (!submitButton) { + console.error("Error: Submit button not found!"); + return; + } + + submitButton.addEventListener("click", async function (e) { + e.preventDefault(); + + // Disable button and show spinner + submitButton.disabled = true; + spinner.classList.remove("d-none"); + + // Create FormData object + const formData = new FormData(form); + const formObject = {}; + formData.forEach((value, key) => { + formObject[key] = value; + }); + formData.append("_method", "PUT"); + + try { + let response = await fetch(form.action, { + method: "POST", // Laravel's update route uses PUT, so adjust accordingly + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(formObject), + }); + + let data = await response.json(); + + if (response.ok) { + // Show success toast + document.getElementById("toast-message").innerText = + data.message; + toast.show(); + setTimeout(() => { + window.location.href = "/data/business-industries"; + }, 2000); + } else { + // Show error toast with message from API + document.getElementById("toast-message").innerText = + data.message; + toast.show(); + submitButton.disabled = false; + spinner.classList.add("d-none"); + } + } catch (error) { + // Show error toast for network errors + document.getElementById("toast-message").innerText = + data.message; + toast.show(); + submitButton.disabled = false; + spinner.classList.add("d-none"); + } + }); + } +} +document.addEventListener("DOMContentLoaded", function (e) { + new UpdateBusinessIndustries().init(); +}); diff --git a/resources/js/data-settings/index.js b/resources/js/data-settings/index.js index 39599eb..497b7de 100644 --- a/resources/js/data-settings/index.js +++ b/resources/js/data-settings/index.js @@ -57,7 +57,7 @@ class DataSettings { - diff --git a/resources/js/master/users/create.js b/resources/js/master/users/create.js index a6b26c7..c684479 100644 --- a/resources/js/master/users/create.js +++ b/resources/js/master/users/create.js @@ -44,12 +44,18 @@ document.addEventListener("DOMContentLoaded", function (e) { error.message; toast.show(); console.error("Error:", error); + + submitButton.disabled = false; + spinner.classList.add("d-none"); } } catch (error) { console.error("Request failed:", error); document.getElementById("toast-message").innerText = error.message; toast.show(); + + submitButton.disabled = false; + spinner.classList.add("d-none"); } }); }); diff --git a/resources/views/business-industries/create.blade.php b/resources/views/business-industries/create.blade.php new file mode 100644 index 0000000..522af0d --- /dev/null +++ b/resources/views/business-industries/create.blade.php @@ -0,0 +1,78 @@ +@extends('layouts.vertical', ['subtitle' => 'Business Industries']) + +@section('content') + +@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Business Industries']) + + +
+
+
+
+
Upload Data
+

+ Please upload a file with the extension .xls or .xlsx with a maximum size of 10 MB. +
+ For .xls and .xlsx files, ensure that the data is contained within a single sheet with the following columns: + +

+
+ +
+ +
+ +
+
+
+ +
+
+
+ +

Drop files here or click to upload.

+
+
+ +
    +
  • + +
    +
    +
    +
    + +
    +
    +
    +
    +
      +
    +

    + +
    +
    +
    + +
    +
    +
    +
  • +
+ +
+
+ +
+
+
+
+
+ +@endsection + +@section('scripts') +@vite(['resources/js/business-industries/create.js']) +@endsection \ No newline at end of file diff --git a/resources/views/business-industries/edit.blade.php b/resources/views/business-industries/edit.blade.php new file mode 100644 index 0000000..5facb56 --- /dev/null +++ b/resources/views/business-industries/edit.blade.php @@ -0,0 +1,89 @@ +@extends('layouts.vertical', ['subtitle' => 'Create']) + +@section('content') + +@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) + + +
+
+
+
+
+ @csrf + @method('PUT') +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+
+
+
+ +@endsection + +@section('scripts') +@vite(['resources/js/business-industries/update.js']) +@endsection \ No newline at end of file diff --git a/resources/views/business-industries/index.blade.php b/resources/views/business-industries/index.blade.php new file mode 100644 index 0000000..ababeea --- /dev/null +++ b/resources/views/business-industries/index.blade.php @@ -0,0 +1,31 @@ +@extends('layouts.vertical', ['subtitle' => 'Business Industries']) + +@section('css') +@vite(['node_modules/gridjs/dist/theme/mermaid.min.css']) +@endsection + +@section('content') + +@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Business Industries']) + + + + +
+
+
+
+
+ Create +
+
+
+
+
+
+ +@endsection + +@section('scripts') +@vite(['resources/js/business-industries/index.js']) +@endsection \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index cced880..fbdc03a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,5 +1,6 @@ 'auth:sanctum'], function (){ // roles api Route::apiResource('api-roles', RolesController::class); + + //business industries api + Route::apiResource('api-business-industries', BusinessOrIndustriesController::class); + Route::post('api-business-industries/upload', [BusinessOrIndustriesController::class, 'upload'])->name('business-industries.upload'); }); diff --git a/routes/web.php b/routes/web.php index 75bad12..51104ea 100755 --- a/routes/web.php +++ b/routes/web.php @@ -1,5 +1,6 @@ 'auth'], function(){ // Rute khusus untuk create dan bulk-create Route::get('/advertisements/create', [AdvertisementController::class, 'create'])->name('advertisements.create'); Route::get('/advertisements/bulk-create', [AdvertisementController::class, 'bulkCreate'])->name('advertisements.bulk-create'); + Route::resource('/business-industries',BusinessOrIndustriesController::class); }); }); \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index ccb7157..9c60b13 100755 --- a/vite.config.js +++ b/vite.config.js @@ -71,6 +71,10 @@ export default defineConfig({ "resources/js/data-settings/index.js", "resources/js/data-settings/create.js", "resources/js/data-settings/update.js", + // business-industries + "resources/js/business-industries/create.js", + "resources/js/business-industries/update.js", + "resources/js/business-industries/index.js", ], refresh: true, }),