Portal, logo, workspace shortcut
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,94 @@
|
||||
(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, <span id="dashboard-user">${name}</span> 👋`;
|
||||
});
|
||||
};
|
||||
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(); });
|
||||
}});
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user