PageSourceSearch

https://evolvh.com/apps/notpo?action=cart_js

js evolvh.com collected 2026-10-03 21:28:30 UTC 5,922 bytes, 67 lines download raw bytes

1(function(){
2  
3  var PTS_PER_DOLLAR = 20;
4  function esc(s){ return String(s == null ? "" : s).replace(/[&<>"]/g, function(ch){ return ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[ch]; }); }
5  function api(action, body){
6    return fetch("/apps/notpo?action=" + action, body ? { method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify(body) } : { credentials:"same-origin" }).then(function(r){ return r.json(); });
7  }
8  function cartSubtotal(){
9    return fetch("/cart.js", { credentials:"same-origin" }).then(function(r){ return r.json(); }).then(function(c){ return (c.items_subtotal_price || 0) / 100; }).catch(function(){ return 0; });
10  }
11  function codeValue(c){ return Math.round(c.points_spent / PTS_PER_DOLLAR); }
12  function applyUrl(code, to){ return "/discount/" + encodeURIComponent(code) + "?redirect=" + (to || "/cart"); }
13
14  if (window.__notpoCart) return; window.__notpoCart = true;
15  var css = document.createElement("style");
16  css.textContent = ".notpo-cp{margin:0 0 12px;padding:14px 16px;border:2px dashed #9fcac3;border-radius:12px;background:#e6f4f1;color:#12302c;font-size:14px;line-height:1.4;text-align:left}.notpo-cp button{font:inherit;cursor:pointer;border:0;border-radius:999px;padding:10px 16px;margin-top:8px;width:100%;background:#0f766e;color:#fff}.notpo-cp button:disabled{opacity:.6;cursor:wait}.notpo-cp a{color:#0f766e}";
17  document.head.appendChild(css);
18  var me = null, sub = 0, html = "", hidden = true;
19  function boxes(){
20    // Rebuy Smart Cart (the slide-out cart on evolvh.com): insert above its Checkout button.
21    Array.prototype.forEach.call(document.querySelectorAll(".rebuy-cart__checkout-button"), function(btn){
22      var prev = btn.previousElementSibling;
23      if (prev && prev.classList.contains("notpo-cart-points")) return;
24      var d = document.createElement("div"); d.className = "notpo-cart-points"; btn.parentNode.insertBefore(d, btn);
25    });
26    var list = Array.prototype.slice.call(document.querySelectorAll("#notpo-cart-points, .notpo-cart-points"));
27    if (!list.length && /^\/cart\/?$/.test(location.pathname)) {
28      var btn = document.querySelector('form[action*="/cart"] [name="checkout"]');
29      if (btn) { var d = document.createElement("div"); d.className = "notpo-cart-points"; btn.parentNode.insertBefore(d, btn); list = [d]; }
30    }
31    return list;
32  }
33  function build(){
34    hidden = true;
35    if (!me || !me.signed_in || !me.member || !(Number(me.balance) >= 10)) return "";
36    hidden = false;
37    var byPts = Math.floor(me.balance / PTS_PER_DOLLAR), max = Math.min(byPts, Math.floor(sub * 0.1));
38    var fit = (me.codes || []).filter(function(c){ return codeValue(c) <= max; }).sort(function(a, b){ return codeValue(b) - codeValue(a); })[0];
39    if (fit && codeValue(fit) === max && max >= 1) return 'You have <b>$' + max + ' off</b> ready to use.<div style="margin-top:2px">Rewards can cover up to 10% of your cart total during The Fall Tiered Sale</div><div style="margin-top:2px">Remaining rewards: <b>' + me.balance.toLocaleString() + ' points</b> ($' + (me.balance / PTS_PER_DOLLAR).toFixed(2) + ' value)</div><button type="button" data-apply="' + esc(fit.discount_code) + '">Apply $' + max + ' off &amp; Checkout</button><div style="margin-top:6px;font-size:12px"><a href="/apps/notpo">See your rewards</a></div>';
40    if (max >= 1) return 'You have <b>$' + max + ' off</b> ready to use.<div style="margin-top:2px">Rewards can cover up to 10% of your cart total during The Fall Tiered Sale</div><div style="margin-top:2px">Remaining rewards: <b>' + (me.balance - max * PTS_PER_DOLLAR).toLocaleString() + ' points</b> ($' + ((me.balance - max * PTS_PER_DOLLAR) / PTS_PER_DOLLAR).toFixed(2) + ' value)</div><button type="button" data-amount="' + max + '">Apply $' + max + ' off & Checkout</button><div style="margin-top:6px;font-size:12px"><a href="https://evolvh.com/apps/notpo">Go to Rewards</a></div>';
41    return 'You have <b>' + me.balance.toLocaleString() + ' points</b>. <a href="/apps/notpo">See your rewards</a>';
42  }
43  function paint(force){
44    boxes().forEach(function(b){
45      if (!b.classList.contains("notpo-cp")) b.classList.add("notpo-cp");
46      b.style.display = hidden ? "none" : "";
47      if (force || b.getAttribute("data-notpo") !== html) { b.innerHTML = html; b.setAttribute("data-notpo", html); }
48    });
49  }
50  function refresh(){ cartSubtotal().then(function(s){ var changed = s !== sub; sub = s; var h = build(); if (changed || h !== html) { html = h; paint(true); } else paint(false); }); }
51  document.addEventListener("click", function(e){
52    var b = e.target.closest && e.target.closest(".notpo-cp button"); if (!b) return;
53    e.preventDefault(); e.stopPropagation();
54    b.disabled = true;
55    if (b.dataset.apply) { location.href = applyUrl(b.dataset.apply, "/checkout"); return; }
56    var amount = parseInt(b.dataset.amount, 10); b.textContent = "Creating your code…";
57    api("redeem_amount", { amount: amount }).then(function(r){
58      if (r.ok) { location.href = applyUrl(r.code, "/checkout"); }
59      else { b.textContent = r.error === "insufficient_points" ? "Not enough points" : "Something went wrong — your points were not spent"; setTimeout(function(){ api("me").then(function(m){ me = m; refresh(); }); }, 2500); }
60    });
61  }, true);
62  var pending = false;
63  new MutationObserver(function(){ if (pending) return; pending = true; setTimeout(function(){ pending = false; paint(false); if (me !== null) refresh(); }, 150); }).observe(document.documentElement, { childList: true, subtree: true });
64  ["cart:updated","cart:refresh","cart-drawer:open","drawer:open"].forEach(function(ev){ document.addEventListener(ev, function(){ refresh(); }); });
65  paint(false);
66  api("me").then(function(m){ me = m; refresh(); setInterval(function(){ if (!document.hidden) refresh(); }, 3000); }).catch(function(){ me = { signed_in: false }; refresh(); });
67})();

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.