Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EP-2518 - Remove ConfirmationStep #1119

9 changes: 7 additions & 2 deletions src/app/branded/branded-checkout.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,13 @@ class BrandedCheckoutController {
next () {
switch (this.checkoutStep) {
case 'giftContactPayment':
this.checkoutStep = 'review'
this.fireAnalyticsEvents('review')
// If it is a single step form, the next step should be 'thankYou'
if (this.useV3 === 'true') {
this.checkoutStep = 'thankYou'
} else {
this.checkoutStep = 'review'
this.fireAnalyticsEvents('review')
}
break
case 'review':
this.checkoutStep = 'thankYou'
Expand Down
120 changes: 116 additions & 4 deletions src/app/branded/step-1/branded-checkout-step-1.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,29 @@ import every from 'lodash/every'
import productConfigForm from 'app/productConfig/productConfigForm/productConfigForm.component'
import contactInfo from 'common/components/contactInfo/contactInfo.component'
import checkoutStep2 from 'app/checkout/step-2/step-2.component'
import checkoutErrorMessages from 'app/checkout/checkout-error-messages/checkout-error-messages.component'

import cartService from 'common/services/api/cart.service'
import orderService from 'common/services/api/order.service'
import analyticsFactory from '../../analytics/analytics.factory'
import brandedAnalyticsFactory from '../../branded/analytics/branded-analytics.factory'

import { FEE_DERIVATIVE } from 'common/components/paymentMethods/coverFees/coverFees.component'

import template from './branded-checkout-step-1.tpl.html'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/do'
import 'rxjs/add/operator/finally'

const componentName = 'brandedCheckoutStep1'

class BrandedCheckoutStep1Controller {
/* @ngInject */
constructor ($log, $filter, brandedAnalyticsFactory, cartService, orderService) {
constructor ($scope, $log, $filter, $window, analyticsFactory, brandedAnalyticsFactory, cartService, orderService) {
this.$scope = $scope
this.$log = $log
this.$filter = $filter
this.$window = $window
this.analyticsFactory = analyticsFactory
this.brandedAnalyticsFactory = brandedAnalyticsFactory
this.cartService = cartService
this.orderService = orderService
Expand Down Expand Up @@ -154,21 +161,123 @@ class BrandedCheckoutStep1Controller {
checkSuccessfulSubmission () {
if (every(this.submission, 'completed')) {
if (every(this.submission, { error: false })) {
this.next()
if (this.useV3 === 'true') {
this.submitOrderInternal()
} else {
this.next()
}
} else {
this.submitted = false
}
}
}

loadCart () {
this.errorLoadingCart = false

const cart = this.cartService.get()
cart.subscribe(
data => {
// Setting cart data and analytics
this.cartData = data
this.brandedAnalyticsFactory.saveCoverFees(this.orderService.retrieveCoverFeeDecision())
if (this.cartData && this.cartData.items) {
this.brandedAnalyticsFactory.saveItem(this.cartData.items[0])
}
this.brandedAnalyticsFactory.addPaymentInfo()
},
error => {
// Handle errors by setting flag and logging the error
this.errorLoadingCart = true
this.$log.error('Error loading cart data for branded checkout (single step)', error)
}
)
return cart
}

loadCurrentPayment () {
this.loadingCurrentPayment = true

const getCurrentPayment = this.orderService.getCurrentPayment()
getCurrentPayment.finally(() => {
caleballdrin marked this conversation as resolved.
Show resolved Hide resolved
this.loadingCurrentPayment = false
}).subscribe(
data => {
if (!data) {
this.$log.error('Error loading current payment info: current payment doesn\'t seem to exist')
} else if (data['account-type']) {
this.bankAccountPaymentDetails = data
} else if (data['card-type']) {
this.creditCardPaymentDetails = data
} else {
this.$log.error('Error loading current payment info: current payment type is unknown')
}
},
error => {
this.$log.error('Error loading current payment info', error)
}
)
return getCurrentPayment
}

checkErrors () {
// Then check for errors on the API
return this.orderService.checkErrors().do(
(data) => {
this.needinfoErrors = data
})
.catch(error => {
this.$log.error('Error loading checkErrors', error)
})
}

submitOrderInternal () {
caleballdrin marked this conversation as resolved.
Show resolved Hide resolved
this.loadingAndSubmitting = true
this.loadCart()
.mergeMap(() => {
return this.loadCurrentPayment()
})
.mergeMap(() => {
return this.checkErrors()
})
.mergeMap(() => {
return this.orderService.submitOrder(this)
})
.finally(() => {
this.loadingAndSubmitting = false
})
.subscribe(() => {
caleballdrin marked this conversation as resolved.
Show resolved Hide resolved
this.next()
caleballdrin marked this conversation as resolved.
Show resolved Hide resolved
})
}

handleRecaptchaFailure () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may not be needed when we move to enterprise. At this point I've removed it, but may need to do something with it after QA.

this.analyticsFactory.checkoutFieldError('submitOrder', 'failed')
this.submittingOrder = false
this.loadingAndSubmitting = false
this.onSubmittingOrder({ value: false })

this.loadCart()

this.onSubmitted()
this.submissionError = 'generic error'
this.$window.scrollTo(0, 0)
}

canSubmitOrder () {
return !this.submittingOrder
wrandall22 marked this conversation as resolved.
Show resolved Hide resolved
}
}

export default angular
.module(componentName, [
productConfigForm.name,
contactInfo.name,
checkoutStep2.name,
checkoutErrorMessages.name,
cartService.name,
orderService.name,
analyticsFactory.name,
brandedAnalyticsFactory.name
])
.component(componentName, {
Expand All @@ -189,6 +298,9 @@ export default angular
onPaymentFailed: '&',
radioStationApiUrl: '<',
radioStationRadius: '<',
useV3: '<'
onSubmittingOrder: '&',
onSubmitted: '&',
useV3: '<',
loadingAndSubmitting: '<'
}
})
25 changes: 23 additions & 2 deletions src/app/branded/step-1/branded-checkout-step-1.tpl.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<checkout-error-messages
needinfo-errors="$ctrl.needinfoErrors"
submission-error="$ctrl.submissionError"
submission-error-status="$ctrl.submissionErrorStatus">
</checkout-error-messages>
<div class="panel">
<div class="panel-body loading-overlay-parent">
<loading ng-if="$ctrl.loadingProductConfig">
Expand Down Expand Up @@ -49,10 +54,26 @@ <h3 class="panel-name" translate>{{'PAYMENT'}}</h3>
</div>
<div class="panel">
<div class="panel-body text-right">
<button class="btn btn-primary"
<div class="checkout-cta pull-right" ng-if="$ctrl.useV3 === 'true'">
<recaptcha-wrapper
action="'branded_submit'"
on-success="$ctrl.submit"
on-failure="$ctrl.handleRecaptchaFailure"
component-instance="$ctrl"
button-id="'submitOrderButton'"
button-type="'submit'"
button-classes="'btn btn-primary btn-lg btn-block'"
button-disabled="$ctrl.errorLoadingProductConfig || !$ctrl.canSubmitOrder()"
button-label="'SUBMIT_GIFT'"></recaptcha-wrapper>
</div>

<button ng-if="$ctrl.useV3 !== 'true'" class="btn btn-primary"
ng-click="$ctrl.submit()"
ng-disabled="$ctrl.errorLoadingProductConfig"
translate>{{'CONTINUE'}}</button>
</div>
</div>
</div>
</div>
<loading type="fixed" ng-if="$ctrl.loadingAndSubmitting">
<translate>{{'SUBMITTING_GIFT'}}</translate>
</loading>
2 changes: 1 addition & 1 deletion src/app/cart/cart.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import productModalService from 'common/services/productModal.service'
import desigSrcDirective from 'common/directives/desigSrc.directive'

import displayRateTotals from 'common/components/displayRateTotals/displayRateTotals.component'
import { cartUpdatedEvent } from 'common/components/nav/navCart/navCart.component'
import { cartUpdatedEvent } from 'common/lib/cartEvents'

import analyticsFactory from 'app/analytics/analytics.factory'

Expand Down
2 changes: 1 addition & 1 deletion src/app/cart/cart.component.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Observable } from 'rxjs/Observable'
import 'rxjs/add/observable/of'
import 'rxjs/add/observable/throw'

import { cartUpdatedEvent } from 'common/components/nav/navCart/navCart.component'
import { cartUpdatedEvent } from 'common/lib/cartEvents'

describe('cart', () => {
beforeEach(angular.mock.module(module.name))
Expand Down
11 changes: 6 additions & 5 deletions src/app/checkout/cart-summary/cart-summary.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,22 @@ export const submitOrderEvent = 'submitOrderEvent'

class CartSummaryController {
/* @ngInject */
constructor (cartService, $scope) {
constructor (cartService, $scope, $rootScope) {
this.$scope = $scope
this.$rootScope = $rootScope
this.cartService = cartService
}

buildCartUrl () {
return this.cartService.buildCartUrl()
}

handleRecaptchaFailure (componentInstance) {
componentInstance.$rootScope.$emit(recaptchaFailedEvent)
handleRecaptchaFailure () {
this.$rootScope.$emit(recaptchaFailedEvent)
}

onSubmit (componentInstance) {
componentInstance.$rootScope.$emit(submitOrderEvent)
onSubmit () {
this.$rootScope.$emit(submitOrderEvent)
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/app/checkout/cart-summary/cart-summary.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ describe('checkout', function () {

describe('onSubmit', () => {
it('should emit an event', () => {
jest.spyOn(componentInstance.$rootScope, '$emit').mockImplementation(() => {})
self.controller.onSubmit(componentInstance)
expect(componentInstance.$rootScope.$emit).toHaveBeenCalledWith(submitOrderEvent)
jest.spyOn(self.controller.$rootScope, '$emit').mockImplementation(() => {})
self.controller.onSubmit()
expect(self.controller.$rootScope.$emit).toHaveBeenCalledWith(submitOrderEvent)
})
})

describe('handleRecaptchaFailure', () => {
it('should emit an event', () => {
jest.spyOn(componentInstance.$rootScope, '$emit').mockImplementation(() => {})
self.controller.handleRecaptchaFailure(componentInstance)
expect(componentInstance.$rootScope.$emit).toHaveBeenCalledWith(recaptchaFailedEvent)
jest.spyOn(self.controller.$rootScope, '$emit').mockImplementation(() => {})
self.controller.handleRecaptchaFailure()
expect(self.controller.$rootScope.$emit).toHaveBeenCalledWith(recaptchaFailedEvent)
})
})
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import angular from 'angular'

import template from './checkout-error-messages.tpl.html'

const componentName = 'checkoutErrorMessages'

class CheckoutErrorMessagesController {}

export default angular
.module(componentName, [])
.component(componentName, {
controller: CheckoutErrorMessagesController,
templateUrl: template,
bindings: {
needinfoErrors: '<',
submissionError: '<',
submissionErrorStatus: '<'
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<div class="alert alert-danger" role="alert" ng-if="$ctrl.needinfoErrors || $ctrl.submissionError">
<p ng-repeat="error in $ctrl.needinfoErrors" ng-switch="error">
<span ng-switch-when="need.email" translate>{{'REVIEW_EMAIL_ERROR'}}</span>
<span ng-switch-when="need.payment.method" translate>{{'REVIEW_PAYMENT_ERROR'}}</span>
<span ng-switch-when="need.billing.address" translate>{{'REVIEW_BILLING_ADDRESS_ERROR'}}</span>
<span ng-switch-default translate>
<span ng-if="$ctrl.submissionErrorStatus > -1" translate>
{{'REVIEW_MISSING_DATA_ERROR'}}
</span>
<span ng-if="$ctrl.submissionErrorStatus === -1" translate>
{{'REVIEW_TIME_OUT_ERROR'}}
</span>
</span>
</p>
<p ng-if="$ctrl.submissionError" ng-switch="$ctrl.submissionError">
<span ng-switch-when="Current payment type is unknown" translate>
{{'REVIEW_SUBMITTING_PAYMENT_ERROR'}}
</span>
<span ng-switch-when="CardExpiredException" translate>
{{'REVIEW_CARD_EXPIRED_ERROR'}}
</span>
<span ng-switch-when="CardErrorException" translate>
{{'REVIEW_INVALID_CARD_ERROR'}}
</span>
<span ng-switch-when="CardDeclinedException" translate>
{{'REVIEW_CARD_DECLINED_ERROR'}}
</span>
<span ng-switch-when="InsufficientFundException" translate>
{{'REVIEW_INSUFFICIENT_FUNDS_ERROR'}}
</span>
<span ng-switch-when="AuthorizedAmountExceededException" translate>
{{'REVIEW_EXCEEDS_BALANCE_ERROR'}}
</span>
<span ng-switch-when="InvalidCVV2Exception" translate>
{{'REVIEW_INVALID_SEC_CODE_ERROR'}}
</span>
<span ng-switch-when="InvalidAddressException" translate>
{{'REVIEW_ADDRESS_MISMATCH_ERROR'}}
</span>
<span ng-switch-default translate>
{{'REVIEW_DEFAULT_ERROR'}}
</span>
</p>
</div>
Loading