From 23ac5283e15b7421610a9e6af6efe4386bca220f Mon Sep 17 00:00:00 2001 From: sponglord Date: Fri, 21 Jan 2022 17:49:25 +0100 Subject: [PATCH] Chore/reorganisation secured fields directory (#1457) * Receiving and storing panLength prop * Created SFP directory * Created CSF directory * Created CSF/extensions and lib/securedField directories * Moving files into CSF/extensions * More files moved * Moving utils * Removing panLength related vars - they belong in another PR * First batch of partials * Adding 3 more partials * Removing files replaced by partials * Removing private function getIframeContentWindow form CSF (replace by util) * fix unit tests * Fixed linting error --- .../Ach/components/AchInput/AchInput.tsx | 2 +- .../components/CardInput/CardInput.test.tsx | 2 +- .../Card/components/CardInput/CardInput.tsx | 2 +- .../components/CardInput/components/types.ts | 2 +- .../Card/components/CardInput/types.ts | 2 +- packages/lib/src/components/Card/types.ts | 2 +- .../Giftcard/components/GiftcardComponent.tsx | 2 +- .../SecuredFieldsInput/SecuredFieldsInput.tsx | 2 +- .../internal/SecuredFields/SFP/SFPUtils.ts | 108 ++++++++++++++++++ .../{ => SFP}/SecuredFieldsProvider.test.tsx | 8 +- .../{ => SFP}/SecuredFieldsProvider.ts | 19 ++- .../SecuredFieldsProviderHandlers.ts | 8 +- .../SecuredFields/{ => SFP}/defaultProps.ts | 4 +- .../SecuredFields/binLookup/extensions.ts | 2 +- .../lib/{core => CSF}/AbstractCSF.ts | 15 +-- .../SecuredFields/lib/{core => CSF}/CSF.ts | 90 +++++++-------- .../extensions/additionalFields.ts} | 2 +- .../extensions}/configureCallbacks.ts | 0 .../extensions}/createSecuredFields.ts | 16 +-- .../extensions}/handleBrandFromBinLookup.ts | 12 +- .../extensions}/handleConfig.ts | 6 +- .../extensions}/handleEncryption.ts | 21 ++-- .../tabbing => CSF/extensions}/handleTab.ts | 14 +-- .../extensions}/handleValidation.ts | 16 +-- .../internal/SecuredFields/lib/CSF/index.ts | 3 + .../lib/{core => CSF}/initCSF.ts | 26 ++++- .../lib/CSF/partials/handleBinValue.ts | 26 +++++ .../lib/CSF/partials/handleFocus.ts | 45 ++++++++ .../partials/handleIframeConfigFeedback.ts | 49 ++++++++ .../utils => CSF/partials}/isConfigured.ts | 26 +++-- .../CSF/partials/postMessageToAllIframes.ts | 36 ++++++ .../partials}/processAutoComplete.ts | 39 ++++--- .../utils => CSF/partials}/processBrand.ts | 32 ++++-- .../lib/CSF/partials/setFocusOnFrame.ts | 26 +++++ .../utils => CSF/partials}/validateForm.ts | 17 ++- .../internal/SecuredFields/lib/CSF/types.ts | 88 ++++++++++++++ .../lib/{core => CSF}/utils/callbackUtils.ts | 0 .../cardType-tests/cardType-amex.test.ts | 0 .../cardType-detectCardLength.test.ts | 0 .../utils}/cardType-tests/cardType-mc.test.ts | 0 .../cardType-tests/cardType-otherFns.test.ts | 0 .../cardType-tests/cardType-visa.test.ts | 0 .../utils}/cardType-tests/cardType.test.ts | 2 +- .../lib/{utilities => CSF/utils}/cardType.ts | 4 +- .../utils}/destroySecuredFields.ts | 2 +- .../{ui => CSF/utils}/encryptedElements.ts | 4 +- .../utils/getCardGroupTypes.test.ts | 0 .../{core => CSF}/utils/getCardGroupTypes.ts | 0 .../CSF/utils/iframes/getIframeContentWin.ts | 8 ++ .../utils/iframes/postMessageToIframe.ts | 0 .../utils/iframes/postMessageValidation.ts | 0 .../{core => CSF}/utils/processErrors.test.ts | 2 +- .../lib/{core => CSF}/utils/processErrors.ts | 2 +- .../utils/tabbing/tabScenarioACH.ts | 0 .../utils/tabbing/tabScenarioCreditCard.ts | 2 +- .../utils/tabbing/tabScenarioGiftCard.ts | 2 +- .../utils/tabbing/tabScenarioKCP.ts | 2 +- .../utils/tabbing/utils.ts} | 22 +--- .../lib/{utilities => CSF/utils}/userAgent.ts | 0 .../lib/configuration/constants.ts | 4 +- .../lib/core/utils/handleBinValue.ts | 20 ---- .../lib/core/utils/iframes/handleFocus.ts | 37 ------ .../iframes/handleIframeConfigFeedback.ts | 40 ------- .../utils/iframes/postMessageToAllIframes.ts | 28 ----- .../lib/core/utils/iframes/setFocusOnFrame.ts | 18 --- .../internal/SecuredFields/lib/index.ts | 3 - .../AbstractSecuredField.ts | 9 +- .../SecuredField.test.ts | 3 +- .../{core => securedField}/SecuredField.ts | 24 ++-- .../utils}/createIframe.ts | 0 .../utils}/processAriaConfig.ts | 8 +- .../utils}/processPlaceholders.ts | 6 +- .../internal/SecuredFields/lib/types.ts | 95 ++------------- .../lib/utilities/commonUtils.ts | 19 +++ .../internal/SecuredFields/utils.ts | 106 +---------------- 75 files changed, 668 insertions(+), 574 deletions(-) create mode 100644 packages/lib/src/components/internal/SecuredFields/SFP/SFPUtils.ts rename packages/lib/src/components/internal/SecuredFields/{ => SFP}/SecuredFieldsProvider.test.tsx (97%) rename packages/lib/src/components/internal/SecuredFields/{ => SFP}/SecuredFieldsProvider.ts (96%) rename packages/lib/src/components/internal/SecuredFields/{ => SFP}/SecuredFieldsProviderHandlers.ts (98%) rename packages/lib/src/components/internal/SecuredFields/{ => SFP}/defaultProps.ts (95%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/AbstractCSF.ts (82%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/CSF.ts (73%) rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils/registerAdditionalField.ts => CSF/extensions/additionalFields.ts} (98%) rename packages/lib/src/components/internal/SecuredFields/lib/{configuration => CSF/extensions}/configureCallbacks.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF/extensions}/createSecuredFields.ts (94%) rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils => CSF/extensions}/handleBrandFromBinLookup.ts (91%) rename packages/lib/src/components/internal/SecuredFields/lib/{configuration => CSF/extensions}/handleConfig.ts (96%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF/extensions}/handleEncryption.ts (81%) rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils/tabbing => CSF/extensions}/handleTab.ts (83%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF/extensions}/handleValidation.ts (85%) create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/index.ts rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/initCSF.ts (75%) create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleBinValue.ts create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleFocus.ts create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleIframeConfigFeedback.ts rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils => CSF/partials}/isConfigured.ts (53%) create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/postMessageToAllIframes.ts rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils => CSF/partials}/processAutoComplete.ts (57%) rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils => CSF/partials}/processBrand.ts (69%) create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/setFocusOnFrame.ts rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils => CSF/partials}/validateForm.ts (53%) create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/types.ts rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/callbackUtils.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/cardType-tests/cardType-amex.test.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/cardType-tests/cardType-detectCardLength.test.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/cardType-tests/cardType-mc.test.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/cardType-tests/cardType-otherFns.test.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/cardType-tests/cardType-visa.test.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/cardType-tests/cardType.test.ts (98%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/cardType.ts (98%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF/utils}/destroySecuredFields.ts (90%) rename packages/lib/src/components/internal/SecuredFields/lib/{ui => CSF/utils}/encryptedElements.ts (96%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/getCardGroupTypes.test.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/getCardGroupTypes.ts (100%) create mode 100644 packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/getIframeContentWin.ts rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/iframes/postMessageToIframe.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/iframes/postMessageValidation.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/processErrors.test.ts (99%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/processErrors.ts (95%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/tabbing/tabScenarioACH.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/tabbing/tabScenarioCreditCard.ts (95%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/tabbing/tabScenarioGiftCard.ts (91%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => CSF}/utils/tabbing/tabScenarioKCP.ts (95%) rename packages/lib/src/components/internal/SecuredFields/lib/{ui/domUtils.ts => CSF/utils/tabbing/utils.ts} (79%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => CSF/utils}/userAgent.ts (100%) delete mode 100644 packages/lib/src/components/internal/SecuredFields/lib/core/utils/handleBinValue.ts delete mode 100644 packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleFocus.ts delete mode 100644 packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleIframeConfigFeedback.ts delete mode 100644 packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageToAllIframes.ts delete mode 100644 packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/setFocusOnFrame.ts delete mode 100644 packages/lib/src/components/internal/SecuredFields/lib/index.ts rename packages/lib/src/components/internal/SecuredFields/lib/{core => securedField}/AbstractSecuredField.ts (90%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => securedField}/SecuredField.test.ts (99%) rename packages/lib/src/components/internal/SecuredFields/lib/{core => securedField}/SecuredField.ts (96%) rename packages/lib/src/components/internal/SecuredFields/lib/{utilities => securedField/utils}/createIframe.ts (100%) rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils/init => securedField/utils}/processAriaConfig.ts (90%) rename packages/lib/src/components/internal/SecuredFields/lib/{core/utils/init => securedField/utils}/processPlaceholders.ts (85%) diff --git a/packages/lib/src/components/Ach/components/AchInput/AchInput.tsx b/packages/lib/src/components/Ach/components/AchInput/AchInput.tsx index e63bb2d2e1..9ece2d2d6c 100644 --- a/packages/lib/src/components/Ach/components/AchInput/AchInput.tsx +++ b/packages/lib/src/components/Ach/components/AchInput/AchInput.tsx @@ -2,7 +2,7 @@ import { h } from 'preact'; import { useState, useEffect, useRef } from 'preact/hooks'; import classNames from 'classnames'; import AchSecuredFields from './components/AchSecuredFields'; -import SecuredFieldsProvider from '../../../../components/internal/SecuredFields/SecuredFieldsProvider'; +import SecuredFieldsProvider from '../../../internal/SecuredFields/SFP/SecuredFieldsProvider'; import Address from '../../../internal/Address'; import { renderFormField } from '../../../internal/FormFields'; import Field from '../../../internal/FormFields/Field'; diff --git a/packages/lib/src/components/Card/components/CardInput/CardInput.test.tsx b/packages/lib/src/components/Card/components/CardInput/CardInput.test.tsx index b143ffcba3..999893fd41 100644 --- a/packages/lib/src/components/Card/components/CardInput/CardInput.test.tsx +++ b/packages/lib/src/components/Card/components/CardInput/CardInput.test.tsx @@ -5,7 +5,7 @@ import Language from '../../../../language/Language'; import { CardInputDataState, CardInputValidState } from './types'; import { render, screen, fireEvent } from '@testing-library/preact'; -jest.mock('../../../internal/SecuredFields/lib'); +jest.mock('../../../internal/SecuredFields/lib/CSF'); let valid = {} as CardInputValidState; let data = {} as CardInputDataState; diff --git a/packages/lib/src/components/Card/components/CardInput/CardInput.tsx b/packages/lib/src/components/Card/components/CardInput/CardInput.tsx index 153fc55462..38a6ca7ecc 100644 --- a/packages/lib/src/components/Card/components/CardInput/CardInput.tsx +++ b/packages/lib/src/components/Card/components/CardInput/CardInput.tsx @@ -1,6 +1,6 @@ import { h } from 'preact'; import { useState, useEffect, useRef, useMemo } from 'preact/hooks'; -import SecuredFieldsProvider, { SFPState } from '../../../internal/SecuredFields/SecuredFieldsProvider'; +import SecuredFieldsProvider, { SFPState } from '../../../internal/SecuredFields/SFP/SecuredFieldsProvider'; import defaultProps from './defaultProps'; import defaultStyles from './defaultStyles'; import styles from './CardInput.module.scss'; diff --git a/packages/lib/src/components/Card/components/CardInput/components/types.ts b/packages/lib/src/components/Card/components/CardInput/components/types.ts index 70acd7e7a7..8e5b767722 100644 --- a/packages/lib/src/components/Card/components/CardInput/components/types.ts +++ b/packages/lib/src/components/Card/components/CardInput/components/types.ts @@ -1,7 +1,7 @@ import { PaymentAmount } from '../../../../../types'; import { CardBrandsConfiguration } from '../../../types'; import { ComponentChildren } from 'preact'; -import { CVCPolicyType, DatePolicyType } from '../../../../internal/SecuredFields/lib/core/AbstractSecuredField'; +import { CVCPolicyType, DatePolicyType } from '../../../../internal/SecuredFields/lib/types'; export interface BrandIconProps { brand: string; diff --git a/packages/lib/src/components/Card/components/CardInput/types.ts b/packages/lib/src/components/Card/components/CardInput/types.ts index 8437b50d47..49a341a004 100644 --- a/packages/lib/src/components/Card/components/CardInput/types.ts +++ b/packages/lib/src/components/Card/components/CardInput/types.ts @@ -3,7 +3,7 @@ import { CardBrandsConfiguration, CardConfiguration, DualBrandSelectElement, Soc import { PaymentAmount } from '../../../../types'; import { InstallmentOptions } from './components/types'; import { ValidationResult } from '../../../internal/PersonalDetails/types'; -import { CVCPolicyType, DatePolicyType } from '../../../internal/SecuredFields/lib/core/AbstractSecuredField'; +import { CVCPolicyType, DatePolicyType } from '../../../internal/SecuredFields/lib/types'; import { ValidationRuleResult } from '../../../../utils/Validator/Validator'; import Specifications from '../../../internal/Address/Specifications'; import { AddressSchema, StringObject } from '../../../internal/Address/types'; diff --git a/packages/lib/src/components/Card/types.ts b/packages/lib/src/components/Card/types.ts index 7de9acb914..e60fb180cc 100644 --- a/packages/lib/src/components/Card/types.ts +++ b/packages/lib/src/components/Card/types.ts @@ -10,7 +10,7 @@ import { CbObjOnLoad, CbObjOnBinLookup } from '../internal/SecuredFields/lib/types'; -import { CVCPolicyType, DatePolicyType } from '../internal/SecuredFields/lib/core/AbstractSecuredField'; +import { CVCPolicyType, DatePolicyType } from '../internal/SecuredFields/lib/types'; export interface CardElementProps extends UIElementProps { /** diff --git a/packages/lib/src/components/Giftcard/components/GiftcardComponent.tsx b/packages/lib/src/components/Giftcard/components/GiftcardComponent.tsx index 3101ab8a75..81e48b16d5 100644 --- a/packages/lib/src/components/Giftcard/components/GiftcardComponent.tsx +++ b/packages/lib/src/components/Giftcard/components/GiftcardComponent.tsx @@ -1,6 +1,6 @@ import { Component, h } from 'preact'; import classNames from 'classnames'; -import SecuredFieldsProvider from '../../../components/internal/SecuredFields/SecuredFieldsProvider'; +import SecuredFieldsProvider from '../../internal/SecuredFields/SFP/SecuredFieldsProvider'; import Field from '../../internal/FormFields/Field'; import Alert from '../../internal/Alert'; import GiftcardResult from './GiftcardResult'; diff --git a/packages/lib/src/components/SecuredFields/SecuredFieldsInput/SecuredFieldsInput.tsx b/packages/lib/src/components/SecuredFields/SecuredFieldsInput/SecuredFieldsInput.tsx index e2a364b8d6..c2bdadc29e 100644 --- a/packages/lib/src/components/SecuredFields/SecuredFieldsInput/SecuredFieldsInput.tsx +++ b/packages/lib/src/components/SecuredFields/SecuredFieldsInput/SecuredFieldsInput.tsx @@ -1,7 +1,7 @@ import { h } from 'preact'; import { useState, useEffect, useRef, useMemo } from 'preact/hooks'; import Language from '../../../language/Language'; -import SecuredFieldsProvider, { SFPState } from '../../internal/SecuredFields/SecuredFieldsProvider'; +import SecuredFieldsProvider, { SFPState } from '../../internal/SecuredFields/SFP/SecuredFieldsProvider'; import { BinLookupResponse } from '../../Card/types'; import SFExtensions from '../../internal/SecuredFields/binLookup/extensions'; diff --git a/packages/lib/src/components/internal/SecuredFields/SFP/SFPUtils.ts b/packages/lib/src/components/internal/SecuredFields/SFP/SFPUtils.ts new file mode 100644 index 0000000000..2901a019cf --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/SFP/SFPUtils.ts @@ -0,0 +1,108 @@ +// ROUTINES USED IN SecuredFieldsProvider.componentDidMount TO DETECT & MAP FIELD NAMES /////////// +import { + CVC_POLICY_HIDDEN, + CVC_POLICY_OPTIONAL, + DATE_POLICY_HIDDEN, + DATE_POLICY_OPTIONAL, + ENCRYPTED_EXPIRY_DATE, + ENCRYPTED_EXPIRY_MONTH, + ENCRYPTED_EXPIRY_YEAR, + ENCRYPTED_SECURITY_CODE +} from '../lib/configuration/constants'; +import getProp from '../../../../utils/getProp'; +import { DEFAULT_ERROR } from '../../../../core/Errors/constants'; + +/** + * Make an array of encrypted field names based on the value of the 'data-cse' attribute of elements in the rootNode + */ +export const getFields = rootNode => { + if (rootNode) { + return Array.prototype.slice.call(rootNode.querySelectorAll('[data-cse*="encrypted"]')).map(f => f.getAttribute('data-cse')); + } + return []; +}; + +/** + * If, visually, we're dealing with a single date field (expiryDate) we still need separate entries + * for expiryMonth & expiryYear - since that is how the values will be delivered from securedFields + */ +export const validFieldsReducer = (acc, cur) => { + if (cur === ENCRYPTED_EXPIRY_DATE) { + acc[ENCRYPTED_EXPIRY_MONTH] = false; + acc[ENCRYPTED_EXPIRY_YEAR] = false; + } else { + acc[cur] = false; + } + + return acc; +}; +// -- end ROUTINES USED IN SecuredFieldsProvider.componentDidMount -------------------------------- + +// ROUTINES USED IN SecuredFieldsProvider.showValidation TO GENERATE ERRORS /////////// +/** + * If, visually, we're dealing with a single date field (expiryDate) remap the separate entries we have + * for the valid states of expiryMonth & expiryYear back to the single key we use to an store an error + * i.e `"encryptedExpiryMonth" & "encryptedExpiryYear" => "encryptedExpiryDate"` + */ +const mapDateFields = (field, numDateFields) => { + const isDateField = field === ENCRYPTED_EXPIRY_MONTH || field === ENCRYPTED_EXPIRY_YEAR; + return numDateFields === 1 && isDateField ? ENCRYPTED_EXPIRY_DATE : field; +}; + +/** + * Skip generating an error for an optional field, unless it is already in error + */ +const skipOptionalFields = (field, state, fieldNames) => { + // console.log('\n### utils::skipOptionalField3:: examining field=', field); + const { isFieldOfType, fieldIsValid } = fieldNames.reduce( + (acc, fieldName) => { + if (!acc.isFieldOfType) { + // console.log('### utils:: fieldName:: ', fieldName, 'match=', field === fieldName); + acc.isFieldOfType = field === fieldName; + acc.fieldIsValid = !state.errors[fieldName]; + } + return acc; + }, + { isFieldOfType: false, fieldIsValid: false } + ); + + const policyType = field === ENCRYPTED_SECURITY_CODE ? 'cvcPolicy' : 'expiryDatePolicy'; + + const policyOptional = policyType === 'cvcPolicy' ? CVC_POLICY_OPTIONAL : DATE_POLICY_OPTIONAL; + const policyHidden = policyType === 'cvcPolicy' ? CVC_POLICY_HIDDEN : DATE_POLICY_HIDDEN; + + // if policy != required + return (state[policyType] === policyOptional || state[policyType] === policyHidden) && fieldIsValid && isFieldOfType ? null : field; +}; + +export const getErrorReducer = (numDateFields, state) => (acc, field) => { + // We're only interested in the non-valid fields from the state.valid object... + let val = + state.valid[field] !== true + ? mapDateFields(field, numDateFields) // Map the keys we use for the valid state to the key(s) we use for the error state + : null; + + // Skip error generation for optional/hidden CVC & Date unless the fields are already in error + val = skipOptionalFields(val, state, [ENCRYPTED_SECURITY_CODE, ENCRYPTED_EXPIRY_DATE, ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR]); + + // console.log('### utils:::: ############# val=', val); + + if (val && !acc.includes(val)) acc.push(val); + + return acc; +}; + +/** + * Create an object suitable for sending to our handleOnError function + */ +export const getErrorObject = (fieldType, rootNode, state) => { + const error = getProp(state, `errors.${fieldType}`) || DEFAULT_ERROR; + + return { + rootNode, + fieldType, + error, + type: 'card' + }; +}; +// -- end ROUTINES USED IN SecuredFieldsProvider.showValidation ----------------------- diff --git a/packages/lib/src/components/internal/SecuredFields/SecuredFieldsProvider.test.tsx b/packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProvider.test.tsx similarity index 97% rename from packages/lib/src/components/internal/SecuredFields/SecuredFieldsProvider.test.tsx rename to packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProvider.test.tsx index a089b6b5ac..12941965dd 100644 --- a/packages/lib/src/components/internal/SecuredFields/SecuredFieldsProvider.test.tsx +++ b/packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProvider.test.tsx @@ -1,11 +1,11 @@ import { shallow } from 'enzyme'; import { h } from 'preact'; import SecuredFieldsProvider from './SecuredFieldsProvider'; -import Language from '../../../language/Language'; -import { ERROR_CODES, ERROR_MSG_INCOMPLETE_FIELD, ERROR_MSG_UNSUPPORTED_CARD_ENTERED, ERROR_MSG_CLEARED } from '../../../core/Errors/constants'; -import { getError } from '../../../core/Errors/utils'; +import Language from '../../../../language/Language'; +import { ERROR_CODES, ERROR_MSG_INCOMPLETE_FIELD, ERROR_MSG_UNSUPPORTED_CARD_ENTERED, ERROR_MSG_CLEARED } from '../../../../core/Errors/constants'; +import { getError } from '../../../../core/Errors/utils'; -jest.mock('./lib', () => { +jest.mock('../lib/CSF', () => { return () => true; }); diff --git a/packages/lib/src/components/internal/SecuredFields/SecuredFieldsProvider.ts b/packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProvider.ts similarity index 96% rename from packages/lib/src/components/internal/SecuredFields/SecuredFieldsProvider.ts rename to packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProvider.ts index 307a418083..8175e6d9e8 100644 --- a/packages/lib/src/components/internal/SecuredFields/SecuredFieldsProvider.ts +++ b/packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProvider.ts @@ -1,11 +1,9 @@ import { Component } from 'preact'; -import { getErrorObject, getFields, getErrorReducer, validFieldsReducer } from './utils'; -import initCSF from './lib'; +import { getErrorObject, getFields, getErrorReducer, validFieldsReducer } from './SFPUtils'; +import initCSF from '../lib/CSF'; import handlers from './SecuredFieldsProviderHandlers'; import defaultProps, { SFPProps } from './defaultProps'; import { - CSFReturnObject, - CSFSetupObject, StylesObject, CbObjOnError, CbObjOnFocus, @@ -15,12 +13,13 @@ import { CbObjOnAutoComplete, CbObjOnConfigSuccess, CbObjOnLoad -} from './lib/types'; -import { AddressData } from '../../../types'; -import { CVC_POLICY_REQUIRED, DATE_POLICY_REQUIRED, ENCRYPTED_CARD_NUMBER, ENCRYPTED_PWD_FIELD } from './lib/configuration/constants'; -import { BinLookupResponse } from '../../Card/types'; -import { CVCPolicyType, DatePolicyType } from './lib/core/AbstractSecuredField'; -import { getError } from '../../../core/Errors/utils'; +} from '../lib/types'; +import { CSFReturnObject, CSFSetupObject } from '../lib/CSF/types'; +import { AddressData } from '../../../../types'; +import { CVC_POLICY_REQUIRED, DATE_POLICY_REQUIRED, ENCRYPTED_CARD_NUMBER, ENCRYPTED_PWD_FIELD } from '../lib/configuration/constants'; +import { BinLookupResponse } from '../../../Card/types'; +import { CVCPolicyType, DatePolicyType } from '../lib/types'; +import { getError } from '../../../../core/Errors/utils'; export interface SFPState { status?: string; diff --git a/packages/lib/src/components/internal/SecuredFields/SecuredFieldsProviderHandlers.ts b/packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProviderHandlers.ts similarity index 98% rename from packages/lib/src/components/internal/SecuredFields/SecuredFieldsProviderHandlers.ts rename to packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProviderHandlers.ts index 79e5b79899..e7e0aa1a4d 100644 --- a/packages/lib/src/components/internal/SecuredFields/SecuredFieldsProviderHandlers.ts +++ b/packages/lib/src/components/internal/SecuredFields/SFP/SecuredFieldsProviderHandlers.ts @@ -1,4 +1,4 @@ -import { getCardImageUrl } from './utils'; +import { getCardImageUrl } from '../utils'; import { ENCRYPTED_SECURITY_CODE, ENCRYPTED_CARD_NUMBER, @@ -9,7 +9,7 @@ import { HIDDEN, ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR -} from './lib/configuration/constants'; +} from '../lib/configuration/constants'; import { CbObjOnError, CbObjOnFocus, @@ -19,8 +19,8 @@ import { CbObjOnAutoComplete, CbObjOnConfigSuccess, CbObjOnLoad -} from './lib/types'; -import { existy } from './lib/utilities/commonUtils'; +} from '../lib/types'; +import { existy } from '../lib/utilities/commonUtils'; /** * Emits the onConfigSuccess (ready) event diff --git a/packages/lib/src/components/internal/SecuredFields/defaultProps.ts b/packages/lib/src/components/internal/SecuredFields/SFP/defaultProps.ts similarity index 95% rename from packages/lib/src/components/internal/SecuredFields/defaultProps.ts rename to packages/lib/src/components/internal/SecuredFields/SFP/defaultProps.ts index f66306f830..51bbef315c 100644 --- a/packages/lib/src/components/internal/SecuredFields/defaultProps.ts +++ b/packages/lib/src/components/internal/SecuredFields/SFP/defaultProps.ts @@ -1,5 +1,5 @@ -import { Language } from '../../../language/Language'; -import { CVCPolicyType } from './lib/core/AbstractSecuredField'; +import { Language } from '../../../../language/Language'; +import { CVCPolicyType } from '../lib/types'; export interface SFPProps { /** diff --git a/packages/lib/src/components/internal/SecuredFields/binLookup/extensions.ts b/packages/lib/src/components/internal/SecuredFields/binLookup/extensions.ts index 7d72be811c..ccc914d903 100644 --- a/packages/lib/src/components/internal/SecuredFields/binLookup/extensions.ts +++ b/packages/lib/src/components/internal/SecuredFields/binLookup/extensions.ts @@ -1,4 +1,4 @@ -import { SingleBrandResetObject } from '../SecuredFieldsProvider'; +import { SingleBrandResetObject } from '../SFP/SecuredFieldsProvider'; import { BrandObject } from '../../../Card/types'; import createCardVariantSwitcher from './createCardVariantSwitcher'; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/AbstractCSF.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/AbstractCSF.ts similarity index 82% rename from packages/lib/src/components/internal/SecuredFields/lib/core/AbstractCSF.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/AbstractCSF.ts index 7cb09304b6..53147671f0 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/AbstractCSF.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/AbstractCSF.ts @@ -1,7 +1,8 @@ -import { CSFSetupObject, CSFConfigObject, CSFCallbacksConfig, CSFStateObject, SFFeedbackObj, SendBrandObject, SendExpiryDateObject } from '../types'; -import { createSecuredFields } from './createSecuredFields'; -import { handleProcessBrand } from './utils/processBrand'; -import { handleBrandFromBinLookup } from './utils/handleBrandFromBinLookup'; +import { CSFSetupObject, CSFConfigObject, CSFCallbacksConfig, CSFStateObject } from './types'; +import { SFFeedbackObj, SendBrandObject, SendExpiryDateObject } from '../types'; +import { createSecuredFields } from './extensions/createSecuredFields'; +import processBrand from './partials/processBrand'; +import handleBrandFromBinLookup from './extensions/handleBrandFromBinLookup'; abstract class AbstractCSF { // Set in CSF @@ -9,8 +10,8 @@ abstract class AbstractCSF { protected config: CSFConfigObject; protected props: CSFSetupObject; protected state: CSFStateObject; - protected assessFormValidity: () => void; - protected brandsFromBinLookup: typeof handleBrandFromBinLookup; + protected validateForm: () => void; + protected handleBrandFromBinLookup: typeof handleBrandFromBinLookup; protected callbacksHandler: (callbacksObj: object) => void; protected configHandler: () => void; protected createCardSecuredFields: (securedFields: HTMLElement[]) => number; @@ -29,7 +30,7 @@ abstract class AbstractCSF { protected isConfigured: () => void; protected postMessageToAllIframes: (pDataObj: object) => void; protected processAutoComplete: (pFeedbackObj: SFFeedbackObj) => void; - protected processBrand: typeof handleProcessBrand; + protected processBrand: typeof processBrand; protected sendBrandToCardSF: (brandObj: SendBrandObject) => void; protected sendExpiryDatePolicyToSF: (dateObj: SendExpiryDateObject) => void; protected setFocusOnFrame: (pFieldType: string, doLog?: boolean) => void; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/CSF.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/CSF.ts similarity index 73% rename from packages/lib/src/components/internal/SecuredFields/lib/core/CSF.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/CSF.ts index 1a8d758bde..5e9a2b4c9d 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/CSF.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/CSF.ts @@ -1,27 +1,30 @@ -import { handleConfig } from '../configuration/handleConfig'; -import { configureCallbacks } from '../configuration/configureCallbacks'; -import { handleProcessBrand } from './utils/processBrand'; -import { handleValidation } from './handleValidation'; -import { handleEncryption } from './handleEncryption'; -import { createSecuredFields, createNonCardSecuredFields, createCardSecuredFields, setupSecuredField } from './createSecuredFields'; -import { setFocusOnFrame } from './utils/iframes/setFocusOnFrame'; -import { postMessageToAllIframes } from './utils/iframes/postMessageToAllIframes'; -import { destroySecuredFields } from './destroySecuredFields'; -import { processAutoComplete } from './utils/processAutoComplete'; -import { handleFocus } from './utils/iframes/handleFocus'; -import { handleIframeConfigFeedback } from './utils/iframes/handleIframeConfigFeedback'; -import { isConfigured } from './utils/isConfigured'; -import { assessFormValidity } from './utils/validateForm'; -import { handleBinValue } from './utils/handleBinValue'; -import { handleBrandFromBinLookup, sendBrandToCardSF, sendExpiryDatePolicyToSF } from './utils/handleBrandFromBinLookup'; -import handleAdditionalFields from './utils/registerAdditionalField'; -import tabHandlers from './utils/tabbing/handleTab'; -import postMessageToIframe from './utils/iframes/postMessageToIframe'; import AbstractCSF from './AbstractCSF'; -import { CSFReturnObject, CSFSetupObject, StylesObject, CbObjOnAdditionalSF, CSFStateObject } from '../types'; +import { CSFReturnObject, CSFSetupObject, CSFStateObject } from './types'; +import { StylesObject, CbObjOnAdditionalSF } from '../types'; +import { BinLookupResponse } from '../../../../Card/types'; +import { handleConfig } from './extensions/handleConfig'; +import { configureCallbacks } from './extensions/configureCallbacks'; +import { handleValidation } from './extensions/handleValidation'; +import { handleEncryption } from './extensions/handleEncryption'; +import { createSecuredFields, createNonCardSecuredFields, createCardSecuredFields, setupSecuredField } from './extensions/createSecuredFields'; +import additionalFields from './extensions/additionalFields'; +import handleTab from './extensions/handleTab'; +import handleBrandFromBinLookup, { sendBrandToCardSF, sendExpiryDatePolicyToSF } from './extensions/handleBrandFromBinLookup'; +import { setFocusOnFrame } from './partials/setFocusOnFrame'; +import { postMessageToAllIframes } from './partials/postMessageToAllIframes'; +import processBrand from './partials/processBrand'; +import { processAutoComplete } from './partials/processAutoComplete'; +import { handleFocus } from './partials/handleFocus'; +import { handleIframeConfigFeedback } from './partials/handleIframeConfigFeedback'; +import { isConfigured } from './partials/isConfigured'; +import validateForm from './partials/validateForm'; +import { handleBinValue } from './partials/handleBinValue'; +import { destroySecuredFields } from './utils/destroySecuredFields'; +import postMessageToIframe from './utils/iframes/postMessageToIframe'; +import getIframeContentWin from './utils/iframes/getIframeContentWin'; import * as logger from '../utilities/logger'; import { selectOne } from '../utilities/dom'; -import { BinLookupResponse } from '../../../../Card/types'; +import { partial } from '../utilities/commonUtils'; import { hasOwnProperty } from '../../../../../utils/hasOwnProperty'; const notConfiguredWarning = (str = 'You cannot use secured fields') => { @@ -58,17 +61,19 @@ class CSF extends AbstractCSF { isKCP: false } as CSFStateObject; + const thisObj = { csfState: this.state, csfConfig: this.config, csfProps: this.props, csfCallbacks: this.callbacks }; + // Setup 'this' references this.configHandler = handleConfig; this.callbacksHandler = configureCallbacks; - this.handleIframeConfigFeedback = handleIframeConfigFeedback; - this.isConfigured = isConfigured; + this.validateForm = partial(validateForm, thisObj); - this.assessFormValidity = assessFormValidity; + this.isConfigured = partial(isConfigured, thisObj, this.validateForm); + this.handleIframeConfigFeedback = partial(handleIframeConfigFeedback, thisObj, this.isConfigured); - this.processBrand = handleProcessBrand; + this.processBrand = partial(processBrand, thisObj); this.handleValidation = handleValidation; this.handleEncryption = handleEncryption; @@ -78,25 +83,25 @@ class CSF extends AbstractCSF { this.createCardSecuredFields = createCardSecuredFields; this.setupSecuredField = setupSecuredField; - this.postMessageToAllIframes = postMessageToAllIframes; + this.postMessageToAllIframes = partial(postMessageToAllIframes, thisObj); - this.setFocusOnFrame = setFocusOnFrame; - this.handleFocus = handleFocus; + this.setFocusOnFrame = partial(setFocusOnFrame, thisObj); + this.handleFocus = partial(handleFocus, thisObj); - this.handleAdditionalFields = handleAdditionalFields.handleAdditionalFields; - this.touchendListener = handleAdditionalFields.touchendListener.bind(this); - this.destroyTouchendListener = handleAdditionalFields.destroyTouchendListener; + this.handleAdditionalFields = additionalFields.handleAdditionalFields; + this.touchendListener = additionalFields.touchendListener.bind(this); + this.destroyTouchendListener = additionalFields.destroyTouchendListener; - this.handleSFShiftTab = tabHandlers.handleSFShiftTab; - this.handleShiftTab = tabHandlers.handleShiftTab; + this.handleSFShiftTab = handleTab.handleSFShiftTab; + this.handleShiftTab = handleTab.handleShiftTab; this.destroySecuredFields = destroySecuredFields; - this.processAutoComplete = processAutoComplete; + this.processAutoComplete = partial(processAutoComplete, thisObj); - this.handleBinValue = handleBinValue; + this.handleBinValue = partial(handleBinValue, thisObj); - this.brandsFromBinLookup = handleBrandFromBinLookup; + this.handleBrandFromBinLookup = handleBrandFromBinLookup; this.sendBrandToCardSF = sendBrandToCardSF; this.sendExpiryDatePolicyToSF = sendExpiryDatePolicyToSF; @@ -162,7 +167,7 @@ class CSF extends AbstractCSF { code, numKey: this.state.securedFields[pFieldType].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(pFieldType), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(this.state, pFieldType), this.config.loadingContext); } } else { notConfiguredWarning('You cannot set validated on any secured field'); @@ -183,7 +188,7 @@ class CSF extends AbstractCSF { code, numKey: this.state.securedFields[pFieldType].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(pFieldType), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(this.state, pFieldType), this.config.loadingContext); } } else { notConfiguredWarning('You cannot set hasUnsupportedCard on any secured field'); @@ -200,7 +205,7 @@ class CSF extends AbstractCSF { if (!this.config.isCreditCardType) return null; if (this.state.isConfigured) { - this.brandsFromBinLookup(binLookupResponse); + this.handleBrandFromBinLookup(binLookupResponse); } else { notConfiguredWarning('You cannot set pass brands to secured fields'); } @@ -229,13 +234,6 @@ class CSF extends AbstractCSF { return returnObj; } - - /** - * Retrieves the iframe, stored by field type, & returns it's contentWindow - */ - private getIframeContentWin(fieldType: string): Window { - return this.state.securedFields[fieldType]?.iframeContentWindow || null; - } } export default CSF; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/registerAdditionalField.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/additionalFields.ts similarity index 98% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/registerAdditionalField.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/additionalFields.ts index 4ed92086cd..8afbec4e8c 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/registerAdditionalField.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/additionalFields.ts @@ -1,5 +1,5 @@ import { on, off, selectOne } from '../../utilities/dom'; -import ua from '../../utilities/userAgent'; +import ua from '../utils/userAgent'; import * as logger from '../../utilities/logger'; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/configuration/configureCallbacks.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/configureCallbacks.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/configuration/configureCallbacks.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/configureCallbacks.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/createSecuredFields.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/createSecuredFields.ts similarity index 94% rename from packages/lib/src/components/internal/SecuredFields/lib/core/createSecuredFields.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/createSecuredFields.ts index 7277f6872f..f6ae459660 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/createSecuredFields.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/createSecuredFields.ts @@ -1,4 +1,4 @@ -import { select, getAttribute } from '../utilities/dom'; +import { select, getAttribute } from '../../utilities/dom'; import { ENCRYPTED_EXPIRY_YEAR, DATE_POLICY_REQUIRED, @@ -6,13 +6,13 @@ import { DATA_ENCRYPTED_FIELD_ATTR, DATA_INFO, DATA_UID -} from '../configuration/constants'; -import { existy } from '../utilities/commonUtils'; -import cardType from '../utilities/cardType'; -import { CVCPolicyType, SFSetupObject } from './AbstractSecuredField'; -import SecuredField from './SecuredField'; -import { CardObject, CbObjOnBrand, SFFeedbackObj, CbObjOnLoad } from '../types'; -import * as logger from '../utilities/logger'; +} from '../../configuration/constants'; +import { existy } from '../../utilities/commonUtils'; +import cardType from '../utils/cardType'; +import { SFSetupObject } from '../../securedField/AbstractSecuredField'; +import SecuredField from '../../securedField/SecuredField'; +import { CardObject, CbObjOnBrand, SFFeedbackObj, CbObjOnLoad, CVCPolicyType } from '../../types'; +import * as logger from '../../utilities/logger'; /** * cvcPolicy - 'required' | 'optional' | 'hidden' diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/handleBrandFromBinLookup.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleBrandFromBinLookup.ts similarity index 91% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/handleBrandFromBinLookup.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleBrandFromBinLookup.ts index 0c4414f207..a875ceeebd 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/handleBrandFromBinLookup.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleBrandFromBinLookup.ts @@ -7,10 +7,11 @@ import { ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR } from '../../configuration/constants'; -import postMessageToIframe from './iframes/postMessageToIframe'; +import postMessageToIframe from '../utils/iframes/postMessageToIframe'; import { SFFeedbackObj, SendBrandObject, SendExpiryDateObject } from '../../types'; import { BinLookupResponse, BrandObject } from '../../../../../Card/types'; import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; +import getIframeContentWin from '../utils/iframes/getIframeContentWin'; export function sendBrandToCardSF(brandObj: SendBrandObject): void { if (hasOwnProperty(this.state.securedFields, ENCRYPTED_CARD_NUMBER)) { @@ -20,7 +21,7 @@ export function sendBrandToCardSF(brandObj: SendBrandObject): void { fieldType: ENCRYPTED_CARD_NUMBER, numKey: this.state.securedFields[ENCRYPTED_CARD_NUMBER].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(ENCRYPTED_CARD_NUMBER), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(this.state, ENCRYPTED_CARD_NUMBER), this.config.loadingContext); } } @@ -37,11 +38,11 @@ export function sendExpiryDatePolicyToSF(expiryDateObj: SendExpiryDateObject): v fieldType: key, numKey: this.state.securedFields[key].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(key), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(this.state, key), this.config.loadingContext); }); } -export function handleBrandFromBinLookup(binLookupResponse: BinLookupResponse): void { +export default function handleBrandFromBinLookup(binLookupResponse: BinLookupResponse): void { const isGenericCard: boolean = this.state.type === 'card'; /** @@ -59,6 +60,7 @@ export function handleBrandFromBinLookup(binLookupResponse: BinLookupResponse): if (this.state.type === 'card' && hasOwnProperty(this.state.securedFields, ENCRYPTED_EXPIRY_DATE)) { this.state.securedFields[ENCRYPTED_EXPIRY_DATE].expiryDatePolicy = DATE_POLICY_REQUIRED; } + return; } @@ -118,5 +120,5 @@ export function handleBrandFromBinLookup(binLookupResponse: BinLookupResponse): /** * ...and now re-check if form i.e all the SecuredFields, are valid */ - this.assessFormValidity(); + this.validateForm(); } diff --git a/packages/lib/src/components/internal/SecuredFields/lib/configuration/handleConfig.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleConfig.ts similarity index 96% rename from packages/lib/src/components/internal/SecuredFields/lib/configuration/handleConfig.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleConfig.ts index 4678bcbcfd..179d2affff 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/configuration/handleConfig.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleConfig.ts @@ -1,6 +1,6 @@ -import { getCardGroupTypes } from '../core/utils/getCardGroupTypes'; -import { NON_CREDIT_CARD_TYPE_SECURED_FIELDS, SF_VERSION } from './constants'; -import * as logger from '../utilities/logger'; +import { getCardGroupTypes } from '../utils/getCardGroupTypes'; +import { NON_CREDIT_CARD_TYPE_SECURED_FIELDS, SF_VERSION } from '../../configuration/constants'; +import * as logger from '../../utilities/logger'; /** * Parses this.props to set 'config' type vars on this (CSFComp) diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/handleEncryption.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleEncryption.ts similarity index 81% rename from packages/lib/src/components/internal/SecuredFields/lib/core/handleEncryption.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleEncryption.ts index fdd1707991..823074b46c 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/handleEncryption.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleEncryption.ts @@ -1,11 +1,12 @@ -import { makeCallbackObjectsEncryption } from './utils/callbackUtils'; -import { addEncryptedElements } from '../ui/encryptedElements'; -import { ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR, ENCRYPTED_SECURITY_CODE, ENCRYPTED_CARD_NUMBER } from '../configuration/constants'; -import { processErrors } from './utils/processErrors'; -import { truthy } from '../utilities/commonUtils'; -import { SFFeedbackObj, CbObjOnFieldValid, EncryptionObj } from '../types'; -import postMessageToIframe from './utils/iframes/postMessageToIframe'; -import { hasOwnProperty } from '../../../../../utils/hasOwnProperty'; +import { makeCallbackObjectsEncryption } from '../utils/callbackUtils'; +import { addEncryptedElements } from '../utils/encryptedElements'; +import { ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR, ENCRYPTED_SECURITY_CODE, ENCRYPTED_CARD_NUMBER } from '../../configuration/constants'; +import { processErrors } from '../utils/processErrors'; +import { truthy } from '../../utilities/commonUtils'; +import { SFFeedbackObj, CbObjOnFieldValid, EncryptionObj } from '../../types'; +import postMessageToIframe from '../utils/iframes/postMessageToIframe'; +import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; +import getIframeContentWin from '../utils/iframes/getIframeContentWin'; export function handleEncryption(pFeedbackObj: SFFeedbackObj): void { // EXTRACT VARS @@ -64,7 +65,7 @@ export function handleEncryption(pFeedbackObj: SFFeedbackObj): void { fieldType: ENCRYPTED_EXPIRY_YEAR, numKey: this.state.securedFields[ENCRYPTED_EXPIRY_YEAR].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(ENCRYPTED_EXPIRY_YEAR), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(this.state, ENCRYPTED_EXPIRY_YEAR), this.config.loadingContext); } } @@ -80,5 +81,5 @@ export function handleEncryption(pFeedbackObj: SFFeedbackObj): void { //-------------------------------------------- // STORE & BROADCAST VALID STATE OF THE FORM AS A WHOLE /////// - this.assessFormValidity(); + this.validateForm(); } diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/handleTab.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleTab.ts similarity index 83% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/handleTab.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleTab.ts index bbf4416aa6..653824ee42 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/handleTab.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleTab.ts @@ -1,10 +1,10 @@ -import ua from '../../../utilities/userAgent'; -import * as logger from '../../../utilities/logger'; -import { shiftTabCreditCard } from './tabScenarioCreditCard'; -import { shiftTabACH } from './tabScenarioACH'; -import { shiftTabGiftCard } from './tabScenarioGiftCard'; -import { shiftTabKCP } from './tabScenarioKCP'; -import { ShiftTabObject } from '../../../types'; +import ua from '../utils/userAgent'; +import * as logger from '../../utilities/logger'; +import { shiftTabCreditCard } from '../utils/tabbing/tabScenarioCreditCard'; +import { shiftTabACH } from '../utils/tabbing/tabScenarioACH'; +import { shiftTabGiftCard } from '../utils/tabbing/tabScenarioGiftCard'; +import { shiftTabKCP } from '../utils/tabbing/tabScenarioKCP'; +import { ShiftTabObject } from '../../types'; const logTab = false; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/handleValidation.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleValidation.ts similarity index 85% rename from packages/lib/src/components/internal/SecuredFields/lib/core/handleValidation.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleValidation.ts index 114e0fc486..6ee41aaf3d 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/handleValidation.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/extensions/handleValidation.ts @@ -1,10 +1,10 @@ -import { makeCallbackObjectsValidation } from './utils/callbackUtils'; -import { removeEncryptedElement } from '../ui/encryptedElements'; -import { processErrors } from './utils/processErrors'; -import { existy } from '../utilities/commonUtils'; -import { ENCRYPTED_SECURITY_CODE, ENCRYPTED_CARD_NUMBER } from '../configuration/constants'; -import { SFFeedbackObj, CbObjOnFieldValid } from '../types'; -import { hasOwnProperty } from '../../../../../utils/hasOwnProperty'; +import { makeCallbackObjectsValidation } from '../utils/callbackUtils'; +import { removeEncryptedElement } from '../utils/encryptedElements'; +import { processErrors } from '../utils/processErrors'; +import { existy } from '../../utilities/commonUtils'; +import { ENCRYPTED_SECURITY_CODE, ENCRYPTED_CARD_NUMBER } from '../../configuration/constants'; +import { SFFeedbackObj, CbObjOnFieldValid } from '../../types'; +import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; export function handleValidation(pFeedbackObj: SFFeedbackObj): void { // -- @@ -64,7 +64,7 @@ export function handleValidation(pFeedbackObj: SFFeedbackObj): void { /** * STORE & BROADCAST VALID STATE OF THE FORM AS A WHOLE */ - this.assessFormValidity(); + this.validateForm(); /** * PROCESS & BROADCAST CARD BRANDS diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/index.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/index.ts new file mode 100644 index 0000000000..84f56c5076 --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/index.ts @@ -0,0 +1,3 @@ +import csf from './initCSF'; + +export default csf; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/initCSF.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/initCSF.ts similarity index 75% rename from packages/lib/src/components/internal/SecuredFields/lib/core/initCSF.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/initCSF.ts index b04e03f17b..9b97ede1c9 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/initCSF.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/initCSF.ts @@ -1,10 +1,10 @@ import CSF from './CSF'; -import cardType from '../utilities/cardType'; +import cardType from './utils/cardType'; import * as logger from '../utilities/logger'; import { falsy } from '../utilities/commonUtils'; -import { findRootNode } from '../ui/domUtils'; -import { CSFReturnObject, CSFSetupObject } from '../types'; +import { CSFReturnObject, CSFSetupObject } from './types'; import { hasOwnProperty } from '../../../../../utils/hasOwnProperty'; +import { selectOne } from '../utilities/dom'; const initCSF = (pSetupObj: CSFSetupObject): CSFReturnObject => { if (!pSetupObj) { @@ -46,4 +46,24 @@ const initCSF = (pSetupObj: CSFSetupObject): CSFReturnObject => { return myCSF.createReturnObject(); }; +const findRootNode = pRootNode => { + let rootNode; + + // Expect to be sent the actual html node... + if (typeof pRootNode === 'object') { + rootNode = pRootNode; + } + + if (typeof pRootNode === 'string') { + // ... but if only sent a string - find it ourselves + rootNode = selectOne(document, pRootNode); + + if (!rootNode) { + return null; + } + } + + return rootNode; +}; + export default initCSF; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleBinValue.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleBinValue.ts new file mode 100644 index 0000000000..dd4a04da12 --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleBinValue.ts @@ -0,0 +1,26 @@ +import { SFFeedbackObj, CbObjOnBinValue } from '../../types'; + +interface DestructuredFeedbackObj { + binValue?: string; + encryptedBin?: string; + uuid?: string; +} + +/** + * @param csfState - comes from initial, partial, implementation + * @param csfCallbacks - comes from initial, partial, implementation + * + * @param pFeedbackObj - + */ +export function handleBinValue({ csfState, csfCallbacks }, pFeedbackObj: SFFeedbackObj): void { + const { binValue, encryptedBin, uuid }: DestructuredFeedbackObj = pFeedbackObj; + + const callbacksObj: CbObjOnBinValue = { binValue, type: csfState.type }; + + if (encryptedBin) { + callbacksObj.encryptedBin = encryptedBin; + callbacksObj.uuid = uuid; + } + + csfCallbacks.onBinValue(callbacksObj); +} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleFocus.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleFocus.ts new file mode 100644 index 0000000000..bff336583e --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleFocus.ts @@ -0,0 +1,45 @@ +import { SFFeedbackObj, CbObjOnFocus } from '../../types'; + +/** + * Call focus callback and store which field currently has focus + * + * @param csfState - comes from initial, partial, implementation + * @param csfProps - comes from initial, partial, implementation + * @param csfCallbacks - comes from initial, partial, implementation + * + * @param pFeedbackObj - + */ +export function handleFocus({ csfState, csfProps, csfCallbacks }, pFeedbackObj: SFFeedbackObj): void { + const feedbackObj: SFFeedbackObj = { ...pFeedbackObj }; + + delete feedbackObj.numKey; + + feedbackObj.rootNode = csfProps.rootNode; + feedbackObj.type = csfState.type; + + // Store which field has focus + const focusString: string = feedbackObj.fieldType; + + // Focus event - store, if this isn't the field that already has focus + if (feedbackObj.focus) { + if (csfState.currentFocusObject !== focusString) { + csfState.currentFocusObject = focusString; + + // iOS ONLY thing (fn returns if not iOS) + if (!csfState.registerFieldForIos) { + this.handleAdditionalFields(); + } + } + } else { + // Blur event - remove stored focus + const focusObjectMatches: boolean = csfState.currentFocusObject === focusString; + if (focusObjectMatches) { + csfState.currentFocusObject = null; + } + } + + // Call callback + const callbackObj: CbObjOnFocus = feedbackObj as CbObjOnFocus; + callbackObj.currentFocusObject = csfState.currentFocusObject; + csfCallbacks.onFocus(callbackObj); +} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleIframeConfigFeedback.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleIframeConfigFeedback.ts new file mode 100644 index 0000000000..1cc8bdc6c1 --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/handleIframeConfigFeedback.ts @@ -0,0 +1,49 @@ +// Count how many iframes have successfully been configured and, if its all of them, call callback function + +import { CbObjOnAdditionalSF } from '../../types'; + +// First, object, param comes from partial implementation +/** + * @param csfState - comes from initial, partial, implementation + * @param csfCallbacks - comes from initial, partial, implementation + * @param isConfigured - comes from initial, partial, implementation + * + * @param pFeedbackObj - + */ +export function handleIframeConfigFeedback({ csfState, csfCallbacks }, isConfigured, pFeedbackObj): boolean { + csfState.iframeConfigCount += 1; + + if (!csfState.isConfigured) { + if (process.env.NODE_ENV === 'development' && window._b$dl) { + console.log('\n### handleIframeConfigFeedback:: csfState.type=', csfState.type); + console.log('### handleIframeConfigFeedback:: pFeedbackObj=', pFeedbackObj); + console.log('### handleIframeConfigFeedback:: csfState.iframeConfigCount=', csfState.iframeConfigCount); + console.log('### handleIframeConfigFeedback:: csfState.originalNumIframes=', csfState.originalNumIframes); + } + + if (csfState.iframeConfigCount === csfState.originalNumIframes) { + if (process.env.NODE_ENV === 'development' && window._b$dl) { + console.log('\n### handleIframeConfigFeedback::handleIframeConfigFeedback:: ALL IFRAMES CONFIG DO CALLBACK type=', csfState.type); + } + + // Announce we're configured to the rest of the system + // this.isConfigured(); + isConfigured(); + + return true; + } + } else { + if (process.env.NODE_ENV === 'development' && window._b$dl) { + console.log('### handleIframeConfigFeedback:: State is already configured so MUST BE ADDING IFRAMES'); + console.log('### handleIframeConfigFeedback:: csfState.iframeConfigCount=', csfState.iframeConfigCount); + console.log('### handleIframeConfigFeedback:: csfState.originalNumIframes=', csfState.originalNumIframes); + console.log('### handleIframeConfigFeedback:: current csfState.numIframes=', csfState.numIframes); + console.log('### handleIframeConfigFeedback:: pFeedbackObj=', pFeedbackObj); + } + + const callbackObj: CbObjOnAdditionalSF = { additionalIframeConfigured: true, fieldType: pFeedbackObj.fieldType, type: csfState.type }; + csfCallbacks.onAdditionalSFConfig(callbackObj); + } + + return false; +} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/isConfigured.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/isConfigured.ts similarity index 53% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/isConfigured.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/isConfigured.ts index 4caa6b4aef..fa4b06e35b 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/isConfigured.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/isConfigured.ts @@ -1,24 +1,31 @@ -import cardType from '../../utilities/cardType'; +import cardType from '../utils/cardType'; import { CardObject, CbObjOnConfigSuccess } from '../../types'; import * as logger from '../../utilities/logger'; import { CVC_POLICY_REQUIRED } from '../../configuration/constants'; -export function isConfigured(): void { - this.state.isConfigured = true; +/** + * @param csfState - comes from initial, partial, implementation + * @param csfConfig - comes from initial, partial, implementation + * @param csfProps - comes from initial, partial, implementation + * @param csfCallbacks - comes from initial, partial, implementation + * @param validateForm - comes from initial, partial, implementation + */ +export function isConfigured({ csfState, csfConfig, csfProps, csfCallbacks }, validateForm): void { + csfState.isConfigured = true; - const callbackObj: CbObjOnConfigSuccess = { iframesConfigured: true, type: this.state.type, rootNode: this.props.rootNode }; + const callbackObj: CbObjOnConfigSuccess = { iframesConfigured: true, type: csfState.type, rootNode: csfProps.rootNode }; - this.callbacks.onConfigSuccess(callbackObj); + csfCallbacks.onConfigSuccess(callbackObj); // If a recurring card - if (this.state.numIframes === 1 && this.config.isCreditCardType) { - if (this.state.type === 'card') { + if (csfState.numIframes === 1 && csfConfig.isCreditCardType) { + if (csfState.type === 'card') { logger.error("ERROR: Payment method with a single secured field - but 'type' has not been set to a specific card brand"); return; } // Get card object from txVariant - const card: CardObject = cardType.getCardByBrand(this.state.type); + const card: CardObject = cardType.getCardByBrand(csfState.type); // It's possible we don't recognise the card type - // scenario: frontend initially recognises card as e.g. Visa - but then backend tokenises it as a sub-brand which we currently don't recognise @@ -28,7 +35,8 @@ export function isConfigured(): void { // If cvc is optional - the form can be considered valid if (cvcPolicy !== CVC_POLICY_REQUIRED) { - this.assessFormValidity(); + // this.validateForm(); + validateForm(); } } } diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/postMessageToAllIframes.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/postMessageToAllIframes.ts new file mode 100644 index 0000000000..a246a8cadc --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/postMessageToAllIframes.ts @@ -0,0 +1,36 @@ +import postMessageToIframe from '../utils/iframes/postMessageToIframe'; +import getIframeContentWin from '../utils/iframes/getIframeContentWin'; + +/** + * UTIL TO BROADCAST TO ALL IFRAMES AT ONCE + * Adds correct txVariant, fieldType and numKey for each iframe + * + * @param csfState - comes from initial, partial, implementation + * @param csfConfig - comes from initial, partial, implementation + * + * @param pDataObj - + */ +export function postMessageToAllIframes({ csfState, csfConfig }, pDataObj: object): void { + const objKeys: string[] = Object.keys(pDataObj || {}); + if (!objKeys.length) { + // pDataObj is an object with the 'special' key(s) that represent the reason for making this postMessage + // without it/them there is no reason to postMessage + return; + } + + const securedFieldKeys: string[] = Object.keys(csfState.securedFields); + securedFieldKeys.forEach(pFieldType => { + const dataObj: object = { + txVariant: csfState.type, + fieldType: pFieldType, + numKey: csfState.securedFields[pFieldType].numKey + }; + + // Copy across 'special' properties from passed data object + objKeys.forEach(pKey => { + dataObj[pKey] = pDataObj[pKey]; + }); + + postMessageToIframe(dataObj, getIframeContentWin(csfState, pFieldType), csfConfig.loadingContext); + }); +} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processAutoComplete.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/processAutoComplete.ts similarity index 57% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/processAutoComplete.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/processAutoComplete.ts index b6cb8e6f2e..9af60df5e2 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processAutoComplete.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/processAutoComplete.ts @@ -1,15 +1,24 @@ -import postMessageToIframe from './iframes/postMessageToIframe'; +import postMessageToIframe from '../utils/iframes/postMessageToIframe'; import { ENCRYPTED_EXPIRY_DATE, ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR } from '../../configuration/constants'; import { SFFeedbackObj, CbObjOnAutoComplete } from '../../types'; import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; +import getIframeContentWin from '../utils/iframes/getIframeContentWin'; -export function processAutoComplete(pFeedbackObj: SFFeedbackObj): void { +/** + * + * @param csfState - comes from initial, partial, implementation + * @param csfConfig - comes from initial, partial, implementation + * @param csfCallbacks - comes from initial, partial, implementation + * + * @param pFeedbackObj - + */ +export function processAutoComplete({ csfState, csfConfig, csfCallbacks }, pFeedbackObj: SFFeedbackObj): void { // Specifically for cc-name (but no reason not to propagate all AC objects to the merchant) if (pFeedbackObj.name === 'cc-name') { const feedbackObj: SFFeedbackObj = { ...pFeedbackObj }; delete feedbackObj.numKey; const ACFeedbackObj: CbObjOnAutoComplete = feedbackObj as CbObjOnAutoComplete; - this.callbacks.onAutoComplete(ACFeedbackObj); + csfCallbacks.onAutoComplete(ACFeedbackObj); } // Send date info to relevant secured fields @@ -26,37 +35,37 @@ export function processAutoComplete(pFeedbackObj: SFFeedbackObj): void { const acYearVal: string = dateValArr[1].substr(2); // take last 2 digits of year const acDateVal = `${acMonthVal}/${acYearVal}`; - if (hasOwnProperty(this.state.securedFields, ENCRYPTED_EXPIRY_DATE)) { + if (hasOwnProperty(csfState.securedFields, ENCRYPTED_EXPIRY_DATE)) { const dataObj: object = { - txVariant: this.state.type, + txVariant: csfState.type, fieldType: ENCRYPTED_EXPIRY_DATE, autoComplete: acDateVal, - numKey: this.state.securedFields[ENCRYPTED_EXPIRY_DATE].numKey + numKey: csfState.securedFields[ENCRYPTED_EXPIRY_DATE].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(ENCRYPTED_EXPIRY_DATE), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(csfState, ENCRYPTED_EXPIRY_DATE), csfConfig.loadingContext); return; } - if (hasOwnProperty(this.state.securedFields, ENCRYPTED_EXPIRY_MONTH)) { + if (hasOwnProperty(csfState.securedFields, ENCRYPTED_EXPIRY_MONTH)) { const dataObj: object = { - txVariant: this.state.type, + txVariant: csfState.type, fieldType: ENCRYPTED_EXPIRY_MONTH, autoComplete: acMonthVal, - numKey: this.state.securedFields[ENCRYPTED_EXPIRY_MONTH].numKey + numKey: csfState.securedFields[ENCRYPTED_EXPIRY_MONTH].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(ENCRYPTED_EXPIRY_MONTH), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(csfState, ENCRYPTED_EXPIRY_MONTH), csfConfig.loadingContext); } - if (hasOwnProperty(this.state.securedFields, ENCRYPTED_EXPIRY_YEAR)) { + if (hasOwnProperty(csfState.securedFields, ENCRYPTED_EXPIRY_YEAR)) { // Dirty! - Need to wait til next page draw if setting month and year at the same time, otherwise only year gets set setTimeout(() => { const dataObj: object = { - txVariant: this.state.type, + txVariant: csfState.type, fieldType: ENCRYPTED_EXPIRY_YEAR, autoComplete: acYearVal, - numKey: this.state.securedFields[ENCRYPTED_EXPIRY_YEAR].numKey + numKey: csfState.securedFields[ENCRYPTED_EXPIRY_YEAR].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(ENCRYPTED_EXPIRY_YEAR), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(csfState, ENCRYPTED_EXPIRY_YEAR), csfConfig.loadingContext); }, 0); } } diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processBrand.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/processBrand.ts similarity index 69% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/processBrand.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/processBrand.ts index c07595bc2d..80be2bd4e0 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processBrand.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/processBrand.ts @@ -1,9 +1,10 @@ import { ENCRYPTED_CARD_NUMBER, ENCRYPTED_SECURITY_CODE } from '../../configuration/constants'; -import postMessageToIframe from './iframes/postMessageToIframe'; +import postMessageToIframe from '../utils/iframes/postMessageToIframe'; import { objectsDeepEqual } from '../../utilities/commonUtils'; import { BrandStorageObject, CbObjOnBrand, SFFeedbackObj } from '../../types'; import { pick } from '../../../utils'; import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; +import getIframeContentWin from '../utils/iframes/getIframeContentWin'; const checkForBrandChange = (pBrand: BrandStorageObject, storedBrand: BrandStorageObject): boolean => { // if the objects aren't the same - then return true = brandChange has happened @@ -15,8 +16,15 @@ const checkForBrandChange = (pBrand: BrandStorageObject, storedBrand: BrandStora * (so it can reassess what length it should be and if any value it contains is now valid) * * - Create object for onBrand callback aka SFPHandlers.handleOnBrand + * + * @param csfState - comes from initial, partial, implementation + * @param csfConfig - comes from initial, partial, implementation + * @param csfProps - comes from initial, partial, implementation + * @param csfCallbacks - comes from initial, partial, implementation + * + * @param pFeedbackObj - */ -export function handleProcessBrand(pFeedbackObj: SFFeedbackObj): boolean { +export default function processBrand({ csfState, csfConfig, csfProps, csfCallbacks }, pFeedbackObj: SFFeedbackObj): boolean { const fieldType: string = pFeedbackObj.fieldType; if (fieldType === ENCRYPTED_CARD_NUMBER) { @@ -27,31 +35,31 @@ export function handleProcessBrand(pFeedbackObj: SFFeedbackObj): boolean { expiryDatePolicy: pFeedbackObj.expiryDatePolicy, showSocialSecurityNumber: pFeedbackObj.showSocialSecurityNumber }; - const newBrand: boolean = checkForBrandChange(newBrandObj, this.state.brand); + const newBrand: boolean = checkForBrandChange(newBrandObj, csfState.brand); if (!newBrand) { return null; } // Now BCMC can dual brand with Visa it must also be treated as a generic card so we can show/hide the CVC field - const treatAsGenericCard: boolean = this.state.type === 'card' || this.state.type === 'bcmc'; + const treatAsGenericCard: boolean = csfState.type === 'card' || csfState.type === 'bcmc'; // ...if also a generic card - tell cvc field... if (treatAsGenericCard && newBrand) { // Store on state so for subsequent brand messages we can compare the new and the old - this.state.brand = newBrandObj; + csfState.brand = newBrandObj; // Perform postMessage to send brand to CVC field - this also needs to happen for BCMC, single branded cards, // because it needs to know the cvcPolicy (to set the aria-required attribute & to show the iframe) - if (hasOwnProperty(this.state.securedFields, ENCRYPTED_SECURITY_CODE)) { + if (hasOwnProperty(csfState.securedFields, ENCRYPTED_SECURITY_CODE)) { const dataObj: object = { - txVariant: this.state.type, + txVariant: csfState.type, brand: newBrandObj.brand, fieldType: ENCRYPTED_SECURITY_CODE, cvcPolicy: pFeedbackObj.cvcPolicy, - numKey: this.state.securedFields[ENCRYPTED_SECURITY_CODE].numKey + numKey: csfState.securedFields[ENCRYPTED_SECURITY_CODE].numKey }; - postMessageToIframe(dataObj, this.getIframeContentWin(ENCRYPTED_SECURITY_CODE), this.config.loadingContext); + postMessageToIframe(dataObj, getIframeContentWin(csfState, ENCRYPTED_SECURITY_CODE), csfConfig.loadingContext); } } @@ -62,11 +70,11 @@ export function handleProcessBrand(pFeedbackObj: SFFeedbackObj): boolean { if (brandInfoObj && brandInfoObj.brand) { const callbackObj: CbObjOnBrand = brandInfoObj as CbObjOnBrand; - callbackObj.type = this.state.type; - callbackObj.rootNode = this.props.rootNode; + callbackObj.type = csfState.type; + callbackObj.rootNode = csfProps.rootNode; /// ...and call SFPHandlers.handleOnBrand - this.callbacks.onBrand(callbackObj); + csfCallbacks.onBrand(callbackObj); } return true; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/setFocusOnFrame.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/setFocusOnFrame.ts new file mode 100644 index 0000000000..17c1f55357 --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/setFocusOnFrame.ts @@ -0,0 +1,26 @@ +import postMessageToIframe from '../utils/iframes/postMessageToIframe'; +import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; +import getIframeContentWin from '../utils/iframes/getIframeContentWin'; + +/** + * @param csfState - comes from initial, partial, implementation + * @param csfConfig - comes from initial, partial, implementation + * + * @param pFieldType - + * @param doLog - + */ +export function setFocusOnFrame({ csfState, csfConfig }, pFieldType: string, doLog?: boolean): void { + // Check destroySecuredFields hasn't been called (thus clearing the state's securedFields object) + if (!hasOwnProperty(csfState.securedFields, pFieldType)) return; + + if (process.env.NODE_ENV === 'development' && doLog) console.log('\n### setFocusOnFrame:: (SHIFT_TAB) place focus on:', pFieldType); + + const focusData = { + txVariant: csfState.type, + fieldType: pFieldType, + focus: true, + numKey: csfState.securedFields[pFieldType].numKey + }; + + postMessageToIframe(focusData, getIframeContentWin(csfState, pFieldType), csfConfig.loadingContext); +} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/validateForm.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/validateForm.ts similarity index 53% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/validateForm.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/validateForm.ts index 1f84f7326d..69e8df0a0b 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/validateForm.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/partials/validateForm.ts @@ -13,18 +13,23 @@ const checkFormIsValid = (pSecuredFields: object): boolean => { return true; }; -export function assessFormValidity(): void { - const isValid: boolean = checkFormIsValid(this.state.securedFields); +/** + * @param csfState - comes from initial, partial, implementation + * @param csfProps - comes from initial, partial, implementation + * @param csfCallbacks - comes from initial, partial, implementation + */ +export default function validateForm({ csfState, csfProps, csfCallbacks }): void { + const isValid: boolean = checkFormIsValid(csfState.securedFields); - const validityHasChanged: boolean = isValid !== this.state.allValid; + const validityHasChanged: boolean = isValid !== csfState.allValid; - this.state.allValid = isValid; + csfState.allValid = isValid; // Only call onAllValid callback if value has changed OR is true if (!isValid && !validityHasChanged) return; - const callbackObj: CbObjOnAllValid = { allValid: isValid, type: this.state.type, rootNode: this.props.rootNode }; + const callbackObj: CbObjOnAllValid = { allValid: isValid, type: csfState.type, rootNode: csfProps.rootNode }; // BROADCAST VALID STATE OF THE FORM AS A WHOLE - this.callbacks.onAllValid(callbackObj); + csfCallbacks.onAllValid(callbackObj); } diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/types.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/types.ts new file mode 100644 index 0000000000..369648e0a1 --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/types.ts @@ -0,0 +1,88 @@ +import Language from '../../../../../language/Language'; +import { BrandStorageObject } from '../types'; + +/** + * Exposed functions that can be called on the CSF instance + */ +export interface CSFReturnObject { + updateStyles: any; + setFocusOnFrame: any; + isValidated: any; + destroy: any; + brandsFromBinLookup: any; + hasUnsupportedCard: any; + addSecuredField: any; + removeSecuredField: any; + setKCPStatus: any; + sendValueToFrame?: any; +} + +/** + * Base interface for SetupObject & ConfigObject + */ +interface CSFCommonProps { + loadingContext: string; + cardGroupTypes?: string[]; + allowedDOMAccess?: boolean; + autoFocus?: boolean; + trimTrailingSeparator?: boolean; + showWarnings?: boolean; + keypadFix?: boolean; + isKCP?: boolean; + iframeUIConfig?: object; + legacyInputMode?: boolean; + minimumExpiryDate?: string; + implementationType?: string; + isCollatingErrors?: boolean; +} + +/** + * Object sent when SecuredFieldsProvider initialises CSF + */ +export interface CSFSetupObject extends CSFCommonProps { + type: string; + clientKey: string; + rootNode: string | HTMLElement; + callbacks?: object; + i18n?: Language; +} + +/** + * The type for the config object created by CSF: properties that just need to be set once, at startup, and then don't change + * This object provides the source for many of the properties that are written into the SFSetupObject used to initialise a new SecuredField.ts + */ +export interface CSFConfigObject extends CSFCommonProps { + iframeSrc: string; + isCreditCardType: boolean; + sfLogAtStart: boolean; +} + +export interface CSFCallbacksConfig { + onLoad?: (callbackObj: object) => void; + onConfigSuccess?: (callbackObj: object) => void; + onFieldValid?: (callbackObj: object) => void; + onAllValid?: (callbackObj: object) => void; + onBrand?: (callbackObj: object) => void; + onError?: (callbackObj: object) => void; + onFocus?: (callbackObj: object) => void; + onBinValue?: (callbackObj: object) => void; + onAutoComplete?: (callbackObj: object) => void; + onAdditionalSFConfig?: (callbackObj: object) => void; + onAdditionalSFRemoved?: (callbackObj: object) => void; +} + +export interface CSFStateObject { + type: string; + brand: BrandStorageObject; + allValid: boolean; + numIframes: number; + originalNumIframes: number; + iframeCount: number; + iframeConfigCount: number; + isConfigured: boolean; + hasSeparateDateFields: boolean; + currentFocusObject: string; + registerFieldForIos: boolean; + securedFields: object; + isKCP: boolean; +} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/callbackUtils.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/callbackUtils.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/callbackUtils.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/callbackUtils.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-amex.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-amex.test.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-amex.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-amex.test.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-detectCardLength.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-detectCardLength.test.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-detectCardLength.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-detectCardLength.test.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-mc.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-mc.test.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-mc.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-mc.test.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-otherFns.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-otherFns.test.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-otherFns.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-otherFns.test.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-visa.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-visa.test.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType-visa.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType-visa.test.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType.test.ts similarity index 98% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType.test.ts index 15021a150e..e743103694 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType-tests/cardType.test.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType-tests/cardType.test.ts @@ -1,6 +1,6 @@ /* global expect, describe, jest, beforeEach */ import CardType from '../cardType'; -import { CVC_POLICY_HIDDEN, CVC_POLICY_OPTIONAL } from '../../configuration/constants'; +import { CVC_POLICY_HIDDEN, CVC_POLICY_OPTIONAL } from '../../../configuration/constants'; const allCards = CardType.allCards.map(pCard => pCard.cardType); diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType.ts similarity index 98% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType.ts index 2ab0db6d6f..0f67c3cc26 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/utilities/cardType.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/cardType.ts @@ -1,5 +1,5 @@ -import { CardObject } from '../types'; -import { hasOwnProperty } from '../../../../../utils/hasOwnProperty'; +import { CardObject } from '../../types'; +import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; let shortestPermittedCardLength; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/destroySecuredFields.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/destroySecuredFields.ts similarity index 90% rename from packages/lib/src/components/internal/SecuredFields/lib/core/destroySecuredFields.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/destroySecuredFields.ts index 54bafbc2e9..51d67b815c 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/destroySecuredFields.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/destroySecuredFields.ts @@ -1,4 +1,4 @@ -import SecuredField from '../../../../../components/internal/SecuredFields/lib/core/SecuredField'; +import SecuredField from '../../securedField/SecuredField'; export function destroySecuredFields(): void { // Tell all securedFields iframes: they will remove all event listeners including keyboard events diff --git a/packages/lib/src/components/internal/SecuredFields/lib/ui/encryptedElements.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/encryptedElements.ts similarity index 96% rename from packages/lib/src/components/internal/SecuredFields/lib/ui/encryptedElements.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/encryptedElements.ts index 70480fb7cb..b3a396f4af 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/ui/encryptedElements.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/encryptedElements.ts @@ -1,5 +1,5 @@ -import { selectOne } from '../utilities/dom'; -import * as logger from '../utilities/logger'; +import { selectOne } from '../../utilities/dom'; +import * as logger from '../../utilities/logger'; const doLog = false; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/getCardGroupTypes.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/getCardGroupTypes.test.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/getCardGroupTypes.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/getCardGroupTypes.test.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/getCardGroupTypes.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/getCardGroupTypes.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/getCardGroupTypes.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/getCardGroupTypes.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/getIframeContentWin.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/getIframeContentWin.ts new file mode 100644 index 0000000000..b30ef17406 --- /dev/null +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/getIframeContentWin.ts @@ -0,0 +1,8 @@ +import { CSFStateObject } from '../../types'; + +/** + * Retrieves the iframe, stored by field type, & returns it's contentWindow + */ +export default function getIframeContentWin(csfState: CSFStateObject, fieldType: string): Window { + return csfState.securedFields[fieldType]?.iframeContentWindow || null; +} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageToIframe.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/postMessageToIframe.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageToIframe.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/postMessageToIframe.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageValidation.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/postMessageValidation.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageValidation.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/iframes/postMessageValidation.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processErrors.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/processErrors.test.ts similarity index 99% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/processErrors.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/processErrors.test.ts index 9415a43e5d..230df7bb1b 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processErrors.test.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/processErrors.test.ts @@ -1,6 +1,6 @@ /* global expect, describe, jest, beforeEach */ import { processErrors } from './processErrors'; -import SecuredField from '../SecuredField'; +import SecuredField from '../../securedField/SecuredField'; const ERROR_MSG_CARD_TOO_FAR_IN_FUTURE = 'ERROR_MSG_CARD_TOO_FAR_IN_FUTURE'; const ERROR_MSG_CARD_TOO_OLD = 'ERROR_MSG_CARD_TOO_OLD'; const ERROR_MSG_INCOMPLETE_FIELD = 'ERROR_MSG_INCOMPLETE_FIELD'; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processErrors.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/processErrors.ts similarity index 95% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/processErrors.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/processErrors.ts index 7b2e10c616..51bf946e44 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/processErrors.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/processErrors.ts @@ -1,5 +1,5 @@ import { CbObjOnError, SFFeedbackObj } from '../../types'; -import SecuredField from '../../../../../../components/internal/SecuredFields/lib/core/SecuredField'; +import SecuredField from '../../securedField/SecuredField'; import { ERROR_CODES, ERROR_MSG_UNSUPPORTED_CARD_ENTERED } from '../../../../../../core/Errors/constants'; import { hasOwnProperty } from '../../../../../../utils/hasOwnProperty'; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioACH.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioACH.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioACH.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioACH.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioCreditCard.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioCreditCard.ts similarity index 95% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioCreditCard.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioCreditCard.ts index 68b1c98d68..705fcec0c6 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioCreditCard.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioCreditCard.ts @@ -5,7 +5,7 @@ import { ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR } from '../../../configuration/constants'; -import { getPreviousTabbableNonSFElement } from '../../../ui/domUtils'; +import { getPreviousTabbableNonSFElement } from './utils'; import { ShiftTabObject } from '../../../types'; // Regular Credit Card scenario diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioGiftCard.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioGiftCard.ts similarity index 91% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioGiftCard.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioGiftCard.ts index c16a2ff709..1186f31ca8 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioGiftCard.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioGiftCard.ts @@ -1,5 +1,5 @@ import { ENCRYPTED_CARD_NUMBER, ENCRYPTED_SECURITY_CODE } from '../../../configuration/constants'; -import { getPreviousTabbableNonSFElement } from '../../../ui/domUtils'; +import { getPreviousTabbableNonSFElement } from './utils'; import { ShiftTabObject } from '../../../types'; // GIFT CARD scenario: SecurityCode preceded by CardNumber diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioKCP.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioKCP.ts similarity index 95% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioKCP.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioKCP.ts index f8ea890ae1..c1ad48eaaf 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/tabbing/tabScenarioKCP.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/tabScenarioKCP.ts @@ -7,7 +7,7 @@ import { ENCRYPTED_PWD_FIELD, ENCRYPTED_PIN_FIELD } from '../../../configuration/constants'; -import { getPreviousTabbableNonSFElement } from '../../../ui/domUtils'; +import { getPreviousTabbableNonSFElement } from './utils'; import { ShiftTabObject } from '../../../types'; // KCP scenario: Regular credit card but with additional fields - diff --git a/packages/lib/src/components/internal/SecuredFields/lib/ui/domUtils.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/utils.ts similarity index 79% rename from packages/lib/src/components/internal/SecuredFields/lib/ui/domUtils.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/utils.ts index 07718e7c62..bdc35b24e2 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/ui/domUtils.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/tabbing/utils.ts @@ -1,4 +1,4 @@ -import { selectOne, select } from '../utilities/dom'; +import { selectOne, select } from '../../../utilities/dom'; const getPreviousTabbableEl = (matchEl, getPrevious = true) => { const selStr = @@ -40,26 +40,6 @@ const getPreviousTabbableEl = (matchEl, getPrevious = true) => { return actualTabEls[matchElIndex + indexModifier]; }; -export const findRootNode = pRootNode => { - let rootNode; - - // Expect to be sent the actual html node... - if (typeof pRootNode === 'object') { - rootNode = pRootNode; - } - - if (typeof pRootNode === 'string') { - // ... but if only sent a string - find it ourselves - rootNode = selectOne(document, pRootNode); - - if (!rootNode) { - return null; - } - } - - return rootNode; -}; - export const getPreviousTabbableNonSFElement = (passedFieldType, rootNode) => { // -- const sfEl = selectOne(rootNode, `[data-cse=${passedFieldType}]`); diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/userAgent.ts b/packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/userAgent.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/userAgent.ts rename to packages/lib/src/components/internal/SecuredFields/lib/CSF/utils/userAgent.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/configuration/constants.ts b/packages/lib/src/components/internal/SecuredFields/lib/configuration/constants.ts index 51ca3cfb93..521f098ac0 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/configuration/constants.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/configuration/constants.ts @@ -1,4 +1,4 @@ -import { CVCPolicyType, DatePolicyType } from '../core/AbstractSecuredField'; +import { CVCPolicyType, DatePolicyType } from '../types'; export const ENCRYPTED_CARD_NUMBER = 'encryptedCardNumber'; export const ENCRYPTED_EXPIRY_DATE = 'encryptedExpiryDate'; @@ -16,7 +16,7 @@ export const GIFT_CARD = 'giftcard'; export const ENCRYPTED_BANK_ACCNT_NUMBER_FIELD = 'encryptedBankAccountNumber'; export const ENCRYPTED_BANK_LOCATION_FIELD = 'encryptedBankLocationId'; -export const SF_VERSION = '3.7.5'; +export const SF_VERSION = '3.8.0'; export const DEFAULT_CARD_GROUP_TYPES = ['amex', 'mc', 'visa']; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/handleBinValue.ts b/packages/lib/src/components/internal/SecuredFields/lib/core/utils/handleBinValue.ts deleted file mode 100644 index bb4d8779b4..0000000000 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/handleBinValue.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { SFFeedbackObj, CbObjOnBinValue } from '../../types'; - -interface DestructuredFeedbackObj { - binValue?: string; - encryptedBin?: string; - uuid?: string; -} - -export function handleBinValue(pFeedbackObj: SFFeedbackObj): void { - const { binValue, encryptedBin, uuid }: DestructuredFeedbackObj = pFeedbackObj; - - const callbacksObj: CbObjOnBinValue = { binValue, type: this.state.type }; - - if (encryptedBin) { - callbacksObj.encryptedBin = encryptedBin; - callbacksObj.uuid = uuid; - } - - this.callbacks.onBinValue(callbacksObj); -} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleFocus.ts b/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleFocus.ts deleted file mode 100644 index c1e55ac686..0000000000 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleFocus.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { SFFeedbackObj, CbObjOnFocus } from '../../../types'; - -// Call focus callback and store which field currently has focus -export function handleFocus(pFeedbackObj: SFFeedbackObj): void { - const feedbackObj: SFFeedbackObj = { ...pFeedbackObj }; - - delete feedbackObj.numKey; - - feedbackObj.rootNode = this.props.rootNode; - feedbackObj.type = this.state.type; - - // Store which field has focus - const focusString: string = feedbackObj.fieldType; - - // Focus event - store, if this isn't the field that already has focus - if (feedbackObj.focus) { - if (this.state.currentFocusObject !== focusString) { - this.state.currentFocusObject = focusString; - - // iOS ONLY thing (fn returns if not iOS) - if (!this.state.registerFieldForIos) { - this.handleAdditionalFields(); - } - } - } else { - // Blur event - remove stored focus - const focusObjectMatches: boolean = this.state.currentFocusObject === focusString; - if (focusObjectMatches) { - this.state.currentFocusObject = null; - } - } - - // Call callback - const callbackObj: CbObjOnFocus = feedbackObj as CbObjOnFocus; - callbackObj.currentFocusObject = this.state.currentFocusObject; - this.callbacks.onFocus(callbackObj); -} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleIframeConfigFeedback.ts b/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleIframeConfigFeedback.ts deleted file mode 100644 index 2dda04234a..0000000000 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/handleIframeConfigFeedback.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Count how many iframes have successfully been configured and, if its all of them, call callback function - -import { CbObjOnAdditionalSF } from '../../../types'; - -export function handleIframeConfigFeedback(pFeedbackObj): boolean { - this.state.iframeConfigCount += 1; - - if (!this.state.isConfigured) { - if (process.env.NODE_ENV === 'development' && window._b$dl) { - console.log('\n### handleIframeConfigFeedback:: this.state.type=', this.state.type); - console.log('### handleIframeConfigFeedback:: pFeedbackObj=', pFeedbackObj); - console.log('### handleIframeConfigFeedback:: this.state.iframeConfigCount=', this.state.iframeConfigCount); - console.log('### handleIframeConfigFeedback:: this.state.originalNumIframes=', this.state.originalNumIframes); - } - - if (this.state.iframeConfigCount === this.state.originalNumIframes) { - if (process.env.NODE_ENV === 'development' && window._b$dl) { - console.log('\n### handleIframeConfigFeedback::handleIframeConfigFeedback:: ALL IFRAMES CONFIG DO CALLBACK type=', this.state.type); - } - - // Announce we're configured to the rest of the system - this.isConfigured(); - - return true; - } - } else { - if (process.env.NODE_ENV === 'development' && window._b$dl) { - console.log('### handleIframeConfigFeedback:: State is already configured so MUST BE ADDING IFRAMES'); - console.log('### handleIframeConfigFeedback:: this.state.iframeConfigCount=', this.state.iframeConfigCount); - console.log('### handleIframeConfigFeedback:: this.state.originalNumIframes=', this.state.originalNumIframes); - console.log('### handleIframeConfigFeedback:: current this.state.numIframes=', this.state.numIframes); - console.log('### handleIframeConfigFeedback:: pFeedbackObj=', pFeedbackObj); - } - - const callbackObj: CbObjOnAdditionalSF = { additionalIframeConfigured: true, fieldType: pFeedbackObj.fieldType, type: this.state.type }; - this.callbacks.onAdditionalSFConfig(callbackObj); - } - - return false; -} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageToAllIframes.ts b/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageToAllIframes.ts deleted file mode 100644 index c03408041c..0000000000 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/postMessageToAllIframes.ts +++ /dev/null @@ -1,28 +0,0 @@ -import postMessageToIframe from './postMessageToIframe'; - -// UTIL TO BROADCAST TO ALL IFRAMES AT ONCE -// Adds correct txVariant, fieldType and numKey for each iframe -export function postMessageToAllIframes(pDataObj: object): void { - const objKeys: string[] = Object.keys(pDataObj || {}); - if (!objKeys.length) { - // pDataObj is an object with the 'special' key(s) that represent the reason for making this postMessage - // without it/them there is no reason to postMessage - return; - } - - const securedFieldKeys: string[] = Object.keys(this.state.securedFields); - securedFieldKeys.forEach(pFieldType => { - const dataObj: object = { - txVariant: this.state.type, - fieldType: pFieldType, - numKey: this.state.securedFields[pFieldType].numKey - }; - - // Copy across 'special' properties from passed data object - objKeys.forEach(pKey => { - dataObj[pKey] = pDataObj[pKey]; - }); - - postMessageToIframe(dataObj, this.getIframeContentWin(pFieldType), this.config.loadingContext); - }); -} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/setFocusOnFrame.ts b/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/setFocusOnFrame.ts deleted file mode 100644 index 40b35b4715..0000000000 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/iframes/setFocusOnFrame.ts +++ /dev/null @@ -1,18 +0,0 @@ -import postMessageToIframe from './postMessageToIframe'; -import { hasOwnProperty } from '../../../../../../../utils/hasOwnProperty'; - -export function setFocusOnFrame(pFieldType: string, doLog?: boolean): void { - // Check destroySecuredFields hasn't been called (thus clearing the state's securedFields object) - if (!hasOwnProperty(this.state.securedFields, pFieldType)) return; - - if (process.env.NODE_ENV === 'development' && doLog) console.log('\n### setFocusOnFrame:: (SHIFT_TAB) place focus on:', pFieldType); - - const focusData = { - txVariant: this.state.type, - fieldType: pFieldType, - focus: true, - numKey: this.state.securedFields[pFieldType].numKey - }; - - postMessageToIframe(focusData, this.getIframeContentWin(pFieldType), this.config.loadingContext); -} diff --git a/packages/lib/src/components/internal/SecuredFields/lib/index.ts b/packages/lib/src/components/internal/SecuredFields/lib/index.ts deleted file mode 100644 index cfe64e81ce..0000000000 --- a/packages/lib/src/components/internal/SecuredFields/lib/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import csf from './core/initCSF'; - -export default csf; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/AbstractSecuredField.ts b/packages/lib/src/components/internal/SecuredFields/lib/securedField/AbstractSecuredField.ts similarity index 90% rename from packages/lib/src/components/internal/SecuredFields/lib/core/AbstractSecuredField.ts rename to packages/lib/src/components/internal/SecuredFields/lib/securedField/AbstractSecuredField.ts index a102d633e6..a2b8878df1 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/AbstractSecuredField.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/securedField/AbstractSecuredField.ts @@ -1,4 +1,4 @@ -import { SFFeedbackObj, StylesObject } from '../types'; +import { CVCPolicyType, DatePolicyType, RtnType_callbackFn, RtnType_noParamVoidFn, RtnType_postMessageListener, StylesObject } from '../types'; import { ENCRYPTED_BANK_ACCNT_NUMBER_FIELD, ENCRYPTED_BANK_LOCATION_FIELD, @@ -12,13 +12,6 @@ import { ENCRYPTED_SECURITY_CODE_4_DIGITS } from '../configuration/constants'; -export type RtnType_noParamVoidFn = () => void; -export type RtnType_postMessageListener = (event: Event) => void; -export type RtnType_callbackFn = (feedbackObj: SFFeedbackObj) => void; - -export type CVCPolicyType = 'required' | 'optional' | 'hidden'; -export type DatePolicyType = 'required' | 'optional' | 'hidden'; - /** * Base interface, props common to both SFSetupObject & IframeConfigObject */ diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/SecuredField.test.ts b/packages/lib/src/components/internal/SecuredFields/lib/securedField/SecuredField.test.ts similarity index 99% rename from packages/lib/src/components/internal/SecuredFields/lib/core/SecuredField.test.ts rename to packages/lib/src/components/internal/SecuredFields/lib/securedField/SecuredField.test.ts index b5239e83d4..dea1fd8447 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/SecuredField.test.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/securedField/SecuredField.test.ts @@ -1,5 +1,6 @@ import SecuredField from './SecuredField'; -import { AriaConfig, CVCPolicyType, DatePolicyType } from './AbstractSecuredField'; +// import { AriaConfig } from './AbstractSecuredField'; +import { CVCPolicyType, DatePolicyType } from '../types'; import Language from '../../../../../language/Language'; import LANG from '../../../../../language/locales/en-US.json'; import { ERROR_CODES, ERROR_MSG_CARD_TOO_OLD, ERROR_MSG_INVALID_FIELD, ERROR_MSG_LUHN_CHECK_FAILED } from '../../../../../core/Errors/constants'; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/SecuredField.ts b/packages/lib/src/components/internal/SecuredFields/lib/securedField/SecuredField.ts similarity index 96% rename from packages/lib/src/components/internal/SecuredFields/lib/core/SecuredField.ts rename to packages/lib/src/components/internal/SecuredFields/lib/securedField/SecuredField.ts index 3ba74cd4e3..2b22e40c54 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/SecuredField.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/securedField/SecuredField.ts @@ -1,8 +1,8 @@ import * as logger from '../utilities/logger'; -import createIframe from '../utilities/createIframe'; +import createIframe from './utils/createIframe'; import { selectOne, on, off, removeAllChildren } from '../utilities/dom'; -import postMessageToIframe from './utils/iframes/postMessageToIframe'; -import { isWebpackPostMsg, originCheckPassed, isChromeVoxPostMsg } from './utils/iframes/postMessageValidation'; +import postMessageToIframe from '../CSF/utils/iframes/postMessageToIframe'; +import { isWebpackPostMsg, originCheckPassed, isChromeVoxPostMsg } from '../CSF/utils/iframes/postMessageValidation'; import { CVC_POLICY_HIDDEN, CVC_POLICY_OPTIONAL, @@ -15,21 +15,11 @@ import { } from '../configuration/constants'; import { generateRandomNumber } from '../utilities/commonUtils'; import { SFFeedbackObj } from '../types'; -import AbstractSecuredField, { - SFSetupObject, - IframeConfigObject, - RtnType_noParamVoidFn, - RtnType_postMessageListener, - RtnType_callbackFn, - AriaConfig, - SFPlaceholdersObject, - CVCPolicyType, - DatePolicyType, - SFInternalConfig -} from '../core/AbstractSecuredField'; +import AbstractSecuredField, { SFSetupObject, IframeConfigObject, AriaConfig, SFPlaceholdersObject, SFInternalConfig } from './AbstractSecuredField'; +import { CVCPolicyType, DatePolicyType, RtnType_noParamVoidFn, RtnType_postMessageListener, RtnType_callbackFn } from '../types'; import { pick, reject } from '../../utils'; -import { processAriaConfig } from './utils/init/processAriaConfig'; -import { processPlaceholders } from './utils/init/processPlaceholders'; +import { processAriaConfig } from './utils/processAriaConfig'; +import { processPlaceholders } from './utils/processPlaceholders'; import Language from '../../../../../language/Language'; import { hasOwnProperty } from '../../../../../utils/hasOwnProperty'; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/createIframe.ts b/packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/createIframe.ts similarity index 100% rename from packages/lib/src/components/internal/SecuredFields/lib/utilities/createIframe.ts rename to packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/createIframe.ts diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/init/processAriaConfig.ts b/packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/processAriaConfig.ts similarity index 90% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/init/processAriaConfig.ts rename to packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/processAriaConfig.ts index 3d881841d1..53b981d3c4 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/init/processAriaConfig.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/processAriaConfig.ts @@ -1,6 +1,6 @@ -import { addErrorTranslationsToObject } from '../../../../../../../core/Errors/utils'; -import { AriaConfigObject, AriaConfig, SFInternalConfig } from '../../AbstractSecuredField'; -import Language from '../../../../../../../language/Language'; +import { addErrorTranslationsToObject } from '../../../../../../core/Errors/utils'; +import { AriaConfigObject, AriaConfig, SFInternalConfig } from '../AbstractSecuredField'; +import Language from '../../../../../../language/Language'; /** * Checks if the merchant has defined an ariaConfig object and if so enhances it with a iframeTitle and label property, if they don't already exist. @@ -13,7 +13,7 @@ import Language from '../../../../../../../language/Language'; */ export function processAriaConfig(configObj: SFInternalConfig, fieldType: string, i18n: Language): AriaConfig { // txVariant can be the scheme name (VISA, Mastercard...) so we put all of them under creditCard - const type = ['ach','giftcard'].includes(configObj.txVariant) ? configObj.txVariant : 'creditCard'; + const type = ['ach', 'giftcard'].includes(configObj.txVariant) ? configObj.txVariant : 'creditCard'; // Get translation for iframeTitle const iframeTitle: string = i18n.get(`${type}.${fieldType}.aria.iframeTitle`); diff --git a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/init/processPlaceholders.ts b/packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/processPlaceholders.ts similarity index 85% rename from packages/lib/src/components/internal/SecuredFields/lib/core/utils/init/processPlaceholders.ts rename to packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/processPlaceholders.ts index 3bb8eee5b5..d8b64d49de 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/core/utils/init/processPlaceholders.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/securedField/utils/processPlaceholders.ts @@ -1,11 +1,11 @@ -import { resolvePlaceholders } from '../../../../utils'; -import { SFPlaceholdersObject, SFInternalConfig } from '../../AbstractSecuredField'; +import { resolvePlaceholders } from '../../../utils'; +import { SFPlaceholdersObject, SFInternalConfig } from '../AbstractSecuredField'; import { ENCRYPTED_SECURITY_CODE, ENCRYPTED_SECURITY_CODE_3_DIGITS, ENCRYPTED_SECURITY_CODE_4_DIGITS, GIFT_CARD -} from '../../../configuration/constants'; +} from '../../configuration/constants'; /** * Create placeholders with a value from the relevant translation file diff --git a/packages/lib/src/components/internal/SecuredFields/lib/types.ts b/packages/lib/src/components/internal/SecuredFields/lib/types.ts index 2d79983d9f..3e56d23548 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/types.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/types.ts @@ -1,5 +1,3 @@ -import Language from '../../../../language/Language'; -import { CVCPolicyType, DatePolicyType } from './core/AbstractSecuredField'; import { BrandObject } from '../../../Card/types'; // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -17,92 +15,6 @@ export interface BrandStorageObject { showSocialSecurityNumber?: boolean; } -/** - * Exposed functions that can be called on the CSF instance - */ -export interface CSFReturnObject { - updateStyles: any; - setFocusOnFrame: any; - isValidated: any; - destroy: any; - brandsFromBinLookup: any; - hasUnsupportedCard: any; - addSecuredField: any; - removeSecuredField: any; - setKCPStatus: any; - sendValueToFrame?: any; -} - -/** - * Base interface for SetupObject & ConfigObject - */ -interface CSFCommonProps { - loadingContext: string; - cardGroupTypes?: string[]; - allowedDOMAccess?: boolean; - autoFocus?: boolean; - trimTrailingSeparator?: boolean; - showWarnings?: boolean; - keypadFix?: boolean; - isKCP?: boolean; - iframeUIConfig?: object; - legacyInputMode?: boolean; - minimumExpiryDate?: string; - implementationType?: string; - isCollatingErrors?: boolean; -} - -/** - * Object sent when SecuredFieldsProvider initialises CSF - */ -export interface CSFSetupObject extends CSFCommonProps { - type: string; - clientKey: string; - rootNode: string | HTMLElement; - callbacks?: object; - i18n?: Language; -} - -/** - * The type for the config object created by CSF: properties that just need to be set once, at startup, and then don't change - * This object provides the source for many of the properties that are written into the SFSetupObject used to initialise a new SecuredField.ts - */ -export interface CSFConfigObject extends CSFCommonProps { - iframeSrc: string; - isCreditCardType: boolean; - sfLogAtStart: boolean; -} - -export interface CSFCallbacksConfig { - onLoad?: (callbackObj: object) => void; - onConfigSuccess?: (callbackObj: object) => void; - onFieldValid?: (callbackObj: object) => void; - onAllValid?: (callbackObj: object) => void; - onBrand?: (callbackObj: object) => void; - onError?: (callbackObj: object) => void; - onFocus?: (callbackObj: object) => void; - onBinValue?: (callbackObj: object) => void; - onAutoComplete?: (callbackObj: object) => void; - onAdditionalSFConfig?: (callbackObj: object) => void; - onAdditionalSFRemoved?: (callbackObj: object) => void; -} - -export interface CSFStateObject { - type: string; - brand: BrandStorageObject; - allValid: boolean; - numIframes: number; - originalNumIframes: number; - iframeCount: number; - iframeConfigCount: number; - isConfigured: boolean; - hasSeparateDateFields: boolean; - currentFocusObject: string; - registerFieldForIos: boolean; - securedFields: object; - isKCP: boolean; -} - export interface StylesObject { base?: StyleDefinitions; error?: StyleDefinitions; @@ -294,3 +206,10 @@ export interface SendBrandObject { export interface SendExpiryDateObject { expiryDatePolicy: DatePolicyType; } + +export type RtnType_noParamVoidFn = () => void; +export type RtnType_postMessageListener = (event: Event) => void; +export type RtnType_callbackFn = (feedbackObj: SFFeedbackObj) => void; + +export type CVCPolicyType = 'required' | 'optional' | 'hidden'; +export type DatePolicyType = 'required' | 'optional' | 'hidden'; diff --git a/packages/lib/src/components/internal/SecuredFields/lib/utilities/commonUtils.ts b/packages/lib/src/components/internal/SecuredFields/lib/utilities/commonUtils.ts index 79bfc41671..efe1efbb67 100644 --- a/packages/lib/src/components/internal/SecuredFields/lib/utilities/commonUtils.ts +++ b/packages/lib/src/components/internal/SecuredFields/lib/utilities/commonUtils.ts @@ -203,6 +203,24 @@ function notFalsy(x) { return !falsy(x); } +/** + * This function allows us to partially apply any number of variables to functions that take any number of parameters. + * @returns {function(): *} + */ +function partial(...args) { + // Store the args array + const myArgs = args; + + // Grab the function (the first argument). myArgs now contains the remaining arguments + const fn = myArgs.shift(); + + // Return a function that calls fn with myArgs + whatever else is passed when this returned function is called + function partialFn(...args2) { + return fn.apply(this, myArgs.concat(args2)); + } + return partialFn; +} + export { generateRandomNumber, existy, @@ -210,6 +228,7 @@ export { isArray, objectsDeepEqual, notFalsy, + partial, truthy // wait }; diff --git a/packages/lib/src/components/internal/SecuredFields/utils.ts b/packages/lib/src/components/internal/SecuredFields/utils.ts index 7ba1fdefc9..d812d3d863 100644 --- a/packages/lib/src/components/internal/SecuredFields/utils.ts +++ b/packages/lib/src/components/internal/SecuredFields/utils.ts @@ -1,4 +1,3 @@ -import getProp from '../../../utils/getProp'; import Language from '../../../language/Language'; import { getImageUrl } from '../../../utils/get-image'; import { @@ -8,114 +7,13 @@ import { ENCRYPTED_EXPIRY_YEAR, ENCRYPTED_SECURITY_CODE, ENCRYPTED_PWD_FIELD, - CVC_POLICY_OPTIONAL, - CVC_POLICY_HIDDEN, ENCRYPTED_SECURITY_CODE_3_DIGITS, - ENCRYPTED_SECURITY_CODE_4_DIGITS, - DATE_POLICY_OPTIONAL, - DATE_POLICY_HIDDEN + ENCRYPTED_SECURITY_CODE_4_DIGITS // TODO Comment out until translations are available // ENCRYPTED_BANK_ACCNT_NUMBER_FIELD, // ENCRYPTED_BANK_LOCATION_FIELD } from './lib/configuration/constants'; -import { DEFAULT_ERROR } from '../../../core/Errors/constants'; -import { SFPlaceholdersObject } from './lib/core/AbstractSecuredField'; - -// ROUTINES USED IN SecuredFieldsProvider.componentDidMount TO DETECT & MAP FIELD NAMES /////////// -/** - * Make an array of encrypted field names based on the value of the 'data-cse' attribute of elements in the rootNode - */ -export const getFields = rootNode => { - if (rootNode) { - return Array.prototype.slice.call(rootNode.querySelectorAll('[data-cse*="encrypted"]')).map(f => f.getAttribute('data-cse')); - } - return []; -}; - -/** - * If, visually, we're dealing with a single date field (expiryDate) we still need separate entries - * for expiryMonth & expiryYear - since that is how the values will be delivered from securedFields - */ -export const validFieldsReducer = (acc, cur) => { - if (cur === ENCRYPTED_EXPIRY_DATE) { - acc[ENCRYPTED_EXPIRY_MONTH] = false; - acc[ENCRYPTED_EXPIRY_YEAR] = false; - } else { - acc[cur] = false; - } - - return acc; -}; -// -- end ROUTINES USED IN SecuredFieldsProvider.componentDidMount -------------------------------- - -// ROUTINES USED IN SecuredFieldsProvider.showValidation TO GENERATE ERRORS /////////// -/** - * If, visually, we're dealing with a single date field (expiryDate) remap the separate entries we have - * for the valid states of expiryMonth & expiryYear back to the single key we use to an store an error - * i.e `"encryptedExpiryMonth" & "encryptedExpiryYear" => "encryptedExpiryDate"` - */ -const mapDateFields = (field, numDateFields) => { - const isDateField = field === ENCRYPTED_EXPIRY_MONTH || field === ENCRYPTED_EXPIRY_YEAR; - return numDateFields === 1 && isDateField ? ENCRYPTED_EXPIRY_DATE : field; -}; - -/** - * Skip generating an error for an optional field, unless it is already in error - */ -const skipOptionalFields = (field, state, fieldNames) => { - // console.log('\n### utils::skipOptionalField3:: examining field=', field); - const { isFieldOfType, fieldIsValid } = fieldNames.reduce( - (acc, fieldName) => { - if (!acc.isFieldOfType) { - // console.log('### utils:: fieldName:: ', fieldName, 'match=', field === fieldName); - acc.isFieldOfType = field === fieldName; - acc.fieldIsValid = !state.errors[fieldName]; - } - return acc; - }, - { isFieldOfType: false, fieldIsValid: false } - ); - - const policyType = field === ENCRYPTED_SECURITY_CODE ? 'cvcPolicy' : 'expiryDatePolicy'; - - const policyOptional = policyType === 'cvcPolicy' ? CVC_POLICY_OPTIONAL : DATE_POLICY_OPTIONAL; - const policyHidden = policyType === 'cvcPolicy' ? CVC_POLICY_HIDDEN : DATE_POLICY_HIDDEN; - - // if policy != required - return (state[policyType] === policyOptional || state[policyType] === policyHidden) && fieldIsValid && isFieldOfType ? null : field; -}; - -export const getErrorReducer = (numDateFields, state) => (acc, field) => { - // We're only interested in the non-valid fields from the state.valid object... - let val = - state.valid[field] !== true - ? mapDateFields(field, numDateFields) // Map the keys we use for the valid state to the key(s) we use for the error state - : null; - - // Skip error generation for optional/hidden CVC & Date unless the fields are already in error - val = skipOptionalFields(val, state, [ENCRYPTED_SECURITY_CODE, ENCRYPTED_EXPIRY_DATE, ENCRYPTED_EXPIRY_MONTH, ENCRYPTED_EXPIRY_YEAR]); - - // console.log('### utils:::: ############# val=', val); - - if (val && !acc.includes(val)) acc.push(val); - - return acc; -}; - -/** - * Create an object suitable for sending to our handleOnError function - */ -export const getErrorObject = (fieldType, rootNode, state) => { - const error = getProp(state, `errors.${fieldType}`) || DEFAULT_ERROR; - - return { - rootNode, - fieldType, - error, - type: 'card' - }; -}; -// -- end ROUTINES USED IN SecuredFieldsProvider.showValidation ----------------------- +import { SFPlaceholdersObject } from './lib/securedField/AbstractSecuredField'; /** * Lookup translated values for the placeholders for the SecuredFields