1// Gap F R2 (2026-05-20): /me dashboard banner for wholesale order confirmation. 2// 3// When place_wholesale_order successfully creates docs, the endpoint redirects to 4// /me?gap_f_order=ok&si=ACC-SINV-...&so=SAL-ORD-... 5// (either si or so may be absent â all-in-stock omits so; all-OOS omits si). 6// 7// This file is included via hooks.py `web_include_js` so it runs on all portal pages, 8// but the path gate ensures the banner only renders on /me. Bullet-safe: any URL 9// without the expected param is a no-op. 10// 11// Banner is informational ("Order received"), NOT navigational. Customer continues 12// using /me normally. Banner can be dismissed via X button. 13 14(function () { 15 'use strict'; 16 17 // Only act on /me page (defensive trailing-slash strip) 18 const path = window.location.pathname.replace(/\/+$/, ''); 19 if (path !== '/me') return; 20 21 // Read query params 22 const params = new URLSearchParams(window.location.search); 23 if (params.get('gap_f_order') !== 'ok') return; 24 25 const si = params.get('si'); 26 const so = params.get('so'); 27 if (!si && !so) return; // nothing to confirm 28 29 // Build banner copy 30 let parts = []; 31 if (si) parts.push('items are being invoiced (pending our review)'); 32 if (so) parts.push('items have been backordered'); 33 const message = 'Order received! Your ' + parts.join(' and ') +
34 '. Our team will confirm shortly via email or phone.'; 35 36 // Render banner at the top of #page-me (or main-content fallback) 37 function injectBanner() { 38 if (document.getElementById('csl-gap-f-order-banner')) return; // already rendered 39 40 const banner = document.createElement('div'); 41 banner.id = 'csl-gap-f-order-banner'; 42 banner.setAttribute('role', 'status'); 43 banner.style.cssText = [ 44 'background: #ecfdf5', 45 'border: 1px solid #6ee7b7', 46 'border-left: 4px solid #059669', 47 'border-radius: 8px', 48 'padding: 16px 20px', 49 'margin: 16px auto', 50 'max-width: 900px', 51 'color: #064e3b', 52 'display: flex', 53 'gap: 14px', 54 'align-items: flex-start', 55 'font-size: 0.95rem', 56 'line-height: 1.5', 57 ].join(';'); 58 59 banner.innerHTML = 60 '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" ' + 61 'style="width:24px;height:24px;flex-shrink:0;margin-top:2px;">' + 62 '<polyline points="20 6 9 17 4 12"/></svg>' + 63 '<div style="flex:1;">' + 64 '<div style="font-weight:600;margin-bottom:4px;">Order received</div>' + 65 '<div></div>' + 66 '</div>' + 67 '<button type="button" aria-label="Dismiss" style="background:none;border:none;' + 68 'color:#064e3b;cursor:pointer;font-size:1.3rem;line-height:1;padding:0 4px;">Ã</button>'; 69 70 // Set message text via textContent to avoid HTML injection 71 banner.querySelector('div > div:nth-child(2)').textContent = message; 72 73 // Dismiss handler â removes banner + strips query params (so refresh doesn't re-show) 74 banner.querySelector('button').addEventListener('click', function () { 75 banner.remove(); 76 try { 77 const url = new URL(window.location.href); 78 url.searchParams.delete('gap_f_order'); 79 url.searchParams.delete('si'); 80 url.searchParams.delete('so'); 81 window.history.replaceState({}, '', url.toString()); 82 } catch (e) { /* IE/old-browser fallback: ignore */ } 83 }); 84 85 // Try a few anchors in order â /me layout varies across Frappe versions 86 const anchors = [ 87 document.getElementById('page-me'), 88 document.querySelector('main'), 89 document.querySelector('.web-page'), 90 document.querySelector('.page_content'), 91 document.querySelector('#main-content'), 92 document.body, 93 ]; 94 const anchor = anchors.find(function (a) { return a; }); 95 if (anchor) anchor.insertBefore(banner, anchor.firstChild); 96 } 97 98 if (document.readyState === 'loading') { 99 document.addEventListener('DOMContentLoaded', injectBanner); 100 } else { 101 injectBanner(); 102 } 103})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.