(() => { const app = document.querySelector('[data-api-base]'); const apiBase = app.dataset.apiBase; const state = { user: null, stores: [], ovens: [], parts: [], maintenance: [], }; const $ = (selector) => document.querySelector(selector); const $$ = (selector) => Array.from(document.querySelectorAll(selector)); function toast(message, type = 'success') { const region = $('#toastRegion'); const el = document.createElement('div'); el.className = `app-toast ${type === 'error' ? 'error' : ''}`; el.textContent = message; region.appendChild(el); setTimeout(() => el.remove(), 3200); } function setScreen(screenId) { $$('.screen').forEach((screen) => screen.classList.toggle('active', screen.id === screenId)); const active = document.getElementById(screenId); $('#screenTitle').textContent = active?.dataset.title || 'ManutApp'; $('#logoutBtn').classList.toggle('d-none', screenId === 'loginScreen'); if (screenId === 'maintenanceScreen') renderMaintenance(); } async function api(action, options = {}) { const response = await fetch(`${apiBase}?action=${encodeURIComponent(action)}`, { headers: { 'Content-Type': 'application/json' }, ...options, }); const payload = await response.json(); if (!response.ok || payload.success === false) throw new Error(payload.error || 'Falha na API mock.'); return payload; } async function bootstrap() { try { const payload = await api('bootstrap'); state.stores = payload.stores || []; state.ovens = payload.ovens || []; state.parts = payload.parts || []; state.maintenance = payload.maintenance || []; renderSeedLists(); renderFormOptions(); renderMaintenance(); } catch (error) { toast(error.message, 'error'); } } function renderSeedLists() { $('#storesList').innerHTML = state.stores.map((store) => `
${escapeHtml(store.name)}${escapeHtml(store.id)}
${escapeHtml(store.city)}
`).join(''); $('#partsList').innerHTML = state.parts.map((part) => `
${escapeHtml(part.name)}${escapeHtml(part.sku)}
Peça mock para seleção em manutenção
`).join(''); $('#ovensList').innerHTML = state.ovens.map((oven) => { const store = state.stores.find((item) => item.id === oven.store_id); return `
${escapeHtml(oven.name)}${escapeHtml(oven.model)}
${escapeHtml(store?.name || 'Loja')}
`; }).join(''); } function renderFormOptions() { $('#storeSelect').innerHTML = '' + state.stores.map((store) => ``).join(''); renderOvenOptions(); $('#partsChoices').innerHTML = state.parts.map((part) => ` `).join(''); } function renderOvenOptions() { const storeId = $('#storeSelect').value; const ovens = state.ovens.filter((oven) => oven.store_id === storeId); $('#ovenSelect').innerHTML = '' + ovens.map((oven) => ``).join(''); } function renderMaintenance() { $('#maintenanceCount').textContent = state.maintenance.length === 1 ? '1 manutenção' : `${state.maintenance.length} manutenções`; $('#maintenanceEmpty').classList.toggle('d-none', state.maintenance.length > 0); $('#maintenanceList').innerHTML = state.maintenance.map((item) => ` `).join(''); } function renderDetail(id) { const item = state.maintenance.find((entry) => String(entry.id) === String(id)); if (!item) { toast('Registro não encontrado.', 'error'); return; } const parts = Array.isArray(item.parts) ? item.parts.map((part) => part.name).join(', ') : 'Não informado'; $('#detailCard').innerHTML = `

Registro #${escapeHtml(String(item.id))}

${escapeHtml(item.store_name)}

Forno${escapeHtml(item.oven_name)}
Técnico${escapeHtml(item.technician)}
Tipo${escapeHtml(item.service_type)}
Peças${escapeHtml(parts)}
Observações

${escapeHtml(item.notes || 'Sem observações.')}

Criado em${formatDate(item.created_at)}
`; setScreen('detailScreen'); } function resetMaintenanceForm() { $('#maintenanceForm').reset(); renderOvenOptions(); } function escapeHtml(value) { return String(value ?? '').replace(/[&<>'"]/g, (char) => ({ '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' }[char])); } function escapeAttr(value) { return escapeHtml(value).replace(/`/g, '`'); } function formatDate(value) { if (!value) return 'agora'; const normalized = String(value).replace(' ', 'T'); const date = new Date(normalized); if (Number.isNaN(date.getTime())) return value; return date.toLocaleString('pt-BR', { dateStyle: 'short', timeStyle: 'short' }); } $('#loginForm').addEventListener('submit', (event) => { event.preventDefault(); const username = $('#username').value.trim(); const password = $('#password').value.trim(); if (!username || !password) { toast('Informe usuário e senha para continuar.', 'error'); return; } state.user = username; $('#welcomeUser').textContent = `Olá, ${username}`; toast('Login fake realizado com sucesso.'); setScreen('homeScreen'); }); $('#logoutBtn').addEventListener('click', () => { state.user = null; $('#loginForm').reset(); setScreen('loginScreen'); }); document.addEventListener('click', (event) => { const nav = event.target.closest('[data-target]'); if (nav) setScreen(nav.dataset.target); const detail = event.target.closest('[data-detail-id]'); if (detail) renderDetail(detail.dataset.detailId); }); $('#storeSelect').addEventListener('change', renderOvenOptions); $('#maintenanceForm').addEventListener('submit', async (event) => { event.preventDefault(); const selectedParts = $$('#partsChoices input:checked').map((input) => input.value); const payload = { store_id: $('#storeSelect').value, oven_id: $('#ovenSelect').value, technician: $('#technicianInput').value.trim(), service_type: $('#serviceTypeSelect').value, parts: selectedParts, notes: $('#notesInput').value.trim(), }; if (!payload.store_id || !payload.oven_id || !payload.technician || selectedParts.length === 0) { toast('Preencha loja, forno, técnico e pelo menos uma peça.', 'error'); return; } try { const result = await api('maintenance', { method: 'POST', body: JSON.stringify(payload) }); state.maintenance = result.maintenance || []; resetMaintenanceForm(); toast('Manutenção salva e listada com sucesso.'); setScreen('maintenanceScreen'); } catch (error) { toast(error.message, 'error'); } }); bootstrap(); })();