diff --git a/README.md b/README.md index 834b093..ce84416 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Contents: * [1](https://github.com/rspective/voucherify.js#initialize-settings) - Installation and client-side authentication * [2](https://github.com/rspective/voucherify.js#validation) - How to validate [vouchers](https://docs.voucherify.io/reference/#vouchers-validate) and [promotions](https://docs.voucherify.io/reference/#validate-promotions-1) -* [3](https://github.com/rspective/voucherify.js#redeem-vouchers) - How to call [redemption](https://docs.voucherify.io/reference/#redeem-voucher-client-side) +* [3](https://github.com/rspective/voucherify.js#redemption) - How to call [redemption](https://docs.voucherify.io/reference/#redeem-voucher-client-side) * [4](https://github.com/rspective/voucherify.js#publish-vouchers) - How to call [publish](https://docs.voucherify.io/reference/#publish-voucher) coupons * [5](https://github.com/rspective/voucherify.js#list-vouchers) - How to call [list](https://docs.voucherify.io/reference/#list-vouchers) coupons * [6](https://github.com/rspective/voucherify.js#validation-widget) - Configuring validation widget @@ -307,16 +307,16 @@ Voucherify.validate("VOUCHER-CODE") There are several reasons why validation may fail (`valid: false` response). You'll find the actual cause in the `reason` field. For more details, visit [error reference](https://docs.voucherify.io/reference#errors) section. -### Redeem vouchers +### Redemption -Next to validation, the library allows you to [redeem](https://docs.voucherify.io/reference/#redeem-voucher-client-side) vouchers. +Next to validation, the library allows you to redeem [vouchers](https://docs.voucherify.io/reference/#redeem-voucher-client-side) and [promotions](https://docs.voucherify.io/reference/#redeem-promotion). Note: you have to enable **client-side redemptions** in your project's configuration. Reference: [redemption object](http://docs.voucherify.io/reference#the-redemption-object), [client-side redeem](https://docs.voucherify.io/reference/#redeem-voucher-client-side) How to use it: - +#### Vouchers `Voucherify.redeem("VOUCHER-CODE", payload, function callback (response) { })` where `payload` is an object which can include: @@ -325,12 +325,12 @@ where `payload` is an object which can include: - `source_id` - if not set, `tracking_id` will be used (if `tracking_id` is set) - `order` - with at least - `amount` +- `metadata` Example: `Voucherify.redeem("gfct5ZWI1nL", { order: { amount: 5000 } }, function callback (response) { })` - Success response ```javascript @@ -381,6 +381,89 @@ Success response } ``` +#### Promotion + +`Voucherify.redeem(null, payload, function callback (response) { })` + +where `payload` is an object which can include: + +- `tier` - promotion tier ID +- `customer` - voucher customer object + - `source_id` - if not set, `tracking_id` will be used (if `tracking_id` is set) +- `order` - with at least + - `amount` +- `metadata` + +Example: + +`Voucherify.redeem(null, { tier: 'promo_yourpromotiontierid', order: { amount: 5000 } }, function callback (response) { })` + +Success response + +```javascript +{ + "object": "redemption", + "customer_id": "cust_vAZ0M5nQUDv3zDoAcT6QSYhb", + "tracking_id": "(tracking_id not set)" + "result": "SUCCESS", + "amount": 30, + "order": { + "amount": 30, + "discount_amount": 30, + "items": null, + "customer": { + "id": "cust_vAZ0M5nQUDv3zDoAcT6QSYhb", + "object": "customer" + }, + "referrer": null, + "status": "CREATED", + "metadata": null + }, + "promotion_tier":{ + "id":"promo_TvPlKsF2tNXh3GhKPh0JKtDa", + "object":"promotion_tier", + "name":"tier_2", + "banner":null, + "campaign":{ + "id":"camp_mFxeXvEj7VeugrmFGdUNmKEp", + "object":"campaign", + "start_date":"2018-04-18T00:00:00Z", + "expiration_date":"2023-07-02T00:00:00Z", + "active":true + }, + "condition":{ + "id":"val_TerxvCfNklYF", + "created_at":"2018-04-25T07:06:29Z", + "junction":"AND", + "orders":{ + "junction":"AND", + "any_order_item_price":{ + "$more_than":[ + 1000000 + ] + } + } + }, + "action":{ + "discount":{ + "type":"AMOUNT", + "amount_off":100000 + } + }, + "metadata":null, + "summary":{ + "redemptions":{ + "total_redeemed":1 + }, + "orders":{ + "total_amount":0, + "total_discount_amount":0 + } + } + } +} +``` + If you are using *jQuery* in version higher than *1.5*, you can use its implementation of promises (remember to load `voucherify.js` script after loading *jQuery*): ```javascript @@ -671,6 +754,7 @@ The widget is fully configurable. You can decide which fields are visible and re ### Changelog +- **2018-04-25** - `1.19.0` - Add client side method for promotion redemption - **2018-04-24** - `1.18.0` - Add client side method for promotion validation - **2017-12-12** - `1.17.0` - Add redeem iframe widget - **2017-10-23** - `1.16.1` - Fix tracking custom events diff --git a/dist/voucherify.js b/dist/voucherify.js index b67300e..93019bd 100644 --- a/dist/voucherify.js +++ b/dist/voucherify.js @@ -9,7 +9,8 @@ window.Voucherify = (function (window, document, $) { publish: API_BASE + "/client/v1/publish", list: API_BASE + "/client/v1/vouchers", track: API_BASE + "/client/v1/events", - validatePromotion: API_BASE + "/client/v1/promotions/validation" + validatePromotion: API_BASE + "/client/v1/promotions/validation", + redeemPromotion: API_BASE + "/client/v1/promotions/tiers/" }; var OPTIONS = {}; @@ -285,23 +286,35 @@ window.Voucherify = (function (window, document, $) { }, redeem: function (code, payload, callback) { + var isPromotion = false; + var tier; + if (!isValidInit(OPTIONS)) { return null; } if (!code) { - console.error("Voucherify client could not verify code, because it is missing - please provide Voucher Code."); - return null; + if( !payload.tier ){ + console.error("Voucherify client could not redeem promotion without tier, because it is missing."); + return null; + } + isPromotion = true; + tier = payload.tier; + delete payload.tier } - var queryString = "?code=" + encodeURIComponent(code.replace(/[\s\r\n]/g, "")); + var queryString = "" + if(!isPromotion){ + queryString += "?code=" + encodeURIComponent(code.replace(/[\s\r\n]/g, "")); + } // -- Tracking ID fallback payload = payload || {}; payload.customer = payload.customer || {}; payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId; - return xhrImplementation("POST", API.redeem + queryString, payload, callback); + + return xhrImplementation("POST", (isPromotion ? API.redeemPromotion + tier + "/redemption" : API.redeem) + queryString, payload, callback); }, publish: function (campaign, payload, callback) { diff --git a/dist/voucherify.min.js b/dist/voucherify.min.js index ec65cf7..ee41027 100644 --- a/dist/voucherify.min.js +++ b/dist/voucherify.min.js @@ -1,2 +1,2 @@ -window.Voucherify=function(e,t,n){"use strict";function o(e){return e&&("boolean"==typeof e.valid||"string"==typeof e.result||"object"==typeof e.voucher||"object"==typeof e.vouchers||"event"===e.object&&"string"==typeof e.type)}function i(e){return Math.round(100.001*e)/100}function r(e){if(!e||0>e||e>100)throw new Error("Invalid voucher, percent discount should be between 0-100.")}function a(e){if(!e||0>e)throw new Error("Invalid voucher, amount discount must be higher than zero.")}function l(e){if(!e||0>e)throw new Error("Invalid voucher, unit discount must be higher than zero.")}function s(e){return e.applicationId?e.applicationId?!0:(console.error("Voucherify.js ERROR: Missing Client Token (Secret Key)."),!1):(console.error("Voucherify.js ERROR: Missing Client Application ID."),!1)}function c(){function n(e,t){var n=this;return n._element=e,n._path=t.path,n._options=a.readOptions(n._element,i.concat(t.attributes)),n._iframe=null,this.renderIframe()}var o="https://app.voucherify.io",i=["client-app-id","client-token","logo"],r={"voucher-redeem":{path:"/widgets/redeem",attributes:["code-field","code-field-required","code-field-label","amount-field","amount-field-required","amount-field-label","name-field","name-field-required","name-field-label","email-field","email-field-required","email-field-label","phone-field","phone-field-required","phone-field-label","address-line-1-field","address-line-1-field-required","address-line-1-field-label","address-line-2-field","address-line-2-field-required","address-line-2-field-label","city-field","city-field-required","city-field-label","postal-code-field","postal-code-field-required","postal-code-field-label","state-field","state-field-required","state-field-label","country-field","country-field-required","country-field-label","button-label"]},"get-voucher":{path:"/widgets/publish",attributes:["campaign","metadata","source","name-field","name-field-required","name-field-label","email-field","email-field-required","email-field-label","phone-field","phone-field-required","phone-field-label","address-line-1-field","address-line-1-field-required","address-line-1-field-label","address-line-2-field","address-line-2-field-required","address-line-2-field-label","city-field","city-field-required","city-field-label","postal-code-field","postal-code-field-required","postal-code-field-label","state-field","state-field-required","state-field-label","country-field","country-field-required","country-field-label","button-label"]},subscribe:{path:"/widgets/subscribe",attributes:["metadata","source","name-field","name-field-required","name-field-label","email-field","email-field-required","email-field-label","phone-field","phone-field-required","phone-field-label","address-line-1-field","address-line-1-field-required","address-line-1-field-label","address-line-2-field","address-line-2-field-required","address-line-2-field-label","city-field","city-field-required","city-field-label","postal-code-field","postal-code-field-required","postal-code-field-label","state-field","state-field-required","state-field-label","country-field","country-field-required","country-field-label","subscribe-label"]}},a={bind:function(e,t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent("on"+t,n)},readOptions:function(e,t){return Array.prototype.reduce.call(t,function(t,n){var o=e.getAttribute("data-"+n);return o&&(t[n]=o),t},{})},encodeOptions:function(e){var t=[];return Object.keys(e).forEach(function(n){t.push("[options]["+n+"]="+encodeURIComponent(e[n]))}),"?"+t.join("&")}};n.prototype.renderIframe=function(){var e=this;if(e._iframe)return e;var n=["width:400px;","height:475px;","background: transparent;","border: 0px none transparent;","overflow-x: hidden;","overflow-y: auto;","visibility: hidden;","margin: 0;","padding: 0;","-webkit-tap-highlight-color: transparent;","-webkit-touch-callout: none;"];return e._iframe=t.createElement("iframe"),e._iframe.setAttribute("frameBorder","0"),e._iframe.setAttribute("allowtransparency","true"),e._iframe.style.cssText=n.join("\n"),a.bind(e._iframe,"load",function(){return e._iframe.style.visibility="visible"}),e._iframe.src=o+e._path+a.encodeOptions(e._options),e._element.appendChild(e._iframe),e};var l=[];return Object.keys(r).forEach(function(t){var o=e.document.querySelectorAll(".voucherify-"+t);Array.prototype.forEach.call(o,function(e){l.push(new n(e,r[t]))})}),l}var d="https://api.voucherify.io",u={validate:d+"/client/v1/validate",redeem:d+"/client/v1/redeem",publish:d+"/client/v1/publish",list:d+"/client/v1/vouchers",track:d+"/client/v1/events",validatePromotion:d+"/client/v1/promotions/validation"},f={},p="invalid_amount",m="invalid_number",g="missing_amount",h="invalid_customer_phone",v=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,y=null;y=n&&"function"==typeof n.ajax&&n.Deferred?function(e,t,i,r){var a=null;return"function"!=typeof r&&(a=n.Deferred()),n.ajax({type:e,url:t,data:JSON.stringify(i),xhrFields:{withCredentials:!0},dataType:"json",headers:{Accept:"application/json","Content-Type":"application/json","X-Client-Application-Id":f.applicationId,"X-Client-Token":f.token,"X-Voucherify-Channel":"Voucherify.js"},timeout:f.timeout,success:function(e){var t=null;o(e)?"function"==typeof r?r(e):a.resolve(e):(t={type:"error",message:"Unexpected response structure.",context:e},"function"==typeof r?r(t):a.reject(t))},error:function(e){var t={type:"error",message:"XHR error happened.",context:e};"function"==typeof r?r(t):a.reject(t)}}),"function"!=typeof r?a.promise():void 0}:function(t,n,i,r){var a=new e.XMLHttpRequest;a.withCredentials=!0,a.open(t,n,!0),a.timeout=f.timeout,a.setRequestHeader("Accept","application/json"),a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("X-Client-Application-Id",f.applicationId),a.setRequestHeader("X-Client-Token",f.token),a.setRequestHeader("X-Voucherify-Channel","Voucherify.js"),a.onload=function(){var e=null;if(a.status>=200&&a.status<400){var t=JSON.parse(a.responseText);o(t)?"function"==typeof r&&r(t):(e={type:"error",message:"Unexpected response structure.",context:t},"function"==typeof r&&r(e))}else e={type:"error",message:"Unexpected status code.",context:a.status},"function"==typeof r&&r(e)},a.onerror=function(e){var t={type:"error",message:"XHR error happened.",context:e};"function"==typeof r&&r(t)},a.send(JSON.stringify(i))};var b={initialize:function(e,t,n){f.applicationId=e,f.token=t,f.timeout=n||5e3},setIdentity:function(e){f.trackingId=e},validate:function(e,t){if(!s(f))return null;var n,o,i,r,a=!1;"object"==typeof e&&(n=e.amount,o=e.items,i=e.metadata,r=e.customer,e=e.code),e&&(e=e.replace(/[\s\r\n]/g,""));var l="?";if(e?(l+="code="+encodeURIComponent(e),n&&(l+="&amount="+parseInt(n))):(a=!0,n&&(l+="amount="+parseInt(n))),o&&(l+="&"+o.map(function(e,t){return Object.keys(e).map(function(n){return encodeURIComponent("item["+t+"]["+n+"]")+"="+encodeURIComponent(e[n])}).join("&")}).join("&")),i&&(l+="&"+Object.keys(i).map(function(e){return encodeURIComponent("metadata["+e+"]")+"="+encodeURIComponent(i[e])}).join("&")),r){if("object"!=typeof r)return console.error("Customer must be an object - please use instead { source_id: 'your_user' }"),null;l+="&"+Object.keys(r).map(function(e){return encodeURIComponent("customer["+e+"]")+"="+encodeURIComponent(r[e])}).join("&")}return f.trackingId&&(l+="&tracking_id="+encodeURIComponent(f.trackingId)),y("GET",(a?u.validatePromotion:u.validate)+l,void 0,t)},redeem:function(e,t,n){if(!s(f))return null;if(!e)return console.error("Voucherify client could not verify code, because it is missing - please provide Voucher Code."),null;var o="?code="+encodeURIComponent(e.replace(/[\s\r\n]/g,""));return t=t||{},t.customer=t.customer||{},t.customer.source_id=t.customer.source_id||f.trackingId,y("POST",u.redeem+o,t,n)},publish:function(e,t,n){if(!s(f))return null;if(!e)return console.error("Voucherify.js ERROR: campaign is required to publish a voucher."),null;var o="?campaign="+encodeURIComponent(e);return t=t||{},t.customer=t.customer||{},t.customer.source_id=t.customer.source_id||f.trackingId,t.channel=t.channel||"Voucherify.js",y("POST",u.publish+o,t,n)},listVouchers:function(e,t){if(!s(f))return null;"function"!=typeof e||t||(t=e,e={});var n="?"+Object.keys(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&");return y("GET",u.list+n,void 0,t)},track:function(e,t,n,o){if(!s(f))return null;"function"!=typeof n||o||(o=n,n={});var i={};return i.event=e,i.metadata=t,i.customer=i.customer||n||{},i.customer.source_id=i.customer.source_id||f.trackingId,y("POST",u.track,i,o)},utils:{calculatePrice:function(e,t,n){var o,s=100;if(t.gift)return o=Math.min(t.gift.balance/s,e),i(e-o);if(!t.discount)throw new Error("Unsupported voucher type.");if("PERCENT"===t.discount.type){o=t.discount.percent_off,r(o);var c=e*(o/100);return t.discount.amount_limit&&(c=Math.min(t.discount.amount_limit/s,c)),i(e-c)}if("AMOUNT"===t.discount.type){o=t.discount.amount_off/s,a(o);var d=e-o;return i(d>0?d:0)}if("UNIT"===t.discount.type){o=t.discount.unit_off,l(o);var d=e-n*o;return i(d>0?d:0)}throw new Error("Unsupported discount type.")},calculateDiscount:function(e,t,n){var o,s=100;if(t.gift)return o=Math.min(t.gift.balance/s,e),i(o);if(!t.discount)throw new Error("Unsupported voucher type.");if("PERCENT"===t.discount.type){o=t.discount.percent_off,r(o);var c=e*(o/s);return t.discount.amount_limit&&(c=Math.min(t.discount.amount_limit/s,c)),i(c)}if("AMOUNT"===t.discount.type){o=t.discount.amount_off/s,a(o);var d=e-o;return i(d>0?o:e)}if("UNIT"===t.discount.type){o=t.discount.unit_off,l(o);var c=n*o;return i(c>e?e:c)}throw new Error("Unsupported discount type.")}},render:function(e,o){function i(e){return e.charAt(0).toUpperCase()+e.slice(1)}function r(e,t){return e+i(t)}function a(e,t){return o[r(e,t)]}function l(e,o,i,l){l=l||{};var s=null,c=a("selector",o);if(l.configurable&&c&&(s=n(c)),!s||!s.length){s=n(t.createElement(e)),i.append(s);for(var d in l)"configurable"!==d&&l.hasOwnProperty(d)&&s.attr(d,l[d]);"input"===e&&s.attr("name",r("voucherify",o)),"span"===e&&l.text&&s.text(l.text)}return s.addClass("string"==typeof a("class",o)?a("class",o):r("voucherify",o)),s}var s=n(e);if(!s||!s.length)throw new Error("Element '"+e+"' cannot be found");o=o||{};var c=l("div","container",s),d=l("figure","logo",c),u=(l("img","logo",d,{src:"string"==typeof o.logoSrc?o.logoSrc:"https://app.voucherify.io/images/favicon.png"}),l("input","code",c,{type:"text",placeholder:"string"==typeof o.textPlaceholder?o.textPlaceholder:"e.g. abc-123"})),f=l("input","amount",c,{type:o.amount?"text":"hidden",placeholder:"string"==typeof o.amountPlaceholder?o.amountPlaceholder:"e.g. 52.22"}),h=l("input","discountType",c,{type:"hidden",configurable:!0}),v=l("input","percentOff",c,{type:"hidden",configurable:!0}),y=l("input","amountOff",c,{type:"hidden",configurable:!0}),b=l("input","unitOff",c,{type:"hidden",configurable:!0}),C=l("input","tracking",c,{type:"hidden",configurable:!0}),_=l("button","validate",c,{}),x=(l("span","validateText",_,{text:"string"==typeof o.textValidate?o.textValidate:"Validate"}),this),w="string"===o.classInvalid?o.classInvalid:"voucherifyInvalid",I="string"==typeof o.classValid?o.classValid:"voucherifyValid",P="string"===o.classInvalidAnimation?o.classInvalidAnimation:"voucherifyAnimationShake",q="string"===o.classValidAnimation?o.classValidAnimation:"voucherifyAnimationTada";u.on("keyup",function(e){u.toggleClass(P,!1)}),f.on("keyup",function(e){f.toggleClass(P,!1)}),_.on("click",function(e){if(h.val(""),y.val(""),b.val(""),v.val(""),C.val(""),_.toggleClass(w,!1),_.toggleClass(I,!1),!u.val())return void u.toggleClass(P,!0).delay(1e3).queue(function(){u.toggleClass(P,!1),u.dequeue()});var t={code:u.val(),amount:parseInt(100*parseFloat(f.val().replace(/\,/,".")))};x.validate(t,function(e){if(!e||!e.valid){var t=function(e){e.toggleClass(w,!0),e.toggleClass(I,!1),e.toggleClass(P,!0).delay(1e3).queue(function(){e.toggleClass(P,!1),e.dequeue()})};_.toggleClass(w,!0),_.toggleClass(I,!1);var n=e.context||{},i=n.responseJSON||{},r=i.key;return void t(!o.amount||r!==p&&r!==m&&r!==g?u:f)}f.val()>=0?f.val(parseFloat(f.val().replace(/\,/,"."))):f.hide(100),u.toggleClass(w,!1),f.toggleClass(w,!1),h.val(e.discount&&e.discount.type||""),y.val(e.discount&&e.discount.amount_off||0),b.val(e.discount&&e.discount.unit_off||0),v.val(e.discount&&e.discount.percent_off||0),C.val(e.tracking_id||""),u.prop("disabled",!0),f.prop("disabled",!0),_.prop("disabled",!0),u.toggleClass(I,!0),f.toggleClass(I,!0),_.toggleClass(I,!0),_.toggleClass(w,!1),u.toggleClass(w,!1),u.toggleClass(q,!0),f.toggleClass(q,!0),o&&o.onValidated&&"function"==typeof o.onValidated&&o.onValidated(e)})})},renderRedeem:function(e,o){function i(e){return e.charAt(0).toUpperCase()+e.slice(1)}function r(e,t){return e+i(t)}function a(e,t){return o[r(e,t)]}function l(e,o,i,l){l=l||{};var s=null,c=a("selector",o);if(l.configurable&&c&&(s=n(c)),!s||!s.length){s=n(t.createElement(e)),i.append(s);for(var d in l)"configurable"!==d&&l.hasOwnProperty(d)&&s.attr(d,l[d]);"input"===e&&s.attr("name",r("voucherify",o)),"span"===e&&l.text&&s.text(l.text)}return s.addClass("string"==typeof a("class",o)?a("class",o):r("voucherify",o)),s}var s=n(e);if(!s||!s.length)throw new Error("Element '"+e+"' cannot be found");o=o||{};var c=l("div","container",s),d=l("figure","logo",c),u=(l("img","logo",d,{src:"string"==typeof o.logoSrc?o.logoSrc:"https://app.voucherify.io/images/favicon.png"}),l("input","code",c,{type:"text",placeholder:"string"==typeof o.textPlaceholder?o.textPlaceholder:"e.g. abc-123"})),f=l("input","amount",c,{type:o.amount?"text":"hidden",placeholder:"string"==typeof o.amountPlaceholder?o.amountPlaceholder:"e.g. 52.22"}),h=l("input","tracking",c,{type:"hidden",configurable:!0}),v=l("button","redeem",c,{}),y=(l("span","redeemText",v,{text:"string"==typeof o.textRedeem?o.textRedeem:"Redeem"}),this),b="string"===o.classInvalid?o.classInvalid:"voucherifyInvalid",C="string"==typeof o.classValid?o.classValid:"voucherifyValid",_="string"===o.classInvalidAnimation?o.classInvalidAnimation:"voucherifyAnimationShake",x="string"===o.classValidAnimation?o.classValidAnimation:"voucherifyAnimationTada";u.on("keyup",function(e){u.toggleClass(_,!1)}),f.on("keyup",function(e){f.toggleClass(_,!1)}),v.on("click",function(e){if(h.val(""),v.toggleClass(b,!1),v.toggleClass(C,!1),!u.val())return void u.toggleClass(_,!0).delay(1e3).queue(function(){u.toggleClass(_,!1),u.dequeue()});var t={order:{amount:parseInt(100*parseFloat(f.val().replace(/\,/,".")))}};y.redeem(u.val(),t,function(e){if(!e||"SUCCESS"!==e.result){var t=function(e){e.toggleClass(b,!0),e.toggleClass(C,!1),e.toggleClass(_,!0).delay(1e3).queue(function(){e.toggleClass(_,!1),e.dequeue()})};v.toggleClass(b,!0),v.toggleClass(C,!1);var n=e.context||{},i=n.responseJSON||{},r=i.key;return void t(!o.amount||r!==p&&r!==m&&r!==g?u:f)}f.val()>=0?f.val(parseFloat(f.val().replace(/\,/,"."))):f.hide(100),u.toggleClass(b,!1),f.toggleClass(b,!1),h.val(e.tracking_id||""),u.prop("disabled",!0),f.prop("disabled",!0),v.prop("disabled",!0),u.toggleClass(C,!0),f.toggleClass(C,!0),v.toggleClass(C,!0),v.toggleClass(b,!1),u.toggleClass(b,!1),u.toggleClass(x,!0),f.toggleClass(x,!0),o&&o.onRedeem&&"function"==typeof o.onRedeem&&o.onRedeem(e)})})},renderPublish:function(e,o){function i(e,t){return Array.prototype.some.call(e||[],function(e){return e.name===t})}function r(e){return i(o.customerFields,e)}function a(e){var t=Array.prototype.find.call(o.customerFields||[],function(t){return t.name===e});return t&&t.required||!1}function l(e){return e.charAt(0).toUpperCase()+e.slice(1)}function s(e,t){return e+l(t)}function c(e,t){return o[s(e,t)]}function d(e,o,i,r){r=r||{};var a=null,l=c("selector",o);if(r.configurable&&l&&(a=n(l)),!a||!a.length){a=n(t.createElement(e)),i.append(a);for(var d in r)"configurable"!==d&&r.hasOwnProperty(d)&&a.attr(d,r[d]);"input"===e&&a.attr("name",s("voucherify",o)),"span"===e&&r.text&&a.text(r.text)}return a.addClass("string"==typeof c("class",o)?c("class",o):s("voucherify",o)),a}function u(e){e.toggleClass(O,!0),e.toggleClass(S,!1),e.toggleClass(T,!0).delay(1e3).queue(function(){e.toggleClass(T,!1),e.toggleClass(O,!1),e.toggleClass(S,!1),e.dequeue()})}var f=n(e);if(!f||!f.length)throw new Error("Element '"+e+"' cannot be found");if(o=o||{},!o.campaignName)throw new Error("Option campaignName is not specified");var p=d("div","container",f);p.addClass("wide");{var m=d("figure","logo",p),g=(d("img","logo",m,{src:"string"==typeof o.logoSrc?o.logoSrc:"https://app.voucherify.io/images/favicon.png"}),r("name")&&d("input","customerName",p,{type:"text",placeholder:"string"==typeof o.customerNamePlaceholder?o.customerNamePlaceholder:"Name"})),y=d("div","row",p),b=r("email")&&d("input","customerEmail",y,{type:"email",placeholder:"string"==typeof o.customerEmailPlaceholder?o.customerEmailPlaceholder:"Email"}),C=r("phone")&&d("input","customerPhone",y,{type:"text",placeholder:"string"==typeof o.customerPhonePlaceholder?o.customerPhonePlaceholder:"Phone"}),_=r("line_1")&&d("input","customerLine1",p,{type:"text",placeholder:"string"==typeof o.customerLine1Placeholder?o.customerLine1Placeholder:"Address line 1"}),x=r("line_2")&&d("input","customerLine2",p,{type:"text",placeholder:"string"==typeof o.customerLine2Placeholder?o.customerLine2Placeholder:"Address line 2"}),w=d("div","row",p),I=r("postal_code")&&d("input","customerPostalCode",w,{type:"text",placeholder:"string"==typeof o.customerPostalCodePlaceholder?o.customerPostalCodePlaceholder:"Postal Code"}),P=r("city")&&d("input","customerCity",w,{type:"text",placeholder:"string"==typeof o.customerCityPlaceholder?o.customerCityPlaceholder:"City"}),q=d("div","row",p),k=r("state")&&d("input","customerState",q,{type:"text",placeholder:"string"==typeof o.customerStatePlaceholder?o.customerStatePlaceholder:"State"}),E=r("country")&&d("input","customerCountry",q,{type:"text",placeholder:"string"==typeof o.customerCountryPlaceholder?o.customerCountryPlaceholder:"Country"}),R=d("input","tracking",p,{type:"hidden",configurable:!0}),A=d("input","publishStatus",p,{type:"text"}),j=d("button","publish",p,{});d("span","publishText",j,{text:"string"==typeof o.textPublish?o.textPublish:"Get voucher"})}A.prop("readonly",!0).hide();var V=this,O="string"===o.classInvalid?o.classInvalid:"voucherifyInvalid",S="string"==typeof o.classValid?o.classValid:"voucherifyValid",T="string"===o.classInvalidAnimation?o.classInvalidAnimation:"voucherifyAnimationShake",U="string"===o.classValidAnimation?o.classValidAnimation:"voucherifyAnimationTada";j.on("click",function(e){R.val(""),j.toggleClass(O,!1),j.toggleClass(S,!1);var t={customer:{}};if(r("name")){if(!g.val()&&a("name"))return u(g);t.customer.name=g.val()}if(r("email")){if(!b.val()&&a("email"))return u(b);if(b.val()&&!v.test(b.val()))return u(b);t.customer.email=b.val(),t.customer.source_id=t.customer.email}if(r("phone")){if(!C.val()&&a("phone"))return u(C);C.val()&&(t.customer.phone=C.val())}if((r("line_1")||r("line_2")||r("postal_code")||r("city")||r("state")||r("country"))&&(t.customer.address={}),r("line_1")){if(!_.val()&&a("line_1"))return u(_);t.customer.address.line_1=_.val()}if(r("line_2")){if(!x.val()&&a("line_2"))return u(x);t.customer.address.line_2=x.val()}if(r("postal_code")){if(!I.val()&&a("postal_code"))return u(I);t.customer.address.postal_code=I.val()}if(r("city")){if(!P.val()&&a("city"))return u(P);t.customer.address.city=P.val()}if(r("state")){if(!k.val()&&a("state"))return u(k);t.customer.address.state=k.val()}if(r("country")){if(!E.val()&&a("country"))return u(E);t.customer.address.country=E.val()}V.publish(o.campaignName,t,function(e){if(!e||!e.voucher||!e.voucher.code){var t=e.context||{},n=t.responseJSON||{},i=n.key;return u(j),void(r("phone")&&i===h&&u(C))}g&&g.hide(),b&&b.hide(),C&&C.hide(),_&&_.hide(),x&&x.hide(),I&&I.hide(),P&&P.hide(),k&&k.hide(),E&&E.hide(),A.toggleClass(U,!0).val(e.voucher.code).show(100),R.val(e.tracking_id||""),j.prop("disabled",!0),j.toggleClass(O,!1).hide(),o&&o.onPublished&&"function"==typeof o.onPublished&&o.onPublished(e)})})}};return function(n,o){function i(){if(!l){l=!0;for(var t=0;te||e>100)throw new Error("Invalid voucher, percent discount should be between 0-100.")}function a(e){if(!e||0>e)throw new Error("Invalid voucher, amount discount must be higher than zero.")}function l(e){if(!e||0>e)throw new Error("Invalid voucher, unit discount must be higher than zero.")}function s(e){return e.applicationId?e.applicationId?!0:(console.error("Voucherify.js ERROR: Missing Client Token (Secret Key)."),!1):(console.error("Voucherify.js ERROR: Missing Client Application ID."),!1)}function d(){function n(e,t){var n=this;return n._element=e,n._path=t.path,n._options=a.readOptions(n._element,i.concat(t.attributes)),n._iframe=null,this.renderIframe()}var o="https://app.voucherify.io",i=["client-app-id","client-token","logo"],r={"voucher-redeem":{path:"/widgets/redeem",attributes:["code-field","code-field-required","code-field-label","amount-field","amount-field-required","amount-field-label","name-field","name-field-required","name-field-label","email-field","email-field-required","email-field-label","phone-field","phone-field-required","phone-field-label","address-line-1-field","address-line-1-field-required","address-line-1-field-label","address-line-2-field","address-line-2-field-required","address-line-2-field-label","city-field","city-field-required","city-field-label","postal-code-field","postal-code-field-required","postal-code-field-label","state-field","state-field-required","state-field-label","country-field","country-field-required","country-field-label","button-label"]},"get-voucher":{path:"/widgets/publish",attributes:["campaign","metadata","source","name-field","name-field-required","name-field-label","email-field","email-field-required","email-field-label","phone-field","phone-field-required","phone-field-label","address-line-1-field","address-line-1-field-required","address-line-1-field-label","address-line-2-field","address-line-2-field-required","address-line-2-field-label","city-field","city-field-required","city-field-label","postal-code-field","postal-code-field-required","postal-code-field-label","state-field","state-field-required","state-field-label","country-field","country-field-required","country-field-label","button-label"]},subscribe:{path:"/widgets/subscribe",attributes:["metadata","source","name-field","name-field-required","name-field-label","email-field","email-field-required","email-field-label","phone-field","phone-field-required","phone-field-label","address-line-1-field","address-line-1-field-required","address-line-1-field-label","address-line-2-field","address-line-2-field-required","address-line-2-field-label","city-field","city-field-required","city-field-label","postal-code-field","postal-code-field-required","postal-code-field-label","state-field","state-field-required","state-field-label","country-field","country-field-required","country-field-label","subscribe-label"]}},a={bind:function(e,t,n){return e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent("on"+t,n)},readOptions:function(e,t){return Array.prototype.reduce.call(t,function(t,n){var o=e.getAttribute("data-"+n);return o&&(t[n]=o),t},{})},encodeOptions:function(e){var t=[];return Object.keys(e).forEach(function(n){t.push("[options]["+n+"]="+encodeURIComponent(e[n]))}),"?"+t.join("&")}};n.prototype.renderIframe=function(){var e=this;if(e._iframe)return e;var n=["width:400px;","height:475px;","background: transparent;","border: 0px none transparent;","overflow-x: hidden;","overflow-y: auto;","visibility: hidden;","margin: 0;","padding: 0;","-webkit-tap-highlight-color: transparent;","-webkit-touch-callout: none;"];return e._iframe=t.createElement("iframe"),e._iframe.setAttribute("frameBorder","0"),e._iframe.setAttribute("allowtransparency","true"),e._iframe.style.cssText=n.join("\n"),a.bind(e._iframe,"load",function(){return e._iframe.style.visibility="visible"}),e._iframe.src=o+e._path+a.encodeOptions(e._options),e._element.appendChild(e._iframe),e};var l=[];return Object.keys(r).forEach(function(t){var o=e.document.querySelectorAll(".voucherify-"+t);Array.prototype.forEach.call(o,function(e){l.push(new n(e,r[t]))})}),l}var c="https://api.voucherify.io",u={validate:c+"/client/v1/validate",redeem:c+"/client/v1/redeem",publish:c+"/client/v1/publish",list:c+"/client/v1/vouchers",track:c+"/client/v1/events",validatePromotion:c+"/client/v1/promotions/validation",redeemPromotion:c+"/client/v1/promotions/tiers/"},f={},p="invalid_amount",m="invalid_number",g="missing_amount",h="invalid_customer_phone",v=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,y=null;y=n&&"function"==typeof n.ajax&&n.Deferred?function(e,t,i,r){var a=null;return"function"!=typeof r&&(a=n.Deferred()),n.ajax({type:e,url:t,data:JSON.stringify(i),xhrFields:{withCredentials:!0},dataType:"json",headers:{Accept:"application/json","Content-Type":"application/json","X-Client-Application-Id":f.applicationId,"X-Client-Token":f.token,"X-Voucherify-Channel":"Voucherify.js"},timeout:f.timeout,success:function(e){var t=null;o(e)?"function"==typeof r?r(e):a.resolve(e):(t={type:"error",message:"Unexpected response structure.",context:e},"function"==typeof r?r(t):a.reject(t))},error:function(e){var t={type:"error",message:"XHR error happened.",context:e};"function"==typeof r?r(t):a.reject(t)}}),"function"!=typeof r?a.promise():void 0}:function(t,n,i,r){var a=new e.XMLHttpRequest;a.withCredentials=!0,a.open(t,n,!0),a.timeout=f.timeout,a.setRequestHeader("Accept","application/json"),a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("X-Client-Application-Id",f.applicationId),a.setRequestHeader("X-Client-Token",f.token),a.setRequestHeader("X-Voucherify-Channel","Voucherify.js"),a.onload=function(){var e=null;if(a.status>=200&&a.status<400){var t=JSON.parse(a.responseText);o(t)?"function"==typeof r&&r(t):(e={type:"error",message:"Unexpected response structure.",context:t},"function"==typeof r&&r(e))}else e={type:"error",message:"Unexpected status code.",context:a.status},"function"==typeof r&&r(e)},a.onerror=function(e){var t={type:"error",message:"XHR error happened.",context:e};"function"==typeof r&&r(t)},a.send(JSON.stringify(i))};var b={initialize:function(e,t,n){f.applicationId=e,f.token=t,f.timeout=n||5e3},setIdentity:function(e){f.trackingId=e},validate:function(e,t){if(!s(f))return null;var n,o,i,r,a=!1;"object"==typeof e&&(n=e.amount,o=e.items,i=e.metadata,r=e.customer,e=e.code),e&&(e=e.replace(/[\s\r\n]/g,""));var l="?";if(e?(l+="code="+encodeURIComponent(e),n&&(l+="&amount="+parseInt(n))):(a=!0,n&&(l+="amount="+parseInt(n))),o&&(l+="&"+o.map(function(e,t){return Object.keys(e).map(function(n){return encodeURIComponent("item["+t+"]["+n+"]")+"="+encodeURIComponent(e[n])}).join("&")}).join("&")),i&&(l+="&"+Object.keys(i).map(function(e){return encodeURIComponent("metadata["+e+"]")+"="+encodeURIComponent(i[e])}).join("&")),r){if("object"!=typeof r)return console.error("Customer must be an object - please use instead { source_id: 'your_user' }"),null;l+="&"+Object.keys(r).map(function(e){return encodeURIComponent("customer["+e+"]")+"="+encodeURIComponent(r[e])}).join("&")}return f.trackingId&&(l+="&tracking_id="+encodeURIComponent(f.trackingId)),y("GET",(a?u.validatePromotion:u.validate)+l,void 0,t)},redeem:function(e,t,n){var o,i=!1;if(!s(f))return null;if(!e){if(!t.tier)return console.error("Voucherify client could not redeem promotion without tier, because it is missing."),null;i=!0,o=t.tier,delete t.tier}var r="";return i||(r+="?code="+encodeURIComponent(e.replace(/[\s\r\n]/g,""))),t=t||{},t.customer=t.customer||{},t.customer.source_id=t.customer.source_id||f.trackingId,y("POST",(i?u.redeemPromotion+o+"/redemption":u.redeem)+r,t,n)},publish:function(e,t,n){if(!s(f))return null;if(!e)return console.error("Voucherify.js ERROR: campaign is required to publish a voucher."),null;var o="?campaign="+encodeURIComponent(e);return t=t||{},t.customer=t.customer||{},t.customer.source_id=t.customer.source_id||f.trackingId,t.channel=t.channel||"Voucherify.js",y("POST",u.publish+o,t,n)},listVouchers:function(e,t){if(!s(f))return null;"function"!=typeof e||t||(t=e,e={});var n="?"+Object.keys(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&");return y("GET",u.list+n,void 0,t)},track:function(e,t,n,o){if(!s(f))return null;"function"!=typeof n||o||(o=n,n={});var i={};return i.event=e,i.metadata=t,i.customer=i.customer||n||{},i.customer.source_id=i.customer.source_id||f.trackingId,y("POST",u.track,i,o)},utils:{calculatePrice:function(e,t,n){var o,s=100;if(t.gift)return o=Math.min(t.gift.balance/s,e),i(e-o);if(!t.discount)throw new Error("Unsupported voucher type.");if("PERCENT"===t.discount.type){o=t.discount.percent_off,r(o);var d=e*(o/100);return t.discount.amount_limit&&(d=Math.min(t.discount.amount_limit/s,d)),i(e-d)}if("AMOUNT"===t.discount.type){o=t.discount.amount_off/s,a(o);var c=e-o;return i(c>0?c:0)}if("UNIT"===t.discount.type){o=t.discount.unit_off,l(o);var c=e-n*o;return i(c>0?c:0)}throw new Error("Unsupported discount type.")},calculateDiscount:function(e,t,n){var o,s=100;if(t.gift)return o=Math.min(t.gift.balance/s,e),i(o);if(!t.discount)throw new Error("Unsupported voucher type.");if("PERCENT"===t.discount.type){o=t.discount.percent_off,r(o);var d=e*(o/s);return t.discount.amount_limit&&(d=Math.min(t.discount.amount_limit/s,d)),i(d)}if("AMOUNT"===t.discount.type){o=t.discount.amount_off/s,a(o);var c=e-o;return i(c>0?o:e)}if("UNIT"===t.discount.type){o=t.discount.unit_off,l(o);var d=n*o;return i(d>e?e:d)}throw new Error("Unsupported discount type.")}},render:function(e,o){function i(e){return e.charAt(0).toUpperCase()+e.slice(1)}function r(e,t){return e+i(t)}function a(e,t){return o[r(e,t)]}function l(e,o,i,l){l=l||{};var s=null,d=a("selector",o);if(l.configurable&&d&&(s=n(d)),!s||!s.length){s=n(t.createElement(e)),i.append(s);for(var c in l)"configurable"!==c&&l.hasOwnProperty(c)&&s.attr(c,l[c]);"input"===e&&s.attr("name",r("voucherify",o)),"span"===e&&l.text&&s.text(l.text)}return s.addClass("string"==typeof a("class",o)?a("class",o):r("voucherify",o)),s}var s=n(e);if(!s||!s.length)throw new Error("Element '"+e+"' cannot be found");o=o||{};var d=l("div","container",s),c=l("figure","logo",d),u=(l("img","logo",c,{src:"string"==typeof o.logoSrc?o.logoSrc:"https://app.voucherify.io/images/favicon.png"}),l("input","code",d,{type:"text",placeholder:"string"==typeof o.textPlaceholder?o.textPlaceholder:"e.g. abc-123"})),f=l("input","amount",d,{type:o.amount?"text":"hidden",placeholder:"string"==typeof o.amountPlaceholder?o.amountPlaceholder:"e.g. 52.22"}),h=l("input","discountType",d,{type:"hidden",configurable:!0}),v=l("input","percentOff",d,{type:"hidden",configurable:!0}),y=l("input","amountOff",d,{type:"hidden",configurable:!0}),b=l("input","unitOff",d,{type:"hidden",configurable:!0}),C=l("input","tracking",d,{type:"hidden",configurable:!0}),_=l("button","validate",d,{}),x=(l("span","validateText",_,{text:"string"==typeof o.textValidate?o.textValidate:"Validate"}),this),w="string"===o.classInvalid?o.classInvalid:"voucherifyInvalid",I="string"==typeof o.classValid?o.classValid:"voucherifyValid",P="string"===o.classInvalidAnimation?o.classInvalidAnimation:"voucherifyAnimationShake",q="string"===o.classValidAnimation?o.classValidAnimation:"voucherifyAnimationTada";u.on("keyup",function(e){u.toggleClass(P,!1)}),f.on("keyup",function(e){f.toggleClass(P,!1)}),_.on("click",function(e){if(h.val(""),y.val(""),b.val(""),v.val(""),C.val(""),_.toggleClass(w,!1),_.toggleClass(I,!1),!u.val())return void u.toggleClass(P,!0).delay(1e3).queue(function(){u.toggleClass(P,!1),u.dequeue()});var t={code:u.val(),amount:parseInt(100*parseFloat(f.val().replace(/\,/,".")))};x.validate(t,function(e){if(!e||!e.valid){var t=function(e){e.toggleClass(w,!0),e.toggleClass(I,!1),e.toggleClass(P,!0).delay(1e3).queue(function(){e.toggleClass(P,!1),e.dequeue()})};_.toggleClass(w,!0),_.toggleClass(I,!1);var n=e.context||{},i=n.responseJSON||{},r=i.key;return void t(!o.amount||r!==p&&r!==m&&r!==g?u:f)}f.val()>=0?f.val(parseFloat(f.val().replace(/\,/,"."))):f.hide(100),u.toggleClass(w,!1),f.toggleClass(w,!1),h.val(e.discount&&e.discount.type||""),y.val(e.discount&&e.discount.amount_off||0),b.val(e.discount&&e.discount.unit_off||0),v.val(e.discount&&e.discount.percent_off||0),C.val(e.tracking_id||""),u.prop("disabled",!0),f.prop("disabled",!0),_.prop("disabled",!0),u.toggleClass(I,!0),f.toggleClass(I,!0),_.toggleClass(I,!0),_.toggleClass(w,!1),u.toggleClass(w,!1),u.toggleClass(q,!0),f.toggleClass(q,!0),o&&o.onValidated&&"function"==typeof o.onValidated&&o.onValidated(e)})})},renderRedeem:function(e,o){function i(e){return e.charAt(0).toUpperCase()+e.slice(1)}function r(e,t){return e+i(t)}function a(e,t){return o[r(e,t)]}function l(e,o,i,l){l=l||{};var s=null,d=a("selector",o);if(l.configurable&&d&&(s=n(d)),!s||!s.length){s=n(t.createElement(e)),i.append(s);for(var c in l)"configurable"!==c&&l.hasOwnProperty(c)&&s.attr(c,l[c]);"input"===e&&s.attr("name",r("voucherify",o)),"span"===e&&l.text&&s.text(l.text)}return s.addClass("string"==typeof a("class",o)?a("class",o):r("voucherify",o)),s}var s=n(e);if(!s||!s.length)throw new Error("Element '"+e+"' cannot be found");o=o||{};var d=l("div","container",s),c=l("figure","logo",d),u=(l("img","logo",c,{src:"string"==typeof o.logoSrc?o.logoSrc:"https://app.voucherify.io/images/favicon.png"}),l("input","code",d,{type:"text",placeholder:"string"==typeof o.textPlaceholder?o.textPlaceholder:"e.g. abc-123"})),f=l("input","amount",d,{type:o.amount?"text":"hidden",placeholder:"string"==typeof o.amountPlaceholder?o.amountPlaceholder:"e.g. 52.22"}),h=l("input","tracking",d,{type:"hidden",configurable:!0}),v=l("button","redeem",d,{}),y=(l("span","redeemText",v,{text:"string"==typeof o.textRedeem?o.textRedeem:"Redeem"}),this),b="string"===o.classInvalid?o.classInvalid:"voucherifyInvalid",C="string"==typeof o.classValid?o.classValid:"voucherifyValid",_="string"===o.classInvalidAnimation?o.classInvalidAnimation:"voucherifyAnimationShake",x="string"===o.classValidAnimation?o.classValidAnimation:"voucherifyAnimationTada";u.on("keyup",function(e){u.toggleClass(_,!1)}),f.on("keyup",function(e){f.toggleClass(_,!1)}),v.on("click",function(e){if(h.val(""),v.toggleClass(b,!1),v.toggleClass(C,!1),!u.val())return void u.toggleClass(_,!0).delay(1e3).queue(function(){u.toggleClass(_,!1),u.dequeue()});var t={order:{amount:parseInt(100*parseFloat(f.val().replace(/\,/,".")))}};y.redeem(u.val(),t,function(e){if(!e||"SUCCESS"!==e.result){var t=function(e){e.toggleClass(b,!0),e.toggleClass(C,!1),e.toggleClass(_,!0).delay(1e3).queue(function(){e.toggleClass(_,!1),e.dequeue()})};v.toggleClass(b,!0),v.toggleClass(C,!1);var n=e.context||{},i=n.responseJSON||{},r=i.key;return void t(!o.amount||r!==p&&r!==m&&r!==g?u:f)}f.val()>=0?f.val(parseFloat(f.val().replace(/\,/,"."))):f.hide(100),u.toggleClass(b,!1),f.toggleClass(b,!1),h.val(e.tracking_id||""),u.prop("disabled",!0),f.prop("disabled",!0),v.prop("disabled",!0),u.toggleClass(C,!0),f.toggleClass(C,!0),v.toggleClass(C,!0),v.toggleClass(b,!1),u.toggleClass(b,!1),u.toggleClass(x,!0),f.toggleClass(x,!0),o&&o.onRedeem&&"function"==typeof o.onRedeem&&o.onRedeem(e)})})},renderPublish:function(e,o){function i(e,t){return Array.prototype.some.call(e||[],function(e){return e.name===t})}function r(e){return i(o.customerFields,e)}function a(e){var t=Array.prototype.find.call(o.customerFields||[],function(t){return t.name===e});return t&&t.required||!1}function l(e){return e.charAt(0).toUpperCase()+e.slice(1)}function s(e,t){return e+l(t)}function d(e,t){return o[s(e,t)]}function c(e,o,i,r){r=r||{};var a=null,l=d("selector",o);if(r.configurable&&l&&(a=n(l)),!a||!a.length){a=n(t.createElement(e)),i.append(a);for(var c in r)"configurable"!==c&&r.hasOwnProperty(c)&&a.attr(c,r[c]);"input"===e&&a.attr("name",s("voucherify",o)),"span"===e&&r.text&&a.text(r.text)}return a.addClass("string"==typeof d("class",o)?d("class",o):s("voucherify",o)),a}function u(e){e.toggleClass(V,!0),e.toggleClass(S,!1),e.toggleClass(T,!0).delay(1e3).queue(function(){e.toggleClass(T,!1),e.toggleClass(V,!1),e.toggleClass(S,!1),e.dequeue()})}var f=n(e);if(!f||!f.length)throw new Error("Element '"+e+"' cannot be found");if(o=o||{},!o.campaignName)throw new Error("Option campaignName is not specified");var p=c("div","container",f);p.addClass("wide");{var m=c("figure","logo",p),g=(c("img","logo",m,{src:"string"==typeof o.logoSrc?o.logoSrc:"https://app.voucherify.io/images/favicon.png"}),r("name")&&c("input","customerName",p,{type:"text",placeholder:"string"==typeof o.customerNamePlaceholder?o.customerNamePlaceholder:"Name"})),y=c("div","row",p),b=r("email")&&c("input","customerEmail",y,{type:"email",placeholder:"string"==typeof o.customerEmailPlaceholder?o.customerEmailPlaceholder:"Email"}),C=r("phone")&&c("input","customerPhone",y,{type:"text",placeholder:"string"==typeof o.customerPhonePlaceholder?o.customerPhonePlaceholder:"Phone"}),_=r("line_1")&&c("input","customerLine1",p,{type:"text",placeholder:"string"==typeof o.customerLine1Placeholder?o.customerLine1Placeholder:"Address line 1"}),x=r("line_2")&&c("input","customerLine2",p,{type:"text",placeholder:"string"==typeof o.customerLine2Placeholder?o.customerLine2Placeholder:"Address line 2"}),w=c("div","row",p),I=r("postal_code")&&c("input","customerPostalCode",w,{type:"text",placeholder:"string"==typeof o.customerPostalCodePlaceholder?o.customerPostalCodePlaceholder:"Postal Code"}),P=r("city")&&c("input","customerCity",w,{type:"text",placeholder:"string"==typeof o.customerCityPlaceholder?o.customerCityPlaceholder:"City"}),q=c("div","row",p),k=r("state")&&c("input","customerState",q,{type:"text",placeholder:"string"==typeof o.customerStatePlaceholder?o.customerStatePlaceholder:"State"}),E=r("country")&&c("input","customerCountry",q,{type:"text",placeholder:"string"==typeof o.customerCountryPlaceholder?o.customerCountryPlaceholder:"Country"}),R=c("input","tracking",p,{type:"hidden",configurable:!0}),A=c("input","publishStatus",p,{type:"text"}),j=c("button","publish",p,{});c("span","publishText",j,{text:"string"==typeof o.textPublish?o.textPublish:"Get voucher"})}A.prop("readonly",!0).hide();var O=this,V="string"===o.classInvalid?o.classInvalid:"voucherifyInvalid",S="string"==typeof o.classValid?o.classValid:"voucherifyValid",T="string"===o.classInvalidAnimation?o.classInvalidAnimation:"voucherifyAnimationShake",U="string"===o.classValidAnimation?o.classValidAnimation:"voucherifyAnimationTada";j.on("click",function(e){R.val(""),j.toggleClass(V,!1),j.toggleClass(S,!1);var t={customer:{}};if(r("name")){if(!g.val()&&a("name"))return u(g);t.customer.name=g.val()}if(r("email")){if(!b.val()&&a("email"))return u(b);if(b.val()&&!v.test(b.val()))return u(b);t.customer.email=b.val(),t.customer.source_id=t.customer.email}if(r("phone")){if(!C.val()&&a("phone"))return u(C);C.val()&&(t.customer.phone=C.val())}if((r("line_1")||r("line_2")||r("postal_code")||r("city")||r("state")||r("country"))&&(t.customer.address={}),r("line_1")){if(!_.val()&&a("line_1"))return u(_);t.customer.address.line_1=_.val()}if(r("line_2")){if(!x.val()&&a("line_2"))return u(x);t.customer.address.line_2=x.val()}if(r("postal_code")){if(!I.val()&&a("postal_code"))return u(I);t.customer.address.postal_code=I.val()}if(r("city")){if(!P.val()&&a("city"))return u(P);t.customer.address.city=P.val()}if(r("state")){if(!k.val()&&a("state"))return u(k);t.customer.address.state=k.val()}if(r("country")){if(!E.val()&&a("country"))return u(E);t.customer.address.country=E.val()}O.publish(o.campaignName,t,function(e){if(!e||!e.voucher||!e.voucher.code){var t=e.context||{},n=t.responseJSON||{},i=n.key;return u(j),void(r("phone")&&i===h&&u(C))}g&&g.hide(),b&&b.hide(),C&&C.hide(),_&&_.hide(),x&&x.hide(),I&&I.hide(),P&&P.hide(),k&&k.hide(),E&&E.hide(),A.toggleClass(U,!0).val(e.voucher.code).show(100),R.val(e.tracking_id||""),j.prop("disabled",!0),j.toggleClass(V,!1).hide(),o&&o.onPublished&&"function"==typeof o.onPublished&&o.onPublished(e)})})}};return function(n,o){function i(){if(!l){l=!0;for(var t=0;t()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n\n function isValidResponseStructure(data) {\n return data && (typeof(data.valid) === \"boolean\" // validate\n || typeof(data.result) === \"string\" // redeem\n || typeof(data.voucher) === \"object\" // publish\n || typeof(data.vouchers) === \"object\" // list\n || (data.object === \"event\" && typeof(data.type) === \"string\") // track\n );\n }\n\n var xhrImplementation = null;\n\n if (!!$ && typeof($.ajax) === \"function\" && !!$.Deferred) {\n xhrImplementation = function (method, url, payload, callback) {\n var deferred = null;\n\n if (typeof(callback) !== \"function\") {\n deferred = $.Deferred();\n }\n\n $.ajax({\n type: method,\n\n url: url,\n\n data: JSON.stringify(payload),\n\n xhrFields: {\n withCredentials: true\n },\n\n dataType: \"json\",\n headers: {\n \"Accept\": \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Client-Application-Id\": OPTIONS.applicationId,\n \"X-Client-Token\": OPTIONS.token,\n \"X-Voucherify-Channel\": \"Voucherify.js\"\n },\n timeout: OPTIONS.timeout,\n\n success: function (data) {\n var result = null;\n\n if (isValidResponseStructure(data)) {\n if (typeof(callback) === \"function\") {\n callback(data);\n } else {\n deferred.resolve(data);\n }\n } else {\n result = {\n type: \"error\",\n message: \"Unexpected response structure.\",\n context: data\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n } else {\n deferred.reject(result);\n }\n }\n },\n\n error: function (error) {\n var result = {\n type: \"error\",\n message: \"XHR error happened.\",\n context: error\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n } else {\n deferred.reject(result);\n }\n }\n });\n\n if (typeof(callback) !== \"function\") {\n return deferred.promise();\n } else {\n return undefined;\n }\n };\n } else {\n xhrImplementation = function (method, url, payload, callback) {\n var request = new window.XMLHttpRequest();\n\n request.withCredentials = true;\n request.open(method, url, true);\n request.timeout = OPTIONS.timeout;\n\n request.setRequestHeader(\"Accept\", \"application/json\");\n request.setRequestHeader(\"Content-Type\", \"application/json\");\n request.setRequestHeader(\"X-Client-Application-Id\", OPTIONS.applicationId);\n request.setRequestHeader(\"X-Client-Token\", OPTIONS.token);\n request.setRequestHeader(\"X-Voucherify-Channel\", \"Voucherify.js\");\n\n request.onload = function() {\n var result = null;\n\n if (request.status >= 200 && request.status < 400) {\n var data = JSON.parse(request.responseText);\n\n if (isValidResponseStructure(data)) {\n if (typeof(callback) === \"function\") {\n callback(data);\n }\n } else {\n result = {\n type: \"error\",\n message: \"Unexpected response structure.\",\n context: data\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n }\n }\n } else {\n result = {\n type: \"error\",\n message: \"Unexpected status code.\",\n context: request.status\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n }\n }\n };\n\n request.onerror = function (error) {\n var result = {\n type: \"error\",\n message: \"XHR error happened.\",\n context: error\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n }\n };\n\n request.send(JSON.stringify(payload));\n };\n }\n\n function roundMoney(value) {\n return Math.round(value * (100 + 0.001)) / 100;\n }\n\n function validatePercentDiscount(discount) {\n if (!discount || discount < 0 || discount > 100) {\n throw new Error('Invalid voucher, percent discount should be between 0-100.');\n }\n }\n\n function validateAmountDiscount(discount) {\n if (!discount || discount < 0) {\n throw new Error(\"Invalid voucher, amount discount must be higher than zero.\");\n }\n }\n\n function validateUnitDiscount(discount) {\n if (!discount || discount < 0) {\n throw new Error(\"Invalid voucher, unit discount must be higher than zero.\");\n }\n }\n\n function isValidInit(options) {\n if (!options.applicationId) {\n console.error(\"Voucherify.js ERROR: Missing Client Application ID.\");\n return false;\n }\n if (!options.applicationId) {\n console.error(\"Voucherify.js ERROR: Missing Client Token (Secret Key).\");\n return false;\n }\n return true;\n }\n\n var voucherify = {\n initialize: function (clientAppId, token, timeout) {\n OPTIONS.applicationId = clientAppId;\n OPTIONS.token = token;\n OPTIONS.timeout = timeout || 5000;\n },\n\n setIdentity: function (trackingId) {\n OPTIONS.trackingId = trackingId;\n },\n\n validate: function (code, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n var isPromotion = false;\n var amount;\n var items;\n var metadata;\n var customer;\n\n if (typeof(code) === \"object\") {\n amount = code.amount;\n items = code.items;\n metadata = code.metadata;\n customer = code.customer;\n code = code.code;\n }\n\n if (!!code) {\n code = code.replace(/[\\s\\r\\n]/g, \"\");\n }\n\n var queryString = \"?\";\n if (!code) {\n isPromotion = true;\n if(amount) {\n queryString += \"amount=\" + parseInt(amount);\n }\n } else {\n queryString += \"code=\" + encodeURIComponent(code);\n if (amount) {\n queryString += \"&amount=\" + parseInt(amount); // in cents, amount=1000 means $10\n }\n }\n\n if (items) {\n queryString += \"&\" + items.map(function(item, index) {\n return Object.keys(item).map(function(key) {\n return encodeURIComponent(\"item[\" + index + \"][\" + key + \"]\") + \"=\" + encodeURIComponent(item[key]);\n }).join(\"&\");\n }).join(\"&\");\n }\n\n if (metadata) {\n queryString += \"&\" + Object.keys(metadata).map(function(key) {\n return encodeURIComponent(\"metadata[\" + key + \"]\") + \"=\" + encodeURIComponent(metadata[key]);\n }).join(\"&\");\n }\n\n if (customer) {\n if(typeof(customer) !== \"object\") {\n console.error(\"Customer must be an object - please use instead { source_id: 'your_user' }\");\n return null;\n }\n\n queryString += \"&\" + Object.keys(customer).map(function (key) {\n return encodeURIComponent(\"customer[\" + key + \"]\") + \"=\" + encodeURIComponent(customer[ key ]);\n }).join(\"&\");\n }\n\n if (OPTIONS.trackingId) {\n queryString += \"&tracking_id=\" + encodeURIComponent(OPTIONS.trackingId);\n }\n\n return xhrImplementation(\"GET\", (isPromotion ? API.validatePromotion : API.validate) + queryString, undefined, callback);\n },\n\n redeem: function (code, payload, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (!code) {\n console.error(\"Voucherify client could not verify code, because it is missing - please provide Voucher Code.\");\n return null;\n }\n\n var queryString = \"?code=\" + encodeURIComponent(code.replace(/[\\s\\r\\n]/g, \"\"));\n\n // -- Tracking ID fallback\n payload = payload || {};\n payload.customer = payload.customer || {};\n payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId;\n\n return xhrImplementation(\"POST\", API.redeem + queryString, payload, callback);\n },\n\n publish: function (campaign, payload, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (!campaign) {\n console.error(\"Voucherify.js ERROR: campaign is required to publish a voucher.\");\n return null;\n }\n\n var queryString = \"?campaign=\" + encodeURIComponent(campaign);\n\n // -- Tracking ID fallback\n payload = payload || {};\n payload.customer = payload.customer || {};\n payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId;\n // -- Default channel\n payload.channel = payload.channel || \"Voucherify.js\";\n\n return xhrImplementation(\"POST\", API.publish + queryString, payload, callback);\n },\n\n listVouchers: function (filters, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (typeof filters === \"function\" && !callback) {\n callback = filters;\n filters = {};\n }\n\n var queryString = \"?\" + Object.keys(filters)\n .map(function(key) {\n return encodeURIComponent(key) + \"=\" + encodeURIComponent(filters[key])\n })\n .join(\"&\");\n\n return xhrImplementation(\"GET\", API.list + queryString, undefined, callback);\n },\n\n track: function (event_name, metadata, customer, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (typeof customer === \"function\" && !callback) {\n callback = customer;\n customer = {};\n }\n\n var payload = {};\n payload.event = event_name;\n payload.metadata = metadata;\n payload.customer = payload.customer || customer || {};\n payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId;\n\n return xhrImplementation(\"POST\", API.track, payload, callback);\n },\n\n utils: {\n calculatePrice: function (basePrice, voucher, unitPrice) {\n var e = 100; // Number of digits after the decimal separator.\n var discount;\n\n if (voucher.gift) {\n discount = Math.min(voucher.gift.balance / e, basePrice);\n return roundMoney(basePrice - discount);\n }\n\n if (!voucher.discount) {\n throw new Error(\"Unsupported voucher type.\");\n }\n\n if (voucher.discount.type === 'PERCENT') {\n discount = voucher.discount.percent_off;\n validatePercentDiscount(discount);\n var priceDiscount = basePrice * (discount / 100);\n\n if (voucher.discount.amount_limit) {\n priceDiscount = Math.min(voucher.discount.amount_limit / e, priceDiscount);\n }\n\n return roundMoney(basePrice - priceDiscount);\n\n } else if (voucher.discount.type === 'AMOUNT') {\n discount = voucher.discount.amount_off / e;\n validateAmountDiscount(discount);\n var newPrice = basePrice - discount;\n return roundMoney(newPrice > 0 ? newPrice : 0);\n\n } else if (voucher.discount.type === 'UNIT') {\n discount = voucher.discount.unit_off;\n validateUnitDiscount(discount);\n var newPrice = basePrice - unitPrice * discount;\n return roundMoney(newPrice > 0 ? newPrice : 0);\n\n } else {\n throw new Error(\"Unsupported discount type.\");\n }\n },\n\n calculateDiscount: function(basePrice, voucher, unitPrice) {\n var e = 100; // Number of digits after the decimal separator.\n var discount;\n\n if (voucher.gift) {\n discount = Math.min(voucher.gift.balance / e, basePrice);\n return roundMoney(discount);\n }\n\n if (!voucher.discount) {\n throw new Error(\"Unsupported voucher type.\");\n }\n\n if (voucher.discount.type === 'PERCENT') {\n discount = voucher.discount.percent_off;\n validatePercentDiscount(discount);\n var priceDiscount = basePrice * (discount / e);\n\n if (voucher.discount.amount_limit) {\n priceDiscount = Math.min(voucher.discount.amount_limit / e, priceDiscount);\n }\n\n return roundMoney(priceDiscount);\n } else if (voucher.discount.type === 'AMOUNT') {\n discount = voucher.discount.amount_off / e;\n validateAmountDiscount(discount);\n var newPrice = basePrice - discount;\n return roundMoney(newPrice > 0 ? discount : basePrice);\n\n } else if (voucher.discount.type === 'UNIT') {\n discount = voucher.discount.unit_off;\n validateUnitDiscount(discount);\n var priceDiscount = unitPrice * discount;\n return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount);\n\n } else {\n throw new Error(\"Unsupported discount type.\");\n }\n }\n },\n render: function(selector, options) {\n var $element = $(selector);\n if (!$element || !$element.length) {\n throw new Error(\"Element '\" + selector + \"' cannot be found\");\n }\n options = options || {};\n\n function getCapitalizedName(name) {\n return name.charAt(0).toUpperCase() + name.slice(1);\n }\n\n function getPropertyName(prefix, name) {\n return prefix + getCapitalizedName(name);\n }\n\n function getConfigProperty(prefix, name) {\n return options[getPropertyName(prefix, name)];\n }\n\n function create$control(type, name, $container, config) {\n config = config || {};\n var $control = null;\n var configured$control = getConfigProperty(\"selector\", name);\n\n if (config.configurable && configured$control) {\n $control = $(configured$control);\n }\n\n if (!$control || !$control.length) {\n $control = $(document.createElement(type));\n $container.append($control);\n\n for (var attribute in config) {\n if (attribute !== \"configurable\" && config.hasOwnProperty(attribute)) {\n $control.attr(attribute, config[attribute]);\n }\n }\n\n if (type === \"input\") {\n $control.attr(\"name\", getPropertyName(\"voucherify\", name));\n }\n\n if (type === \"span\" && config.text) {\n $control.text(config.text);\n }\n }\n\n $control.addClass(typeof getConfigProperty(\"class\", name) === \"string\" ? getConfigProperty(\"class\", name) : getPropertyName(\"voucherify\", name));\n return $control;\n }\n\n var $container = create$control(\"div\", \"container\", $element);\n var $logoContainer = create$control(\"figure\", \"logo\", $container);\n var $logo = create$control(\"img\", \"logo\", $logoContainer, { src: typeof options.logoSrc === \"string\" ? options.logoSrc : \"https://app.voucherify.io/images/favicon.png\" });\n var $code = create$control(\"input\", \"code\", $container, { type: \"text\", placeholder: typeof options.textPlaceholder === \"string\" ? options.textPlaceholder : \"e.g. abc-123\" });\n var $amount = create$control(\"input\", \"amount\", $container, { type: options.amount ? \"text\" : \"hidden\", placeholder: typeof options.amountPlaceholder === \"string\" ? options.amountPlaceholder : \"e.g. 52.22\" });\n var $discountType = create$control(\"input\", \"discountType\", $container, { type: \"hidden\", configurable: true });\n var $percentOff = create$control(\"input\", \"percentOff\", $container, { type: \"hidden\", configurable: true });\n var $amountOff = create$control(\"input\", \"amountOff\", $container, { type: \"hidden\", configurable: true });\n var $unitOff = create$control(\"input\", \"unitOff\", $container, { type: \"hidden\", configurable: true });\n var $tracking = create$control(\"input\", \"tracking\", $container, { type: \"hidden\", configurable: true });\n var $validate = create$control(\"button\", \"validate\", $container, {});\n var $validateText = create$control(\"span\", \"validateText\", $validate, { text: typeof options.textValidate === \"string\" ? options.textValidate : \"Validate\" });\n\n var self = this;\n var classInvalid = options.classInvalid === \"string\" ? options.classInvalid : \"voucherifyInvalid\";\n var classValid = typeof options.classValid === \"string\" ? options.classValid : \"voucherifyValid\";\n var classInvalidAnimation = options.classInvalidAnimation === \"string\" ? options.classInvalidAnimation : \"voucherifyAnimationShake\";\n var classValidAnimation = options.classValidAnimation === \"string\" ? options.classValidAnimation : \"voucherifyAnimationTada\";\n\n $code.on(\"keyup\", function(event) {\n $code.toggleClass(classInvalidAnimation, false);\n });\n\n $amount.on(\"keyup\", function(event) {\n $amount.toggleClass(classInvalidAnimation, false);\n });\n\n $validate.on(\"click\", function(event) {\n $discountType.val(\"\");\n $amountOff.val(\"\");\n $unitOff.val(\"\");\n $percentOff.val(\"\");\n $tracking.val(\"\");\n\n $validate.toggleClass(classInvalid, false);\n $validate.toggleClass(classValid, false);\n\n if (!$code.val()) {\n $code.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $code.toggleClass(classInvalidAnimation, false);\n $code.dequeue();\n });\n return;\n }\n\n var payload = {\n code: $code.val(),\n amount: parseInt(parseFloat($amount.val().replace(/\\,/, \".\")) * 100)\n };\n\n self.validate(payload, function(response) {\n if (!response || !response.valid) {\n\n var setFieldInvalid = function ($field) {\n $field.toggleClass(classInvalid, true);\n $field.toggleClass(classValid, false);\n $field.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $field.toggleClass(classInvalidAnimation, false);\n $field.dequeue();\n });\n };\n\n $validate.toggleClass(classInvalid, true);\n $validate.toggleClass(classValid, false);\n\n var context = response.context || {};\n var responseJSON = context.responseJSON || {};\n var error_key = responseJSON.key;\n\n if (options.amount && (\n error_key === INVALID_AMOUNT ||\n error_key === INVALID_NUMBER ||\n error_key === MISSING_AMOUNT)) {\n setFieldInvalid($amount);\n } else {\n setFieldInvalid($code);\n }\n return;\n }\n\n if ($amount.val() >= 0) {\n $amount.val(parseFloat($amount.val().replace(/\\,/, \".\")))\n } else {\n $amount.hide(100);\n }\n\n $code.toggleClass(classInvalid, false);\n $amount.toggleClass(classInvalid, false);\n $discountType.val(response.discount && response.discount.type || \"\");\n $amountOff.val(response.discount && response.discount.amount_off || 0);\n $unitOff.val(response.discount && response.discount.unit_off || 0);\n $percentOff.val(response.discount && response.discount.percent_off || 0);\n $tracking.val(response.tracking_id || \"\");\n\n $code.prop(\"disabled\", true);\n $amount.prop(\"disabled\", true);\n $validate.prop(\"disabled\", true);\n\n $code.toggleClass(classValid, true);\n $amount.toggleClass(classValid, true);\n $validate.toggleClass(classValid, true);\n $validate.toggleClass(classInvalid, false);\n $code.toggleClass(classInvalid, false);\n\n $code.toggleClass(classValidAnimation, true);\n $amount.toggleClass(classValidAnimation, true);\n\n if (options && options.onValidated && typeof options.onValidated === \"function\") {\n options.onValidated(response);\n }\n });\n });\n },\n\n renderRedeem: function(selector, options) {\n var $element = $(selector);\n if (!$element || !$element.length) {\n throw new Error(\"Element '\" + selector + \"' cannot be found\");\n }\n options = options || {};\n\n function getCapitalizedName(name) {\n return name.charAt(0).toUpperCase() + name.slice(1);\n }\n\n function getPropertyName(prefix, name) {\n return prefix + getCapitalizedName(name);\n }\n\n function getConfigProperty(prefix, name) {\n return options[getPropertyName(prefix, name)];\n }\n\n function create$control(type, name, $container, config) {\n config = config || {};\n var $control = null;\n var configured$control = getConfigProperty(\"selector\", name);\n\n if (config.configurable && configured$control) {\n $control = $(configured$control);\n }\n\n if (!$control || !$control.length) {\n $control = $(document.createElement(type));\n $container.append($control);\n\n for (var attribute in config) {\n if (attribute !== \"configurable\" && config.hasOwnProperty(attribute)) {\n $control.attr(attribute, config[attribute]);\n }\n }\n\n if (type === \"input\") {\n $control.attr(\"name\", getPropertyName(\"voucherify\", name));\n }\n\n if (type === \"span\" && config.text) {\n $control.text(config.text);\n }\n }\n\n $control.addClass(typeof getConfigProperty(\"class\", name) === \"string\" ? getConfigProperty(\"class\", name) : getPropertyName(\"voucherify\", name));\n return $control;\n }\n\n var $container = create$control(\"div\", \"container\", $element);\n var $logoContainer = create$control(\"figure\", \"logo\", $container);\n var $logo = create$control(\"img\", \"logo\", $logoContainer, { src: typeof options.logoSrc === \"string\" ? options.logoSrc : \"https://app.voucherify.io/images/favicon.png\" });\n var $code = create$control(\"input\", \"code\", $container, { type: \"text\", placeholder: typeof options.textPlaceholder === \"string\" ? options.textPlaceholder : \"e.g. abc-123\" });\n var $amount = create$control(\"input\", \"amount\", $container, { type: options.amount ? \"text\" : \"hidden\", placeholder: typeof options.amountPlaceholder === \"string\" ? options.amountPlaceholder : \"e.g. 52.22\" });\n var $tracking = create$control(\"input\", \"tracking\", $container, { type: \"hidden\", configurable: true });\n var $redeem = create$control(\"button\", \"redeem\", $container, {});\n var $redeemText = create$control(\"span\", \"redeemText\", $redeem, { text: typeof options.textRedeem === \"string\" ? options.textRedeem : \"Redeem\" });\n\n var self = this;\n var classInvalid = options.classInvalid === \"string\" ? options.classInvalid : \"voucherifyInvalid\";\n var classValid = typeof options.classValid === \"string\" ? options.classValid : \"voucherifyValid\";\n var classInvalidAnimation = options.classInvalidAnimation === \"string\" ? options.classInvalidAnimation : \"voucherifyAnimationShake\";\n var classValidAnimation = options.classValidAnimation === \"string\" ? options.classValidAnimation : \"voucherifyAnimationTada\";\n\n $code.on(\"keyup\", function(event) {\n $code.toggleClass(classInvalidAnimation, false);\n });\n\n $amount.on(\"keyup\", function(event) {\n $amount.toggleClass(classInvalidAnimation, false);\n });\n\n $redeem.on(\"click\", function(event) {\n $tracking.val(\"\");\n\n $redeem.toggleClass(classInvalid, false);\n $redeem.toggleClass(classValid, false);\n\n if (!$code.val()) {\n $code.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $code.toggleClass(classInvalidAnimation, false);\n $code.dequeue();\n });\n return;\n }\n\n var payload = {\n order: {\n amount: parseInt(parseFloat($amount.val().replace(/\\,/, \".\")) * 100)\n }\n };\n\n self.redeem($code.val(), payload, function(response) {\n if (!response || response.result !== 'SUCCESS') {\n\n var setFieldInvalid = function ($field) {\n $field.toggleClass(classInvalid, true);\n $field.toggleClass(classValid, false);\n $field.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $field.toggleClass(classInvalidAnimation, false);\n $field.dequeue();\n });\n };\n\n $redeem.toggleClass(classInvalid, true);\n $redeem.toggleClass(classValid, false);\n\n var context = response.context || {};\n var responseJSON = context.responseJSON || {};\n var error_key = responseJSON.key;\n\n if (options.amount && (\n error_key === INVALID_AMOUNT ||\n error_key === INVALID_NUMBER ||\n error_key === MISSING_AMOUNT)) {\n setFieldInvalid($amount);\n } else {\n setFieldInvalid($code);\n }\n return;\n }\n\n if ($amount.val() >= 0) {\n $amount.val(parseFloat($amount.val().replace(/\\,/, \".\")))\n } else {\n $amount.hide(100);\n }\n\n $code.toggleClass(classInvalid, false);\n $amount.toggleClass(classInvalid, false);\n $tracking.val(response.tracking_id || \"\");\n\n $code.prop(\"disabled\", true);\n $amount.prop(\"disabled\", true);\n $redeem.prop(\"disabled\", true);\n\n $code.toggleClass(classValid, true);\n $amount.toggleClass(classValid, true);\n $redeem.toggleClass(classValid, true);\n $redeem.toggleClass(classInvalid, false);\n $code.toggleClass(classInvalid, false);\n\n $code.toggleClass(classValidAnimation, true);\n $amount.toggleClass(classValidAnimation, true);\n\n if (options && options.onRedeem && typeof options.onRedeem === \"function\") {\n options.onRedeem(response);\n }\n });\n });\n },\n\n renderPublish : function (selector, options) {\n var $element = $(selector);\n if (!$element || !$element.length) {\n throw new Error(\"Element '\" + selector + \"' cannot be found\");\n }\n\n options = options || {};\n\n if (!options.campaignName) {\n throw new Error(\"Option campaignName is not specified\");\n }\n\n function contains(arr, prop) {\n return Array.prototype.some.call(arr || [], function (field) {\n return field.name === prop;\n });\n }\n\n function containsCustomer(prop) {\n return contains(options.customerFields, prop);\n }\n\n function isRequired(prop) {\n var field = Array.prototype.find.call(options.customerFields || [], function (field) {\n return field.name === prop;\n });\n\n return field && field.required || false;\n }\n\n function getCapitalizedName(name) {\n return name.charAt(0).toUpperCase() + name.slice(1);\n }\n\n function getPropertyName(prefix, name) {\n return prefix + getCapitalizedName(name);\n }\n\n function getConfigProperty(prefix, name) {\n return options[getPropertyName(prefix, name)];\n }\n\n function create$control(type, name, $container, config) {\n config = config || {};\n var $control = null;\n var configured$control = getConfigProperty(\"selector\", name);\n\n if (config.configurable && configured$control) {\n $control = $(configured$control);\n }\n\n if (!$control || !$control.length) {\n $control = $(document.createElement(type));\n $container.append($control);\n\n for (var attribute in config) {\n if (attribute !== \"configurable\" && config.hasOwnProperty(attribute)) {\n $control.attr(attribute, config[attribute]);\n }\n }\n\n if (type === \"input\") {\n $control.attr(\"name\", getPropertyName(\"voucherify\", name));\n }\n\n if (type === \"span\" && config.text) {\n $control.text(config.text);\n }\n }\n\n $control.addClass(typeof getConfigProperty(\"class\", name) === \"string\" ? getConfigProperty(\"class\", name) : getPropertyName(\"voucherify\", name));\n return $control;\n }\n\n var $container = create$control(\"div\", \"container\", $element);\n $container.addClass(\"wide\");\n var $logoContainer = create$control(\"figure\", \"logo\", $container);\n var $logo = create$control(\"img\", \"logo\", $logoContainer, { src: typeof options.logoSrc === \"string\" ? options.logoSrc : \"https://app.voucherify.io/images/favicon.png\" });\n\n var $customerName = containsCustomer(\"name\") && create$control(\"input\", \"customerName\", $container, { type: \"text\", placeholder: typeof options.customerNamePlaceholder === \"string\" ? options.customerNamePlaceholder : \"Name\" });\n var $row1 = create$control(\"div\", \"row\", $container);\n var $customerEmail = containsCustomer(\"email\") && create$control(\"input\", \"customerEmail\", $row1, { type: \"email\", placeholder: typeof options.customerEmailPlaceholder === \"string\" ? options.customerEmailPlaceholder : \"Email\" });\n var $customerPhone = containsCustomer(\"phone\") && create$control(\"input\", \"customerPhone\", $row1, { type: \"text\", placeholder: typeof options.customerPhonePlaceholder === \"string\" ? options.customerPhonePlaceholder : \"Phone\" });\n var $customerLine1 = containsCustomer(\"line_1\") && create$control(\"input\", \"customerLine1\", $container, { type: \"text\", placeholder: typeof options.customerLine1Placeholder === \"string\" ? options.customerLine1Placeholder : \"Address line 1\" });\n var $customerLine2 = containsCustomer(\"line_2\") && create$control(\"input\", \"customerLine2\", $container, { type: \"text\", placeholder: typeof options.customerLine2Placeholder === \"string\" ? options.customerLine2Placeholder : \"Address line 2\" });\n var $row3 = create$control(\"div\", \"row\", $container);\n var $customerPostalCode = containsCustomer(\"postal_code\") && create$control(\"input\", \"customerPostalCode\", $row3, { type: \"text\", placeholder: typeof options.customerPostalCodePlaceholder === \"string\" ? options.customerPostalCodePlaceholder : \"Postal Code\" });\n var $customerCity = containsCustomer(\"city\") && create$control(\"input\", \"customerCity\", $row3, { type: \"text\", placeholder: typeof options.customerCityPlaceholder === \"string\" ? options.customerCityPlaceholder : \"City\" });\n var $row4 = create$control(\"div\", \"row\", $container);\n var $customerState = containsCustomer(\"state\") && create$control(\"input\", \"customerState\", $row4, { type: \"text\", placeholder: typeof options.customerStatePlaceholder === \"string\" ? options.customerStatePlaceholder : \"State\" });\n var $customerCountry = containsCustomer(\"country\") && create$control(\"input\", \"customerCountry\", $row4, { type: \"text\", placeholder: typeof options.customerCountryPlaceholder === \"string\" ? options.customerCountryPlaceholder : \"Country\" });\n\n var $tracking = create$control(\"input\", \"tracking\", $container, { type: \"hidden\", configurable: true });\n\n var $publishStatus = create$control(\"input\", \"publishStatus\", $container, { type: \"text\" });\n\n var $publish = create$control(\"button\", \"publish\", $container, {});\n var $publishText = create$control(\"span\", \"publishText\", $publish, { text: typeof options.textPublish === \"string\" ? options.textPublish : \"Get voucher\" });\n\n $publishStatus.prop(\"readonly\", true).hide();\n\n var self = this;\n var classInvalid = options.classInvalid === \"string\" ? options.classInvalid : \"voucherifyInvalid\";\n var classValid = typeof options.classValid === \"string\" ? options.classValid : \"voucherifyValid\";\n var classInvalidAnimation = options.classInvalidAnimation === \"string\" ? options.classInvalidAnimation : \"voucherifyAnimationShake\";\n var classValidAnimation = options.classValidAnimation === \"string\" ? options.classValidAnimation : \"voucherifyAnimationTada\";\n\n function error$control($control) {\n $control.toggleClass(classInvalid, true);\n $control.toggleClass(classValid, false);\n $control.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $control.toggleClass(classInvalidAnimation, false);\n $control.toggleClass(classInvalid, false);\n $control.toggleClass(classValid, false);\n $control.dequeue();\n });\n }\n\n $publish.on(\"click\", function(event) {\n $tracking.val(\"\");\n\n $publish.toggleClass(classInvalid, false);\n $publish.toggleClass(classValid, false);\n\n var payload = {\n customer: {}\n };\n\n if (containsCustomer(\"name\")) {\n if (!$customerName.val() && isRequired(\"name\")) {\n return error$control($customerName);\n }\n payload.customer[\"name\"] = $customerName.val();\n }\n\n if (containsCustomer(\"email\")) {\n if (!$customerEmail.val() && isRequired(\"email\")) {\n return error$control($customerEmail);\n }\n if ($customerEmail.val() && !EMAIL_PATTERN.test($customerEmail.val())) {\n return error$control($customerEmail);\n }\n payload.customer[\"email\"] = $customerEmail.val();\n payload.customer[\"source_id\"] = payload.customer[\"email\"];\n }\n\n if (containsCustomer(\"phone\") ) {\n if (!$customerPhone.val() && isRequired(\"phone\")) {\n return error$control($customerPhone);\n }\n if ($customerPhone.val()) {\n payload.customer[\"phone\"] = $customerPhone.val();\n }\n }\n\n if (containsCustomer(\"line_1\") ||\n containsCustomer(\"line_2\") ||\n containsCustomer(\"postal_code\") ||\n containsCustomer(\"city\") ||\n containsCustomer(\"state\") ||\n containsCustomer(\"country\")) {\n payload.customer[\"address\"] = {};\n }\n\n if (containsCustomer(\"line_1\")) {\n if (!$customerLine1.val() && isRequired(\"line_1\")) {\n return error$control($customerLine1);\n }\n payload.customer[\"address\"][\"line_1\"] = $customerLine1.val();\n }\n\n if (containsCustomer(\"line_2\")) {\n if (!$customerLine2.val() && isRequired(\"line_2\")) {\n return error$control($customerLine2);\n }\n payload.customer[\"address\"][\"line_2\"] = $customerLine2.val();\n }\n\n if (containsCustomer(\"postal_code\")) {\n if (!$customerPostalCode.val() && isRequired(\"postal_code\")) {\n return error$control($customerPostalCode);\n }\n payload.customer[\"address\"][\"postal_code\"] = $customerPostalCode.val();\n }\n\n if (containsCustomer(\"city\")) {\n if (!$customerCity.val() && isRequired(\"city\")) {\n return error$control($customerCity);\n }\n payload.customer[\"address\"][\"city\"] = $customerCity.val();\n }\n\n if (containsCustomer(\"state\")) {\n if (!$customerState.val() && isRequired(\"state\")) {\n return error$control($customerState);\n }\n payload.customer[\"address\"][\"state\"] = $customerState.val();\n }\n\n if (containsCustomer(\"country\")) {\n if (!$customerCountry.val() && isRequired(\"country\")) {\n return error$control($customerCountry);\n }\n payload.customer[\"address\"][\"country\"] = $customerCountry.val()\n }\n\n self.publish(options.campaignName, payload, function(response) {\n if (!response || !response.voucher || !response.voucher.code) {\n var context = response.context || {};\n var responseJSON = context.responseJSON || {};\n var error_key = responseJSON.key;\n\n error$control($publish);\n\n if (containsCustomer(\"phone\") && error_key === INVALID_CUSTOMER_PHONE) {\n error$control($customerPhone);\n }\n\n return;\n }\n\n $customerName && $customerName.hide();\n $customerEmail && $customerEmail.hide();\n $customerPhone && $customerPhone.hide();\n $customerLine1 && $customerLine1.hide();\n $customerLine2 && $customerLine2.hide();\n $customerPostalCode && $customerPostalCode.hide();\n $customerCity && $customerCity.hide();\n $customerState && $customerState.hide();\n $customerCountry && $customerCountry.hide();\n\n $publishStatus\n .toggleClass(classValidAnimation, true)\n .val(response.voucher.code).show(100);\n\n $tracking.val(response.tracking_id || \"\");\n\n $publish.prop(\"disabled\", true);\n\n $publish\n .toggleClass(classInvalid, false)\n .hide();\n\n if (options && options.onPublished && typeof options.onPublished === \"function\") {\n options.onPublished(response);\n }\n });\n });\n }\n };\n\n (function(funcName, baseObj) {\n \"use strict\";\n\n if (!baseObj) {\n return;\n }\n\n funcName = funcName || \"docReady\";\n baseObj = baseObj || window;\n var readyList = [];\n var readyFired = false;\n var readyEventHandlersInstalled = false;\n\n function ready() {\n if (!readyFired) {\n readyFired = true;\n for (var i = 0; i < readyList.length; i++) {\n readyList[i].fn.call(window, readyList[i].ctx);\n }\n readyList = [];\n }\n }\n\n function readyStateChange() {\n if ( document.readyState === \"complete\" ) {\n ready();\n }\n }\n\n baseObj[funcName] = function(callback, context) {\n if (typeof callback !== \"function\") {\n throw new TypeError(\"callback for docReady(fn) must be a function\");\n }\n if (readyFired) {\n setTimeout(function() {callback(context);}, 1);\n return;\n } else {\n readyList.push({fn: callback, ctx: context});\n }\n if (document.readyState === \"complete\" || (!document.attachEvent && document.readyState === \"interactive\")) {\n setTimeout(ready, 1);\n } else if (!readyEventHandlersInstalled) {\n if (document.addEventListener) {\n document.addEventListener(\"DOMContentLoaded\", ready, false);\n window.addEventListener(\"load\", ready, false);\n } else {\n document.attachEvent(\"onreadystatechange\", readyStateChange);\n window.attachEvent(\"onload\", ready);\n }\n readyEventHandlersInstalled = true;\n }\n }\n })(\"docReady\", window);\n\n function renderIframes() {\n var host = \"https://app.voucherify.io\";\n var common_attributes = [\n \"client-app-id\",\n \"client-token\",\n\n \"logo\"\n ];\n\n var iframes_widgets = {\n \"voucher-redeem\": {\n \"path\": \"/widgets/redeem\",\n \"attributes\": [\n \"code-field\",\n \"code-field-required\",\n \"code-field-label\",\n\n \"amount-field\",\n \"amount-field-required\",\n \"amount-field-label\",\n\n \"name-field\",\n \"name-field-required\",\n \"name-field-label\",\n\n \"email-field\",\n \"email-field-required\",\n \"email-field-label\",\n\n \"phone-field\",\n \"phone-field-required\",\n \"phone-field-label\",\n\n \"address-line-1-field\",\n \"address-line-1-field-required\",\n \"address-line-1-field-label\",\n\n \"address-line-2-field\",\n \"address-line-2-field-required\",\n \"address-line-2-field-label\",\n\n \"city-field\",\n \"city-field-required\",\n \"city-field-label\",\n\n \"postal-code-field\",\n \"postal-code-field-required\",\n \"postal-code-field-label\",\n\n \"state-field\",\n \"state-field-required\",\n \"state-field-label\",\n\n \"country-field\",\n \"country-field-required\",\n \"country-field-label\",\n\n \"button-label\"\n ]\n },\n \"get-voucher\": {\n \"path\": \"/widgets/publish\",\n \"attributes\": [\n \"campaign\",\n\n \"metadata\",\n \"source\",\n\n \"name-field\",\n \"name-field-required\",\n \"name-field-label\",\n\n \"email-field\",\n \"email-field-required\",\n \"email-field-label\",\n\n \"phone-field\",\n \"phone-field-required\",\n \"phone-field-label\",\n\n \"address-line-1-field\",\n \"address-line-1-field-required\",\n \"address-line-1-field-label\",\n\n \"address-line-2-field\",\n \"address-line-2-field-required\",\n \"address-line-2-field-label\",\n\n \"city-field\",\n \"city-field-required\",\n \"city-field-label\",\n\n \"postal-code-field\",\n \"postal-code-field-required\",\n \"postal-code-field-label\",\n\n \"state-field\",\n \"state-field-required\",\n \"state-field-label\",\n\n \"country-field\",\n \"country-field-required\",\n \"country-field-label\",\n\n \"button-label\"\n ]\n },\n \"subscribe\": {\n \"path\": \"/widgets/subscribe\",\n \"attributes\": [\n \"metadata\",\n \"source\",\n\n \"name-field\",\n \"name-field-required\",\n \"name-field-label\",\n\n \"email-field\",\n \"email-field-required\",\n \"email-field-label\",\n\n \"phone-field\",\n \"phone-field-required\",\n \"phone-field-label\",\n\n \"address-line-1-field\",\n \"address-line-1-field-required\",\n \"address-line-1-field-label\",\n\n \"address-line-2-field\",\n \"address-line-2-field-required\",\n \"address-line-2-field-label\",\n\n \"city-field\",\n \"city-field-required\",\n \"city-field-label\",\n\n \"postal-code-field\",\n \"postal-code-field-required\",\n \"postal-code-field-label\",\n\n \"state-field\",\n \"state-field-required\",\n \"state-field-label\",\n\n \"country-field\",\n \"country-field-required\",\n \"country-field-label\",\n\n \"subscribe-label\"\n ]\n }\n };\n\n var helpers = {\n bind: function (element, name, callback) {\n if (element.addEventListener) {\n return element.addEventListener(name, callback, false)\n } else {\n return element.attachEvent(\"on\" + name, callback)\n }\n },\n readOptions: function (element, allowed_options) {\n return Array.prototype.reduce.call(allowed_options, function (options, allowed_option) {\n var option_value = element.getAttribute(\"data-\" + allowed_option);\n\n if (option_value) {\n options[allowed_option] = option_value;\n }\n\n return options;\n }, {});\n },\n encodeOptions: function (options) {\n var query_parameters = [];\n\n Object.keys(options).forEach(function(option_key) {\n query_parameters.push(\"[options][\"+option_key+\"]=\"+encodeURIComponent(options[option_key]));\n });\n\n return \"?\" + query_parameters.join(\"&\");\n }\n };\n\n\n function RenderIframe(element, options) {\n var self = this;\n\n self._element = element;\n\n self._path = options.path;\n\n self._options = helpers.readOptions(self._element, common_attributes.concat(options.attributes));\n\n self._iframe = null;\n\n return this.renderIframe();\n }\n\n RenderIframe.prototype.renderIframe = function () {\n var self = this;\n\n if (self._iframe) {\n return self;\n }\n\n var css_props = [\n \"width:400px;\",\n \"height:475px;\",\n \"background: transparent;\",\n \"border: 0px none transparent;\",\n \"overflow-x: hidden;\",\n \"overflow-y: auto;\",\n \"visibility: hidden;\",\n \"margin: 0;\",\n \"padding: 0;\",\n \"-webkit-tap-highlight-color: transparent;\",\n \"-webkit-touch-callout: none;\"\n ];\n\n self._iframe = document.createElement(\"iframe\");\n self._iframe.setAttribute(\"frameBorder\", \"0\");\n self._iframe.setAttribute(\"allowtransparency\", \"true\");\n self._iframe.style.cssText = css_props.join(\"\\n\");\n\n helpers.bind(self._iframe, \"load\", function () {\n return self._iframe.style.visibility = \"visible\"\n });\n\n self._iframe.src = host + self._path + helpers.encodeOptions(self._options);\n\n self._element.appendChild(self._iframe);\n\n return self;\n };\n\n var widgets = [];\n\n Object.keys(iframes_widgets).forEach(function (widget_name) {\n var elements = window.document.querySelectorAll(\".voucherify-\" + widget_name);\n\n Array.prototype.forEach.call(elements, function (element) {\n widgets.push(new RenderIframe(element, iframes_widgets[widget_name]));\n })\n });\n\n return widgets;\n }\n\n if (window) {\n window.docReady(function () {\n console.info(\"Document ready. Render voucherify iframes.\");\n renderIframes();\n });\n }\n\n\n if (typeof module !== \"undefined\" && module.exports) {\n module.exports = voucherify;\n }\n\n return voucherify;\n} (window, window.document, window.jQuery));\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["voucherify.js"],"names":["window","Voucherify","document","$","isValidResponseStructure","data","object","roundMoney","value","Math","round","validatePercentDiscount","discount","Error","validateAmountDiscount","validateUnitDiscount","isValidInit","options","applicationId","console","error","renderIframes","RenderIframe","element","self","this","_element","_path","path","_options","helpers","readOptions","common_attributes","concat","attributes","_iframe","renderIframe","host","iframes_widgets","voucher-redeem","get-voucher","subscribe","bind","name","callback","addEventListener","attachEvent","allowed_options","Array","prototype","reduce","call","allowed_option","option_value","getAttribute","encodeOptions","query_parameters","Object","keys","forEach","option_key","push","encodeURIComponent","join","css_props","createElement","setAttribute","style","cssText","visibility","src","appendChild","widgets","widget_name","elements","querySelectorAll","API_BASE","API","validate","redeem","publish","list","track","validatePromotion","redeemPromotion","OPTIONS","INVALID_AMOUNT","INVALID_NUMBER","MISSING_AMOUNT","INVALID_CUSTOMER_PHONE","EMAIL_PATTERN","xhrImplementation","Deferred","method","url","payload","deferred","ajax","type","JSON","stringify","xhrFields","withCredentials","dataType","headers","Accept","Content-Type","X-Client-Application-Id","X-Client-Token","token","X-Voucherify-Channel","timeout","success","result","resolve","message","context","reject","promise","undefined","request","XMLHttpRequest","open","setRequestHeader","onload","status","parse","responseText","onerror","send","voucherify","initialize","clientAppId","setIdentity","trackingId","code","amount","items","metadata","customer","isPromotion","replace","queryString","parseInt","map","item","index","key","tier","source_id","campaign","channel","listVouchers","filters","event_name","event","utils","calculatePrice","basePrice","voucher","unitPrice","e","gift","min","balance","percent_off","priceDiscount","amount_limit","amount_off","newPrice","unit_off","calculateDiscount","render","selector","getCapitalizedName","charAt","toUpperCase","slice","getPropertyName","prefix","getConfigProperty","create$control","$container","config","$control","configured$control","configurable","length","append","attribute","hasOwnProperty","attr","text","addClass","$element","$logoContainer","$code","logoSrc","placeholder","textPlaceholder","$amount","amountPlaceholder","$discountType","$percentOff","$amountOff","$unitOff","$tracking","$validate","textValidate","classInvalid","classValid","classInvalidAnimation","classValidAnimation","on","toggleClass","val","delay","queue","dequeue","parseFloat","response","valid","setFieldInvalid","$field","responseJSON","error_key","hide","tracking_id","prop","onValidated","renderRedeem","$redeem","textRedeem","order","onRedeem","renderPublish","contains","arr","some","field","containsCustomer","customerFields","isRequired","find","required","error$control","campaignName","$customerName","customerNamePlaceholder","$row1","$customerEmail","customerEmailPlaceholder","$customerPhone","customerPhonePlaceholder","$customerLine1","customerLine1Placeholder","$customerLine2","customerLine2Placeholder","$row3","$customerPostalCode","customerPostalCodePlaceholder","$customerCity","customerCityPlaceholder","$row4","$customerState","customerStatePlaceholder","$customerCountry","customerCountryPlaceholder","$publishStatus","$publish","textPublish","test","show","onPublished","funcName","baseObj","ready","readyFired","i","readyList","fn","ctx","readyStateChange","readyState","readyEventHandlersInstalled","TypeError","setTimeout","docReady","info","module","exports","jQuery"],"mappings":"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","file":"voucherify.min.js","sourcesContent":["window.Voucherify = (function (window, document, $) {\n \"use strict\";\n\n var API_BASE = \"https://api.voucherify.io\";\n\n var API = {\n validate: API_BASE + \"/client/v1/validate\",\n redeem: API_BASE + \"/client/v1/redeem\",\n publish: API_BASE + \"/client/v1/publish\",\n list: API_BASE + \"/client/v1/vouchers\",\n track: API_BASE + \"/client/v1/events\",\n validatePromotion: API_BASE + \"/client/v1/promotions/validation\",\n redeemPromotion: API_BASE + \"/client/v1/promotions/tiers/\"\n };\n\n var OPTIONS = {};\n\n // Error keys returned from voucherify API\n var INVALID_AMOUNT = \"invalid_amount\";\n var INVALID_NUMBER = \"invalid_number\";\n var MISSING_AMOUNT = \"missing_amount\";\n var INVALID_CUSTOMER_PHONE = \"invalid_customer_phone\";\n\n var EMAIL_PATTERN = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n\n function isValidResponseStructure(data) {\n return data && (typeof(data.valid) === \"boolean\" // validate\n || typeof(data.result) === \"string\" // redeem\n || typeof(data.voucher) === \"object\" // publish\n || typeof(data.vouchers) === \"object\" // list\n || (data.object === \"event\" && typeof(data.type) === \"string\") // track\n );\n }\n\n var xhrImplementation = null;\n\n if (!!$ && typeof($.ajax) === \"function\" && !!$.Deferred) {\n xhrImplementation = function (method, url, payload, callback) {\n var deferred = null;\n\n if (typeof(callback) !== \"function\") {\n deferred = $.Deferred();\n }\n\n $.ajax({\n type: method,\n\n url: url,\n\n data: JSON.stringify(payload),\n\n xhrFields: {\n withCredentials: true\n },\n\n dataType: \"json\",\n headers: {\n \"Accept\": \"application/json\",\n \"Content-Type\": \"application/json\",\n \"X-Client-Application-Id\": OPTIONS.applicationId,\n \"X-Client-Token\": OPTIONS.token,\n \"X-Voucherify-Channel\": \"Voucherify.js\"\n },\n timeout: OPTIONS.timeout,\n\n success: function (data) {\n var result = null;\n\n if (isValidResponseStructure(data)) {\n if (typeof(callback) === \"function\") {\n callback(data);\n } else {\n deferred.resolve(data);\n }\n } else {\n result = {\n type: \"error\",\n message: \"Unexpected response structure.\",\n context: data\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n } else {\n deferred.reject(result);\n }\n }\n },\n\n error: function (error) {\n var result = {\n type: \"error\",\n message: \"XHR error happened.\",\n context: error\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n } else {\n deferred.reject(result);\n }\n }\n });\n\n if (typeof(callback) !== \"function\") {\n return deferred.promise();\n } else {\n return undefined;\n }\n };\n } else {\n xhrImplementation = function (method, url, payload, callback) {\n var request = new window.XMLHttpRequest();\n\n request.withCredentials = true;\n request.open(method, url, true);\n request.timeout = OPTIONS.timeout;\n\n request.setRequestHeader(\"Accept\", \"application/json\");\n request.setRequestHeader(\"Content-Type\", \"application/json\");\n request.setRequestHeader(\"X-Client-Application-Id\", OPTIONS.applicationId);\n request.setRequestHeader(\"X-Client-Token\", OPTIONS.token);\n request.setRequestHeader(\"X-Voucherify-Channel\", \"Voucherify.js\");\n\n request.onload = function() {\n var result = null;\n\n if (request.status >= 200 && request.status < 400) {\n var data = JSON.parse(request.responseText);\n\n if (isValidResponseStructure(data)) {\n if (typeof(callback) === \"function\") {\n callback(data);\n }\n } else {\n result = {\n type: \"error\",\n message: \"Unexpected response structure.\",\n context: data\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n }\n }\n } else {\n result = {\n type: \"error\",\n message: \"Unexpected status code.\",\n context: request.status\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n }\n }\n };\n\n request.onerror = function (error) {\n var result = {\n type: \"error\",\n message: \"XHR error happened.\",\n context: error\n };\n\n if (typeof(callback) === \"function\") {\n callback(result);\n }\n };\n\n request.send(JSON.stringify(payload));\n };\n }\n\n function roundMoney(value) {\n return Math.round(value * (100 + 0.001)) / 100;\n }\n\n function validatePercentDiscount(discount) {\n if (!discount || discount < 0 || discount > 100) {\n throw new Error('Invalid voucher, percent discount should be between 0-100.');\n }\n }\n\n function validateAmountDiscount(discount) {\n if (!discount || discount < 0) {\n throw new Error(\"Invalid voucher, amount discount must be higher than zero.\");\n }\n }\n\n function validateUnitDiscount(discount) {\n if (!discount || discount < 0) {\n throw new Error(\"Invalid voucher, unit discount must be higher than zero.\");\n }\n }\n\n function isValidInit(options) {\n if (!options.applicationId) {\n console.error(\"Voucherify.js ERROR: Missing Client Application ID.\");\n return false;\n }\n if (!options.applicationId) {\n console.error(\"Voucherify.js ERROR: Missing Client Token (Secret Key).\");\n return false;\n }\n return true;\n }\n\n var voucherify = {\n initialize: function (clientAppId, token, timeout) {\n OPTIONS.applicationId = clientAppId;\n OPTIONS.token = token;\n OPTIONS.timeout = timeout || 5000;\n },\n\n setIdentity: function (trackingId) {\n OPTIONS.trackingId = trackingId;\n },\n\n validate: function (code, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n var isPromotion = false;\n var amount;\n var items;\n var metadata;\n var customer;\n\n if (typeof(code) === \"object\") {\n amount = code.amount;\n items = code.items;\n metadata = code.metadata;\n customer = code.customer;\n code = code.code;\n }\n\n if (!!code) {\n code = code.replace(/[\\s\\r\\n]/g, \"\");\n }\n\n var queryString = \"?\";\n if (!code) {\n isPromotion = true;\n if(amount) {\n queryString += \"amount=\" + parseInt(amount);\n }\n } else {\n queryString += \"code=\" + encodeURIComponent(code);\n if (amount) {\n queryString += \"&amount=\" + parseInt(amount); // in cents, amount=1000 means $10\n }\n }\n\n if (items) {\n queryString += \"&\" + items.map(function(item, index) {\n return Object.keys(item).map(function(key) {\n return encodeURIComponent(\"item[\" + index + \"][\" + key + \"]\") + \"=\" + encodeURIComponent(item[key]);\n }).join(\"&\");\n }).join(\"&\");\n }\n\n if (metadata) {\n queryString += \"&\" + Object.keys(metadata).map(function(key) {\n return encodeURIComponent(\"metadata[\" + key + \"]\") + \"=\" + encodeURIComponent(metadata[key]);\n }).join(\"&\");\n }\n\n if (customer) {\n if(typeof(customer) !== \"object\") {\n console.error(\"Customer must be an object - please use instead { source_id: 'your_user' }\");\n return null;\n }\n\n queryString += \"&\" + Object.keys(customer).map(function (key) {\n return encodeURIComponent(\"customer[\" + key + \"]\") + \"=\" + encodeURIComponent(customer[ key ]);\n }).join(\"&\");\n }\n\n if (OPTIONS.trackingId) {\n queryString += \"&tracking_id=\" + encodeURIComponent(OPTIONS.trackingId);\n }\n\n return xhrImplementation(\"GET\", (isPromotion ? API.validatePromotion : API.validate) + queryString, undefined, callback);\n },\n\n redeem: function (code, payload, callback) {\n var isPromotion = false;\n var tier;\n\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (!code) {\n if( !payload.tier ){\n console.error(\"Voucherify client could not redeem promotion without tier, because it is missing.\");\n return null;\n }\n isPromotion = true;\n tier = payload.tier;\n delete payload.tier\n }\n\n var queryString = \"\"\n if(!isPromotion){\n queryString += \"?code=\" + encodeURIComponent(code.replace(/[\\s\\r\\n]/g, \"\"));\n }\n\n // -- Tracking ID fallback\n payload = payload || {};\n payload.customer = payload.customer || {};\n payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId;\n\n\n return xhrImplementation(\"POST\", (isPromotion ? API.redeemPromotion + tier + \"/redemption\" : API.redeem) + queryString, payload, callback);\n },\n\n publish: function (campaign, payload, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (!campaign) {\n console.error(\"Voucherify.js ERROR: campaign is required to publish a voucher.\");\n return null;\n }\n\n var queryString = \"?campaign=\" + encodeURIComponent(campaign);\n\n // -- Tracking ID fallback\n payload = payload || {};\n payload.customer = payload.customer || {};\n payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId;\n // -- Default channel\n payload.channel = payload.channel || \"Voucherify.js\";\n\n return xhrImplementation(\"POST\", API.publish + queryString, payload, callback);\n },\n\n listVouchers: function (filters, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (typeof filters === \"function\" && !callback) {\n callback = filters;\n filters = {};\n }\n\n var queryString = \"?\" + Object.keys(filters)\n .map(function(key) {\n return encodeURIComponent(key) + \"=\" + encodeURIComponent(filters[key])\n })\n .join(\"&\");\n\n return xhrImplementation(\"GET\", API.list + queryString, undefined, callback);\n },\n\n track: function (event_name, metadata, customer, callback) {\n if (!isValidInit(OPTIONS)) {\n return null;\n }\n\n if (typeof customer === \"function\" && !callback) {\n callback = customer;\n customer = {};\n }\n\n var payload = {};\n payload.event = event_name;\n payload.metadata = metadata;\n payload.customer = payload.customer || customer || {};\n payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId;\n\n return xhrImplementation(\"POST\", API.track, payload, callback);\n },\n\n utils: {\n calculatePrice: function (basePrice, voucher, unitPrice) {\n var e = 100; // Number of digits after the decimal separator.\n var discount;\n\n if (voucher.gift) {\n discount = Math.min(voucher.gift.balance / e, basePrice);\n return roundMoney(basePrice - discount);\n }\n\n if (!voucher.discount) {\n throw new Error(\"Unsupported voucher type.\");\n }\n\n if (voucher.discount.type === 'PERCENT') {\n discount = voucher.discount.percent_off;\n validatePercentDiscount(discount);\n var priceDiscount = basePrice * (discount / 100);\n\n if (voucher.discount.amount_limit) {\n priceDiscount = Math.min(voucher.discount.amount_limit / e, priceDiscount);\n }\n\n return roundMoney(basePrice - priceDiscount);\n\n } else if (voucher.discount.type === 'AMOUNT') {\n discount = voucher.discount.amount_off / e;\n validateAmountDiscount(discount);\n var newPrice = basePrice - discount;\n return roundMoney(newPrice > 0 ? newPrice : 0);\n\n } else if (voucher.discount.type === 'UNIT') {\n discount = voucher.discount.unit_off;\n validateUnitDiscount(discount);\n var newPrice = basePrice - unitPrice * discount;\n return roundMoney(newPrice > 0 ? newPrice : 0);\n\n } else {\n throw new Error(\"Unsupported discount type.\");\n }\n },\n\n calculateDiscount: function(basePrice, voucher, unitPrice) {\n var e = 100; // Number of digits after the decimal separator.\n var discount;\n\n if (voucher.gift) {\n discount = Math.min(voucher.gift.balance / e, basePrice);\n return roundMoney(discount);\n }\n\n if (!voucher.discount) {\n throw new Error(\"Unsupported voucher type.\");\n }\n\n if (voucher.discount.type === 'PERCENT') {\n discount = voucher.discount.percent_off;\n validatePercentDiscount(discount);\n var priceDiscount = basePrice * (discount / e);\n\n if (voucher.discount.amount_limit) {\n priceDiscount = Math.min(voucher.discount.amount_limit / e, priceDiscount);\n }\n\n return roundMoney(priceDiscount);\n } else if (voucher.discount.type === 'AMOUNT') {\n discount = voucher.discount.amount_off / e;\n validateAmountDiscount(discount);\n var newPrice = basePrice - discount;\n return roundMoney(newPrice > 0 ? discount : basePrice);\n\n } else if (voucher.discount.type === 'UNIT') {\n discount = voucher.discount.unit_off;\n validateUnitDiscount(discount);\n var priceDiscount = unitPrice * discount;\n return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount);\n\n } else {\n throw new Error(\"Unsupported discount type.\");\n }\n }\n },\n render: function(selector, options) {\n var $element = $(selector);\n if (!$element || !$element.length) {\n throw new Error(\"Element '\" + selector + \"' cannot be found\");\n }\n options = options || {};\n\n function getCapitalizedName(name) {\n return name.charAt(0).toUpperCase() + name.slice(1);\n }\n\n function getPropertyName(prefix, name) {\n return prefix + getCapitalizedName(name);\n }\n\n function getConfigProperty(prefix, name) {\n return options[getPropertyName(prefix, name)];\n }\n\n function create$control(type, name, $container, config) {\n config = config || {};\n var $control = null;\n var configured$control = getConfigProperty(\"selector\", name);\n\n if (config.configurable && configured$control) {\n $control = $(configured$control);\n }\n\n if (!$control || !$control.length) {\n $control = $(document.createElement(type));\n $container.append($control);\n\n for (var attribute in config) {\n if (attribute !== \"configurable\" && config.hasOwnProperty(attribute)) {\n $control.attr(attribute, config[attribute]);\n }\n }\n\n if (type === \"input\") {\n $control.attr(\"name\", getPropertyName(\"voucherify\", name));\n }\n\n if (type === \"span\" && config.text) {\n $control.text(config.text);\n }\n }\n\n $control.addClass(typeof getConfigProperty(\"class\", name) === \"string\" ? getConfigProperty(\"class\", name) : getPropertyName(\"voucherify\", name));\n return $control;\n }\n\n var $container = create$control(\"div\", \"container\", $element);\n var $logoContainer = create$control(\"figure\", \"logo\", $container);\n var $logo = create$control(\"img\", \"logo\", $logoContainer, { src: typeof options.logoSrc === \"string\" ? options.logoSrc : \"https://app.voucherify.io/images/favicon.png\" });\n var $code = create$control(\"input\", \"code\", $container, { type: \"text\", placeholder: typeof options.textPlaceholder === \"string\" ? options.textPlaceholder : \"e.g. abc-123\" });\n var $amount = create$control(\"input\", \"amount\", $container, { type: options.amount ? \"text\" : \"hidden\", placeholder: typeof options.amountPlaceholder === \"string\" ? options.amountPlaceholder : \"e.g. 52.22\" });\n var $discountType = create$control(\"input\", \"discountType\", $container, { type: \"hidden\", configurable: true });\n var $percentOff = create$control(\"input\", \"percentOff\", $container, { type: \"hidden\", configurable: true });\n var $amountOff = create$control(\"input\", \"amountOff\", $container, { type: \"hidden\", configurable: true });\n var $unitOff = create$control(\"input\", \"unitOff\", $container, { type: \"hidden\", configurable: true });\n var $tracking = create$control(\"input\", \"tracking\", $container, { type: \"hidden\", configurable: true });\n var $validate = create$control(\"button\", \"validate\", $container, {});\n var $validateText = create$control(\"span\", \"validateText\", $validate, { text: typeof options.textValidate === \"string\" ? options.textValidate : \"Validate\" });\n\n var self = this;\n var classInvalid = options.classInvalid === \"string\" ? options.classInvalid : \"voucherifyInvalid\";\n var classValid = typeof options.classValid === \"string\" ? options.classValid : \"voucherifyValid\";\n var classInvalidAnimation = options.classInvalidAnimation === \"string\" ? options.classInvalidAnimation : \"voucherifyAnimationShake\";\n var classValidAnimation = options.classValidAnimation === \"string\" ? options.classValidAnimation : \"voucherifyAnimationTada\";\n\n $code.on(\"keyup\", function(event) {\n $code.toggleClass(classInvalidAnimation, false);\n });\n\n $amount.on(\"keyup\", function(event) {\n $amount.toggleClass(classInvalidAnimation, false);\n });\n\n $validate.on(\"click\", function(event) {\n $discountType.val(\"\");\n $amountOff.val(\"\");\n $unitOff.val(\"\");\n $percentOff.val(\"\");\n $tracking.val(\"\");\n\n $validate.toggleClass(classInvalid, false);\n $validate.toggleClass(classValid, false);\n\n if (!$code.val()) {\n $code.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $code.toggleClass(classInvalidAnimation, false);\n $code.dequeue();\n });\n return;\n }\n\n var payload = {\n code: $code.val(),\n amount: parseInt(parseFloat($amount.val().replace(/\\,/, \".\")) * 100)\n };\n\n self.validate(payload, function(response) {\n if (!response || !response.valid) {\n\n var setFieldInvalid = function ($field) {\n $field.toggleClass(classInvalid, true);\n $field.toggleClass(classValid, false);\n $field.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $field.toggleClass(classInvalidAnimation, false);\n $field.dequeue();\n });\n };\n\n $validate.toggleClass(classInvalid, true);\n $validate.toggleClass(classValid, false);\n\n var context = response.context || {};\n var responseJSON = context.responseJSON || {};\n var error_key = responseJSON.key;\n\n if (options.amount && (\n error_key === INVALID_AMOUNT ||\n error_key === INVALID_NUMBER ||\n error_key === MISSING_AMOUNT)) {\n setFieldInvalid($amount);\n } else {\n setFieldInvalid($code);\n }\n return;\n }\n\n if ($amount.val() >= 0) {\n $amount.val(parseFloat($amount.val().replace(/\\,/, \".\")))\n } else {\n $amount.hide(100);\n }\n\n $code.toggleClass(classInvalid, false);\n $amount.toggleClass(classInvalid, false);\n $discountType.val(response.discount && response.discount.type || \"\");\n $amountOff.val(response.discount && response.discount.amount_off || 0);\n $unitOff.val(response.discount && response.discount.unit_off || 0);\n $percentOff.val(response.discount && response.discount.percent_off || 0);\n $tracking.val(response.tracking_id || \"\");\n\n $code.prop(\"disabled\", true);\n $amount.prop(\"disabled\", true);\n $validate.prop(\"disabled\", true);\n\n $code.toggleClass(classValid, true);\n $amount.toggleClass(classValid, true);\n $validate.toggleClass(classValid, true);\n $validate.toggleClass(classInvalid, false);\n $code.toggleClass(classInvalid, false);\n\n $code.toggleClass(classValidAnimation, true);\n $amount.toggleClass(classValidAnimation, true);\n\n if (options && options.onValidated && typeof options.onValidated === \"function\") {\n options.onValidated(response);\n }\n });\n });\n },\n\n renderRedeem: function(selector, options) {\n var $element = $(selector);\n if (!$element || !$element.length) {\n throw new Error(\"Element '\" + selector + \"' cannot be found\");\n }\n options = options || {};\n\n function getCapitalizedName(name) {\n return name.charAt(0).toUpperCase() + name.slice(1);\n }\n\n function getPropertyName(prefix, name) {\n return prefix + getCapitalizedName(name);\n }\n\n function getConfigProperty(prefix, name) {\n return options[getPropertyName(prefix, name)];\n }\n\n function create$control(type, name, $container, config) {\n config = config || {};\n var $control = null;\n var configured$control = getConfigProperty(\"selector\", name);\n\n if (config.configurable && configured$control) {\n $control = $(configured$control);\n }\n\n if (!$control || !$control.length) {\n $control = $(document.createElement(type));\n $container.append($control);\n\n for (var attribute in config) {\n if (attribute !== \"configurable\" && config.hasOwnProperty(attribute)) {\n $control.attr(attribute, config[attribute]);\n }\n }\n\n if (type === \"input\") {\n $control.attr(\"name\", getPropertyName(\"voucherify\", name));\n }\n\n if (type === \"span\" && config.text) {\n $control.text(config.text);\n }\n }\n\n $control.addClass(typeof getConfigProperty(\"class\", name) === \"string\" ? getConfigProperty(\"class\", name) : getPropertyName(\"voucherify\", name));\n return $control;\n }\n\n var $container = create$control(\"div\", \"container\", $element);\n var $logoContainer = create$control(\"figure\", \"logo\", $container);\n var $logo = create$control(\"img\", \"logo\", $logoContainer, { src: typeof options.logoSrc === \"string\" ? options.logoSrc : \"https://app.voucherify.io/images/favicon.png\" });\n var $code = create$control(\"input\", \"code\", $container, { type: \"text\", placeholder: typeof options.textPlaceholder === \"string\" ? options.textPlaceholder : \"e.g. abc-123\" });\n var $amount = create$control(\"input\", \"amount\", $container, { type: options.amount ? \"text\" : \"hidden\", placeholder: typeof options.amountPlaceholder === \"string\" ? options.amountPlaceholder : \"e.g. 52.22\" });\n var $tracking = create$control(\"input\", \"tracking\", $container, { type: \"hidden\", configurable: true });\n var $redeem = create$control(\"button\", \"redeem\", $container, {});\n var $redeemText = create$control(\"span\", \"redeemText\", $redeem, { text: typeof options.textRedeem === \"string\" ? options.textRedeem : \"Redeem\" });\n\n var self = this;\n var classInvalid = options.classInvalid === \"string\" ? options.classInvalid : \"voucherifyInvalid\";\n var classValid = typeof options.classValid === \"string\" ? options.classValid : \"voucherifyValid\";\n var classInvalidAnimation = options.classInvalidAnimation === \"string\" ? options.classInvalidAnimation : \"voucherifyAnimationShake\";\n var classValidAnimation = options.classValidAnimation === \"string\" ? options.classValidAnimation : \"voucherifyAnimationTada\";\n\n $code.on(\"keyup\", function(event) {\n $code.toggleClass(classInvalidAnimation, false);\n });\n\n $amount.on(\"keyup\", function(event) {\n $amount.toggleClass(classInvalidAnimation, false);\n });\n\n $redeem.on(\"click\", function(event) {\n $tracking.val(\"\");\n\n $redeem.toggleClass(classInvalid, false);\n $redeem.toggleClass(classValid, false);\n\n if (!$code.val()) {\n $code.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $code.toggleClass(classInvalidAnimation, false);\n $code.dequeue();\n });\n return;\n }\n\n var payload = {\n order: {\n amount: parseInt(parseFloat($amount.val().replace(/\\,/, \".\")) * 100)\n }\n };\n\n self.redeem($code.val(), payload, function(response) {\n if (!response || response.result !== 'SUCCESS') {\n\n var setFieldInvalid = function ($field) {\n $field.toggleClass(classInvalid, true);\n $field.toggleClass(classValid, false);\n $field.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $field.toggleClass(classInvalidAnimation, false);\n $field.dequeue();\n });\n };\n\n $redeem.toggleClass(classInvalid, true);\n $redeem.toggleClass(classValid, false);\n\n var context = response.context || {};\n var responseJSON = context.responseJSON || {};\n var error_key = responseJSON.key;\n\n if (options.amount && (\n error_key === INVALID_AMOUNT ||\n error_key === INVALID_NUMBER ||\n error_key === MISSING_AMOUNT)) {\n setFieldInvalid($amount);\n } else {\n setFieldInvalid($code);\n }\n return;\n }\n\n if ($amount.val() >= 0) {\n $amount.val(parseFloat($amount.val().replace(/\\,/, \".\")))\n } else {\n $amount.hide(100);\n }\n\n $code.toggleClass(classInvalid, false);\n $amount.toggleClass(classInvalid, false);\n $tracking.val(response.tracking_id || \"\");\n\n $code.prop(\"disabled\", true);\n $amount.prop(\"disabled\", true);\n $redeem.prop(\"disabled\", true);\n\n $code.toggleClass(classValid, true);\n $amount.toggleClass(classValid, true);\n $redeem.toggleClass(classValid, true);\n $redeem.toggleClass(classInvalid, false);\n $code.toggleClass(classInvalid, false);\n\n $code.toggleClass(classValidAnimation, true);\n $amount.toggleClass(classValidAnimation, true);\n\n if (options && options.onRedeem && typeof options.onRedeem === \"function\") {\n options.onRedeem(response);\n }\n });\n });\n },\n\n renderPublish : function (selector, options) {\n var $element = $(selector);\n if (!$element || !$element.length) {\n throw new Error(\"Element '\" + selector + \"' cannot be found\");\n }\n\n options = options || {};\n\n if (!options.campaignName) {\n throw new Error(\"Option campaignName is not specified\");\n }\n\n function contains(arr, prop) {\n return Array.prototype.some.call(arr || [], function (field) {\n return field.name === prop;\n });\n }\n\n function containsCustomer(prop) {\n return contains(options.customerFields, prop);\n }\n\n function isRequired(prop) {\n var field = Array.prototype.find.call(options.customerFields || [], function (field) {\n return field.name === prop;\n });\n\n return field && field.required || false;\n }\n\n function getCapitalizedName(name) {\n return name.charAt(0).toUpperCase() + name.slice(1);\n }\n\n function getPropertyName(prefix, name) {\n return prefix + getCapitalizedName(name);\n }\n\n function getConfigProperty(prefix, name) {\n return options[getPropertyName(prefix, name)];\n }\n\n function create$control(type, name, $container, config) {\n config = config || {};\n var $control = null;\n var configured$control = getConfigProperty(\"selector\", name);\n\n if (config.configurable && configured$control) {\n $control = $(configured$control);\n }\n\n if (!$control || !$control.length) {\n $control = $(document.createElement(type));\n $container.append($control);\n\n for (var attribute in config) {\n if (attribute !== \"configurable\" && config.hasOwnProperty(attribute)) {\n $control.attr(attribute, config[attribute]);\n }\n }\n\n if (type === \"input\") {\n $control.attr(\"name\", getPropertyName(\"voucherify\", name));\n }\n\n if (type === \"span\" && config.text) {\n $control.text(config.text);\n }\n }\n\n $control.addClass(typeof getConfigProperty(\"class\", name) === \"string\" ? getConfigProperty(\"class\", name) : getPropertyName(\"voucherify\", name));\n return $control;\n }\n\n var $container = create$control(\"div\", \"container\", $element);\n $container.addClass(\"wide\");\n var $logoContainer = create$control(\"figure\", \"logo\", $container);\n var $logo = create$control(\"img\", \"logo\", $logoContainer, { src: typeof options.logoSrc === \"string\" ? options.logoSrc : \"https://app.voucherify.io/images/favicon.png\" });\n\n var $customerName = containsCustomer(\"name\") && create$control(\"input\", \"customerName\", $container, { type: \"text\", placeholder: typeof options.customerNamePlaceholder === \"string\" ? options.customerNamePlaceholder : \"Name\" });\n var $row1 = create$control(\"div\", \"row\", $container);\n var $customerEmail = containsCustomer(\"email\") && create$control(\"input\", \"customerEmail\", $row1, { type: \"email\", placeholder: typeof options.customerEmailPlaceholder === \"string\" ? options.customerEmailPlaceholder : \"Email\" });\n var $customerPhone = containsCustomer(\"phone\") && create$control(\"input\", \"customerPhone\", $row1, { type: \"text\", placeholder: typeof options.customerPhonePlaceholder === \"string\" ? options.customerPhonePlaceholder : \"Phone\" });\n var $customerLine1 = containsCustomer(\"line_1\") && create$control(\"input\", \"customerLine1\", $container, { type: \"text\", placeholder: typeof options.customerLine1Placeholder === \"string\" ? options.customerLine1Placeholder : \"Address line 1\" });\n var $customerLine2 = containsCustomer(\"line_2\") && create$control(\"input\", \"customerLine2\", $container, { type: \"text\", placeholder: typeof options.customerLine2Placeholder === \"string\" ? options.customerLine2Placeholder : \"Address line 2\" });\n var $row3 = create$control(\"div\", \"row\", $container);\n var $customerPostalCode = containsCustomer(\"postal_code\") && create$control(\"input\", \"customerPostalCode\", $row3, { type: \"text\", placeholder: typeof options.customerPostalCodePlaceholder === \"string\" ? options.customerPostalCodePlaceholder : \"Postal Code\" });\n var $customerCity = containsCustomer(\"city\") && create$control(\"input\", \"customerCity\", $row3, { type: \"text\", placeholder: typeof options.customerCityPlaceholder === \"string\" ? options.customerCityPlaceholder : \"City\" });\n var $row4 = create$control(\"div\", \"row\", $container);\n var $customerState = containsCustomer(\"state\") && create$control(\"input\", \"customerState\", $row4, { type: \"text\", placeholder: typeof options.customerStatePlaceholder === \"string\" ? options.customerStatePlaceholder : \"State\" });\n var $customerCountry = containsCustomer(\"country\") && create$control(\"input\", \"customerCountry\", $row4, { type: \"text\", placeholder: typeof options.customerCountryPlaceholder === \"string\" ? options.customerCountryPlaceholder : \"Country\" });\n\n var $tracking = create$control(\"input\", \"tracking\", $container, { type: \"hidden\", configurable: true });\n\n var $publishStatus = create$control(\"input\", \"publishStatus\", $container, { type: \"text\" });\n\n var $publish = create$control(\"button\", \"publish\", $container, {});\n var $publishText = create$control(\"span\", \"publishText\", $publish, { text: typeof options.textPublish === \"string\" ? options.textPublish : \"Get voucher\" });\n\n $publishStatus.prop(\"readonly\", true).hide();\n\n var self = this;\n var classInvalid = options.classInvalid === \"string\" ? options.classInvalid : \"voucherifyInvalid\";\n var classValid = typeof options.classValid === \"string\" ? options.classValid : \"voucherifyValid\";\n var classInvalidAnimation = options.classInvalidAnimation === \"string\" ? options.classInvalidAnimation : \"voucherifyAnimationShake\";\n var classValidAnimation = options.classValidAnimation === \"string\" ? options.classValidAnimation : \"voucherifyAnimationTada\";\n\n function error$control($control) {\n $control.toggleClass(classInvalid, true);\n $control.toggleClass(classValid, false);\n $control.toggleClass(classInvalidAnimation, true)\n .delay(1000)\n .queue(function(){\n $control.toggleClass(classInvalidAnimation, false);\n $control.toggleClass(classInvalid, false);\n $control.toggleClass(classValid, false);\n $control.dequeue();\n });\n }\n\n $publish.on(\"click\", function(event) {\n $tracking.val(\"\");\n\n $publish.toggleClass(classInvalid, false);\n $publish.toggleClass(classValid, false);\n\n var payload = {\n customer: {}\n };\n\n if (containsCustomer(\"name\")) {\n if (!$customerName.val() && isRequired(\"name\")) {\n return error$control($customerName);\n }\n payload.customer[\"name\"] = $customerName.val();\n }\n\n if (containsCustomer(\"email\")) {\n if (!$customerEmail.val() && isRequired(\"email\")) {\n return error$control($customerEmail);\n }\n if ($customerEmail.val() && !EMAIL_PATTERN.test($customerEmail.val())) {\n return error$control($customerEmail);\n }\n payload.customer[\"email\"] = $customerEmail.val();\n payload.customer[\"source_id\"] = payload.customer[\"email\"];\n }\n\n if (containsCustomer(\"phone\") ) {\n if (!$customerPhone.val() && isRequired(\"phone\")) {\n return error$control($customerPhone);\n }\n if ($customerPhone.val()) {\n payload.customer[\"phone\"] = $customerPhone.val();\n }\n }\n\n if (containsCustomer(\"line_1\") ||\n containsCustomer(\"line_2\") ||\n containsCustomer(\"postal_code\") ||\n containsCustomer(\"city\") ||\n containsCustomer(\"state\") ||\n containsCustomer(\"country\")) {\n payload.customer[\"address\"] = {};\n }\n\n if (containsCustomer(\"line_1\")) {\n if (!$customerLine1.val() && isRequired(\"line_1\")) {\n return error$control($customerLine1);\n }\n payload.customer[\"address\"][\"line_1\"] = $customerLine1.val();\n }\n\n if (containsCustomer(\"line_2\")) {\n if (!$customerLine2.val() && isRequired(\"line_2\")) {\n return error$control($customerLine2);\n }\n payload.customer[\"address\"][\"line_2\"] = $customerLine2.val();\n }\n\n if (containsCustomer(\"postal_code\")) {\n if (!$customerPostalCode.val() && isRequired(\"postal_code\")) {\n return error$control($customerPostalCode);\n }\n payload.customer[\"address\"][\"postal_code\"] = $customerPostalCode.val();\n }\n\n if (containsCustomer(\"city\")) {\n if (!$customerCity.val() && isRequired(\"city\")) {\n return error$control($customerCity);\n }\n payload.customer[\"address\"][\"city\"] = $customerCity.val();\n }\n\n if (containsCustomer(\"state\")) {\n if (!$customerState.val() && isRequired(\"state\")) {\n return error$control($customerState);\n }\n payload.customer[\"address\"][\"state\"] = $customerState.val();\n }\n\n if (containsCustomer(\"country\")) {\n if (!$customerCountry.val() && isRequired(\"country\")) {\n return error$control($customerCountry);\n }\n payload.customer[\"address\"][\"country\"] = $customerCountry.val()\n }\n\n self.publish(options.campaignName, payload, function(response) {\n if (!response || !response.voucher || !response.voucher.code) {\n var context = response.context || {};\n var responseJSON = context.responseJSON || {};\n var error_key = responseJSON.key;\n\n error$control($publish);\n\n if (containsCustomer(\"phone\") && error_key === INVALID_CUSTOMER_PHONE) {\n error$control($customerPhone);\n }\n\n return;\n }\n\n $customerName && $customerName.hide();\n $customerEmail && $customerEmail.hide();\n $customerPhone && $customerPhone.hide();\n $customerLine1 && $customerLine1.hide();\n $customerLine2 && $customerLine2.hide();\n $customerPostalCode && $customerPostalCode.hide();\n $customerCity && $customerCity.hide();\n $customerState && $customerState.hide();\n $customerCountry && $customerCountry.hide();\n\n $publishStatus\n .toggleClass(classValidAnimation, true)\n .val(response.voucher.code).show(100);\n\n $tracking.val(response.tracking_id || \"\");\n\n $publish.prop(\"disabled\", true);\n\n $publish\n .toggleClass(classInvalid, false)\n .hide();\n\n if (options && options.onPublished && typeof options.onPublished === \"function\") {\n options.onPublished(response);\n }\n });\n });\n }\n };\n\n (function(funcName, baseObj) {\n \"use strict\";\n\n if (!baseObj) {\n return;\n }\n\n funcName = funcName || \"docReady\";\n baseObj = baseObj || window;\n var readyList = [];\n var readyFired = false;\n var readyEventHandlersInstalled = false;\n\n function ready() {\n if (!readyFired) {\n readyFired = true;\n for (var i = 0; i < readyList.length; i++) {\n readyList[i].fn.call(window, readyList[i].ctx);\n }\n readyList = [];\n }\n }\n\n function readyStateChange() {\n if ( document.readyState === \"complete\" ) {\n ready();\n }\n }\n\n baseObj[funcName] = function(callback, context) {\n if (typeof callback !== \"function\") {\n throw new TypeError(\"callback for docReady(fn) must be a function\");\n }\n if (readyFired) {\n setTimeout(function() {callback(context);}, 1);\n return;\n } else {\n readyList.push({fn: callback, ctx: context});\n }\n if (document.readyState === \"complete\" || (!document.attachEvent && document.readyState === \"interactive\")) {\n setTimeout(ready, 1);\n } else if (!readyEventHandlersInstalled) {\n if (document.addEventListener) {\n document.addEventListener(\"DOMContentLoaded\", ready, false);\n window.addEventListener(\"load\", ready, false);\n } else {\n document.attachEvent(\"onreadystatechange\", readyStateChange);\n window.attachEvent(\"onload\", ready);\n }\n readyEventHandlersInstalled = true;\n }\n }\n })(\"docReady\", window);\n\n function renderIframes() {\n var host = \"https://app.voucherify.io\";\n var common_attributes = [\n \"client-app-id\",\n \"client-token\",\n\n \"logo\"\n ];\n\n var iframes_widgets = {\n \"voucher-redeem\": {\n \"path\": \"/widgets/redeem\",\n \"attributes\": [\n \"code-field\",\n \"code-field-required\",\n \"code-field-label\",\n\n \"amount-field\",\n \"amount-field-required\",\n \"amount-field-label\",\n\n \"name-field\",\n \"name-field-required\",\n \"name-field-label\",\n\n \"email-field\",\n \"email-field-required\",\n \"email-field-label\",\n\n \"phone-field\",\n \"phone-field-required\",\n \"phone-field-label\",\n\n \"address-line-1-field\",\n \"address-line-1-field-required\",\n \"address-line-1-field-label\",\n\n \"address-line-2-field\",\n \"address-line-2-field-required\",\n \"address-line-2-field-label\",\n\n \"city-field\",\n \"city-field-required\",\n \"city-field-label\",\n\n \"postal-code-field\",\n \"postal-code-field-required\",\n \"postal-code-field-label\",\n\n \"state-field\",\n \"state-field-required\",\n \"state-field-label\",\n\n \"country-field\",\n \"country-field-required\",\n \"country-field-label\",\n\n \"button-label\"\n ]\n },\n \"get-voucher\": {\n \"path\": \"/widgets/publish\",\n \"attributes\": [\n \"campaign\",\n\n \"metadata\",\n \"source\",\n\n \"name-field\",\n \"name-field-required\",\n \"name-field-label\",\n\n \"email-field\",\n \"email-field-required\",\n \"email-field-label\",\n\n \"phone-field\",\n \"phone-field-required\",\n \"phone-field-label\",\n\n \"address-line-1-field\",\n \"address-line-1-field-required\",\n \"address-line-1-field-label\",\n\n \"address-line-2-field\",\n \"address-line-2-field-required\",\n \"address-line-2-field-label\",\n\n \"city-field\",\n \"city-field-required\",\n \"city-field-label\",\n\n \"postal-code-field\",\n \"postal-code-field-required\",\n \"postal-code-field-label\",\n\n \"state-field\",\n \"state-field-required\",\n \"state-field-label\",\n\n \"country-field\",\n \"country-field-required\",\n \"country-field-label\",\n\n \"button-label\"\n ]\n },\n \"subscribe\": {\n \"path\": \"/widgets/subscribe\",\n \"attributes\": [\n \"metadata\",\n \"source\",\n\n \"name-field\",\n \"name-field-required\",\n \"name-field-label\",\n\n \"email-field\",\n \"email-field-required\",\n \"email-field-label\",\n\n \"phone-field\",\n \"phone-field-required\",\n \"phone-field-label\",\n\n \"address-line-1-field\",\n \"address-line-1-field-required\",\n \"address-line-1-field-label\",\n\n \"address-line-2-field\",\n \"address-line-2-field-required\",\n \"address-line-2-field-label\",\n\n \"city-field\",\n \"city-field-required\",\n \"city-field-label\",\n\n \"postal-code-field\",\n \"postal-code-field-required\",\n \"postal-code-field-label\",\n\n \"state-field\",\n \"state-field-required\",\n \"state-field-label\",\n\n \"country-field\",\n \"country-field-required\",\n \"country-field-label\",\n\n \"subscribe-label\"\n ]\n }\n };\n\n var helpers = {\n bind: function (element, name, callback) {\n if (element.addEventListener) {\n return element.addEventListener(name, callback, false)\n } else {\n return element.attachEvent(\"on\" + name, callback)\n }\n },\n readOptions: function (element, allowed_options) {\n return Array.prototype.reduce.call(allowed_options, function (options, allowed_option) {\n var option_value = element.getAttribute(\"data-\" + allowed_option);\n\n if (option_value) {\n options[allowed_option] = option_value;\n }\n\n return options;\n }, {});\n },\n encodeOptions: function (options) {\n var query_parameters = [];\n\n Object.keys(options).forEach(function(option_key) {\n query_parameters.push(\"[options][\"+option_key+\"]=\"+encodeURIComponent(options[option_key]));\n });\n\n return \"?\" + query_parameters.join(\"&\");\n }\n };\n\n\n function RenderIframe(element, options) {\n var self = this;\n\n self._element = element;\n\n self._path = options.path;\n\n self._options = helpers.readOptions(self._element, common_attributes.concat(options.attributes));\n\n self._iframe = null;\n\n return this.renderIframe();\n }\n\n RenderIframe.prototype.renderIframe = function () {\n var self = this;\n\n if (self._iframe) {\n return self;\n }\n\n var css_props = [\n \"width:400px;\",\n \"height:475px;\",\n \"background: transparent;\",\n \"border: 0px none transparent;\",\n \"overflow-x: hidden;\",\n \"overflow-y: auto;\",\n \"visibility: hidden;\",\n \"margin: 0;\",\n \"padding: 0;\",\n \"-webkit-tap-highlight-color: transparent;\",\n \"-webkit-touch-callout: none;\"\n ];\n\n self._iframe = document.createElement(\"iframe\");\n self._iframe.setAttribute(\"frameBorder\", \"0\");\n self._iframe.setAttribute(\"allowtransparency\", \"true\");\n self._iframe.style.cssText = css_props.join(\"\\n\");\n\n helpers.bind(self._iframe, \"load\", function () {\n return self._iframe.style.visibility = \"visible\"\n });\n\n self._iframe.src = host + self._path + helpers.encodeOptions(self._options);\n\n self._element.appendChild(self._iframe);\n\n return self;\n };\n\n var widgets = [];\n\n Object.keys(iframes_widgets).forEach(function (widget_name) {\n var elements = window.document.querySelectorAll(\".voucherify-\" + widget_name);\n\n Array.prototype.forEach.call(elements, function (element) {\n widgets.push(new RenderIframe(element, iframes_widgets[widget_name]));\n })\n });\n\n return widgets;\n }\n\n if (window) {\n window.docReady(function () {\n console.info(\"Document ready. Render voucherify iframes.\");\n renderIframes();\n });\n }\n\n\n if (typeof module !== \"undefined\" && module.exports) {\n module.exports = voucherify;\n }\n\n return voucherify;\n} (window, window.document, window.jQuery));\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/lib/voucherify.js b/lib/voucherify.js index b67300e..93019bd 100644 --- a/lib/voucherify.js +++ b/lib/voucherify.js @@ -9,7 +9,8 @@ window.Voucherify = (function (window, document, $) { publish: API_BASE + "/client/v1/publish", list: API_BASE + "/client/v1/vouchers", track: API_BASE + "/client/v1/events", - validatePromotion: API_BASE + "/client/v1/promotions/validation" + validatePromotion: API_BASE + "/client/v1/promotions/validation", + redeemPromotion: API_BASE + "/client/v1/promotions/tiers/" }; var OPTIONS = {}; @@ -285,23 +286,35 @@ window.Voucherify = (function (window, document, $) { }, redeem: function (code, payload, callback) { + var isPromotion = false; + var tier; + if (!isValidInit(OPTIONS)) { return null; } if (!code) { - console.error("Voucherify client could not verify code, because it is missing - please provide Voucher Code."); - return null; + if( !payload.tier ){ + console.error("Voucherify client could not redeem promotion without tier, because it is missing."); + return null; + } + isPromotion = true; + tier = payload.tier; + delete payload.tier } - var queryString = "?code=" + encodeURIComponent(code.replace(/[\s\r\n]/g, "")); + var queryString = "" + if(!isPromotion){ + queryString += "?code=" + encodeURIComponent(code.replace(/[\s\r\n]/g, "")); + } // -- Tracking ID fallback payload = payload || {}; payload.customer = payload.customer || {}; payload.customer.source_id = payload.customer.source_id || OPTIONS.trackingId; - return xhrImplementation("POST", API.redeem + queryString, payload, callback); + + return xhrImplementation("POST", (isPromotion ? API.redeemPromotion + tier + "/redemption" : API.redeem) + queryString, payload, callback); }, publish: function (campaign, payload, callback) {