1/* vv-role-dashboard WaveAD 20260919T223300Z â BLACK-DASH FIX: never park #root / never set vv-role-dash-on */ 2(function () { 3 if (window.__vvRoleDash && window.__vvRoleDash.v === '20260919T223300Z') return; 4 var VER = '20260919T223300Z'; 5 window.__vvRoleDash = { v: VER }; 6 7 function path() { return String(location.pathname || ''); } 8 function isAnyDash(p) { 9 p = String(p || path()); 10 return /^\/v3\/(my-dashboard|customer-dashboard|agent-dashboard|agent-dashboard-pro|broker-dashboard|vendor-dashboard|vendor-hub|homebuyer-hub|agent-hub)(\/|$)/.test(p); 11 } 12 function esc(s) { 13 return String(s == null ? '' : s) 14 .replace(/&/g, '&').replace(/</g, '<') 15 .replace(/>/g, '>').replace(/"/g, '"'); 16 } 17 function money(n) { 18 var x = Number(n); 19 if (!isFinite(x)) return 'â'; 20 try { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(x); } 21 catch (e) { return '$' + x; } 22 } 23 function cookieLogged() { 24 try { 25 return document.cookie.split(';').some(function (c) { 26 return /^\s*vv_logged_in=(true|1)/i.test(c) || /^\s*vv_session=/.test(c); 27 }); 28 } catch (e) { return false; } 29 } 30 async function jget(url) { 31 try { 32 var r = await fetch(url, { credentials: 'include', headers: { Accept: 'application/json' } }); 33 var data = null; 34 try { data = await r.json(); } catch (_) {} 35 return { ok: r.ok, status: r.status, data: data }; 36 } catch (e) { 37 return { ok: false, status: 0, data: null }; 38 } 39 } 40 function roleFromMe(me) { 41 if (!me) return 'customer'; 42 var u = me.user || me; 43 var r = String(u.role || u.user_type || u.account_type || me.role || 'customer').toLowerCase(); 44 if (/broker|brokerage/.test(r)) return 'broker'; 45 if (/agent|realtor|loan_officer/.test(r)) return 'agent'; 46 if (/vendor|pro|contractor|provider|builder/.test(r)) return 'vendor'; 47 return 'customer'; 48 } 49 function nukeStub() { 50 /* BLACK-DASH FIX: NEVER add vv-role-dash-on â CSS used to park #root at left:-9999px */ 51 try { document.documentElement.classList.remove('vv-role-dash-on'); } catch (e0) {} 52 var hostOk = document.getElementById('vv-role-dash-root'); 53 if (!hostOk || !hostOk.children || !hostOk.children.length) { 54 /* no visible replacement â leave React alone */ 55 return; 56 } 57 var root = document.querySelector('#root') || document.body; 58 var walk = root.querySelectorAll('h1,h2,h3,h4,p,button,a,span,div,li'); 59 for (var i = 0; i < walk.length; i++) { 60 var el = walk[i]; 61 if (el.closest && el.closest('#vv-role-dash-root')) continue; 62 if (el.closest && el.closest('[data-vv-my-dashboard-gold="1"]')) continue; 63 var t = (el.textContent || '').trim(); 64 if (!t || t.length > 120) continue; 65 if (/Italian Leather|Leather Sofa|Innovation Lab|Upgrade to Platinum|Video Call|PRE-LAUNCH|Coming Soon|Demo Mode|demo sofa|Marketplace Theatre|KAFZourL/i.test(t)) { 66 var card = el.closest('section,article,[class*="card"],[class*="Card"],[class*="panel"],[class*="grid"] > div'); 67 (card || el).style.setProperty('display', 'none', 'important'); 68 } 69 } 70 } 71 function panel(title, bodyHtml, emptyMsg) { 72 var inner = bodyHtml || ('<p class="vrd-empty">' + esc(emptyMsg || 'Nothing here yet â honest empty, not a demo.') + '</p>'); 73 return '<section class="vrd-panel"><header class="vrd-panel__h"><h2>' + esc(title) + '</h2></header><div class="vrd-panel__b">' + inner + '</div></section>'; 74 } 75 function kv(rows) { 76 return rows.map(function (r) { 77 return '<div class="vrd-kv"><span>' + esc(r[0]) + '</span><strong>' + esc(r[1]) + '</strong></div>'; 78 }).join(''); 79 } 80 function listRows(items, mapFn) { 81 if (!items || !items.length) return ''; 82 return '<ul class="vrd-list">' + items.map(mapFn).join('') + '</ul>'; 83 } 84 function linksPanel(title, pairs) { 85 return '<section class="vrd-panel"><header class="vrd-panel__h"><h2>' + esc(title) + '</h2></header><div class="vrd-panel__b vrd-links">' + 86 pairs.map(function (p) { return '<a href="' + esc(p[1]) + '">' + esc(p[0]) + '</a>'; }).join('') + 87 '</div></section>'; 88 } 89 90 function customerView(pack) { 91 var hub = (pack.hub && pack.hub.data) || {}; 92 var me = (pack.me && pack.me.data) || {}; 93 var u = me.user || me || {}; 94 var acct = hub.account || {}; 95 var stats = hub.stats || {}; 96 var name = acct.name || acct.full_name || u.name || u.full_name ||
97 [u.first_name, u.last_name].filter(Boolean).join(' ') || u.email || 'Customer'; 98 var orders = hub.order_history || hub.orders || hub.recent_orders || []; 99 if (!orders.length && Array.isArray(hub.recent_orders)) orders = hub.recent_orders; 100 var cards = hub.payment_methods || []; 101 var pays = hub.payments || []; 102 var warranties = hub.warranties || []; 103 var insurance = hub.insurance || []; 104 var saved = hub.saved_properties || []; 105 if (!saved.length) { 106 var sd = pack.saved && pack.saved.data; 107 saved = (sd && (sd.properties || sd.saved_properties || sd.items)) || []; 108 } 109 if (!saved.length) { 110 var pd = pack.props && pack.props.data; 111 saved = (pd && (pd.properties || pd.items)) || []; 112 } 113 114 var hero = 115 '<div class="vrd-hero"><p class="vrd-eye">VistaView · Customer desk · ' + esc(VER) + '</p>' + 116 '<h1>Welcome, ' + esc(String(name).split(' ')[0] || 'there') + '</h1>' + 117 '<p class="vrd-sub">Homes you saved, orders & receipts, cards on file, warranties, insurance â live from your VistaView account. Empty means empty, never a fake sofa.</p></div>'; 118 119 var facts = 120 '<div class="vrd-facts">' + 121 '<div><span>Orders</span><strong>' + esc(stats.totalOrders != null ? stats.totalOrders : orders.length) + '</strong></div>' + 122 '<div><span>Spent</span><strong>' + esc(money(stats.totalSpent || 0)) + '</strong></div>' + 123 '<div><span>Saved homes</span><strong>' + esc(stats.savedProperties != null ? stats.savedProperties : saved.length) + '</strong></div>' + 124 '<div><span>Warranties</span><strong>' + esc(stats.activeWarranties != null ? stats.activeWarranties : warranties.length) + '</strong></div>' + 125 '<div><span>Insurance</span><strong>' + esc(stats.insuranceQuotes != null ? stats.insuranceQuotes : insurance.length) + '</strong></div>' + 126 '</div>'; 127 128 var acctP = panel('Account', kv([ 129 ['Name', name], 130 ['Email', acct.email || u.email || 'â'], 131 ['Phone', acct.phone || u.phone || 'â'], 132 ['Member since', acct.member_since || acct.created_at 133 ? new Date(acct.member_since || acct.created_at).toLocaleDateString() 134 : 'â'] 135 ])); 136 137 var homeP = panel('Saved homes', listRows(saved.slice(0, 12), function (h) { 138 var addr = h.address || h.street || h.full_address || h.title || 'Property'; 139 var price = h.price != null ? money(h.price) : (h.list_price != null ? money(h.list_price) : ''); 140 return '<li><div class="vrd-row"><div><strong>' + esc(addr) + '</strong>' + 141 '<div class="vrd-muted">' + esc([h.city, h.state].filter(Boolean).join(', ')) + '</div></div>' + 142 '<strong>' + esc(price) + '</strong></div></li>'; 143 }), 'No saved homes yet â heart a listing on Super Map.'); 144 145 var ordP = panel('Orders & receipts', listRows(orders.slice(0, 20), function (o) { 146 return '<li><div class="vrd-row"><div><strong>' + esc(o.order_number || o.id) + '</strong>' + 147 '<div class="vrd-muted">' + esc(o.item || o.product_name || o.description || 'Order') + '</div></div>' + 148 '<div class="vrd-right"><strong>' + esc(money(o.total != null ? o.total : o.total_amount)) + '</strong>' + 149 '<div class="vrd-muted">' + esc(o.payment_status || o.status || '') + '</div></div></div></li>'; 150 }), 'No orders yet â browse marketplace when youâre ready.'); 151 152 var cardP = panel('Payment methods', listRows(cards, function (c) { 153 return '<li><div class="vrd-row"><strong>' + esc(String(c.brand || c.card_brand || 'Card').toUpperCase()) + 154 ' â¢â¢â¢â¢ ' + esc(c.last4 || c.last_4 || '????') + '</strong>' + 155 '<span class="vrd-muted">Exp ' + esc(c.exp_month || c.expMonth || 'â') + '/' + esc(c.exp_year || c.expYear || 'â') + '</span></div></li>'; 156 }), 'No cards on file.'); 157 158 var payP = panel('Payments', listRows(pays.slice(0, 15), function (p) { 159 return '<li><div class="vrd-row"><strong>' + esc(p.order_number || p.id) + '</strong>' + 160 '<span>' + esc(money(p.amount)) + ' · ' + esc(p.payment_status || p.status || '') + '</span></div></li>'; 161 }), 'No payments yet.'); 162 163 var warP = panel('Warranties', listRows(warranties.slice(0, 10), function (w) { 164 return '<li><div class="vrd-row"><strong>' + esc(w.product_name || w.title || w.id || 'Warranty') + '</strong>' + 165 '<span class="vrd-muted">' + esc(w.status || w.coverage || '') + '</span></div></li>'; 166 }), 'No active warranties.'); 167 168 var insP = panel('Insurance quotes', listRows(insurance.slice(0, 10), function (q) { 169 return '<li><div class="vrd-row"><strong>' + esc(q.carrier || q.provider || q.id || 'Quote') + '</strong>' + 170 '<span class="vrd-muted">' + esc(q.status || money(q.premium) || '') + '</span></div></li>'; 171 }), 'No insurance quotes yet.'); 172 173 var go = linksPanel('Go do something', [ 174 ['Super Map', '/v3/map-search'], 175 ['Wishlist', '/v3/wishlist'], 176 ['All orders', '/v3/orders'], 177 ['VistaSign', '/v3/vista-sign'], 178 ['Hire a pro', '/v3/services'], 179 ['Settings', '/v3/settings'] 180 ]); 181 182 var authNote = hub.authenticated || pack.me.ok 183 ? '<p class="vrd-note">Signed in · hub ' + esc(hub.code || 'OK') + '</p>' 184 : '<p class="vrd-note">Browsing signed-out soft desk · hub ' + esc(hub.code || 'AUTH_OPTIONAL_EMPTY') + ' â TopBar login still loads your rows.</p>'; 185 186 187 var goldCard = 188 '<div class="vrd-gold-card" aria-label="VistaView account card">' + 189 '<div class="vrd-shield">V</div>' + 190 '<div><strong>' + esc(name) + '</strong>' + 191 '<span>VistaView · Customer License · ' + esc((acct.email || u.email || 'member').split('@')[0]) + '</span></div>' + 192 '<div class="vrd-serial">VV-CUS</div></div>'; 193 return hero + goldCard + facts + authNote + 194 '<div class="vrd-grid">' + acctP + homeP + '</div>' + 195 '<div class="vrd-grid">' + ordP + cardP + '</div>' + 196 '<div class="vrd-grid">' + payP + warP + '</div>' + 197 insP + go; 198 } 199 200 function agentView(pack) { 201 var me = (pack.me && pack.me.data) || {}; 202 var u = me.user || me || {};
203 var name = u.name || u.full_name || u.email || 'Agent'; 204 var dash = (pack.agentDash && pack.agentDash.data) || {}; 205 var kpis = dash.kpis || {}; 206 var kpiData = dash.kpiData || []; 207 var leads = dash.leads || (pack.leads && pack.leads.data && (pack.leads.data.leads || pack.leads.data.clients || pack.leads.data.items)) || []; 208 if (!Array.isArray(leads)) leads = []; 209 var listings = dash.listings || (pack.listings && pack.listings.data && (pack.listings.data.listings || pack.listings.data.items)) || []; 210 if (!Array.isArray(listings)) listings = []; 211 var showings = dash.showings || (pack.showings && pack.showings.data && (pack.showings.data.showings || pack.showings.data.items)) || []; 212 if (!Array.isArray(showings)) showings = []; 213 var commissions = dash.commissions || (pack.commissions && pack.commissions.data && (pack.commissions.data.commissions || pack.commissions.data.items)) || []; 214 if (!Array.isArray(commissions)) commissions = []; 215 var clients = (pack.clients && pack.clients.data && pack.clients.data.clients) || []; 216 if (!Array.isArray(clients)) clients = []; 217 // Never trust is_demo theatre lists 218 if (pack.clients && pack.clients.data && pack.clients.data.is_demo) clients = []; 219 220 var activeListings = kpis.activeListings != null ? kpis.activeListings : listings.length; 221 var pendingDeals = kpis.pendingDeals != null ? kpis.pendingDeals : 0; 222 var commYTD = kpis.commissionYTD != null ? kpis.commissionYTD : 0; 223 var totalClients = kpis.totalClients != null ? kpis.totalClients : clients.length; 224 var openLeads = kpis.openLeads != null ? kpis.openLeads : leads.length; 225 226 var hero = 227 '<div class="vrd-hero"><p class="vrd-eye">VistaView · Agent desk · Wave 2</p>' + 228 '<h1>' + esc(String(name).split(' ')[0]) + '\u2019s book</h1>' + 229 '<p class="vrd-sub">Leads, listings, showings, commissions \u2014 live hub data. Empty means empty.</p></div>'; 230 231 var facts = 232 '<div class="vrd-facts">' + 233 '<div><span>Active listings</span><strong>' + esc(activeListings) + '</strong></div>' + 234 '<div><span>Open leads</span><strong>' + esc(openLeads) + '</strong></div>' + 235 '<div><span>Pending deals</span><strong>' + esc(pendingDeals) + '</strong></div>' + 236 '<div><span>Clients</span><strong>' + esc(totalClients) + '</strong></div>' + 237 '<div><span>Commission YTD</span><strong>' + esc(typeof commYTD === 'number' ? money(commYTD) : String(commYTD || '$0')) + '</strong></div></div>'; 238 239 var leadP = panel('Lead pipeline', listRows(leads.slice(0, 20), function (L) { 240 return '<li><div class="vrd-row"><div><strong>' + esc(L.name || L.full_name || L.email || 'Lead') + '</strong>' + 241 '<div class="vrd-muted">' + esc(L.status || L.stage || L.source || '') + '</div></div>' + 242 '<span class="vrd-muted">' + esc(L.phone || L.email || '') + '</span></div></li>'; 243 }), 'No leads yet \u2014 capture from Super Map or share a listing.'); 244 245 var listP = panel('Listings', listRows(listings.slice(0, 15), function (L) { 246 var title = L.name || L.address || L.address_line1 || ('Listing #' + (L.id || '')); 247 var price = L.price != null ? money(L.price) : ''; 248 return '<li><div class="vrd-row"><div><strong>' + esc(title) + '</strong>' + 249 '<div class="vrd-muted">' + esc([L.city, L.state].filter(Boolean).join(', ') + (L.status ? ' · ' + L.status : '')) + '</div></div>' + 250 '<strong>' + esc(price) + '</strong></div></li>'; 251 }), 'No listings on your book yet.'); 252 253 var showP = panel('Showings', listRows(showings.slice(0, 15), function (S) { 254 return '<li><div class="vrd-row"><div><strong>' + esc(S.property || S.property_address || S.address || 'Showing') + '</strong>' + 255 '<div class="vrd-muted">' + esc(S.client || S.buyer_name || '') + '</div></div>' + 256 '<span class="vrd-muted">' + esc(S.date || S.scheduled_at || S.status || '') + '</span></div></li>'; 257 }), 'No showings scheduled.'); 258 259 var commP = panel('Commissions', listRows(commissions.slice(0, 15), function (C) { 260 return '<li><div class="vrd-row"><div><strong>' + esc(C.property || C.property_address || ('Deal #' + (C.id || ''))) + '</strong>' + 261 '<div class="vrd-muted">' + esc(C.status || '') + '</div></div>' + 262 '<strong>' + esc(money(C.commissionAmt != null ? C.commissionAmt : C.commission_amount)) + '</strong></div></li>'; 263 }), 'No commissions logged yet.'); 264 265 var clientP = panel('Clients', listRows(clients.slice(0, 15), function (C) { 266 return '<li><div class="vrd-row"><div><strong>' + esc(C.name || C.email || 'Client') + '</strong>' + 267 '<div class="vrd-muted">' + esc(C.stage || C.role || '') + '</div></div>' + 268 '<span class="vrd-muted">' + esc(C.phone || C.email || '') + '</span></div></li>'; 269 }), 'No clients assigned yet.'); 270 271 var go = linksPanel('Agent tools', [ 272 ['Agent Hub', '/v3/agent-hub'], 273 ['Lead capture', '/v3/lead-capture'], 274 ['Calendar', '/v3/calendar'], 275 ['Map / listings', '/v3/map-search'], 276 ['Data intel', '/v3/data-intelligence'], 277 ['VistaSign', '/v3/vista-sign'] 278 ]); 279 280 var authNote = (dash.authenticated || (pack.me && pack.me.ok)) 281 ? '<p class="vrd-note">Signed in · agent hub ' + esc(dash.code || 'OK') + '</p>' 282 : '<p class="vrd-note">Soft desk · ' + esc(dash.code || 'AUTH_OPTIONAL_EMPTY') + ' \u2014 sign in via TopBar to load your book.</p>'; 283 284 return hero + facts + authNote + 285 '<div class="vrd-grid">' + leadP + listP + '</div>' + 286 '<div class="vrd-grid">
286' + showP + commP + '</div>' + 287 clientP + go; 288 } 289 290 function brokerView(pack) { 291 var me = (pack.me && pack.me.data) || {}; 292 var u = me.user || me || {}; 293 var name = u.name || u.full_name || 'Broker'; 294 var pulse = (pack.brokerPulse && pack.brokerPulse.data) || {}; 295 var report = (pack.brokerReport && pack.brokerReport.data) || {}; 296 var isDemo = !!(pulse.is_demo || pulse.isDemo); 297 var agents = pulse.roster || pulse.agents || pulse.team || []; 298 if (!Array.isArray(agents)) agents = []; 299 var matrix = pulse.matrix || pulse.production || []; 300 if (!Array.isArray(matrix)) matrix = []; 301 var stats = pulse.stats || (report.report && report.report.stats) || report.stats || {}; 302 var kpis = pulse.kpis || pulse.kpi || report.kpis || { 303 agentCount: pulse.roster_count != null ? pulse.roster_count : agents.length, 304 openDeals: stats.contact_clicks_30d != null ? stats.contact_clicks_30d : stats.views_30d, 305 volumeYTD: null, 306 closings: stats.leads_30d, 307 compliance: (pulse.brokerage && pulse.brokerage.name) || 'â' 308 }; 309 var hero = 310 '<div class="vrd-hero"><p class="vrd-eye">VistaView · Brokerage · Wave 3' + (isDemo ? ' · sample firm' : '') + '</p>' + 311 '<h1>' + esc(String(name).split(' ')[0]) + ' · Office</h1>' + 312 '<p class="vrd-sub">Team production, compliance pulse, payouts. Sample slug only when signed out â your firm loads when you are in.</p></div>'; 313 var facts = 314 '<div class="vrd-facts">' + 315 '<div><span>Agents</span><strong>' + esc(kpis.agentCount != null ? kpis.agentCount : agents.length) + '</strong></div>' + 316 '<div><span>Open pipeline</span><strong>' + esc(kpis.openDeals != null ? kpis.openDeals : (kpis.pipeline || 'â')) + '</strong></div>' + 317 '<div><span>Volume YTD</span><strong>' + esc(kpis.volumeYTD != null ? money(kpis.volumeYTD) : (kpis.volume || 'â')) + '</strong></div>' + 318 '<div><span>Closings</span><strong>' + esc(kpis.closings != null ? kpis.closings : 'â') + '</strong></div>' + 319 '<div><span>Compliance</span><strong>' + esc(kpis.compliance || 'â') + '</strong></div></div>'; 320 var teamP = panel('Team roster', listRows(agents.slice(0, 20), function (A) { 321 return '<li><div class="vrd-row"><div><strong>' + esc(A.name || A.full_name || A.email || 'Agent') + '</strong>' + 322 '<div class="vrd-muted">' + esc(A.role || A.status || '') + '</div></div>' + 323 '<span class="vrd-muted">' + esc(A.ytd_volume != null ? money(A.ytd_volume) : (A.volume || A.deals || '')) + '</span></div></li>'; 324 }), isDemo ? 'Sample firm â sign in as brokerage admin for your roster.' : 'No agents on roster yet.'); 325 var pipeP = panel('Office pipeline', listRows(matrix.slice(0, 15), function (R) { 326 return '<li><div class="vrd-row"><strong>' + esc(R.agent || R.name || R.label || 'Row') + '</strong>' + 327 '<span class="vrd-muted">' + esc(R.deals != null ? R.deals + ' deals' : (R.value != null ? money(R.value) : (R.status || ''))) + '</span></div></li>'; 328 }), 'No pipeline rows yet.'); 329 var payP = panel('Payouts / success fees', '', 'Wire next from brokerage billing-status when firm is linked.'); 330 var go = linksPanel('Broker tools', [ 331 ['Command center', '/v3/command-center'], 332 ['Team chat', '/v3/team-chat'], 333 ['Reports', '/v3/reports'], 334 ['HR', '/v3/hr'], 335 ['Billing', '/v3/brokerage-billing'] 336 ]); 337 var note = isDemo 338 ? '<p class="vrd-note">Showing sample brokerage pulse (slug=remax&sample=1). Real firm data needs brokerage login.</p>' 339 : '<p class="vrd-note">Brokerage pulse ' + esc(pulse.code || report.code || 'OK') + '</p>'; 340 return hero + facts + note + '<div class="vrd-grid">' + teamP + pipeP + '</div>' + payP + go; 341 } 342 343 function vendorView(pack) { 344 var me = (pack.me && pack.me.data) || {}; 345 var u = me.user || me || {}; 346 var name = u.name || u.business_name || u.full_name || 'Pro'; 347 var dash = (pack.vendorDash && pack.vendorDash.data) || {}; 348 var kpi = dash.kpi || dash.kpis || {}; 349 var products = dash.products || []; 350 if (!Array.isArray(products)) products = []; 351 var orders = dash.orders || (pack.vendorOrders && pack.vendorOrders.data && (pack.vendorOrders.data.orders || pack.vendorOrders.data.items)) || []; 352 if (!Array.isArray(orders)) orders = []; 353 var payouts = (pack.vendorPayouts && pack.vendorPayouts.data && (pack.vendorPayouts.data.payouts || pack.vendorPayouts.data.items)) || []; 354 if (!Array.isArray(payouts)) payouts = []; 355 var proDash = (pack.proDash && pack.proDash.data) || {}; 356 var earnings = (pack.proEarn && pack.proEarn.data) || {}; 357 var jobs = proDash.jobs || proDash.recent_jobs || earnings.recent_jobs || []; 358 if (!Array.isArray(jobs)) jobs = []; 359 360 var hero = 361 '<div class="vrd-hero"><p class="vrd-eye">VistaView · Pro / Vendor · Wave 4</p>' + 362 '<h1>' + esc(String(name).split(' ')[0]) + ' · Shop & jobs</h1>' + 363 '<p class="vrd-sub">Catalog orders, payouts, Hire-Me jobs â scoped to you. Empty when signed out or new.</p></div>'; 364 var facts = 365 '<div class="vrd-facts">' + 366 '<div><span>Products</span><strong>' + esc(kpi.totalProducts != null ? kpi.totalProducts : products.length) + '</strong></div>' + 367 '<div><span>Orders</span><strong>' + esc(kpi.totalOrders != null ? kpi.totalOrders : orders.length) + '</strong></div>' + 368 '<div><span>Revenue</span><strong>' + esc(kpi.totalRevenue != null ? money(kpi.totalRevenue) : 'â') + '</strong></div>' + 369 '<div><span>Open jobs</span><strong>' + esc(jobs.length) + '</strong></div>' + 370 '<div><span>Payouts</span><strong>' + esc(payouts.length) + '</strong></div></div>'; 371 372 var ordP = panel('Orders', listRows(orders.slice(0, 15), function (O) { 373 return '<li><div class="vrd-row"><div><strong>' + esc(O.order_number || O.id || 'Order') + '</strong>' + 374 '<div class="vrd-muted">' + esc(O.status || O.payment_status || '') + '</div></div>' + 375 '<strong>' + esc(money(O.total_amount != null ? O.total_amount : O.total)) + '</strong></div></li>'; 376 }), 'No vendor orders yet.'); 377 var payP = panel('Payouts', listRows(payouts.slice(0, 15), function (P) { 378 return '<li><div class="vrd-row"><strong>' + esc(P.id || P.payout_id || 'Payout') + '</strong>' + 379 '<span>' + esc(money(P.amount)) + ' · ' + esc(P.status || '') + '</span></div></li>'; 380 }), 'No payouts yet.'); 381 var jobP = panel('Hire-Me jobs', listRows(jobs.slice(0, 15), function (J) { 382 return '<li><div class="vrd-row"><strong>' + esc(J.title || J.id || 'Job') + '</strong>' + 383 '<span class="vrd-muted">' + esc(J.status || '') + '</span></div></li>'; 384 }), 'No Hire-Me jobs â turn on Join Pro.'); 385 var prodP = panel('Catalog snapshot', listRows(products.slice(0, 10), function (P) { 386 return '<li><div class="vrd-row"><strong>' + esc(P.name || P.title || P.id) + '</strong>' + 387 '<span>' + esc(money(P.price)) + '</span></div></li>'; 388 }), 'No products in your catalog yet.'); 389 var go = linksPanel('Pro tools', [ 390 ['Vendor Hub', '/v3/vendor-hub'], 391 ['Service map', '/v3/services'], 392 ['Invoices', '/v3/invoices'], 393 ['Join Pro card', '/v3/join-pro'], 394 ['Payouts', '/v3/vendor-payouts'] 395 ]); 396 var note = '<p class="vrd-note">Vendor hub ' + esc(dash.code || 'OK') + ' · Hire-Me ' + esc(proDash.code || earnings.code || 'â') + '</p>'; 397 return hero + facts + note + 398 '<div class="vrd-grid">' + ordP + payP + '</div>' + 399 '<div class="vrd-grid">' + jobP + prodP + '</div>' + go; 400 } 401 402 async function loadPack(role) { 403 var me = await jget('/api/auth/sso/me'); 404 if (!me.ok) me = await jget('/api/auth/me'); 405 var detected = roleFromMe(me.data); 406 if (!role || role === 'auto') role = detected; 407 408 var pack = { me: me, role: role, hub: null, saved: null, props: null, leads: null, vendor: null }; 409 if (role === 'customer') { 410 pack.hub = await jget('/api/hub/customer/dashboard'); 411 pack.saved = await jget('/api/hub/buyer/saved-properties'); 412 pack.props = await jget('/api/hub/customer/properties'); 413 } else if (role === 'agent') { 414 pack.agentDash = await jget('/api/hub/agent/dashboard'); 415 pack.listings = await jget('/api/hub/agent/listings'); 416 pack.showings = await jget('/api/hub/agent/showings'); 417 pack.commissions = await jget('/api/hub/agent/commissions'); 418 pack.clients = await jget('/api/hub/agent/clients'); 419 pack.leads = await jget('/api/hub/agent/crm-summary'); 420 if (!pack.leads.ok) pack.leads = await jget('/api/leads/list'); 421 } else if (role === 'broker') { 422 pack.brokerPulse = await jget('/api/hub/brokerage/pulse?slug=remax&sample=1'); 423 pack.brokerReport = await jget('/api/hub/brokerage/report-30d'); 424 pack.brokerBilling = await jget('/api/hub/brokerage/billing-status'); 425 } else if (role === 'vendor') { 426 pack.vendorDash = await jget('/api/hub/vendor/dashboard'); 427 pack.vendorOrders = await jget('/api/hub/vendor/orders'); 428 pack.vendorPayouts = await jget('/api/hub/vendor/payouts'); 429 pack.proDash = await jget('/api/service-marketplace/provider/dashboard'); 430 pack.proEarn = await jget('/api/service-marketplace/provider/earnings'); 431 } 432 return pack; 433 } 434 435 function render(host, pack) { 436 var role = pack.role || 'customer'; 437 var html; 438 if (role === 'agent') html = agentView(pack); 439 else if (role === 'broker') html = brokerView(pack); 440 else if (role === 'vendor') html = vendorView(pack); 441 else html = customerView(pack); 442 443 var switcher = 444 '<div class="vrd-switch" role="navigation" aria-label="Role preview">' + 445 ['customer', 'agent', 'broker', 'vendor'].map(function (r) { 446 return '<button type="button" data-vrd-role="' + r + '" class="' + (r === role ? 'on' : '') + '">' + r + '</button>'; 447 }).join('') + '</div>'; 448 449 host.innerHTML = '<div class="vrd-shell" data-v="' + VER + '">' + switcher + html + '</div>'; 450 host.querySelectorAll('[data-vrd-role]').forEach(function (btn) { 451 btn.addEventListener('click', function () { mount(btn.getAttribute('data-vrd-role')); }); 452 }); 453 } 454 455 async function mount(forceRole) { 456 if (!isAnyDash()) { 457 var old = document.getElementById('vv-role-dash-root'); 458 if (old) old.remove(); 459 document.documentElement.classList.remove('vv-role-dash-on'); 460 return; 461 } 462 var host = document.getElementById('vv-role-dash-root'); 463 if (!host) { 464 host = document.createElement('div'); 465 host.id = 'vv-role-dash-root'; 466 /* Append as body sibling â never nest inside #root child that CSS used to park */ 467 document.body.appendChild(host); 468 } 469 host.innerHTML = '<div class="vrd-shell"><div class="vrd-hero"><p class="vrd-eye">VistaView</p><h1>Loading your deskâ¦</h1></div></div>'; 470 var pack = await loadPack(forceRole || 'auto'); 471 if (!pack.me.ok && !cookieLogged()) { 472 pack.role = forceRole && forceRole !== 'auto' ? forceRole : 'customer'; 473 if (!pack.hub) { 474 pack.hub = { 475 ok: true, 476 data: { 477 authenticated: false, 478 stats: { totalOrders: 0, totalSpent: 0, savedProperties: 0, activeWarranties: 0, insuranceQuotes: 0 }, 479 account: null, orders: [], order_history: [], recent_orders: [], 480 saved_properties: [], payment_methods: [], payments: [], 481 warranties: [], insurance: [], code: 'AUTH_OPTIONAL_EMPTY' 482 } 483 }; 484 } 485 } 486 render(host, pack); 487 /* Only after host has children; never sets vv-role-dash-on */ 488 nukeStub(); 489 } 490 491 function boot() { 492 mount('auto'); 493 var n = 0; 494 var t = setInterval(function () { 495 n++; 496 /* remount if path ok but host missing; never park #root */ 497 if (isAnyDash() && !document.getElementById('vv-role-dash-root')) mount('auto'); 498 else if (isAnyDash()) nukeStub(); 499 if (n > 60) clearInterval(t); 500 }, 400); 501 window.addEventListener('popstate', function () { mount('auto'); }); 502 var _ps = history.pushState, _rs = history.replaceState; 503 history.pushState = function () { 504 var r = _ps.apply(this, arguments); 505 setTimeout(function () { mount('auto'); }, 0); 506 return r; 507 }; 508 history.replaceState = function () { 509 var r = _rs.apply(this, arguments); 510 setTimeout(function () { mount('auto'); }, 0); 511 return r; 512 }; 513 } 514 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot); 515 else boot(); 516})();
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.