✨ feat(noc): implementasi perhitungan total nominal diterima pada pembayaran
- Hitung total nominal diterima dari semua data yang difilter (bukan hanya halaman aktif) - Tampilkan total dalam format currency Indonesia (IDR) di footer tabel - Integrasi backend (NocController) dan frontend (Blade + JS) secara real-time - Update otomatis via event listener DataTable saat data berubah atau difilter - Validasi dan parsing currency string dengan aman, casting ke float untuk akurasi - Tambahkan field totalNominalDiterima pada response JSON DataTable - Footer tabel dengan styling TailwindCSS (text-green-600, font-bold) untuk highlight - UX lebih transparan: user langsung melihat total pembayaran yang diterima - Performa terjaga: minimal DOM manipulation, native Intl.NumberFormat, efisien pada filter
This commit is contained in:
@@ -296,6 +296,13 @@
|
|||||||
];
|
];
|
||||||
})->sortBy('updated_at', 1)->values();
|
})->sortBy('updated_at', 1)->values();
|
||||||
|
|
||||||
|
// Calculate total nominal diterima from all filtered data (not just current page)
|
||||||
|
$totalNominalDiterima = $data->sum(function ($item) {
|
||||||
|
// Extract numeric value from formatted currency string
|
||||||
|
$nominal = str_replace(['Rp', '.', ',00'], '', $item['nominal_diterima']);
|
||||||
|
return (float) $nominal;
|
||||||
|
});
|
||||||
|
|
||||||
// Calculate the page count
|
// Calculate the page count
|
||||||
$pageCount = ceil($totalRecords / $request->get('size'));
|
$pageCount = ceil($totalRecords / $request->get('size'));
|
||||||
|
|
||||||
@@ -310,6 +317,7 @@
|
|||||||
'pageCount' => $pageCount,
|
'pageCount' => $pageCount,
|
||||||
'page' => $currentPage,
|
'page' => $currentPage,
|
||||||
'totalCount' => $totalRecords,
|
'totalCount' => $totalRecords,
|
||||||
|
'totalNominalDiterima' => $totalNominalDiterima,
|
||||||
'data' => $data,
|
'data' => $data,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,15 @@
|
|||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Table Footer untuk Total -->
|
||||||
|
<div class="px-5 py-3 bg-gray-50 border-t border-gray-200">
|
||||||
|
<div class="flex justify-end items-center">
|
||||||
|
<div class="text-sm font-semibold text-gray-700">
|
||||||
|
Total Nominal Diterima: <span id="total-nominal-diterima"
|
||||||
|
class="text-lg font-bold text-green-600">Rp 0</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
|
class="flex-col gap-3 justify-center font-medium text-gray-600 card-footer md:justify-between md:flex-row text-2sm">
|
||||||
<div class="flex gap-2 items-center">
|
<div class="flex gap-2 items-center">
|
||||||
@@ -218,6 +227,30 @@
|
|||||||
|
|
||||||
let dataTable = new KTDataTable(element, dataTableOptions);
|
let dataTable = new KTDataTable(element, dataTableOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fungsi untuk menampilkan total nominal diterima dari backend
|
||||||
|
* @param {number} total - Total nominal diterima dari backend
|
||||||
|
*/
|
||||||
|
function updateTotalNominalDiterima(total) {
|
||||||
|
// Format dan tampilkan total
|
||||||
|
const formattedTotal = new Intl.NumberFormat('id-ID', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'IDR',
|
||||||
|
minimumFractionDigits: 0
|
||||||
|
}).format(total || 0);
|
||||||
|
|
||||||
|
document.getElementById('total-nominal-diterima').textContent = formattedTotal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event listener untuk update total saat data berubah
|
||||||
|
dataTable.on('fetched', function(e, response) {
|
||||||
|
// Ambil total dari response backend
|
||||||
|
console.log(e.response);
|
||||||
|
if (e.response && e.response.totalNominalDiterima !== undefined) {
|
||||||
|
updateTotalNominalDiterima(e.response.totalNominalDiterima);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Custom search functionality
|
// Custom search functionality
|
||||||
searchInput.addEventListener('input', function() {
|
searchInput.addEventListener('input', function() {
|
||||||
const searchValue = this.value.trim();
|
const searchValue = this.value.trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user