Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
"@paypal/common-components": "^1.0.33",
"@paypal/sdk-client": "^4.0.166",
"@paypal/sdk-constants": "^1.0.118",
"@paypal/sdk-logos": "^2.0.0",
"core-js-pure": "3.31.1"
"@paypal/sdk-logos": "^2.0.0"
},
"devDependencies": {
"@axe-core/playwright": "^4.10.1",
Expand Down
3 changes: 1 addition & 2 deletions src/components/message/Message.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import objectEntries from 'core-js-pure/stable/object/entries';
import { uniqueID } from '@krakenjs/belter/src';

import {
Expand Down Expand Up @@ -159,7 +158,7 @@ const Message = function ({ markup, meta, parentStyles, warnings }) {
// Generate new MRID on message update.
const newMessageRequestId = uniqueID();

const query = objectEntries({
const query = Object.entries({
message_request_id: newMessageRequestId,
amount,
currency,
Expand Down
16 changes: 14 additions & 2 deletions src/components/modal/v2/lib/hooks/content.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import arrayFind from 'core-js-pure/stable/array/find';
import { useServerData } from '../providers';

/**
* Retrieves product data from server views by product identifier.
* Returns a fallback object with empty content if views is not an array or product is not found.
*
* @param {string} product - The product identifier to find
* @returns {Object} Product object containing meta and content
*/
export function useProduct(product) {
const fallback = { content: {} };
const { views } = useServerData();

return arrayFind(views, ({ meta }) => meta.product === product) ?? { content: {} };
if (!Array.isArray(views)) {
return fallback;
}
const view = views.find(({ meta }) => meta.product === product);

return view ?? fallback;
}

export function useContent(product) {
Expand Down
6 changes: 2 additions & 4 deletions src/components/modal/v2/lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import objectEntries from 'core-js-pure/stable/object/entries';
import arrayFrom from 'core-js-pure/stable/array/from';
import { isIosWebview, isAndroidWebview } from '@krakenjs/belter/src';
import { request, memoize, ppDebug } from '../../../../utils';
import validate from '../../../../library/zoid/message/validation';
Expand Down Expand Up @@ -28,7 +26,7 @@ export const getContent = memoize(
buttonSessionId,
integrationIdentifier
}) => {
const query = objectEntries({
const query = Object.entries({
currency,
amount,
payer_id: payerId,
Expand Down Expand Up @@ -87,7 +85,7 @@ export function setupTabTrap() {
function trapTabKey(e) {
// Check for TAB key press
if (e.keyCode === 9 && !document.querySelector('.modal-closed')) {
const tabArray = arrayFrom(document.querySelectorAll(focusableElementsString)).filter(
const tabArray = Array.from(document.querySelectorAll(focusableElementsString)).filter(
node => window.getComputedStyle(node).visibility === 'visible'
);
// SHIFT + TAB
Expand Down
3 changes: 1 addition & 2 deletions src/components/modal/v2/parts/LoadingShimmer.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint-disable eslint-comments/disable-enable-pair */
/** @jsx h */
import { Fragment, h } from 'preact';
import arrayFrom from 'core-js-pure/stable/array/from';

const LoadingShimmer = ({ numOffers = 3, offerCountry, useNewCheckoutDesign }) => {
/**
Expand All @@ -11,7 +10,7 @@ const LoadingShimmer = ({ numOffers = 3, offerCountry, useNewCheckoutDesign }) =

return (
<Fragment>
{arrayFrom({ length: numOffers }).map((_, index) => {
{Array.from({ length: numOffers }).map((_, index) => {
if (offerCountry === 'DE') {
return (
<div id={index} className="accordion__container shimmer">
Expand Down
4 changes: 1 addition & 3 deletions src/library/controllers/message/adapter.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import objectAssign from 'core-js-pure/stable/object/assign';

import { getGlobalState, setGlobalState } from '../../../utils';
import Messages from './interface';

objectAssign(Messages, {
Object.assign(Messages, {
// Support previous API
render: (config, selector) => Messages(config).render(selector),
// Method to manually set global state instead of with data-pp attributes on the script tag
Expand Down
3 changes: 1 addition & 2 deletions src/library/controllers/message/interface.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import objectEntries from 'core-js-pure/stable/object/entries';
import { ZalgoPromise } from '@krakenjs/zalgo-promise/src';

import {
Expand Down Expand Up @@ -210,7 +209,7 @@ export default (options = {}) => ({
}

// Filter out undefined to prevent overwriting previous values
const updatedMessageProps = objectEntries(messageProps).reduce(
const updatedMessageProps = Object.entries(messageProps).reduce(
(acc, [key, val]) =>
typeof val === 'undefined' ? acc : Object.assign(acc, { [key]: val }),
{}
Expand Down
4 changes: 2 additions & 2 deletions src/library/controllers/modal/interface.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import arrayFind from 'core-js-pure/stable/array/find';
import { ZalgoPromise } from '@krakenjs/zalgo-promise/src';

import {
Expand Down Expand Up @@ -141,7 +140,8 @@ const memoizedModal = memoizeOnProps(
typeof requestedProduct !== 'undefined' &&
requestedProduct !== 'NONE' &&
Array.isArray(zoidComponent.state.products) &&
!arrayFind(productState, supportedProduct => supportedProduct === requestedProduct)
Array.isArray(productState) &&
!productState.find(supportedProduct => supportedProduct === requestedProduct)
) {
logger.warn('invalid_option_value', {
location: 'offer',
Expand Down
5 changes: 2 additions & 3 deletions src/library/zoid/message/component.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import stringStartsWith from 'core-js-pure/stable/string/starts-with';
import { SDK_SETTINGS } from '@paypal/sdk-constants/src';
import { ZalgoPromise } from '@krakenjs/zalgo-promise/src';
import { uniqueID, getCurrentScriptUID } from '@krakenjs/belter/src';
Expand Down Expand Up @@ -357,15 +356,15 @@ export default createGlobalVariableGetter('__paypal_credit_message__', () =>
payerId: {
type: 'string',
queryParam: 'payer_id',
decorate: ({ props }) => (!stringStartsWith(props.account, 'client-id:') ? props.account : null),
decorate: ({ props }) => (!props.account.startsWith('client-id:') ? props.account : null),
default: () => '',
required: false
},
clientId: {
type: 'string',
queryParam: 'client_id',
decorate: ({ props }) => {
return stringStartsWith(props.account, 'client-id:') ? props.account.slice(10) : null;
return props.account.startsWith('client-id:') ? props.account.slice(10) : null;
},
default: () => '',
required: false
Expand Down
11 changes: 4 additions & 7 deletions src/library/zoid/message/validation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import arrayIncludes from 'core-js-pure/stable/array/includes';
import numberIsNaN from 'core-js-pure/stable/number/is-nan';
import stringStartsWith from 'core-js-pure/stable/string/starts-with';
import { logger, memoize, getEnv } from '../../../utils';
import { OFFER } from '../../../utils/constants';

Expand All @@ -21,7 +18,7 @@ export function validateType(expectedType, val) {
case Types.BOOLEAN:
return typeof val === 'boolean';
case Types.NUMBER:
return typeof val === 'number' && !numberIsNaN(val);
return typeof val === 'number' && !Number.isNaN(val);
case Types.FUNCTION:
return typeof val === 'function';
case Types.ARRAY:
Expand Down Expand Up @@ -69,9 +66,9 @@ export default {
account: ({ props: { account } }) => {
if (!validateType(Types.STRING, account)) {
logInvalidType('account', Types.STRING, account);
} else if (getEnv() === 'local' && stringStartsWith(account, 'DEV_')) {
} else if (getEnv() === 'local' && account.startsWith('DEV_')) {
return account;
} else if (account.length !== 13 && account.length !== 10 && !stringStartsWith(account, 'client-id:')) {
} else if (account.length !== 13 && account.length !== 10 && !account.startsWith('client-id:')) {
logInvalid('account', 'Ensure the correct Merchant Account ID has been entered.');
} else {
return account;
Expand Down Expand Up @@ -206,7 +203,7 @@ export default {

if (!validateType(Types.STRING, pageType)) {
logInvalidType('pageType', Types.STRING, pageType);
} else if (!arrayIncludes(options, pageType)) {
} else if (!options.includes(pageType)) {
logInvalidOption('pageType', options, pageType);
} else {
return pageType;
Expand Down
13 changes: 7 additions & 6 deletions src/library/zoid/modal/component.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import stringIncludes from 'core-js-pure/stable/string/includes';
import stringStartsWith from 'core-js-pure/stable/string/starts-with';
import { SDK_SETTINGS } from '@paypal/sdk-constants';
import { create } from '@krakenjs/zoid/src';
import { uniqueID, getCurrentScriptUID } from '@krakenjs/belter/src';
Expand Down Expand Up @@ -178,7 +176,11 @@ export default createGlobalVariableGetter('__paypal_credit_modal__', () =>
onClick({ linkName });
}

if (typeof onApply === 'function' && stringIncludes(linkName, 'Apply Now')) {
if (
typeof onApply === 'function' &&
typeof linkName === 'string' &&
linkName.includes('Apply Now')
) {
onApply();
}
};
Expand Down Expand Up @@ -385,15 +387,14 @@ export default createGlobalVariableGetter('__paypal_credit_modal__', () =>
payerId: {
type: 'string',
queryParam: 'payer_id',
decorate: ({ props }) => (!stringStartsWith(props.account, 'client-id:') ? props.account : null),
decorate: ({ props }) => (!props.account.startsWith('client-id:') ? props.account : null),
default: () => '',
required: false
},
clientId: {
type: 'string',
queryParam: 'client_id',
decorate: ({ props }) =>
stringStartsWith(props.account, 'client-id:') ? props.account.slice(10) : null,
decorate: ({ props }) => (props.account.startsWith('client-id:') ? props.account.slice(10) : null),
default: () => '',
required: false
},
Expand Down
3 changes: 1 addition & 2 deletions src/server/message/index.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from 'preact';
import arrayIncludes from 'core-js-pure/stable/array/includes';
import { objectMerge, objectFlattenToArray, curry } from '../../utils/server';
import { getMutations, getLocaleStyles, getLocaleClass, getLocaleProductName } from '../locale';
import allStyles from './styles';
Expand All @@ -25,7 +24,7 @@ const applyCascade = curry((style, flattened, type, rules) =>
rules.reduce(
(accumulator, [key, val]) => {
const split = key.split(' && ');
if (key === 'default' || split.every(k => arrayIncludes(flattened, k))) {
if (key === 'default' || split.every(k => flattened.includes(k))) {
// after numerous tests, Helvetica and Arial are 98.2% smaller than PayPal Sans font
// but 0.983 is used here to provide a slight buffer
const BASIC_FONT_FACTOR = 0.983;
Expand Down
16 changes: 14 additions & 2 deletions src/server/message/parts/BreakText.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
/** @jsx h */
import { h } from 'preact';
import stringIncludes from 'core-js-pure/stable/string/includes';
import Text from './Text';

/**
* Splits text at the first occurrence of a break word.
* If the break word is not found, returns the original text in an array.
*
* @param {string} text - The text to be split
* @param {string} breakWord - The word to split by
* @returns {string[]} An array containing either [text] if breakWord not found,
* or [firstPart, secondPart] where firstPart ends with breakWord
*/
function splitText(text, breakWord) {
const breakIndex = text.indexOf(breakWord) + breakWord.length;
const s1 = text.slice(0, breakIndex).trim();
Expand All @@ -22,11 +30,15 @@ const BreakText = ({ textParts, options }) => {
const spaced = idx < textParts.length - 1;
const containedBreaks = [];

while (stringIncludes(text, availableBreaks[0])) {
while (availableBreaks.length > 0 && typeof text === 'string' && text.includes(availableBreaks[0])) {
containedBreaks.push(availableBreaks[0]);
availableBreaks.shift();
}

if (typeof text !== 'string') {
return null;
}

// Prevent unnecessary nesting if the entire span innerText would be wrapped in a single br span
if (containedBreaks.length === 0 || (containedBreaks.length === 1 && text.endsWith(containedBreaks[0]))) {
return (
Expand Down
8 changes: 2 additions & 6 deletions src/utils/activeTags.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import arrayFind from 'core-js-pure/stable/array/find';
import arrayFrom from 'core-js-pure/stable/array/from';

import { getWindowFromElement } from './elements';

// Map class name of visible element to size tag.
const toTagSize = classList => {
const sizes = ['xsmall', 'small', 'medium', 'large', 'xlarge'];

// Match on first tag contained in classList, ignoring other values.
const tag = arrayFind(sizes, size => classList.contains(`tag--${size}`)) || 'NONE';
const tag = sizes.find(size => classList.contains(`tag--${size}`)) || 'NONE';

return tag.toUpperCase();
};
Expand All @@ -19,8 +16,7 @@ const getTagSize = node => {
return 'NONE';
}

const visibleElement = arrayFind(
arrayFrom(node.children),
const visibleElement = Array.from(node.children).find(
element => getWindowFromElement(node).getComputedStyle(element).getPropertyValue('display') !== 'none'
);

Expand Down
19 changes: 7 additions & 12 deletions src/utils/elements.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
import arrayFind from 'core-js-pure/stable/array/find';
import arrayFrom from 'core-js-pure/stable/array/from';
import arrayFlatMap from 'core-js-pure/stable/array/flat-map';
import arrayIncludes from 'core-js-pure/stable/array/includes';
import stringStartsWith from 'core-js-pure/stable/string/starts-with';
import { ZalgoPromise } from '@krakenjs/zalgo-promise/src';

import { curry } from './functional';
Expand Down Expand Up @@ -58,20 +53,20 @@ export function getInlineOptions(container) {
const inlineEventHandlers = ['onclick', 'onapply', 'onrender'];

const getOptionValue = (name, value) => {
if (stringStartsWith(value, '[')) {
if (typeof value === 'string' && value.startsWith('[')) {
try {
return flattenedToObject(name, JSON.parse(value.replace(/'/g, '"')));
} catch (err) {} // eslint-disable-line no-empty
}
return flattenedToObject(name, value);
};

const dataOptions = arrayFrom(container.attributes)
.filter(({ nodeName }) => stringStartsWith(nodeName, 'data-pp-'))
const dataOptions = Array.from(container.attributes)
.filter(({ nodeName }) => nodeName.startsWith('data-pp-'))
.reduce((accumulator, { nodeName, nodeValue }) => {
if (nodeValue) {
const attributeName = nodeName.replace('data-pp-', '');
const value = arrayIncludes(inlineEventHandlers, attributeName)
const value = inlineEventHandlers.includes(attributeName)
? // eslint-disable-next-line no-new-func
new Function(nodeValue)
: nodeValue;
Expand Down Expand Up @@ -278,15 +273,15 @@ export function isHidden(container) {

export function getAllBySelector(selector) {
if (typeof selector === 'string') {
return arrayFrom(document.querySelectorAll(selector));
return Array.from(document.querySelectorAll(selector));
}

if (isElement(selector)) {
return [selector];
}

if (Array.isArray(selector) && selector.every(isElement)) {
return arrayFlatMap(selector, getAllBySelector);
return selector.flatMap(getAllBySelector);
}

return [];
Expand Down Expand Up @@ -385,7 +380,7 @@ export const getRoot = baseElement => {
domPath.reverse();
let biggestEl = domPath[0];

const computedRoot = arrayFind(domPath, (el, index, elements) => {
const computedRoot = domPath.find((el, index, elements) => {
// We are searching for the element that contains the page scrolling.
// Some merchant sites will use height 100% on elements such as html and body
// that cause the intersection observer to hide elements below the fold.
Expand Down
7 changes: 2 additions & 5 deletions src/utils/global.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import objectKeys from 'core-js-pure/stable/object/keys';
import objectAssign from 'core-js-pure/stable/object/assign';
import Map from 'core-js-pure/stable/map';
import { eventEmitter } from '@krakenjs/belter/src';

import {
Expand Down Expand Up @@ -41,8 +38,8 @@ export const createGlobalState = () => {
};
export const destroyGlobalState = () => {
if (window[NAMESPACE]) {
objectKeys(window[NAMESPACE]).forEach(key => delete window[NAMESPACE][key]);
objectAssign(window[NAMESPACE], createDefaultState());
Object.keys(window[NAMESPACE]).forEach(key => delete window[NAMESPACE][key]);
Object.assign(window[NAMESPACE], createDefaultState());

delete window[NAMESPACE];
}
Expand Down
Loading
Loading