JSFiddle - React, Tailwind, and code Playground

Emulator with Promises

by herodrigues

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.4.6/bluebird.min.js"></script>
<body>
    <div class='network-fake'>
      <label><input type='checkbox'> Fake network delay</label>
    </div>
    <div class='coupon'></div>
    <svg class='spinner' viewBox='0 0 100 100' width='20' height='20'>
      <circle cx='50' cy='50' r='42' transform='rotate(-90,50,50)' />
    </svg>

    <br />
    <input type="text" id="code" value="">
    <input type="button" value="Apply" id="apply" >
  </body>

CSS

@-webkit-keyframes spin {
  to {
    stroke-dashoffset: -264;
  }
}

@keyframes spin {
  to {
    stroke-dashoffset: -264;
  }
}

.spinner circle {
  fill: none;
  stroke: slategray;
  stroke-width: 16;
  stroke-linecap: round;
  stroke-dasharray: 0, 0, 70, 194;
  stroke-dashoffset: 0;
  animation: spin 1s infinite linear;
  -webkit-animation: spin 1s infinite linear;
}

html {
  font-family: sans-serif;
  line-height: 1.5;
  font-size: 14px;
}
h1 {
  font-family: Cambria, Georgia, serif;
  font-size: 2em;
  line-height: 1.3em;
  margin: 0 0 0.5em;
}
.network-fake {
  display: none;
  margin-bottom: 1em;
}
input {
  vertical-align: middle;
}

JavaScript

let fakeSlowNetwork;

document.addEventListener('DOMContentLoaded', function() {
  const lsKey = 'fake-slow-network';
  const networkFakeDiv = document.querySelector('.network-fake');
  const checkbox = networkFakeDiv.querySelector('input');
  const couponDiv = document.querySelector('.coupon');

  fakeSlowNetwork = Number(localStorage.getItem(lsKey)) || 0;

  networkFakeDiv.style.display = 'block';
  checkbox.checked = !!fakeSlowNetwork;

  checkbox.addEventListener('change', function() {
    localStorage.setItem(lsKey, Number(checkbox.checked));
    location.reload();
  });

  document.getElementById('apply').addEventListener('click', function () {
    const url = 'http://goguru.io/api/v1/coupons?url=http://www.ricardoeletro.com.br&locale=pt-BR';

    getStoreData(url).then(JSON.parse).then(function(storeData) {
      // Map our array of coupons to an array of coupon json promises
      return storeData.coupons.reduce(function(chain, coupon) {
        return chain.then(function() {
          return simulateClick(coupon);
        }).then(function(response) {
          addHtmlToPage(coupon.code);
        });
      }, Promise.resolve());
    }).then(function() {
      addTextToPage('All done');
    }).catch(function(error) {
      addTextToPage('Argh, broken: ' + error.message);
    }).then(function() {
      document.querySelector('.spinner').style.display = 'none';
    });
  });

  function wait(ms) {
    return new Promise(function(resolve) {
      setTimeout(resolve, ms);
    });
  }

  function getStoreData(url) {
    return new Promise(function(resolve, reject) {
      const xhr = new XMLHttpRequest();
      xhr.open('GET', url);
      xhr.onload = function() {
        if (xhr.status == 200) {
          resolve(xhr.response);
        } else {
          reject(Error(xhr.statusText));
        }
      };

      xhr.onerror = function() {
        reject(Error("Network Error"));
      };
      xhr.send();
    });
  }

  function simulateClick(params) {
    const...