feat(branch): tambahkan fitur filter dan search pada eksport dan tabel cabang
- Menambahkan parameter `search` dan `parent_id` pada `BranchExport` untuk mendukung fitur filter. - Memodifikasi method `collection` di `BranchExport` agar mendukung filter pencarian dan parent cabang. - Memperbaiki issue pada method `collection` terkait penggunaan query `LOWER` untuk pencarian. - Mengubah method `export` di `BranchController` agar menerima parameter filter dari request. - Menambahkan logika filtering untuk `search` dan `parent_id` pada method index API `BranchController`. - Menambahkan dropdown filter parent di tampilan `branch/index.blade.php`. - Implementasi JavaScript di `branch/index.blade.php` untuk mendukung filter pencarian dan parent cabang. - Menambahkan logika sinkronisasi URL eksport dengan parameter filter. - Menambahkan event listener untuk filter pencarian dan dropdown parent. - Menambahkan validasi agar filter diterapkan ke datatable dan URL eksport secara dinamis. - Memperbaiki penghitungan halaman pagination di datatable. - Penyesuaian minor pada model Branch dan cara logging aktivitas di model Base. Fitur ini memungkinkan pengguna melakukan filter data cabang berdasarkan pencarian dan parent cabang saat menampilkan tabel ataupun mengekspor data ke Excel. Signed-off-by: Daeng Deni Mardaeni <ddeni05@gmail.com>
This commit is contained in:
@@ -9,11 +9,38 @@
|
|||||||
use Modules\Basicdata\Models\Branch;
|
use Modules\Basicdata\Models\Branch;
|
||||||
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
|
||||||
|
|
||||||
class BranchExport implements WithColumnFormatting, WithHeadings, FromCollection, withMapping
|
class BranchExport implements WithColumnFormatting, WithHeadings, FromCollection, WithMapping
|
||||||
{
|
{
|
||||||
|
protected $search;
|
||||||
|
|
||||||
|
public function __construct($search = null, $parent_id = null)
|
||||||
|
{
|
||||||
|
$this->search = $search;
|
||||||
|
$this->parent_id = $parent_id;
|
||||||
|
}
|
||||||
|
|
||||||
public function collection()
|
public function collection()
|
||||||
{
|
{
|
||||||
return Branch::all();
|
$query = Branch::query();
|
||||||
|
|
||||||
|
if (!empty($this->search)) {
|
||||||
|
$search = strtolower($this->search);
|
||||||
|
$query->where(function ($q) use ($search) {
|
||||||
|
$q->whereRaw('LOWER(code) LIKE ?', ['%' . $search . '%'])
|
||||||
|
->orWhereRaw('LOWER(name) LIKE ?', ['%' . $search . '%'])
|
||||||
|
->orWhereHas('parent', function ($q) use ($search) {
|
||||||
|
$q->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply parent filter if provided
|
||||||
|
if (isset($this->parent_id) && !empty($this->parent_id)) {
|
||||||
|
$parentId = $this->parent_id;
|
||||||
|
$query->where('parent_id', $parentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function map($row)
|
public function map($row)
|
||||||
@@ -23,6 +50,7 @@
|
|||||||
$row->id,
|
$row->id,
|
||||||
$row->code,
|
$row->code,
|
||||||
$row->name,
|
$row->name,
|
||||||
|
$row->parent ? $row->parent->name : '',
|
||||||
$row->created_at
|
$row->created_at
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -34,6 +62,7 @@
|
|||||||
'ID',
|
'ID',
|
||||||
'Code',
|
'Code',
|
||||||
'Name',
|
'Name',
|
||||||
|
'Parent Branch',
|
||||||
'Created At'
|
'Created At'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,11 +182,24 @@
|
|||||||
|
|
||||||
// Apply search filter if provided
|
// Apply search filter if provided
|
||||||
if ($request->has('search') && !empty($request->get('search'))) {
|
if ($request->has('search') && !empty($request->get('search'))) {
|
||||||
$search = $request->get('search');
|
$search = json_decode($request->get('search'));
|
||||||
$query->where(function ($q) use ($search) {
|
|
||||||
$q->where('code', 'LIKE', "%$search%");
|
if(isset($search->search)) {
|
||||||
$q->orWhere('name', 'LIKE', "%$search%");
|
$search_ = strtolower($search->search);
|
||||||
});
|
$query->where(function ($q) use ($search_) {
|
||||||
|
$q->whereRaw('LOWER(code) LIKE ?', ['%' . strtolower($search_) . '%']);
|
||||||
|
$q->orWhereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search_) . '%']);
|
||||||
|
$q->orWhereHas('parent', function ($q) use ($search_) {
|
||||||
|
$q->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search_) . '%']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply parent filter if provided
|
||||||
|
if (isset($search->parent_id) && !empty($search->parent_id)) {
|
||||||
|
$parentId = $search->parent_id;
|
||||||
|
$query->where('parent_id', $parentId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply sorting if provided
|
// Apply sorting if provided
|
||||||
@@ -227,7 +240,7 @@
|
|||||||
$pageCount = ceil($totalRecords / $request->get('size'));
|
$pageCount = ceil($totalRecords / $request->get('size'));
|
||||||
|
|
||||||
// Calculate the current page number
|
// Calculate the current page number
|
||||||
$currentPage = 0 + 1;
|
$currentPage = $request->get('page') ?: 1;
|
||||||
|
|
||||||
|
|
||||||
// Return the response data as a JSON object
|
// Return the response data as a JSON object
|
||||||
@@ -242,13 +255,17 @@
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function export()
|
public function export(Request $request)
|
||||||
{
|
{
|
||||||
// Check if the authenticated user has the required permission to export branches
|
// Check if the authenticated user has the required permission to export branches
|
||||||
if (is_null($this->user) || !$this->user->can('basic-data.export')) {
|
if (is_null($this->user) || !$this->user->can('basic-data.export')) {
|
||||||
abort(403, 'Sorry! You are not allowed to export branches.');
|
abort(403, 'Sorry! You are not allowed to export branches.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return Excel::download(new BranchExport, 'branch.xlsx');
|
// Get search parameter from request
|
||||||
|
$search = $request->get('search');
|
||||||
|
$parentId = $request->get('parent_id');
|
||||||
|
|
||||||
|
return Excel::download(new BranchExport($search,$parentId), 'branch.xlsx');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,6 @@
|
|||||||
public function getActivitylogOptions()
|
public function getActivitylogOptions()
|
||||||
: LogOptions
|
: LogOptions
|
||||||
{
|
{
|
||||||
//CauserResolver::setCauser(auth()->user());
|
|
||||||
|
|
||||||
return LogOptions::defaults()->logAll()->useLogName('Basic Data');
|
return LogOptions::defaults()->logAll()->useLogName('Basic Data');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace Modules\Basicdata\Models;
|
namespace Modules\Basicdata\Models;
|
||||||
|
|
||||||
|
|
||||||
class Branch extends Base
|
class Branch extends Base
|
||||||
{
|
{
|
||||||
protected $table = 'branches';
|
protected $table = 'branches';
|
||||||
|
|||||||
@@ -12,15 +12,21 @@
|
|||||||
Daftar Cabang
|
Daftar Cabang
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex flex-wrap gap-2 lg:gap-5">
|
<div class="flex flex-wrap gap-2 lg:gap-5">
|
||||||
<div class="flex">
|
<div class="flex gap-2 lg:gap-5">
|
||||||
<label class="input input-sm"> <i class="ki-filled ki-magnifier"> </i>
|
<label class="input input-sm"> <i class="ki-filled ki-magnifier"> </i>
|
||||||
<input placeholder="Search Branch" id="search" type="text" value="">
|
<input placeholder="Search Branch" id="search" type="text" value="">
|
||||||
</label>
|
</label>
|
||||||
|
<select class="select select-sm" id="parent-filter" data-datatable-filter-column="parent_id">
|
||||||
|
<option value="">All Parent Branches</option>
|
||||||
|
@foreach(\Modules\Basicdata\Models\Branch::orderBy('name')->get() as $branch)
|
||||||
|
<option value="{{ $branch->id }}">{{ $branch->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-2.5">
|
<div class="flex flex-wrap gap-2 lg:gap-5">
|
||||||
<div class="h-[24px] border border-r-gray-200"></div>
|
<div class="h-[24px] border border-r-gray-200"></div>
|
||||||
@can('basic-data.export')
|
@can('basic-data.export')
|
||||||
<a class="btn btn-sm btn-light" href="{{ route('basicdata.branch.export') }}"> Export to Excel </a>
|
<a id="export-btn" class="btn btn-sm btn-light" href="{{ route('basicdata.branch.export') }}"> Export to Excel </a>
|
||||||
@endcan
|
@endcan
|
||||||
@can('basic-data.create')
|
@can('basic-data.create')
|
||||||
<a class="btn btn-sm btn-primary" href="{{ route('basicdata.branch.create') }}"> Tambah Cabang </a>
|
<a class="btn btn-sm btn-primary" href="{{ route('basicdata.branch.create') }}"> Tambah Cabang </a>
|
||||||
@@ -149,7 +155,9 @@
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
const element = document.querySelector('#branch-table');
|
const element = document.querySelector('#branch-table');
|
||||||
const searchInput = document.getElementById('search');
|
const searchInput = document.getElementById('search');
|
||||||
|
const parentFilter = document.getElementById('parent-filter');
|
||||||
const deleteSelectedButton = document.getElementById('deleteSelected');
|
const deleteSelectedButton = document.getElementById('deleteSelected');
|
||||||
|
const exportBtn = document.getElementById('export-btn');
|
||||||
|
|
||||||
const apiUrl = element.getAttribute('data-api-url');
|
const apiUrl = element.getAttribute('data-api-url');
|
||||||
const dataTableOptions = {
|
const dataTableOptions = {
|
||||||
@@ -200,12 +208,62 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
let dataTable = new KTDataTable(element, dataTableOptions);
|
let dataTable = new KTDataTable(element, dataTableOptions);
|
||||||
|
|
||||||
|
// Function to apply all filters
|
||||||
|
function applyFilters() {
|
||||||
|
let filters = {};
|
||||||
|
|
||||||
|
if (searchInput.value) {
|
||||||
|
filters.search = searchInput.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentFilter.value) {
|
||||||
|
filters.parent_id = parentFilter.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataTable.search(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update export URL with filters
|
||||||
|
function updateExportUrl() {
|
||||||
|
let url = new URL(exportBtn.href);
|
||||||
|
|
||||||
|
if (parentFilter.value) {
|
||||||
|
url.searchParams.set('parent_id', parentFilter.value);
|
||||||
|
} else {
|
||||||
|
url.searchParams.delete('parent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchInput.value) {
|
||||||
|
url.searchParams.set('search', searchInput.value);
|
||||||
|
} else {
|
||||||
|
url.searchParams.delete('search');
|
||||||
|
}
|
||||||
|
|
||||||
|
exportBtn.href = url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
// Custom search functionality
|
// Custom search functionality
|
||||||
searchInput.addEventListener('input', function () {
|
searchInput.addEventListener('input', function () {
|
||||||
const searchValue = this.value.trim();
|
dataTable.goPage(1);
|
||||||
dataTable.search(searchValue, true);
|
|
||||||
|
// Update export URL with search parameter
|
||||||
|
applyFilters();
|
||||||
|
updateExportUrl();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Parent branch filter functionality
|
||||||
|
parentFilter.addEventListener('change', function() {
|
||||||
|
updateExportUrl();
|
||||||
|
applyFilters();
|
||||||
|
});
|
||||||
|
|
||||||
|
exportBtn.addEventListener('click', function() {
|
||||||
|
console.log('Exporting data...');
|
||||||
|
updateExportUrl();
|
||||||
|
applyFilters();
|
||||||
|
})
|
||||||
|
|
||||||
function updateDeleteButtonVisibility() {
|
function updateDeleteButtonVisibility() {
|
||||||
const selectedCheckboxes = document.querySelectorAll('input[data-datatable-row-check="true"]:checked');
|
const selectedCheckboxes = document.querySelectorAll('input[data-datatable-row-check="true"]:checked');
|
||||||
if (selectedCheckboxes.length > 0) {
|
if (selectedCheckboxes.length > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user