Files
Verde-Web/resources/views/store/inventory.blade.php

132 lines
6.6 KiB
PHP

@extends('store.layouts.app', ['pageTitle' => 'Inventory', 'pageSubtitle' => 'Stock history and acquisitions'])
@section('page')
<div class="space-y-8">
{{-- Summary Cards --}}
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div class="rounded-xl border border-neutral-200 bg-white p-6 shadow-sm">
<p class="text-xs font-bold text-neutral-400 uppercase tracking-widest">Consignment Stock</p>
<p id="inv-balance" class="mt-1 text-3xl font-black text-neutral-900">...</p>
<p class="mt-2 text-xs text-neutral-500">Available codes (Consignment).</p>
</div>
<div class="rounded-xl border border-neutral-200 bg-white p-6 shadow-sm border-l-4 border-l-emerald-500">
<p class="text-xs font-bold text-neutral-400 uppercase tracking-widest text-emerald-600">Prepaid Stock</p>
<p id="inv-prepaid" class="mt-1 text-3xl font-black text-neutral-900">...</p>
<p class="mt-2 text-xs text-neutral-500">Available codes (Fully Paid).</p>
</div>
<div class="rounded-xl border border-neutral-200 bg-white p-6 shadow-sm">
<p class="text-xs font-bold text-neutral-400 uppercase tracking-widest">Total Acquired</p>
<p id="inv-total" class="mt-1 text-3xl font-black text-neutral-900">...</p>
<p class="mt-2 text-xs text-neutral-500">Total codes issued to your store by the LGU.</p>
</div>
</div>
{{-- History Table --}}
<div class="rounded-xl border border-neutral-200 bg-white shadow-sm overflow-hidden">
<div class="border-b border-neutral-100 px-6 py-4 bg-neutral-50/30">
<h3 class="font-semibold text-neutral-900">Inventory Logs</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left text-sm">
<thead>
<tr class="border-b border-neutral-100 bg-neutral-50/50 text-[10px] font-bold uppercase tracking-wider text-neutral-400">
<th class="px-6 py-3">Date</th>
<th class="px-6 py-3">Type</th>
<th class="px-6 py-3">Quantity</th>
<th class="px-6 py-3">Reason / Details</th>
<th class="px-6 py-3">Reference</th>
</tr>
</thead>
<tbody id="inventory-history-body" class="divide-y divide-neutral-100">
<tr>
<td colspan="5" class="px-6 py-8 text-center text-neutral-400">Loading history...</td>
</tr>
</tbody>
</table>
</div>
<div id="pagination" class="border-t border-neutral-100 px-6 py-4 bg-neutral-50/30 flex items-center justify-between">
<p id="pagination-info" class="text-xs text-neutral-500">Showing ... results</p>
<div class="flex gap-2">
<button id="prev-page" class="btn-ghost px-3 py-1.5 text-xs disabled:opacity-50">Previous</button>
<button id="next-page" class="btn-ghost px-3 py-1.5 text-xs disabled:opacity-50">Next</button>
</div>
</div>
</div>
</div>
<script type="module">
let currentPage = 1;
async function loadHistory(page = 1) {
try {
const res = await window.Verde.apiFetch(`/api/v1/store/inventory?page=${page}`);
const paginated = res.body?.data;
if (!paginated) return;
const logs = paginated.data;
const tbody = document.getElementById('inventory-history-body');
if (logs.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" class="px-6 py-8 text-center text-neutral-400">No inventory history found.</td></tr>';
} else {
tbody.innerHTML = logs.map(log => {
const isPositive = log.quantity > 0;
const qtyClass = isPositive ? 'text-emerald-600 font-bold' : 'text-red-600 font-bold';
const typeLabel = log.type.charAt(0).toUpperCase() + log.type.slice(1);
return `
<tr class="hover:bg-neutral-50/50 transition-colors">
<td class="px-6 py-4 text-xs text-neutral-500">${new Date(log.created_at).toLocaleString()}</td>
<td class="px-6 py-4">
<span class="rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-tight ${isPositive ? 'bg-emerald-50 text-emerald-700' : 'bg-red-50 text-red-700'}">
${typeLabel}
</span>
</td>
<td class="px-6 py-4 ${qtyClass}">${isPositive ? '+' : ''}${log.quantity}</td>
<td class="px-6 py-4 text-neutral-600">${log.reason || '-'}</td>
<td class="px-6 py-4 font-mono text-[10px] text-neutral-400">#${log.qr_code_id || 'BATCH'}</td>
</tr>
`;
}).join('');
}
document.getElementById('pagination-info').textContent = `Showing ${paginated.from || 0} to ${paginated.to || 0} of ${paginated.total} logs`;
document.getElementById('prev-page').disabled = !paginated.prev_page_url;
document.getElementById('next-page').disabled = !paginated.next_page_url;
currentPage = page;
if (window.lucide) window.lucide.createIcons();
} catch (e) {
console.error('Failed to load history', e);
}
}
async function loadSummary() {
const res = await window.Verde.apiFetch('/api/v1/store/dashboard');
const data = res.body?.data;
if (data) {
document.getElementById('inv-balance').textContent = data.inventory_balance;
document.getElementById('inv-prepaid').textContent = data.prepaid_balance;
}
// Calculate total acquired by summing positive adjustments
const histRes = await window.Verde.apiFetch('/api/v1/store/inventory?per_page=100');
const hist = histRes.body?.data;
if (hist) {
const total = hist.data.reduce((acc, log) => log.quantity > 0 ? acc + log.quantity : acc, 0);
document.getElementById('inv-total').textContent = total;
}
}
document.getElementById('prev-page').addEventListener('click', () => loadHistory(currentPage - 1));
document.getElementById('next-page').addEventListener('click', () => loadHistory(currentPage + 1));
document.addEventListener('DOMContentLoaded', () => {
loadSummary();
loadHistory();
});
</script>
@endsection