Status Updated

This commit is contained in:
Utkarsh Khedkar
2026-03-12 18:11:43 +05:30
parent bb2a361a97
commit 5d8a746876
18 changed files with 421 additions and 176 deletions

View File

@@ -640,6 +640,24 @@
/* ── DIVIDER ── */
.section-divider { height: 1px; background: var(--border); margin: 0 2.5rem; }
.pagination .page-link {
border-radius: 6px;
border: 1px solid #e5e7eb;
padding: 4px 10px;
font-size: 0.78rem;
color: #111827;
}
.pagination .page-item.active .page-link {
background-color: #111827;
border-color: #111827;
color: #ffffff;
}
.pagination .page-item.disabled .page-link {
background-color: #f3f4f6;
color: #9ca3af;
border-color: #e5e7eb;
}
</style>
</head>
<body>
@@ -781,89 +799,125 @@
@endphp
<div class="panel">
<div class="panel-header">
<i class="fas fa-list"></i> Invoice Items
<div class="panel-header">
<i class="fas fa-list"></i> Invoice Items
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="invoice-table items-table">
<thead>
<tr>
<th class="text-center" style="width:44px;">
<input type="checkbox" id="selectAllItems">
</th>
<th class="text-center" style="min-width:50px;">#</th>
<th style="min-width:200px;">Description</th>
<th class="text-center" style="min-width:75px;">CTN</th>
<th class="text-center" style="min-width:75px;">QTY</th>
<th class="text-center" style="min-width:95px;">TTL/QTY</th>
<th class="text-center" style="min-width:75px;">Unit</th>
<th class="text-center" style="min-width:110px;">Price</th>
<th class="text-center" style="min-width:125px;">TTL Amount</th>
<th class="text-center" style="min-width:85px;">CBM</th>
<th class="text-center" style="min-width:95px;">TTL CBM</th>
<th class="text-center" style="min-width:80px;">KG</th>
<th class="text-center" style="min-width:95px;">TTL KG</th>
<th class="text-center" style="min-width:95px;">Shop No</th>
</tr>
</thead>
<tbody id="itemsTableBody">
@foreach($invoice->items as $i => $item)
@php
$alreadyGrouped = in_array($item->id, $groupedItemIds ?? []);
@endphp
<tr class="{{ $alreadyGrouped ? 'grouped-item-row' : '' }}">
<td class="text-center">
<input type="checkbox"
class="item-select-checkbox"
name="item_ids[]"
value="{{ $item->id }}"
{{ $alreadyGrouped ? 'disabled' : '' }}>
</td>
<td class="text-center" style="font-weight:600;color:var(--text-muted);">
{{ $i + 1 }}
</td>
<td class="desc-col" style="font-weight:600;color:var(--primary);">
{{ $item->description }}
</td>
<td class="text-center">{{ $item->ctn }}</td>
<td class="text-center">{{ $item->qty }}</td>
<td class="text-center" style="font-weight:700;">{{ $item->ttl_qty }}</td>
<td class="text-center">{{ $item->unit }}</td>
@if($isEmbedded)
<td class="text-center" style="min-width:120px;">
<input type="number" step="0.01" min="0"
name="items[{{ $item->id }}][price]"
value="{{ old('items.' . $item->id . '.price', $item->price) }}"
class="form-control form-control-sm text-end">
</td>
<td class="text-center" style="min-width:140px;">
<input type="number" step="0.01" min="0"
name="items[{{ $item->id }}][ttl_amount]"
value="{{ old('items.' . $item->id . '.ttl_amount', $item->ttl_amount) }}"
class="form-control form-control-sm text-end">
</td>
@else
<td class="text-center price-green">
{{ number_format($item->price, 2) }}
</td>
<td class="text-center price-blue">
{{ number_format($item->ttl_amount, 2) }}
</td>
@endif
<td class="text-center">{{ $item->cbm }}</td>
<td class="text-center">{{ $item->ttl_cbm }}</td>
<td class="text-center">{{ $item->kg }}</td>
<td class="text-center">{{ $item->ttl_kg }}</td>
<td class="text-center">
<span class="badge-shop">{{ $item->shop_no }}</span>
</td>
</tr>
@endforeach
@if($invoice->items->isEmpty())
<tr>
<td colspan="15" class="text-center py-4"
style="color:var(--text-muted);font-weight:600;">
<i class="fas fa-inbox me-2"
style="font-size:1.3rem;opacity:.4;"></i><br>
No invoice items found.
</td>
</tr>
@endif
</tbody>
</table>
</div>
<div class="table-responsive">
<table class="invoice-table items-table">
<thead>
<tr>
<th class="text-center" style="width:44px;">
<input type="checkbox" id="selectAllItems">
</th>
<th class="text-center" style="min-width:50px;">#</th>
<th style="min-width:200px;">Description</th>
<th class="text-center" style="min-width:75px;">CTN</th>
<th class="text-center" style="min-width:75px;">QTY</th>
<th class="text-center" style="min-width:95px;">TTL/QTY</th>
<th class="text-center" style="min-width:75px;">Unit</th>
<th class="text-center" style="min-width:110px;">Price</th>
<th class="text-center" style="min-width:125px;">TTL Amount</th>
<th class="text-center" style="min-width:85px;">CBM</th>
<th class="text-center" style="min-width:95px;">TTL CBM</th>
<th class="text-center" style="min-width:80px;">KG</th>
<th class="text-center" style="min-width:95px;">TTL KG</th>
<th class="text-center" style="min-width:95px;">Shop No</th>
</tr>
</thead>
<tbody>
@foreach($invoice->items as $i => $item)
@php
$alreadyGrouped = in_array($item->id, $groupedItemIds ?? []);
@endphp
<tr class="{{ $alreadyGrouped ? 'grouped-item-row' : '' }}">
<td class="text-center">
<input type="checkbox"
class="item-select-checkbox"
name="item_ids[]"
value="{{ $item->id }}"
{{ $alreadyGrouped ? 'disabled' : '' }}>
</td>
<td class="text-center" style="font-weight:600;color:var(--text-muted);">{{ $i + 1 }}</td>
<td class="desc-col" style="font-weight:600;color:var(--primary);">{{ $item->description }}</td>
<td class="text-center">{{ $item->ctn }}</td>
<td class="text-center">{{ $item->qty }}</td>
<td class="text-center" style="font-weight:700;">{{ $item->ttl_qty }}</td>
<td class="text-center">{{ $item->unit }}</td>
{{-- Items pagination bar --}}
<div class="d-flex justify-content-between align-items-center mt-2"
id="itemsPaginationBar"
style="font-size:0.8rem;">
<div>
Showing <span id="itemsStart">0</span> to
<span id="itemsEnd">0</span> of
<span id="itemsTotal">0</span> items
</div>
@if($isEmbedded)
<td class="text-center" style="min-width:120px;">
<input type="number" step="0.01" min="0"
name="items[{{ $item->id }}][price]"
value="{{ old('items.' . $item->id . '.price', $item->price) }}"
class="form-control form-control-sm text-end">
</td>
<td class="text-center" style="min-width:140px;">
<input type="number" step="0.01" min="0"
name="items[{{ $item->id }}][ttl_amount]"
value="{{ old('items.' . $item->id . '.ttl_amount', $item->ttl_amount) }}"
class="form-control form-control-sm text-end">
</td>
@else
<td class="text-center price-green">{{ number_format($item->price, 2) }}</td>
<td class="text-center price-blue">{{ number_format($item->ttl_amount, 2) }}</td>
@endif
<nav aria-label="Items pagination">
<ul class="pagination mb-0 pagination-sm" id="itemsPages">
{{-- JS will render buttons here --}}
</ul>
</nav>
</div>
<td class="text-center">{{ $item->cbm }}</td>
<td class="text-center">{{ $item->ttl_cbm }}</td>
<td class="text-center">{{ $item->kg }}</td>
<td class="text-center">{{ $item->ttl_kg }}</td>
<td class="text-center"><span class="badge-shop">{{ $item->shop_no }}</span></td>
</tr>
@endforeach
@if($invoice->items->isEmpty())
<tr>
<td colspan="15" class="text-center py-4" style="color:var(--text-muted);font-weight:600;">
<i class="fas fa-inbox me-2" style="font-size:1.3rem;opacity:.4;"></i><br>No invoice items found.
</td>
</tr>
@endif
</tbody>
</table>
</div>
</div>
</div>
<!-- ACTION BAR -->
<div class="action-bar">
<small>Selected items for charge group: <span id="selectedItemsCount">0</span></small>
@@ -1671,8 +1725,7 @@ document.addEventListener('DOMContentLoaded', function () {
: '<i class="fas fa-eye-slash"></i> Hide';
});
});
// simple select all (duplicate राहिला तरी harmless)
// "Select All" checkbox logic
document.addEventListener('DOMContentLoaded', function () {
const selectAll = document.getElementById('selectAllItems');
const checkboxes = document.querySelectorAll('.item-select-checkbox');
@@ -1687,6 +1740,113 @@ document.addEventListener('DOMContentLoaded', function () {
});
}
});
// Items table pagination logic edit blade
document.addEventListener('DOMContentLoaded', function () {
// ====== ITEMS TABLE PAGINATION (50 per page, numbered) ======
const itemsPerPage = 50;
const itemsTbody = document.getElementById('itemsTableBody');
const allItemRows = itemsTbody ? Array.from(itemsTbody.querySelectorAll('tr')) : [];
const itemsStart = document.getElementById('itemsStart');
const itemsEnd = document.getElementById('itemsEnd');
const itemsTotal = document.getElementById('itemsTotal');
const itemsPages = document.getElementById('itemsPages');
const itemsBar = document.getElementById('itemsPaginationBar');
let itemsCurrentPage = 1;
if (allItemRows.length) {
// data rows
const dataRows = allItemRows.filter(row => !row.querySelector('td[colspan]'));
const total = dataRows.length;
const totalPages = Math.max(1, Math.ceil(total / itemsPerPage));
if (itemsTotal) itemsTotal.textContent = total;
function renderItemsPage() {
if (!total) {
allItemRows.forEach(r => r.style.display = '');
if (itemsStart) itemsStart.textContent = 0;
if (itemsEnd) itemsEnd.textContent = 0;
if (itemsPages) itemsPages.innerHTML = '';
return;
}
const startIndex = (itemsCurrentPage - 1) * itemsPerPage;
const endIndex = Math.min(startIndex + itemsPerPage, total);
dataRows.forEach((row, idx) => {
row.style.display = (idx >= startIndex && idx < endIndex) ? '' : 'none';
});
// "no items" row hide
allItemRows.forEach(row => {
const td = row.querySelector('td[colspan]');
if (td) row.style.display = 'none';
});
if (itemsStart) itemsStart.textContent = startIndex + 1;
if (itemsEnd) itemsEnd.textContent = endIndex;
// pagination buttons: 1 2 …
if (itemsPages) {
itemsPages.innerHTML = '';
// prev
const prevLi = document.createElement('li');
prevLi.className = 'page-item' + (itemsCurrentPage === 1 ? ' disabled' : '');
prevLi.innerHTML = '<button class="page-link" type="button" aria-label="Previous"></button>';
if (itemsCurrentPage > 1) {
prevLi.querySelector('button').addEventListener('click', () => {
itemsCurrentPage--;
renderItemsPage();
});
}
itemsPages.appendChild(prevLi);
// page numbers
for (let p = 1; p <= totalPages; p++) {
const li = document.createElement('li');
li.className = 'page-item' + (p === itemsCurrentPage ? ' active' : '');
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'page-link';
btn.textContent = p;
if (p !== itemsCurrentPage) {
btn.addEventListener('click', () => {
itemsCurrentPage = p;
renderItemsPage();
});
}
li.appendChild(btn);
itemsPages.appendChild(li);
}
// next
const nextLi = document.createElement('li');
nextLi.className = 'page-item' + (itemsCurrentPage === totalPages ? ' disabled' : '');
nextLi.innerHTML = '<button class="page-link" type="button" aria-label="Next"></button>';
if (itemsCurrentPage < totalPages) {
nextLi.querySelector('button').addEventListener('click', () => {
itemsCurrentPage++;
renderItemsPage();
});
}
itemsPages.appendChild(nextLi);
}
}
renderItemsPage();
} else if (itemsBar) {
itemsBar.style.display = 'none';
}
});
</script>