mirror of
https://github.com/jlengrand/adyen-web.git
synced 2026-03-10 08:01:22 +00:00
Feature/preconfiguring aria config objects (#221)
* Ensure ariaConfig object always has an iframeTitle property * Initialiser of SecuredField takes responsibility for ensuring a default ariaConfig object * SecuredField takes responsibility for adding translated error property * ariaConfig object processing moved to own file * Renaming ariaLabels prop to ariaConfig * Adding types * Initialiser of securedField takes responsibility for adding translated placeholder, if required. Ensures fields don't get values in their placeholder config that don't apply to their group * When ariaConfig object already exists - destructure it to remove existing references from memory * changed folder name * syncing processAriaConfig * Pass i18n prop from SecuredFieldsProvider into CSF so it can reach SecuredField.ts (since useCoreContext is not available anymore) * Removed unnecessary interface. Added comments. * Removed logs * Small refactor, responding to comment * Added tests. Restored default values to commonConfig.js
This commit is contained in:
@@ -27,7 +27,7 @@ export const ariaLabels = {
|
||||
encryptedCardNumber: {
|
||||
label: 'Credit or debit card number field',
|
||||
iframeTitle: 'Iframe for credit card number field'
|
||||
// error: "credit card number is in error"
|
||||
// error: 'credit card number is in error'
|
||||
},
|
||||
encryptedExpiryDate: {
|
||||
label: 'Credit or debit card expiration date field'
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
import { Component } from 'preact';
|
||||
import {
|
||||
getErrorObject,
|
||||
getFields,
|
||||
getErrorReducer,
|
||||
validFieldsReducer,
|
||||
addTranslationsToObject,
|
||||
getTranslatedErrors,
|
||||
resolvePlaceholders
|
||||
} from './utils';
|
||||
import { CSF_FIELDS_ARRAY } from './lib/configuration/constants';
|
||||
import { getErrorObject, getFields, getErrorReducer, validFieldsReducer } from './utils';
|
||||
import initCSF from './lib';
|
||||
import handlers from './SecuredFieldsProviderHandlers';
|
||||
import defaultProps, { SFPProps } from './defaultProps';
|
||||
@@ -153,12 +144,10 @@ class SecuredFieldsProvider extends Component<SFPProps, SFPState> {
|
||||
showWarnings: this.props.showWarnings,
|
||||
iframeUIConfig: {
|
||||
sfStyles: this.props.styles,
|
||||
placeholders: {
|
||||
...resolvePlaceholders(this.props.i18n),
|
||||
...this.props.placeholders
|
||||
},
|
||||
ariaLabels: addTranslationsToObject(this.props.ariaLabels, CSF_FIELDS_ARRAY, 'error', getTranslatedErrors(this.props.i18n))
|
||||
placeholders: this.props.placeholders,
|
||||
ariaConfig: this.props.ariaLabels
|
||||
},
|
||||
i18n: this.props.i18n,
|
||||
callbacks: {
|
||||
onLoad: this.handleOnLoad,
|
||||
onConfigSuccess: this.handleOnConfigSuccess,
|
||||
|
||||
@@ -28,33 +28,33 @@ export interface IframeConfigObject extends SFInternalConfig {
|
||||
fieldType: string;
|
||||
cvcRequired: boolean;
|
||||
numKey: number;
|
||||
pmConfig?: any; // TODO - only needed until latest version of 3.2.2 is on test
|
||||
}
|
||||
|
||||
interface IframeUIConfigObject {
|
||||
sfStyles?: StylesObject;
|
||||
placeholders?: PlaceholdersObject;
|
||||
ariaLabels?: AriaLabels;
|
||||
ariaConfig?: AriaConfig;
|
||||
ariaLabels?: AriaConfig; // TODO - only needed until latest version of SF 3.2.5 is on test
|
||||
}
|
||||
|
||||
interface PlaceholdersObject {
|
||||
export interface PlaceholdersObject {
|
||||
[key: string]: string; // e.g. encryptedExpiryDate: 'MM/YY'
|
||||
}
|
||||
|
||||
type AriaLabels = {
|
||||
export type AriaConfig = {
|
||||
lang?: string;
|
||||
} & {
|
||||
[key: string]: AriaLabelsObject; // e.g. encryptedCardNumber: {...}
|
||||
[key: string]: AriaConfigObject; // e.g. encryptedCardNumber: {...}
|
||||
};
|
||||
|
||||
interface AriaLabelsObject {
|
||||
export interface AriaConfigObject {
|
||||
iframeTitle?: string;
|
||||
label?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
abstract class AbstractSecuredField {
|
||||
protected config: SFInternalConfig;
|
||||
public config: SFInternalConfig; // could be protected but needs to be public for tests to run
|
||||
protected fieldType: string;
|
||||
protected cvcRequired: boolean;
|
||||
protected iframeSrc: string;
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
import SecuredField from './SecuredField';
|
||||
import { AriaConfig } from './AbstractSecuredField';
|
||||
import Language from '../../../../../language/Language';
|
||||
import { IFRAME_TITLE } from '../configuration/constants';
|
||||
import LANG from '../../../../../language/locales/nl-NL.json';
|
||||
|
||||
const ENCRYPTED_CARD_NUMBER = 'encryptedCardNumber';
|
||||
const ENCRYPTED_EXPIRY_DATE = 'encryptedExpiryDate';
|
||||
const ENCRYPTED_SECURITY_CODE = 'encryptedSecurityCode';
|
||||
|
||||
const TRANSLATED_NUMBER_ERROR = LANG['creditCard.numberField.invalid'];
|
||||
const TRANSLATED_DATE_ERROR = LANG['creditCard.expiryDateField.invalid'];
|
||||
const TRANSLATED_CVC_ERROR = LANG['creditCard.oneClickVerification.invalidInput.title'];
|
||||
|
||||
const TRANSLATED_NUMBER_PLACEHOLDER = LANG['creditCard.numberField.placeholder'];
|
||||
const TRANSLATED_DATE_PLACEHOLDER = LANG['creditCard.expiryDateField.placeholder'];
|
||||
const TRANSLATED_CVC_PLACEHOLDER = LANG['creditCard.cvcField.placeholder'];
|
||||
|
||||
const nodeHolder = document.createElement('div');
|
||||
|
||||
const i18n = new Language('nl-NL', {});
|
||||
|
||||
const mockAriaConfig = {
|
||||
lang: 'en-GB',
|
||||
encryptedCardNumber: {
|
||||
label: 'Credit or debit card number field',
|
||||
iframeTitle: 'Iframe for credit card number field'
|
||||
},
|
||||
encryptedExpiryDate: {
|
||||
label: 'Credit or debit card expiration date field',
|
||||
error: 'Date field is in error'
|
||||
},
|
||||
encryptedSecurityCode: {
|
||||
label: 'Credit or debit card 3 or 4 digit security code field'
|
||||
}
|
||||
} as AriaConfig;
|
||||
|
||||
const mockPlaceholders = {
|
||||
encryptedCardNumber: '9999 9999 9999 9999',
|
||||
encryptedExpiryDate: 'MM/YY',
|
||||
encryptedSecurityCode: 999
|
||||
};
|
||||
|
||||
const iframeUIConfig = {
|
||||
placeholders: null,
|
||||
sfStyles: null,
|
||||
ariaConfig: {}
|
||||
};
|
||||
|
||||
const setupObj = {
|
||||
extraFieldData: null,
|
||||
txVariant: 'card',
|
||||
cardGroupTypes: ['amex', 'mc', 'visa'],
|
||||
iframeUIConfig,
|
||||
sfLogAtStart: false,
|
||||
trimTrailingSeparator: false,
|
||||
isCreditCardType: true,
|
||||
showWarnings: false,
|
||||
//
|
||||
fieldType: ENCRYPTED_CARD_NUMBER,
|
||||
cvcRequired: true,
|
||||
iframeSrc: null,
|
||||
loadingContext: null,
|
||||
holderEl: nodeHolder
|
||||
};
|
||||
|
||||
describe('SecuredField handling ariaConfig object - should set defaults', () => {
|
||||
//
|
||||
test('Card number field with no defined ariaConfig should get default title & translated error props', () => {
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_CARD_NUMBER].iframeTitle).toEqual(IFRAME_TITLE);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_CARD_NUMBER].error).toEqual(TRANSLATED_NUMBER_ERROR);
|
||||
});
|
||||
|
||||
test('Date field with no defined ariaConfig should get default title & translated error props', () => {
|
||||
setupObj.fieldType = ENCRYPTED_EXPIRY_DATE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_EXPIRY_DATE].iframeTitle).toEqual(IFRAME_TITLE);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_EXPIRY_DATE].error).toEqual(TRANSLATED_DATE_ERROR);
|
||||
});
|
||||
|
||||
test('CVC field with no defined ariaConfig should get default title & translated error props', () => {
|
||||
setupObj.fieldType = ENCRYPTED_SECURITY_CODE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_SECURITY_CODE].iframeTitle).toEqual(IFRAME_TITLE);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_SECURITY_CODE].error).toEqual(TRANSLATED_CVC_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SecuredField handling ariaConfig object - should set defaults only where they are not already defined', () => {
|
||||
//
|
||||
test('Card number field with ariaConfig with label & iframeTitle should preserve these props and also get a translated error prop', () => {
|
||||
setupObj.iframeUIConfig.ariaConfig = mockAriaConfig;
|
||||
setupObj.fieldType = ENCRYPTED_CARD_NUMBER;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_CARD_NUMBER].label).toEqual(mockAriaConfig[ENCRYPTED_CARD_NUMBER].label);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_CARD_NUMBER].iframeTitle).toEqual(mockAriaConfig[ENCRYPTED_CARD_NUMBER].iframeTitle);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_CARD_NUMBER].error).toEqual(TRANSLATED_NUMBER_ERROR);
|
||||
|
||||
// Also check that configured language is preserved
|
||||
expect(card.config.iframeUIConfig.ariaConfig.lang).toEqual(mockAriaConfig.lang);
|
||||
});
|
||||
|
||||
test('Date field with ariaConfig with label & error should preserve these props and also get a iframeTitle prop', () => {
|
||||
setupObj.fieldType = ENCRYPTED_EXPIRY_DATE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_EXPIRY_DATE].label).toEqual(mockAriaConfig[ENCRYPTED_EXPIRY_DATE].label);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_EXPIRY_DATE].iframeTitle).toEqual(IFRAME_TITLE);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_EXPIRY_DATE].error).toEqual(mockAriaConfig[ENCRYPTED_EXPIRY_DATE].error);
|
||||
});
|
||||
|
||||
test('CVC field with ariaConfig with label should preserve this prop and also get default title & translated error props', () => {
|
||||
setupObj.fieldType = ENCRYPTED_SECURITY_CODE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_SECURITY_CODE].label).toEqual(mockAriaConfig[ENCRYPTED_SECURITY_CODE].label);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_SECURITY_CODE].iframeTitle).toEqual(IFRAME_TITLE);
|
||||
expect(card.config.iframeUIConfig.ariaConfig[ENCRYPTED_SECURITY_CODE].error).toEqual(TRANSLATED_CVC_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SecuredField handling placeholders config object - should set defaults', () => {
|
||||
//
|
||||
test('Card number field with no defined placeholders config should get default value from translation field', () => {
|
||||
setupObj.fieldType = ENCRYPTED_CARD_NUMBER;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.placeholders[ENCRYPTED_CARD_NUMBER]).toEqual(TRANSLATED_NUMBER_PLACEHOLDER);
|
||||
});
|
||||
|
||||
test('Date field with no defined placeholders config should get default value from translation field', () => {
|
||||
setupObj.fieldType = ENCRYPTED_EXPIRY_DATE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.placeholders[ENCRYPTED_EXPIRY_DATE]).toEqual(TRANSLATED_DATE_PLACEHOLDER);
|
||||
});
|
||||
|
||||
test('CVC field with no defined placeholders config should get default value from translation field', () => {
|
||||
setupObj.fieldType = ENCRYPTED_SECURITY_CODE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.placeholders[ENCRYPTED_SECURITY_CODE]).toEqual(TRANSLATED_CVC_PLACEHOLDER);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SecuredField handling placeholders config object - defined placeholder should be preserved', () => {
|
||||
//
|
||||
test('Card number field with defined placeholders should keep that value', () => {
|
||||
setupObj.iframeUIConfig.placeholders = mockPlaceholders;
|
||||
setupObj.fieldType = ENCRYPTED_CARD_NUMBER;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.placeholders[ENCRYPTED_CARD_NUMBER]).toEqual(mockPlaceholders[ENCRYPTED_CARD_NUMBER]);
|
||||
});
|
||||
|
||||
test('Date field with defined placeholders should keep that value', () => {
|
||||
setupObj.fieldType = ENCRYPTED_EXPIRY_DATE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.placeholders[ENCRYPTED_EXPIRY_DATE]).toEqual(mockPlaceholders[ENCRYPTED_EXPIRY_DATE]);
|
||||
});
|
||||
|
||||
test('CVC field with defined placeholders should keep that value', () => {
|
||||
setupObj.fieldType = ENCRYPTED_SECURITY_CODE;
|
||||
|
||||
const card = new SecuredField(setupObj, i18n);
|
||||
expect(card.config.iframeUIConfig.placeholders[ENCRYPTED_SECURITY_CODE]).toEqual(mockPlaceholders[ENCRYPTED_SECURITY_CODE]);
|
||||
});
|
||||
});
|
||||
@@ -3,7 +3,7 @@ import createIframe from '../utilities/createIframe';
|
||||
import { selectOne, on, off, removeAllChildren } from '../utilities/dom';
|
||||
import postMessageToIframe from './utils/iframes/postMessageToIframe';
|
||||
import { isWebpackPostMsg, originCheckPassed, isChromeVoxPostMsg } from './utils/iframes/postMessageValidation';
|
||||
import { ENCRYPTED_SECURITY_CODE, IFRAME_TITLE } from '../configuration/constants';
|
||||
import { ENCRYPTED_SECURITY_CODE } from '../configuration/constants';
|
||||
import { generateRandomNumber } from '../utilities/commonUtils';
|
||||
import { SFFeedbackObj } from '../types';
|
||||
import AbstractSecuredField, {
|
||||
@@ -11,17 +11,21 @@ import AbstractSecuredField, {
|
||||
IframeConfigObject,
|
||||
RtnType_noParamVoidFn,
|
||||
RtnType_postMessageListener,
|
||||
RtnType_callbackFn
|
||||
RtnType_callbackFn,
|
||||
AriaConfig,
|
||||
PlaceholdersObject
|
||||
} from '../core/AbstractSecuredField';
|
||||
import { pick, reject } from '../../utils';
|
||||
import getProp from '../../../../../utils/getProp';
|
||||
import { processAriaConfig } from './utils/init/processAriaConfig';
|
||||
import { processPlaceholders } from './utils/init/processPlaceholders';
|
||||
import Language from '../../../../../language/Language';
|
||||
|
||||
const logPostMsg = false;
|
||||
const doLog = false;
|
||||
|
||||
class SecuredField extends AbstractSecuredField {
|
||||
// --
|
||||
constructor(pSetupObj: SFSetupObject) {
|
||||
constructor(pSetupObj: SFSetupObject, i18n: Language) {
|
||||
super();
|
||||
|
||||
// List of props from setup object not needed for iframe config
|
||||
@@ -53,13 +57,28 @@ class SecuredField extends AbstractSecuredField {
|
||||
logger.log('\n');
|
||||
}
|
||||
|
||||
return this.init();
|
||||
return this.init(i18n);
|
||||
}
|
||||
|
||||
init(): SecuredField {
|
||||
const iframeTitle: string = getProp(this.config, `iframeUIConfig.ariaLabels.${this.fieldType}.iframeTitle`) || IFRAME_TITLE;
|
||||
init(i18n: Language): SecuredField {
|
||||
/**
|
||||
* Ensure all fields have a related ariaConfig object containing, at minimum, an iframeTitle property and a (translated) error
|
||||
*/
|
||||
const processedAriaConfig: AriaConfig = processAriaConfig(this.config, this.fieldType, i18n);
|
||||
// Set result back onto config object
|
||||
this.config.iframeUIConfig.ariaConfig = processedAriaConfig;
|
||||
|
||||
const iframeEl: HTMLIFrameElement = createIframe(`${this.iframeSrc}`, iframeTitle);
|
||||
/**
|
||||
* Ensure that if a placeholder hasn't been set for a field then it gets a default, translated, one
|
||||
*/
|
||||
const processedPlaceholders: PlaceholdersObject = processPlaceholders(this.config, this.fieldType, i18n);
|
||||
// Set result back onto config object
|
||||
this.config.iframeUIConfig.placeholders = processedPlaceholders;
|
||||
|
||||
/**
|
||||
* Create & reference iframe and add load listener
|
||||
*/
|
||||
const iframeEl: HTMLIFrameElement = createIframe(`${this.iframeSrc}`, processedAriaConfig[this.fieldType].iframeTitle);
|
||||
|
||||
// Place the iframe into the holder
|
||||
this.holderEl.appendChild(iframeEl);
|
||||
@@ -93,6 +112,9 @@ class SecuredField extends AbstractSecuredField {
|
||||
// Add general listener for 'message' EVENT - the event that 'powers' postMessage
|
||||
on(window, 'message', this.postMessageListener, false);
|
||||
|
||||
// TODO - only needed until latest version of 3.2.5 is on test
|
||||
this.config.iframeUIConfig.ariaLabels = this.config.iframeUIConfig.ariaConfig;
|
||||
|
||||
// Create and send config object to iframe
|
||||
const configObj: IframeConfigObject = {
|
||||
fieldType: this.fieldType,
|
||||
@@ -102,7 +124,6 @@ class SecuredField extends AbstractSecuredField {
|
||||
extraFieldData: this.config.extraFieldData,
|
||||
cardGroupTypes: this.config.cardGroupTypes,
|
||||
iframeUIConfig: this.config.iframeUIConfig,
|
||||
pmConfig: this.config.iframeUIConfig, // TODO - only needed until latest version of 3.2.2 is on test
|
||||
sfLogAtStart: this.config.sfLogAtStart,
|
||||
showWarnings: this.config.showWarnings,
|
||||
trimTrailingSeparator: this.config.trimTrailingSeparator,
|
||||
|
||||
@@ -181,7 +181,7 @@ export function setupSecuredField(pItem: HTMLElement): void {
|
||||
holderEl: pItem
|
||||
};
|
||||
|
||||
const sf: SecuredField = new SecuredField(setupObj)
|
||||
const sf: SecuredField = new SecuredField(setupObj, this.props.i18n)
|
||||
.onIframeLoaded((): void => {
|
||||
// Count
|
||||
this.state.iframeCount += 1;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { CSF_FIELDS_ARRAY, IFRAME_TITLE } from '../../../configuration/constants';
|
||||
import getProp from '../../../../../../../utils/getProp';
|
||||
import { addErrorTranslationToObject } from '../../../../utils';
|
||||
import { AriaConfigObject, AriaConfig } from '../../AbstractSecuredField';
|
||||
|
||||
/**
|
||||
* Checks if the merchant has defined an ariaConfig object and if so enhances it with a iframeTitle and error property, if they don't already exist
|
||||
* If the ariaConfig object doesn't exist then creates one with the default properties
|
||||
* In both cases where the error property doesn't exist we extract the correct translation for the field and use that
|
||||
*/
|
||||
export function processAriaConfig(configObj, fieldType, i18n) {
|
||||
const iframeTitle: string = IFRAME_TITLE;
|
||||
let newAriaFieldConfigObj: AriaConfigObject;
|
||||
|
||||
// Check for a pre-existing, merchant defined object
|
||||
const ariaFieldConfig: AriaConfigObject = getProp(configObj, `iframeUIConfig.ariaConfig.${fieldType}`);
|
||||
|
||||
if (ariaFieldConfig) {
|
||||
newAriaFieldConfigObj = {
|
||||
...ariaFieldConfig,
|
||||
// If object already has a title, use it - else set default
|
||||
iframeTitle: ariaFieldConfig.iframeTitle || iframeTitle
|
||||
};
|
||||
} else {
|
||||
// Create a new object with the default title
|
||||
newAriaFieldConfigObj = { iframeTitle };
|
||||
}
|
||||
|
||||
// Add error translation
|
||||
const ariaFieldConfigWithTranslation = addErrorTranslationToObject(newAriaFieldConfigObj, fieldType, i18n, CSF_FIELDS_ARRAY);
|
||||
|
||||
// Create a new aria config object keeping the old entries and adding a new one for this field
|
||||
// N.B. need to do this deconstruction of the original aria config object to break existing refs & avoid getting an "accumulated" object
|
||||
return {
|
||||
...configObj.iframeUIConfig.ariaConfig,
|
||||
[fieldType]: ariaFieldConfigWithTranslation
|
||||
} as AriaConfig;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import getProp from '../../../../../../../utils/getProp';
|
||||
import { resolvePlaceholders } from '../../../../utils';
|
||||
import { PlaceholdersObject } from '../../AbstractSecuredField';
|
||||
|
||||
/**
|
||||
* Checks if the merchant has defined an placeholder config object and if not create one with a value from the relevant translation file
|
||||
*/
|
||||
export function processPlaceholders(configObj, fieldType, i18n) {
|
||||
let placeholderFieldValue: string = getProp(configObj, `iframeUIConfig.placeholders.${fieldType}`);
|
||||
|
||||
// If no value set by merchant - get translated one
|
||||
if (!placeholderFieldValue) {
|
||||
placeholderFieldValue = resolvePlaceholders(i18n)[fieldType];
|
||||
}
|
||||
|
||||
return {
|
||||
...configObj.iframeUIConfig.placeholders,
|
||||
[fieldType]: placeholderFieldValue
|
||||
} as PlaceholdersObject;
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import Language from '../../../../language/Language';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
_b$dl: boolean;
|
||||
@@ -33,6 +35,7 @@ export interface SetupObject extends CSFCommonProps {
|
||||
clientKey: string;
|
||||
rootNode: string | HTMLElement;
|
||||
callbacks?: object;
|
||||
i18n?: Language;
|
||||
}
|
||||
|
||||
export interface ConfigObject extends CSFCommonProps {
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
ENCRYPTED_EXPIRY_DATE,
|
||||
ENCRYPTED_EXPIRY_MONTH,
|
||||
ENCRYPTED_EXPIRY_YEAR,
|
||||
ENCRYPTED_SECURITY_CODE
|
||||
ENCRYPTED_SECURITY_CODE,
|
||||
ENCRYPTED_PWD_FIELD
|
||||
} from './lib/configuration/constants';
|
||||
|
||||
// ROUTINES USED IN SecuredFieldsProvider.componentDidMount TO DETECT & MAP FIELD NAMES ///////////
|
||||
@@ -82,36 +83,42 @@ export const getErrorObject = (fieldType, rootNode, state) => ({
|
||||
});
|
||||
// -- end ROUTINES USED IN SecuredFieldsProvider.showValidation -----------------------
|
||||
|
||||
// USED BY SecuredFieldsProvider WHEN CREATING SETUP OBJECT FOR CSF
|
||||
/**
|
||||
* Adds a new, translated, property e.g. "error" to the specified keys within an object
|
||||
* @param originalObject - object we want to duplicate and enhance
|
||||
* @param fieldNamesList - list of keys on the original object that we want to add the new property to
|
||||
* @param translationsArr - an array containing translations stored under the same keys as used in the original object
|
||||
* @returns a duplicate of the original object with a new property e.g. "error" added under the specified keys
|
||||
* Used below in addErrorTranslationToObject (called from SecuredField.ts) AND also by handler for SecuredFieldComponent aka CustomCardComponent
|
||||
*/
|
||||
export const addTranslationsToObject = (originalObject, fieldNamesList, propName, translationsArr) => {
|
||||
const originalKeys = Object.keys(originalObject);
|
||||
export const getTranslatedErrors = (i18n = {}) => ({
|
||||
[ENCRYPTED_CARD_NUMBER]: i18n.get && i18n.get('creditCard.numberField.invalid'),
|
||||
[ENCRYPTED_EXPIRY_DATE]: i18n.get && i18n.get('creditCard.expiryDateField.invalid'),
|
||||
[ENCRYPTED_EXPIRY_MONTH]: i18n.get && i18n.get('creditCard.expiryDateField.invalid'),
|
||||
[ENCRYPTED_EXPIRY_YEAR]: i18n.get && i18n.get('creditCard.expiryDateField.invalid'),
|
||||
[ENCRYPTED_SECURITY_CODE]: i18n.get && i18n.get('creditCard.oneClickVerification.invalidInput.title'),
|
||||
defaultError: 'error.title'
|
||||
});
|
||||
|
||||
const nuObj = { ...originalObject };
|
||||
|
||||
originalKeys
|
||||
.filter(key => fieldNamesList.includes(key))
|
||||
.map(key => {
|
||||
nuObj[key][propName] = !nuObj[key][propName] ? translationsArr[key] : nuObj[key][propName];
|
||||
return null;
|
||||
});
|
||||
|
||||
return nuObj;
|
||||
/**
|
||||
* Adds a new, translated, error property to an object, unless it already exists
|
||||
* @param originalObject - object we want to duplicate and enhance
|
||||
* @param key - fieldID eg. "encryptedCardNumber", id under which we expect a translation to exist
|
||||
* @param i18n - an i18n object to use to get translations
|
||||
* @param fieldNamesList - list of keys (fieldIDs) we want to add translations for
|
||||
* @returns a duplicate of the original object with a new property: "error" whose value is a translation extracted from the i18n object
|
||||
*/
|
||||
export const addErrorTranslationToObject = (originalObj, key, i18n, fieldNamesList) => {
|
||||
if (fieldNamesList.includes(key)) {
|
||||
const nuObj = { ...originalObj };
|
||||
const translatedErrors = getTranslatedErrors(i18n);
|
||||
nuObj.error = !nuObj.error ? translatedErrors[key] : nuObj.error;
|
||||
return nuObj;
|
||||
}
|
||||
return originalObj;
|
||||
};
|
||||
|
||||
export const resolvePlaceholders = (i18n = {}) => ({
|
||||
encryptedCardNumber: i18n.get && i18n.get('creditCard.numberField.placeholder'),
|
||||
encryptedExpiryDate: i18n.get && i18n.get('creditCard.expiryDateField.placeholder'),
|
||||
encryptedSecurityCode: i18n.get && i18n.get('creditCard.cvcField.placeholder'),
|
||||
encryptedPassword: i18n.get && i18n.get('creditCard.encryptedPassword.placeholder')
|
||||
[ENCRYPTED_CARD_NUMBER]: i18n.get && i18n.get('creditCard.numberField.placeholder'),
|
||||
[ENCRYPTED_EXPIRY_DATE]: i18n.get && i18n.get('creditCard.expiryDateField.placeholder'),
|
||||
[ENCRYPTED_SECURITY_CODE]: i18n.get && i18n.get('creditCard.cvcField.placeholder'),
|
||||
[ENCRYPTED_PWD_FIELD]: i18n.get && i18n.get('creditCard.encryptedPassword.placeholder')
|
||||
});
|
||||
// -- end USED BY SecuredFieldsProvider WHEN CREATING SETUP OBJECT FOR CSF
|
||||
|
||||
/**
|
||||
* Used by SecuredFieldsProviderHandlers
|
||||
@@ -128,18 +135,6 @@ export const getCardImageUrl = (brand, loadingContext) => {
|
||||
return getImageUrl(imageOptions)(type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by SecuredFieldsProvider when creating setup object for csf AND also by handler for SecuredFieldComponent aka CustomCardComponent
|
||||
*/
|
||||
export const getTranslatedErrors = (i18n = {}) => ({
|
||||
[ENCRYPTED_CARD_NUMBER]: i18n.get && i18n.get('creditCard.numberField.invalid'),
|
||||
[ENCRYPTED_EXPIRY_DATE]: i18n.get && i18n.get('creditCard.expiryDateField.invalid'),
|
||||
[ENCRYPTED_EXPIRY_MONTH]: i18n.get && i18n.get('creditCard.expiryDateField.invalid'),
|
||||
[ENCRYPTED_EXPIRY_YEAR]: i18n.get && i18n.get('creditCard.expiryDateField.invalid'),
|
||||
[ENCRYPTED_SECURITY_CODE]: i18n.get && i18n.get('creditCard.oneClickVerification.invalidInput.title'),
|
||||
defaultError: 'error.title'
|
||||
});
|
||||
|
||||
// REGULAR "UTIL" UTILS
|
||||
/**
|
||||
* Checks if `prop` is classified as an `Array` primitive or object.
|
||||
|
||||
Reference in New Issue
Block a user