Omacro Buy Now Widget BS4

Exploring Omacro Buy Now WIdget upgrade with Bootstrap 4

by Jesse Johnson

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-debug.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://bootswatch.com/4/cosmo/bootstrap.min.css">
<div class="omacro">
  <div class="modal" tabindex="-1" role="dialog" data-bind="with: product">
    <div class="modal-dialog modal-xl" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">
            <span data-bind="text: name"></span>
            <span data-bind="text: key" class="small"></span>
          </h5>
          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        </div>
        <div class="modal-body">
          <ul class="nav nav-tabs" role="tablist">
            <li class="nav-item">
              <a class="nav-link active" id="online-tab" data-toggle="tab" href="#online" role="tab" aria-controls="online" aria-selected="true">Online Retailers</a>
            </li>
            <li class="nav-item">
              <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Local Retailers</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" id="kocontext-tab" data-toggle="tab" href="#kocontext" role="tab" aria-controls="kocontext" aria-selected="false">Knockout Context</a>
            </li>
          </ul>
          <div class="tab-content">
            <div class="tab-pane show active" id="online" role="tabpanel" aria-labelledby="online-tab">
              <div class="modal">
                <div data-bind="with: markets">
                  <div data-bind="with: online"...

CSS

body {
  padding: 1rem;
}

.omacro {
  min-width: 480px;
}

.modal {
  position: relative;
  top: auto;
  right: auto;
  bottom: auto;
  left: auto;
  z-index: 1;
  display: block;
}

.modal-dialog {
  left: auto;
  margin-right: auto;
  margin-left: auto;
}

TypeScript

interface IRetailer {
  cid: string,
  name: string,
  logo: string,
  locations: IRetailLocation[]
}
interface IRetailLocation {
  lid: string,
  inStock?: boolean,
  price?: number
  attributes?: {
  	[name: string]: string
  }
}
interface IOnlineRetailer extends IRetailer {
  locations: IOnlineLocation[]
}
interface IOnlineLocation extends IRetailLocation {
 link: string;
}

var BUYNOW = {
  PRODUCTS: {
    SINGLEPRD: {
      KEY: "SINGLEPRD",
      NAME: "Sample Single Product",
      ISSTYLED: false,
      RETAILERS: {
        ONLINE: "https://next.json-generator.com/api/json/get/VyPblEhmG?indent=4&delay=1500"
      }
    },
    STYLEDPRD: {
      KEY: "STYLEDPRD",
      NAME: "Sample Styled Product",
      ISSTYLED: true,
      RETAILERS: {
        ONLINE: "https://next.json-generator.com/api/json/get/41YDiQ058?indent=4&delay=1500"
      }
    }
  }
}

class OnlineMarketViewModel {
	url: string;
	retailers: KnockoutObservableArray<IOnlineRetailer>;
	getRetailers() {
    $.getJSON(this.url, this.retailers);
  }
  constructor(data) {
  	this.url = data.RETAILERS.ONLINE;
  	this.retailers = ko.observableArray([]);
    this.getRetailers();
  }
}

class MarketplaceViewModel {
  online: OnlineMarketViewModel;
  constructor(data) {
  	this.online = new OnlineMarketViewModel(data);
  }
}

class ProductViewModel {
  key: KnockoutObservable<string>;
  name: KnockoutObservable<string>;
	markets: MarketplaceViewModel;
	constructor(data) {
  	this.key = ko.observable(data.KEY || null);
    this.name = ko.observable(data.NAME || null);
  	this.markets = new MarketplaceViewModel(data);
  }
}

class WidgetViewModel {
	product: KnockoutObservable<ProductViewModel>;
  show(key: string) {
   	let data = BUYNOW.PRODUCTS[key]; 
  	let product = new ProductViewModel(data);
  	this.product(product);
  }
  constructor() {
  	this.product = new ko.observable(null);
  }
}

let widget = new WidgetViewModel();

ko.applyBindings(widget);
widget.show(BUYNOW.PRODUCTS.STYLEDPRD.KEY);