feat(memo): tambah filter jenis penilaian dan perbaiki fungsi clear checkbox pada datatable memo

Perubahan yang dilakukan:
- Menambahkan dropdown filter "Jenis Penilaian" (Internal/External) pada halaman index memo penyelesaian
- Mengimplementasikan filter gabungan menggunakan separator '|' untuk kombinasi filter dan search
- Memperbaiki fungsi clearSelectedCheckboxes dengan selector '#memo-table thead input[type="checkbox"]' agar lebih spesifik
- Menambahkan event listener untuk filter jenis penilaian yang terintegrasi dengan fungsi search datatable
- Mengupdate MemoController untuk memisahkan parameter filter menjadi jenis penilaian dan search term menggunakan explode('|')
- Menambahkan log untuk debugging filter dan proses checkbox
- Memodifikasi tampilan dengan class `gap-2` pada container filter untuk spacing yang lebih baik
- Menambahkan console.log pada fungsi handleCheckboxChange untuk tracking interaksi user
- Memperbaiki error handling pada fungsi clearSelectedCheckboxes untuk memastikan checkbox ter-reset dengan benar
- Menampilkan jumlah item terpilih pada tombol "Create Memo" untuk meningkatkan feedback user

Tujuan perubahan:
- Mempermudah pengguna dalam memfilter data berdasarkan jenis penilaian langsung di datatable memo
- Memastikan fungsi checkbox selection berjalan dengan konsisten dan lebih robust
- Meningkatkan user experience dengan feedback visual yang lebih jelas saat filter dan selection digunakan
- Menyederhanakan interaksi user sekaligus menjaga akurasi proses pembuatan memo penyelesaian
This commit is contained in:
Daeng Deni Mardaeni
2025-07-17 15:16:58 +07:00
parent cd46a3b0dc
commit d7e5df569a
2 changed files with 109 additions and 15 deletions

View File

@@ -190,22 +190,33 @@ class MemoController extends Controller
$q->whereIn('nilai_plafond_id', [1, 4])
->whereNotNull('approval_dd_at')
->orWhereIn('nilai_plafond_id', [2, 3]);
})
->whereHas('noc'); // Hanya tampilkan permohonan yang memiliki NOC
});
//->whereHas('noc'); // Hanya tampilkan permohonan yang memiliki NOC
$query = $query->orderBy('nomor_registrasi', 'desc');
// Apply search filter jika ada
if ($request->has('search') && !empty($request->get('search'))) {
$search = $request->get('search');
$query->where(function ($q) use ($search) {
$q->where('nomor_registrasi', 'LIKE', '%' . $search . '%');
$q->orWhere('tanggal_permohonan', 'LIKE', '%' . $search . '%');
$q->orWhereRelation('user', 'name', 'LIKE', '%' . $search . '%');
$q->orWhereRelation('debiture', 'name', 'LIKE', '%' . $search . '%');
$q->orWhereRelation('tujuanPenilaian', 'name', 'LIKE', '%' . $search . '%');
$q->orWhereRelation('branch', 'name', 'LIKE', '%' . $search . '%');
$q->orWhere('status', 'LIKE', '%' . $search . '%');
$searchParams = explode('|', $request->get('search'));
$filterJenisPenilaian = $searchParams[0] ?? '';
$searchTerm = $searchParams[1] ?? '';
// Filter berdasarkan jenis penilaian
if (!empty($filterJenisPenilaian)) {
$query->where('jenis_penilaian_id', $filterJenisPenilaian);
Log::info('Applied jenis penilaian filter', ['filter' => $filterJenisPenilaian]);
}
$query->where(function ($q) use ($searchTerm) {
$q->where('nomor_registrasi', 'LIKE', '%' . $searchTerm . '%');
$q->orWhere('tanggal_permohonan', 'LIKE', '%' . $searchTerm . '%');
$q->orWhereRelation('user', 'name', 'LIKE', '%' . $searchTerm . '%');
$q->orWhereRelation('debiture', 'name', 'LIKE', '%' . $searchTerm . '%');
$q->orWhereRelation('tujuanPenilaian', 'name', 'LIKE', '%' . $searchTerm . '%');
$q->orWhereRelation('branch', 'name', 'LIKE', '%' . $searchTerm . '%');
$q->orWhere('status', 'LIKE', '%' . $searchTerm . '%');
});
}

View File

@@ -13,10 +13,15 @@
Memo Penyelesaian
</h3>
<div class="flex flex-wrap gap-2 lg:gap-5">
<div class="flex">
<div class="flex gap-2">
<label class="input input-sm"> <i class="ki-filled ki-magnifier"> </i>
<input placeholder="Search Memo Penyelesaian" id="search" type="text" value="">
</label>
<select class="select select-sm" id="filter-jenis-penilaian">
<option value="">Semua Jenis Penilaian</option>
<option value="1">Internal</option>
<option value="2">External</option>
</select>
</div>
<div class="flex flex-wrap gap-2.5">
<div class="h-[24px] border border-r-gray-200"></div>
@@ -128,6 +133,7 @@
<script type="module">
const element = document.querySelector('#memo-table');
const searchInput = document.getElementById('search');
const filterJenisPenilaian = document.getElementById('filter-jenis-penilaian');
const btnCreateMemo = document.getElementById('btn-create-memo');
let selectedItems = [];
@@ -298,22 +304,60 @@
/**
* Fungsi untuk menangani perubahan checkbox
* Mengelola state tombol berdasarkan checkbox yang dipilih
*/
function handleCheckboxChange() {
// Hanya ambil checkbox yang tidak disabled dan checked
const checkboxes = document.querySelectorAll('input[data-datatable-row-check="true"]:checked:not(:disabled)');
selectedItems = Array.from(checkboxes).map(cb => cb.value);
// Enable/disable tombol create memo berdasarkan jumlah item yang dipilih
btnCreateMemo.disabled = selectedItems.length === 0;
// Log untuk debugging
console.log('Selected items:', selectedItems);
if (selectedItems.length > 0) {
// Enable/disable tombol berdasarkan jumlah item yang dipilih
const hasSelection = selectedItems.length > 0;
btnCreateMemo.disabled = !hasSelection;
// Update text tombol create memo
if (hasSelection) {
btnCreateMemo.textContent = `Buat Memo Penyelesaian (${selectedItems.length} item)`;
} else {
btnCreateMemo.textContent = 'Buat Memo Penyelesaian';
}
}
/**
* Fungsi untuk clear semua checkbox yang terpilih
* Menghapus semua selection dan reset state tombol
*/
function clearSelectedCheckboxes() {
try {
// Uncheck master checkbox juga - gunakan selector yang lebih spesifik
const masterCheckbox = document.querySelector('#memo-table thead input[type="checkbox"]');
if (masterCheckbox) {
masterCheckbox.checked = false;
}
// Uncheck semua checkbox yang tidak disabled
const checkboxes = document.querySelectorAll('input[data-datatable-row-check="true"]:not(:disabled)');
checkboxes.forEach(checkbox => {
checkbox.checked = false;
});
// Reset selected items array
selectedItems = [];
// Update state tombol
btnCreateMemo.disabled = true;
btnCreateMemo.textContent = 'Buat Memo Penyelesaian';
// Log untuk debugging
console.log('All checkboxes cleared successfully');
} catch (error) {
console.error('Error clearing checkboxes:', error);
}
}
// Event listener untuk checkbox changes
element.addEventListener('change', function(e) {
if (e.target.type === 'checkbox') {
@@ -325,6 +369,7 @@
btnCreateMemo.addEventListener('click', function() {
if (selectedItems.length > 0) {
const selectedIds = selectedItems.join(',');
console.log('Creating memo for IDs:', selectedIds);
window.location.href = `{{ route('memo.create') }}?selected_ids=${selectedIds}`;
}
});
@@ -334,5 +379,43 @@
const searchValue = this.value.trim();
dataTable.search(searchValue, true);
});
/**
* Filter berdasarkan jenis penilaian
* Menggunakan pola yang sama dengan districts filter
*/
filterJenisPenilaian.addEventListener('change', function() {
const filterValue = this.value;
const searchValue = searchInput.value.trim();
// Gabungkan filter dan search dalam satu parameter
const combinedSearch = `${filterValue}|${searchValue}`;
// Log untuk debugging
console.log('Filter jenis penilaian:', filterValue);
console.log('Search value:', searchValue);
console.log('Combined search:', combinedSearch);
// Gunakan search method seperti di districts
dataTable.search(combinedSearch, true);
});
/**
* Update search input handler untuk mendukung filter
*/
searchInput.addEventListener('input', function() {
const searchValue = this.value.trim();
const filterValue = filterJenisPenilaian.value;
// Gabungkan search dan filter
const combinedSearch = `${filterValue}|${searchValue}`;
// Log untuk debugging
console.log('Search input:', searchValue);
console.log('Current filter:', filterValue);
console.log('Combined search:', combinedSearch);
dataTable.search(combinedSearch, true);
});
</script>
@endpush