Raw Source
noahzark / Rewardpoints per Dollar

// ==UserScript==
// @name         Rewardpoints per Dollar
// @version      2.0
// @updateURL    https://openuserjs.org/meta/noahzark/Starpoints_per_Dollar.meta.js
// @description  calculates the value of starpoints when redeeming to free nights, yellow suggests to redeem and green suggests to use cash
// @author       Feliciano Long
// @match        *://www.marriott.com/search/*
// @match        *://www.marriott.com/reservation/*
// @match        *://www.marriott.com.cn/search/*
// @match        *://www.marriott.com.cn/reservation/*
// @run-at       document-end
// @grant        none
// @license      MIT
// ==/UserScript==

  function isNull(A) {
    if (A === null || typeof A == 'undefined') {
      A = "";
    }
    return (A.length === 0);
  }

  function getRatio(price, points, currency) {
    var ratio = (price / currency / points * 100).toPrecision(5)
    console.log(price / currency + " : " + points + " = " + ratio);
    return ratio;
  }

  function getValueColor(ratio, scale) {
    var color = (ratio > 0.75 / scale) ? "orange" : "red";
    color = (ratio < 0.45 / scale) ? "green" : color;
    return color;
  }

  function analyze() {
    var dollars;
    var ratio;
    var color;
    var i;
    var rewardpoints;

    console.log("Page loaded.");
    var brand = '';
    if (location.href.indexOf('/search/') > -1) {
      console.log("Analyzing Marriot Prices");
      var marriott_entries = $('.rate-block');
      console.log("found " + marriott_entries.length + " marriott entries");
      if (marriott_entries !== null) {
        // Load the nights of this stay
        var nights = 1;

        var cp_range = {}
        for (i = 0; i < marriott_entries.length; i++) {
          var price = marriott_entries[i].getElementsByClassName("t-price")[0];
          var currencyExchange = $('*[data-name="currency"] > span > span').first().text();
          console.log("currency:" + currencyExchange);
          if (currencyExchange.indexOf('CNY') > -1) {
            currencyExchange = 7.2;
          } else if (currencyExchange.indexOf('HKD') > -1) {
              currencyExchange = 7.83;
          } else {
            currencyExchange = 1;
          }
          var rewardpoint = marriott_entries[i].getElementsByClassName("t-points")[0];

          // Load adjusted points
          rewardpoint = isNull(rewardpoint) ? marriott_entries[i].getElementsByClassName("t-points")[0] : rewardpoint;

          if (isNull(price) || isNull(rewardpoint)) {
            console.log("No." + i + " is not valid");
            continue;
          }

          console.log(price.innerHTML + " " + rewardpoint.innerHTML);

          ratio = getRatio(parseInt(price.innerHTML.replace(/,/g, '')), parseInt(rewardpoint.innerHTML.replace(/,/g, '')) * 1.0 / nights, currencyExchange);
          var ratio_range = parseInt(ratio * 10)
          cp_range[ratio_range] = (cp_range[ratio_range] || 0) + 0.5
          //console.log(dollars + " : " + rewardpoints + " = " + ratio);

          color = getValueColor(ratio, 1);
          var node = document.createElement("span");
          node.style = "color:" + (color) + "; font-weight:bold\"";
          var textnode = document.createTextNode(ratio + " c/p");
          node.appendChild(textnode);
          marriott_entries[i].getElementsByClassName("non-eeo-price-container")[0].appendChild(node);
        }
        const entries = Object.entries(cp_range);
        const sortedEntries = entries.sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
        const sortedDictionary = Object.fromEntries(sortedEntries);
        console.log(JSON.stringify(sortedDictionary, null, 2));
      }
    }
  }

  window.addEventListener('load', function() {
      setTimeout(analyze, 10 * 1000);
  });