update
This commit is contained in:
@@ -4,11 +4,13 @@
|
||||
data-bs-toggle="modal" data-bs-target="#deleteModal-{{ $row->id }}" />
|
||||
</div>
|
||||
|
||||
@include('administrator.pages.product.categories.datatable.modal', [
|
||||
'deleteRoute' => 'products.group.destroy',
|
||||
'itemLabel' => 'Product Group',
|
||||
'itemId' => $row->id,
|
||||
'itemName' => $row->name,
|
||||
'modalId' => 'deleteModal-' . $row->id
|
||||
])
|
||||
@push('modals')
|
||||
@include('administrator.pages.product.categories.datatable.modal', [
|
||||
'deleteRoute' => 'products.group.destroy',
|
||||
'itemLabel' => 'Product Group',
|
||||
'itemId' => $row->id,
|
||||
'itemName' => $row->name,
|
||||
'modalId' => 'deleteModal-' . $row->id
|
||||
])
|
||||
@endpush
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="{{ $modalId ?? 'deleteModal' }}" tabindex="-1"
|
||||
aria-labelledby="deleteModalLabel-{{ $modalId ?? 'deleteModal' }}" aria-hidden="true">
|
||||
aria-labelledby="deleteModalLabel-{{ $modalId ?? 'deleteModal' }}" aria-hidden="true" data-bs-backdrop="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-sm">
|
||||
<div class="modal-content shadow-lg border-0">
|
||||
<div class="modal-header bg-danger text-white py-2">
|
||||
@@ -9,8 +9,8 @@
|
||||
Xác nhận xóa
|
||||
</h6>
|
||||
<button type="button" class="btn-close btn-close-white shadow-none" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body py-4">
|
||||
</div>
|
||||
<div class="modal-body py-4">
|
||||
<div class="text-center">
|
||||
<div class="mb-3">
|
||||
<i data-lucide="alert-triangle" class="text-warning" style="width: 54px; height: 54px;"></i>
|
||||
@@ -21,11 +21,11 @@
|
||||
<div class="px-3 py-2 bg-danger-subtle rounded-3">
|
||||
<p class="text-danger small mb-0 fw-medium">Hành động này không thể hoàn tác!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light border-0 py-2 d-flex justify-content-center gap-2">
|
||||
<x-button-c-r-m type="button" variant="secondary" size="sm" icon="x" data-bs-dismiss="modal">Hủy bỏ</x-button-c-r-m>
|
||||
<form action="{{ route($deleteRoute, ['id' => $itemId ?? 0]) }}" method="POST" class="d-inline m-0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light border-0 py-2 d-flex justify-content-center gap-2">
|
||||
<x-button-c-r-m type="button" variant="secondary" size="sm" icon="x" data-bs-dismiss="modal">Hủy bỏ</x-button-c-r-m>
|
||||
<form action="{{ route($deleteRoute, ['id' => $itemId ?? 0]) }}" method="POST" class="d-inline m-0">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<x-button-c-r-m type="submit" variant="danger" size="sm" icon="trash-2">Xác nhận xóa</x-button-c-r-m>
|
||||
|
||||
@@ -64,8 +64,55 @@ $tabs = [
|
||||
@push('custom-scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// DataTable is already initialized in components/datatable
|
||||
// If we need custom behavior here, we can add it.
|
||||
// Re-initialize Lucide icons after DataTable draws
|
||||
$('#productTable').on('draw.dt', function() {
|
||||
setTimeout(function() {
|
||||
if (typeof lucide !== 'undefined') {
|
||||
lucide.createIcons();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@push('custom-styles')
|
||||
<style>
|
||||
/* Fix Bootstrap 5 modal z-index to be above DataTable and all other elements */
|
||||
.modal-backdrop {
|
||||
z-index: 9998 !important;
|
||||
}
|
||||
|
||||
.modal {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
/* Override datatable wrapper overflow to prevent clipping modals */
|
||||
.data-table-wrapper {
|
||||
overflow: visible !important;
|
||||
overflow-x: auto !important;
|
||||
}
|
||||
|
||||
/* Reduce z-index of sticky elements to be below modal */
|
||||
.data-table-wrapper .table thead th {
|
||||
z-index: 3 !important;
|
||||
}
|
||||
|
||||
.table thead th:last-child,
|
||||
.table tbody td:last-child {
|
||||
z-index: 2 !important;
|
||||
}
|
||||
|
||||
.table thead th:first-child,
|
||||
.table tbody td:first-child {
|
||||
z-index: 2 !important;
|
||||
}
|
||||
|
||||
.table thead th:nth-child(2) {
|
||||
z-index: 4 !important;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
{{-- Render all modals outside datatable wrapper --}}
|
||||
@stack('modals')
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
@props(['id', 'columns', 'ajax', 'bulkDeleteUrl' => null])
|
||||
|
||||
@php
|
||||
$dtColumns = collect($columns)
|
||||
->map(function ($c) {
|
||||
return [
|
||||
'data' => $c['key'],
|
||||
'name' => $c['key'],
|
||||
'orderable' => $c['orderable'] ?? true,
|
||||
'searchable' => $c['searchable'] ?? true,
|
||||
'className' => $c['className'] ?? '',
|
||||
];
|
||||
})
|
||||
->values();
|
||||
$dtColumns = collect($columns)
|
||||
->map(function ($c) {
|
||||
return [
|
||||
'data' => $c['key'],
|
||||
'name' => $c['key'],
|
||||
'orderable' => $c['orderable'] ?? true,
|
||||
'searchable' => $c['searchable'] ?? true,
|
||||
'className' => $c['className'] ?? '',
|
||||
];
|
||||
})
|
||||
->values();
|
||||
@endphp
|
||||
@if ($bulkDeleteUrl)
|
||||
<div class="d-flex justify-content-start align-items-center mb-3" id="{{ $id }}-bulk-actions"
|
||||
@@ -116,473 +116,473 @@
|
||||
</table>
|
||||
</div>
|
||||
@push('custom-scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$.fn.DataTable.ext.pager.numbers_length = 7;
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$.fn.DataTable.ext.pager.numbers_length = 7;
|
||||
|
||||
var table = $('#{{ $id }}').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: '{{ $ajax }}',
|
||||
columns: @json($dtColumns),
|
||||
orderCellsTop: true,
|
||||
fixedHeader: false,
|
||||
stateSave: true,
|
||||
pagingType: 'full_numbers',
|
||||
language: {
|
||||
loadingRecords: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="spinner-border text-primary mb-3" role="status"></div><h6 class="text-secondary fw-medium">Đang tải dữ liệu...</h6></div>',
|
||||
searchPlaceholder: "Tìm kiếm...",
|
||||
search: "",
|
||||
lengthMenu: "_MENU_",
|
||||
info: "Showing <span class='fw-bold'>_START_</span> to <span class='fw-bold'>_END_</span> of <span class='fw-bold'>_TOTAL_</span> entries",
|
||||
paginate: {
|
||||
first: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevrons-left" width="16" height="16"></i></span>',
|
||||
last: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevrons-right" width="16" height="16"></i></span>',
|
||||
next: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevron-right" width="16" height="16"></i></span>',
|
||||
previous: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevron-left" width="16" height="16"></i></span>'
|
||||
},
|
||||
zeroRecords: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="text-secondary mb-3"><i data-lucide="inbox" width="28" height="28" stroke-width="1.5"></i></div><h6 class="text-secondary fw-medium">No matching records found</h6></div>',
|
||||
emptyTable: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="text-secondary mb-3"><i data-lucide="inbox" width="28" height="28" stroke-width="1.5"></i></div><h6 class="text-secondary fw-medium">No data available</h6></div>'
|
||||
},
|
||||
dom: "<'row p-3'<'col-sm-12'tr>>" +
|
||||
"<'row px-3 pb-3 pt-1 align-items-center'<'col-sm-12 col-md-5 text-muted small'i><'col-sm-12 col-md-7 d-flex align-items-center justify-content-end gap-2'lp>>",
|
||||
initComplete: function() {
|
||||
// Initialize select2 with custom styling
|
||||
$('.dataTables_length select').select2({
|
||||
minimumResultsForSearch: Infinity,
|
||||
width: '80px',
|
||||
dropdownCssClass: 'small-select-dropdown',
|
||||
selectionCssClass: 'small-select-selection'
|
||||
});
|
||||
var table = $('#{{ $id }}').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
ajax: '{{ $ajax }}',
|
||||
columns: @json($dtColumns),
|
||||
orderCellsTop: true,
|
||||
fixedHeader: false,
|
||||
stateSave: true,
|
||||
pagingType: 'full_numbers',
|
||||
language: {
|
||||
loadingRecords: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="spinner-border text-primary mb-3" role="status"></div><h6 class="text-secondary fw-medium">Đang tải dữ liệu...</h6></div>',
|
||||
searchPlaceholder: "Tìm kiếm...",
|
||||
search: "",
|
||||
lengthMenu: "_MENU_",
|
||||
info: "Showing <span class='fw-bold'>_START_</span> to <span class='fw-bold'>_END_</span> of <span class='fw-bold'>_TOTAL_</span> entries",
|
||||
paginate: {
|
||||
first: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevrons-left" width="16" height="16"></i></span>',
|
||||
last: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevrons-right" width="16" height="16"></i></span>',
|
||||
next: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevron-right" width="16" height="16"></i></span>',
|
||||
previous: '<span class="d-flex align-items-center justify-content-center"><i data-lucide="chevron-left" width="16" height="16"></i></span>'
|
||||
},
|
||||
zeroRecords: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="text-secondary mb-3"><i data-lucide="inbox" width="28" height="28" stroke-width="1.5"></i></div><h6 class="text-secondary fw-medium">No matching records found</h6></div>',
|
||||
emptyTable: '<div class="d-flex flex-column align-items-center justify-content-center py-5"><div class="text-secondary mb-3"><i data-lucide="inbox" width="28" height="28" stroke-width="1.5"></i></div><h6 class="text-secondary fw-medium">No data available</h6></div>'
|
||||
},
|
||||
dom: "<'row p-3'<'col-sm-12'tr>>" +
|
||||
"<'row px-3 pb-3 pt-1 align-items-center'<'col-sm-12 col-md-5 text-muted small'i><'col-sm-12 col-md-7 d-flex align-items-center justify-content-end gap-2'lp>>",
|
||||
initComplete: function() {
|
||||
// Initialize select2 with custom styling
|
||||
$('.dataTables_length select').select2({
|
||||
minimumResultsForSearch: Infinity,
|
||||
width: '80px',
|
||||
dropdownCssClass: 'small-select-dropdown',
|
||||
selectionCssClass: 'small-select-selection'
|
||||
});
|
||||
|
||||
// Debounced search for column inputs (ERP Standard: Reduce server load)
|
||||
let searchTimeouts = {};
|
||||
this.api().columns().every(function() {
|
||||
var that = this;
|
||||
$('input', this.header()).on('keyup change clear', function() {
|
||||
const colIdx = that.index();
|
||||
const value = this.value;
|
||||
// Debounced search for column inputs (ERP Standard: Reduce server load)
|
||||
let searchTimeouts = {};
|
||||
this.api().columns().every(function() {
|
||||
var that = this;
|
||||
$('input', this.header()).on('keyup change clear', function() {
|
||||
const colIdx = that.index();
|
||||
const value = this.value;
|
||||
|
||||
clearTimeout(searchTimeouts[colIdx]);
|
||||
searchTimeouts[colIdx] = setTimeout(function() {
|
||||
if (that.search() !== value) {
|
||||
that.search(value).draw();
|
||||
}
|
||||
}, 400); // 400ms delay
|
||||
});
|
||||
});
|
||||
},
|
||||
drawCallback: function() {
|
||||
// Re-initialize Select2 on draw (if lost)
|
||||
if ($('.dataTables_length select').data('select2')) {
|
||||
$('.dataTables_length select').select2('destroy');
|
||||
}
|
||||
$('.dataTables_length select').select2({
|
||||
minimumResultsForSearch: Infinity,
|
||||
width: '80px'
|
||||
});
|
||||
clearTimeout(searchTimeouts[colIdx]);
|
||||
searchTimeouts[colIdx] = setTimeout(function() {
|
||||
if (that.search() !== value) {
|
||||
that.search(value).draw();
|
||||
}
|
||||
}, 400); // 400ms delay
|
||||
});
|
||||
});
|
||||
},
|
||||
drawCallback: function() {
|
||||
// Re-initialize Select2 on draw (if lost)
|
||||
if ($('.dataTables_length select').data('select2')) {
|
||||
$('.dataTables_length select').select2('destroy');
|
||||
}
|
||||
$('.dataTables_length select').select2({
|
||||
minimumResultsForSearch: Infinity,
|
||||
width: '80px'
|
||||
});
|
||||
|
||||
// Re-initialize icons with slight delay to ensuring DOM is ready
|
||||
setTimeout(function() {
|
||||
if (window.lucide) {
|
||||
lucide.createIcons();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
// Re-initialize icons with slight delay to ensuring DOM is ready
|
||||
setTimeout(function() {
|
||||
if (window.lucide) {
|
||||
lucide.createIcons();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
|
||||
// ERP Standard: Double click row to edit
|
||||
$('#{{ $id }} tbody').on('dblclick', 'tr', function() {
|
||||
// Try to find an edit link in the row
|
||||
const editLink = $(this).find('a.btn-outline-primary, a[href*="edit"]').first();
|
||||
if (editLink.length && editLink.attr('href')) {
|
||||
window.location.href = editLink.attr('href');
|
||||
}
|
||||
});
|
||||
// ERP Standard: Double click row to edit
|
||||
$('#{{ $id }} tbody').on('dblclick', 'tr', function() {
|
||||
// Try to find an edit link in the row
|
||||
const editLink = $(this).find('a.btn-outline-primary, a[href*="edit"]').first();
|
||||
if (editLink.length && editLink.attr('href')) {
|
||||
window.location.href = editLink.attr('href');
|
||||
}
|
||||
});
|
||||
|
||||
// Custom Loading Process Logic
|
||||
table.on('processing.dt', function(e, settings, processing) {
|
||||
const loadingEl = $('#{{ $id }}-loading');
|
||||
if (processing) {
|
||||
loadingEl.fadeIn(100);
|
||||
} else {
|
||||
loadingEl.fadeOut(200);
|
||||
}
|
||||
});
|
||||
// Custom Loading Process Logic
|
||||
table.on('processing.dt', function(e, settings, processing) {
|
||||
const loadingEl = $('#{{ $id }}-loading');
|
||||
if (processing) {
|
||||
loadingEl.fadeIn(100);
|
||||
} else {
|
||||
loadingEl.fadeOut(200);
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent sorting when clicking on the input
|
||||
$('#{{ $id }} thead tr:eq(1) th').on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
// Prevent sorting when clicking on the input
|
||||
$('#{{ $id }} thead tr:eq(1) th').on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// External trigger for column search (redundant but kept for manual binding if needed)
|
||||
$('#{{ $id }} .column-search').on('keyup change', function() {
|
||||
var columnIndex = $(this).data('column');
|
||||
table.column(columnIndex).search(this.value).draw();
|
||||
});
|
||||
});
|
||||
// External trigger for column search (redundant but kept for manual binding if needed)
|
||||
$('#{{ $id }} .column-search').on('keyup change', function() {
|
||||
var columnIndex = $(this).data('column');
|
||||
table.column(columnIndex).search(this.value).draw();
|
||||
});
|
||||
});
|
||||
|
||||
@if ($bulkDeleteUrl)
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tableId = '#{{ $id }}';
|
||||
const bulkActions = $('#{{ $id }}-bulk-actions');
|
||||
const deleteBtn = $('#{{ $id }}-bulk-delete-btn');
|
||||
const selectedCount = $('#{{ $id }}-selected-count');
|
||||
const masterCheckbox = $('#dt-master-checkbox');
|
||||
let selectedIds = [];
|
||||
@if ($bulkDeleteUrl)
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tableId = '#{{ $id }}';
|
||||
const bulkActions = $('#{{ $id }}-bulk-actions');
|
||||
const deleteBtn = $('#{{ $id }}-bulk-delete-btn');
|
||||
const selectedCount = $('#{{ $id }}-selected-count');
|
||||
const masterCheckbox = $('#dt-master-checkbox');
|
||||
let selectedIds = [];
|
||||
|
||||
// Handle Master Checkbox
|
||||
$(document).on('change', '#dt-master-checkbox', function() {
|
||||
const isChecked = $(this).is(':checked');
|
||||
$('.dt-checkbox').prop('checked', isChecked).trigger('change');
|
||||
});
|
||||
// Handle Master Checkbox
|
||||
$(document).on('change', '#dt-master-checkbox', function() {
|
||||
const isChecked = $(this).is(':checked');
|
||||
$('.dt-checkbox').prop('checked', isChecked).trigger('change');
|
||||
});
|
||||
|
||||
// Handle Individual Checkbox
|
||||
$(document).on('change', '.dt-checkbox', function() {
|
||||
const id = $(this).val();
|
||||
if ($(this).is(':checked')) {
|
||||
if (!selectedIds.includes(id)) selectedIds.push(id);
|
||||
} else {
|
||||
selectedIds = selectedIds.filter(item => item !== id);
|
||||
}
|
||||
// Handle Individual Checkbox
|
||||
$(document).on('change', '.dt-checkbox', function() {
|
||||
const id = $(this).val();
|
||||
if ($(this).is(':checked')) {
|
||||
if (!selectedIds.includes(id)) selectedIds.push(id);
|
||||
} else {
|
||||
selectedIds = selectedIds.filter(item => item !== id);
|
||||
}
|
||||
|
||||
// Update UI
|
||||
selectedCount.text(selectedIds.length);
|
||||
if (selectedIds.length > 0) {
|
||||
bulkActions.show();
|
||||
bulkActions.removeClass('d-none').addClass('d-flex');
|
||||
bulkActions.attr('style', ''); // Clear inline style
|
||||
} else {
|
||||
bulkActions.hide();
|
||||
}
|
||||
// Update UI
|
||||
selectedCount.text(selectedIds.length);
|
||||
if (selectedIds.length > 0) {
|
||||
bulkActions.show();
|
||||
bulkActions.removeClass('d-none').addClass('d-flex');
|
||||
bulkActions.attr('style', ''); // Clear inline style
|
||||
} else {
|
||||
bulkActions.hide();
|
||||
}
|
||||
|
||||
// Update Master Checkbox state
|
||||
const allCheckboxes = $('.dt-checkbox').length;
|
||||
const checkedCheckboxes = $('.dt-checkbox:checked').length;
|
||||
// Update Master Checkbox state
|
||||
const allCheckboxes = $('.dt-checkbox').length;
|
||||
const checkedCheckboxes = $('.dt-checkbox:checked').length;
|
||||
|
||||
if (allCheckboxes > 0 && allCheckboxes === checkedCheckboxes) {
|
||||
masterCheckbox.prop('checked', true);
|
||||
masterCheckbox.prop('indeterminate', false);
|
||||
} else if (checkedCheckboxes > 0) {
|
||||
masterCheckbox.prop('checked', false);
|
||||
masterCheckbox.prop('indeterminate', true);
|
||||
} else {
|
||||
masterCheckbox.prop('checked', false);
|
||||
masterCheckbox.prop('indeterminate', false);
|
||||
}
|
||||
});
|
||||
if (allCheckboxes > 0 && allCheckboxes === checkedCheckboxes) {
|
||||
masterCheckbox.prop('checked', true);
|
||||
masterCheckbox.prop('indeterminate', false);
|
||||
} else if (checkedCheckboxes > 0) {
|
||||
masterCheckbox.prop('checked', false);
|
||||
masterCheckbox.prop('indeterminate', true);
|
||||
} else {
|
||||
masterCheckbox.prop('checked', false);
|
||||
masterCheckbox.prop('indeterminate', false);
|
||||
}
|
||||
});
|
||||
|
||||
// Reset selection on table draw
|
||||
$('#{{ $id }}').on('draw.dt', function() {
|
||||
selectedIds = [];
|
||||
bulkActions.hide();
|
||||
masterCheckbox.prop('checked', false);
|
||||
masterCheckbox.prop('indeterminate', false);
|
||||
});
|
||||
// Reset selection on table draw
|
||||
$('#{{ $id }}').on('draw.dt', function() {
|
||||
selectedIds = [];
|
||||
bulkActions.hide();
|
||||
masterCheckbox.prop('checked', false);
|
||||
masterCheckbox.prop('indeterminate', false);
|
||||
});
|
||||
|
||||
// Handle Bulk Delete Opener
|
||||
const modalId = '{{ $id }}-bulk-delete-modal';
|
||||
const modalEl = document.getElementById(modalId);
|
||||
const openerBtn = $('#{{ $id }}-bulk-delete-opener-btn');
|
||||
const confirmBtn = $('#{{ $id }}-confirm-bulk-delete-btn');
|
||||
const countDisplay = $('#{{ $id }}-bulk-delete-count-display');
|
||||
let bsModal = null;
|
||||
// Handle Bulk Delete Opener
|
||||
const modalId = '{{ $id }}-bulk-delete-modal';
|
||||
const modalEl = document.getElementById(modalId);
|
||||
const openerBtn = $('#{{ $id }}-bulk-delete-opener-btn');
|
||||
const confirmBtn = $('#{{ $id }}-confirm-bulk-delete-btn');
|
||||
const countDisplay = $('#{{ $id }}-bulk-delete-count-display');
|
||||
let bsModal = null;
|
||||
|
||||
openerBtn.on('click', function() {
|
||||
if (selectedIds.length === 0) return;
|
||||
countDisplay.text(selectedIds.length);
|
||||
openerBtn.on('click', function() {
|
||||
if (selectedIds.length === 0) return;
|
||||
countDisplay.text(selectedIds.length);
|
||||
|
||||
if (!bsModal) {
|
||||
bsModal = new bootstrap.Modal(modalEl);
|
||||
}
|
||||
bsModal.show();
|
||||
});
|
||||
if (!bsModal) {
|
||||
bsModal = new bootstrap.Modal(modalEl);
|
||||
}
|
||||
bsModal.show();
|
||||
});
|
||||
|
||||
// Handle Confirm Delete
|
||||
confirmBtn.on('click', function() {
|
||||
$.ajax({
|
||||
url: '{{ $bulkDeleteUrl }}',
|
||||
type: 'DELETE',
|
||||
data: {
|
||||
ids: selectedIds,
|
||||
_token: '{{ csrf_token() }}'
|
||||
},
|
||||
beforeSend: function() {
|
||||
confirmBtn.prop('disabled', true).text('Deleting...');
|
||||
},
|
||||
success: function(response) {
|
||||
if (bsModal) bsModal.hide();
|
||||
$('#{{ $id }}').DataTable().ajax.reload();
|
||||
selectedIds = [];
|
||||
bulkActions.hide();
|
||||
// Handle Confirm Delete
|
||||
confirmBtn.on('click', function() {
|
||||
$.ajax({
|
||||
url: '{{ $bulkDeleteUrl }}',
|
||||
type: 'DELETE',
|
||||
data: {
|
||||
ids: selectedIds,
|
||||
_token: '{{ csrf_token() }}'
|
||||
},
|
||||
beforeSend: function() {
|
||||
confirmBtn.prop('disabled', true).text('Deleting...');
|
||||
},
|
||||
success: function(response) {
|
||||
if (bsModal) bsModal.hide();
|
||||
$('#{{ $id }}').DataTable().ajax.reload();
|
||||
selectedIds = [];
|
||||
bulkActions.hide();
|
||||
|
||||
// Show success toast
|
||||
if (typeof FuiToast !== 'undefined') {
|
||||
FuiToast.success(response.message ||
|
||||
'Selected items have been deleted successfully.');
|
||||
}
|
||||
// Show success toast
|
||||
if (typeof FuiToast !== 'undefined') {
|
||||
FuiToast.success(response.message ||
|
||||
'Selected items have been deleted successfully.');
|
||||
}
|
||||
|
||||
// Re-render icons after reload
|
||||
if (window.lucide) lucide.createIcons();
|
||||
},
|
||||
error: function(xhr) {
|
||||
const message = xhr.responseJSON?.message ||
|
||||
'Something went wrong.';
|
||||
if (typeof FuiToast !== 'undefined') {
|
||||
FuiToast.error(message);
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
if (bsModal) bsModal.hide();
|
||||
},
|
||||
complete: function() {
|
||||
confirmBtn.prop('disabled', false).text('Delete');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@endif
|
||||
</script>
|
||||
// Re-render icons after reload
|
||||
if (window.lucide) lucide.createIcons();
|
||||
},
|
||||
error: function(xhr) {
|
||||
const message = xhr.responseJSON?.message ||
|
||||
'Something went wrong.';
|
||||
if (typeof FuiToast !== 'undefined') {
|
||||
FuiToast.error(message);
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
if (bsModal) bsModal.hide();
|
||||
},
|
||||
complete: function() {
|
||||
confirmBtn.prop('disabled', false).text('Delete');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@endif
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Custom SAAS DataTable Styles */
|
||||
.data-table-wrapper {
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
}
|
||||
<style>
|
||||
/* Custom SAAS DataTable Styles */
|
||||
.data-table-wrapper {
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pagination button.page-link {
|
||||
height: 100%;
|
||||
}
|
||||
.pagination button.page-link {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.data-table-wrapper .table thead th {
|
||||
border-color: #f1f5f9 !important;
|
||||
font-family: 'Inter', sans-serif;
|
||||
vertical-align: middle;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background-color: #f8f9fa;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.data-table-wrapper .table thead th {
|
||||
border-color: #f1f5f9 !important;
|
||||
font-family: 'Inter', sans-serif;
|
||||
vertical-align: middle;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 3; {{-- Lowered from 10 --}}
|
||||
background-color: #f8f9fa;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* Sticky Action Column (ERP Standard for wide tables) */
|
||||
.table thead th:last-child,
|
||||
.table tbody td:last-child {
|
||||
position: sticky;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
z-index: 5;
|
||||
border-left: 1px solid #f1f5f9;
|
||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
/* Sticky Action Column (ERP Standard for wide tables) */
|
||||
.table thead th:last-child,
|
||||
.table tbody td:last-child {
|
||||
position: sticky;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
z-index: 2; {{-- Lowered from 5 --}}
|
||||
border-left: 1px solid #f1f5f9;
|
||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
.table thead th:last-child {
|
||||
background: #f8f9fa;
|
||||
z-index: 11;
|
||||
}
|
||||
.table thead th:last-child {
|
||||
background: #f8f9fa;
|
||||
z-index: 4; {{-- Lowered from 11 --}}
|
||||
}
|
||||
|
||||
/* Sticky Checkbox Column */
|
||||
.table thead th:first-child,
|
||||
.table tbody td:first-child {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
z-index: 5;
|
||||
border-right: 1px solid #f1f5f9;
|
||||
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
/* Sticky Checkbox Column */
|
||||
.table thead th:first-child,
|
||||
.table tbody td:first-child {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
z-index: 2; {{-- Lowered from 5 --}}
|
||||
border-right: 1px solid #f1f5f9;
|
||||
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
.table thead th:first-child {
|
||||
background: #f8f9fa;
|
||||
z-index: 11;
|
||||
}
|
||||
.table thead th:first-child {
|
||||
background: #f8f9fa;
|
||||
z-index: 4; {{-- Lowered from 11 --}}
|
||||
}
|
||||
|
||||
.table tbody tr:hover td {
|
||||
background-color: #f8fafc !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
.table tbody tr:hover td {
|
||||
background-color: #f8fafc !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.data-table-wrapper .table td:not(:last-child) {
|
||||
border-right: 1px solid #f1f5f9;
|
||||
}
|
||||
.data-table-wrapper .table td:not(:last-child) {
|
||||
border-right: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
/* Sticky for second row (filter inputs) if present */
|
||||
.data-table-wrapper .table thead tr:nth-child(2) th {
|
||||
top: 45px;
|
||||
/* Adjust based on typical header height */
|
||||
z-index: 4;
|
||||
}
|
||||
/* Sticky for second row (filter inputs) if present */
|
||||
.data-table-wrapper .table thead tr:nth-child(2) th {
|
||||
top: 45px;
|
||||
/* Adjust based on typical header height */
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.data-table-wrapper .input-group-text {
|
||||
color: #94a3b8;
|
||||
/* Slate 400 */
|
||||
}
|
||||
.data-table-wrapper .input-group-text {
|
||||
color: #94a3b8;
|
||||
/* Slate 400 */
|
||||
}
|
||||
|
||||
.data-table-wrapper .form-control::placeholder {
|
||||
color: #cbd5e1;
|
||||
/* Slate 300 */
|
||||
}
|
||||
.data-table-wrapper .form-control::placeholder {
|
||||
color: #cbd5e1;
|
||||
/* Slate 300 */
|
||||
}
|
||||
|
||||
.dataTables_wrapper .pagination .page-item .page-link {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
margin: 0 2px;
|
||||
color: #64748b;
|
||||
padding: 0;
|
||||
font-size: 0.875rem;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 38px;
|
||||
min-width: 38px;
|
||||
}
|
||||
.dataTables_wrapper .pagination .page-item .page-link {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
margin: 0 2px;
|
||||
color: #64748b;
|
||||
padding: 0;
|
||||
font-size: 0.875rem;
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 38px;
|
||||
min-width: 38px;
|
||||
}
|
||||
|
||||
.dataTables_wrapper .pagination .page-item.active .page-link {
|
||||
background-color: #0f172a;
|
||||
/* Slate 900 or Primary Color */
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
border-color: #0f172a;
|
||||
}
|
||||
.dataTables_wrapper .pagination .page-item.active .page-link {
|
||||
background-color: #0f172a;
|
||||
/* Slate 900 or Primary Color */
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
border-color: #0f172a;
|
||||
}
|
||||
|
||||
.dataTables_wrapper .pagination .page-item.disabled .page-link {
|
||||
color: #cbd5e1;
|
||||
background-color: transparent;
|
||||
}
|
||||
.dataTables_wrapper .pagination .page-item.disabled .page-link {
|
||||
color: #cbd5e1;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.dataTables_wrapper .pagination .page-item:not(.active) .page-link:hover {
|
||||
background-color: #f8fafc;
|
||||
color: #0f172a;
|
||||
border-color: #e2e8f0;
|
||||
}
|
||||
.dataTables_wrapper .pagination .page-item:not(.active) .page-link:hover {
|
||||
background-color: #f8fafc;
|
||||
color: #0f172a;
|
||||
border-color: #e2e8f0;
|
||||
}
|
||||
|
||||
/* Select2 Customization for Table Length */
|
||||
.dataTables_length {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
/* Select2 Customization for Table Length */
|
||||
.dataTables_length {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
}
|
||||
.select2-container--default .select2-selection--single {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single:focus {
|
||||
border-color: #94a3b8;
|
||||
}
|
||||
.select2-container--default .select2-selection--single:focus {
|
||||
border-color: #94a3b8;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 30px;
|
||||
}
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: #475569;
|
||||
font-size: 0.8125rem;
|
||||
padding-left: 10px;
|
||||
line-height: normal;
|
||||
}
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: #475569;
|
||||
font-size: 0.8125rem;
|
||||
padding-left: 10px;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/* Loading Process Styles */
|
||||
.loading-process {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* Loading Process Styles */
|
||||
.loading-process {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 5; {{-- Lowered from 1000 --}}
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.loading-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
background: #f1f5f9;
|
||||
overflow: hidden;
|
||||
z-index: 1001;
|
||||
}
|
||||
.loading-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
background: #f1f5f9;
|
||||
overflow: hidden;
|
||||
z-index: 6; {{-- Lowered from 1001 --}}
|
||||
}
|
||||
|
||||
.loading-bar::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
background: linear-gradient(90deg, transparent, #0f172a, transparent);
|
||||
animation: loading-process-info 1.5s infinite linear;
|
||||
}
|
||||
.loading-bar::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
background: linear-gradient(90deg, transparent, #0f172a, transparent);
|
||||
animation: loading-process-info 1.5s infinite linear;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(1px);
|
||||
}
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
backdrop-filter: blur(1px);
|
||||
}
|
||||
|
||||
@keyframes loading-process-info {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
@keyframes loading-process-info {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(200%);
|
||||
}
|
||||
}
|
||||
100% {
|
||||
transform: translateX(200%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Sort Icons Styles */
|
||||
.sort-icons {
|
||||
opacity: 0.15;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
/* Custom Sort Icons Styles */
|
||||
.sort-icons {
|
||||
opacity: 0.15;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
th:hover .sort-icons {
|
||||
opacity: 0.5;
|
||||
}
|
||||
th:hover .sort-icons {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
th.sorting_asc .sort-icons {
|
||||
opacity: 1;
|
||||
}
|
||||
th.sorting_asc .sort-icons {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
th.sorting_asc .sort-icon-desc {
|
||||
display: none !important;
|
||||
}
|
||||
th.sorting_asc .sort-icon-desc {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
th.sorting_desc .sort-icons {
|
||||
opacity: 1;
|
||||
}
|
||||
th.sorting_desc .sort-icons {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
th.sorting_desc .sort-icon-asc {
|
||||
display: none !important;
|
||||
}
|
||||
th.sorting_desc .sort-icon-asc {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide default DataTables icons */
|
||||
table.dataTable thead .sorting:before,
|
||||
table.dataTable thead .sorting:after,
|
||||
table.dataTable thead .sorting_asc:before,
|
||||
table.dataTable thead .sorting_asc:after,
|
||||
table.dataTable thead .sorting_desc:before,
|
||||
table.dataTable thead .sorting_desc:after {
|
||||
display: none !important;
|
||||
}
|
||||
/* Hide default DataTables icons */
|
||||
table.dataTable thead .sorting:before,
|
||||
table.dataTable thead .sorting:after,
|
||||
table.dataTable thead .sorting_asc:before,
|
||||
table.dataTable thead .sorting_asc:after,
|
||||
table.dataTable thead .sorting_desc:before,
|
||||
table.dataTable thead .sorting_desc:after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Processing Indicator with improved look - Centered */
|
||||
div.dataTables_processing {
|
||||
display: none !important;
|
||||
/* Hide default processing */
|
||||
}
|
||||
</style>
|
||||
/* Processing Indicator with improved look - Centered */
|
||||
div.dataTables_processing {
|
||||
display: none !important;
|
||||
/* Hide default processing */
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
Reference in New Issue
Block a user