{% extends "layout.html" %} {% block title %}{{ title }}{% endblock %} {% block content %}
{{ breadcrumbs.breadcrumb_header( title=title, save_button=True ) }}
Inventory Settings
{{ combos.render_combobox( id='brand', options=brands, label='Brands', placeholder='Add a new brand' ) }}
{{ combos.render_combobox( id='type', options=types, label='Inventory Types', placeholder='Add a new type' ) }}
Location Settings
{{ combos.render_combobox( id='section', options=sections, label='Sections', placeholder='Add a new section' ) }}
{{ combos.render_combobox( id='function', options=functions, label='Functions', placeholder='Add a new function' ) }}
{% set room_editor %} const roomEditorModal = new bootstrap.Modal(document.getElementById('roomEditor')); const input = document.getElementById('room-input'); const name = input.value.trim(); const existingOption = Array.from(document.getElementById('room-list').options) .find(opt => opt.textContent.trim() === name); const event = new CustomEvent('roomEditor:prepare', { detail: { id: existingOption?.value ?? '', name: name, sectionId: existingOption?.dataset.sectionId ?? '', functionId: existingOption?.dataset.functionId ?? '' } }); document.getElementById('roomEditor').dispatchEvent(event); roomEditorModal.show(); document.getElementById('room-input').value = ''; {% endset %}
{{ combos.render_combobox( id='room', options=rooms, label='Rooms', placeholder='Add a new room', onAdd=room_editor, onEdit=room_editor, data_attributes={'area_id': 'section-id', 'function_id': 'function-id'} ) }}
{% endblock %} {% block script %} function isSerializable(obj) { try { JSON.stringify(obj); return true; } catch { return false; } } function buildFormState() { function extractOptions(id) { const select = document.getElementById(`${id}-list`); return Array.from(select.options).map(opt => { const name = opt.textContent.trim(); const rawId = opt.value?.trim(); return { name, ...(rawId ? { id: /^\d+$/.test(rawId) ? parseInt(rawId, 10) : rawId } : {}) }; }); } function sanitizeFk(val) { if (val && val !== "null" && val !== "" && val !== "None") { return /^\d+$/.test(val) ? parseInt(val, 10) : val; } return null; } const roomOptions = Array.from(document.getElementById('room-list').options); const rooms = roomOptions.map(opt => { const id = opt.value?.trim(); const name = opt.textContent.trim(); const sectionId = sanitizeFk(opt.dataset.sectionId); const functionId = sanitizeFk(opt.dataset.functionId); const result = { name, ...(id ? { id } : {}), section_id: sectionId, function_id: functionId }; return result; }); return { brands: extractOptions("brand"), types: extractOptions("type"), sections: extractOptions("section"), functions: extractOptions("function"), rooms }; } const modal = document.getElementById('roomEditor'); const saveButton = document.getElementById('saveButton') const editorSaveButton = document.getElementById('editorSaveButton'); const cancelButton = document.getElementById('roomEditorCancelButton'); const form = document.getElementById('settingsForm'); modal.addEventListener('roomEditor:prepare', (event) => { const { id, name, sectionId, functionId } = event.detail; document.getElementById('roomId').value = id; document.getElementById('roomName').value = name; // Populate dropdowns before assigning selection const modalSections = document.getElementById('roomSection'); const modalFunctions = document.getElementById('roomFunction'); const pageSections = document.getElementById('section-list'); const pageFunctions = document.getElementById('function-list'); modalSections.innerHTML = ''; modalFunctions.innerHTML = ''; Array.from(pageSections.options).forEach(opt => { const option = new Option(opt.textContent, opt.value); if (opt.value === sectionId) { option.selected = true; } modalSections.appendChild(option); }); Array.from(pageFunctions.options).forEach(opt => { const option = new Option(opt.textContent, opt.value); if (opt.value === functionId) { option.selected = true; } modalFunctions.appendChild(option); }); }); saveButton.addEventListener('click', async (event) => { event.preventDefault(); console.log("Test") const state = buildFormState(); if (!isSerializable(state)) { console.warn("🚨 Payload is not serializable:", state); alert("Invalid payload — check console."); return; } try { const response = await fetch('/api/settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(state) }); const contentType = response.headers.get("content-type"); if (!response.ok) { if (contentType && contentType.includes("application/json")) { const data = await response.json(); throw new Error(data.errors?.join("\n") || "Unknown error"); } else { const text = await response.text(); throw new Error("Unexpected response:\n" + text.slice(0, 200)); } } const data = await response.json(); console.log("Sync result:", data); renderToast({ message: 'Settings updated successfully.', type: 'success' }); } catch (err) { console.error("Submission error:", err); renderToast({ message: `Failed to update settings, ${err}`, type: 'danger' }); } }); editorSaveButton.addEventListener('click', () => { const name = document.getElementById('roomName').value.trim(); const sectionVal = document.getElementById('roomSection').value; const funcVal = document.getElementById('roomFunction').value; let idRaw = document.getElementById('roomId').value; if (!name) { alert('Please enter a room name.'); return; } const roomList = document.getElementById('room-list'); let existingOption = Array.from(roomList.options).find(opt => opt.value === idRaw); if (!idRaw) { idRaw = ComboBoxWidget.createTempId("room"); } if (!existingOption) { existingOption = ComboBoxWidget.createOption(name, idRaw); roomList.appendChild(existingOption); } existingOption.textContent = name; existingOption.value = idRaw; existingOption.dataset.sectionId = sectionVal || ""; existingOption.dataset.functionId = funcVal || ""; ComboBoxWidget.sortOptions(roomList); bootstrap.Modal.getInstance(modal).hide(); }); cancelButton.addEventListener('click', () => { bootstrap.Modal.getInstance(modal).hide(); }); {% endblock %}