const modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.innerHTML = ` `; document.body.appendChild(modal); } function saveOrder() { const items = JSON.parse(document.getElementById('o-items').value || '[]'); const data = { channel: document.getElementById('o-channel').value, customer_name: document.getElementById('o-name').value, customer_email: document.getElementById('o-email').value, customer_phone: document.getElementById('o-phone').value, shipping_address: document.getElementById('o-address').value, shipping_city: document.getElementById('o-city').value, shipping_state: document.getElementById('o-state').value, shipping_zip: document.getElementById('o-zip').value, items, notes: document.getElementById('o-notes').value }; api('POST', '/orders', data).then(() => { document.querySelector('.modal-overlay').remove(); loadPageData(); }).catch(err => alert(err.message)); } // ─── PRINT QUEUE ─── function renderPrintQueue() { const jobs = state.data.printJobs || []; return `

Print Queue

Manage print jobs across all printers

`; } function updatePrintJob(id, status) { api('PUT', `/print-jobs/${id}/status`, { status }).then(() => loadPageData()).catch(err => alert(err.message)); } function filterPrintJobs(status) { api('GET', `/print-jobs?status=${status}`).then(data => { state.data.printJobs = data; render(); }); } // ─── MATERIALS ─── function renderMaterials() { const materials = state.data.materials || []; return `

Materials

Track filament inventory and costs

${materials.map(m => ` `).join('') || ''}
TypeColorBrandRemainingCost/kgStatus
${m.type} ${m.color} ${m.brand || '-'} ${m.remaining_g}g $${m.cost_per_kg} ${m.status}
No materials tracked yet
`; } function showAddMaterialModal() { const modal = document.createElement('div'); modal.className = 'modal-overlay'; modal.innerHTML = ` `; document.body.appendChild(modal); } function saveMaterial() { const data = { type: document.getElementById('m-type').value, color: document.getElementById('m-color').value, brand: document.getElementById('m-brand').value, cost_per_kg: parseFloat(document.getElementById('m-cost').value), notes: document.getElementById('m-notes').value }; api('POST', '/materials', data).then(() => { document.querySelector('.modal-overlay').remove(); loadPageData(); }).catch(err => alert(err.message)); } // ─── AUTOMATION ─── function renderAutomation() { const rules = state.data.automationRules || []; return `

Automation

Status-based triggers and actions

Active Rules
${rules.map(r => ` `).join('') || ''}
NameTriggerActionStatus
${r.name} ${r.trigger_status} ${r.action_type} ${r.is_active ? 'Active' : 'Inactive'}
No automation rules configured
`; } // ─── DATA LOADER ─── function loadPageData() { state.loading = true; render(); const promises = []; if (state.currentPage === 'dashboard') { promises.push(api('GET', '/dashboard').then(d => state.data = { ...state.data, ...d })); } if (state.currentPage === 'products') { promises.push(api('GET', '/products').then(d => state.data.products = d)); } if (state.currentPage === 'inventory') { promises.push(api('GET', '/inventory').then(d => state.data.inventory = d)); } if (state.currentPage === 'orders') { promises.push(api('GET', '/orders').then(d => state.data.orders = d)); } if (state.currentPage === 'print-queue') { promises.push(api('GET', '/print-jobs').then(d => state.data.printJobs = d)); } if (state.currentPage === 'materials') { promises.push(api('GET', '/materials').then(d => state.data.materials = d)); } if (state.currentPage === 'automation') { promises.push(api('GET', '/automation-rules').then(d => state.data.automationRules = d)); } Promise.all(promises).then(() => { state.loading = false; render(); }).catch(err => { state.loading = false; console.error(err); render(); }); } // ─── INIT ─── render();