fix add params filter date on grid js, export excel and pdf payment recaps

This commit is contained in:
arifal
2025-03-20 20:12:42 +07:00
parent eadfddb3a4
commit 088f173fec
6 changed files with 400 additions and 55 deletions

View File

@@ -11,8 +11,15 @@ class PaymentRecaps {
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
this.startDate = undefined;
this.endDate = undefined;
}
init() {
this.initTablePaymentRecaps();
this.initFilterDatepicker();
this.handleFilterBtn();
this.handleExportPDF();
this.handleExportToExcel();
}
initFilterDatepicker() {
new InitDatePicker(
@@ -20,8 +27,13 @@ class PaymentRecaps {
this.handleChangeFilterDate.bind(this)
).init();
}
handleChangeFilterDate(strDate) {
console.log("filter date : ", strDate);
handleChangeFilterDate(filterDate) {
this.startDate = moment(filterDate, "YYYY-MM-DD")
.startOf("day")
.format("YYYY-MM-DD");
this.endDate = moment(filterDate, "YYYY-MM-DD")
.endOf("day")
.format("YYYY-MM-DD");
}
formatCategory(category) {
const categoryMap = {
@@ -41,64 +53,208 @@ class PaymentRecaps {
initTablePaymentRecaps() {
let tableContainer = document.getElementById("table-payment-recaps");
this.table = new Grid({
columns: [
{ name: "Kategori", data: (row) => row[0] },
{ name: "Nominal", data: (row) => row[1] },
{
name: "Created",
data: (row) => row[2],
attributes: { style: "width: 200px; white-space: nowrap;" },
},
],
pagination: {
limit: 10,
server: {
url: (prev, page) =>
`${prev}${prev.includes("?") ? "&" : "?"}page=${
page + 1
}`,
},
},
sort: true,
server: {
url: `${GlobalConfig.apiHost}/api/payment-recaps`,
// Fetch data from the server
fetch(
`${GlobalConfig.apiHost}/api/payment-recaps?start_date=${
this.startDate || ""
}&end_date=${this.endDate || ""}`,
{
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (response) => {
console.log("API Response:", response); // Debugging
}
)
.then((response) => response.json())
.then((data) => {
if (!data || !Array.isArray(data.data)) {
console.error("Error: Data is not an array", data);
return;
}
if (!response.data || !Array.isArray(response.data)) {
console.error(
"Error: Data is not an array",
response.data
);
return [];
}
let formattedData = data.data.map((item) => [
this.formatCategory(item.category ?? "Unknown"),
addThousandSeparators(Number(item.nominal).toString() || 0),
moment(item.created_at).isValid()
? moment(item.created_at).format("YYYY-MM-DD H:mm:ss")
: "-",
]);
return response.data.map((item) => [
this.formatCategory(item.category ?? "Unknown"), // Ensure category is not null
addThousandSeparators(
Number(item.nominal).toString() || 0
), // Ensure nominal is a valid number
moment(item.created_at).isValid()
? moment(item.created_at).format(
"YYYY-MM-DD H:mm:ss"
)
: "-", // Handle invalid dates
]);
},
total: (response) => response.pagination?.total || 0,
},
width: "auto",
fixedHeader: true,
}).render(tableContainer);
// 🔥 If the table already exists, update it instead of re-creating
if (this.table) {
this.table
.updateConfig({
data: formattedData.length > 0 ? formattedData : [],
})
.forceRender();
} else {
// 🔹 First-time initialization
this.table = new Grid({
columns: [
{ name: "Kategori", data: (row) => row[0] },
{ name: "Nominal", data: (row) => row[1] },
{
name: "Created",
data: (row) => row[2],
attributes: {
style: "width: 200px; white-space: nowrap;",
},
},
],
pagination: {
limit: 50,
},
sort: true,
data: formattedData.length > 0 ? formattedData : [],
width: "auto",
fixedHeader: true,
}).render(tableContainer);
}
})
.catch((error) => console.error("Error fetching data:", error));
}
async handleFilterBtn() {
const filterBtn = document.getElementById("btnFilterData");
if (!filterBtn) {
console.error("Button not found: #btnFilterData");
return;
}
filterBtn.addEventListener("click", async () => {
if (!this.startDate || !this.endDate) {
console.log("No date filter applied, using default data");
} else {
console.log(
`Filtering with dates: ${this.startDate} - ${this.endDate}`
);
}
// Reinitialize table with updated filters
this.initTablePaymentRecaps();
});
}
async handleExportToExcel() {
const button = document.getElementById("btn-export-excel");
if (!button) {
console.error("Button not found: #btn-export-excel");
return;
}
button.addEventListener("click", async () => {
button.disabled = true;
let exportUrl = new URL(button.getAttribute("data-url"));
if (this.startDate) {
exportUrl.searchParams.append("start_date", this.startDate);
} else {
console.warn("⚠️ start_date is missing");
}
if (this.endDate) {
exportUrl.searchParams.append("end_date", this.endDate);
} else {
console.warn("⚠️ end_date is missing");
}
// Final check
console.log("Final Export URL:", exportUrl.toString());
try {
const response = await fetch(`${exportUrl}`, {
method: "GET",
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
});
if (!response.ok) {
console.error("Error fetching data:", response.statusText);
button.disabled = false;
return;
}
// Convert response to Blob and trigger download
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "rekap-pembayaran.xlsx";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
} catch (error) {
console.error("Error fetching data:", error);
button.disabled = false;
return;
} finally {
button.disabled = false;
}
});
}
async handleExportPDF() {
const button = document.getElementById("btn-export-pdf");
if (!button) {
console.error("Button not found: #btn-export-pdf");
return;
}
button.addEventListener("click", async () => {
button.disabled = true;
let exportUrl = new URL(button.getAttribute("data-url"));
if (this.startDate) {
exportUrl.searchParams.append("start_date", this.startDate);
} else {
console.warn("⚠️ start_date is missing");
}
if (this.endDate) {
exportUrl.searchParams.append("end_date", this.endDate);
} else {
console.warn("⚠️ end_date is missing");
}
try {
const response = await fetch(`${exportUrl}`, {
method: "GET",
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
});
if (!response.ok) {
console.error("Error fetching data:", response.statusText);
button.disabled = false;
return;
}
// Convert response to Blob and trigger download
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "rekap-pembayaran.pdf";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
} catch (error) {
console.error("Error fetching data:", error);
button.disabled = false;
return;
} finally {
button.disabled = false;
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new PaymentRecaps();
new PaymentRecaps().init();
});

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Laporan Rekap Pembayaran</title>
<style>
body { font-family: Arial, sans-serif; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid black; padding: 8px; text-align: center; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h2>Laporan Rekap Pembayaran</h2>
<table>
<thead>
<tr>
<th>Kategori</th>
<th>Nominal</th>
<th>Created</th>
</tr>
</thead>
<tbody>
@foreach($data as $item)
<tr>
<td>{{ $item['category'] }}</td>
<td>{{ $item['nominal'] }}</td>
<td>{{ $item['created_at'] }}</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>

View File

@@ -13,6 +13,19 @@
<div class="row">
<div class="col-12">
<div class="card w-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">Rekap Pembayaran</h5>
<div class="d-flex gap-2">
<button class="btn btn-sm bg-black text-white d-flex align-items-center content-center gap-2" id="btn-export-excel" data-url="{{ route('api.payment-recaps.excel') }}">
<span>.xlsx</span>
<iconify-icon icon="mingcute:file-export-line" width="20" height="20" class="d-flex align-items-center"></iconify-icon>
</button>
<button class="btn btn-sm bg-black text-white d-flex align-items-center content-center gap-2" id="btn-export-pdf" data-url="{{ route('api.payment-recaps.pdf') }}">
<span>.pdf</span>
<iconify-icon icon="mingcute:file-export-line" width="20" height="20" class="d-flex align-items-center"></iconify-icon>
</button>
</div>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-12 d-flex justify-content-end align-items-center flex-wrap gap-2">