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 {