Added fix price etc to inv items
This commit is contained in:
+3
-6
@@ -10,13 +10,10 @@ async function request(url, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
const query = new URLSearchParams({ q: $('#searchInput').value, type: $('#typeFilter').value, status: $('#statusFilter').value });
|
const query = new URLSearchParams({ q: $('#searchInput').value, type: $('#typeFilter').value });
|
||||||
const [items, summary] = await Promise.all([request(`/api/items?${query}`), request('/api/summary')]);
|
const [items, summary] = await Promise.all([request(`/api/items?${query}`), request('/api/summary')]);
|
||||||
state.items = items;
|
state.items = items;
|
||||||
$('#totalCount').textContent = summary.total;
|
$('#totalCount').textContent = summary.total;
|
||||||
$('#availableCount').textContent = summary.available;
|
|
||||||
$('#trashedCount').textContent = summary.trashed;
|
|
||||||
$('#soldCount').textContent = summary.sold;
|
|
||||||
$('#resultCount').textContent = `${items.length} ${items.length === 1 ? 'item' : 'items'}`;
|
$('#resultCount').textContent = `${items.length} ${items.length === 1 ? 'item' : 'items'}`;
|
||||||
renderItems(items);
|
renderItems(items);
|
||||||
}
|
}
|
||||||
@@ -24,7 +21,7 @@ async function load() {
|
|||||||
function renderItems(items) {
|
function renderItems(items) {
|
||||||
const body = $('#inventoryBody');
|
const body = $('#inventoryBody');
|
||||||
$('#emptyState').style.display = items.length ? 'none' : 'block';
|
$('#emptyState').style.display = items.length ? 'none' : 'block';
|
||||||
body.innerHTML = items.map((item) => `<tr class="inventory-row"><td><div class="item-cell">${item.images?.length ? `<img class="item-thumb" src="${escapeHtml(item.images[0].url)}" alt="">${item.images.length > 1 ? `<span class="image-count">+${item.images.length - 1}</span>` : ''}` : '<div class="item-thumb placeholder">◌</div>'}<div><span class="item-title">${escapeHtml(item.name)}</span><span class="item-sub">${escapeHtml([item.brand, item.model].filter(Boolean).join(' · ') || 'No manufacturer details')}</span></div></div></td><td><span class="type-pill">${escapeHtml(item.item_type)}</span></td><td><span class="identifier">${escapeHtml(item.serial_number || 'No serial')}<em>${escapeHtml(item.asset_tag || 'No asset tag')}</em></span></td><td><span class="location">${escapeHtml(item.location || 'Unassigned')}<em>${escapeHtml(item.destination ? `Went to: ${item.destination}` : '')}</em></span></td><td><span class="status ${item.status.toLowerCase().replace(' ', '-')}">${escapeHtml(item.status)}</span><em class="price">${item.price != null ? escapeHtml(Number(item.price).toFixed(2)) : ''}</em></td><td><div class="row-actions"><button class="small-action" onclick="editItem(${item.id})">Edit</button><button class="small-action delete" onclick="removeItem(${item.id})">Delete</button></div></td></tr>`).join('');
|
body.innerHTML = items.map((item) => `<tr class="inventory-row"><td><div class="item-cell">${item.images?.length ? `<img class="item-thumb" src="${escapeHtml(item.images[0].url)}" alt="">${item.images.length > 1 ? `<span class="image-count">+${item.images.length - 1}</span>` : ''}` : '<div class="item-thumb placeholder">◌</div>'}<div><span class="item-title">${escapeHtml(item.name)}</span><span class="item-sub">${escapeHtml([item.brand, item.model].filter(Boolean).join(' · ') || 'No manufacturer details')}</span></div></div></td><td><span class="type-pill">${escapeHtml(item.item_type)}</span></td><td><span class="identifier">${escapeHtml(item.serial_number || 'No serial')}<em>${escapeHtml(item.asset_tag || 'No asset tag')}</em></span></td><td><span class="location">${escapeHtml(item.location || 'Unassigned')}</span></td><td><div class="row-actions"><button class="small-action" onclick="editItem(${item.id})">Edit</button><button class="small-action delete" onclick="removeItem(${item.id})">Delete</button></div></td></tr>`).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(value) { return String(value).replace(/[&<>'"]/g, (char) => ({ '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' }[char])); }
|
function escapeHtml(value) { return String(value).replace(/[&<>'"]/g, (char) => ({ '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' }[char])); }
|
||||||
@@ -43,7 +40,7 @@ $('#emptyAddButton').addEventListener('click', () => openModal());
|
|||||||
$('#closeModal').addEventListener('click', closeModal);
|
$('#closeModal').addEventListener('click', closeModal);
|
||||||
$('#cancelButton').addEventListener('click', closeModal);
|
$('#cancelButton').addEventListener('click', closeModal);
|
||||||
$('#modal').addEventListener('click', (event) => { if (event.target === $('#modal')) closeModal(); });
|
$('#modal').addEventListener('click', (event) => { if (event.target === $('#modal')) closeModal(); });
|
||||||
['searchInput', 'typeFilter', 'statusFilter'].forEach((id) => $(`#${id}`).addEventListener(id === 'searchInput' ? 'input' : 'change', load));
|
['searchInput', 'typeFilter'].forEach((id) => $(`#${id}`).addEventListener(id === 'searchInput' ? 'input' : 'change', load));
|
||||||
ensureImageControls();
|
ensureImageControls();
|
||||||
$('#imageInput').addEventListener('change', () => { const files = [...$('#imageInput').files]; $('#imageName').textContent = files.length ? `${files.length} new picture${files.length === 1 ? '' : 's'} selected` : 'Up to 5 pictures'; });
|
$('#imageInput').addEventListener('change', () => { const files = [...$('#imageInput').files]; $('#imageName').textContent = files.length ? `${files.length} new picture${files.length === 1 ? '' : 's'} selected` : 'Up to 5 pictures'; });
|
||||||
$('#itemForm').addEventListener('submit', async (event) => { event.preventDefault(); const formData = new FormData(event.target); if (!$('#imageInput').files.length) formData.delete('images'); try { await request(state.editingId ? `/api/items/${state.editingId}` : '/api/items', { method: state.editingId ? 'PUT' : 'POST', body: formData }); closeModal(); toast(state.editingId ? 'Item updated.' : 'Item added to inventory.'); await load(); } catch (error) { toast(error.message); } });
|
$('#itemForm').addEventListener('submit', async (event) => { event.preventDefault(); const formData = new FormData(event.target); if (!$('#imageInput').files.length) formData.delete('images'); try { await request(state.editingId ? `/api/items/${state.editingId}` : '/api/items', { method: state.editingId ? 'PUT' : 'POST', body: formData }); closeModal(); toast(state.editingId ? 'Item updated.' : 'Item added to inventory.'); await load(); } catch (error) { toast(error.message); } });
|
||||||
|
|||||||
@@ -20,14 +20,11 @@
|
|||||||
<header class="topbar"><div><p class="eyebrow">Operations / Stockroom</p><h1>Inventory</h1></div><button class="primary-button" id="addButton"><span>+</span> Add item</button></header>
|
<header class="topbar"><div><p class="eyebrow">Operations / Stockroom</p><h1>Inventory</h1></div><button class="primary-button" id="addButton"><span>+</span> Add item</button></header>
|
||||||
<section class="stats-grid">
|
<section class="stats-grid">
|
||||||
<article class="stat-card accent"><div class="stat-label">Total assets <span class="stat-symbol">◉</span></div><strong id="totalCount">0</strong><small>Across all categories</small></article>
|
<article class="stat-card accent"><div class="stat-label">Total assets <span class="stat-symbol">◉</span></div><strong id="totalCount">0</strong><small>Across all categories</small></article>
|
||||||
<article class="stat-card"><div class="stat-label">Available <span class="stat-symbol green">●</span></div><strong id="availableCount">0</strong><small>Ready to use</small></article>
|
|
||||||
<article class="stat-card"><div class="stat-label">Trashed <span class="stat-symbol amber">●</span></div><strong id="trashedCount">0</strong><small>Removed from stock</small></article>
|
|
||||||
<article class="stat-card"><div class="stat-label">Sold <span class="stat-symbol red">●</span></div><strong id="soldCount">0</strong><small>Transferred or sold</small></article>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="inventory-panel">
|
<section class="inventory-panel">
|
||||||
<div class="panel-heading"><div><h2>All inventory</h2><p>Search, filter, and manage every item in your stockroom.</p></div><span class="item-count" id="resultCount">0 items</span></div>
|
<div class="panel-heading"><div><h2>All inventory</h2><p>Search, filter, and manage every item in your stockroom.</p></div><span class="item-count" id="resultCount">0 items</span></div>
|
||||||
<div class="toolbar"><label class="search-box"><span>⌕</span><input id="searchInput" type="search" placeholder="Search name, serial, model..." autocomplete="off"></label><select id="typeFilter"><option value="">All types</option><option>Computer</option><option>Audio</option><option>Graphics</option><option>Long play disk</option><option>CD</option><option>Display</option><option>Peripheral</option><option>Other</option></select><select id="statusFilter"><option value="">All status</option><option>Available</option><option>Trashed</option><option>Sold</option></select></div>
|
<div class="toolbar"><label class="search-box"><span>⌕</span><input id="searchInput" type="search" placeholder="Search name, serial, model..." autocomplete="off"></label><select id="typeFilter"><option value="">All types</option><option>Computer</option><option>Audio</option><option>Graphics</option><option>Long play disk</option><option>CD</option><option>Display</option><option>Peripheral</option><option>Other</option></select></div>
|
||||||
<div class="table-wrap"><table><thead><tr><th>Item</th><th>Type</th><th>Identifiers</th><th>Location</th><th>Status</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody id="inventoryBody"></tbody></table><div class="empty-state" id="emptyState"><div class="empty-icon">⌁</div><h3>No items found</h3><p>Adjust your search or add the first item to your inventory.</p><button class="secondary-button" id="emptyAddButton">Add first item</button></div></div>
|
<div class="table-wrap"><table><thead><tr><th>Item</th><th>Type</th><th>Identifiers</th><th>Location</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody id="inventoryBody"></tbody></table><div class="empty-state" id="emptyState"><div class="empty-icon">⌁</div><h3>No items found</h3><p>Adjust your search or add the first item to your inventory.</p><button class="secondary-button" id="emptyAddButton">Add first item</button></div></div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user