From 6a2f32f8c7740bb791aeb2087149756b50c2b508 Mon Sep 17 00:00:00 2001 From: wjames111 Date: Thu, 12 Dec 2024 18:48:58 -0500 Subject: [PATCH 1/5] CVV validation on all transactions. --- .../existingPaymentMethods.component.js | 43 +++++++- .../existingPaymentMethods.component.spec.js | 100 +++++++++++++++++- .../existingPaymentMethods.tpl.html | 25 +++-- src/app/checkout/step-2/step-2.component.js | 12 ++- .../checkout/step-2/step-2.component.spec.js | 91 ++++++++++++++-- src/app/checkout/step-2/step-2.tpl.html | 5 +- .../creditCardForm.component.js | 4 +- .../creditCardForm/creditCardForm.tpl.html | 22 +--- .../directives/creditCardCvv.directive.js | 35 ++++++ 9 files changed, 287 insertions(+), 50 deletions(-) create mode 100644 src/common/directives/creditCardCvv.directive.js diff --git a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.js b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.js index ce59dea7a..04b7d188d 100644 --- a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.js +++ b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.js @@ -6,19 +6,20 @@ import paymentMethodDisplay from 'common/components/paymentMethods/paymentMethod import paymentMethodFormModal from 'common/components/paymentMethods/paymentMethodForm/paymentMethodForm.modal.component' import coverFees from 'common/components/paymentMethods/coverFees/coverFees.component' +import * as cruPayments from '@cruglobal/cru-payments/dist/cru-payments' import orderService from 'common/services/api/order.service' import cartService from 'common/services/api/cart.service' import { validPaymentMethod } from 'common/services/paymentHelpers/validPaymentMethods' import giveModalWindowTemplate from 'common/templates/giveModalWindow.tpl.html' import { SignInEvent } from 'common/services/session/session.service' - +import creditCardCvv from '../../../../common/directives/creditCardCvv.directive' import template from './existingPaymentMethods.tpl.html' const componentName = 'checkoutExistingPaymentMethods' class ExistingPaymentMethodsController { /* @ngInject */ - constructor ($log, $scope, orderService, cartService, $uibModal) { + constructor ($log, $scope, orderService, cartService, $uibModal, $window) { this.$log = $log this.$scope = $scope this.orderService = orderService @@ -26,6 +27,7 @@ class ExistingPaymentMethodsController { this.$uibModal = $uibModal this.paymentFormResolve = {} this.validPaymentMethod = validPaymentMethod + this.sessionStorage = $window.sessionStorage this.$scope.$on(SignInEvent, () => { this.$onInit() @@ -33,7 +35,9 @@ class ExistingPaymentMethodsController { } $onInit () { + this.enableContinue({ $event: false }) this.loadPaymentMethods() + this.waitForFormInitialization() } $onChanges (changes) { @@ -52,6 +56,27 @@ class ExistingPaymentMethodsController { } } + waitForFormInitialization () { + const unregister = this.$scope.$watch('$ctrl.creditCardPaymentForm.securityCode', () => { + if (this.creditCardPaymentForm && this.creditCardPaymentForm.securityCode) { + unregister() + this.addCvvValidators() + this.switchPayment() + } + }) + } + + addCvvValidators () { + this.$scope.$watch('$ctrl.creditCardPaymentForm.securityCode.$viewValue', (number) => { + if (this.selectedPaymentMethod?.['card-type'] && this.creditCardPaymentForm.securityCode) { + this.creditCardPaymentForm.securityCode.$validators.minLength = cruPayments.creditCard.cvv.validate.minLength + this.creditCardPaymentForm.securityCode.$validators.maxLength = cruPayments.creditCard.cvv.validate.maxLength + this.enableContinue({ $event: cruPayments.creditCard.cvv.validate.minLength(number) && cruPayments.creditCard.cvv.validate.maxLength(number) }) + this.selectedPaymentMethod.cvv = number + } + }) + } + loadPaymentMethods () { this.orderService.getExistingPaymentMethods() .subscribe((data) => { @@ -80,6 +105,7 @@ class ExistingPaymentMethodsController { // Select the first payment method this.selectedPaymentMethod = paymentMethods[0] } + this.shouldRecoverCvv = true this.switchPayment() } @@ -130,6 +156,13 @@ class ExistingPaymentMethodsController { switchPayment () { this.onPaymentChange({ selectedPaymentMethod: this.selectedPaymentMethod }) + if (this.selectedPaymentMethod?.['card-type'] && this.creditCardPaymentForm?.securityCode) { + // Set cvv from session storage + const storage = this.shouldRecoverCvv ? JSON.parse(this.sessionStorage.getItem('cvv')) : '' + this.creditCardPaymentForm.securityCode.$setViewValue(storage) + this.creditCardPaymentForm.securityCode.$render() + this.shouldRecoverCvv = false + } if (this.selectedPaymentMethod?.['bank-name']) { // This is an EFT payment method so we need to remove any fee coverage this.orderService.storeCoverFeeDecision(false) @@ -144,7 +177,8 @@ export default angular paymentMethodFormModal.name, coverFees.name, orderService.name, - cartService.name + cartService.name, + creditCardCvv.name ]) .component(componentName, { controller: ExistingPaymentMethodsController, @@ -159,6 +193,7 @@ export default angular brandedCheckoutItem: '<', onPaymentFormStateChange: '&', onPaymentChange: '&', - onLoad: '&' + onLoad: '&', + enableContinue: '&' } }) diff --git a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.spec.js b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.spec.js index d2194b8ca..372ea7726 100644 --- a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.spec.js +++ b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.component.spec.js @@ -4,6 +4,7 @@ import { Observable } from 'rxjs/Observable' import 'rxjs/add/observable/of' import 'rxjs/add/observable/throw' import 'rxjs/add/operator/toPromise' +import * as cruPayments from '@cruglobal/cru-payments/dist/cru-payments' import { SignInEvent } from 'common/services/session/session.service' @@ -15,24 +16,43 @@ describe('checkout', () => { beforeEach(angular.mock.module(module.name)) const self = {} - beforeEach(inject(($componentController, $timeout) => { + beforeEach(inject(($componentController, $timeout, $window) => { self.$timeout = $timeout self.controller = $componentController(module.name, {}, { onLoad: jest.fn(), onPaymentChange: jest.fn(), + enableContinue: jest.fn(), onPaymentFormStateChange: jest.fn(), - cartData: { items: [] } + cartData: { items: [] }, + creditCardPaymentForm: { + securityCode: { + $valid: true, + $validators: { + minLength: (value) => cruPayments.creditCard.cvv.validate.minLength(value), + maxLength: cruPayments.creditCard.cvv.validate.maxLength + }, + $setViewValue: jest.fn(), + $render: jest.fn(), + } + }, + selectedPaymentMethod: { + cvv: '', + 'card-type': 'Visa' + } }) + self.$window = $window + self.$window.sessionStorage.clear() })) - describe('$onInit', () => { it('should call loadPaymentMethods', () => { jest.spyOn(self.controller, 'loadPaymentMethods').mockImplementation(() => {}) + jest.spyOn(self.controller, 'waitForFormInitialization').mockImplementation(() => {}) self.controller.$onInit() expect(self.controller.loadPaymentMethods).toHaveBeenCalled() + expect(self.controller.waitForFormInitialization).toHaveBeenCalled() }) it('should be called on sign in', () => { @@ -329,6 +349,80 @@ describe('checkout', () => { expect(self.controller.onPaymentChange).toHaveBeenCalledWith({ selectedPaymentMethod: undefined }) expect(self.controller.orderService.storeCoverFeeDecision).not.toHaveBeenCalled() }) + + it('should reset securityCode viewValue', () => { + self.controller.switchPayment() + + expect(self.controller.creditCardPaymentForm.securityCode.$setViewValue).toHaveBeenCalledWith('') + expect(self.controller.creditCardPaymentForm.securityCode.$render).toHaveBeenCalled() + }) + + it('should add securityCode viewValue from sessionStorage', () => { + self.$window.sessionStorage.setItem( + 'cvv', + '456' + ) + self.controller.shouldRecoverCvv = true + self.controller.switchPayment() + + expect(self.controller.creditCardPaymentForm.securityCode.$setViewValue).toHaveBeenCalledWith(456) + expect(self.controller.creditCardPaymentForm.securityCode.$render).toHaveBeenCalled() + }) + }) + + describe('addCvvValidators', () => { + it('should add a watch on the security code value', () => { + self.controller.creditCardPaymentForm = { + $valid: true, + $dirty: false, + securityCode: { + $viewValue: '123', + $validators: {} + } + } + self.controller.addCvvValidators() + expect(self.controller.$scope.$$watchers.length).toEqual(1) + expect(self.controller.$scope.$$watchers[0].exp).toEqual('$ctrl.creditCardPaymentForm.securityCode.$viewValue') + }) + + it('should add validator functions to creditCardPaymentForm.securityCode', () => { + jest.spyOn(self.controller, 'addCvvValidators') + self.controller.selectedPaymentMethod.self = { + type: 'cru.creditcards.named-credit-card', + uri: 'selected uri' + } + self.controller.waitForFormInitialization() + self.controller.$scope.$digest() + + expect(self.controller.addCvvValidators).toHaveBeenCalled() + expect(Object.keys(self.controller.creditCardPaymentForm.securityCode.$validators).length).toEqual(2) + expect(typeof self.controller.creditCardPaymentForm.securityCode.$validators.minLength).toBe('function') + expect(typeof self.controller.creditCardPaymentForm.securityCode.$validators.maxLength).toBe('function') + }) + + it('should call enableContinue when cvv is valid', () => { + self.controller.creditCardPaymentForm.securityCode.$viewValue = '123' + self.controller.addCvvValidators() + self.controller.$scope.$apply() + + expect(self.controller.enableContinue).toHaveBeenCalledWith({ $event: true }) + }) + + it('should call enableContinue when cvv is too long', () => { + self.controller.creditCardPaymentForm.securityCode.$viewValue = '12345' + self.controller.addCvvValidators() + self.controller.$scope.$apply() + + expect(self.controller.enableContinue).toHaveBeenCalledWith({ $event: false }) + }) + + it('should call enableContinue when cvv is too short', () => { + self.controller.creditCardPaymentForm.securityCode.$viewValue = '1' + self.controller.addCvvValidators() + self.controller.$scope.$apply() + + expect(self.controller.enableContinue).toHaveBeenCalledWith({ $event: false }) + }) }) }) }) diff --git a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html index 54080a339..287cc758b 100644 --- a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html +++ b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html @@ -1,17 +1,24 @@ -
+
Your Payment Methods
-
- -
- +
+
+
+ +
+
+ +
+
+
+
{{'OPTIONAL'}}
diff --git a/src/app/checkout/step-2/step-2.component.js b/src/app/checkout/step-2/step-2.component.js index d1f384c3a..2b6c54b4e 100644 --- a/src/app/checkout/step-2/step-2.component.js +++ b/src/app/checkout/step-2/step-2.component.js @@ -78,6 +78,7 @@ class Step2Controller { onPaymentFormStateChange ($event) { this.paymentFormState = $event.state + if ($event.state === 'loading' && $event.payload) { const paymentType = $event.payload.creditCard ? $event.payload.creditCard['card-type'] : $event.payload.bankAccount ? $event.payload.bankAccount['account-type'] : 'Unknown' const request = $event.update @@ -109,6 +110,8 @@ class Step2Controller { this.changeStep({ newStep: 'review' }) this.onStateChange({ state: 'submitted' }) this.paymentFormState = 'success' + } else if ($event.state === 'submitted') { + this.orderService.storeCardSecurityCode(this.selectedPaymentMethod.cvv, this.selectedPaymentMethod.self.uri) } else if ($event.state === 'unsubmitted') { this.onStateChange({ state: 'unsubmitted' }) } else if ($event.state === 'error') { @@ -116,7 +119,10 @@ class Step2Controller { } } - getContinueDisabled () { + isContinueDisabled () { + if (this.selectedPaymentMethod?.['card-type'] && !this.isCvvValid) { + return true + } if (this.loadingPaymentMethods) { return true } @@ -129,6 +135,10 @@ class Step2Controller { } return false } + + enableContinue (isCvvValid) { + this.isCvvValid = isCvvValid + } } export default angular diff --git a/src/app/checkout/step-2/step-2.component.spec.js b/src/app/checkout/step-2/step-2.component.spec.js index f3e61ae79..32dfa424c 100644 --- a/src/app/checkout/step-2/step-2.component.spec.js +++ b/src/app/checkout/step-2/step-2.component.spec.js @@ -164,6 +164,7 @@ describe('checkout', () => { it('should update paymentFormState if transitioning to a different state', () => { self.controller.paymentFormState = 'unsubmitted' + self.controller.selectedPaymentMethod = { cvv: '123', self: { uri: 'uri'} } self.controller.onPaymentFormStateChange({ state: 'submitted' }) expect(self.controller.paymentFormState).toEqual('submitted') @@ -249,14 +250,14 @@ describe('checkout', () => { }) }) - describe('getContinueDisabled', () => { + describe('isContinueDisabled', () => { it('should return true when there are existing payment methods but none are valid', () => { self.controller.handleExistingPaymentLoading(true, true) self.controller.handlePaymentChange(undefined) expect(self.controller.existingPaymentMethods).toBe(true) expect(self.controller.selectedPaymentMethod).toBeUndefined() - expect(self.controller.getContinueDisabled()).toBe(true) + expect(self.controller.isContinueDisabled()).toBe(true) }) it('should return false when there are existing payment methods and at least one is valid', () => { @@ -265,7 +266,7 @@ describe('checkout', () => { expect(self.controller.existingPaymentMethods).toBe(true) expect(self.controller.selectedPaymentMethod).not.toBeUndefined() - expect(self.controller.getContinueDisabled()).toBe(false) + expect(self.controller.isContinueDisabled()).toBe(false) }) it('should return false when there are not existing payment methods', () => { @@ -273,19 +274,19 @@ describe('checkout', () => { expect(self.controller.existingPaymentMethods).toBe(false) expect(self.controller.selectedPaymentMethod).toBeUndefined() - expect(self.controller.getContinueDisabled()).toBe(false) + expect(self.controller.isContinueDisabled()).toBe(false) }) it('should return true while the payment methods are loading', () => { self.controller.$onInit() expect(self.controller.loadingPaymentMethods).toBe(true) - expect(self.controller.getContinueDisabled()).toBe(true) + expect(self.controller.isContinueDisabled()).toBe(true) self.controller.handleExistingPaymentLoading(true, false) expect(self.controller.loadingPaymentMethods).toBe(false) - expect(self.controller.getContinueDisabled()).toBe(false) + expect(self.controller.isContinueDisabled()).toBe(false) }) it('should return true while the payment form is encrypting or loading', () => { @@ -295,18 +296,90 @@ describe('checkout', () => { self.controller.onPaymentFormStateChange({ state: 'encrypting' }) expect(self.controller.paymentFormState).toBe('encrypting') - expect(self.controller.getContinueDisabled()).toBe(true) + expect(self.controller.isContinueDisabled()).toBe(true) self.controller.onPaymentFormStateChange({ state: 'loading', payload: {}, update: false }) expect(self.controller.paymentFormState).toBe('loading') - expect(self.controller.getContinueDisabled()).toBe(true) + expect(self.controller.isContinueDisabled()).toBe(true) deferred.resolve() self.$flushPendingTasks() expect(self.controller.paymentFormState).toBe('success') - expect(self.controller.getContinueDisabled()).toBe(false) + expect(self.controller.isContinueDisabled()).toBe(false) + }) + + describe('existing credit card used', () => { + it('should disable continue when cvv is invalid', () => { + self.controller.handleExistingPaymentLoading(true, true) + self.controller.isCvvValid = false + self.controller.handlePaymentChange({'card-type': 'visa'}) + + expect(self.controller.isContinueDisabled()).toBe(true) + }) + + it('should disable continue when cvv is valid', () => { + self.controller.handleExistingPaymentLoading(true, true) + self.controller.isCvvValid = true + self.controller.handlePaymentChange({'card-type': 'visa'}) + + expect(self.controller.isContinueDisabled()).toBe(false) + }) + + it('should not disable continue when cvv is invalid', () => { + self.controller.handleExistingPaymentLoading(true, true) + self.controller.isCvvValid = false + self.controller.handlePaymentChange({'account-type': 'checking'}) + + expect(self.controller.isContinueDisabled()).toBe(false) + }) + }) + + describe('existing EFT used', () => { + it('should not disable continue when cvv validity is undefined', () => { + self.controller.handleExistingPaymentLoading(true, true) + self.controller.isCvvValid = undefined + self.controller.handlePaymentChange({'account-type': 'checking'}) + + expect(self.controller.isContinueDisabled()).toBe(false) + }) + + it('should not disable continue when cvv is valid', () => { + self.controller.handleExistingPaymentLoading(true, true) + self.controller.isCvvValid = true + self.controller.handlePaymentChange({'account-type': 'checking'}) + + expect(self.controller.isContinueDisabled()).toBe(false) + }) + }) + + describe('new credit card used', () => { + it('should disable continue when cvv is invalid and new credit card payment is added', () => { + self.controller.handlePaymentChange({'card-type': 'visa'}) + self.controller.isCvvValid = false + expect(self.controller.isContinueDisabled()).toBe(true) + }) + }) + + describe('new EFT used', () => { + it('should not disable continue when cvv is invalid and new EFT is added', () => { + self.controller.handlePaymentChange({'account-type': 'checking'}) + self.controller.isCvvValid = false + expect(self.controller.isContinueDisabled()).toBe(false) + }) + }) + }) + + describe('enableContinue', () => { + it('should set isCvvValid to false', () => { + self.controller.enableContinue(false) + expect(self.controller.isCvvValid).toBe(false) + }) + + it('should set isCvvValid to true', () => { + self.controller.enableContinue(true) + expect(self.controller.isCvvValid).toBe(true) }) }) }) diff --git a/src/app/checkout/step-2/step-2.tpl.html b/src/app/checkout/step-2/step-2.tpl.html index 7a3edb704..d2203b9cd 100644 --- a/src/app/checkout/step-2/step-2.tpl.html +++ b/src/app/checkout/step-2/step-2.tpl.html @@ -31,7 +31,8 @@ default-payment-type="$ctrl.defaultPaymentType" hide-payment-type-options="$ctrl.hidePaymentTypeOptions" cart-data="$ctrl.cartData" - branded-checkout-item="$ctrl.brandedCheckoutItem"> + branded-checkout-item="$ctrl.brandedCheckoutItem" + enable-continue="$ctrl.enableContinue($event)">
@@ -42,7 +43,7 @@
- diff --git a/src/common/components/paymentMethods/creditCardForm/creditCardForm.component.js b/src/common/components/paymentMethods/creditCardForm/creditCardForm.component.js index 6e152e545..88ca925b4 100644 --- a/src/common/components/paymentMethods/creditCardForm/creditCardForm.component.js +++ b/src/common/components/paymentMethods/creditCardForm/creditCardForm.component.js @@ -21,6 +21,7 @@ import tsys from 'common/services/api/tsys.service' import template from './creditCardForm.tpl.html' import creditCardNumberDirective from '../../../directives/creditCardNumber.directive' +import creditCardCvv from '../../../../common/directives/creditCardCvv.directive' const componentName = 'creditCardForm' @@ -195,7 +196,8 @@ export default angular showErrors.name, analyticsFactory.name, tsys.name, - creditCardNumberDirective.name + creditCardNumberDirective.name, + creditCardCvv.name ]) .component(componentName, { controller: CreditCardController, diff --git a/src/common/components/paymentMethods/creditCardForm/creditCardForm.tpl.html b/src/common/components/paymentMethods/creditCardForm/creditCardForm.tpl.html index b22a1d791..1cd86debb 100644 --- a/src/common/components/paymentMethods/creditCardForm/creditCardForm.tpl.html +++ b/src/common/components/paymentMethods/creditCardForm/creditCardForm.tpl.html @@ -102,27 +102,7 @@

{{'CREDIT_CARD_PAYMENT'}}

-
- -
-
{{'CARD_SEC_CODE_ERROR'}}
-
{{'MIN_LENGTH_CARD_SEC_CODE'}}
-
{{'MAX_LENGTH_CARD_SEC_CODE'}}
-
- {{'LOCATION_OF_CODE_OTHER'}} - {{'LOCATION_OF_CODE_AMEX'}} -
-
-
+
diff --git a/src/common/directives/creditCardCvv.directive.js b/src/common/directives/creditCardCvv.directive.js new file mode 100644 index 000000000..c77e49378 --- /dev/null +++ b/src/common/directives/creditCardCvv.directive.js @@ -0,0 +1,35 @@ +import angular from 'angular' +const directiveName = 'creditCardCvv' + +const template = +`
+ + +
+
{{'CARD_SEC_CODE_ERROR'}}
+
{{'MIN_LENGTH_CARD_SEC_CODE'}}
+
{{'MAX_LENGTH_CARD_SEC_CODE'}}
+
+ {{'LOCATION_OF_CODE_OTHER'}} + {{'LOCATION_OF_CODE_AMEX'}} +
+
+
` + +const creditCardCvv = /* @ngInject */ () => { + const directiveDefinitionObject = { + restrict: 'E', + template + } + return directiveDefinitionObject +} + +export default angular + .module(directiveName, []) + .directive(directiveName, creditCardCvv) From 912379556a280d4f4a57847c58e74ef5ca3a8dfe Mon Sep 17 00:00:00 2001 From: wjames111 Date: Fri, 13 Dec 2024 10:43:57 -0500 Subject: [PATCH 2/5] Fix display issue with cover fees. --- .../existingPaymentMethods.tpl.html | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html index 287cc758b..c9f5b4598 100644 --- a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html +++ b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html @@ -3,22 +3,21 @@ Your Payment Methods +
-
- -
+
-
+
{{'OPTIONAL'}}
From c92ebd83cd6370b043b99d46beb2bdfdc9ef1422 Mon Sep 17 00:00:00 2001 From: wjames111 Date: Fri, 13 Dec 2024 18:28:14 -0500 Subject: [PATCH 3/5] Add styles for creditCardCvv.directive. --- .../existingPaymentMethods.tpl.html | 18 +++---- .../directives/creditCardCvv.directive.js | 32 +++++++------ .../directives/creditCardCvv.directive.scss | 48 +++++++++++++++++++ 3 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 src/common/directives/creditCardCvv.directive.scss diff --git a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html index c9f5b4598..e642b6269 100644 --- a/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html +++ b/src/app/checkout/step-2/existingPaymentMethods/existingPaymentMethods.tpl.html @@ -6,14 +6,16 @@
-
- -
- +
+
+ + + +
diff --git a/src/common/directives/creditCardCvv.directive.js b/src/common/directives/creditCardCvv.directive.js index c77e49378..ee295809c 100644 --- a/src/common/directives/creditCardCvv.directive.js +++ b/src/common/directives/creditCardCvv.directive.js @@ -1,23 +1,27 @@ import angular from 'angular' const directiveName = 'creditCardCvv' +import './creditCardCvv.directive.scss' + const template = -`
- - -
-
{{'CARD_SEC_CODE_ERROR'}}
-
{{'MIN_LENGTH_CARD_SEC_CODE'}}
-
{{'MAX_LENGTH_CARD_SEC_CODE'}}
-
+`
+ {{'SEC_CODE'}} +
+ +
+
{{'CARD_SEC_CODE_ERROR'}}
+
{{'MIN_LENGTH_CARD_SEC_CODE'}}
+
{{'MAX_LENGTH_CARD_SEC_CODE'}}
+
{{'LOCATION_OF_CODE_OTHER'}} {{'LOCATION_OF_CODE_AMEX'}} +
` diff --git a/src/common/directives/creditCardCvv.directive.scss b/src/common/directives/creditCardCvv.directive.scss new file mode 100644 index 000000000..31f04ea53 --- /dev/null +++ b/src/common/directives/creditCardCvv.directive.scss @@ -0,0 +1,48 @@ + +.radio.radio-method { + .credit-card-cvv-container { + display: flex; + margin: 8px 20px 8px 38px; + .col-sm-4 { + padding-left: 10px; + padding-right: 0; + } + .form-control { + line-height: 1.6; + height: auto; + } + .credit-card-cvv-label { + margin-top: 9px; + margin-right: 9px; + font-size: 15px; + line-height: 1.2em; + font-weight: bold; + white-space: nowrap; + &::after { + content: ':'; + } + } + .credit-card-cvv-help-block { + margin-bottom: 0; + } + } +} + +.give-modal-content { + .credit-card-cvv-label { + text-transform: uppercase; + font-weight: 500; + letter-spacing: 1px; + font-size: 14px; + display: block; + margin-bottom: 4px; + &::after { + content: '*'; + display: inline-block; + font-size: 115%; + line-height: 0; + font-family: "fontawesome", "Font Awesome 5 Pro"; + margin-left: 6px; + } + } +} From 115ac0f4f007b1041390b1f3840bb4a773dd13d0 Mon Sep 17 00:00:00 2001 From: wjames111 Date: Fri, 13 Dec 2024 18:31:10 -0500 Subject: [PATCH 4/5] Add styles for creditCardCvv directive in BCO. --- branded-checkout.html | 2 +- src/common/directives/creditCardCvv.directive.js | 2 +- src/common/directives/creditCardCvv.directive.scss | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/branded-checkout.html b/branded-checkout.html index cf436fd12..5874ff654 100644 --- a/branded-checkout.html +++ b/branded-checkout.html @@ -12,7 +12,7 @@ - + diff --git a/src/common/directives/creditCardCvv.directive.js b/src/common/directives/creditCardCvv.directive.js index ee295809c..841118061 100644 --- a/src/common/directives/creditCardCvv.directive.js +++ b/src/common/directives/creditCardCvv.directive.js @@ -1,7 +1,7 @@ import angular from 'angular' -const directiveName = 'creditCardCvv' import './creditCardCvv.directive.scss' +const directiveName = 'creditCardCvv' const template = `
diff --git a/src/common/directives/creditCardCvv.directive.scss b/src/common/directives/creditCardCvv.directive.scss index 31f04ea53..20b858516 100644 --- a/src/common/directives/creditCardCvv.directive.scss +++ b/src/common/directives/creditCardCvv.directive.scss @@ -28,7 +28,7 @@ } } -.give-modal-content { +.give-modal-content, .branded-checkout { .credit-card-cvv-label { text-transform: uppercase; font-weight: 500; From 57360ce72c79e1d54ec5d12dd11b75487f6207d3 Mon Sep 17 00:00:00 2001 From: wjames111 Date: Mon, 16 Dec 2024 12:26:59 -0500 Subject: [PATCH 5/5] Uses tabs over spaces in scss file. --- .../directives/creditCardCvv.directive.scss | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/common/directives/creditCardCvv.directive.scss b/src/common/directives/creditCardCvv.directive.scss index 20b858516..f75352093 100644 --- a/src/common/directives/creditCardCvv.directive.scss +++ b/src/common/directives/creditCardCvv.directive.scss @@ -1,48 +1,48 @@ .radio.radio-method { - .credit-card-cvv-container { - display: flex; - margin: 8px 20px 8px 38px; - .col-sm-4 { - padding-left: 10px; - padding-right: 0; - } - .form-control { - line-height: 1.6; - height: auto; - } - .credit-card-cvv-label { - margin-top: 9px; - margin-right: 9px; - font-size: 15px; - line-height: 1.2em; - font-weight: bold; - white-space: nowrap; - &::after { - content: ':'; - } - } - .credit-card-cvv-help-block { - margin-bottom: 0; - } - } + .credit-card-cvv-container { + display: flex; + margin: 8px 20px 8px 38px; + .col-sm-4 { + padding-left: 10px; + padding-right: 0; + } + .form-control { + line-height: 1.6; + height: auto; + } + .credit-card-cvv-label { + margin-top: 9px; + margin-right: 9px; + font-size: 15px; + line-height: 1.2em; + font-weight: bold; + white-space: nowrap; + &::after { + content: ':'; + } + } + .credit-card-cvv-help-block { + margin-bottom: 0; + } + } } .give-modal-content, .branded-checkout { - .credit-card-cvv-label { - text-transform: uppercase; - font-weight: 500; - letter-spacing: 1px; - font-size: 14px; - display: block; + .credit-card-cvv-label { + text-transform: uppercase; + font-weight: 500; + letter-spacing: 1px; + font-size: 14px; + display: block; margin-bottom: 4px; - &::after { - content: '*'; - display: inline-block; - font-size: 115%; - line-height: 0; - font-family: "fontawesome", "Font Awesome 5 Pro"; - margin-left: 6px; - } - } + &::after { + content: '*'; + display: inline-block; + font-size: 115%; + line-height: 0; + font-family: "fontawesome", "Font Awesome 5 Pro"; + margin-left: 6px; + } + } }