From d74c430caa2bd4511ed3f345c175d629241e6b75 Mon Sep 17 00:00:00 2001 From: sponglord Date: Thu, 23 Nov 2023 12:58:48 +0100 Subject: [PATCH] Fix/v6 dropping TxVariants prop for Cards (#2428) * Removing txVariants static prop for card pms * Rationalising how type and brand are sent through the Card, Bancontact, StoredCard & CustomCard components * Cleaned up logs and removed commented out code * merging v6 changes - again * All Card comps now have consistent setting of type and brand props * Fixed unit test --- .../lib/src/components/Card/Bancontact.ts | 7 ++++++- packages/lib/src/components/Card/Card.test.ts | 2 +- packages/lib/src/components/Card/Card.tsx | 21 ++++++++----------- .../Card/components/CardInput/CardInput.tsx | 2 +- .../Card/components/CardInput/defaultProps.ts | 2 +- .../Card/components/CardInput/utils.ts | 10 ++++----- .../src/components/CustomCard/CustomCard.tsx | 7 ++++--- .../CustomCardInput/CustomCardInput.tsx | 13 ++++++++++-- .../binLookup/triggerBinLookUp.ts | 2 +- 9 files changed, 39 insertions(+), 27 deletions(-) diff --git a/packages/lib/src/components/Card/Bancontact.ts b/packages/lib/src/components/Card/Bancontact.ts index 6a8aae62b7..13e3ca5d86 100644 --- a/packages/lib/src/components/Card/Bancontact.ts +++ b/packages/lib/src/components/Card/Bancontact.ts @@ -30,7 +30,12 @@ class BancontactElement extends CardElement { formatProps(props: CardElementProps) { return { ...super.formatProps(props), - type: 'bcmc', // Force type (only for the Dropin is type automatically set to 'bcmc') - this will bypass the regEx brand detection + /** + * Force type (only for the Dropin is type automatically set to 'bcmc') + * - this will bypass the regEx brand detection that SF normally tries to carry out when the first few digits are entered in the PAN + */ + type: TxVariants.bcmc, + brand: TxVariants.bcmc, cvcPolicy: CVC_POLICY_HIDDEN }; } diff --git a/packages/lib/src/components/Card/Card.test.ts b/packages/lib/src/components/Card/Card.test.ts index 26fef673d5..2583f8d447 100644 --- a/packages/lib/src/components/Card/Card.test.ts +++ b/packages/lib/src/components/Card/Card.test.ts @@ -5,7 +5,7 @@ describe('Card', () => { test('should not require a billingAddress if it is a stored card', () => { const card = new CardElement({ core: global.core, billingAddressRequired: true, storedPaymentMethodId: 'test' }); expect(card.props.billingAddressRequired).toBe(false); - expect(card.props.type).toEqual('card'); + expect(card.props.type).toEqual('scheme'); }); test('should format countryCode to lowerCase', () => { diff --git a/packages/lib/src/components/Card/Card.tsx b/packages/lib/src/components/Card/Card.tsx index 6dea822b5e..ee8e0cbd9d 100644 --- a/packages/lib/src/components/Card/Card.tsx +++ b/packages/lib/src/components/Card/Card.tsx @@ -17,7 +17,6 @@ import { TxVariants } from '../tx-variants'; export class CardElement extends UIElement { public static type = TxVariants.scheme; - public static txVariants = [TxVariants.scheme, TxVariants.card]; private readonly clickToPayService: IClickToPayService | null; @@ -66,7 +65,8 @@ export class CardElement extends UIElement { // billingAddressRequired only available for non-stored cards billingAddressRequired: props.storedPaymentMethodId ? false : props.billingAddressRequired, // ...(props.brands && !props.groupTypes && { groupTypes: props.brands }), - type: props.type === 'scheme' ? 'card' : props.type, + /** props.brand will be specified in the case of a StoredCard or a Bancontact component, for a regular Card we default it to 'card' */ + brand: props.brand ?? TxVariants.card, countryCode: props.countryCode ? props.countryCode.toLowerCase() : null, // Required for transition period (until configuration object becomes the norm) // - if merchant has defined value directly in props, use this instead @@ -98,11 +98,12 @@ export class CardElement extends UIElement { */ formatData(): CardElementData { /** - * this.props.brand is never set for the generic card only for a 'dedicated' single-branded card e.g. bcmc - * this.state.selectedBrandValue will be set when /binLookup detects a single brand &/or when /binLookup detects a dual-branded card and - * the shopper makes a brand selection + * this.state.selectedBrandValue will be set when: + * - /binLookup detects a single brand, + * - when /binLookup detects a dual-branded card and the shopper makes a brand selection + * - or, in the case of a storedCard */ - const cardBrand = this.state.selectedBrandValue || this.props.brand; + const cardBrand = this.state.selectedBrandValue; const includeStorePaymentMethod = this.props.enableStoreDetails && typeof this.state.storePaymentMethod !== 'undefined'; return { @@ -167,7 +168,7 @@ export class CardElement extends UIElement { } get icon() { - return this.props.icon ?? this.resources.getImage()(this.brand); + return this.props.icon ?? this.resources.getImage()(this.props.brand); } get brands(): { icon: any; name: string }[] { @@ -182,10 +183,6 @@ export class CardElement extends UIElement { return []; } - get brand(): string { - return this.props.brand || this.props.type; - } - get displayName(): string { if (this.props.storedPaymentMethodId) { return `•••• ${this.props.lastFour}`; @@ -219,7 +216,7 @@ export class CardElement extends UIElement { payButton={this.payButton} onBrand={this.onBrand} onBinValue={this.onBinValue} - brand={this.brand} + brand={this.props.brand} brandsIcons={this.brands} isPayButtonPrimaryVariant={isCardPrimaryInput} resources={this.resources} diff --git a/packages/lib/src/components/Card/components/CardInput/CardInput.tsx b/packages/lib/src/components/Card/components/CardInput/CardInput.tsx index 6a230efd8c..2d5ac50710 100644 --- a/packages/lib/src/components/Card/components/CardInput/CardInput.tsx +++ b/packages/lib/src/components/Card/components/CardInput/CardInput.tsx @@ -84,7 +84,7 @@ const CardInput = (props: CardInputProps) => { const [issuingCountryCode, setIssuingCountryCode] = useState(null); const [dualBrandSelectElements, setDualBrandSelectElements] = useState([]); - const [selectedBrandValue, setSelectedBrandValue] = useState(''); + const [selectedBrandValue, setSelectedBrandValue] = useState(props.storedPaymentMethodId ? props.brand : ''); // If this is a storedCard comp initialise state with the storedCard's brand const showBillingAddress = props.billingAddressMode !== AddressModeOptions.none && props.billingAddressRequired; diff --git a/packages/lib/src/components/Card/components/CardInput/defaultProps.ts b/packages/lib/src/components/Card/components/CardInput/defaultProps.ts index 2ee91a6bff..ab40c0dab0 100644 --- a/packages/lib/src/components/Card/components/CardInput/defaultProps.ts +++ b/packages/lib/src/components/Card/components/CardInput/defaultProps.ts @@ -2,7 +2,7 @@ import { SocialSecurityMode } from '../../types'; import { AddressModeOptions } from './types'; export default { - type: 'card', + type: 'scheme', setComponentRef: () => {}, diff --git a/packages/lib/src/components/Card/components/CardInput/utils.ts b/packages/lib/src/components/Card/components/CardInput/utils.ts index b1ba3e070e..ff7172f8dc 100644 --- a/packages/lib/src/components/Card/components/CardInput/utils.ts +++ b/packages/lib/src/components/Card/components/CardInput/utils.ts @@ -148,6 +148,7 @@ export const extractPropsForSFP = (props: CardInputProps) => { keypadFix: props.keypadFix, legacyInputMode: props.legacyInputMode, loadingContext: props.loadingContext, + maskSecurityCode: props.maskSecurityCode, minimumExpiryDate: props.minimumExpiryDate, onAdditionalSFConfig: props.onAdditionalSFConfig, onAdditionalSFRemoved: props.onAdditionalSFRemoved, @@ -158,12 +159,11 @@ export const extractPropsForSFP = (props: CardInputProps) => { onError: props.onError, onFieldValid: props.onFieldValid, onLoad: props.onLoad, - showWarnings: props.showWarnings, - trimTrailingSeparator: props.trimTrailingSeparator, - resources: props.resources, - maskSecurityCode: props.maskSecurityCode, placeholders: props.placeholders, - showContextualElement: props.showContextualElement + resources: props.resources, + showContextualElement: props.showContextualElement, + showWarnings: props.showWarnings, + trimTrailingSeparator: props.trimTrailingSeparator } as SFPProps; // Can't set as return type on fn or it will complain about missing, mandatory, props }; diff --git a/packages/lib/src/components/CustomCard/CustomCard.tsx b/packages/lib/src/components/CustomCard/CustomCard.tsx index e6a8794291..8981b25728 100644 --- a/packages/lib/src/components/CustomCard/CustomCard.tsx +++ b/packages/lib/src/components/CustomCard/CustomCard.tsx @@ -38,7 +38,6 @@ type CustomCardProps = Omit< export class CustomCard extends UIElement { public static type = TxVariants.customCard; - public static txVariants = [TxVariants.customCard, TxVariants.card]; public static analyticsType = 'custom-scheme'; @@ -50,7 +49,8 @@ export class CustomCard extends UIElement { formatProps(props: CustomCardProps) { return { ...props, - type: props.type === 'scheme' || props.type === 'securedfields' ? 'card' : props.type + type: TxVariants.customCard, + brand: TxVariants.card }; } @@ -58,7 +58,7 @@ export class CustomCard extends UIElement { * Formats the component data output */ formatData() { - const sfBrand = this.state.selectedBrandValue || this.props.brand; + const sfBrand = this.state.selectedBrandValue; return { paymentMethod: { type: 'scheme', @@ -137,6 +137,7 @@ export class CustomCard extends UIElement { onBinValue={this.onBinValue} implementationType={'custom'} resources={this.resources} + brand={this.props.brand} /> ); diff --git a/packages/lib/src/components/CustomCard/CustomCardInput/CustomCardInput.tsx b/packages/lib/src/components/CustomCard/CustomCardInput/CustomCardInput.tsx index abd4b89c04..a21bc44abd 100644 --- a/packages/lib/src/components/CustomCard/CustomCardInput/CustomCardInput.tsx +++ b/packages/lib/src/components/CustomCard/CustomCardInput/CustomCardInput.tsx @@ -11,6 +11,7 @@ import { Placeholders } from '../../Card/components/CardInput/types'; interface SecuredFieldsProps { autoFocus?: boolean; + brand?: string; brands?: string[]; brandsConfiguration?: CardBrandsConfiguration; clientKey?: string; @@ -124,7 +125,16 @@ function CustomCardInput(props: SecuredFieldsProps) { /** * RENDER */ - return null} />; + // prettier-ignore + return ( + null} + /> + ); } CustomCardInput.defaultProps = defaultProps; @@ -161,7 +171,6 @@ const extractPropsForSFP = (props: SecuredFieldsProps) => { showWarnings: props.showWarnings, styles: props.styles, trimTrailingSeparator: props.trimTrailingSeparator, - type: props.type, resources: props.resources, maskSecurityCode: props.maskSecurityCode, placeholders: props.placeholders diff --git a/packages/lib/src/components/internal/SecuredFields/binLookup/triggerBinLookUp.ts b/packages/lib/src/components/internal/SecuredFields/binLookup/triggerBinLookUp.ts index 0960446c7a..d1630058fb 100644 --- a/packages/lib/src/components/internal/SecuredFields/binLookup/triggerBinLookUp.ts +++ b/packages/lib/src/components/internal/SecuredFields/binLookup/triggerBinLookUp.ts @@ -30,7 +30,7 @@ export default parent => { path: `v3/bin/binLookup?token=${parent.props.clientKey}` }, { - type: parent.props.type, + type: parent.props.brand, supportedBrands: parent.props.brands || DEFAULT_CARD_GROUP_TYPES, encryptedBin: callbackObj.encryptedBin, requestId: callbackObj.uuid // Pass id of request