add business industry crud

This commit is contained in:
arifal
2025-02-17 18:40:00 +07:00
parent 154b7f40df
commit beac71d182
21 changed files with 1088 additions and 3 deletions

View File

@@ -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 =
'<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>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();
// }

View File

@@ -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(`
<div class="d-flex justify-content-center gap-2">
<a href="/data/business-industries/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i>
</a>
<button class="btn btn-sm btn-red d-inline-flex align-items-center justify-content-center btn-delete-business-industries" data-id="${cell}">
<i class='bx bxs-trash'></i>
</button>
</div>
`);
},
},
],
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();
});

View File

@@ -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();
});

View File

@@ -57,7 +57,7 @@ class DataSettings {
<a href="/data-settings/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i>
</a>
<button class="btn btn-sm btn-red d-inline-flex align-items-center justify-content-centerbtn-delete-data-settings" data-id="${cell}">
<button class="btn btn-sm btn-red d-inline-flex align-items-center justify-content-center btn-delete-data-settings" data-id="${cell}">
<i class='bx bxs-trash' ></i>
</button>
</div>

View File

@@ -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");
}
});
});

View File

@@ -0,0 +1,78 @@
@extends('layouts.vertical', ['subtitle' => 'Business Industries'])
@section('content')
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Business Industries'])
<x-toast-notification />
<div class="row">
<div class="col-xl-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Upload Data</h5>
<p class="card-subtitle">
Please upload a file with the extension <strong>.xls or .xlsx</strong> with a maximum size of <strong>10 MB</strong>.
<br>
For <strong>.xls</strong> and <strong>.xlsx</strong> files, ensure that the data is contained within a <strong>single sheet</strong> with the following columns:
<!-- <strong>No, Nama Wajib Pajak, NPWPD, Jenis Reklame, Isi Reklame, Alamat Wajib Pajak, Lokasi Reklame, Desa,
Kecamatan, Panajang, Lebar, Sudut Pandang, Muka, Luas, Sudut, Kontak.</strong> -->
</p>
</div>
<div class="card-body">
<div class="mb-3">
<div class="dropzone">
<form enctype="multipart/form-data">
<div class="fallback">
<input id="file-dropzone"type="file" name="file" multiple/>
</div>
</form>
<div class="dz-message needsclick">
<i class="h1 bx bx-cloud-upload"></i>
<h3>Drop files here or click to upload.</h3>
</div>
</div>
<ul class="list-unstyled mb-0" id="dropzone-preview">
<li class="mt-2" id="dropzone-preview-list">
<!-- This is used as the file preview template -->
<div class="border rounded">
<div class="d-flex align-items-center p-2">
<div class="flex-shrink-0 me-3">
<div class="avatar-sm bg-light rounded">
<img data-dz-thumbnail class="img-fluid rounded d-block" src="#"
alt="" />
</div>
</div>
<div class="flex-grow-1">
<div class="pt-1">
<h5 class="fs-14 mb-1" data-dz-name>&nbsp;
</h5>
<p class="fs-13 text-muted mb-0" data-dz-size></p>
<strong class="error text-danger" data-dz-errormessage></strong>
</div>
</div>
<div class="flex-shrink-0 ms-3">
<button data-dz-remove class="btn btn-sm btn-danger">Delete</button>
</div>
</div>
</div>
</li>
</ul>
<!-- end dropzon-preview -->
</div>
<div class="d-flex justify-content-end">
<button id="submit-upload" class="btn btn-primary">Upload Files</button>
</div>
</div> <!-- end card body -->
</div> <!-- end card -->
</div> <!-- end col -->
</div> <!-- end row -->
@endsection
@section('scripts')
@vite(['resources/js/business-industries/create.js'])
@endsection

View File

@@ -0,0 +1,89 @@
@extends('layouts.vertical', ['subtitle' => 'Create'])
@section('content')
@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard'])
<x-toast-notification />
<div class="row d-flex justify-content-center">
<div class="col-lg-6">
<div class="card">
<div class="card-body">
<form id="formUpdateBusinessIndustries" action="{{ route('api-business-industries.update', $data->id) }}" method="POST">
@csrf
@method('PUT')
<div class="mb-3">
<label for="nama_kecamatan" class="form-label">Nama Kecamatan</label>
<input type="text" id="nama_kecamatan" class="form-control" name="nama_kecamatan" value="{{ $data->nama_kecamatan }}">
</div>
<div class="mb-3">
<label for="nama_kelurahan" class="form-label">Nama Kelurahan</label>
<input type="text" id="nama_kelurahan" class="form-control" name="nama_kelurahan" value="{{ $data->nama_kelurahan }}">
</div>
<div class="mb-3">
<label for="nop" class="form-label">NOP</label>
<input type="text" id="nop" class="form-control" name="nop" value="{{ $data->nop }}">
</div>
<div class="mb-3">
<label for="nama_wajib_pajak" class="form-label">Nama Wajib Pajak</label>
<input type="text" id="nama_wajib_pajak" class="form-control" name="nama_wajib_pajak" value="{{ $data->nama_wajib_pajak }}">
</div>
<div class="mb-3">
<label for="alamat_wajib_pajak" class="form-label">Alamat Wajib Pajak</label>
<input type="text" id="alamat_wajib_pajak" class="form-control" name="alamat_wajib_pajak" value="{{ $data->alamat_wajib_pajak }}">
</div>
<div class="mb-3">
<label for="alamat_objek_pajak" class="form-label">Alamat Objek Pajak</label>
<input type="text" id="alamat_objek_pajak" class="form-control" name="alamat_objek_pajak" value="{{ $data->alamat_objek_pajak }}">
</div>
<div class="mb-3">
<label for="luas_bumi" class="form-label">Luas Bumi</label>
<input type="number" id="luas_bumi" class="form-control" name="luas_bumi" value="{{ $data->luas_bumi }}">
</div>
<div class="mb-3">
<label for="luas_bangunan" class="form-label">Luas Bangunan</label>
<input type="number" id="luas_bangunan" class="form-control" name="luas_bangunan" value="{{ $data->luas_bangunan }}">
</div>
<div class="mb-3">
<label for="njop_bumi" class="form-label">NJOP Bumi</label>
<input type="number" id="njop_bumi" class="form-control" name="njop_bumi" value="{{ $data->njop_bumi }}">
</div>
<div class="mb-3">
<label for="njop_bangunan" class="form-label">NJOP Bangunan</label>
<input type="number" id="njop_bangunan" class="form-control" name="njop_bangunan" value="{{ $data->njop_bangunan }}">
</div>
<div class="mb-3">
<label for="ketetapan" class="form-label">Ketetapan</label>
<input type="text" id="ketetapan" class="form-control" name="ketetapan" value="{{ $data->ketetapan }}">
</div>
<div class="mb-3">
<label for="tahun_pajak" class="form-label">Tahun Pajak</label>
<input type="number" id="tahun_pajak" class="form-control" name="tahun_pajak" value="{{ $data->tahun_pajak }}">
</div>
<button class="btn btn-primary me-1" type="button" id="btnUpdateBusinessIndustries">
<span id="spinner" class="spinner-border spinner-border-sm me-1 d-none" role="status" aria-hidden="true"></span>
Update
</button>
</form>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/business-industries/update.js'])
@endsection

View File

@@ -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'])
<x-toast-notification />
<x-modal-confirmation buttonText="Delete" confirmationMessage="Are you sure you want to delete this?" />
<div class="row">
<div class="col-12">
<div class="card w-100">
<div class="card-body">
<div class="d-flex flex-wrap justify-content-end align-items-center mb-2">
<a href="{{ route('business-industries.create')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a>
</div>
<div id="table-business-industries"></div>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/business-industries/index.js'])
@endsection