Add inventory type and edit popup

This commit is contained in:
2026-08-29 10:17:28 +03:00
parent 91cef24f68
commit ec69b8b3c2
3 changed files with 10 additions and 5 deletions
+9 -4
View File
@@ -72,10 +72,13 @@ function toast(message) { const element = $('#toast'); element.textContent = mes
function ensureTypeManager() {
if ($('#typeManagerModal')) return;
document.body.insertAdjacentHTML('beforeend', '<div class="modal-backdrop" id="typeManagerModal"><section class="modal type-manager"><div class="modal-header"><div><p class="eyebrow">Administration</p><h2>Inventory types</h2></div><button class="icon-button" id="closeTypeManager" aria-label="Close">×</button></div><form id="typeForm"><input id="editingTypeName" type="hidden"><div class="form-grid"><label class="full">Type name *<input id="typeName" required maxlength="80" placeholder="e.g. Camera"></label><div class="type-fields full" id="typeFields"></div></div><div class="form-actions"><button type="button" class="secondary-button" id="resetTypeForm">New type</button><button class="primary-button" type="submit">Save type</button></div></form><div class="type-list" id="typeList"></div></section></div>');
document.body.insertAdjacentHTML('beforeend', '<div class="modal-backdrop" id="typeManagerModal"><section class="modal type-manager"><div class="modal-header"><div><p class="eyebrow">Administration</p><h2>Inventory types</h2></div><button class="icon-button" id="closeTypeManager" aria-label="Close">×</button></div><div class="type-manager-actions"><button type="button" class="primary-button" id="newTypeButton">New type</button></div><div class="type-list" id="typeList"></div></section></div><div class="modal-backdrop type-editor-backdrop" id="typeEditorModal"><section class="modal type-editor"><div class="modal-header"><div><p class="eyebrow">Inventory type</p><h2 id="typeEditorTitle">New type</h2></div><button class="icon-button" id="closeTypeEditor" aria-label="Close">×</button></div><form id="typeForm"><input id="editingTypeName" type="hidden"><div class="form-grid"><label class="full">Type name *<input id="typeName" required maxlength="80" placeholder="e.g. Camera"></label><div class="type-fields full" id="typeFields"></div></div><div class="form-actions"><button type="button" class="secondary-button" id="cancelTypeEditor">Cancel</button><button class="primary-button" type="submit">Save type</button></div></form></section></div>');
$('#closeTypeManager').addEventListener('click', () => $('#typeManagerModal').classList.remove('open'));
$('#resetTypeForm').addEventListener('click', resetTypeForm);
$('#typeManagerModal').addEventListener('click', (event) => { if (event.target === $('#typeManagerModal')) $('#typeManagerModal').classList.remove('open'); });
$('#newTypeButton').addEventListener('click', () => openTypeEditor());
$('#closeTypeEditor').addEventListener('click', closeTypeEditor);
$('#cancelTypeEditor').addEventListener('click', closeTypeEditor);
$('#typeEditorModal').addEventListener('click', (event) => { if (event.target === $('#typeEditorModal')) closeTypeEditor(); });
$('#typeForm').addEventListener('submit', saveType);
$('#typeList').addEventListener('click', (event) => { const button = event.target.closest('[data-type-action]'); if (!button) return; const name = button.dataset.typeName; if (button.dataset.typeAction === 'edit') editType(name); if (button.dataset.typeAction === 'delete') removeType(name); });
}
@@ -85,9 +88,11 @@ function renderTypeManager() {
$('#typeList').innerHTML = state.types.map((type) => `<div class="type-row"><div><strong>${escapeHtml(type.name)}</strong><span>${type.fields.map((field) => escapeHtml(fieldLabels[field])).join(', ') || 'Name, type, and status only'}</span></div><div class="row-actions"><button class="small-action" type="button" data-type-action="edit" data-type-name="${escapeHtml(type.name)}">Edit</button><button class="small-action delete" type="button" data-type-action="delete" data-type-name="${escapeHtml(type.name)}">Delete</button></div></div>`).join('');
}
async function openTypeManager() { ensureTypeManager(); await loadTypes(); resetTypeForm(); renderTypeManager(); $('#typeManagerModal').classList.add('open'); }
function editType(name) { const type = state.types.find((entry) => entry.name === name); if (!type) return; $('#editingTypeName').value = type.name; $('#typeName').value = type.name; document.querySelectorAll('[name="type_field"]').forEach((field) => { field.checked = type.fields.includes(field.value); }); }
function closeTypeEditor() { $('#typeEditorModal').classList.remove('open'); }
function openTypeEditor(type = null) { resetTypeForm(); $('#typeEditorTitle').textContent = type ? 'Edit type' : 'New type'; $('#typeFields').innerHTML = `<span>Fields shown for this type</span><div class="field-checklist">${Object.entries(fieldLabels).map(([key, label]) => `<label><input type="checkbox" name="type_field" value="${key}">${label}</label>`).join('')}</div>`; if (type) { $('#editingTypeName').value = type.name; $('#typeName').value = type.name; document.querySelectorAll('[name="type_field"]').forEach((field) => { field.checked = type.fields.includes(field.value); }); } $('#typeEditorModal').classList.add('open'); $('#typeName').focus(); }
function editType(name) { const type = state.types.find((entry) => entry.name === name); if (type) openTypeEditor(type); }
async function removeType(name) { if (!confirm(`Delete the "${name}" inventory type?`)) return; try { await request(`/api/types/${encodeURIComponent(name)}`, { method: 'DELETE' }); await loadTypes(); renderTypeManager(); toast('Inventory type deleted.'); } catch (error) { toast(error.message); } }
async function saveType(event) { event.preventDefault(); const previousName = $('#editingTypeName').value; const fields = [...document.querySelectorAll('[name="type_field"]:checked')].map((field) => field.value); try { await request(previousName ? `/api/types/${encodeURIComponent(previousName)}` : '/api/types', { method: previousName ? 'PUT' : 'POST', body: JSON.stringify({ name: $('#typeName').value, fields }) }); await loadTypes(); renderTypeManager(); resetTypeForm(); toast('Inventory type saved.'); } catch (error) { toast(error.message); } }
async function saveType(event) { event.preventDefault(); const previousName = $('#editingTypeName').value; const fields = [...document.querySelectorAll('[name="type_field"]:checked')].map((field) => field.value); try { await request(previousName ? `/api/types/${encodeURIComponent(previousName)}` : '/api/types', { method: previousName ? 'PUT' : 'POST', body: JSON.stringify({ name: $('#typeName').value, fields }) }); await loadTypes(); renderTypeManager(); closeTypeEditor(); toast('Inventory type saved.'); } catch (error) { toast(error.message); } }
window.editItem = (id) => openModal(state.items.find((item) => item.id === id));
window.deleteImage = async (imageId) => { if (!state.editingId || !confirm('Delete this picture?')) return; try { const item = await request(`/api/items/${state.editingId}/images/${imageId}`, { method: 'DELETE' }); renderImageGallery(item.images); $('#imageName').textContent = `${item.images.length} saved picture${item.images.length === 1 ? '' : 's'}. Add more below.`; state.items = state.items.map((entry) => entry.id === item.id ? item : entry); renderItems(state.items); toast('Picture deleted.'); } catch (error) { toast(error.message); } };