From b4b34b503ec8fd4813c09a56d6db9f87b1ab7352 Mon Sep 17 00:00:00 2001 From: arifal Date: Wed, 12 Feb 2025 01:53:40 +0700 Subject: [PATCH] fix loading all pages --- .../Controllers/DataSettingController.php | 17 +- .../Controllers/Master/UsersController.php | 8 +- app/Http/Controllers/MenusController.php | 12 +- app/Http/Controllers/RolesController.php | 5 +- resources/js/data-settings/create.js | 57 ++++++ resources/js/data-settings/index.js | 162 +++++++++++++---- resources/js/data-settings/update.js | 53 ++++++ resources/js/master/users/create.js | 55 ++++++ resources/js/master/users/update.js | 53 ++++++ resources/js/menus/create.js | 55 ++++++ resources/js/menus/index.js | 163 +++++++++++++++--- resources/js/menus/update.js | 53 ++++++ resources/js/roles/index.js | 156 ++++++++++++----- .../views/data-settings/create.blade.php | 24 +-- resources/views/data-settings/edit.blade.php | 24 +-- resources/views/data-settings/index.blade.php | 2 + resources/views/master/users/create.blade.php | 10 +- resources/views/master/users/edit.blade.php | 10 +- resources/views/menus/create.blade.php | 9 +- resources/views/menus/edit.blade.php | 9 +- resources/views/menus/index.blade.php | 2 + vite.config.js | 11 +- 22 files changed, 784 insertions(+), 166 deletions(-) create mode 100644 resources/js/data-settings/create.js create mode 100644 resources/js/data-settings/update.js create mode 100644 resources/js/master/users/create.js create mode 100644 resources/js/master/users/update.js create mode 100644 resources/js/menus/create.js create mode 100644 resources/js/menus/update.js diff --git a/app/Http/Controllers/DataSettingController.php b/app/Http/Controllers/DataSettingController.php index 872f87d..1ed4ab4 100644 --- a/app/Http/Controllers/DataSettingController.php +++ b/app/Http/Controllers/DataSettingController.php @@ -36,12 +36,13 @@ class DataSettingController extends Controller DB::beginTransaction(); DataSetting::create($request->validated()); DB::commit(); - return redirect()->route("data-settings.index")->with("success","Successfully created"); + return response()->json(['message' => 'Successfully created'],201); }catch(Exception $ex){ DB::rollBack(); - return redirect()->back() - ->withInput() - ->with('error', 'Something went wrong while saving data. ' . $ex->getMessage()); + return response()->json([ + 'message' => 'Failed to create data setting', + 'error' => $ex->getMessage() + ], 500); } } @@ -79,12 +80,10 @@ class DataSettingController extends Controller $data = DataSetting::findOrFail($id); $data->update($request->validated()); DB::commit(); - return redirect()->route("data-settings.index")->with("success","Successfully updated"); + return response()->json(['message' => 'Successfully updated'], 200); }catch(Exception $ex){ DB::rollBack(); - return redirect()->back() - ->withInput() - ->with('error', 'Something went wrong while saving data. ' . $ex->getMessage()); + return response()->json(['message' => $ex->getMessage()],500); } } @@ -97,7 +96,7 @@ class DataSettingController extends Controller DB::beginTransaction(); DataSetting::findOrFail($id)->delete(); DB::commit(); - return response()->json(['success' => true, 'message' => 'Item deleted successfully.']); + return response()->json(['success' => true, 'message' => 'Item deleted successfully.'], 200); }catch(Exception $e){ DB::rollBack(); Log::error($e->getMessage()); diff --git a/app/Http/Controllers/Master/UsersController.php b/app/Http/Controllers/Master/UsersController.php index 88d3388..62c0458 100644 --- a/app/Http/Controllers/Master/UsersController.php +++ b/app/Http/Controllers/Master/UsersController.php @@ -53,10 +53,10 @@ class UsersController extends Controller $user->roles()->attach($request->role_id); DB::commit(); - return redirect()->route('users.index')->with('success','Successfully registered'); + return response()->json(['message' => 'Successfully created'],201); }catch(\Exception $e){ DB::rollBack(); - return redirect()->back()->with("error", $e->getMessage()); + return response()->json(['message' => $e->getMessage()],500); }; } public function show($id){ @@ -90,10 +90,10 @@ class UsersController extends Controller $user->update($updateData); $user->roles()->sync([$request->role_id]); DB::commit(); - return redirect()->route('users.index')->with('success', 'Successfully'); + return response()->json(['message' => 'Successfully updated'],200); }catch(\Exception $e){ DB::rollBack(); - return redirect()->back()->with("error", $e->getMessage()); + return response()->json(['message' => $e->getMessage()],500); } } public function destroy($id){ diff --git a/app/Http/Controllers/MenusController.php b/app/Http/Controllers/MenusController.php index 53d59c8..8f4415d 100644 --- a/app/Http/Controllers/MenusController.php +++ b/app/Http/Controllers/MenusController.php @@ -47,13 +47,11 @@ class MenusController extends Controller 'sort_order' => $request->sort_order, ]); DB::commit(); - return redirect()->route('menus.index')->with('success','Success created menu'); + return response()->json(['message' => 'Successfully created'], 200); }catch(\Exception $e){ DB::rollBack(); \Log::error('Menu creation failed: ' . $e->getMessage()); // Log the error for debugging - return redirect()->back() - ->withInput() - ->withErrors('Something went wrong! Please try again.'); + return response()->json(['message'=> $e->getMessage()],500); } } @@ -95,13 +93,11 @@ class MenusController extends Controller DB::beginTransaction(); $menu->update($validateData); DB::commit(); - return redirect()->route('menus.index')->with('success','Successfully updated'); + return response()->json(['message' => 'Successfully updated'], 200); }catch(\Exception $e){ DB::rollBack(); \Log::error('Menu update failed: '. $e->getMessage()); // Log the error for debugging - return redirect()->back() - ->withInput() - ->withErrors('Something went wrong! Please try again.'); + return response()->json(['message' => $e->getMessage()],500); } } diff --git a/app/Http/Controllers/RolesController.php b/app/Http/Controllers/RolesController.php index 4db0026..449b5f6 100644 --- a/app/Http/Controllers/RolesController.php +++ b/app/Http/Controllers/RolesController.php @@ -98,12 +98,11 @@ class RolesController extends Controller try{ DB::beginTransaction(); $deleted = Role::findOrFail($id)->delete(); - info("deleted". $deleted); DB::commit(); - return response()->json(array('success' => true, "message" => "Successfully deleted")); + return response()->json(['success' => true, "message" => "Successfully deleted"]); }catch(\Exception $e){ DB::rollBack(); - return response()->json(array('success' => false, "message" => $e->getMessage())); + return response()->json(['success' => false, "message" => $e->getMessage()]); } } diff --git a/resources/js/data-settings/create.js b/resources/js/data-settings/create.js new file mode 100644 index 0000000..f0f604f --- /dev/null +++ b/resources/js/data-settings/create.js @@ -0,0 +1,57 @@ +document.addEventListener("DOMContentLoaded", function (e) { + const toastNotification = document.getElementById("toastNotification"); + const toast = new bootstrap.Toast(toastNotification); + document + .getElementById("btnCreateDataSettings") + .addEventListener("click", async function () { + let submitButton = this; + let spinner = document.getElementById("spinner"); + let form = document.getElementById("formDataSettings"); + + if (!form) { + console.error("Form element not found!"); + return; + } + // Get form data + let formData = new FormData(form); + + // Disable button and show spinner + submitButton.disabled = true; + spinner.classList.remove("d-none"); + + try { + let response = await fetch(form.action, { + method: "POST", + credentials: "include", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + "Content-Type": "application/json", + }, + body: formData, + }); + + if (response.ok) { + let result = await response.json(); + document.getElementById("toast-message").innerText = + result.message; + toast.show(); + setTimeout(() => { + window.location.href = "/data-settings"; + }, 2000); + } else { + let error = await response.json(); + document.getElementById("toast-message").innerText = + error.message; + toast.show(); + console.error("Error:", error); + } + } catch (error) { + console.error("Request failed:", error); + document.getElementById("toast-message").innerText = + error.message; + toast.show(); + } + }); +}); diff --git a/resources/js/data-settings/index.js b/resources/js/data-settings/index.js index 2e9f2a4..0f3944e 100644 --- a/resources/js/data-settings/index.js +++ b/resources/js/data-settings/index.js @@ -4,12 +4,45 @@ import "gridjs/dist/gridjs.umd.js"; import GlobalConfig from "../global-config.js"; class DataSettings { + constructor() { + this.table = null; // Store Grid.js instance + } init() { this.getFetchApiData(); } getFetchApiData() { - const table = new Grid({ + let tableContainer = document.getElementById("table-data-settings"); + + if (this.table) { + // If table exists, update its data instead of recreating + this.table + .updateConfig({ + server: { + url: `${GlobalConfig.apiHost}/api/api-data-settings`, + 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.key, + item.value, + item.created_at, + item.id, + ]), + total: (data) => data.meta.total, + }, + }) + .forceRender(); + return; + } + + this.table = new Grid({ columns: [ "ID", "Key", @@ -62,43 +95,114 @@ class DataSettings { ]), total: (data) => data.meta.total, }, - }); - table.render(document.getElementById("table-data-settings")); + }).render(tableContainer); - document.addEventListener("click", this.handleDelete); + document.addEventListener("click", this.handleDelete.bind(this)); } handleDelete(event) { if (event.target.classList.contains("btn-delete-data-settings")) { event.preventDefault(); const id = event.target.getAttribute("data-id"); + let modalElement = document.getElementById("modalConfirmation"); + let toastMessage = document.getElementById("toast-message"); - if (confirm("Are you sure you want to delete this item?")) { - fetch(`/data-settings/${id}`, { - method: "DELETE", - headers: { - "X-CSRF-TOKEN": document - .querySelector('meta[name="csrf-token"]') - .getAttribute("content"), - "Content-Type": "application/json", + 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-settings-id", id); + + // Show the modal + modal.show(); + + btnSaveConfirmation.addEventListener("click", async () => { + let dataSettingId = + btnSaveConfirmation.getAttribute("data-settings-id"); + + try { + let response = await fetch( + `/data-settings/${dataSettingId}`, + { + method: "DELETE", + credentials: "include", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-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-data-settings`, + 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.key, + item.value, + item.created_at, + item.id, + ]), + total: (data) => data.meta.total, }, }) - .then((response) => { - if (response.ok) { - alert("Item deleted successfully!"); - window.location.reload(); - } else { - return response.json().then((error) => { - throw new Error( - error.message || "Failed to delete item." - ); - }); - } - }) - .catch((error) => { - console.error("Error deleting item:", error); - alert("Something went wrong. Please try again."); - }); - } + .forceRender(); } } } diff --git a/resources/js/data-settings/update.js b/resources/js/data-settings/update.js new file mode 100644 index 0000000..792bd63 --- /dev/null +++ b/resources/js/data-settings/update.js @@ -0,0 +1,53 @@ +document.addEventListener("DOMContentLoaded", function (e) { + let form = document.getElementById("formUpdateDataSettings"); + let submitButton = document.getElementById("btnUpdateDataSettings"); + let spinner = document.getElementById("spinner"); + let toastMessage = document.getElementById("toast-message"); + let toast = new bootstrap.Toast( + document.getElementById("toastNotification") + ); + submitButton.addEventListener("click", async function () { + let submitButton = this; + + if (!form) { + console.error("Form element not found!"); + return; + } + // Get form data + let formData = new FormData(form); + + // Disable button and show spinner + submitButton.disabled = true; + spinner.classList.remove("d-none"); + + try { + let response = await fetch(form.action, { + method: "POST", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + }, + body: formData, + }); + + if (response.ok) { + let result = await response.json(); + toastMessage.innerText = result.message; + toast.show(); + setTimeout(() => { + window.location.href = "/data-settings"; + }, 2000); + } else { + let error = await response.json(); + toastMessage.innerText = error.message; + toast.show(); + console.error("Error:", error); + } + } catch (error) { + console.error("Request failed:", error); + toastMessage.innerText = error.message; + toast.show(); + } + }); +}); diff --git a/resources/js/master/users/create.js b/resources/js/master/users/create.js new file mode 100644 index 0000000..a6b26c7 --- /dev/null +++ b/resources/js/master/users/create.js @@ -0,0 +1,55 @@ +document.addEventListener("DOMContentLoaded", function (e) { + const toastNotification = document.getElementById("toastNotification"); + const toast = new bootstrap.Toast(toastNotification); + document + .getElementById("btnCreateUsers") + .addEventListener("click", async function () { + let submitButton = this; + let spinner = document.getElementById("spinner"); + let form = document.getElementById("formCreateUsers"); + + if (!form) { + console.error("Form element not found!"); + return; + } + // Get form data + let formData = new FormData(form); + + // Disable button and show spinner + submitButton.disabled = true; + spinner.classList.remove("d-none"); + + try { + let response = await fetch(form.action, { + method: "POST", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + }, + body: formData, + }); + + if (response.ok) { + let result = await response.json(); + document.getElementById("toast-message").innerText = + result.message; + toast.show(); + setTimeout(() => { + window.location.href = "/master/users"; + }, 2000); + } else { + let error = await response.json(); + document.getElementById("toast-message").innerText = + error.message; + toast.show(); + console.error("Error:", error); + } + } catch (error) { + console.error("Request failed:", error); + document.getElementById("toast-message").innerText = + error.message; + toast.show(); + } + }); +}); diff --git a/resources/js/master/users/update.js b/resources/js/master/users/update.js new file mode 100644 index 0000000..d4e04a5 --- /dev/null +++ b/resources/js/master/users/update.js @@ -0,0 +1,53 @@ +document.addEventListener("DOMContentLoaded", function (e) { + let form = document.getElementById("formUpdateUsers"); + let submitButton = document.getElementById("btnUpdateUsers"); + let spinner = document.getElementById("spinner"); + let toastMessage = document.getElementById("toast-message"); + let toast = new bootstrap.Toast( + document.getElementById("toastNotification") + ); + submitButton.addEventListener("click", async function () { + let submitButton = this; + + if (!form) { + console.error("Form element not found!"); + return; + } + // Get form data + let formData = new FormData(form); + + // Disable button and show spinner + submitButton.disabled = true; + spinner.classList.remove("d-none"); + + try { + let response = await fetch(form.action, { + method: "POST", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + }, + body: formData, + }); + + if (response.ok) { + let result = await response.json(); + toastMessage.innerText = result.message; + toast.show(); + setTimeout(() => { + window.location.href = "/master/users"; + }, 2000); + } else { + let error = await response.json(); + toastMessage.innerText = error.message; + toast.show(); + console.error("Error:", error); + } + } catch (error) { + console.error("Request failed:", error); + toastMessage.innerText = error.message; + toast.show(); + } + }); +}); diff --git a/resources/js/menus/create.js b/resources/js/menus/create.js new file mode 100644 index 0000000..8ab2a1d --- /dev/null +++ b/resources/js/menus/create.js @@ -0,0 +1,55 @@ +document.addEventListener("DOMContentLoaded", function (e) { + const toastNotification = document.getElementById("toastNotification"); + const toast = new bootstrap.Toast(toastNotification); + document + .getElementById("btnCreateMenus") + .addEventListener("click", async function () { + let submitButton = this; + let spinner = document.getElementById("spinner"); + let form = document.getElementById("formCreateMenus"); + + if (!form) { + console.error("Form element not found!"); + return; + } + // Get form data + let formData = new FormData(form); + + // Disable button and show spinner + submitButton.disabled = true; + spinner.classList.remove("d-none"); + + try { + let response = await fetch(form.action, { + method: "POST", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + }, + body: formData, + }); + + if (response.ok) { + let result = await response.json(); + document.getElementById("toast-message").innerText = + result.message; + toast.show(); + setTimeout(() => { + window.location.href = "/menus"; + }, 2000); + } else { + let error = await response.json(); + document.getElementById("toast-message").innerText = + error.message; + toast.show(); + console.error("Error:", error); + } + } catch (error) { + console.error("Request failed:", error); + document.getElementById("toast-message").innerText = + error.message; + toast.show(); + } + }); +}); diff --git a/resources/js/menus/index.js b/resources/js/menus/index.js index ec6ca2b..67cb0a2 100644 --- a/resources/js/menus/index.js +++ b/resources/js/menus/index.js @@ -4,12 +4,47 @@ import "gridjs/dist/gridjs.umd.js"; import GlobalConfig from "../global-config"; class Menus { + constructor() { + this.table = null; + } init() { this.initTableMenus(); } initTableMenus() { - new Grid({ + let tableContainer = document.getElementById("table-menus"); + + if (this.table) { + // If table exists, update its data instead of recreating + this.table + .updateConfig({ + server: { + url: `${GlobalConfig.apiHost}/api/api-menus`, + 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.name, + item.url, + item.icon, + item.parent_id, + item.sort_order, + item.id, + ]), + total: (data) => data.total, + }, + }) + .forceRender(); + return; + } + + this.table = new Grid({ columns: [ "ID", "Name", @@ -63,43 +98,115 @@ class Menus { ]), total: (data) => data.total, }, - }).render(document.getElementById("table-menus")); + }).render(tableContainer); - document.addEventListener("click", this.handleDelete); + document.addEventListener("click", this.handleDelete.bind(this)); } handleDelete(event) { if (event.target.classList.contains("btn-delete-menu")) { event.preventDefault(); const id = event.target.getAttribute("data-id"); + let modalElement = document.getElementById("modalConfirmation"); + let toastMessage = document.getElementById("toast-message"); - if (confirm("Are you sure you want to delete this item?")) { - fetch(`/menus/${id}`, { - method: "DELETE", - headers: { - "X-CSRF-TOKEN": document - .querySelector('meta[name="csrf-token"]') - .getAttribute("content"), - "Content-Type": "application/json", + 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-menu-id", id); + + // Show the modal + modal.show(); + + btnSaveConfirmation.addEventListener("click", async () => { + let menuId = btnSaveConfirmation.getAttribute("data-menu-id"); + + try { + let response = await fetch(`/menus/${menuId}`, { + method: "DELETE", + credentials: "include", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-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.refreshTableMenus(); + } 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(); + } + }); + } + } + + refreshTableMenus() { + if (this.table) { + this.table + .updateConfig({ + server: { + url: `${GlobalConfig.apiHost}/api/api-menus`, + 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.name, + item.url, + item.icon, + item.parent_id, + item.sort_order, + item.id, + ]), + total: (data) => data.total, }, }) - .then((response) => { - if (response.ok) { - alert("Item deleted successfully!"); - window.location.reload(); - } else { - return response.json().then((error) => { - throw new Error( - error.message || "Failed to delete item." - ); - }); - } - }) - .catch((error) => { - console.error("Error deleting item:", error); - alert("Something went wrong. Please try again."); - }); - } + .forceRender(); + } else { + this.initTableMenus(); // If no table exists, reinitialize it } } } diff --git a/resources/js/menus/update.js b/resources/js/menus/update.js new file mode 100644 index 0000000..a5024ee --- /dev/null +++ b/resources/js/menus/update.js @@ -0,0 +1,53 @@ +document.addEventListener("DOMContentLoaded", function (e) { + let form = document.getElementById("formUpdateMenus"); + let submitButton = document.getElementById("btnUpdateMenus"); + let spinner = document.getElementById("spinner"); + let toastMessage = document.getElementById("toast-message"); + let toast = new bootstrap.Toast( + document.getElementById("toastNotification") + ); + submitButton.addEventListener("click", async function () { + let submitButton = this; + + if (!form) { + console.error("Form element not found!"); + return; + } + // Get form data + let formData = new FormData(form); + + // Disable button and show spinner + submitButton.disabled = true; + spinner.classList.remove("d-none"); + + try { + let response = await fetch(form.action, { + method: "POST", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + }, + body: formData, + }); + + if (response.ok) { + let result = await response.json(); + toastMessage.innerText = result.message; + toast.show(); + setTimeout(() => { + window.location.href = "/menus"; + }, 2000); + } else { + let error = await response.json(); + toastMessage.innerText = error.message; + toast.show(); + console.error("Error:", error); + } + } catch (error) { + console.error("Request failed:", error); + toastMessage.innerText = error.message; + toast.show(); + } + }); +}); diff --git a/resources/js/roles/index.js b/resources/js/roles/index.js index ed5f4d2..63c28f6 100644 --- a/resources/js/roles/index.js +++ b/resources/js/roles/index.js @@ -4,12 +4,46 @@ import "gridjs/dist/gridjs.umd.js"; import GlobalConfig from "../global-config"; class Roles { + constructor() { + this.table = null; // Store Grid.js instance + } + init() { this.initTableRoles(); } initTableRoles() { - new Grid({ + let tableContainer = document.getElementById("table-roles"); + + // If table instance already exists, update it instead of re-creating + if (this.table) { + this.table + .updateConfig({ + server: { + url: `${GlobalConfig.apiHost}/api/api-roles`, + 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.name, + item.description, + item.id, + ]), + total: (data) => data.total, + }, + }) + .forceRender(); + return; + } + + // Create a new Grid.js instance only if it doesn't exist + this.table = new gridjs.Grid({ columns: [ "ID", "Name", @@ -21,8 +55,8 @@ class Roles {
Update Role Menu - -
+ +
`), }, ], @@ -59,9 +93,9 @@ class Roles { ]), total: (data) => data.total, }, - }).render(document.getElementById("table-roles")); + }).render(tableContainer); - document.addEventListener("click", this.handleDelete); + document.addEventListener("click", this.handleDelete.bind(this)); } handleDelete(event) { @@ -70,6 +104,7 @@ class Roles { 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!"); @@ -77,51 +112,94 @@ class Roles { } let modal = new bootstrap.Modal(modalElement); - - // Set the role ID on the confirm button inside the modal let btnSaveConfirmation = document.getElementById( "btnSaveConfirmation" ); - btnSaveConfirmation.setAttribute("data-role-id", id); - - let toastElement = document.getElementById("toastNotificationApi"); + 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-role-id", id); + // Show the modal modal.show(); - // Prevent multiple event listeners - btnSaveConfirmation.onclick = function () { - let roleId = this.getAttribute("data-role-id"); - console.log("Deleted ID:", roleId); + btnSaveConfirmation.addEventListener("click", async () => { + let roleId = btnSaveConfirmation.getAttribute("data-role-id"); - fetch(`/roles/${roleId}`, { - method: "DELETE", - credentials: "include", - headers: { - "X-CSRF-TOKEN": document - .querySelector('meta[name="csrf-token"]') - .getAttribute("content"), - "Content-Type": "application/json", + try { + let response = await fetch(`/roles/${roleId}`, { + method: "DELETE", + credentials: "include", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-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.refreshRolesTable(); + } 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(); + } + }); + } + } + + refreshRolesTable() { + if (this.table) { + this.table + .updateConfig({ + server: { + url: `${GlobalConfig.apiHost}/api/api-roles`, + 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.name, + item.description, + item.id, + ]), + total: (data) => data.total, }, }) - .then((response) => { - if (response.ok) { - modal.hide(); - toast.show(); - setTimeout(() => window.location.reload(), 1500); - } else { - return response.json().then((error) => { - console.error("Delete failed:", error); - toast.show(); - }); - } - }) - .catch((error) => { - console.error("Error deleting item:", error); - toast.show(); - }); - }; + .forceRender(); + } else { + this.initTableRoles(); // If the table is null, reinitialize } } } diff --git a/resources/views/data-settings/create.blade.php b/resources/views/data-settings/create.blade.php index e6d22da..976eeb5 100644 --- a/resources/views/data-settings/create.blade.php +++ b/resources/views/data-settings/create.blade.php @@ -4,26 +4,12 @@ @include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) +
- @if (session('error')) -
- {{ session('error') }} -
- @endif - - @if ($errors->any()) -
-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif
-
+ @csrf
@@ -37,7 +23,10 @@
- +
@@ -47,4 +36,5 @@ @endsection @section('scripts') +@vite(['resources/js/data-settings/create.js']) @endsection \ No newline at end of file diff --git a/resources/views/data-settings/edit.blade.php b/resources/views/data-settings/edit.blade.php index 58a8c42..c10b56c 100644 --- a/resources/views/data-settings/edit.blade.php +++ b/resources/views/data-settings/edit.blade.php @@ -4,26 +4,12 @@ @include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) +
- @if (session('error')) -
- {{ session('error') }} -
- @endif - - @if ($errors->any()) -
-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif
-
+ @csrf @method('PUT')
@@ -38,7 +24,10 @@
- +
@@ -48,4 +37,5 @@ @endsection @section('scripts') +@vite(['resources/js/data-settings/update.js']) @endsection \ No newline at end of file diff --git a/resources/views/data-settings/index.blade.php b/resources/views/data-settings/index.blade.php index 202aa77..d99b2b8 100644 --- a/resources/views/data-settings/index.blade.php +++ b/resources/views/data-settings/index.blade.php @@ -8,6 +8,8 @@ @include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) + +
diff --git a/resources/views/master/users/create.blade.php b/resources/views/master/users/create.blade.php index ef3f6ac..b8f7af6 100644 --- a/resources/views/master/users/create.blade.php +++ b/resources/views/master/users/create.blade.php @@ -4,11 +4,12 @@ @include('layouts.partials/page-title', ['title' => 'Users', 'subtitle' => 'Create']) +
-
+ @csrf
@@ -54,8 +55,10 @@ @endforeach
- - +
@@ -65,4 +68,5 @@ @endsection @section('scripts') +@vite(['resources/js/master/users/create.js']) @endsection \ No newline at end of file diff --git a/resources/views/master/users/edit.blade.php b/resources/views/master/users/edit.blade.php index 53350d7..ac0becd 100644 --- a/resources/views/master/users/edit.blade.php +++ b/resources/views/master/users/edit.blade.php @@ -4,11 +4,12 @@ @include('layouts.partials/page-title', ['title' => 'Users', 'subtitle' => 'Create']) +
-
+ @csrf @method("put")
@@ -47,8 +48,10 @@ @endforeach
- - +
@@ -58,4 +61,5 @@ @endsection @section('scripts') +@vite(['resources/js/master/users/update.js']) @endsection \ No newline at end of file diff --git a/resources/views/menus/create.blade.php b/resources/views/menus/create.blade.php index 8666454..822c7f3 100644 --- a/resources/views/menus/create.blade.php +++ b/resources/views/menus/create.blade.php @@ -8,11 +8,12 @@ @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu']) +
-
+ @csrf
@@ -43,7 +44,10 @@
- +
@@ -53,4 +57,5 @@ @endsection @section('scripts') +@vite(['resources/js/menus/create.js']) @endsection \ No newline at end of file diff --git a/resources/views/menus/edit.blade.php b/resources/views/menus/edit.blade.php index 6be23d6..e4628b0 100644 --- a/resources/views/menus/edit.blade.php +++ b/resources/views/menus/edit.blade.php @@ -8,11 +8,12 @@ @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu']) +
-
id)}}" method="post"> + id)}}" method="post"> @csrf @method("put")
@@ -44,7 +45,10 @@
- +
@@ -54,4 +58,5 @@ @endsection @section('scripts') +@vite(['resources/js/menus/update.js']) @endsection \ No newline at end of file diff --git a/resources/views/menus/index.blade.php b/resources/views/menus/index.blade.php index 06294b5..ce9eca0 100644 --- a/resources/views/menus/index.blade.php +++ b/resources/views/menus/index.blade.php @@ -8,6 +8,8 @@ @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu']) + +
diff --git a/vite.config.js b/vite.config.js index 154488a..7a329eb 100755 --- a/vite.config.js +++ b/vite.config.js @@ -46,17 +46,24 @@ export default defineConfig({ //js-additional "resources/js/dashboards/bigdata.js", - "resources/js/master/users/users.js", "resources/js/settings/syncronize/syncronize.js", "resources/js/data-settings/index.js", "resources/js/pbg-task/index.js", "resources/js/settings/general/general-settings.js", "resources/js/tables/common-table.js", - "resources/js/menus/index.js", + // roles "resources/js/roles/index.js", "resources/js/roles/create.js", "resources/js/roles/update.js", "resources/roles/role_menu.js", + // users + "resources/js/master/users/users.js", + "resources/js/master/users/create.js", + "resources/js/master/users/update.js", + // menus + "resources/js/menus/index.js", + "resources/js/menus/create.js", + "resources/js/menus/update.js", ], refresh: true, }),