Skip to content

Instantly share code, notes, and snippets.

@frankiefu
Created May 9, 2016 23:50
Show Gist options
  • Save frankiefu/7d331126726fe4e33ee3daad8284fffa to your computer and use it in GitHub Desktop.
Save frankiefu/7d331126726fe4e33ee3daad8284fffa to your computer and use it in GitHub Desktop.
<!--
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/carbon-route/carbon-route.html">
<link rel="import" href="../bower_components/iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="kart-button.html">
<link rel="import" href="kart-common-styles.html">
<link rel="import" href="kart-form-styles.html">
<link rel="import" href="kart-input.html">
<link rel="import" href="kart-select.html">
<link rel="import" href="kart-switch.html">
<!-- resources loaded by lazy-resources.html -->
<!--
<link rel="prefetch" href="../bower_components/iron-form/iron-form.html">
<link rel="prefetch" href="../bower_components/iron-icon/iron-icon.html">
<link rel="prefetch" href="../bower_components/paper-spinner/paper-spinner-lite.html">
<link rel="prefetch" href="kart-icons.html">
-->
<dom-module id="kart-checkout">
<template>
<style include="kart-common-styles kart-button kart-form-styles kart-input kart-select kart-switch">
.main-frame {
transition: opacity 0.5s;
}
:host([waiting]) .main-frame {
opacity: 0.1;
}
kart-input, kart-select {
font-size: 16px;
color: var(--app-accent-color);
}
kart-select {
margin-bottom: 20px;
}
paper-spinner-lite {
position: fixed;
top: calc(50% - 14px);
left: calc(50% - 14px);
}
.billing-address-picker {
margin: 30px 0;
}
.billing-address-picker > label {
margin-left: 10px;
vertical-align: middle;
}
.grid {
margin-top: 40px;
@apply(--layout-horizontal);
}
.grid > section {
@apply(--layout-flex);
}
.grid > section:not(:first-child) {
margin-left: 80px;
}
.row {
@apply(--layout-horizontal);
}
.column {
@apply(--layout-vertical);
}
.row > .flex,
.input-row > * {
@apply(--layout-flex);
}
.input-row > *:not(:first-child) {
margin-left: 8px;
}
.order-summary-row {
line-height: 24px;
}
.total-row {
font-weight: 500;
margin: 30px 0;
}
@media (max-width: 767px) {
:host {
margin-bottom: 64px;
}
.grid {
display: block;
margin-top: 0;
}
.grid > section:not(:first-child) {
margin-left: 0;
}
}
</style>
<div class="main-frame">
<iron-pages selected="[[state]]" attr-for-selected="state">
<div state="init">
<form action="/shop.axd/UpdateBillingAddress" method="post" name="frmBillingAddress">
<div class="theLeft">
<label>Name <span class="required">*</span></label>
<input class="input-medium" type="text" name="first_name" size="16" maxlength="16" value="" placeholder="First">
<input class="input-itty" type="text" name="middle_initial" size="1" maxlength="1" value="" placeholder="MI">
<input class="input-medium" type="text" name="last_name" size="16" maxlength="16" value="" placeholder="Last">
<label>Address <span class="required">*</span></label>
<input class="input-xlarge" type="text" name="street" size="40" maxlength="30" value="">
<label>Apt./Suite</label>
<input class="input-xlarge" type="text" name="address_ref1" size="40" maxlength="30" value="">
<label>City <span class="required">*</span></label>
<input class="input-xlarge" type="text" name="city" size="40" maxlength="30" value="">
<label>State <span class="required">*</span></label>
<div class="billing-address">
<select name="state">
<option value="" selected>State</option>
<option value="AK" >
AK: Alaska
<option value="AL" >
AL: Alabama
<option value="AR" >
AR: Arkansas
<option value="AZ" >
AZ: Arizona
<option value="CA" >
CA: California
<option value="CO" >
CO: Colorado
<option value="CT" >
CT: Connecticut
<option value="DC" >
DC: District of Columbia
<option value="DE" >
DE: Delaware
<option value="FL" >
FL: Florida
<option value="GA" >
GA: Georgia
<option value="GU" >
GU: Guam
<option value="HI" >
HI: Hawaii
<option value="IA" >
IA: Iowa
<option value="ID" >
ID: Idaho
<option value="IL" >
IL: Illinois
<option value="IN" >
IN: Indiana
<option value="KS" >
KS: Kansas
<option value="KY" >
KY: Kentucky
<option value="LA" >
LA: Louisiana
<option value="MA" >
MA: Massachusetts
<option value="MD" >
MD: Maryland
<option value="ME" >
ME: Maine
<option value="MI" >
MI: Michigan
<option value="MN" >
MN: Minnesota
<option value="MO" >
MO: Missouri
<option value="MS" >
MS: Mississippi
<option value="MT" >
MT: Montana
<option value="NC" >
NC: North Carolina
<option value="ND" >
ND: North Dakota
<option value="NE" >
NE: Nebraska
<option value="NH" >
NH: New Hampshire
<option value="NJ" >
NJ: New Jersey
<option value="NM" >
NM: New Mexico
<option value="NV" >
NV: Nevada
<option value="NY" >
NY: New York
<option value="OH" >
OH: Ohio
<option value="OK" >
OK: Oklahoma
<option value="OR" >
OR: Oregon
<option value="PA" >
PA: Pennsylvania
<option value="PR" >
PR: Puerto Rico
<option value="PW" >
PW: Palau
<option value="RI" >
RI: Rhode Island
<option value="SC" >
SC: South Carolina
<option value="SD" >
SD: South Dakota
<option value="TN" >
TN: Tennessee
<option value="TX" >
TX: Texas
<option value="UT" >
UT: Utah
<option value="VA" >
VA: Virginia
<option value="VT" >
VT: Vermont
<option value="WA" >
WA: Washington
<option value="WI" >
WI: Wisconsin
<option value="WV" >
WV: West Virginia
<option value="WY" >
WY: Wyoming
<option value=" " >
------- Canada --------
<option value="AB" >
AB: Alberta
<option value="BC" >
BC: British Columbia
<option value="MB" >
MB: Manitoba
<option value="NB" >
NB: New Brunswick
<option value="NF" >
NF: Newfoundland
<option value="NS" >
NS: Nova Scotia
<option value="NT" >
NT: Northwest Territory
<option value="NU" >
NU: Nunavut
<option value="ON" >
ON: Ontario
<option value="PE" >
PE: Prince Edward Island
<option value="PQ" >
PQ: Quebec
<option value="SK" >
SK: Saskatchewan
<option value="YT" >
YT: Yukon Territory
<option value=" " >
-----------------------
<option value="FN" >
Foreign (non-US/Canada)
</select>
</div>
<label>Zip Code <span class="required">*</span></label>
<input class="input-small" type="text" name="zip_code" size="12" maxlength="7" value="">&nbsp;
<input class="input-ext" type="text" name="zip_code_4" size="5" maxlength="4" value="">
</div>
<!-- pull-left -->
<div class="theRight">
<label>Country</label>
<div class="billing-address">
<select name="country_code">
<option value="0000" >
USA
<option value="0001" >
CANADA
</select>
</div>
<label>Phone <span class="required">*</span></label>
<input class="input-mini" type="text" name="day_phone_1" size="4" onkeyup="autotab(this, document.frmBillingAddress.day_phone_2)" maxlength="3" value="">
<input class="input-mini" type="text" name="day_phone_2" size="4" onkeyup="autotab(this, document.frmBillingAddress.day_phone_3)" maxlength="3" value="">
<input class="input-ext" type="text" name="day_phone_3" size="6" onkeyup="autotab(this, document.frmBillingAddress.day_phone_4)" maxlength="4" value="">
&nbsp; Ext:
<input class="input-ext" type="text" name="day_phone_4" size="4" maxlength="4" value="">
<label>Night Phone</label>
<input class="input-mini" type="text" name="night_phone_1" size="4" onkeyup="autotab(this, document.frmBillingAddress.night_phone_2)" maxlength="3" value="">
<input class="input-mini" type="text" name="night_phone_2" size="4" onkeyup="autotab(this, document.frmBillingAddress.night_phone_3)" maxlength="3" value="">
<input class="input-ext" type="text" name="night_phone_3" size="6" onkeyup="autotab(this, document.frmBillingAddress.night_phone_4)" maxlength="4" value="">
&nbsp; Ext:
<input class="input-ext" type="text" name="night_phone_4" size="4" maxlength="4" value="">
<label>Email Address <span class="required">*</span></label>
<input type="text" name="email" size="40" maxlength="50" value="">
<label>Shipping Options</label>
<div class="well">
<label class="radio">
<input type="radio" name="ship_to_flag" value="B" checked>
Ship entire order to my billing address
</label>
<label class="radio">
<input type="radio" name="ship_to_flag" value="C" >
Ship entire order to an address other than my billing address
</label>
</div>
<!-- /well -->
</div>
</form>
</div>
<!-- Success message UI -->
<header state="success">
<h1>Thanks for your purchase!</h1>
<p>[[response.successMessage]]</p>
<kart-button class="action-btn">
<a href="/">Finish</a>
</kart-button>
</header>
<!-- Error message UI -->
<header state="error">
<h1>We couldn&acute;t process your order</h1>
<p id="errorMessage">[[response.errorMessage]]</p>
<kart-button class="action-btn">
<a href="/checkout">Try again</a>
</kart-button>
</header>
</iron-pages>
</div>
<!-- Handles the routing for the success and error subroutes -->
<carbon-route
route="[[route]]"
pattern="/:state"
on-active-changed="_activeRouteHandler">
</carbon-route>
<!-- Show spinner when waiting for the server to repond -->
<paper-spinner-lite active="[[waiting]]"></paper-spinner-lite>
</template>
<script>
Polymer({
is: 'kart-checkout',
properties: {
/**
* The route for the state. e.g. `success` and `error` are mounted in the
* `checkout/` route.
*/
route: {
type: Object,
notify: true
},
/**
* The total price of the contents in the user's cart.
*/
total: Number,
/**
* The state of the form. Valid values are:
* `init`, `success` and `error`.
*/
state: {
type: String,
value: 'init'
},
/**
* An array containing the items in the cart.
*/
cart: Array,
/**
* The server's response.
*/
response: Object,
/**
* If true, the user must enter a billing address.
*/
hasBillingAddress: {
type: Boolean,
value: false
},
/**
* If true, kart-checkout is currently visible on the screen.
*/
visible: {
type: Boolean,
observer: '_visibleChanged'
},
/**
* True when waiting for the server to repond.
*/
waiting: {
type: Boolean,
readOnly: true,
reflectToAttribute: true
},
/**
* True when waiting for the server to repond.
*/
_hasItems: {
type: Boolean,
computed: '_computeHasItem(cart.length)'
}
},
_submit: function(e) {
if (this._validateForm()) {
this.$.checkoutForm.submit();
}
},
/**
* Sets the valid state and updates the location.
*/
_pushState: function(state) {
this._validState = state;
this.set('route.path', state);
},
/**
* Checks that the `:state` subroute is correct. That is, the state has been pushed
* after receiving response from the server. e.g. Users can only go to `/checkout/success`
* if the server responsed with a success message.
*/
_activeRouteHandler: function(e) {
var route = e.target;
if (e.detail.value) {
var state = route.data.state;
if (this._validState === state) {
this.state = state;
this._validState = '';
return;
}
}
this.state = 'init';
},
/**
* Sets the initial state.
*/
_reset: function() {
return;
var form = this.$.checkoutForm;
this._setWaiting(false);
form.reset();
// Remove the `aria-invalid` attribute from the form inputs.
for (var el, i = 0; el = form.elements[i], i < form.elements.length; i++) {
el.removeAttribute('aria-invalid');
}
},
/**
* Validates the form's inputs and adds the `aria-invalid` attribute to the inputs
* that don't match the pattern specified in the markup.
*/
_validateForm: function() {
var form = this.$.checkoutForm;
var firstInvalid = false;
for (var el, i = 0; el = form.elements[i], i < form.elements.length; i++) {
if (el.checkValidity()) {
el.removeAttribute('aria-invalid');
} else {
if (!firstInvalid) {
// announce error message
if (el.nextElementSibling) {
this.fire('announce', el.nextElementSibling.getAttribute('error-message'));
}
if (el.scrollIntoViewIfNeeded) {
// safari, chrome
el.scrollIntoViewIfNeeded();
} else {
// firefox, edge, ie
el.scrollIntoView(false);
}
el.focus();
firstInvalid = true;
}
el.setAttribute('aria-invalid', 'true');
}
}
return !firstInvalid;
},
/**
* Adds the cart data to the payload that will be sent to the server
* and updates the UI to reflect the waiting state.
*/
_willSendRequest: function(e) {
var form = e.target;
var rqBody = form.request.body;
// Populate the request body where `cartItemsId[i]` is the ID and `cartItemsQuantity[i]`
// is the quantity for some item `i`.
rqBody.cartItemsId = [];
rqBody.cartItemsQuantity = [];
this.cart.forEach(function(cartItem) {
rqBody.cartItemsId.push(cartItem.item.itemId);
rqBody.cartItemsQuantity.push(cartItem.quantity);
});
this._setWaiting(true);
},
/**
* Handles the response from the server by checking the response status
* and transitioning to the success or error UI.
*/
_didReceiveResponse: function(e) {
var response = e.detail.response;
this.response = response;
this._setWaiting(true);
if (response.success) {
this._pushState('success');
this._reset();
this.fire('clear-cart');
} else {
this._pushState('error');
}
},
_toggleBillingAddress: function(e) {
this.hasBillingAddress = e.target.checked;
if (this.hasBillingAddress) {
this.$.frmAddressB.focus();
}
},
_computeHasItem: function(cartLength) {
return cartLength > 0;
},
_formatPrice: function(total) {
return isNaN(total) ? '' : '$' + total.toFixed(2);
},
_getEntryTotal: function(entry) {
return this._formatPrice(entry.quantity * entry.item.price);
},
_visibleChanged: function(visible) {
if (!visible) {
return;
}
// Reset the UI states
this._reset();
// Notify the page's title
this.fire('change-section', { title: 'Checkout' });
}
});
</script>
</dom-module>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment