sementara

This commit is contained in:
Daeng Deni Mardaeni
2026-01-30 14:44:14 +07:00
parent f402c0831a
commit aceff4f006
29 changed files with 2144 additions and 93 deletions

View File

@@ -5,17 +5,47 @@
@endsection
@section('content')
<div class="grid grid-cols-1 lg:grid-cols-4 gap-5 lg:gap-7.5 mb-10">
<style>
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.8);
display: none;
justify-content: center;
align-items: center;
z-index: 9999;
}
.loading-spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
<div class="loading-overlay" id="loadingOverlay">
<div class="loading-spinner"></div>
</div>
<div class="grid grid-cols-1 gap-5 mb-10 lg:grid-cols-4 lg:gap-7.5">
<div class="col-span-1">
<div class="card border border-agi-100 card-grid min-w-full">
<div class="card-header bg-agi-50 py-5 flex-wrap">
<div class="min-w-full border card border-agi-100 card-grid">
<div class="flex-wrap py-5 card-header bg-agi-50">
<h3 class="card-title">
Filter
</h3>
</div>
<div class="card-body px-5">
<div class="px-5 card-body">
<form id="filter-form">
<div class="grid gap-4 w-full p-5">
<div class="grid gap-4 p-5 w-full">
<div>
<label for="kategori" class="block text-sm font-medium text-gray-700">Kategori</label>
@@ -77,14 +107,20 @@
</div>
<div>
<label for="start_date" class="block text-sm font-medium text-gray-700">Start Date</label>
<input type="date" id="start_date" name="start_date" class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<input type="date" id="start_date" name="start_date" class="block px-3 py-2 mt-1 w-full bg-white rounded-md border border-gray-300 shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div>
<label for="end_date" class="block text-sm font-medium text-gray-700">End Date</label>
<input type="date" id="end_date" name="end_date" class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<input type="date" id="end_date" name="end_date" class="block px-3 py-2 mt-1 w-full bg-white rounded-md border border-gray-300 shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div>
<button type="submit" class="w-full inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<div class="flex items-center">
<input id="show_all" name="show_all" type="checkbox" class="w-4 h-4 text-indigo-600 bg-gray-100 rounded border-gray-300 focus:ring-indigo-500 focus:ring-2">
<label for="show_all" class="ml-2 text-sm font-medium text-gray-700">Tampilkan Semua Data</label>
</div>
</div>
<div>
<button type="submit" class="inline-flex justify-center px-4 py-2 w-full text-sm font-medium text-white bg-indigo-600 rounded-md border border-transparent shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Apply Filters
</button>
</div>
@@ -95,21 +131,21 @@
</div>
<div class="col-span-3">
<div class="card border border-agi-100 card-grid min-w-full">
<div class="card-header bg-agi-50 py-5 flex-wrap">
<div class="min-w-full border card border-agi-100 card-grid">
<div class="flex-wrap py-5 card-header bg-agi-50">
<h3 class="card-title">
Maps
</h3>
</div>
<div class="card-body px-5">
<div class="px-5 card-body">
<div id="map" style="height: 700px; width: 100%;"></div>
</div>
</div>
</div>
</div>
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
<div class="card border border-agi-100 card-grid min-w-full" data-datatable="false" data-datatable-page-size="10" data-datatable-state-save="false" id="bank-data-table" data-api-url="{{ route('bank-data.datatables') }}">
<div class="card-header bg-agi-50 py-5 flex-wrap">
<div class="grid gap-5 mx-auto w-full lg:gap-7.5">
<div class="min-w-full border card border-agi-100 card-grid" data-datatable="false" data-datatable-page-size="10" data-datatable-state-save="false" id="bank-data-table" data-api-url="{{ route('bank-data.datatables') }}">
<div class="flex-wrap py-5 card-header bg-agi-50">
<h3 class="card-title">
Daftar Bank Data
</h3>
@@ -128,7 +164,7 @@
<div class="card-body">
<div class="scrollable-x-auto">
<table class="table table-auto table-border align-middle text-gray-700 font-medium text-sm" data-datatable-table="true">
<table class="table text-sm font-medium text-gray-700 align-middle table-auto table-border" data-datatable-table="true">
<thead>
<tr>
<th class="w-14">
@@ -174,13 +210,13 @@
</thead>
</table>
</div>
<div class="card-footer justify-center md:justify-between flex-col md:flex-row gap-3 text-gray-600 text-2sm font-medium">
<div class="flex items-center gap-2">
<div 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">
Show
<select class="select select-sm w-16" data-datatable-size="true" name="perpage"> </select> per
<select class="w-16 select select-sm" data-datatable-size="true" name="perpage"> </select> per
page
</div>
<div class="flex items-center gap-4">
<div class="flex gap-4 items-center">
<span data-datatable-info="true"> </span>
<div class="pagination" data-datatable-pagination="true">
</div>
@@ -190,10 +226,10 @@
</div>
</div>
<div id="imageModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div id="imageModal" class="hidden fixed inset-0 z-50 justify-center items-center bg-black bg-opacity-50">
<div class="bg-white p-4 rounded-lg max-w-3xl max-h-[100vh] overflow-auto">
<img id="modalImage" src="" alt="Zoomed Image" class="max-w-full h-auto">
<button id="closeModal" class="mt-4 px-4 py-2 bg-red-300 text-gray-800 rounded hover:bg-red-400" onclick="closeImageModal()">Close</button>
<button id="closeModal" class="px-4 py-2 mt-4 text-gray-800 bg-red-300 rounded hover:bg-red-400" onclick="closeImageModal()">Close</button>
</div>
</div>
@endsection
@@ -261,8 +297,9 @@
const markerColors = {
data_pembanding: 'http://maps.google.com/mapfiles/ms/icons/red-dot.png',
penilaian: 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png',
input: 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png'
internal: 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png',
input: 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png',
kjpp: 'http://maps.google.com/mapfiles/ms/icons/purple-dot.png'
};
if (lat && lng) {
@@ -277,95 +314,95 @@
const contentString = `
<div id='content' style='width: 550px; max-width: 100%;'>
<div id='siteNotice'></div>
<h2 class='card-title mb-5'>
<h2 class='mb-5 card-title'>
${item.jenis_aset}
</h2>
<div class="grid gap-3">
<div class='flex items-center justify-between flex-wrap gap-1.5'>
<div class='flex items-center gap-1.5'>
<div class='flex flex-wrap gap-1.5 justify-between items-center'>
<div class='flex gap-1.5 items-center'>
<span class='text-sm font-normal text-gray-900'>
Tanggal Penilaian
</span>
</div>
<div class='flex items-center text-sm font-medium text-gray-800 gap-6'>
<div class='flex gap-6 items-center text-sm font-medium text-gray-800'>
<span class='lg:text-right'>
${window.formatTanggalIndonesia(item.tanggal)}
</span>
</div>
</div>
<div class="border-t border-gray-300 border-dashed"></div>
<div class='flex items-center justify-between flex-wrap gap-1.5'>
<div class='flex items-center gap-1.5'>
<div class='flex flex-wrap gap-1.5 justify-between items-center'>
<div class='flex gap-1.5 items-center'>
<span class='text-sm font-normal text-gray-900'>
Tahun
</span>
</div>
<div class='flex items-center text-sm font-medium text-gray-800 gap-6'>
<div class='flex gap-6 items-center text-sm font-medium text-gray-800'>
<span class='lg:text-right'>
${item.tahun}
</span>
</div>
</div>
<div class="border-t border-gray-300 border-dashed"></div>
<div class='flex items-center justify-between flex-wrap gap-1.5'>
<div class='flex items-center gap-1.5'>
<div class='flex flex-wrap gap-1.5 justify-between items-center'>
<div class='flex gap-1.5 items-center'>
<span class='text-sm font-normal text-gray-900'>
Luas Tanah
</span>
</div>
<div class='flex items-center text-sm font-medium text-gray-800 gap-6'>
<div class='flex gap-6 items-center text-sm font-medium text-gray-800'>
<span class='lg:text-right'>
${item.luas_tanah} m²
</span>
</div>
</div>
<div class="border-t border-gray-300 border-dashed"></div>
<div class='flex items-center justify-between flex-wrap gap-1.5'>
<div class='flex items-center gap-1.5'>
<div class='flex flex-wrap gap-1.5 justify-between items-center'>
<div class='flex gap-1.5 items-center'>
<span class='text-sm font-normal text-gray-900'>
Luas Bangunan
</span>
</div>
<div class='flex items-center text-sm font-medium text-gray-800 gap-6'>
<div class='flex gap-6 items-center text-sm font-medium text-gray-800'>
<span class='lg:text-right'>
${item.luas_bangunan} m²
</span>
</div>
</div>
<div class="border-t border-gray-300 border-dashed"></div>
<div class='flex items-center justify-between flex-wrap gap-1.5'>
<div class='flex items-center gap-1.5'>
<div class='flex flex-wrap gap-1.5 justify-between items-center'>
<div class='flex gap-1.5 items-center'>
<span class='text-sm font-normal text-gray-900'>
Harga
</span>
</div>
<div class='flex items-center text-sm font-medium text-gray-800 gap-6'>
<div class='flex gap-6 items-center text-sm font-medium text-gray-800'>
<span class='lg:text-right'>
${window.formatRupiah(item.harga)}
</span>
</div>
</div>
<div class="border-t border-gray-300 border-dashed"></div>
<div class='flex items-center justify-between flex-wrap gap-1.5'>
<div class='flex items-center gap-1.5'>
<div class='flex flex-wrap gap-1.5 justify-between items-center'>
<div class='flex gap-1.5 items-center'>
<span class='text-sm font-normal text-gray-900'>
Nilai Pasar
</span>
</div>
<div class='flex items-center text-sm font-medium text-gray-800 gap-6'>
<div class='flex gap-6 items-center text-sm font-medium text-gray-800'>
<span class='lg:text-right'>
${window.formatRupiah(item.nilai_pasar)}
</span>
</div>
</div>
<div class="border-t border-gray-300 border-dashed"></div>
<div class='flex items-start justify-between flex-wrap gap-1.5'>
<div class='flex items-start gap-1.5'>
<div class='flex flex-wrap gap-1.5 justify-between items-start'>
<div class='flex gap-1.5 items-start'>
<span class='text-sm font-normal text-gray-900'>
Location
</span>
</div>
<div class='flex items-center text-sm font-medium text-gray-800 gap-6'>
<div class='flex gap-6 items-center text-sm font-medium text-gray-800'>
<span class='text-right whitespace-normal break-words'>
${item.address.split(' ').reduce((acc, word, index, array) => {
if (index > 0 && index % 7 === 0) {
@@ -378,16 +415,16 @@
</div>
</div>
${item.photos && item.photos.length > 0 ? `
<div class="photo-gallery mb-5">
<div class="main-photo mb-2">
<div class="mb-5 photo-gallery">
<div class="mb-2 main-photo">
<img src="storage/${item.photos[0]}" alt="${item.jenis_aset}"
style="width: 100%; height: auto; object-fit: cover; cursor: pointer;"
onclick="openImageModal(this.src)">
</div>
<div class="thumbnail-container flex gap-2 overflow-x-auto">
<div class="flex overflow-x-auto gap-2 thumbnail-container">
${item.photos.map((photo, index) => `
<img src="storage/${photo}" alt="${item.jenis_aset} ${index + 1}"
class="thumbnail cursor-pointer"
class="cursor-pointer thumbnail"
style="width: 60px; height: 60px; object-fit: cover;"
onclick="changeMainPhoto(this, ${index})">
`).join('')}
@@ -462,6 +499,16 @@
const dataTableOptions = {
apiEndpoint: apiUrl,
pageSize: 5,
ajax: {
data: function(data) {
// Add show_all parameter if checkbox is checked
const showAllCheckbox = document.getElementById('show_all');
if (showAllCheckbox && showAllCheckbox.checked) {
data.show_all = true;
}
return data;
}
},
columns: {
select: {
render: (item, data, context) => {
@@ -535,11 +582,36 @@
}
const filterForm = document.getElementById('filter-form');
const loadingOverlay = document.getElementById('loadingOverlay');
function showLoading() {
loadingOverlay.style.display = 'flex';
}
function hideLoading() {
loadingOverlay.style.display = 'none';
}
filterForm.addEventListener('submit', function (e) {
e.preventDefault();
showLoading();
const formData = new FormData(this);
const filters = Object.fromEntries(formData.entries());
// Check if show_all is checked
const showAllCheckbox = document.getElementById('show_all');
if (showAllCheckbox.checked) {
filters.show_all = true;
// Hide pagination controls when showing all data
document.querySelector('[data-datatable-pagination="true"]').style.display = 'none';
document.querySelector('[data-datatable-size="true"]').closest('div').style.display = 'none';
} else {
// Show pagination controls when using pagination
document.querySelector('[data-datatable-pagination="true"]').style.display = 'block';
document.querySelector('[data-datatable-size="true"]').closest('div').style.display = 'flex';
}
// Apply the new search/filter
if (filters) {
dataTable.search(filters, true);
@@ -547,16 +619,26 @@
// Reload the table to apply the new filters
dataTable.reload();
// Hide loading after a short delay to allow table to update
setTimeout(hideLoading, 300);
});
function updatePagination(response) {
const paginationInfo = document.querySelector('[data-datatable-info="true"]');
const showAllCheckbox = document.getElementById('show_all');
if (paginationInfo) {
if (response.recordsFiltered > 0) {
const start = (response.page - 1) * response.pageSize + 1;
const end = Math.min(start + response.pageSize - 1, response.recordsFiltered);
paginationInfo.textContent = `Showing ${start} to ${end} of ${response.recordsFiltered} entries`;
if (showAllCheckbox && showAllCheckbox.checked) {
// Show all data message when show_all is active
paginationInfo.textContent = `Showing all ${response.recordsFiltered} entries`;
} else {
// Normal pagination message
const start = (response.page - 1) * response.pageSize + 1;
const end = Math.min(start + response.pageSize - 1, response.recordsFiltered);
paginationInfo.textContent = `Showing ${start} to ${end} of ${response.recordsFiltered} entries`;
}
} else {
paginationInfo.textContent = 'No entries to show';
}
@@ -567,6 +649,17 @@
initMap();
initializeDataTable();
// Load all data on first initialization
setTimeout(() => {
const showAllCheckbox = document.getElementById('show_all');
showAllCheckbox.checked = true; // Check the show all checkbox by default
// Trigger filter submit to load all data
const filterForm = document.getElementById('filter-form');
const event = new Event('submit');
filterForm.dispatchEvent(event);
}, 500);
dataTable.on('draw', () => {
console.log("Table redrawn");
});