1/** 2 * Created by Narinder Gaheer on 11/01/2017. 3 */ 4var wl = wl || {}; 5 6wl.app.module('oPayments', function (oPayments, oPaymentsApp, Backbone, Marionette, $) { 7 8 //disable cache for webview 9 if (location.pathname.indexOf('mobile') !== -1) { 10 $.ajaxSetup({ cache: false }); 11 } 12 13 var PaymentModel = Backbone.Model.extend({ 14 defaults: { 15 error: undefined, 16 subscriptionEndDate: dayjs(), 17 subscrOnTrialPeriod: false, 18 subscrPricePerMonth: 0, 19 company: undefined, 20 proPlusUpgradeAmount: 0, 21 paymentDetails: null, 22 cardExpired: false, 23 useSavedCard: true, 24 amountDue: 0, 25 taxDue: 0, 26 taxRate: 0, 27 beforeTax: true, 28 existingUpgrades: 1, 29 usedUpgrades: 0, 30 existingUpgradesAmountDue: 0, 31 newUgradesAmountDue: 0, 32 totalAmountDue: 0, 33 couponDiscount: null, 34 validatedAddresses: [], 35 subscriptionTerms: [], 36 newSubscriptionTermId: 1, 37 currentSubscrLengthInMonths: 12, 38 lengthInMonths: 12, 39 showUpgradesDetected: false, 40 selectedAddressIndex: 0, 41 cardholderName: null, 42 cardNumber: null, 43 expiration: null, 44 cvc: null, 45 countryId: null, 46 countryName: undefined, 47 countryCode: null, 48 address1: null, 49 city: null, 50 state: null, 51 zipCode: null, 52 couponCode: null, 53 requestTokenForm: undefined, 54 newSubscrTypeId: null, 55 userSubscriptionTypeId: null, 56 userSubscriptionTypeName: null, 57 expDate: null, 58 proPrice: 47.4, 59 proPlusPrice: 107.4, 60 subscriptionTypes: [], 61 selectedServicePlan: null, 62 trialMode: false, 63 newUpgradesAdjustmentAmount: 0, 64 numNewUpgrades: 1, 65 upgradeType: null, 66 upgradeSystemId: 0, 67 newArchivalRate: null, 68 standalone: false, 69 renewal: false, 70 taxLabel: 'Tax', 71 taxLabelInDesc: 'tax', 72 reactivateDevice: false, 73 customerCurrency: 'USD', 74 totalAmountCustomerCurrency: null, 75 paymentIntentId: null, 76 clientSecret: null 77 } 78 }); 79 80 oPayments.checkIfCardExpired = function (paymentDetails) { 81 var expired = false; 82 if (paymentDetails) { 83 var expMonth = paymentDetails.expMonth; 84 var expYear = paymentDetails.expYear; 85 var currentMonth = dayjs().month() + 1; 86 var currentYear = dayjs().year() 87 expired = expYear < currentYear || (expYear === currentYear && 88 expMonth < currentMonth); 89 } 90 return expired; 91 } 92 93 oPayments.sharedModel = new PaymentModel(); 94 95 oPayments.MakePaymentView = Marionette.LayoutView.extend({ 96 trialMode: false, 97 model: oPayments.sharedModel, 98 regions: { 99 fullWidthRegion: '#full-width-region', 100 mainRegion: '#main-region', 101 detailsRegion: '#details-region' 102 }, 103 childEvents: { 104 'billingAddress:render': function () { 105 this.showBillingAddressForm(); 106 }, 107 'paymentForm:render': function () { 108 this.showPaymentForm(); 109 }, 110 'detectedUpgrades:render': function () { 111 this.showDetectedUpgrades(); 112 }, 113 'detectedUpgradesOrPaymentForm:render': function () { 114 this.showDetectedUpgradesOrPaymentForm(); 115 }, 116 'resellerAssociated:render': function () { 117 this.showResellerAssociated(); 118 }, 119 'confirm-address:render': function () { 120 this.showConfirmAddress(); 121 }, 122 'payment-success:render': function () { 123 this.showPaymentSuccess(); 124 }, 125 'subscription-select:render': function () { 126 this.showSubscriptionSelect(); 127 }, 128 'comparison-chart:render': function () { 129 this.showComparisonChart(); 130 }, 131 'addMoreSensors:render': function () { 132 this.showAddMoreSensors(); 133 }, 134 'cardDetails:saved': function () { 135 // pass event to parent card details view 136 this.triggerMethod('cardDetails:saved'); 137 } 138 }, 139 initialize: function (options) { 140 if (options.isTrial) { 141 this.trialMode = (options.isTrial && options.isTrial === 'true') ? 142 true : false; 143 } 144 this.newSubscrType = options.subscrType; 145 146 this.model.set('upgradeSystemId', Number(options.upgradeSystemId)); 147 this.model.set('newArchivalRate', Number(options.newArchivalRate)); 148 149 //if passed 0 as numNewUpgrades param 150 //upgrade from pro to proplus without buying an additional upgrade 151 if (options.numNewUpgrades && !_.isNaN(Number(options.numNewUpgrades)) && 152 this.newSubscrType === "ProPlus") { 153 this.model.set('numNewUpgrades', Number(options.numNewUpgrades)) 154 } 155 156 //check if user has saved card
157 this.getCreditCardProfile(); 158 159 this.checkIfAssociatedWithReseller().then(function (response) { 160 if (response && response.data) { 161 this.model.set('company', response.data); 162 } 163 this.checkIfAlreadySubscribed().then(function (response) { 164 if (response.data && response.data.subscription) { 165 this.model.set('subscrOnTrialPeriod', Boolean( 166 response.data 167 .subscription.isTrialPeriod)); 168 169 var alreadySubscribed = this.newSubscrType == 'Pro' && 170 response.data.subscriptionType.userSubscriptionTypeId == 171 2; 172 173 alreadySubscribed = alreadySubscribed || (this.newSubscrType == 174 'ProPlus' && response.data.subscriptionType.userSubscriptionTypeId == 175 3); 176 177 if (response.data.proPlusUpgradeAmount) { 178 this.model.set('proPlusUpgradeAmount', 179 response.data.proPlusUpgradeAmount); 180 //this.model.set('totalAmountDue', response.data.proPlusUpgradeAmount); 181 } 182 183 this.model.set('existingUpgrades', response.data.subscription 184 .numDeviceUpgrades); 185 this.model.set('userSubscriptionTypeId', response.data 186 .subscription.userSubscriptionTypeId); 187 this.model.set('userSubscriptionTypeName', response.data 188 .subscriptionType.subscriptionTypeName); 189 this.model.set('newSubscriptionTermId', response.data 190 .subscription.subscriptionTermId); 191 //this.model.set('expDate', response.data.subscription.expirationDate); 192 193 var subscriptionEnd = dayjs(response.data.subscription 194 .subscriptionEnd); 195 this.model.set('subscriptionEndDate', subscriptionEnd 196 .format('MMMM Do, YYYY')); 197 var now = dayjs(); 198 199 //if not passed in url 200 if (!this.newSubscrType) { 201 this.newSubscrType = this.model.get('userSubscriptionTypeId') === 3 202 ? 'ProPlus' : 'Pro'; 203 } 204 205 //if user is on Pro+ can't set Pro 206 if (this.newSubscrType == 'Pro' && this.model.get('userSubscriptionTypeId') === 3) { 207 this.newSubscrType = 'ProPlus'; 208 makeChangesToUrl(this.model.get('upgradeSystemId'), this.model.get('newArchivalRate'), 3, 209 this.model.get('trialMode')); 210 } 211 212 if (this.newSubscrType == 'Pro') { 213 this.model.set('newSubscrName', 'Pro'); 214 this.model.set('newSubscrTypeId', 2); 215 } else if (this.newSubscrType == 'ProPlus') { 216 this.model.set('newSubscrName', 'Pro+'); 217 this.model.set('newSubscrTypeId', 3); 218 } 219 220 //load subscription types 221 this.loadSubscriptionTypes().then(function (response) { 222 if (response.freeTrial === false && this.model.get('trialMode')) { 223 this.showFreeTrialWarning(); 224 return; 225 } 226 227 var currentSubscriptionType = _.find(response.subscriptionTypes, { 228 userSubscriptionTypeId: this.model.get( 229 'userSubscriptionTypeId') 230 }); 231 var currentSubscriptionTerms = _.get( 232 currentSubscriptionType, 233 'subscriptionTerms'); 234 var currentSubscriptionTerm = _.find( 235 currentSubscriptionTerms, { 236 iUserSubscriptionTermId: this.model.get( 237 'newSubscriptionTermId') 238 }); 239 240 var newSubscriptionType = _.find(response.subscriptionTypes, { 241 userSubscriptionTypeId: this.model.get( 242 'newSubscrTypeId') 243 }); 244 var newSubscriptionTerms = _.get( 245 newSubscriptionType, 'subscriptionTerms'); 246 var subscriptionTerm = 247 _.find(newSubscriptionTerms, { 248 iUserSubscriptionTermId: this.model.get( 249 'newSubscriptionTermId') 250 }); 251 252 //if length in months was passed as url param 253 if (options.lengthInMonths && !_.isNaN(Number(options.lengthInMonths))) { 254 subscriptionTerm = _.find(newSubscriptionTerms, { 255 lengthInMonths: Number(options.lengthInMonths) 256 }); 257 258 this.model.set('newSubscriptionTermId', 259 subscriptionTerm.iUserSubscriptionTermId); 260 } 261 262 if (!subscriptionTerm) { //when changing subscr type 263 //find subscription term with matching length of the current term 264 subscriptionTerm = _.find( 265 newSubscriptionTerms, { 266 lengthInMonths: currentSubscriptionTerm && currentSubscriptionTerm 267 .lengthInMonths || this.model.get('currentSubscrLengthInMonths') 268 }); 269 //if still not found i.e current term is Basic, then select the first one available 270 if (!subscriptionTerm) { 271 subscriptionTerm = newSubscriptionTerms[0]; 272 } 273 this.model.set('newSubscriptionTermId', 274 subscriptionTerm.iUserSubscriptionTermId); 275 } 276 277 //if no term found on current subscription 278 if (!currentSubscriptionTerm || this.model.get( 279 'userSubscriptionTypeId') === 1) { //basic user 280 currentSubscriptionTerm = subscriptionTerm; 281 } 282 283 this.model.set('currentSubscrLengthInMonths', _ 284 .get(currentSubscriptionTerm, 285 'lengthInMonths')); 286 287 //if user is on 3-year plan, can't set 1-year 288 var lengthInMonths = _.get(subscriptionTerm, 'lengthInMonths') < 289 this.model.get('currentSubscrLengthInMonths') ? this.model.get('currentSubscrLengthInMonths') 290 : _.get(subscriptionTerm, 'lengthInMonths'); 291 292 //if it wasn't set on plan selection step 293 if (this.model.get('lengthInMonths') !== 36) { 294 this.model.set('lengthInMonths', lengthInMonths); 295 } 296 this.model.set('subscriptionTypes', response.subscriptionTypes); 297 this.model.set('subscriptionTerms', 298 newSubscriptionTerms); 299 300 if (options.subscrType) { 301 //detect existing upgrades
302 this.showDetectedUpgradesOrPaymentForm(); 303 } else { 304 //show if subscr type param is not passed 305 this.showSubscriptionSelect(); 306 } 307 }.bind(this)); 308 } else { 309 this.showBillingAddressForm(); 310 } 311 }.bind(this)); 312 }.bind(this)); 313 314 this.model.set('trialMode', this.trialMode); 315 }, 316 ui: { 317 $cancelPayment: '#cancel-payment', 318 }, 319 template: window.tpl['makePayment'], 320 events: { 321 "click @ui.$cancelPayment": "cancelPaymentForm" 322 }, 323 onRender: function () { 324 }, 325 onShow: function () { 326 var $container = $('#connection-issue'); 327 window.addEventListener('online', function () { 328 $container.empty(); 329 }); 330 331 window.addEventListener('offline', function () { 332 var connectionIssueView = new ConnectionIssueView(); 333 connectionIssueView.render(); 334 $container.append(connectionIssueView.$el); 335 }); 336 }, 337 showFreeTrialWarning: function () { 338 this.showChildView('fullWidthRegion', new FreeTrialNotAvailableView()); 339 this.hideDetailsAndMainRegions(); 340 $('.payment-form-container').show(); 341 $('.payments-loading-spinner').hide(); 342 }, 343 showBillingAddressForm: function (options) { 344 this.showChildView('mainRegion', new oPayments.BillingAddressView(options)); 345 if (!this.detailsRegion.hasView()) { 346 this.showChildView('detailsRegion', new oPayments.SubscriptionDetailsView()); 347 } 348 }, 349 showPaymentForm: function (options) { 350 this.showChildView('mainRegion', new oPayments.PaymentFormView(options)); 351 if (!this.detailsRegion.hasView()) { 352 this.showChildView('detailsRegion', new oPayments.SubscriptionDetailsView()); 353 } 354 }, 355 showCardDetailsForm: function (options) { 356 this.showChildView('mainRegion', new oPayments.CardDetailsFormView(options)); 357 }, 358 showResellerAssociated: function () { 359 this.showChildView('fullWidthRegion', new ResellerAssociatedView()); 360 this.hideDetailsAndMainRegions(); 361 }, 362 showSubscriptionSelect: function () { 363 this.showChildView('mainRegion', new oPayments.SubscriptionSelectView()); 364 if (!this.detailsRegion.hasView()) { 365 this.showChildView('detailsRegion', new oPayments.SubscriptionDetailsView()); 366 } 367 }, 368 showDetectedUpgrades: function () { 369 this.showChildView('mainRegion', new UpgradesDetectedView()); 370 if (!this.detailsRegion.hasView()) { 371 this.showChildView('detailsRegion', new oPayments.SubscriptionDetailsView()); 372 } 373 }, 374 showPurchaseOrUseUpgrade: function () { 375 this.showChildView('mainRegion', new PurchaseOrUseUpgradeView()); 376 if (!this.detailsRegion.hasView()) { 377 this.showChildView('detailsRegion', new oPayments.SubscriptionDetailsView()); 378 } 379 }, 380 showConfirmAddress: function () { 381 this.showChildView('mainRegion', new oPayments.ConfirmAddressView()); 382 }, 383 showPaymentSuccess: function () { 384 this.showChildView('fullWidthRegion', new PaymentSuccessView()); 385 this.hideDetailsAndMainRegions(); 386 }, 387 showComparisonChart: function () { 388 this.showChildView('mainRegion', new ComparisonChartView()); 389 }, 390 showDetectedUpgradesOrPaymentForm: function () { 391 //when upgrading pro to pro+ 392 if (this.model.get('userSubscriptionTypeId') === 2 && this.model.get('newSubscrTypeId') === 3) { 393 this.model.set('numNewUpgrades', 0); 394 } 395 wl.app.shareCalls.getDeviceUpgrades() 396 .then(function (res) { 397 if (res) this.model.set('usedUpgrades', res.length); 398 return getAmountDue( 399 this.model.get('trialMode'), 400 this.model.get('newSubscriptionTermId'), 401 this.model.get('newSubscrTypeId'), 402 this.model.get('numNewUpgrades')) 403 }.bind(this)) 404 .then(function (response) { 405 if (response.data) { 406 $('.payment-form-container').show(); 407 $('.payments-loading-spinner').hide(); 408 getAmountDueCallback(this.model, response.data); 409 if (!this.model.get('existingUpgrades') && !response.data.newUpgradesAdjustmentAmount) { 410 if (this.model.get('company') && !this.model.get('company').isDavisManaged) { 411 this.showResellerAssociated(); 412 } else { 413 this.showBillingAddressForm({upgrade: this.options.upgrade}); 414 } 415 } else { 416 if (window.location.pathname.indexOf('mobile') !== -1 && 417 (this.model.get('userSubscriptionTypeId') === this.model.get('newSubscrTypeId')) && 418 this.model.get('currentSubscrLengthInMonths') === this.model.get('lengthInMonths') && 419 this.model.get('usedUpgrades') < this.model.get('existingUpgrades')) { 420 this.showPurchaseOrUseUpgrade(); 421 } else { 422 if (this.model.get('company') && !this.model.get('company').isDavisManaged) { 423 this.showResellerAssociated(); 424 } else { 425 this.model.set('showUpgradesDetected', true); 426 this.showDetectedUpgrades(); 427 } 428 } 429 } 430 } 431 }.bind(this)) 432 }, 433 showAddMoreSensors: function () { 434 this.showChildView('fullWidthRegion', new oPayments.AddMoreSensorsView()); 435 },
436 getCreditCardProfile: function () { 437 var d = $.Deferred(); 438 $.get('/accountSubscription/creditCardProfile', function (response) { 439 if (response.data != null) { 440 this.model.set('paymentDetails', response.data); 441 this.model.set('address1', response.data.address1); 442 this.model.set('city', response.data.city); 443 this.model.set('state', response.data.region); 444 this.model.set('zipCode', response.data.zipCode); 445 this.model.set('countryId', response.data.countryId); 446 this.model.set('cardExpired', oPayments.checkIfCardExpired(response.data)); 447 this.model.set('stripePaymentMethodId', response.data.stripePaymentMethodId); 448 } 449 d.resolve(response.data); 450 }.bind(this)); 451 return d.promise(); 452 }, 453 loadSubscriptionTypes: function () { 454 var d = $.Deferred(); 455 $.get('/accountSubscription/userSubscriptionPlansPricing', function (response) { 456 if (response.data != null) { 457 d.resolve(response.data); 458 } else { 459 d.resolve([]); 460 } 461 }.bind(this)); 462 return d.promise(); 463 }, 464 checkIfAlreadySubscribed: function () { 465 var d = $.Deferred(); 466 var self = this; 467 $.ajax({ 468 type: "GET", 469 url: "/accountSubscription/currentSubscription", 470 success: function (response) { 471 d.resolve(response); 472 }, 473 error: function (err) { 474 } 475 }); 476 return d.promise(); 477 }, 478 479 checkIfAssociatedWithReseller: function () { 480 var d = $.Deferred(); 481 $.ajax({ 482 type: "GET", 483 url: "/accountSubscription/isUserAssociatedWithReseller", 484 success: function (response) { 485 d.resolve(response); 486 }, 487 error: function (err) { 488 d.resolve(null); 489 } 490 }); 491 return d.promise(); 492 }, 493 // submitPaymentFormFake: function (e) { 494 // this.ui.$formSections.hide(); 495 // this.ui.$paymentSuccess.show(); 496 // return false; 497 // }, 498 cancelPaymentForm: function (e) { 499 if (this.model.get('trialMode')) { 500 window.location = "/accountSubscription#confirmCancel/" + this.model.get('upgradeSystemId') 501 + "/" + this.model.get('newArchivalRate') + "/" + this.newSubscrType; 502 } else { 503 window.location = "/bulletin"; 504 } 505 return false; 506 }, 507 hideDetailsAndMainRegions: function () { 508 $('#main-region').hide(); 509 $('#details-region').hide(); 510 } 511 }); 512 513 this.SubscriptionSelectView = Marionette.ItemView.extend({ 514 template: window.tpl['subscription-plans-select'], 515 model: oPayments.sharedModel, 516 ui: { 517 $subscriptionTermRadio: 'input[name="subscriptionTerm"]', 518 $newSubscrTypeRadio: 'input[name="newSubscrType"]', 519 $continuePurchase: '#goToPayments', 520 $comparisonChartLink: '.comparison-chart-link' 521 }, 522 events: { 523 'click button#continuePurchase': 'continuePurchase', 524 'change @ui.$subscriptionTermRadio': 'onChangeSubscriptionTerm', 525 'change @ui.$newSubscrTypeRadio': 'onChangeNewSubscrType', 526 'click @ui.$continuePurchase': 'onClickContinue', 527 'click @ui.$comparisonChartLink': 'onClickComparisonChartLink', 528 }, 529 templateHelpers: function () { 530 return { 531 getTermTranslationKey: function (name) { 532 return _getTermTranslationKey(name); 533 } 534 } 535 }, 536 initialize: function () { 537 if (this.model.get('newSubscrTypeId') == 2) { 538 this.model.set('totalAmountDue', this.model.get('proPrice').toFixed( 539 2)); 540 } else if (this.model.get('newSubscrTypeId') == 3) { 541 this.model.set('totalAmountDue', this.model.get('proPlusPrice').toFixed( 542 2)); 543 } 544 this.model.set('trialMode', false); 545 this.model.set('subscrPricePerMonth', (this.model.get( 546 'totalAmountDue') / this.model.get('lengthInMonths')).toFixed(2)); 547 makeChangesToUrl(this.model.get('upgradeSystemId'), this.model.get('newArchivalRate'), 548 this.model.get('newSubscrTypeId'), this.model.get('trialMode')); 549 $('.payment-form-container').show(); 550 $('.payments-loading-spinner').hide(); 551 }, 552 onRender: function () { 553 var subscriptionType = _.find(this.model.get('subscriptionTypes'), { 554 userSubscriptionTypeId: this.model.get('newSubscrTypeId') 555 }); 556 var subscriptionTerms = _.get(subscriptionType, 'subscriptionTerms'); 557 var currentTerm = _.find(subscriptionTerms, { 558 iUserSubscriptionTermId: this.model.get('newSubscriptionTermId') 559 }); 560 if (!currentTerm) { //when changing subscr type 561 currentTerm = _.find(subscriptionTerms, { 562 lengthInMonths: this.model.get('lengthInMonths') 563 }); 564 } 565 this.model.set('totalAmountDue', currentTerm.price.toFixed(2)); 566 this.model.set('newSubscriptionTermId', currentTerm.iUserSubscriptionTermId); 567 this.model.set('subscrPricePerMonth', (this.model.get( 568 'totalAmountDue') / currentTerm.lengthInMonths).toFixed(2)); 569 this.model.set('lengthInMonths', currentTerm.lengthInMonths); 570 this.model.set('subscriptionTerms', subscriptionTerms); 571 }, 572 onShow: function () { 573 var price = Number($('input[name="subscriptionTerm"]:checked').attr( 574 'data-price')); 575 this.model.set('totalAmountDue', price.toFixed(2)); 576 }, 577 onChangeSubscriptionTerm: function (e) { 578 var $radioBtn = $(e.target); 579 var lengthInMonth = $radioBtn.attr('data-length'); 580 this.model.set('newSubscriptionTermId', Number($radioBtn.val())); 581 this.model.set('lengthInMonths', Number(lengthInMonth)); 582 this.render(); 583 }, 584 onChangeNewSubscrType: function (e) { 585 var $radioBtn = $(e.target);
586 var newSubscrTypeId = Number($radioBtn.val()); 587 var newSubscrName = $radioBtn.attr('data-name'); 588 this.model.set('newSubscrTypeId', newSubscrTypeId); 589 this.model.set('newSubscrName', newSubscrName); 590 this.render(); 591 makeChangesToUrl(this.model.get('upgradeSystemId'), this.model.get('newArchivalRate'), 592 newSubscrTypeId, this.model.get('trialMode')); 593 }, 594 onClickComparisonChartLink: function () { 595 this.triggerMethod('comparison-chart:render'); 596 }, 597 onClickContinue: function () { 598 this.triggerMethod('detectedUpgradesOrPaymentForm:render'); 599 } 600 }); 601 602 var PurchaseOrUseUpgradeView = Marionette.ItemView.extend({ 603 template: window.tpl['purchase-or-use-upgrade'], 604 model: oPayments.sharedModel, 605 ui: { 606 purchaseUpgradeBtn: '#purchaseUpgrade', 607 useUpgradeBtn: '#useUpgrade', 608 cancelBtn: '#cancel', 609 paymentError: '.payment-error', 610 }, 611 events: { 612 'click @ui.purchaseUpgradeBtn': 'onClickPurchaseUpgrade', 613 'click @ui.useUpgradeBtn': 'onClickUseUpgradeBtn', 614 'click @ui.cancelBtn': 'onClickCancel' 615 }, 616 onClickUseUpgradeBtn: function () { 617 this.ui.paymentError.html(''); 618 wl.app.shareCalls.upgradeDevice(this.model.get('upgradeSystemId')).then( 619 function (response) { 620 if (response.data) { 621 window.location.href = "/bulletin"; 622 } else if (response.error) { 623 this.ui.paymentError.html(response.error.errorMessage); 624 } 625 }.bind(this)) 626 }, 627 onClickPurchaseUpgrade: function () { 628 if(this.model.get('company')) { 629 this.triggerMethod('resellerAssociated:render'); 630 } else { 631 this.triggerMethod('detectedUpgrades:render'); 632 } 633 }, 634 onClickCancel: function () { 635 if (this.model.get('trialMode')) { 636 window.location = window.location.pathname + "#confirmCancel/" + this.model.get('upgradeSystemId') 637 + "/" + this.model.get('newArchivalRate') + "/" + 638 this.model.get('userSubscriptionTypeName'); 639 } else { 640 window.location = "/bulletin"; 641 } 642 return false; 643 } 644 }); 645 646 var UpgradesDetectedView = Marionette.ItemView.extend({ 647 template: window.tpl['upgrades-detected'], 648 model: oPayments.sharedModel, 649 ui: { 650 $subscriptionTermRadio: 'input[name="subscriptionTerm"]', 651 $oneYearProTooltip: '#1_year_pro_tooltip', 652 $threeYearProTooltip: '#3_year_pro_tooltip', 653 }, 654 events: { 655 'click button#continuePurchase': 'continuePurchase', 656 'click button#payment-back': 'onClickBackBtn', 657 'change @ui.$subscriptionTermRadio': 'onChangeSubscriptionTerm' 658 }, 659 templateHelpers: function () { 660 return { 661 getTermTranslationKey: function (name) { 662 return _getTermTranslationKey(name); 663 } 664 } 665 }, 666 initialize: function () { 667 //$.fn.tooltip = $.fn.tooltip.noConflict(); 668 }, 669 onRender: function () { 670 var tooltipTranslationKeys = ['upgrades_detected_1_year_tooltip', 671 'upgrades_detected_3_year_tooltip' 672 ]; 673 var oneYearProTooltip = _.template( 674 "<div style='text-align:left; width: 300px;'><%= upgrades_detected_1_year_tooltip %></div>" 675 ); 676 var threeYearProTooltip = _.template( 677 "<div style='text-align:left; width: 300px;'><%= upgrades_detected_3_year_tooltip %></div>" 678 ); 679 Utils.setTooltipTitleHtml(this.ui.$oneYearProTooltip, 680 tooltipTranslationKeys, oneYearProTooltip); 681 Utils.setTooltipTitleHtml(this.ui.$threeYearProTooltip, 682 tooltipTranslationKeys, threeYearProTooltip); 683 }, 684 onChangeSubscriptionTerm: function (e) { 685 var $radioBtn = $(e.target); 686 var lengthInMonth = Number($radioBtn.attr('data-length')); 687 this.model.set('newSubscriptionTermId', Number($radioBtn.val())); 688 this.model.set('lengthInMonths', lengthInMonth); 689 690 getAmountDue(this.model.get('trialMode'), 691 this.model.get('newSubscriptionTermId'), 692 this.model.get('newSubscrTypeId'), 693 this.model.get('numNewUpgrades'), 694 this.model.get('validatedAddresses')[e.target.value] 695 ).then(function (response) { 696 getAmountDueCallback(this.model, response.data); 697 this.render(); 698 }.bind(this)); 699 }, 700 continuePurchase: function () { 701 this.model.set('showUpgradesDetected', false); 702 //this.triggerMethod('paymentForm:render'); 703 //To be changed when ready 704 this.triggerMethod('billingAddress:render'); 705 }, 706 onClickBackBtn: function () { 707 this.model.set('showUpgradesDetected', false); 708 this.triggerMethod('subscription-select:render'); 709 } 710 }); 711
712 oPayments.SubscriptionDetailsView = Marionette.ItemView.extend({ 713 template: window.tpl['subscription-details'], 714 model: oPayments.sharedModel, 715 initialize: function () { 716 this.model.on('change', this.customRender.bind(this)); 717 }, 718 onDestroy: function () { 719 this.model.off('change'); 720 }, 721 customRender: function () { 722 var textEl = $.parseHTML(this.template(this.model.toJSON()))[8]; 723 $(this.$el).find('.info-section').replaceWith(textEl); 724 } 725 }); 726 727 var FreeTrialNotAvailableView = Marionette.ItemView.extend({ 728 template: window.tpl['free-trial-unavailable'], 729 model: oPayments.sharedModel 730 }); 731 732 var ResellerAssociatedView = Marionette.ItemView.extend({ 733 template: window.tpl['reseller-associated'], 734 model: oPayments.sharedModel 735 }); 736 737 oPayments.BillingAddressView = Marionette.ItemView.extend({ 738 template: window.tpl['billing-address-form'], 739 model: oPayments.sharedModel, 740 ui: { 741 $paymentForm: '#payment-form', 742 $paymentError: '.payment-error', 743 $formInput: '.payment-form input', 744 $country: '#country', 745 $address1: '#address1', 746 $city: '#city', 747 $state: '#state', 748 $countryInput: '.country', 749 $combobox: '.custom-combobox', 750 $zip: '#zipCode', 751 $couponCode: '#couponCode', 752 $couponRow: '#couponRow', 753 $addressSection: '.address-section', 754 $subscriptionTermRadio: 'input[name="subscriptionTerm"]', 755 $backBtn: '#payment-back', 756 $continuePurchase: "#continuePurchase", 757 $invalidAddress: "#invalid-address", 758 $continueWithInvalidAddress: "#invalid-address-continue" 759 }, 760 events: { 761 "focus @ui.$formInput": "onInputFocus", 762 "input @ui.$formInput": "onInput", 763 "blur @ui.$formInput": "onInputBlur", 764 "blur @ui.$countryInput": "onBlurCountryInput", 765 "blur @ui.$couponCode": "onBlurCouponCodeInput", 766 "select @ui.$country": "onChangeCountry", 767 "keypress @ui.$countryInput": "onCountryKeyPress", 768 "change @ui.$subscriptionTermRadio": "onChangeSubscriptionTerm", 769 "click @ui.$backBtn": "onClickBackBtn", 770 "click @ui.$continuePurchase": "onClickContinue", 771 "click @ui.$continueWithInvalidAddress": "onClickContinueWithInvalidAddress" 772 }, 773 templateHelpers: function () { 774 return { 775 getTermTranslationKey: function (name) { 776 return _getTermTranslationKey(name); 777 }, 778 upgrade: this.options.upgrade, 779 mobile: window.location.pathname.indexOf('mobile') !== -1 780 } 781 }, 782 initialize: function () { 783 this.on('external:validate-address', function () { 784 this.validateAddress(); 785 }); 786 }, 787 onRender: function () { 788 $.validator.setDefaults({ 789 ignore: ":hidden:not(.not-masked)" 790 }); 791 this.oFormValidator = FORM_VALIDATOR.addressForm(this.ui.$paymentForm); 792 //load countries 793 this.loadCountries(); 794 if (this.model.get('countryId') === '114' || this.model.get( 795 'countryId') === '17') { 796 this.ui.$addressSection.find('.form-group').show(); 797 } 798 $('.payment-form-container').show(); 799 $('.payments-loading-spinner').hide(); 800 }, 801 onChangeSubscriptionTerm: function (e) { 802 var $radioBtn = $(e.target); 803 var lengthInMonth = Number($radioBtn.attr('data-length')); 804 this.model.set('newSubscriptionTermId', Number($radioBtn.val())); 805 this.model.set('lengthInMonths', lengthInMonth); 806 807 getAmountDue(this.model.get('trialMode'), 808 this.model.get('newSubscriptionTermId'), 809 this.model.get('newSubscrTypeId'), 810 this.model.get('numNewUpgrades'), 811 this.model.get('validatedAddresses')[e.target.value] 812 ).then(function (response) { 813 getAmountDueCallback(this.model, response.data); 814 this.customRender.call(this); 815 }.bind(this)); 816 }, 817 customRender: function () { 818 var textEl = $($.parseHTML(this.template( 819 _.assign(this.model.toJSON(), this.templateHelpers())))[0]).find('.payment-info--mobile'); 820 $(this.$el).find('.payment-info--mobile').replaceWith(textEl); 821 }, 822 onInputFocus: function (e) { 823 $(e.target).closest('.form-group').addClass('focused'); 824 }, 825 onInputBlur: function (e) { 826 $(e.target).closest('.form-group').removeClass('focused'); 827 }, 828 onInput: function (e) { 829 this.triggerMethod('form:change'); 830 }, 831 onChangeCountry: function (e) { 832 var countryCode = $(e.target).find('option:selected').attr( 833 'data-code'); 834 if (countryCode === "US" || countryCode === "CA") { 835 this.ui.$addressSection.find('.form-group').show(); 836 } else { 837 this.ui.$addressSection.find('.form-group').hide(); 838 this.ui.$addressSection.find( 839 '.form-group.country-group, .form-group.zip-code').show(); 840 } 841 this.triggerMethod('form:change'); 842 }, 843 loadCountries: function () { 844 if (this.countriesList) { 845 this.populateCountriesList(this.countriesList); 846 return; 847 } 848 if (this.xhr && this.xhr.readyState === 1) return; 849 this.xhr = $.get('/iris/countries', function (response) { 850 if (response) { 851 this.countriesList = response; 852 this.triggerMethod('countriesList:get', response); 853 this.populateCountriesList(response); 854 } 855 }.bind(this)) 856 }, 857 populateCountriesList: function (countries) { 858 var $selectEl = this.ui.$country; 859 var countryId = this.model.get('countryId'); 860 $selectEl.append('<option></option>'); 861 _.forEach(countries, function (country) { 862 $selectEl.append('<option data-code="' + 863 country.iso2Code + '" value="' + country.countryId + 864 '">' + country.countryName + '</option>') 865 }); 866 if (this.model.get('countryId')) { 867 $selectEl.val(this.model.get('countryId')); 868 $selectEl.find('option[value=' + countryId + ']').attr('selected', 869 true); 870 } 871 $selectEl.combobox(); 872 var countryCode = $selectEl.find('option[value=' + countryId + ']').attr('data-code'); 873 if (countryCode === "US" || countryCode === "CA") { 874 this.ui.$addressSection.find('.form-group').show(); 875 } else { 876 this.ui.$addressSection.find('.form-group').hide(); 877 this.ui.$addressSection.find( 878 '.form-group.country-group, .form-group.zip-code').show(); 879 } 880 //$selectEl.trigger('select'); 881 setTimeout(function () { 882 this.ui.$countryInput.autocomplete("enable"); 883 }.bind(this)); 884 }, 885 onCountryKeyPress: function (e) { 886 if (e.which == 13) { 887 this.ui.$countryInput.blur() 888 } 889 }, 890 onBlurCountryInput: function (e) { 891 var val = $(e.target).val(); 892 if (val) { 893 var startsWithMatcher = new RegExp("^" + val, "i"), 894 option = this.ui.$country.children("option").filter(function(i, elem) { 895 return startsWithMatcher.test(elem.label || elem.value || elem); 896 }).first() 897 option.attr('selected', true); 898 this.ui.$countryInput.val(option.text()); 899 } 900 if (!Utils.isIE()) { 901 $('.ui-menu:not(:hidden) .ui-menu-item-wrapper').first().click(); 902 } 903 if (this.oFormValidator.element(this.ui.$countryInput)) { 904 this.ui.$combobox.find('.help-block').remove(); 905 } 906 }, 907 onBlurCouponCodeInput: function (e) { 908 if (e.target.value === "") { 909 this.oFormValidator.element(this.ui.$couponCode); 910 } 911 }, 912 validateAddress: function () { 913 if (this.oFormValidator.form()) { 914 this.triggerMethod('processing:start'); 915 this.$loadingIcon = $('.loading-icon'); 916 this.ui.$paymentError.html(""); 917 this.ui.$continuePurchase.prop('disabled', true); 918 this.$loadingIcon.show(); 919 var self = this; 920 var countryId = this.ui.$country.val(); 921 var $selectedOption = this.ui.$country.find('option[value="' + 922 countryId + '"]'); 923 if (!$selectedOption.length) { 924 this.oFormValidator.showErrors({ 925 country: "<span data-l10n-id='country_select_required'></span>" 926 }); 927 this.ui.$continuePurchase.prop('disabled', false); 928 return; 929 } 930 var countryCode = $selectedOption.attr('data-code'); 931 this.model.set('countryId', countryId); 932 this.model.set('countryCode', countryCode); 933 this.model.set('countryName', $selectedOption.text()); 934 this.model.set('address1', this.ui.$address1.val()); 935 this.model.set('city', this.ui.$city.val()); 936 this.model.set('state', this.ui.$state.val()); 937 this.model.set('zipCode', this.ui.$zip.val()); 938 this.model.set('couponCode', this.ui.$couponCode.val()); 939 940 var billingAddress = { 941 countryCode: countryCode, 942 zipCode: this.model.get('zipCode') 943 }; 944 945 var url = '/accountSubscription/validateAddress'; 946 947 // if (this.model.get('standalone')) { 948 // url = '/deviceSubscription/validateAddress'; 949 // var $submitBtn = $('#submit') 950 // var $loadingIcon = $('.loading-icon'); 951 // $submitBtn.prop('disabled', 'disabled'); 952 // $loadingIcon.show(); 953 // } 954 955 self.ui.$invalidAddress.hide(); 956 957 if (countryCode === 'US' || countryCode === 'CA') { 958 billingAddress.address1 = this.model.get('address1'); 959 billingAddress.city = this.model.get('city'); 960 billingAddress.state = this.model.get('state'); 961 962 $.ajax({ 963 type: "POST", 964 url: url, 965 contentType: 'application/json', 966 data: JSON.stringify(billingAddress), 967 success: function (response) { 968 if (response.data) { 969 if (response.data.length > 0) { 970 self.model.set('validatedAddresses', response.data);
971 self.triggerMethod('confirm-address:render', self.model.attributes); 972 } 973 } else if (response.error) { 974 var errorObj; 975 try { 976 errorObj = JSON.parse(response.error.errorMessage); 977 } catch (e) { 978 errorObj = response.error.errorMessage; 979 } 980 981 if(errorObj === 'INVALID_ADDRESS' || errorObj.error === 'INVALID_ADDRESS' || errorObj.error.errorMessage === 'INVALID_ADDRESS'){ 982 self.ui.$invalidAddress.show(); 983 }else{ 984 self.ui.$paymentError.html(errorObj.error && errorObj.error 985 .message || errorObj); 986 } 987 self.ui.$continuePurchase.prop('disabled', false); 988 self.triggerMethod('processing:stop'); 989 self.$loadingIcon.hide(); 990 } 991 }, 992 error: function (response) { 993 console.log(response); 994 } 995 }) 996 } else { //not us or canada 997 this.model.set('validatedAddresses', [billingAddress]); 998 this.triggerMethod('confirm-address:render', this.model.attributes); 999 } 1000 } 1001 }, 1002 onClickContinue: function () { 1003 var self = this; 1004 var couponCode = this.ui.$couponCode.val(); 1005 if (couponCode) { 1006 self.ui.$paymentError.html(''); 1007 $.ajax({ 1008 type: 'POST', 1009 url: '/accountSubscription/applyCouponCode', 1010 data: {couponCode: couponCode}, 1011 success: function (res) { 1012 if (res.data) { 1013 self.validateAddress(); 1014 } else if (res.error) { 1015 self.ui.$paymentError.html(res.error.errorMessage); 1016 } 1017 }, 1018 error: function (err) { 1019 self.ui.$paymentError.html(err.responseText); 1020 } 1021 }); 1022 } else { 1023 this.validateAddress(); 1024 } 1025 }, 1026 1027 onClickContinueWithInvalidAddress : function(){ 1028 var countryId = this.ui.$country.val(); 1029 var $selectedOption = this.ui.$country.find('option[value="' + 1030 countryId + '"]'); 1031 var countryCode = $selectedOption.attr('data-code'); 1032 var billingAddress = { 1033 countryCode: countryCode, 1034 zipCode: this.model.get('zipCode') 1035 }; 1036 1037 if (countryCode === 'US' || countryCode === 'CA') { 1038 billingAddress.address1 = this.model.get('address1'); 1039 billingAddress.city = this.model.get('city'); 1040 billingAddress.state = this.model.get('state'); 1041 } 1042 1043 //special indicator to avalara to use zip code for taxation purposes as exact 1044 //street address is not found in Avalara 1045 billingAddress.address2 = "Local Delivery"; 1046 this.model.set('validatedAddresses', [billingAddress]); 1047 this.triggerMethod('confirm-address:render', this.model.attributes); 1048 }, 1049 1050 onClickBackBtn: function () { 1051 if (this.options.upgrade) { 1052 window.location.href = '/bulletin'; 1053 return; 1054 } 1055 if (!this.model.get('existingUpgrades') && !this.model.get('newUpgradesAdjustmentAmount')) { 1056 this.triggerMethod('subscription-select:render'); 1057 } else { 1058 this.triggerMethod('detectedUpgradesOrPaymentForm:render'); 1059 } 1060 }, 1061 onDestroy: function () { 1062 this.off('external:validate-address'); 1063 } 1064 }); 1065 1066 oPayments.PaymentFormView = Marionette.ItemView.extend({ 1067 template: window.tpl['payment-form'], 1068 model: oPayments.sharedModel, 1069 initialize: function (options) { 1070 wl.app.stripe = Stripe(wl.stripePublisherKey); 1071 if (options.model) { 1072 this.model = new PaymentModel( 1073 _.assign(oPayments.sharedModel.attributes, options.model.attributes)); 1074 } 1075 if (options.standalone) { 1076 this.model.set('standalone', options.standalone) 1077 } 1078 }, 1079 ui: { 1080 $paymentForm: '#payment-form', 1081 $paymentError: '.payment-error', 1082 $formInput: '.payment-form input', 1083 $useSavedLink: '.use-saved, .use-saved--mobile', 1084 $enterNewCardLink: '.saved-card-link', 1085 $cardNumber: '#accountCardNumber', 1086 $cardExp: '#accountCardExpiration', 1087 $cardCvc: '#accountCardCvc', 1088 $couponCode: '#couponCode', 1089 $couponRow: '#couponRow', 1090 $newCardBlocks: '#payment-form-buttons, ' + 1091 '.credit-card-section, .use-saved, .use-saved--mobile', 1092 $savedCardBlocks: '#saved-card-buttons, #saved-card', 1093 $subscriptionTermRadio: 'input[name="subscriptionTerm"]', 1094 $submitPaymentBtn: '.submitPayment', 1095 $paymentProcessing: '#paymentProcessing', 1096 submit: '.submitPayment', 1097 errorBlock: '.payment-error', 1098 loadingIcon: '.loading-icon' 1099 }, 1100 events: { 1101 "blur @ui.$couponCode": "onBlurCouponCodeInput", 1102 "click @ui.$useSavedLink": "showSavedCard", 1103 "click @ui.$enterNewCardLink": "showPaymentForm", 1104 "click button#submitPayment": "submitPaymentForm", 1105 "click button#submitPaymentSaved": "submitPaymentFormSaved", 1106 "click button#payment-back, button#payment-back-saved": "onClickBackBtn", 1107 }, 1108 templateHelpers: function () { 1109 return { 1110 getTermTranslationKey: function (name) { 1111 return _getTermTranslationKey(name); 1112 }, 1113 upgrade: this.options.upgrade 1114 } 1115 }, 1116 onRender: function () { 1117 $.validator.setDefaults({ 1118 ignore: ":hidden:not(.not-masked)" 1119 }); 1120 if (this.model.get('paymentDetails') && this.model.get('stripePaymentMethodId') 1121 && this.model.get('useSavedCard')) { 1122 this.showSavedCard(); 1123 } else {
1124 this.showPaymentForm(); 1125 } 1126 $('.payment-form-container').show(); 1127 $('.payments-loading-spinner').hide(); 1128 }, 1129 onShow: function () { 1130 initializeStripeElements(this); 1131 }, 1132 showSavedCard: function () { 1133 this.ui.$newCardBlocks.hide(); 1134 this.ui.$savedCardBlocks.show(); 1135 this.model.set('useSavedCard', true); 1136 this.triggerMethod('useSavedCardOption:change', true); 1137 }, 1138 showPaymentForm: function () { 1139 this.ui.$newCardBlocks.show(); 1140 this.ui.$savedCardBlocks.hide(); 1141 this.model.set('useSavedCard', false); 1142 this.triggerMethod('useSavedCardOption:change', false); 1143 }, 1144 getSetupIntent: function () { 1145 var d = $.Deferred(); 1146 $.ajax({ 1147 type: 'GET', 1148 url: '/accountSubscription/setupIntent', 1149 success: function (response) { 1150 d.resolve(response); 1151 }, 1152 error: function (err) { 1153 d.resolve(null); 1154 } 1155 }); 1156 return d.promise(); 1157 }, 1158 setupCardPaymentMethod: function (stripePaymentMethodId, isTrial, zeroAmount) { //used for trial and amount = 0 1159 var self = this;
1160 this.getSetupIntent().then(function(response) { 1161 if (response && response.data) { 1162 console.log(`got payment intent ${response}`); 1163 self.clientSecret = response.data.clientSecret; 1164 self.setupIntent = response.data.setupIntent; 1165 wl.app.stripe.confirmCardSetup(self.clientSecret, { 1166 payment_method: stripePaymentMethodId ? stripePaymentMethodId : { 1167 card: self.cardNumber 1168 } 1169 }).then(function (result) { 1170 // Handle result.error or result.setupIntent 1171 if (result.setupIntent) { 1172 self.model.set('stripePaymentMethodId', result.setupIntent.payment_method); 1173 self.postPayment(isTrial, zeroAmount); 1174 } else if (result.error) { 1175 self.ui.$paymentError.html(result.error.message); 1176 self.ui.$submitPaymentBtn.prop('disabled', false); 1177 self.ui.loadingIcon.hide(); 1178 self.ui.$paymentProcessing.hide(); 1179 } 1180 }); 1181 } 1182 }); 1183 }, 1184 payWithCard: function (stripePaymentMethodId) { 1185 this.ui.$paymentError.html(""); 1186 // Disable the submit button to prevent repeated clicks: 1187 this.ui.$submitPaymentBtn.prop('disabled', true); 1188 this.ui.$paymentProcessing.show(); 1189 this.ui.loadingIcon.show(); 1190 var clientSecret = this.model.get('clientSecret'); 1191 var card = this.cardNumber; 1192 if (this.model.get('trialMode')) { 1193 this.setupCardPaymentMethod(stripePaymentMethodId, true); 1194 } else if (clientSecret) { // amount > 0 1195 wl.app.stripe 1196 .confirmCardPayment(clientSecret, { 1197 payment_method: stripePaymentMethodId ? stripePaymentMethodId : { 1198 card: card 1199 } 1200 }) 1201 .then(function (result) { 1202 if (result.error) { 1203 // Show error to your customer 1204 //showError(result.error.message); 1205 console.log(result.error.message); 1206 this.ui.$paymentError.html(result.error.message); 1207 this.ui.$submitPaymentBtn.prop('disabled', false); 1208 this.ui.loadingIcon.hide(); 1209 this.ui.$paymentProcessing.hide(); 1210 } else if (result.paymentIntent) { 1211 // The payment succeeded! 1212 this.model.set('stripePaymentMethodId', result.paymentIntent.payment_method); 1213 this.model.set('paymentIntentId', result.paymentIntent.id); 1214 if (this.model.get('renewal')) { 1215 this.renewSubscription(); 1216 } else { 1217 this.postPayment(); 1218 } 1219 console.log(`stripe response ${JSON.stringify(result)}` ) 1220 console.log("payment success") 1221 } 1222 }.bind(this)); 1223 } else { //amount is 0 due to coupon code 1224 this.setupCardPaymentMethod(stripePaymentMethodId, false, true); 1225 } 1226 }, 1227 onBlurCouponCodeInput: function (e) { 1228 if (e.target.value === "") { 1229 this.oFormValidator.element(this.ui.$couponCode); 1230 } 1231 }, 1232 submitPaymentForm: function () { 1233 this.payWithCard(); 1234 return false; 1235 }, 1236 submitPaymentFormSaved: function () { 1237 this.payWithCard(this.model.get('stripePaymentMethodId')); 1238 return false; 1239 }, 1240 postPayment: function (isTrial, zeroAmount) { // coupon code 1241 var url = isTrial ? '/accountSubscription/postTrialSubscription' : 1242 '/accountSubscription/postPayment/' + this.model.get('paymentIntentId'); 1243 if (zeroAmount) { 1244 url = '/accountSubscription/postPayment'; 1245 } 1246 var self = this; 1247 var data = { 1248 numNewUpgrades: this.model.get('numNewUpgrades'), 1249 newSubscriptionTermId: this.model.get('newSubscriptionTermId'), 1250 newSubscriptionType: this.model.get('newSubscrTypeId'), 1251 isTrial: this.model.get('trialMode'), 1252 billingAddress: this.model.get('validatedAddresses')[0], 1253 paymentMethodId: this.model.get('stripePaymentMethodId') 1254 }; 1255 if (this.model.get('couponCode')) { 1256 data.couponCode = this.model.get('couponCode'); 1257 } 1258 $.ajax({ 1259 type: "POST", 1260 url: url, 1261 contentType: 'application/json', 1262 data: JSON.stringify(data), 1263 success: function (response) { 1264 if (response.data) { 1265 console.log(response.data); 1266 onPaymentSuccess.call(self, response); 1267 } else if (response.error) { 1268 self.ui.$paymentError.html(response.error.errorDetail || response.error.errorMessage); 1269 self.ui.$submitPaymentBtn.prop('disabled', false); 1270 self.ui.$paymentProcessing.hide(); 1271 } 1272 }, 1273 error: function (err) { 1274 self.ui.$paymentError.html(err.responseText); 1275 self.ui.$submitPaymentBtn.prop('disabled', false); 1276 self.ui.$paymentProcessing.hide(); 1277 } 1278 }); 1279 }, 1280 renewSubscription: function () { 1281 var self = this; 1282 $.ajax({ 1283 type: "GET", 1284 url: '/accountSubscription/renewSubscription/' + this.model.get('paymentIntentId'), 1285 success: function (response) { 1286 if (response) { 1287 console.log(response); 1288 self.triggerMethod('renewal-success:render'); 1289 } else if (response.error) { 1290 self.ui.$paymentError.html(response.error.errorDetail || response.error.errorMessage); 1291 self.ui.$submitPaymentBtn.prop('disabled', false); 1292 self.ui.$paymentProcessing.hide(); 1293 } 1294 }, 1295 error: function (err) { 1296 self.ui.$paymentError.html(err.responseText); 1297 self.ui.$submitPaymentBtn.prop('disabled', false); 1298 self.ui.$paymentProcessing.hide(); 1299 } 1300 }); 1301 }, 1302 onClickBackBtn: function () { 1303 if (this.options.upgrade || this.model.get('renewal')) { 1304 window.location.href = '/bulletin'; 1305 return; 1306 } 1307 if (this.model.get('taxDue') && this.model.get('totalAmountDue')) { 1308 var amountDue = this.model.get('totalAmountDue') - this.model.get('taxDue'); 1309 this.model.set('totalAmountDue', amountDue.toFixed(2)); 1310 } 1311 this.model.set('totalAmountCustomerCurrency', null); 1312 this.model.set('beforeTax', true);
1313 this.triggerMethod('confirm-address:render', this.model.attributes); 1314 this.triggerMethod('external:confirm-address:render', this.model.attributes); 1315 } 1316 }); 1317 1318 //account and mobile card details 1319 oPayments.CardDetailsFormView = oPayments.BillingAddressView.extend({ 1320 template: window.tpl['card-details-form'], 1321 ui: _.extend({}, oPayments.BillingAddressView.prototype.ui, { 1322 $useSavedLink: '.use-saved, .use-saved--mobile', 1323 $enterNewCardLink: '.saved-card-link', 1324 $cardNumber: '#accountCardNumber', 1325 $cardExp: '#accountCardExpiration', 1326 $cardCvc: '#accountCardCvc', 1327 $newCardBlocks: '#payment-form-buttons, ' + 1328 '.credit-card-section, .use-saved, .use-saved--mobile', 1329 $savedCardBlocks: '#saved-card-buttons, #saved-card', 1330 }), 1331 events: { 1332 "focus @ui.$formInput": "onInputFocus", 1333 "input @ui.$formInput": "onInput", 1334 "blur @ui.$formInput": "onInputBlur", 1335 "blur @ui.$countryInput": "onBlurCountryInput", 1336 "select @ui.$country": "onChangeCountry", 1337 "keypress @ui.$countryInput": "onCountryKeyPress", 1338 "click @ui.$useSavedLink": "showSavedCard", 1339 "click @ui.$enterNewCardLink": "showPaymentForm", 1340 "click @ui.$continueWithInvalidAddress": "continueWithInvalidAddress", 1341 }, 1342 initialize: function (options) { 1343 if (this.options.stripeKey) { 1344 wl.app.stripe = Stripe(this.options.stripeKey); 1345 } 1346 if (options.model) { 1347 this.model = new Backbone.Model(options.model.attributes); 1348 } 1349 if (options.standalone) { 1350 this.model.set('standalone', options.standalone) 1351 } 1352 this.on('external:save-card-details', this.saveCardDetails.bind(this)); 1353 }, 1354 onRender: function () { 1355 $.validator.setDefaults({ 1356 ignore: ":hidden:not(.not-masked)" 1357 }); 1358 this.oFormValidator = FORM_VALIDATOR.addressForm(this.ui.$paymentForm); 1359 this.loadSetupIntent(); 1360 if (this.model.get('paymentDetails') && this.model.get('stripePaymentMethodId') 1361 && this.model.get('useSavedCard')) { 1362 this.showSavedCard(); 1363 } else { 1364 this.showPaymentForm(); 1365 } 1366 //load countries 1367 this.loadCountries(); 1368 if (this.model.get('countryId') === '114' || this.model.get( 1369 'countryId') === '17') { 1370 this.ui.$addressSection.find('.form-group').show(); 1371 } 1372 //setup external ui elements 1373 this.$submitBtn = $('#submit'); 1374 this.$loadingIcon = $('.loading-icon'); 1375 this.$cardSavedMsg = $('.credit-card-saved-msg'); 1376 1377 setTimeout(function () { 1378 initializeStripeElements(this); 1379 console.log("initialized card element"); 1380 }.bind(this), 100); 1381 }, 1382 showSavedCard: function () { 1383 this.ui.$newCardBlocks.hide(); 1384 this.ui.$savedCardBlocks.show(); 1385 this.model.set('useSavedCard', true); 1386 this.triggerMethod('useSavedCardOption:change', true); 1387 }, 1388 showPaymentForm: function () { 1389 this.ui.$newCardBlocks.show(); 1390 this.ui.$savedCardBlocks.hide(); 1391 this.model.set('useSavedCard', false); 1392 this.triggerMethod('useSavedCardOption:change', false); 1393 }, 1394 loadSetupIntent: function () { 1395 $.get('/accountSubscription/setupIntent', function (response) { 1396 if (response && response.data) { 1397 console.log(`got payment intent ${response}`); 1398 this.clientSecret = response.data.clientSecret; 1399 this.setupIntent = response.data.setupIntent; 1400 this.$submitBtn.prop('disabled', false); 1401 this.$loadingIcon.hide(); 1402 } 1403 }.bind(this)) 1404 }, 1405 confirmCardSetup: function (bypassAddressValidation) { 1406 var self = this; 1407 var countryCode = this.model.get('countryCode'); 1408 var billingAddress = { 1409 countryCode: countryCode, 1410 zipCode: this.model.get('zipCode') 1411 }; 1412 1413 if (countryCode === 'US' || countryCode === 'CA') { 1414 billingAddress.address1 = this.model.get('address1'); 1415 billingAddress.city = this.model.get('city'); 1416 billingAddress.state = this.model.get('state'); 1417 if(bypassAddressValidation){ 1418 billingAddress.address2 = "Local Delivery"; 1419 } 1420 } 1421 1422 if (this.model.get('useSavedCard') && this.model.get('paymentDetails') 1423 && this.model.get('stripePaymentMethodId')) { 1424 this.processSavePaymentMethod(this.model.get('paymentDetails').stripePaymentMethodId, billingAddress); 1425 } else { 1426 var d = $.Deferred(); 1427 //we already have a saved Payment method from prior success and we are in "continueWithBadAddress" mode 1428 if(self.savedPaymentMethod){ 1429 d.resolve(self.savedPaymentMethod); 1430 }else{ 1431 wl.app.stripe.confirmCardSetup(this.clientSecret, { 1432 payment_method: { 1433 card: this.cardNumber 1434 } 1435 }).then(function(result){ 1436 if (result.setupIntent) { 1437 self.savedPaymentMethod = result.setupIntent.payment_method; 1438 d.resolve(result.setupIntent.payment_method); 1439 } else if (result.error) { 1440 self.ui.$paymentError.html(result.error.message); 1441 self.$submitBtn.prop('disabled', false); 1442 self.$loadingIcon.hide(); 1443 } 1444 }); 1445 } 1446 1447 d.promise().then(function(payment_method){ 1448 self.processSavePaymentMethod(payment_method, billingAddress); 1449 1450 // Handle result.error or result.setupIntent 1451 }.bind(this)); 1452 } 1453 }, 1454 continueWithInvalidAddress: function(){ 1455 this.confirmCardSetup(true); 1456 }, 1457 processSavePaymentMethod: function (paymentMethodId, billingAddress) { 1458 var self = this; 1459 self.ui.$invalidAddress.hide(); 1460 $.ajax({ 1461 type: "POST", 1462 url: '/accountSubscription/savePaymentMethod?paymentMethodId=' 1463 + paymentMethodId, 1464 contentType: 'application/json', 1465 data: JSON.stringify(billingAddress), 1466 success: function (response) { 1467 if (response.error) { 1468 if(response.error.errorMessage === 'INVALID_ADDRESS'){ 1469 self.ui.$invalidAddress.show(); 1470 }else{ 1471 self.ui.$paymentError.html(response.error.errorMessage); 1472 } 1473 1474 if (self.$submitBtn && self.$loadingIcon) { 1475 self.$submitBtn.prop('disabled', false); 1476 self.$loadingIcon.hide(); 1477 } 1478 } else { 1479 if (!self.model.get('useSavedCard')) { 1480 // load new intent for next save calls 1481 self.loadSetupIntent(); 1482 self.model.set('paymentDetails', response); 1483 self.model.set('stripePaymentMethodId', response.stripePaymentMethodId); 1484 self.model.set('useSavedCard', true); 1485 self.render(); 1486 } else { 1487 self.$submitBtn.prop('disabled', false); 1488 self.$loadingIcon.hide(); 1489 } 1490 self.$cardSavedMsg.show(); 1491 setTimeout(function () { 1492 self.$cardSavedMsg.hide(); 1493 }, 3000);
1494 self.triggerMethod('cardDetails:saved'); 1495 } 1496 }, 1497 error: function (response) { 1498 console.log(response); 1499 } 1500 }); 1501 }, 1502 saveCardDetails: function () { 1503 if (this.oFormValidator.form()) { 1504 this.ui.$paymentError.html(""); 1505 var countryId = this.ui.$country.val(); 1506 var $selectedOption = this.ui.$country.find('option[value="' + 1507 countryId + '"]'); 1508 if (!$selectedOption.length) { 1509 this.oFormValidator.showErrors({ 1510 country: "<span data-l10n-id='country_select_required'></span>" 1511 }); 1512 return; 1513 } 1514 var countryCode = $selectedOption.attr('data-code'); 1515 this.model.set('countryId', countryId); 1516 this.model.set('countryCode', countryCode); 1517 this.model.set('countryName', $selectedOption.text()); 1518 this.model.set('address1', this.ui.$address1.val()); 1519 this.model.set('city', this.ui.$city.val()); 1520 this.model.set('state', this.ui.$state.val()); 1521 this.model.set('zipCode', this.ui.$zip.val()); 1522 1523 this.$submitBtn.prop('disabled', 'disabled'); 1524 this.$loadingIcon.show(); 1525 1526 this.confirmCardSetup(); 1527 } 1528 }, 1529 onDestroy: function () { 1530 this.off('external:save-card-details'); 1531 } 1532 }); 1533 1534 oPayments.ConfirmAddressView = Marionette.ItemView.extend({ 1535 template: window.tpl['confirm-address'], 1536 model: oPayments.sharedModel, 1537 ui: { 1538 $confirmAddressBtn: '#confirmAddressBtn, #submit', 1539 $confirmedAddressRadio: 'input[name="confirmed_address"]', 1540 $paymentError: '.payment-error', 1541 $backBtn: '#payment-back, #back', 1542 $loadingIcon: '.loading-icon' 1543 }, 1544 events: { 1545 'click @ui.$confirmAddressBtn': 'onClickConfirmAddress', 1546 'change @ui.$confirmedAddressRadio': 'onChangeConfirmedAddress', 1547 'click @ui.$backBtn': 'onClickBack' 1548 }, 1549 onChangeConfirmedAddress: function (e) { 1550 var selectedIndex = e.target.value; 1551 this.model.set('selectedAddressIndex', selectedIndex); 1552 }, 1553 onClickConfirmAddress: function () { 1554 if (this.model.get('standalone')) { 1555 this.getAmountWithTaxByOrderId.call(this); 1556 } else { 1557 this.getAmountDueWithTax.call(this); 1558 } 1559 }, 1560 getAmountDueWithTax: function () { 1561 this.ui.$confirmAddressBtn.prop('disabled', true); 1562 this.ui.$loadingIcon.show(); 1563 getAmountDue( 1564 this.model.get('trialMode'), 1565 this.model.get('newSubscriptionTermId'), 1566 this.model.get('newSubscrTypeId'), 1567 this.model.get('numNewUpgrades'), 1568 this.model.get('validatedAddresses')[this.model.get('selectedAddressIndex')], 1569 this.model.get('couponCode'), 1570 ).then(function (response) { 1571 if (response.data) { 1572 getAmountDueCallback(this.model, response.data); 1573 this.model.set('beforeTax', false); 1574 //when coupon code field is not empty 1575 if (this.model.get('couponCode') && response.data.couponDiscount == null) { 1576 this.ui.$paymentError.html("<span data-l10n-id='invalid_coupon_code'></span>"); 1577 this.ui.$confirmAddressBtn.prop('disabled', false); 1578 this.ui.$loadingIcon.hide(); 1579 } else { 1580 this.triggerMethod('paymentForm:render'); 1581 } 1582 //show confirm address and taxes 1583 } else if (response.error) { 1584 this.ui.$paymentError.html(response.error.errorMessage); 1585 this.ui.$confirmAddressBtn.prop('disabled', false); 1586 this.ui.$loadingIcon.hide(); 1587 console.log(response); 1588 } 1589 }.bind(this)); 1590 }, 1591 getAmountWithTaxByOrderId: function () { 1592 this.ui.$paymentError.text(''); 1593 this.ui.$confirmAddressBtn.prop('disabled', 'disabled'); 1594 this.ui.$loadingIcon.show(); 1595 var data = { 1596 orderId: this.model.get('orderId'), 1597 billingAddressInfo: this.model.get('validatedAddresses')[this.model.get('selectedAddressIndex')] 1598 } 1599 if (this.model.get('paymentDetails')) { 1600 data.cardProfileId = this.model.get('paymentDetails').id; 1601 } 1602 getTaxAmount(data); 1603 var self = this; 1604 function getTaxAmount(data) { 1605 $.ajax({ 1606 type: 'POST', 1607 contentType: 'application/json', 1608 data: JSON.stringify(data), 1609 url: '/deviceSubscription/amountDueWithTaxes', 1610 success: function (response) { 1611 console.log(response) 1612 if (response.data) { 1613 self.model.set('totalAmountDue', response.data.totalAmountDue); 1614 self.model.set('taxDue', response.data.taxDue); 1615 self.model.set('taxRate', response.data.appliedTaxRate); 1616 self.model.set('reactivationFeeDetail', response.data.reactivationFeeDetail); 1617 self.model.set('customerCurrency', response.data.customerCurrency); 1618 self.model.set('totalAmountCustomerCurrency', response.data.totalAmountCustomerCurrency); 1619 self.model.set('renewalDate', dayjs(response.data.subscriptionEndDate).format('ll')); 1620 self.model.set('paymentIntentId', response.data.paymentIntentId); 1621 self.model.set('clientSecret', response.data.clientSecret); 1622 self.triggerMethod('paymentForm:render', self.model.attributes); 1623 } else { 1624 self.ui.$paymentError.text(response.error.errorMessage); 1625 self.ui.$confirmAddressBtn.prop('disabled', false); 1626 self.ui.$loadingIcon.hide(); 1627 } 1628 }.bind(this), 1629 error: function (err) { 1630 self.ui.$confirmAddressBtn.prop('disabled', false); 1631 self.ui.$loadingIcon.hide(); 1632 console.log(err); 1633 } 1634 }); 1635 } 1636 }, 1637 onClickBack: function () { 1638 this.triggerMethod('billingAddress:render'); 1639 } 1640 }); 1641 1642 var PaymentSuccessView = Marionette.ItemView.extend({ 1643 template: window.tpl['payment-success'], 1644 model: oPayments.sharedModel, 1645 ui: { 1646 'gotIt': '#gotIt' 1647 }, 1648 events: { 1649 'click @ui.gotIt': 'onClickGotIt' 1650 }, 1651 templateHelpers: function () { 1652 return { 1653 isMobile: window.location.pathname.indexOf('mobile') !== -1 1654 } 1655 }, 1656 onClickGotIt: function () { 1657 if (window.location.pathname.indexOf('mobile') !== -1) { 1658 window.location.href = '/bulletin' 1659 } else { 1660 if(sessionStorage.getItem('showAddMoreSensors')) { 1661 sessionStorage.removeItem("showAddMoreSensors"); 1662 this.triggerMethod('addMoreSensors:render'); 1663 } else { 1664 window.location.href = '/bulletin' 1665 } 1666 } 1667 } 1668 }); 1669 1670 var ComparisonChartView = Marionette.ItemView.extend({ 1671 template: window.tpl['comparison-chart'], 1672 ui: { 1673 'featureRow': '.comparison-chart-feature-row:not(.empty)', 1674 'featureName': '.feature-name', 1675 'featureDesc': '.feature-desc', 1676 'close': 'button.btn-payment-primary', 1677 'historical_data_tooltip': '#historical-data-tooltip', 1678 'bulletin_tooltip': '#bulletin-tooltip', 1679 'map_tooltip': '#map-tooltip', 1680 'chart_tooltip': '#chart-tooltip', 1681 'data_tooltip': '#data-tooltip', 1682 'mobilize_tooltip': '#mobilize-tooltip', 1683 'ipm_tooltip': '#ipm-tooltip', 1684 'pro_shares_tooltip': '#pro-shares-tooltip', 1685 'third_party_intervals_tooltip': '#third-party-intervals-tooltip' 1686 }, 1687 events: { 1688 'click @ui.featureRow': 'onClickFeatureRow', 1689 'click @ui.close': 'onClickClose' 1690 }, 1691 onRender: function () { 1692 this.setTooltipTitles(); 1693 }, 1694 setTooltipTitles: function () { 1695 var self = this; 1696 var promises = []; 1697 var tooltipTranslationKeys = [ 1698 'historical_data_tooltip', 1699 'bulletin_tooltip', 1700 'map_tooltip', 1701 'chart_tooltip', 1702 'data_tooltip', 1703 'mobilize_tooltip', 1704 'ipm_tooltip', 1705 'pro_shares_tooltip', 1706 'third_party_intervals_tooltip' 1707 ]; 1708 _.each(tooltipTranslationKeys, function (key) { 1709 var prom = document.l10n.formatValue(key); 1710 promises.push(prom); 1711 }); 1712 Promise.all(promises).then(function (values) { 1713 _.forEach(values, function (value, i) { 1714 if (self.ui[tooltipTranslationKeys[i]]) { 1715 self.ui[tooltipTranslationKeys[i]].attr( 1716 'data-bs-original-title', 1717 '<div class="">' + 1718 values[i] + '</div>'); 1719 self.ui[tooltipTranslationKeys[i]].tooltip(); 1720 $('.tooltip:visible').hide(); 1721 } 1722 }); 1723 }); 1724 }, 1725 onClickFeatureRow: function (e) { 1726 this.ui.featureRow.removeClass('selected'); 1727 var row = $(e.target); 1728 if (e.target !== e.currentTarget) { 1729 row = $(e.target).closest('.comparison-chart-feature-row') 1730 } 1731 1732 row.addClass('selected'); 1733 var featureDesc = row.find('.icon-faq').attr('data-bs-original-title'); 1734 var featureName = row.find('span').text(); 1735 this.ui.featureName.text(featureName); 1736 this.ui.featureDesc.html(featureDesc); 1737 }, 1738 onClickClose: function () { 1739 this.triggerMethod('subscription-select:render'); 1740 } 1741 }); 1742 1743 var ConnectionIssueView = Marionette.ItemView.extend({ 1744 template: window.tpl['connection-issue'], 1745 ui: { 1746 retry: '#connection-issue__retry' 1747 }, 1748 events: { 1749 'click @ui.retry': 'onClickRetry' 1750 }, 1751 onClickRetry: function () { 1752 if (navigator.onLine) { 1753 $('#connection-issue').empty(); 1754 $('.btn-payment-primary').prop('disabled', false); 1755 } 1756 } 1757 }); 1758 1759 oPayments.AddMoreSensorsView = Marionette.ItemView.extend({ 1760 template: window.tpl['add-more-sensors'], 1761 ui: { 1762 'submit': '#submit', 1763 'finish': '#back' 1764 }, 1765 events: { 1766 'click @ui.submit': 'onClickAddMore', 1767 'click @ui.finish': 'onClickFinish' 1768 }, 1769 initialize: function (options) { 1770 }, 1771 onClickAddMore: function () { 1772 sessionStorage.setItem("loadDeviceConfig", true); 1773 var identifier = this.options.deviceIdentifier || wl.deviceIdentifier || wl.lastViewedSystemId; 1774 1775 window.location.replace( 1776 "/manageDevices/enviroMonitorConfiguration/" + identifier 1777 ); 1778 }, 1779 onClickFinish: function () { 1780 window.location.href = '/bulletin/' + this.options.deviceIdentifier; 1781 } 1782 }); 1783 1784 function onPaymentSuccess(response) { 1785 console.log("response success"); 1786 console.log(response); 1787 if (response.data) { 1788 this.triggerMethod('payment-success:render');
1789 if (this.model.get('trialMode')) { 1790 gtag('event', 'proTrialUpgrade'); 1791 } else { 1792 gtag('event', 'proUpgrade'); 1793 } 1794 } else if (response.error) { 1795 this.ui.$paymentError.html(response.error.errorDetail || response.error.errorMessage); 1796 this.ui.$submitPaymentBtn.prop('disabled', false); 1797 } 1798 $('#paymentProcessing').hide(); 1799 } 1800 1801 function getAmountDue(isTrial, newSubscriptionTermId, subscrTypeId, 1802 numNewUpgrades, billingAddress, couponCode) { 1803 var d = $.Deferred(); 1804 var url = "/accountSubscription/amountDue"; 1805 var data = { 1806 numNewUpgrades: numNewUpgrades, 1807 newSubscriptionTermId: newSubscriptionTermId, 1808 newSubscriptionType: subscrTypeId, 1809 isTrial: isTrial 1810 }; 1811 1812 if (couponCode) { 1813 data.couponCode = couponCode; 1814 } 1815 1816 if (billingAddress) { 1817 data.billingAddress = billingAddress; 1818 url = "/accountSubscription/amountDueWithTaxes"; 1819 } 1820 $.ajax({ 1821 type: "POST", 1822 contentType: 'application/json', 1823 data: JSON.stringify(data), 1824 url: url, 1825 success: function (response) { 1826 d.resolve(response); 1827 }, 1828 error: function (err) { 1829 console.log(err); 1830 } 1831 }); 1832 return d.promise(); 1833 } 1834 1835 function getAmountDueCallback(model, data) { 1836 var totalAmountDue = data.totalAmountDue.toFixed(2); 1837 var newUgradesAmountDue = data.newUgradesAmountDue.toFixed(2); 1838 var existingUpgradesAmountDue = data.existingUpgradesAmountDue.toFixed(2); 1839 var subscrPricePerMonth = (totalAmountDue / model.get('lengthInMonths')).toFixed( 1840 2); 1841 var taxDue = data.taxDue ? data.taxDue.toFixed(2) : 0; 1842 var couponDiscount = data.couponDiscount ? data.couponDiscount.toFixed(2) : 0; 1843 var newUpgradesAdjustmentAmount = data.newUpgradesAdjustmentAmount ? 1844 data.newUpgradesAdjustmentAmount.toFixed(2) : 0; 1845 1846 model.set('totalAmountDue', totalAmountDue); 1847 model.set('newUgradesAmountDue', newUgradesAmountDue); 1848 model.set('existingUpgradesAmountDue', existingUpgradesAmountDue); 1849 model.set('subscrPricePerMonth', subscrPricePerMonth); 1850 model.set('taxDue', taxDue); 1851 model.set('taxRate', data.appliedTaxRate); 1852 model.set('couponDiscount', couponDiscount); 1853 model.set('newUpgradesAdjustmentAmount', newUpgradesAdjustmentAmount); 1854 model.set('upgradeType', data.upgradeType); 1855 model.set('expDate', dayjs(data.subscriptionEndDate).format('MMM D YYYY')); 1856 model.set('appliedTaxRate', data.appliedTaxRate); 1857 model.set('customerCurrency', data.customerCurrency); 1858 model.set('totalAmountCustomerCurrency', data.totalAmountCustomerCurrency); 1859 model.set('paymentIntentId', data.paymentIntentId); 1860 model.set('clientSecret', data.clientSecret); 1861 } 1862 1863 function makeChangesToUrl(upgradeSystemId, newArchivalRate, newSubscrTypeId, trialMode) { 1864 window.history.pushState("", "", window.location.pathname + 1865 '#makePayment/' + upgradeSystemId + '/' + 1866 newArchivalRate + '/' + trialMode + '/' + 1867 (newSubscrTypeId === 2 ? 'Pro' : 'ProPlus')); 1868 } 1869 1870 function showConnectionIssue() { 1871 var connectionIssueView = new ConnectionIssueView(); 1872 connectionIssueView.render(); 1873 $('#connection-issue').append(connectionIssueView.$el); 1874 } 1875 1876 function _getTermTranslationKey(name) { 1877 if (name.indexOf('1') !== -1) { 1878 return '<span data-l10n-id="year_1"></span>' 1879 } 1880 if (name.indexOf('3') !== -1) { 1881 return '<span data-l10n-id="year_3"></span>' 1882 } 1883 return name; 1884 } 1885 1886 function initializeStripeElements(view) { 1887 var elementStyles = { 1888 base: { 1889 color: '#3c464d', 1890 fontWeight: 300, 1891 fontSize: '14px', 1892 fontSmoothing: 'antialiased', 1893 '::placeholder': { 1894 fontSize: '13px', 1895 color: '#b3b6ba' 1896 } 1897 }, 1898 invalid: { 1899 color: '#f15b2a' 1900 }, 1901 }; 1902 1903 var elementClasses = { 1904 focus: 'focused', 1905 empty: 'empty', 1906 invalid: 'invalid', 1907 }; 1908 1909 var elements = wl.app.stripe.elements(); 1910 view.cardNumber = elements.create('cardNumber', { 1911 style: elementStyles, 1912 classes: elementClasses, 1913 }); 1914 view.cardExpiry = elements.create('cardExpiry', { 1915 style: elementStyles, 1916 classes: elementClasses, 1917 }); 1918 view.cardCvc = elements.create('cardCvc', { 1919 style: elementStyles, 1920 classes: elementClasses, 1921 }); 1922 view.cardNumber.mount('#accountCardNumber'); 1923 view.cardExpiry.mount('#accountCardExpiration'); 1924 view.cardCvc.mount('#accountCardCvc'); 1925 console.log("initialized card element"); 1926 } 1927 1928 function logger(text) { 1929 $('#userSubscription').append('<div style="padding: 5px 15px">'+text+'</div>') 1930 } 1931});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.