(function () { const routes = { 'Onboarding requests': 'Customer Onboarding Request', 'Customer': 'Customer', 'Contact': 'Contact', 'Opportunity': 'Opportunity', 'Quotation': 'Quotation', 'Sales order': 'Sales Order', 'Packaging specs': 'Packaging Specification', 'Packaging specifications': 'Packaging Specification', 'Material structures': 'Material Structure', 'Critical acceptance': 'Critical Acceptance Requirement', 'Item': 'Item', 'Operation': 'Operation', 'Work order': 'Work Order', 'Production plan': 'Production Plan', 'Material request': 'Material Request', 'Purchase order': 'Purchase Order', 'Purchase receipt': 'Purchase Receipt', 'Quality inspection': 'Quality Inspection', 'Delivery note': 'Delivery Note', 'Sales invoice': 'Sales Invoice', 'Payment entry': 'Payment Entry', 'Purchase invoice': 'Purchase Invoice', 'Order closure & margin': 'Order Closure And Margin View', 'User': 'User', 'UOM': 'UOM' }; const clean = (text) => text.replace(/\s+/g, ' ').trim(); const slug = (doctype) => doctype.toLowerCase().replaceAll(' ', '-'); const navigate = (doctype) => { if (window.frappe && typeof frappe.set_route === 'function') { frappe.set_route('List', doctype); } else { window.location.assign(`/app/${slug(doctype)}`); } }; // The supplied mockup uses a flat sidebar. Wrap each label plus its items into a group. const sidebar = document.querySelector('.sidebar'); if (sidebar && !sidebar.dataset.groupsWrapped) { const labels = Array.from(sidebar.querySelectorAll('.nav-group-label')); labels.forEach((label, index) => { const group = document.createElement('div'); group.className = 'nav-group'; sidebar.insertBefore(group, label); group.appendChild(label); let sibling = group.nextElementSibling; while (sibling && !sibling.classList.contains('nav-group-label') && !sibling.classList.contains('sidebar-footer')) { const next = sibling.nextElementSibling; group.appendChild(sibling); sibling = next; } if (index > 0) group.classList.add('collapsed'); }); sidebar.dataset.groupsWrapped = '1'; } document.querySelectorAll('.sidebar .nav-item').forEach((item) => { const text = clean(item.textContent || ''); const key = Object.keys(routes).find((label) => text.startsWith(label)); if (!key) return; const doctype = routes[key]; item.dataset.doctype = doctype; item.setAttribute('role', 'link'); item.addEventListener('click', (event) => { event.preventDefault(); navigate(doctype); }); }); document.querySelectorAll('.sidebar .nav-group-label').forEach((label) => { const group = label.parentElement; label.setAttribute('role', 'button'); label.setAttribute('tabindex', '0'); const toggle = () => group.classList.toggle('collapsed'); label.addEventListener('click', toggle); label.addEventListener('keydown', (event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); toggle(); } }); }); // Remove the hardcoded explanatory footer from the supplied mockup. document.querySelector('.sidebar-footer')?.remove(); // Replace hardcoded Grace/GR with the logged-in Frappe user. const setIdentity = (fullName) => { const name = fullName || (window.frappe && frappe.session && frappe.session.user) || 'User'; document.querySelectorAll('#dashboard-user').forEach((node) => { node.textContent = name; }); document.querySelectorAll('#dashboard-initials').forEach((node) => { node.textContent = name.split(/\s+/).map((part) => part[0]).join('').slice(0, 2).toUpperCase(); }); document.querySelectorAll('.hero h1').forEach((heading) => { if (!heading.querySelector('#dashboard-user')) heading.innerHTML = `Welcome back, ${name} 👋`; }); }; setIdentity(); if (window.frappe && frappe.session && frappe.session.user && frappe.call) { frappe.call({ method: 'frappe.client.get_value', args: { doctype: 'User', filters: { name: frappe.session.user }, fieldname: 'full_name' }, callback: (r) => setIdentity(r.message && r.message.full_name) }); } // Update the four cards from live MAKAP DocType data. if (window.frappe && frappe.call) { frappe.call({ method: 'makap_backend.makap_backend.portal_api.get_portal_dashboard', callback: (response) => { const kpis = response.message && response.message.kpis; if (!kpis) return; const values = [kpis.onboarding_requests, kpis.packaging_specifications, kpis.approved_for_manufacture, kpis.critical_requirements_tracked]; document.querySelectorAll('.stat-card .stat-value').forEach((node, index) => { if (values[index] !== undefined) node.textContent = Number(values[index] || 0).toLocaleString(); }); }}); } })();